All files / src/widgets/projects-list/ui/views ProjectListCardsView.tsx

100% Statements 13/13
66.66% Branches 4/6
100% Functions 5/5
100% Lines 11/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                    4x             4x                                     4x 16x 16x   16x 16x 16x 16x                                           14x                                               4x  
import React, { useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { UpdateProjectModal } from '@/features/project-update/model';
import { DeleteProjectModal } from '@/features/project-delete/model';
import { ProjectCard, type ProjectCardData } from '@/entities/project/ui/_shared';
 
interface Props {
	projects: ProjectCardData[];
}
 
const fadeVariants = {
	initial: { opacity: 0 },
	animate: { opacity: 1 },
	exit: { opacity: 0 },
};
 
const gridClasses =
	'grid gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 justify-items-center';
 
function renderCard(
	project: ProjectCardData,
	onEdit: (p: ProjectCardData) => void,
	onDelete: (p: ProjectCardData) => void,
) {
	return (
		<div key={project.id || project.name} className="w-full max-w-[280px]">
			<ProjectCard
				project={project}
				data-testid="project-card"
				onEditClick={onEdit}
				onDeleteClick={onDelete}
			/>
		</div>
	);
}
 
export const ProjectListCardsViewComponent = ({ projects }: Props) => {
	const [editingProject, setEditingProject] = useState<ProjectCardData | null>(null);
	const [deletingProject, setDeletingProject] = useState<ProjectCardData | null>(null);
 
	const handleCloseEdit = () => setEditingProject(null);
	const handleCloseDelete = () => setDeletingProject(null);
	const isDev = import.meta.env.MODE === 'development';
	const projectsWithFake: ProjectCardData[] = isDev
		? [
				...projects,
				{
					id: '', // empty id for ghost project
					name: 'Ghost Project',
					createdAt: Date.now(),
					updatedAt: Date.now(),
				},
			]
		: projects;
 
	return (
		<div className="relative min-h-[400px]" data-testid="project-list">
			<AnimatePresence mode="wait">
				<motion.div
					key="cards"
					{...fadeVariants}
					transition={{ duration: 0.4 }}
					className={gridClasses}
				>
					{projectsWithFake.map((p) =>
						renderCard(p, setEditingProject, setDeletingProject),
					)}
				</motion.div>
			</AnimatePresence>
 
			{editingProject && (
				<UpdateProjectModal
					projectId={editingProject.id}
					initialName={editingProject.name}
					onClose={handleCloseEdit}
				/>
			)}
 
			{deletingProject && (
				<DeleteProjectModal
					projectId={deletingProject.id}
					projectName={deletingProject.name}
					onClose={handleCloseDelete}
				/>
			)}
		</div>
	);
};
 
export const ProjectListCardsView = React.memo(ProjectListCardsViewComponent);