feat(announcements): Add create and edit functionality with form dialog
This commit is contained in:
parent
83743343c9
commit
d251958a9b
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user