Merge branch 'WorkflowChange' of https://github.com/Tria-plc/emaui into estif-branch-1

This commit is contained in:
Estifo77
2026-08-21 09:58:34 +03:00
4 changed files with 49 additions and 8 deletions

View File

@@ -36,6 +36,7 @@ import {
useGetMyMedicalCertificatesQuery,
} from '@ema-platform/api';
import { PdfPreviewModal } from '@ema-platform/ui';
import { useApplicationPayment } from '../../payments/hooks/useApplicationPayment';
// ---------------------------------------------------------------------------
// Mock data
@@ -55,6 +56,9 @@ interface CertificatesOverview {
type: string;
submitted: string;
status: string;
/** The fee owed at the current status, or null when nothing is due. */
feeAmount: number | null;
feeCurrency: string | null;
}[];
}
@@ -141,6 +145,7 @@ export function CertificatesPage() {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [previewTitle, setPreviewTitle] = useState('');
const [loading, setLoading] = useState(false);
const { pay, isPaying } = useApplicationPayment();
const { data } = useApiQuery<CertificatesOverview>({
url: '/certificates/my',
@@ -313,6 +318,19 @@ export function CertificatesPage() {
</Badge>
</Table.Td>
<Table.Td>
<Group gap="xs" justify="flex-end" wrap="nowrap">
{/* feeAmount is non-null exactly when the server would
accept a payment, so the button and the API agree. */}
{app.feeAmount !== null && (
<Button
size="xs"
color="yellow"
loading={isPaying}
onClick={() => pay(app.applicationId)}
>
Pay {app.feeAmount.toLocaleString()} {app.feeCurrency}
</Button>
)}
<Text
fz="xs"
c="blue"
@@ -321,6 +339,7 @@ export function CertificatesPage() {
>
Details
</Text>
</Group>
</Table.Td>
</Table.Tr>
))}

View File

@@ -93,6 +93,25 @@ export function ExamStageActions({
);
}
// Passed: the certificate itself is the last fee on the application.
if (app.status === 'EXAM_PASSED') {
return (
<Button
size="xs"
variant="filled"
color="yellow"
loading={paying}
onClick={() => onPay(app)}
>
{t('applications.actions.payCertificateFee', {
defaultValue: 'Pay certificate fee ({{amount}} {{currency}})',
amount: Number(app.feeAmount ?? 0).toLocaleString(),
currency: app.feeCurrency,
})}
</Button>
);
}
// Paid and scheduled are both waiting states — nothing for the candidate to
// do, so say so rather than offering a button that does nothing.
if (app.status === 'EXAM_PAID' || app.status === 'EXAM_SCHEDULED') {

View File

@@ -14,6 +14,7 @@ const EXAM_STAGE_STATUSES = [
'EXAM_PAID',
'EXAM_SCHEDULED',
'EXAM_FAILED',
'EXAM_PASSED',
];
export function applicationActionsColumn(

View File

@@ -160,6 +160,8 @@ export const APPLICANT_ACTION_STATUSES: LicenseStatus[] = [
// sit again after a failure.
'EXAM_PAYMENT_PENDING',
'EXAM_FAILED',
// Passed: the certificate fee falls due, and only the candidate can pay it.
'EXAM_PASSED',
];
/** Statuses that are finished, whichever way they went. */