announcement
This commit is contained in:
parent
3e3653183a
commit
4f63014500
@ -139,8 +139,8 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className="bg-white">
|
||||||
<CardHeader>
|
<CardHeader className="bg-white text-gray-800">
|
||||||
<CardTitle>Create New Announcement</CardTitle>
|
<CardTitle>Create New Announcement</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Create an announcement to be displayed to specific user roles
|
Create an announcement to be displayed to specific user roles
|
||||||
@ -154,9 +154,13 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
name="title"
|
name="title"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Title</FormLabel>
|
<FormLabel className="text-gray-700">Title</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder="Enter announcement title" {...field} />
|
<Input
|
||||||
|
placeholder="Enter announcement title"
|
||||||
|
className="bg-white text-gray-800 border-gray-300"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -168,11 +172,12 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
name="content"
|
name="content"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Content</FormLabel>
|
<FormLabel className="text-gray-700">Content</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder="Enter announcement content"
|
placeholder="Enter announcement content"
|
||||||
rows={5}
|
rows={5}
|
||||||
|
className="bg-white text-gray-800 border-gray-300"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@ -186,14 +191,16 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
name="targetRoles"
|
name="targetRoles"
|
||||||
render={() => (
|
render={() => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Target Audience</FormLabel>
|
<FormLabel className="text-gray-700">Target Audience</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
<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">
|
<div className="flex flex-wrap gap-2">
|
||||||
{availableRoles.map(role => (
|
{availableRoles.map(role => (
|
||||||
<Badge
|
<Badge
|
||||||
key={role.id}
|
key={role.id}
|
||||||
variant={selectedRoles.includes(role.id) ? "default" : "outline"}
|
variant={selectedRoles.includes(role.id) ? "default" : "outline"}
|
||||||
className={`cursor-pointer ${
|
className={`cursor-pointer px-3 py-1 ${
|
||||||
selectedRoles.includes(role.id)
|
selectedRoles.includes(role.id)
|
||||||
? "bg-blue-600 hover:bg-blue-700"
|
? "bg-blue-600 hover:bg-blue-700"
|
||||||
: "hover:bg-gray-100"
|
: "hover:bg-gray-100"
|
||||||
@ -207,13 +214,19 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
</Badge>
|
</Badge>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button type="submit" disabled={isSubmitting || isSuccess} className="w-full">
|
<div className="flex justify-end">
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
disabled={isSubmitting || isSuccess}
|
||||||
|
className="px-4"
|
||||||
|
>
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
@ -228,6 +241,7 @@ export function AnnouncementForm({ userRole }: AnnouncementFormProps) {
|
|||||||
"Create Announcement"
|
"Create Announcement"
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -73,7 +73,7 @@ export function AnnouncementsDropdown() {
|
|||||||
onValueChange={handleAnnouncementChange}
|
onValueChange={handleAnnouncementChange}
|
||||||
defaultValue={selectedAnnouncement?.id}
|
defaultValue={selectedAnnouncement?.id}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full bg-white text-gray-800 border-gray-300">
|
||||||
<SelectValue placeholder="Select an announcement" />
|
<SelectValue placeholder="Select an announcement" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@ -87,15 +87,15 @@ export function AnnouncementsDropdown() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedAnnouncement && (
|
{selectedAnnouncement && (
|
||||||
<Card className="w-full">
|
<Card className="w-full bg-white">
|
||||||
<CardHeader>
|
<CardHeader className="bg-white text-gray-800">
|
||||||
<CardTitle>{selectedAnnouncement.title}</CardTitle>
|
<CardTitle>{selectedAnnouncement.title}</CardTitle>
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
Posted by {selectedAnnouncement.author.email} on {new Date(selectedAnnouncement.createdAt).toLocaleDateString()}
|
Posted by {selectedAnnouncement.author.email} on {new Date(selectedAnnouncement.createdAt).toLocaleDateString()}
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="prose">
|
<div className="prose max-h-[300px] overflow-y-auto pr-2">
|
||||||
{selectedAnnouncement.content}
|
{selectedAnnouncement.content}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -19,15 +19,10 @@ import {
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import {
|
import {
|
||||||
Pencil,
|
|
||||||
Trash2,
|
Trash2,
|
||||||
Eye,
|
Eye,
|
||||||
Search,
|
|
||||||
Plus,
|
|
||||||
Filter,
|
|
||||||
AlertTriangle
|
AlertTriangle
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@ -46,7 +41,6 @@ interface AnnouncementsListProps {
|
|||||||
|
|
||||||
export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
|
export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
|
||||||
const [announcements, setAnnouncements] = useState<Announcement[]>([]);
|
const [announcements, setAnnouncements] = useState<Announcement[]>([]);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
|
||||||
const [selectedAnnouncement, setSelectedAnnouncement] = useState<Announcement | null>(null);
|
const [selectedAnnouncement, setSelectedAnnouncement] = useState<Announcement | null>(null);
|
||||||
const [isViewDialogOpen, setIsViewDialogOpen] = useState(false);
|
const [isViewDialogOpen, setIsViewDialogOpen] = useState(false);
|
||||||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
||||||
@ -79,13 +73,6 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
|
|||||||
fetchAnnouncements();
|
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
|
// Handle viewing an announcement
|
||||||
const handleViewAnnouncement = (announcement: Announcement) => {
|
const handleViewAnnouncement = (announcement: Announcement) => {
|
||||||
setSelectedAnnouncement(announcement);
|
setSelectedAnnouncement(announcement);
|
||||||
@ -156,20 +143,7 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{/* Search and filter */}
|
{/* Announcements table with scroll */}
|
||||||
<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 */}
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center h-40">
|
<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>
|
<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}
|
{error}
|
||||||
<Button onClick={fetchAnnouncements} className="ml-4">Retry</Button>
|
<Button onClick={fetchAnnouncements} className="ml-4">Retry</Button>
|
||||||
</div>
|
</div>
|
||||||
) : filteredAnnouncements.length === 0 ? (
|
) : announcements.length === 0 ? (
|
||||||
<div className="text-center py-10 text-gray-500">
|
<div className="text-center py-10 text-gray-500">
|
||||||
No announcements found
|
No announcements found
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="border rounded-md">
|
<div className="border rounded-md max-h-[500px] overflow-y-auto">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader className="sticky top-0 bg-white z-10">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Title</TableHead>
|
<TableHead>Title</TableHead>
|
||||||
<TableHead>Created</TableHead>
|
<TableHead>Created</TableHead>
|
||||||
@ -196,7 +170,7 @@ export function AnnouncementsList({ userRole }: AnnouncementsListProps) {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{filteredAnnouncements.map((announcement) => (
|
{announcements.map((announcement) => (
|
||||||
<TableRow key={announcement.id}>
|
<TableRow key={announcement.id}>
|
||||||
<TableCell className="font-medium">{announcement.title}</TableCell>
|
<TableCell className="font-medium">{announcement.title}</TableCell>
|
||||||
<TableCell>{new Date(announcement.createdAt).toLocaleDateString()}</TableCell>
|
<TableCell>{new Date(announcement.createdAt).toLocaleDateString()}</TableCell>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user