feat: add ExamStageActions component for exam fee handling

- Implemented ExamStageActions component to manage actions related to exam booking and payment based on application status.
- Added mock-base-query for development, providing a partial mock backend for various API endpoints.
- Introduced mock-data for simulating responses in the mock-base-query, covering profiles, vessels, applications, licenses, exams, and notifications.
This commit is contained in:
fitse-yotor
2026-08-15 11:51:14 +03:00
parent d8b01a2003
commit 0ac75669d4
34 changed files with 2638 additions and 472 deletions

View File

@@ -44,6 +44,7 @@ import {
useAssignApplicationMutation,
useCompleteReviewMutation,
useConfirmPaymentMutation,
useScheduleExamMutation,
useEscalateApplicationMutation,
useFinalApproveMutation,
useGetApplicationForReviewQuery,
@@ -76,6 +77,7 @@ import {
} from '../../components/DecisionConfirmModal';
import { ActivityRail } from '../../components/ActivityRail';
import { DocumentsTab } from '../../components/DocumentsTab';
import { ScheduleExamModal } from '../../components/ScheduleExamModal';
import { computeSla } from '../../sla';
import { reviewStaffColumns } from './columns';
import { evaluateEligibility, presentationFor } from '../../config/license-types';
@@ -152,6 +154,7 @@ export function LicenseReviewPage() {
const [scheduleInspection] = useScheduleInspectionMutation();
const [recordResult] = useRecordInspectionResultMutation();
const [confirmPayment] = useConfirmPaymentMutation();
const [scheduleExam, { isLoading: schedulingExam }] = useScheduleExamMutation();
const [holdApplication] = useHoldApplicationMutation();
const [resumeApplication] = useResumeApplicationMutation();
const [escalateApplication] = useEscalateApplicationMutation();
@@ -169,6 +172,7 @@ export function LicenseReviewPage() {
const [inspectionOpen, setInspectionOpen] = useState(false);
const [inspectionDate, setInspectionDate] = useState('');
const [resultOpen, setResultOpen] = useState(false);
const [scheduleExamOpen, setScheduleExamOpen] = useState(false);
const [findings, setFindings] = useState('');
const [checklist, setChecklist] = useState<
Record<string, 'PASS' | 'FAIL' | 'NEEDS_CORRECTION'>
@@ -329,6 +333,11 @@ export function LicenseReviewPage() {
case 'record-inspection':
setResultOpen(true);
return;
// Needs a session picked before anything is sent, so it opens its own
// modal rather than going through the generic confirm step.
case 'schedule-exam':
setScheduleExamOpen(true);
return;
case 'copy-link':
navigator.clipboard.writeText(window.location.href);
notifications.show({
@@ -905,6 +914,30 @@ export function LicenseReviewPage() {
onConfirm={submitDecision}
/>
<ScheduleExamModal
opened={scheduleExamOpen}
applicantName={app.companyName ?? t('review.theApplicant', 'the applicant')}
loading={schedulingExam}
onClose={() => setScheduleExamOpen(false)}
onConfirm={async (payload) => {
try {
await scheduleExam({ id, ...payload }).unwrap();
notifications.show({
color: 'teal',
title: t('review.done.scheduleExam', 'Exam scheduled'),
message: '',
});
setScheduleExamOpen(false);
} catch (err) {
notifications.show({
color: 'red',
title: t('review.actionFailed', 'Action failed'),
message: extractErrorMessage(err),
});
}
}}
/>
<Modal
opened={inspectionOpen}
onClose={() => setInspectionOpen(false)}