Files
emaui/apps/portal/src/app/features/licensing/components/StaffEvidence.tsx
2026-07-29 16:53:50 +03:00

82 lines
2.4 KiB
TypeScript

import { useEffect, useState } from 'react';
import { Badge, Button, FileButton, Group, Loader } from '@mantine/core';
import { IconCheck } from '@tabler/icons-react';
import {
localized,
uploadDocument,
useGetAttachmentsQuery,
type StaffEvidenceRequirement,
} from '@ema-platform/api';
interface Props {
staffId: string;
evidence: StaffEvidenceRequirement[];
readOnly?: boolean;
onUploaded: () => void;
}
/**
* Per-person evidence uploads (CV, work agreement, ERB certificate).
*
* These attach to the staff member rather than the application, which is why
* staff are stored as real rows: each needs a stable owner for their files.
*/
export function StaffEvidence({ staffId, evidence, readOnly, onUploaded }: Props) {
const { data: attachments = [], refetch } = useGetAttachmentsQuery({
ownerType: 'APPLICATION_STAFF',
ownerId: staffId,
});
const [busy, setBusy] = useState<string | null>(null);
if (!evidence?.length) return null;
return (
<Group gap="xs">
{evidence.map((item) => {
const uploaded = attachments.some(
(a) => a.documentKey === item.docKey && a.files?.length,
);
return (
<FileButton
key={item.docKey}
accept="application/pdf,image/jpeg,image/png"
onChange={async (file) => {
if (!file) return;
setBusy(item.docKey);
await uploadDocument({
ownerType: 'APPLICATION_STAFF',
ownerId: staffId,
documentKey: item.docKey,
file,
});
setBusy(null);
refetch();
onUploaded();
}}
>
{(props) => (
<Button
{...props}
size="compact-xs"
variant={uploaded ? 'light' : 'outline'}
color={uploaded ? 'teal' : item.mandatory ? 'blue' : 'gray'}
disabled={readOnly || busy === item.docKey}
leftSection={
busy === item.docKey ? (
<Loader size={10} />
) : uploaded ? (
<IconCheck size={12} />
) : undefined
}
>
{localized(item.label)}
{item.mandatory && !uploaded ? ' *' : ''}
</Button>
)}
</FileButton>
);
})}
</Group>
);
}