mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
mock data for test
This commit is contained in:
@@ -19,6 +19,7 @@ import { KpiTiles } from './KpiTiles';
|
|||||||
import { ReportCharts } from './ReportCharts';
|
import { ReportCharts } from './ReportCharts';
|
||||||
import { ReportFilters } from './ReportFilters';
|
import { ReportFilters } from './ReportFilters';
|
||||||
import { ReportTables } from './ReportTables';
|
import { ReportTables } from './ReportTables';
|
||||||
|
import { MOCK_VESSEL_REPORT } from './mock-report';
|
||||||
import { queryToSearchParams, searchParamsToQuery } from './report-format';
|
import { queryToSearchParams, searchParamsToQuery } from './report-format';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,9 +52,11 @@ export function VesselRegistrationReportPage() {
|
|||||||
[setSearchParams],
|
[setSearchParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: report, isLoading, isFetching, error } = useGetVesselReportQuery(
|
const { data, isLoading, isFetching, error } = useGetVesselReportQuery(query);
|
||||||
query,
|
|
||||||
);
|
// Dev-only stand-in so the dashboard can be reviewed before the endpoint is
|
||||||
|
// live. Production still shows the empty state and the error alert.
|
||||||
|
const report = data ?? (import.meta.env.DEV ? MOCK_VESSEL_REPORT : undefined);
|
||||||
|
|
||||||
const exportCsv = useCallback(async () => {
|
const exportCsv = useCallback(async () => {
|
||||||
setExporting(true);
|
setExporting(true);
|
||||||
|
|||||||
@@ -0,0 +1,257 @@
|
|||||||
|
import type { BreakdownItem, VesselReport } from '@ema-platform/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stand-in report for previewing the dashboard before `GET /vessels/report`
|
||||||
|
* is live. Only used in dev, and only when the real call gives nothing back.
|
||||||
|
*
|
||||||
|
* ponytail: hand-written fixture, delete once the endpoint answers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const MONTHS = [
|
||||||
|
'2025-09-01', '2025-10-01', '2025-11-01', '2025-12-01',
|
||||||
|
'2026-01-01', '2026-02-01', '2026-03-01', '2026-04-01',
|
||||||
|
'2026-05-01', '2026-06-01', '2026-07-01', '2026-08-01',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Turns `[label, count]` pairs into slices whose percentages total 100. */
|
||||||
|
function breakdown(pairs: [string, number][]): BreakdownItem[] {
|
||||||
|
const total = pairs.reduce((sum, [, count]) => sum + count, 0) || 1;
|
||||||
|
return pairs.map(([label, count]) => ({
|
||||||
|
key: label.toUpperCase().replace(/[^A-Z0-9]+/g, '_'),
|
||||||
|
label,
|
||||||
|
count,
|
||||||
|
percentage: Math.round((count / total) * 1000) / 10,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const REGISTRATIONS = [18, 24, 21, 30, 27, 33, 29, 38, 35, 41, 37, 26];
|
||||||
|
const SUBMITTED = [26, 31, 28, 39, 34, 42, 37, 47, 44, 51, 46, 33];
|
||||||
|
|
||||||
|
export const MOCK_VESSEL_REPORT: VesselReport = {
|
||||||
|
generatedAt: '2026-08-18T09:15:00.000Z',
|
||||||
|
truncated: false,
|
||||||
|
filters: {
|
||||||
|
from: '2025-09-01',
|
||||||
|
to: '2026-08-18',
|
||||||
|
granularity: 'MONTH',
|
||||||
|
expiringWithinDays: 90,
|
||||||
|
topN: 8,
|
||||||
|
tableLimit: 10,
|
||||||
|
category: null,
|
||||||
|
status: null,
|
||||||
|
flagState: null,
|
||||||
|
portOfRegistry: null,
|
||||||
|
vesselType: null,
|
||||||
|
search: null,
|
||||||
|
},
|
||||||
|
kpis: {
|
||||||
|
register: {
|
||||||
|
total: 1284,
|
||||||
|
registered: 1096,
|
||||||
|
suspended: 87,
|
||||||
|
deregistered: 101,
|
||||||
|
registeredInPeriod: 359,
|
||||||
|
registeredInPreviousPeriod: 302,
|
||||||
|
changePct: 18.9,
|
||||||
|
},
|
||||||
|
fleet: {
|
||||||
|
totalGrossTonnage: 486_320,
|
||||||
|
avgGrossTonnage: 412.7,
|
||||||
|
grossTonnageKnownFor: 1178,
|
||||||
|
totalPassengerCapacity: 39_450,
|
||||||
|
avgLengthMeters: 28.4,
|
||||||
|
avgAgeYears: 16.2,
|
||||||
|
ageKnownFor: 1141,
|
||||||
|
seaGoing: 512,
|
||||||
|
inlandWaterway: 772,
|
||||||
|
},
|
||||||
|
pipeline: {
|
||||||
|
total: 642,
|
||||||
|
draft: 48,
|
||||||
|
inProgress: 113,
|
||||||
|
approved: 351,
|
||||||
|
rejected: 62,
|
||||||
|
issued: 337,
|
||||||
|
submittedInPeriod: 458,
|
||||||
|
decidedInPeriod: 396,
|
||||||
|
newCount: 421,
|
||||||
|
renewalCount: 221,
|
||||||
|
approvalRatePct: 85,
|
||||||
|
avgProcessingDays: 11.4,
|
||||||
|
medianProcessingDays: 9,
|
||||||
|
avgAdjustmentRounds: 1.3,
|
||||||
|
},
|
||||||
|
certificates: {
|
||||||
|
total: 1096,
|
||||||
|
active: 934,
|
||||||
|
expired: 118,
|
||||||
|
suspended: 44,
|
||||||
|
expiringIn30: 37,
|
||||||
|
expiringIn60: 71,
|
||||||
|
expiringIn90: 112,
|
||||||
|
missingCertificate: 23,
|
||||||
|
},
|
||||||
|
incidents: {
|
||||||
|
total: 96,
|
||||||
|
inPeriod: 41,
|
||||||
|
reportedByOfficer: 58,
|
||||||
|
reportedByOwner: 38,
|
||||||
|
vesselsWithIncidents: 74,
|
||||||
|
},
|
||||||
|
revenue: {
|
||||||
|
currency: 'ETB',
|
||||||
|
mixedCurrency: false,
|
||||||
|
paid: 4_812_500,
|
||||||
|
pending: 638_000,
|
||||||
|
paidCount: 389,
|
||||||
|
pendingCount: 54,
|
||||||
|
failedCount: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
timeSeries: {
|
||||||
|
registrations: MONTHS.map((bucket, i) => ({
|
||||||
|
bucket,
|
||||||
|
count: REGISTRATIONS[i],
|
||||||
|
grossTonnage: REGISTRATIONS[i] * 380 + i * 260,
|
||||||
|
})),
|
||||||
|
applications: MONTHS.map((bucket, i) => ({
|
||||||
|
bucket,
|
||||||
|
submitted: SUBMITTED[i],
|
||||||
|
approved: Math.round(SUBMITTED[i] * 0.72),
|
||||||
|
rejected: Math.round(SUBMITTED[i] * 0.11),
|
||||||
|
issued: Math.round(SUBMITTED[i] * 0.68),
|
||||||
|
})),
|
||||||
|
incidents: MONTHS.map((bucket, i) => ({
|
||||||
|
bucket,
|
||||||
|
count: [4, 6, 3, 9, 5, 7, 4, 11, 8, 6, 9, 5][i],
|
||||||
|
})),
|
||||||
|
revenue: MONTHS.map((bucket, i) => ({
|
||||||
|
bucket,
|
||||||
|
amount: 280_000 + REGISTRATIONS[i] * 9_400,
|
||||||
|
count: SUBMITTED[i],
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
breakdowns: {
|
||||||
|
byStatus: breakdown([
|
||||||
|
['Registered', 1096],
|
||||||
|
['Suspended', 87],
|
||||||
|
['Deregistered', 101],
|
||||||
|
]),
|
||||||
|
byCategory: breakdown([
|
||||||
|
['Inland waterway', 772],
|
||||||
|
['Sea-going', 512],
|
||||||
|
]),
|
||||||
|
byFlagState: breakdown([
|
||||||
|
['Ethiopia', 918], ['Djibouti', 142], ['Panama', 88], ['Liberia', 54],
|
||||||
|
['Marshall Islands', 37], ['Malta', 21], ['Other', 24],
|
||||||
|
]),
|
||||||
|
byPortOfRegistry: breakdown([
|
||||||
|
['Bahir Dar', 286], ['Djibouti', 241], ['Gambella', 198],
|
||||||
|
['Hawassa', 176], ['Arba Minch', 154], ['Tana Kirkos', 121],
|
||||||
|
['Other', 108],
|
||||||
|
]),
|
||||||
|
byVesselType: breakdown([
|
||||||
|
['Passenger ferry', 341], ['Cargo', 289], ['Fishing', 214],
|
||||||
|
['Tug', 132], ['Barge', 118], ['Tanker', 76], ['Research', 41],
|
||||||
|
['Other', 73],
|
||||||
|
]),
|
||||||
|
byHullMaterial: breakdown([
|
||||||
|
['Steel', 612], ['Aluminium', 288], ['Fibreglass', 241],
|
||||||
|
['Wood', 108], ['Composite', 35],
|
||||||
|
]),
|
||||||
|
byEngineType: breakdown([
|
||||||
|
['Diesel', 874], ['Outboard petrol', 246], ['Electric', 87],
|
||||||
|
['Hybrid', 44], ['Sail / none', 33],
|
||||||
|
]),
|
||||||
|
byTonnageBand: breakdown([
|
||||||
|
['< 50 GT', 402], ['50-199 GT', 348], ['200-499 GT', 241],
|
||||||
|
['500-999 GT', 152], ['1000+ GT', 141],
|
||||||
|
]),
|
||||||
|
byLengthBand: breakdown([
|
||||||
|
['< 12 m', 318], ['12-24 m', 421], ['24-50 m', 336],
|
||||||
|
['50-100 m', 148], ['100 m+', 61],
|
||||||
|
]),
|
||||||
|
byAgeBand: breakdown([
|
||||||
|
['0-5 yrs', 214], ['6-10 yrs', 287], ['11-20 yrs', 396],
|
||||||
|
['21-30 yrs', 241], ['30+ yrs', 146],
|
||||||
|
]),
|
||||||
|
byBuildDecade: breakdown([
|
||||||
|
['1980s', 96], ['1990s', 187], ['2000s', 341],
|
||||||
|
['2010s', 452], ['2020s', 208],
|
||||||
|
]),
|
||||||
|
byApplicationStatus: breakdown([
|
||||||
|
['Issued', 337], ['Approved', 14], ['Under review', 113],
|
||||||
|
['Draft', 48], ['Rejected', 62], ['Correction required', 68],
|
||||||
|
]),
|
||||||
|
byApplicationKind: breakdown([
|
||||||
|
['New', 421],
|
||||||
|
['Renewal', 221],
|
||||||
|
]),
|
||||||
|
byOfficer: [
|
||||||
|
{ key: '5f1c1b8e-0001-4a11-9c31-0a1b2c3d4e01', label: 'Selam Bekele', count: 148, percentage: 23.1 },
|
||||||
|
{ key: '5f1c1b8e-0002-4a11-9c31-0a1b2c3d4e02', label: 'Dawit Tesfaye', count: 132, percentage: 20.6 },
|
||||||
|
{ key: '5f1c1b8e-0003-4a11-9c31-0a1b2c3d4e03', label: 'Hanna Girma', count: 117, percentage: 18.2 },
|
||||||
|
{ key: '5f1c1b8e-0004-4a11-9c31-0a1b2c3d4e04', label: 'Yonas Alemu', count: 94, percentage: 14.6 },
|
||||||
|
{ key: '5f1c1b8e-0005-4a11-9c31-0a1b2c3d4e05', label: 'Meron Assefa', count: 78, percentage: 12.1 },
|
||||||
|
{ key: 'UNASSIGNED', label: 'Unassigned', count: 73, percentage: 11.4 },
|
||||||
|
],
|
||||||
|
byIncidentSeverity: breakdown([
|
||||||
|
['Minor', 51], ['Moderate', 28], ['Major', 13], ['Critical', 4],
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
tables: {
|
||||||
|
expiringCertificates: [
|
||||||
|
{ registrationNumber: 'ET-VR-004182', name: 'Abay Star', ownerName: 'Blue Nile Transport PLC', certificateNumber: 'CERT-2023-004182', expiryDate: '2026-08-24', daysToExpiry: 6 },
|
||||||
|
{ registrationNumber: 'ET-VR-003907', name: 'Tana Pearl', ownerName: 'Lake Tana Ferries', certificateNumber: 'CERT-2023-003907', expiryDate: '2026-09-02', daysToExpiry: 15 },
|
||||||
|
{ registrationNumber: 'ET-VR-004411', name: 'Gambella Express', ownerName: 'Baro River Logistics', certificateNumber: 'CERT-2023-004411', expiryDate: '2026-09-11', daysToExpiry: 24 },
|
||||||
|
{ registrationNumber: 'ET-VR-003655', name: 'Awash Carrier', ownerName: 'Awash Marine Services', certificateNumber: 'CERT-2023-003655', expiryDate: '2026-09-19', daysToExpiry: 32 },
|
||||||
|
{ registrationNumber: 'ET-VR-004098', name: 'Rift Valley II', ownerName: 'Hawassa Boat Union', certificateNumber: 'CERT-2023-004098', expiryDate: '2026-10-04', daysToExpiry: 47 },
|
||||||
|
{ registrationNumber: 'ET-VR-004320', name: 'Omo Trader', ownerName: 'Omo Cargo Co.', certificateNumber: 'CERT-2023-004320', expiryDate: '2026-10-18', daysToExpiry: 61 },
|
||||||
|
{ registrationNumber: 'ET-VR-003812', name: 'Zeway Runner', ownerName: 'Zeway Fisheries', certificateNumber: 'CERT-2023-003812', expiryDate: '2026-11-01', daysToExpiry: 75 },
|
||||||
|
{ registrationNumber: 'ET-VR-004501', name: 'Djibouti Link', ownerName: 'Horn Shipping Ltd', certificateNumber: 'CERT-2023-004501', expiryDate: '2026-11-13', daysToExpiry: 87 },
|
||||||
|
].map((row, i) => ({
|
||||||
|
...row,
|
||||||
|
vesselId: `9a0e0000-0000-4000-8000-0000000${1000 + i}`,
|
||||||
|
ownerUserId: `7b1f0000-0000-4000-8000-0000000${2000 + i}`,
|
||||||
|
certificateStatus: 'ACTIVE',
|
||||||
|
})),
|
||||||
|
recentRegistrations: ([
|
||||||
|
{ registrationNumber: 'ET-VR-004612', name: 'Blue Horizon', category: 'SEA_GOING', vesselType: 'Cargo', flagState: 'Ethiopia', grossTonnage: 1840, ownerName: 'Horn Shipping Ltd', status: 'REGISTERED', registeredAt: '2026-08-16T08:20:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004611', name: 'Tana Breeze', category: 'INLAND_WATERWAY', vesselType: 'Passenger ferry', flagState: 'Ethiopia', grossTonnage: 96, ownerName: 'Lake Tana Ferries', status: 'REGISTERED', registeredAt: '2026-08-15T13:05:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004610', name: 'Baro Voyager', category: 'INLAND_WATERWAY', vesselType: 'Barge', flagState: 'Ethiopia', grossTonnage: 240, ownerName: 'Baro River Logistics', status: 'REGISTERED', registeredAt: '2026-08-14T10:41:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004609', name: 'Red Sea Falcon', category: 'SEA_GOING', vesselType: 'Tanker', flagState: 'Djibouti', grossTonnage: 3210, ownerName: 'Horn Shipping Ltd', status: 'SUSPENDED', registeredAt: '2026-08-12T15:32:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004608', name: 'Hawassa Queen', category: 'INLAND_WATERWAY', vesselType: 'Passenger ferry', flagState: 'Ethiopia', grossTonnage: 74, ownerName: 'Hawassa Boat Union', status: 'REGISTERED', registeredAt: '2026-08-11T09:12:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004607', name: 'Omo Spirit', category: 'INLAND_WATERWAY', vesselType: 'Fishing', flagState: 'Ethiopia', grossTonnage: 32, ownerName: 'Omo Cargo Co.', status: 'REGISTERED', registeredAt: '2026-08-09T07:55:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004606', name: 'Awash Pioneer', category: 'SEA_GOING', vesselType: 'Cargo', flagState: 'Panama', grossTonnage: 2105, ownerName: 'Awash Marine Services', status: 'REGISTERED', registeredAt: '2026-08-07T11:26:00.000Z' },
|
||||||
|
{ registrationNumber: 'ET-VR-004605', name: 'Gibe Runner', category: 'INLAND_WATERWAY', vesselType: 'Tug', flagState: 'Ethiopia', grossTonnage: 118, ownerName: 'Gibe Marine PLC', status: 'DEREGISTERED', registeredAt: '2026-08-04T14:03:00.000Z' },
|
||||||
|
] as const).map((row, i) => ({
|
||||||
|
...row,
|
||||||
|
vesselId: `9a0e0000-0000-4000-8000-0000000${3000 + i}`,
|
||||||
|
})),
|
||||||
|
recentIncidents: [
|
||||||
|
{ registrationNumber: 'ET-VR-004182', vesselName: 'Abay Star', occurredAt: '2026-08-15T06:40:00.000Z', severity: 'Moderate', location: 'Lake Tana, near Gorgora', description: 'Engine room flooding after a seal failure; vessel towed to port under escort.', reportedByOfficer: true },
|
||||||
|
{ registrationNumber: 'ET-VR-004609', vesselName: 'Red Sea Falcon', occurredAt: '2026-08-10T18:12:00.000Z', severity: 'Major', location: 'Gulf of Tadjoura', description: 'Collision with a moored barge during night manoeuvring. Hull plating breached above the waterline.', reportedByOfficer: true },
|
||||||
|
{ registrationNumber: 'ET-VR-003907', vesselName: 'Tana Pearl', occurredAt: '2026-08-06T12:30:00.000Z', severity: 'Minor', location: 'Bahir Dar jetty', description: 'Passenger slipped on a wet gangway; treated on shore, no hospitalisation.', reportedByOfficer: false },
|
||||||
|
{ registrationNumber: 'ET-VR-004411', vesselName: 'Gambella Express', occurredAt: '2026-07-29T09:05:00.000Z', severity: 'Moderate', location: 'Baro River, km 42', description: 'Grounded on a sandbar for six hours at low water. No pollution reported.', reportedByOfficer: false },
|
||||||
|
{ registrationNumber: 'ET-VR-004098', vesselName: 'Rift Valley II', occurredAt: '2026-07-21T16:48:00.000Z', severity: 'Critical', location: 'Lake Hawassa, south shore', description: 'Fire in the galley spread to the passenger deck; 3 injured, vessel out of service.', reportedByOfficer: true },
|
||||||
|
{ registrationNumber: 'ET-VR-004320', vesselName: 'Omo Trader', occurredAt: '2026-07-14T05:15:00.000Z', severity: 'Minor', location: 'Omo River delta', description: 'Steering hydraulics lost pressure; repaired at berth the same day.', reportedByOfficer: false },
|
||||||
|
].map((row, i) => ({
|
||||||
|
...row,
|
||||||
|
id: `1c2d0000-0000-4000-8000-0000000${4000 + i}`,
|
||||||
|
vesselId: `9a0e0000-0000-4000-8000-0000000${1000 + i}`,
|
||||||
|
})),
|
||||||
|
pendingApplications: ([
|
||||||
|
{ applicationNumber: 'VR-2026-000841', status: 'UNDER_REVIEW', kind: 'NEW', submittedAt: '2026-08-01T08:00:00.000Z', adjustmentRound: 0, daysOpen: 17 },
|
||||||
|
{ applicationNumber: 'VR-2026-000836', status: 'CORRECTION_REQUIRED', kind: 'RENEWAL', submittedAt: '2026-07-28T10:22:00.000Z', adjustmentRound: 2, daysOpen: 21 },
|
||||||
|
{ applicationNumber: 'VR-2026-000829', status: 'UNDER_REVIEW', kind: 'NEW', submittedAt: '2026-07-24T09:14:00.000Z', adjustmentRound: 1, daysOpen: 25 },
|
||||||
|
{ applicationNumber: 'VR-2026-000818', status: 'RESUBMITTED', kind: 'NEW', submittedAt: '2026-07-19T13:40:00.000Z', adjustmentRound: 1, daysOpen: 30 },
|
||||||
|
{ applicationNumber: 'VR-2026-000804', status: 'UNDER_REVIEW', kind: 'RENEWAL', submittedAt: '2026-07-11T07:52:00.000Z', adjustmentRound: 0, daysOpen: 38 },
|
||||||
|
{ applicationNumber: 'VR-2026-000791', status: 'CORRECTION_REQUIRED', kind: 'NEW', submittedAt: '2026-07-02T15:31:00.000Z', adjustmentRound: 3, daysOpen: 47 },
|
||||||
|
{ applicationNumber: 'VR-2026-000783', status: 'SUBMITTED', kind: 'RENEWAL', submittedAt: '2026-06-26T11:09:00.000Z', adjustmentRound: 0, daysOpen: 53 },
|
||||||
|
] as const).map((row, i) => ({
|
||||||
|
...row,
|
||||||
|
assignedOfficerId:
|
||||||
|
i % 3 === 2 ? null : `5f1c1b8e-000${(i % 5) + 1}-4a11-9c31-0a1b2c3d4e0${(i % 5) + 1}`,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user