diff --git a/client/src/components/AnnouncementCard.tsx b/client/src/components/AnnouncementCard.tsx new file mode 100644 index 0000000..4a05de5 --- /dev/null +++ b/client/src/components/AnnouncementCard.tsx @@ -0,0 +1,309 @@ +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { useAuthUnified } from "@/hooks/useAuthUnified"; +import { useStore } from "@/components/Layout"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Megaphone, Plus, X, AlertTriangle, Info, Bell } from "lucide-react"; +import { useState } from "react"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { insertAnnouncementSchema } from "@shared/schema"; +import type { AnnouncementWithRelations } from "@shared/schema"; +import { z } from "zod"; +import { safeFormat, safeDate } from "@/lib/dateUtils"; + +const formSchema = insertAnnouncementSchema.extend({ + groupId: z.coerce.number().optional(), +}); + +export default function AnnouncementCard() { + const { user } = useAuthUnified(); + const { selectedStoreId } = useStore(); + const queryClient = useQueryClient(); + const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + title: "", + content: "", + priority: "normal", + groupId: undefined, + }, + }); + + // Fetch announcements + const { data: announcements = [] } = useQuery({ + queryKey: ['/api/announcements', selectedStoreId], + queryFn: async () => { + const params = new URLSearchParams(); + if (selectedStoreId && user?.role === 'admin') { + params.append('storeId', selectedStoreId.toString()); + } + + const response = await fetch(`/api/announcements?${params}`, { + credentials: 'include' + }); + + if (!response.ok) { + throw new Error('Failed to fetch announcements'); + } + + return response.json(); + }, + }); + + // Fetch groups for admin + const { data: groups = [] } = useQuery({ + queryKey: ['/api/groups'], + enabled: user?.role === 'admin', + }); + + // Create announcement mutation + const createMutation = useMutation({ + mutationFn: async (data: z.infer) => { + const response = await fetch('/api/announcements', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + credentials: 'include', + body: JSON.stringify(data), + }); + + if (!response.ok) { + throw new Error('Failed to create announcement'); + } + + return response.json(); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['/api/announcements'] }); + setIsCreateDialogOpen(false); + form.reset(); + }, + }); + + // Delete announcement mutation + const deleteMutation = useMutation({ + mutationFn: async (id: number) => { + const response = await fetch(`/api/announcements/${id}`, { + method: 'DELETE', + credentials: 'include', + }); + + if (!response.ok) { + throw new Error('Failed to delete announcement'); + } + + return response.json(); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['/api/announcements'] }); + }, + }); + + const onSubmit = (data: z.infer) => { + createMutation.mutate(data); + }; + + const getPriorityIcon = (priority: string) => { + switch (priority) { + case 'urgent': + return ; + case 'important': + return ; + default: + return ; + } + }; + + const getPriorityColor = (priority: string) => { + switch (priority) { + case 'urgent': + return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200'; + case 'important': + return 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200'; + default: + return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200'; + } + }; + + return ( + + +
+ + Informations +
+ {user?.role === 'admin' && ( + + + + + + + Nouvelle information + +
+ + ( + + Titre + + + + + + )} + /> + ( + + Contenu + +