Files
k-photos/libertas-frontend/src/components/people/person-card.tsx
Gabriel Kaszewski 94b184d3b0 feat: Implement person management features
- Added hooks for listing, creating, updating, deleting, sharing, and merging people.
- Introduced a new route for person details and media.
- Implemented clustering faces functionality.
- Created services for person-related API interactions.

feat: Introduce tag management functionality

- Added hooks for listing, adding, and removing tags from media.
- Created services for tag-related API interactions.

feat: Enhance user authentication handling

- Added a hook to fetch current user details.
- Updated auth storage to manage user state more effectively.

feat: Update album management features

- Enhanced album service to return created album details.
- Updated API handlers to return album responses upon creation.
- Modified album repository to return created album.

feat: Implement media management improvements

- Added media details fetching and processing of media URLs.
- Enhanced media upload functionality to return processed media.

feat: Introduce face management features

- Added services for listing faces for media and assigning faces to persons.

fix: Update API client to clear authentication state on 401 errors.
2025-11-16 02:24:50 +01:00

103 lines
3.3 KiB
TypeScript

import { useState } from "react";
import { type Person } from "@/domain/types";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { useNavigate } from "@tanstack/react-router";
import { Trash2, UserSquare } from "lucide-react";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useDeletePerson } from "@/features/people/use-people";
import { buttonVariants } from "@/components/ui/button";
type PersonCardProps = {
person: Person;
};
export function PersonCard({ person }: PersonCardProps) {
const navigate = useNavigate();
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const { mutate: deletePerson, isPending: isDeleting } = useDeletePerson(
person.id
);
const handleDelete = () => {
deletePerson();
};
return (
<>
<ContextMenu>
<ContextMenuTrigger>
<Card
className="overflow-hidden hover:shadow-lg transition-shadow cursor-pointer"
onClick={() => {
// Navigate on left click
navigate({
to: "/people/$personId",
params: { personId: person.id },
});
}}
>
<CardHeader className="p-0">
<div className="aspect-square bg-gray-200 flex items-center justify-center">
{/* TODO: Add person thumbnail */}
<UserSquare className="w-1/2 h-1/2 text-gray-400" />
</div>
</CardHeader>
<CardContent className="p-4">
<CardTitle className="text-lg truncate text-center">
{person.name}
</CardTitle>
</CardContent>
</Card>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
className="text-destructive focus:text-destructive"
onSelect={() => setShowDeleteDialog(true)}
disabled={isDeleting}
>
<Trash2 className="mr-2 h-4 w-4" />
Delete Person
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete{" "}
<strong>{person.name}</strong> and unassign all associated faces.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
className={buttonVariants({ variant: "destructive" })}
onClick={handleDelete}
disabled={isDeleting}
>
{isDeleting ? "Deleting..." : "Delete"}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
}