129 lines
4.9 KiB
JavaScript
129 lines
4.9 KiB
JavaScript
import { useContext } from 'react';
|
|
import CanvasContext from '../Context/canvasContext/CanvasContext';
|
|
import { Button } from '../ui/button';
|
|
import { Loader, Trash, X } from 'lucide-react';
|
|
import { ScrollArea } from '../ui/scroll-area';
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { deleteProject, getProjects } from '@/api/projectApi';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { toast } from '@/hooks/use-toast';
|
|
import ActiveObjectContext from '../Context/activeObject/ObjectContext';
|
|
import { FixedSizeList as List } from 'react-window';
|
|
|
|
export const ProjectPanel = () => {
|
|
const { setSelectedPanel, canvas } = useContext(CanvasContext);
|
|
const { setActiveObject } = useContext(ActiveObjectContext);
|
|
const navigate = useNavigate();
|
|
const queryClient = useQueryClient(); // Initialize query client
|
|
|
|
const { data: projects, isLoading: projectLoading, isSuccess: projectSuccess } = useQuery({
|
|
queryKey: ['projects'],
|
|
queryFn: getProjects, // Simplified function call
|
|
});
|
|
|
|
// To delete a project
|
|
const { mutate: projectDelete, isPending: deletePending } = useMutation({
|
|
mutationFn: async (id) => await deleteProject(id),
|
|
onSuccess: (data, id) => {
|
|
if (data?.status === 200) {
|
|
toast({
|
|
title: data?.status,
|
|
description: data?.message,
|
|
});
|
|
|
|
// Invalidate queries to refresh data
|
|
queryClient.invalidateQueries({ queryKey: ["projects"] });
|
|
queryClient.invalidateQueries({ queryKey: ["project", id] });
|
|
|
|
// Clear canvas if it exists
|
|
if (canvas) {
|
|
canvas.clear();
|
|
canvas.renderAll();
|
|
canvas.setBackgroundColor("#ffffff", canvas.renderAll.bind(canvas));
|
|
}
|
|
setActiveObject(null);
|
|
|
|
setSelectedPanel("");
|
|
navigate("/");
|
|
|
|
} else {
|
|
toast({
|
|
title: data?.status,
|
|
description: data?.message,
|
|
variant: "destructive"
|
|
});
|
|
}
|
|
},
|
|
onError: (error) => {
|
|
toast({
|
|
title: "Error",
|
|
description: error.message || "Failed to delete the project",
|
|
variant: "destructive",
|
|
});
|
|
}
|
|
});
|
|
|
|
const Row = ({ index, style }) => {
|
|
const project = filteredProjects[index];
|
|
|
|
return (
|
|
<div key={project?.id} className="flex flex-col gap-1 p-1 rounded-md border">
|
|
<div
|
|
className="rounded-md flex p-1 flex-col gap-1 bg-red-50 hover:bg-red-100 cursor-pointer transition-all"
|
|
onClick={() => navigate(`/${project.id}`)}
|
|
>
|
|
<p className="font-bold text-sm truncate">{project?.name}</p>
|
|
<p className="text-xs truncate">{project?.description} </p>
|
|
<img className="rounded-md" src={project?.preview_url} alt="each_project" />
|
|
</div>
|
|
|
|
<Button
|
|
disabled={deletePending}
|
|
className="w-fit p-1 ml-auto" size="small"
|
|
onClick={() => { projectDelete(project?.id) }}
|
|
>
|
|
<Trash className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
|
|
// Filter projects where preview_url is not empty or null
|
|
const filteredProjects = projects?.data?.filter(project => project?.preview_url) || [];
|
|
|
|
return (
|
|
<div>
|
|
<div className="flex justify-between items-center p-4 border-b">
|
|
<h2 className="text-lg font-semibold">Projects</h2>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => setSelectedPanel("")}
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
|
|
<ScrollArea className="md:h-[calc(90vh-190px)] px-4 py-4">
|
|
{
|
|
projectLoading && <p><Loader className="animate-spin mx-auto" /></p>
|
|
}
|
|
{
|
|
!projectLoading && projectSuccess && projects?.status === 200 &&
|
|
<List
|
|
height={400} // Set the height of the viewport
|
|
itemCount={filteredProjects.length} // Use length of filtered projects
|
|
itemSize={280} // Height of each row
|
|
width="100%" // Full width of the container
|
|
>
|
|
{Row}
|
|
</List>
|
|
}
|
|
{
|
|
projects?.status !== 200 && <p>{projects?.message}</p>
|
|
}
|
|
</ScrollArea>
|
|
</div>
|
|
);
|
|
};
|