Spaces:
Sleeping
Sleeping
| import React from "react"; | |
| import { zodResolver } from "@hookform/resolvers/zod"; | |
| import { useForm } from "react-hook-form"; | |
| import { z } from "zod"; | |
| import { format } from "date-fns"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Textarea } from "@/components/ui/textarea"; | |
| import { | |
| Dialog, | |
| DialogContent, | |
| DialogDescription, | |
| DialogFooter, | |
| DialogHeader, | |
| DialogTitle | |
| } from "@/components/ui/dialog"; | |
| import { | |
| Form, | |
| FormControl, | |
| FormField, | |
| FormItem, | |
| FormLabel, | |
| FormMessage, | |
| } from "@/components/ui/form"; | |
| import { Leave, LeaveStatus, LeaveStatusUpdateRequest } from "@/types"; | |
| import { toast } from "sonner"; | |
| const statusUpdateSchema = z.object({ | |
| comments: z.string().min(3, { | |
| message: "Comments must be at least 3 characters", | |
| }).optional(), | |
| }); | |
| type StatusUpdateFormValues = z.infer<typeof statusUpdateSchema>; | |
| interface LeaveStatusUpdateProps { | |
| leave: Leave | null; | |
| action: "approve" | "reject"; | |
| isOpen: boolean; | |
| onOpenChange: (open: boolean) => void; | |
| onSubmit: (data: LeaveStatusUpdateRequest) => Promise<void>; | |
| approverId: number; | |
| isSubmitting: boolean; | |
| } | |
| const LeaveStatusUpdate: React.FC<LeaveStatusUpdateProps> = ({ | |
| leave, | |
| action, | |
| isOpen, | |
| onOpenChange, | |
| onSubmit, | |
| approverId, | |
| isSubmitting, | |
| }) => { | |
| const form = useForm<StatusUpdateFormValues>({ | |
| resolver: zodResolver(statusUpdateSchema), | |
| defaultValues: { | |
| comments: "", | |
| }, | |
| }); | |
| if (!leave) return null; | |
| const handleSubmit = async (values: StatusUpdateFormValues) => { | |
| try { | |
| const updateData: LeaveStatusUpdateRequest = { | |
| id: leave.id, | |
| status: action === "approve" ? "Approved" : "Rejected", | |
| approvedById: approverId, | |
| actionDate: format(new Date(), "yyyy-MM-dd'T'HH:mm:ss"), | |
| comments: values.comments, | |
| }; | |
| await onSubmit(updateData); | |
| form.reset(); | |
| toast.success(`Leave request ${action === "approve" ? "approved" : "rejected"} successfully`); | |
| onOpenChange(false); | |
| } catch (error) { | |
| console.error(`Error ${action} leave request:`, error); | |
| toast.error(`Failed to ${action} leave request`); | |
| } | |
| }; | |
| return ( | |
| <Dialog open={isOpen} onOpenChange={onOpenChange}> | |
| <DialogContent className="sm:max-w-[425px]"> | |
| <DialogHeader> | |
| <DialogTitle> | |
| {action === "approve" ? "Approve" : "Reject"} Leave Request | |
| </DialogTitle> | |
| <DialogDescription> | |
| {action === "approve" | |
| ? "Approve the leave request and provide any optional comments." | |
| : "Reject the leave request and provide a reason for rejection."} | |
| </DialogDescription> | |
| </DialogHeader> | |
| <Form {...form}> | |
| <form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4"> | |
| <div className="grid gap-4 py-4"> | |
| <div className="grid grid-cols-4 items-center gap-4"> | |
| <div className="font-medium">Employee:</div> | |
| <div className="col-span-3">ID: {leave.employeeId}</div> | |
| </div> | |
| <div className="grid grid-cols-4 items-center gap-4"> | |
| <div className="font-medium">Date:</div> | |
| <div className="col-span-3"> | |
| {format(new Date(leave.startDate), "PPP")} to{" "} | |
| {format(new Date(leave.endDate), "PPP")} | |
| </div> | |
| </div> | |
| <div className="grid grid-cols-4 items-center gap-4"> | |
| <div className="font-medium">Type:</div> | |
| <div className="col-span-3">{leave.type}</div> | |
| </div> | |
| <div className="grid grid-cols-4 items-center gap-4"> | |
| <div className="font-medium">Reason:</div> | |
| <div className="col-span-3">{leave.reason}</div> | |
| </div> | |
| <FormField | |
| control={form.control} | |
| name="comments" | |
| render={({ field }) => ( | |
| <FormItem> | |
| <FormLabel>Comments</FormLabel> | |
| <FormControl> | |
| <Textarea | |
| placeholder={ | |
| action === "approve" | |
| ? "Optional comments for approval" | |
| : "Please provide a reason for rejection" | |
| } | |
| className="resize-none" | |
| {...field} | |
| /> | |
| </FormControl> | |
| <FormMessage /> | |
| </FormItem> | |
| )} | |
| /> | |
| </div> | |
| <DialogFooter> | |
| <Button type="button" variant="outline" onClick={() => onOpenChange(false)}> | |
| Cancel | |
| </Button> | |
| <Button type="submit" disabled={isSubmitting} variant={action === "reject" ? "destructive" : "default"}> | |
| {isSubmitting | |
| ? "Processing..." | |
| : action === "approve" | |
| ? "Approve" | |
| : "Reject"} | |
| </Button> | |
| </DialogFooter> | |
| </form> | |
| </Form> | |
| </DialogContent> | |
| </Dialog> | |
| ); | |
| }; | |
| export default LeaveStatusUpdate; |