Files
srbhr--resume-matcher/apps/frontend/components/tracker/application-card.tsx
T
wehub-resource-sync 5bdf4cc89a
Publish Docker Image / publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:36 +08:00

96 lines
3.1 KiB
TypeScript

'use client';
import React from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import GripVertical from 'lucide-react/dist/esm/icons/grip-vertical';
import Layers from 'lucide-react/dist/esm/icons/layers';
import { Card } from '@/components/ui/card';
import { useTranslations } from '@/lib/i18n';
import type { Application } from '@/lib/api/tracker';
interface ApplicationCardProps {
application: Application;
selected: boolean;
sharedResume: boolean;
onToggleSelect: (id: string) => void;
onOpen: (id: string) => void;
}
export function ApplicationCard({
application,
selected,
sharedResume,
onToggleSelect,
onOpen,
}: ApplicationCardProps) {
const { t } = useTranslations();
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: application.application_id,
});
const style: React.CSSProperties = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
};
const company = application.company?.trim();
const role = application.role?.trim();
return (
<div ref={setNodeRef} style={style}>
<Card
variant="interactive"
noPadding
className={`p-3 ${selected ? 'ring-2 ring-primary' : ''}`}
>
<div className="flex items-start gap-2">
<input
type="checkbox"
checked={selected}
onChange={() => onToggleSelect(application.application_id)}
onClick={(e) => e.stopPropagation()}
aria-label={t('tracker.card.selectAria')}
className="mt-1 h-4 w-4 shrink-0 rounded-none border-black accent-primary"
/>
<button
type="button"
onClick={() => onOpen(application.application_id)}
className="min-w-0 flex-1 text-left"
>
<p className="truncate text-sm font-semibold text-ink">
{company || t('tracker.card.companyUnknown')}
</p>
<p className="truncate font-mono text-xs text-ink-soft">
{role || t('tracker.card.roleUnknown')}
</p>
{application.applied_at && (
<p className="mt-1 font-mono text-[10px] uppercase tracking-wide text-steel-grey">
{new Date(application.applied_at).toLocaleDateString()}
</p>
)}
{sharedResume && (
<span className="mt-1 inline-flex items-center gap-1 border border-black bg-paper-tint px-1 font-mono text-[10px] uppercase text-ink-soft">
<Layers className="h-3 w-3" />
{t('tracker.card.sharedResume')}
</span>
)}
</button>
<button
type="button"
className="mt-0.5 shrink-0 cursor-grab text-steel-grey hover:text-ink active:cursor-grabbing"
aria-label={t('tracker.card.dragAria')}
{...attributes}
{...listeners}
>
<GripVertical className="h-4 w-4" />
</button>
</div>
</Card>
</div>
);
}