pmtool / src /components /projects /MaintenanceAmcDatesSection.tsx
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
12.4 kB
import React, { useState, useEffect } from "react";
import { Plus, Edit, Trash, CalendarDays } from "lucide-react";
import { format, parseISO } from "date-fns";
import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from "@/components/ui/table";
import { toast } from "@/lib/custom-toast";
import { cn } from "@/lib/utils";
import {
MaintenanceAmcDate,
MaintenanceAmcDateCreateRequest,
MaintenanceAmcDateUpdateRequest
} from "@/types";
import { maintenanceAmcDateService } from "@/lib/api";
import CustomDialog from "@/components/CustomDialog";
interface MaintenanceAmcDatesSectionProps {
projectId: number;
}
export default function MaintenanceAmcDatesSection({ projectId }: MaintenanceAmcDatesSectionProps) {
const queryClient = useQueryClient();
const [open, setOpen] = useState(false);
const [editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState<MaintenanceAmcDateCreateRequest>({
projectId: projectId,
maintenanceType: '',
startDate: new Date().toISOString(),
endDate: new Date().toISOString(),
notes: ''
});
const [selectedId, setSelectedId] = useState<number | null>(null);
const [startDateOpen, setStartDateOpen] = useState(false);
const [endDateOpen, setEndDateOpen] = useState(false);
// Fetch maintenance AMC dates for the project
const { data: maintenanceAmcDates = [], isLoading } = useQuery({
queryKey: ['maintenanceAmcDates', projectId],
queryFn: () => maintenanceAmcDateService.getByProjectId(projectId),
enabled: !!projectId
});
// Create mutation
const createMutation = useMutation({
mutationFn: (data: MaintenanceAmcDateCreateRequest) => maintenanceAmcDateService.create(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['maintenanceAmcDates', projectId] });
toast.success('Maintenance/AMC date added successfully');
resetForm();
setOpen(false);
},
onError: (error) => {
console.error('Error creating maintenance AMC date:', error);
toast.error('Failed to add maintenance/AMC date');
}
});
// Update mutation
const updateMutation = useMutation({
mutationFn: (data: MaintenanceAmcDateUpdateRequest) => maintenanceAmcDateService.update(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['maintenanceAmcDates', projectId] });
toast.success('Maintenance/AMC date updated successfully');
resetForm();
setOpen(false);
},
onError: (error) => {
console.error('Error updating maintenance AMC date:', error);
toast.error('Failed to update maintenance/AMC date');
}
});
// Delete mutation
const deleteMutation = useMutation({
mutationFn: (id: number) => maintenanceAmcDateService.delete(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['maintenanceAmcDates', projectId] });
toast.success('Maintenance/AMC date deleted successfully');
},
onError: (error) => {
console.error('Error deleting maintenance AMC date:', error);
toast.error('Failed to delete maintenance/AMC date');
}
});
// Reset form data
const resetForm = () => {
setFormData({
projectId: projectId,
maintenanceType: '',
startDate: new Date().toISOString(),
endDate: new Date().toISOString(),
notes: ''
});
setEditMode(false);
setSelectedId(null);
};
// Handle submit
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!formData.maintenanceType.trim()) {
toast.error('Maintenance Type is required');
return;
}
if (editMode && selectedId) {
updateMutation.mutate({
...formData,
maintenanceId: selectedId
} as MaintenanceAmcDateUpdateRequest);
} else {
createMutation.mutate(formData);
}
};
// Handle edit button click
const handleEdit = (item: MaintenanceAmcDate) => {
setEditMode(true);
setSelectedId(item.maintenanceId);
setFormData({
projectId: item.projectId,
maintenanceType: item.maintenanceType,
startDate: item.startDate,
endDate: item.endDate,
notes: item.notes
});
setOpen(true);
};
// Handle delete button click
const handleDelete = (id: number) => {
if (confirm('Are you sure you want to delete this maintenance/AMC date?')) {
deleteMutation.mutate(id);
}
};
// Handle form input changes
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
// Handle date changes
const handleStartDateChange = (date: Date | undefined) => {
if (date) {
setFormData(prev => ({ ...prev, startDate: date.toISOString() }));
}
};
const handleEndDateChange = (date: Date | undefined) => {
if (date) {
setFormData(prev => ({ ...prev, endDate: date.toISOString() }));
}
};
// Format date for display
const formatDate = (dateString: string) => {
try {
return format(parseISO(dateString), 'PPP');
} catch (error) {
console.error('Error formatting date:', error);
return 'Invalid date';
}
};
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-medium">Maintenance & AMC Dates</h3>
<Button
size="sm"
onClick={() => {
resetForm();
setOpen(true);
}}
>
<Plus className="h-4 w-4 mr-2" />
Add New
</Button>
</div>
<CustomDialog
isOpen={open}
onClose={() => setOpen(false)}
title={`${editMode ? 'Edit' : 'Add'} Maintenance or AMC Date`}
>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="maintenanceType">Maintenance Type</Label>
<Input
id="maintenanceType"
name="maintenanceType"
value={formData.maintenanceType}
onChange={handleInputChange}
placeholder="e.g. Regular Maintenance, AMC, Service"
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="startDate">Start Date</Label>
<Popover open={startDateOpen} onOpenChange={setStartDateOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn(
"w-full justify-start text-left font-normal",
!formData.startDate && "text-muted-foreground"
)}
>
<CalendarDays className="mr-2 h-4 w-4" />
{formData.startDate ? formatDate(formData.startDate) : <span>Select date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={formData.startDate ? parseISO(formData.startDate) : undefined}
onSelect={(date) => {
handleStartDateChange(date);
setStartDateOpen(false);
}}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
<div className="space-y-2">
<Label htmlFor="endDate">End Date</Label>
<Popover open={endDateOpen} onOpenChange={setEndDateOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn(
"w-full justify-start text-left font-normal",
!formData.endDate && "text-muted-foreground"
)}
>
<CalendarDays className="mr-2 h-4 w-4" />
{formData.endDate ? formatDate(formData.endDate) : <span>Select date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={formData.endDate ? parseISO(formData.endDate) : undefined}
onSelect={(date) => {
handleEndDateChange(date);
setEndDateOpen(false);
}}
initialFocus
/>
</PopoverContent>
</Popover>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="notes">Notes</Label>
<Textarea
id="notes"
name="notes"
value={formData.notes}
onChange={handleInputChange}
placeholder="Additional details or notes"
rows={3}
/>
</div>
<div className="flex justify-end gap-2 pt-2">
<Button type="button" variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button type="submit">
{editMode ? 'Update' : 'Add'}
</Button>
</div>
</form>
</CustomDialog>
{isLoading ? (
<div className="text-center py-4">Loading...</div>
) : maintenanceAmcDates.length === 0 ? (
<div className="text-center py-8 border rounded-md bg-muted/20">
<CalendarDays className="h-8 w-8 mx-auto mb-2 text-muted-foreground" />
<p className="text-muted-foreground">No maintenance or AMC dates have been added yet.</p>
</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead>Type</TableHead>
<TableHead>Start Date</TableHead>
<TableHead>End Date</TableHead>
<TableHead>Notes</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{maintenanceAmcDates.map(item => (
<TableRow key={item.maintenanceId}>
<TableCell className="font-medium">{item.maintenanceType}</TableCell>
<TableCell>{formatDate(item.startDate)}</TableCell>
<TableCell>{formatDate(item.endDate)}</TableCell>
<TableCell className="max-w-[200px] truncate">{item.notes}</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-2">
<Button
size="icon"
variant="ghost"
onClick={() => handleEdit(item)}
>
<Edit className="h-4 w-4" />
</Button>
<Button
size="icon"
variant="ghost"
className="text-destructive"
onClick={() => handleDelete(item.maintenanceId)}
>
<Trash className="h-4 w-4" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</div>
);
}