pmtool / src /pages /deliverable.tsx
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
7.47 kB
import React, { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { format, parseISO } from "date-fns";
import { toast } from "@/lib/custom-toast";
import { Calendar, Edit, Trash } from "lucide-react";
// UI Components
import Layout from "@/components/layout/layout";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Separator } from "@/components/ui/separator";
// Types & API
import { Deliverable, ProjectApi } from "@/types";
import { deliverablesApi, projectService } from "@/lib/api";
const DeliverablePage = () => {
const { id } = useParams<{ id: string }>();
const deliverableId = parseInt(id || "0", 10);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const navigate = useNavigate();
const queryClient = useQueryClient();
// Fetch deliverable data
const {
isLoading: isLoadingDeliverable,
error: deliverableError,
data: deliverable
} = useQuery({
queryKey: ['deliverable', deliverableId],
queryFn: () => deliverablesApi.getById(deliverableId),
enabled: deliverableId > 0,
});
// Fetch project data for the deliverable
const {
isLoading: isLoadingProject,
error: projectError,
data: project
} = useQuery({
queryKey: ['project', deliverable?.projectId],
queryFn: () => projectService.getById(deliverable?.projectId || 0),
enabled: !!deliverable?.projectId,
});
// Delete mutation
const deleteDeliverableMutation = useMutation({
mutationFn: (id: number) => deliverablesApi.delete(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['deliverables'] });
toast.success('Deliverable deleted successfully');
navigate('/deliverables');
},
onError: (error) => {
console.error('Delete error:', error);
toast.error('Failed to delete deliverable');
}
});
// Handle delete deliverable
const handleDeleteDeliverable = () => {
setDeleteDialogOpen(true);
};
// Confirm delete
const confirmDelete = () => {
deleteDeliverableMutation.mutate(deliverableId);
};
// Handle edit
const handleEdit = () => {
navigate(`/deliverable-edit/${deliverableId}`);
};
if (isLoadingDeliverable || (deliverable?.projectId && isLoadingProject)) {
return (
<Layout>
<div className="flex items-center justify-center min-h-screen">
<p>Loading deliverable data...</p>
</div>
</Layout>
);
}
if (deliverableError || (deliverable?.projectId && projectError)) {
return (
<Layout>
<div className="flex flex-col items-center justify-center min-h-screen gap-4">
<p className="text-red-500">Error loading deliverable data</p>
<Button
variant="outline"
onClick={() => navigate("/deliverables")}
>
Back to Deliverables
</Button>
</div>
</Layout>
);
}
if (!deliverable) {
return (
<Layout>
<div className="flex flex-col items-center justify-center min-h-screen gap-4">
<p className="text-red-500">Deliverable not found</p>
<Button
variant="outline"
onClick={() => navigate("/deliverables")}
>
Back to Deliverables
</Button>
</div>
</Layout>
);
}
return (
<Layout>
<div className="flex flex-col w-full min-h-screen p-4 md:p-6">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
<div>
<Button
variant="outline"
onClick={() => navigate("/deliverables")}
className="mb-2"
>
Back to Deliverables
</Button>
<h1 className="text-2xl font-bold tracking-tight">{deliverable.name}</h1>
{project && (
<p className="text-muted-foreground">
Project: {project.projectName}
</p>
)}
</div>
<div className="flex gap-2">
<Button
variant="outline"
onClick={handleEdit}
className="flex items-center gap-1"
>
<Edit className="h-4 w-4" />
Edit
</Button>
<Button
variant="destructive"
onClick={handleDeleteDeliverable}
className="flex items-center gap-1"
>
<Trash className="h-4 w-4" />
Delete
</Button>
</div>
</div>
<div className="grid gap-6">
<Card>
<CardHeader>
<CardTitle className="text-xl">Deliverable Details</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<h3 className="text-sm font-medium text-muted-foreground mb-1">Name</h3>
<p>{deliverable.name}</p>
</div>
<Separator />
<div>
<h3 className="text-sm font-medium text-muted-foreground mb-1">Description</h3>
<p className="whitespace-pre-line">{deliverable.description}</p>
</div>
<Separator />
<div>
<h3 className="text-sm font-medium text-muted-foreground mb-1">Delivery Date</h3>
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4 text-muted-foreground" />
<span>{format(parseISO(deliverable.deliveryDate), "MMMM d, yyyy")}</span>
</div>
</div>
<Separator />
<div>
<h3 className="text-sm font-medium text-muted-foreground mb-1">Project</h3>
<p>{project ? project.projectName : "Loading project..."}</p>
</div>
</CardContent>
</Card>
</div>
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete the deliverable.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={confirmDelete}
className="bg-destructive hover:bg-destructive/90"
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</Layout>
);
};
export default DeliverablePage;