announcement
This commit is contained in:
parent
3e3653183a
commit
4f63014500
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user