announcement

This commit is contained in:
alma 2025-05-04 21:39:29 +02:00
parent 3e3653183a
commit 4f63014500
3 changed files with 62 additions and 74 deletions

View File

@ -139,8 +139,8 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
};
return (
<Card>
<CardHeader>
<Card className="bg-white">
<CardHeader className="bg-white text-gray-800">
<CardTitle>Create New Announcement</CardTitle>
<CardDescription>
Create an announcement to be displayed to specific user roles
@ -154,9 +154,13 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormLabel className="text-gray-700">Title</FormLabel>
<FormControl>
<Input placeholder="Enter announcement title" {...field} />
<Input
placeholder="Enter announcement title"
className="bg-white text-gray-800 border-gray-300"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
@ -168,11 +172,12 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
name="content"
render={({ field }) => (
<FormItem>
<FormLabel>Content</FormLabel>
<FormLabel className="text-gray-700">Content</FormLabel>
<FormControl>
<Textarea
placeholder="Enter announcement content"
rows={5}
className="bg-white text-gray-800 border-gray-300"
{...field}
/>
</FormControl>
@ -186,26 +191,29 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
name="targetRoles"
render={() => (
<FormItem>
<FormLabel>Target Audience</FormLabel>
<FormLabel className="text-gray-700">Target Audience</FormLabel>
<FormControl>
<div className="flex flex-wrap gap-2">
{availableRoles.map(role => (
<Badge
key={role.id}
variant={selectedRoles.includes(role.id) ? "default" : "outline"}
className={`cursor-pointer ${
selectedRoles.includes(role.id)
? "bg-blue-600 hover:bg-blue-700"
: "hover:bg-gray-100"
}`}
onClick={() => handleRoleToggle(role.id)}
>
{role.name}
{selectedRoles.includes(role.id) && (
<CheckIcon className="ml-1 h-3 w-3" />
)}
</Badge>
))}
<div className="p-3 border border-gray-200 rounded-md bg-gray-50">
<p className="text-sm text-gray-500 mb-2">Select which roles can see this announcement:</p>
<div className="flex flex-wrap gap-2">
{availableRoles.map(role => (
<Badge
key={role.id}
variant={selectedRoles.includes(role.id) ? "default" : "outline"}
className={`cursor-pointer px-3 py-1 ${
selectedRoles.includes(role.id)
? "bg-blue-600 hover:bg-blue-700"
: "hover:bg-gray-100"
}`}
onClick={() => handleRoleToggle(role.id)}
>
{role.name}
{selectedRoles.includes(role.id) && (
<CheckIcon className="ml-1 h-3 w-3" />
)}
</Badge>
))}
</div>
</div>
</FormControl>
<FormMessage />
@ -213,21 +221,27 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
)}
/>
<Button type="submit" disabled={isSubmitting || isSuccess} className="w-full">
{isSubmitting ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Submitting...
</>
) : isSuccess ? (
<>
<CheckIcon className="mr-2 h-4 w-4" />
Announcement Created!
</>
) : (
"Create Announcement"
)}
</Button>
<div className="flex justify-end">
<Button
type="submit"
disabled={isSubmitting || isSuccess}
className="px-4"
>
{isSubmitting ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Submitting...
</>
) : isSuccess ? (
<>
<CheckIcon className="mr-2 h-4 w-4" />
Announcement Created!
</>
) : (
"Create Announcement"
)}
</Button>
</div>
</form>
</Form>
</CardContent>

View File

@ -73,7 +73,7 @@ export function AnnouncementsDropdown() {
onValueChange={handleAnnouncementChange}
defaultValue={selectedAnnouncement?.id}
>
<SelectTrigger className="w-full">
<SelectTrigger className="w-full bg-white text-gray-800 border-gray-300">
<SelectValue placeholder="Select an announcement" />
</SelectTrigger>
<SelectContent>
@ -87,15 +87,15 @@ export function AnnouncementsDropdown() {
</div>
{selectedAnnouncement && (
<Card className="w-full">
<CardHeader>
<Card className="w-full bg-white">
<CardHeader className="bg-white text-gray-800">
<CardTitle>{selectedAnnouncement.title}</CardTitle>
<div className="text-sm text-gray-500">
Posted by {selectedAnnouncement.author.email} on {new Date(selectedAnnouncement.createdAt).toLocaleDateString()}
</div>
</CardHeader>
<CardContent>
<div className="prose">
<div className="prose max-h-[300px] overflow-y-auto pr-2">
{selectedAnnouncement.content}
</div>
</CardContent>

View File

@ -19,15 +19,10 @@ import {
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Pencil,
Trash2,
Eye,
Search,
Plus,
Filter,
AlertTriangle
} from "lucide-react";
import { Input } from "@/components/ui/input";
import {
Dialog,
DialogContent,
@ -46,7 +41,6 @@ interface AnnouncementsListProps {
export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
const [announcements, setAnnouncements] = useState<Announcement[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [selectedAnnouncement, setSelectedAnnouncement] = useState<Announcement | null>(null);
const [isViewDialogOpen, setIsViewDialogOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
@ -79,13 +73,6 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
fetchAnnouncements();
}, []);
// Filter announcements based on search term
const filteredAnnouncements = announcements.filter(
announcement =>
announcement.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
announcement.content.toLowerCase().includes(searchTerm.toLowerCase())
);
// Handle viewing an announcement
const handleViewAnnouncement = (announcement: Announcement) => {
setSelectedAnnouncement(announcement);
@ -156,20 +143,7 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
</div>
</CardHeader>
<CardContent>
{/* Search and filter */}
<div className="mb-4 flex items-center space-x-2">
<div className="relative flex-1">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500" />
<Input
placeholder="Search announcements..."
className="pl-8"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
</div>
{/* Announcements table */}
{/* Announcements table with scroll */}
{loading ? (
<div className="flex items-center justify-center h-40">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
@ -179,14 +153,14 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
{error}
<Button onClick={fetchAnnouncements} className="ml-4">Retry</Button>
</div>
) : filteredAnnouncements.length === 0 ? (
) : announcements.length === 0 ? (
<div className="text-center py-10 text-gray-500">
No announcements found
</div>
) : (
<div className="border rounded-md">
<div className="border rounded-md max-h-[500px] overflow-y-auto">
<Table>
<TableHeader>
<TableHeader className="sticky top-0 bg-white z-10">
<TableRow>
<TableHead>Title</TableHead>
<TableHead>Created</TableHead>
@ -196,7 +170,7 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
</TableRow>
</TableHeader>
<TableBody>
{filteredAnnouncements.map((announcement) => (
{announcements.map((announcement) => (
<TableRow key={announcement.id}>
<TableCell className="font-medium">{announcement.title}</TableCell>
<TableCell>{new Date(announcement.createdAt).toLocaleDateString()}</TableCell>