feat(announcements): Add create and edit functionality with form dialog

This commit is contained in:
debudebuye 2026-02-24 19:29:04 +03:00
parent 83743343c9
commit d251958a9b

View File

@ -27,13 +27,50 @@ import { format } from "date-fns"
export default function AnnouncementsPage() { export default function AnnouncementsPage() {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
const [formDialogOpen, setFormDialogOpen] = useState(false)
const [selectedAnnouncement, setSelectedAnnouncement] = useState<any>(null) const [selectedAnnouncement, setSelectedAnnouncement] = useState<any>(null)
const [formData, setFormData] = useState({
title: '',
message: '',
type: 'info' as 'info' | 'warning' | 'success' | 'error',
priority: 0,
targetAudience: 'all',
startsAt: '',
endsAt: '',
})
const { data: announcements, isLoading } = useQuery({ const { data: announcements, isLoading } = useQuery({
queryKey: ['admin', 'announcements'], queryKey: ['admin', 'announcements'],
queryFn: () => announcementService.getAnnouncements(false), queryFn: () => announcementService.getAnnouncements(false),
}) })
const createMutation = useMutation({
mutationFn: (data: any) => announcementService.createAnnouncement(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'announcements'] })
toast.success("Announcement created successfully")
setFormDialogOpen(false)
resetForm()
},
onError: (error: any) => {
toast.error(error.response?.data?.message || "Failed to create announcement")
},
})
const updateMutation = useMutation({
mutationFn: ({ id, data }: { id: string; data: any }) =>
announcementService.updateAnnouncement(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'announcements'] })
toast.success("Announcement updated successfully")
setFormDialogOpen(false)
resetForm()
},
onError: (error: any) => {
toast.error(error.response?.data?.message || "Failed to update announcement")
},
})
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: (id: string) => announcementService.deleteAnnouncement(id), mutationFn: (id: string) => announcementService.deleteAnnouncement(id),
onSuccess: () => { onSuccess: () => {
@ -46,6 +83,59 @@ export default function AnnouncementsPage() {
}, },
}) })
const resetForm = () => {
setFormData({
title: '',
message: '',
type: 'info',
priority: 0,
targetAudience: 'all',
startsAt: '',
endsAt: '',
})
setSelectedAnnouncement(null)
}
const handleOpenCreateDialog = () => {
resetForm()
setFormDialogOpen(true)
}
const handleOpenEditDialog = (announcement: any) => {
setSelectedAnnouncement(announcement)
setFormData({
title: announcement.title || '',
message: announcement.message || '',
type: announcement.type || 'info',
priority: announcement.priority || 0,
targetAudience: announcement.targetAudience || 'all',
startsAt: announcement.startsAt ? announcement.startsAt.split('T')[0] : '',
endsAt: announcement.endsAt ? announcement.endsAt.split('T')[0] : '',
})
setFormDialogOpen(true)
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (!formData.title || !formData.message) {
toast.error("Title and message are required")
return
}
const submitData = {
...formData,
startsAt: formData.startsAt || undefined,
endsAt: formData.endsAt || undefined,
}
if (selectedAnnouncement) {
updateMutation.mutate({ id: selectedAnnouncement.id, data: submitData })
} else {
createMutation.mutate(submitData)
}
}
const handleDelete = () => { const handleDelete = () => {
if (selectedAnnouncement) { if (selectedAnnouncement) {
deleteMutation.mutate(selectedAnnouncement.id) deleteMutation.mutate(selectedAnnouncement.id)
@ -56,7 +146,7 @@ export default function AnnouncementsPage() {
<div className="space-y-6"> <div className="space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h2 className="text-3xl font-bold">Announcements</h2> <h2 className="text-3xl font-bold">Announcements</h2>
<Button> <Button onClick={handleOpenCreateDialog}>
<Plus className="w-4 h-4 mr-2" /> <Plus className="w-4 h-4 mr-2" />
Create Announcement Create Announcement
</Button> </Button>
@ -104,7 +194,11 @@ export default function AnnouncementsPage() {
</TableCell> </TableCell>
<TableCell> <TableCell>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button variant="ghost" size="icon"> <Button
variant="ghost"
size="icon"
onClick={() => handleOpenEditDialog(announcement)}
>
<Edit className="w-4 h-4" /> <Edit className="w-4 h-4" />
</Button> </Button>
<Button <Button
@ -133,6 +227,122 @@ export default function AnnouncementsPage() {
</CardContent> </CardContent>
</Card> </Card>
{/* Create/Edit Dialog */}
<Dialog open={formDialogOpen} onOpenChange={setFormDialogOpen}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>
{selectedAnnouncement ? 'Edit Announcement' : 'Create Announcement'}
</DialogTitle>
<DialogDescription>
{selectedAnnouncement
? 'Update the announcement details below.'
: 'Fill in the details to create a new announcement.'}
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium">Title *</label>
<input
type="text"
className="w-full px-3 py-2 border rounded-md"
value={formData.title}
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
required
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Message *</label>
<textarea
className="w-full px-3 py-2 border rounded-md min-h-[100px]"
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm font-medium">Type</label>
<select
className="w-full px-3 py-2 border rounded-md"
value={formData.type}
onChange={(e) => setFormData({ ...formData, type: e.target.value as any })}
>
<option value="info">Info</option>
<option value="warning">Warning</option>
<option value="success">Success</option>
<option value="error">Error</option>
</select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Priority</label>
<input
type="number"
className="w-full px-3 py-2 border rounded-md"
value={formData.priority}
onChange={(e) => setFormData({ ...formData, priority: parseInt(e.target.value) || 0 })}
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Target Audience</label>
<input
type="text"
className="w-full px-3 py-2 border rounded-md"
value={formData.targetAudience}
onChange={(e) => setFormData({ ...formData, targetAudience: e.target.value })}
placeholder="all, admins, users, etc."
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm font-medium">Start Date</label>
<input
type="date"
className="w-full px-3 py-2 border rounded-md"
value={formData.startsAt}
onChange={(e) => setFormData({ ...formData, startsAt: e.target.value })}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">End Date</label>
<input
type="date"
className="w-full px-3 py-2 border rounded-md"
value={formData.endsAt}
onChange={(e) => setFormData({ ...formData, endsAt: e.target.value })}
/>
</div>
</div>
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => {
setFormDialogOpen(false)
resetForm()
}}
>
Cancel
</Button>
<Button
type="submit"
disabled={createMutation.isPending || updateMutation.isPending}
>
{selectedAnnouncement ? 'Update' : 'Create'}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
{/* Delete Dialog */} {/* Delete Dialog */}
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}> <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<DialogContent> <DialogContent>
@ -155,4 +365,3 @@ export default function AnnouncementsPage() {
</div> </div>
) )
} }