From 5161e278cebb1868ec8183228fa869cc6473c9e5 Mon Sep 17 00:00:00 2001 From: Muluhabt Date: Wed, 29 Jul 2026 16:53:50 +0300 Subject: [PATCH 1/2] Adding license generation functionality --- .../analytics/pages/AnalyticsPage.tsx | 266 +--- .../pages/ApplicationReviewPage.tsx | 457 +------ .../features/coc-queue/pages/CoCQueuePage.tsx | 349 +----- .../coc-queue/pages/CoCReviewPage.tsx | 630 +--------- .../pages/CombinedLicenseQueuePage.tsx | 419 ------- .../pages/CombinedLicenseReviewPage.tsx | 306 ----- .../dashboard/pages/DashboardPage.tsx | 557 ++------- .../pages/EndorsementQueuePage.tsx | 329 +---- .../pages/EndorsementReviewPage.tsx | 588 +-------- .../FreightForwarderLicenseQueuePage.tsx | 418 ------- .../FreightForwarderLicenseReviewPage.tsx | 297 ----- .../pages/JointInvestmentLicenseQueuePage.tsx | 414 ------ .../JointInvestmentLicenseReviewPage.tsx | 269 ---- .../license-review/pages/LicenseQueuePage.tsx | 172 +++ .../pages/LicenseReviewPage.tsx | 600 +++++++++ .../pages/LogisticsHeadDashboardPage.tsx | 322 ++--- .../pages/MedicalVerificationPage.tsx | 390 +----- .../mto-license/pages/MtoLicenseQueuePage.tsx | 422 ------- .../pages/MtoLicenseReviewPage.tsx | 323 ----- .../pages/PaymentConfigPage.tsx | 693 +++++------ .../pages/SeafarerRegistryPage.tsx | 402 ++---- .../pages/SeamanBookQueuePage.tsx | 388 +----- .../pages/ShippingAgentLicenseQueuePage.tsx | 419 ------- .../pages/ShippingAgentLicenseReviewPage.tsx | 300 ----- .../VesselRegistrationHeadDashboardPage.tsx | 176 +-- .../VesselOwnershipTransferQueuePage.tsx | 426 +------ .../VesselOwnershipTransferReviewPage.tsx | 345 +---- .../pages/VesselRegistrationQueuePage.tsx | 544 +------- .../pages/VesselRegistrationReportPage.tsx | 246 +--- .../pages/VesselRegistrationReviewPage.tsx | 404 +----- .../features/waiver/pages/WaiverQueuePage.tsx | 459 +------ .../waiver/pages/WaiverReviewPage.tsx | 372 +----- apps/backoffice/src/app/i18n/locales/am.ts | 9 + apps/backoffice/src/app/i18n/locales/en.ts | 9 + .../src/app/layouts/BackofficeLayout.tsx | 110 +- .../src/app/providers/AppProviders.tsx | 6 +- apps/backoffice/src/app/router/index.tsx | 35 +- .../src/app/store/preferences.slice.ts | 4 +- apps/backoffice/vite.config.mts | 10 + .../pages/BasicSafetyTrainingPage.tsx | 455 +------ .../certificates/pages/CertificatesPage.tsx | 283 +---- .../certificates/pages/CoCApplicationPage.tsx | 1105 +---------------- .../pages/CombinedLicenseApplicationPage.tsx | 461 ------- .../pages/CombinedLicensePage.tsx | 218 ---- .../pages/CombinedLicenseRenewalPage.tsx | 146 --- .../dashboard/pages/DashboardPage.tsx | 726 ++++++++--- .../documents/pages/DocumentVaultPage.tsx | 498 +------- .../endorsement/pages/EndorsementPage.tsx | 447 +------ ...FreightForwarderLicenseApplicationPage.tsx | 434 ------- .../pages/FreightForwarderLicensePage.tsx | 215 ---- .../FreightForwarderLicenseRenewalPage.tsx | 144 --- .../JointInvestmentLicenseApplicationPage.tsx | 549 -------- .../pages/JointInvestmentLicensePage.tsx | 186 --- .../JointInvestmentLicenseRenewalPage.tsx | 36 - .../components/ConfigDrivenSection.tsx | 123 ++ .../licensing/components/DocumentSlots.tsx | 183 +++ .../licensing/components/LicenseCatalogue.tsx | 229 ++++ .../licensing/components/StaffEvidence.tsx | 81 ++ .../pages/LicenseApplicationPage.tsx | 637 ++++++++++ .../licensing/pages/MyApplicationsPage.tsx | 286 +++++ .../pages/LogisticsDashboardPage.tsx | 164 --- .../medical/pages/MedicalCertificatePage.tsx | 346 +----- .../pages/MtoLicenseApplicationPage.tsx | 705 ----------- .../mto-license/pages/MtoLicensePage.tsx | 230 ---- .../pages/MtoLicenseRenewalPage.tsx | 151 --- .../notifications/pages/NotificationsPage.tsx | 374 ++---- .../payments/hooks/useApplicationPayment.ts | 70 ++ .../payments/pages/PaymentCheckPage.tsx | 129 ++ .../payments/pages/PaymentFailurePage.tsx | 51 + .../payments/pages/PaymentSuccessPage.tsx | 77 ++ .../profile-setup/pages/ProfileSetupPage.tsx | 14 +- .../profile/components/AddressFormContent.tsx | 4 +- .../features/profile/pages/ProfilePage.tsx | 5 +- .../pages/SeamanBookApplicationPage.tsx | 666 +--------- .../seaman-book/pages/SeamanBookPage.tsx | 321 +---- .../ShippingAgentLicenseApplicationPage.tsx | 484 -------- .../pages/ShippingAgentLicensePage.tsx | 216 ---- .../pages/ShippingAgentLicenseRenewalPage.tsx | 146 --- .../pages/VesselOwnerDashboardPage.tsx | 125 +- .../pages/OwnershipTransferPage.tsx | 451 +------ .../waiver/pages/WaiverApplicationPage.tsx | 494 -------- .../app/features/waiver/pages/WaiverPage.tsx | 233 +--- apps/portal/src/app/i18n/locales/am.ts | 10 + apps/portal/src/app/i18n/locales/en.ts | 10 + apps/portal/src/app/layouts/PortalLayout.tsx | 82 +- .../portal/src/app/providers/AppProviders.tsx | 10 +- apps/portal/src/app/router.tsx | 90 +- libs/api/src/index.ts | 1 + libs/api/src/lib/features/licensing/index.ts | 3 + .../lib/features/licensing/licensing-api.ts | 434 +++++++ .../features/licensing/licensing.helpers.ts | 341 +++++ .../lib/features/licensing/licensing.types.ts | 336 +++++ libs/auth/src/index.ts | 1 + .../auth/src/lib/components/AuthBootstrap.tsx | 70 ++ libs/auth/src/lib/pages/LoginPage.tsx | 13 +- .../src/lib/pages/OTPVerificationPage.tsx | 7 +- libs/auth/src/lib/pages/SignupPage.tsx | 3 +- libs/auth/src/lib/types/auth.types.ts | 2 +- libs/auth/src/lib/utils/refresh-token.ts | 4 +- libs/ui/src/index.ts | 1 + .../src/lib/feedback/FeatureUnavailable.tsx | 45 + libs/ui/src/lib/layout/AppSidebar.tsx | 75 +- 102 files changed, 5995 insertions(+), 21326 deletions(-) delete mode 100644 apps/backoffice/src/app/features/combined-license/pages/CombinedLicenseQueuePage.tsx delete mode 100644 apps/backoffice/src/app/features/combined-license/pages/CombinedLicenseReviewPage.tsx delete mode 100644 apps/backoffice/src/app/features/freight-forwarder-license/pages/FreightForwarderLicenseQueuePage.tsx delete mode 100644 apps/backoffice/src/app/features/freight-forwarder-license/pages/FreightForwarderLicenseReviewPage.tsx delete mode 100644 apps/backoffice/src/app/features/joint-investment-license/pages/JointInvestmentLicenseQueuePage.tsx delete mode 100644 apps/backoffice/src/app/features/joint-investment-license/pages/JointInvestmentLicenseReviewPage.tsx create mode 100644 apps/backoffice/src/app/features/license-review/pages/LicenseQueuePage.tsx create mode 100644 apps/backoffice/src/app/features/license-review/pages/LicenseReviewPage.tsx delete mode 100644 apps/backoffice/src/app/features/mto-license/pages/MtoLicenseQueuePage.tsx delete mode 100644 apps/backoffice/src/app/features/mto-license/pages/MtoLicenseReviewPage.tsx delete mode 100644 apps/backoffice/src/app/features/shipping-agent-license/pages/ShippingAgentLicenseQueuePage.tsx delete mode 100644 apps/backoffice/src/app/features/shipping-agent-license/pages/ShippingAgentLicenseReviewPage.tsx delete mode 100644 apps/portal/src/app/features/combined-license/pages/CombinedLicenseApplicationPage.tsx delete mode 100644 apps/portal/src/app/features/combined-license/pages/CombinedLicensePage.tsx delete mode 100644 apps/portal/src/app/features/combined-license/pages/CombinedLicenseRenewalPage.tsx delete mode 100644 apps/portal/src/app/features/freight-forwarder-license/pages/FreightForwarderLicenseApplicationPage.tsx delete mode 100644 apps/portal/src/app/features/freight-forwarder-license/pages/FreightForwarderLicensePage.tsx delete mode 100644 apps/portal/src/app/features/freight-forwarder-license/pages/FreightForwarderLicenseRenewalPage.tsx delete mode 100644 apps/portal/src/app/features/joint-investment-license/pages/JointInvestmentLicenseApplicationPage.tsx delete mode 100644 apps/portal/src/app/features/joint-investment-license/pages/JointInvestmentLicensePage.tsx delete mode 100644 apps/portal/src/app/features/joint-investment-license/pages/JointInvestmentLicenseRenewalPage.tsx create mode 100644 apps/portal/src/app/features/licensing/components/ConfigDrivenSection.tsx create mode 100644 apps/portal/src/app/features/licensing/components/DocumentSlots.tsx create mode 100644 apps/portal/src/app/features/licensing/components/LicenseCatalogue.tsx create mode 100644 apps/portal/src/app/features/licensing/components/StaffEvidence.tsx create mode 100644 apps/portal/src/app/features/licensing/pages/LicenseApplicationPage.tsx create mode 100644 apps/portal/src/app/features/licensing/pages/MyApplicationsPage.tsx delete mode 100644 apps/portal/src/app/features/logistics-dashboard/pages/LogisticsDashboardPage.tsx delete mode 100644 apps/portal/src/app/features/mto-license/pages/MtoLicenseApplicationPage.tsx delete mode 100644 apps/portal/src/app/features/mto-license/pages/MtoLicensePage.tsx delete mode 100644 apps/portal/src/app/features/mto-license/pages/MtoLicenseRenewalPage.tsx create mode 100644 apps/portal/src/app/features/payments/hooks/useApplicationPayment.ts create mode 100644 apps/portal/src/app/features/payments/pages/PaymentCheckPage.tsx create mode 100644 apps/portal/src/app/features/payments/pages/PaymentFailurePage.tsx create mode 100644 apps/portal/src/app/features/payments/pages/PaymentSuccessPage.tsx delete mode 100644 apps/portal/src/app/features/shipping-agent-license/pages/ShippingAgentLicenseApplicationPage.tsx delete mode 100644 apps/portal/src/app/features/shipping-agent-license/pages/ShippingAgentLicensePage.tsx delete mode 100644 apps/portal/src/app/features/shipping-agent-license/pages/ShippingAgentLicenseRenewalPage.tsx delete mode 100644 apps/portal/src/app/features/waiver/pages/WaiverApplicationPage.tsx create mode 100644 libs/api/src/lib/features/licensing/index.ts create mode 100644 libs/api/src/lib/features/licensing/licensing-api.ts create mode 100644 libs/api/src/lib/features/licensing/licensing.helpers.ts create mode 100644 libs/api/src/lib/features/licensing/licensing.types.ts create mode 100644 libs/auth/src/lib/components/AuthBootstrap.tsx create mode 100644 libs/ui/src/lib/feedback/FeatureUnavailable.tsx diff --git a/apps/backoffice/src/app/features/analytics/pages/AnalyticsPage.tsx b/apps/backoffice/src/app/features/analytics/pages/AnalyticsPage.tsx index ff3d66a02..070d83e42 100644 --- a/apps/backoffice/src/app/features/analytics/pages/AnalyticsPage.tsx +++ b/apps/backoffice/src/app/features/analytics/pages/AnalyticsPage.tsx @@ -1,255 +1,21 @@ -import { - Badge, - Button, - Card, - Divider, - Group, - Paper, - Progress, - SimpleGrid, - Stack, - Table, - Text, - ThemeIcon, - Title, - rem, -} from '@mantine/core'; -import { - IconBook2, - IconCertificate, - IconChartBar, - IconDownload, - IconHeart, - IconId, - IconShieldCheck, - IconTrendingUp, - IconUsers, -} from '@tabler/icons-react'; +import { Container } from '@mantine/core'; +import { FeatureUnavailable } from '@ema-platform/ui'; -// --------------------------------------------------------------------------- -// Mock statistics -// --------------------------------------------------------------------------- -const KPI = [ - { label: 'Total Seafarers', value: 1284, delta: '+12 this month', color: 'blue', icon: IconUsers }, - { label: 'Seaman Books Issued', value: 1102, delta: '85.8% of total', color: 'teal', icon: IconBook2 }, - { label: 'BTC Issued', value: 1098, delta: '85.5% of total', color: 'teal', icon: IconCertificate }, - { label: 'BSID Issued', value: 874, delta: '68.1% of total', color: 'violet', icon: IconId }, - { label: 'CoC / CoP Issued', value: 342, delta: '26.6% of total', color: 'orange', icon: IconShieldCheck }, - { label: 'Medical Expiring (90d)',value: 41, delta: 'Action required', color: 'red', icon: IconHeart }, -]; - -const MONTHLY_APPS = [ - { month: 'Jan', seamanBook: 18, coc: 4 }, - { month: 'Feb', seamanBook: 22, coc: 6 }, - { month: 'Mar', seamanBook: 28, coc: 9 }, - { month: 'Apr', seamanBook: 31, coc: 12 }, - { month: 'May', seamanBook: 26, coc: 8 }, - { month: 'Jun', seamanBook: 35, coc: 14 }, -]; - -const CERT_DISTRIBUTION = [ - { label: 'Seaman Book', count: 1102, pct: 86, color: 'blue' }, - { label: 'Basic Training Cert', count: 1098, pct: 85, color: 'teal' }, - { label: 'BSID', count: 874, pct: 68, color: 'violet' }, - { label: 'CoC / CoP', count: 342, pct: 27, color: 'orange' }, -]; - -const REVENUE = [ - { cert: 'Seaman Book', apps: 1102, feePerApp: 700, revenue: 771400 }, - { cert: 'BTC', apps: 1098, feePerApp: 400, revenue: 439200 }, - { cert: 'BSID', apps: 874, feePerApp: 250, revenue: 218500 }, - { cert: 'CoC / CoP', apps: 342, feePerApp: 1400, revenue: 478800 }, -]; -const TOTAL_REVENUE = REVENUE.reduce((s, r) => s + r.revenue, 0); - -const EXPIRY_WATCH = [ - { cert: 'Seaman Book', expiring30: 8, expiring90: 23, total: 1102 }, - { cert: 'BTC', expiring30: 6, expiring90: 19, total: 1098 }, - { cert: 'Medical Cert', expiring30: 12, expiring90: 41, total: 1284 }, - { cert: 'CoC / CoP', expiring30: 4, expiring90: 17, total: 342 }, -]; - -// --------------------------------------------------------------------------- -// Components -// --------------------------------------------------------------------------- -function KpiCard({ label, value, delta, color, icon: Icon }: typeof KPI[0]) { - return ( - - - - {value.toLocaleString()} - - {label} - {delta} - - ); -} - -// Simple bar chart using divs -function BarChart() { - const max = Math.max(...MONTHLY_APPS.map((m) => m.seamanBook + m.coc)); - return ( - - {MONTHLY_APPS.map((m) => ( - - {m.month} -
-
-
-
- {m.seamanBook + m.coc} - - ))} - -
Seaman Book -
CoC / CoP - - - ); -} - -// --------------------------------------------------------------------------- -// Main page -// --------------------------------------------------------------------------- +/** + * Placeholder until this feature has a backend. + * + * This page previously rendered invented figures/records that were + * indistinguishable from real ones. + */ export function AnalyticsPage() { return ( - - -
- Analytics & Reports - Overview of seafarer registrations, certificate issuance, and revenue — mock data for demonstration -
- -
- - {/* KPIs */} - - {KPI.map((k) => )} - - - - {/* Monthly applications bar chart */} - - - - - Monthly Applications (2025) - - - - - - {/* Certificate distribution */} - - - - Certificate Distribution - - - {CERT_DISTRIBUTION.map((c) => ( -
- - - {c.label} - - - {c.count.toLocaleString()} - {c.pct}% - - - -
- ))} -
-
-
- - {/* Revenue breakdown */} - - - Revenue Breakdown by Certificate Type - Total: ETB {TOTAL_REVENUE.toLocaleString()} - - - - - {['Certificate Type', 'Applications', 'Fee per App', 'Total Revenue', '% of Revenue'].map((h) => ( - {h} - ))} - - - - {REVENUE.map((r) => ( - - {r.cert} - {r.apps.toLocaleString()} - ETB {r.feePerApp.toLocaleString()} - ETB {r.revenue.toLocaleString()} - - - - {((r.revenue / TOTAL_REVENUE) * 100).toFixed(1)}% - - - - ))} - - - - Total - {REVENUE.reduce((s, r) => s + r.apps, 0).toLocaleString()} - - ETB {TOTAL_REVENUE.toLocaleString()} - - - -
-
- - {/* Expiry watchlist */} - - - - Expiry Watchlist - - - - - {['Certificate', 'Total Issued', 'Expiring in 30 days', 'Expiring in 90 days', '% at Risk'].map((h) => ( - {h} - ))} - - - - {EXPIRY_WATCH.map((e) => ( - - {e.cert} - {e.total.toLocaleString()} - - 5 ? 'red' : 'orange'} variant="light" size="sm">{e.expiring30} - - - 20 ? 'orange' : 'yellow'} variant="light" size="sm">{e.expiring90} - - - - 0.1 ? 'red' : 'orange'} - size="sm" - radius="xl" - style={{ flex: 1, minWidth: 60 }} - /> - {((e.expiring90 / e.total) * 100).toFixed(1)}% - - - - ))} - -
-
-
+ + + ); } + +export default AnalyticsPage; diff --git a/apps/backoffice/src/app/features/applications/pages/ApplicationReviewPage.tsx b/apps/backoffice/src/app/features/applications/pages/ApplicationReviewPage.tsx index 1ec7115d0..344cbd856 100644 --- a/apps/backoffice/src/app/features/applications/pages/ApplicationReviewPage.tsx +++ b/apps/backoffice/src/app/features/applications/pages/ApplicationReviewPage.tsx @@ -1,446 +1,21 @@ -import { useState } from 'react'; -import { - ActionIcon, - Alert, - Badge, - Box, - Button, - Card, - Divider, - Group, - Modal, - Paper, - SimpleGrid, - Stack, - Tabs, - Text, - Textarea, - ThemeIcon, - Title, - rem, -} from '@mantine/core'; -import { - IconAlertTriangle, - IconArrowLeft, - IconBook2, - IconCertificate, - IconCheck, - IconCircleCheck, - IconCreditCard, - IconExternalLink, - IconEye, - IconFileDescription, - IconHeart, - IconInfoCircle, - IconShieldCheck, - IconUser, - IconX, -} from '@tabler/icons-react'; -import { useNavigate } from 'react-router-dom'; -import { notify } from '@ema-platform/ui'; +import { Container } from '@mantine/core'; +import { FeatureUnavailable } from '@ema-platform/ui'; -// --------------------------------------------------------------------------- -// Mock data -// --------------------------------------------------------------------------- -const FEES = [ - { group: 'Seaman Book', label: 'Application Fee', amount: 500 }, - { group: 'Seaman Book', label: 'Document Verification Fee', amount: 200 }, - { group: 'Basic Training Certificate (BTC)', label: 'Application Fee', amount: 300 }, - { group: 'Basic Training Certificate (BTC)', label: 'Document Verification Fee',amount: 100 }, - { group: 'BSID', label: 'Application Fee', amount: 100 }, -]; -const TOTAL = FEES.reduce((s, f) => s + f.amount, 0); - -const MOCK_APPLICATION = { - id: 'SB-APP-2025-001', - submittedAt: '2025-05-10', - status: 'pending_review' as const, - applicant: { - fullName: 'Abebe Girma Tadesse', - dob: '1990-04-15', - nationality: 'Ethiopian', - idNumber: 'ID-ETH-2024-001', - phone: '+251 91 234 5678', - email: 'abebe.girma@email.com', - address: 'Bole, Addis Ababa, Ethiopia', - height: '178 cm', - bloodType: 'O+', - hairColor: 'Black', - eyeColor: 'Dark Brown', - seafarerNumber: 'SEAF-2024-00142', - }, - bst: [ - { key: 'pst', short: 'PST', label: 'Personal Survival Techniques', certNumber: 'PST-2024-001', issuer: 'Bahirdar Maritime Training School', issueDate: '2024-01-15', expiryDate: '2029-01-15', fileName: 'pst_cert.pdf', fileType: 'pdf' }, - { key: 'fpff', short: 'FPFF', label: 'Fire Prevention & Fire Fighting', certNumber: 'FPFF-2024-002', issuer: 'Bahirdar Maritime Training School', issueDate: '2024-01-16', expiryDate: '2029-01-16', fileName: 'fpff_cert.pdf', fileType: 'pdf' }, - { key: 'efa', short: 'EFA', label: 'Elementary First Aid', certNumber: 'EFA-2024-003', issuer: 'EMA Training Centre', issueDate: '2024-02-01', expiryDate: '', fileName: 'efa_cert.jpg', fileType: 'image' }, - { key: 'pssr', short: 'PSSR', label: 'Personal Safety & Social Responsibility', certNumber: 'PSSR-2024-004', issuer: 'EMA Training Centre', issueDate: '2024-02-02', expiryDate: '', fileName: 'pssr_cert.jpg', fileType: 'image' }, - { key: 'shpt', short: 'SHPT', label: 'Sexual Harassment Prevention Training', certNumber: 'SHPT-2024-005', issuer: 'EMA Training Centre', issueDate: '2024-02-03', expiryDate: '', fileName: 'shpt_cert.jpg', fileType: 'image' }, - ], - medical: { - certNumber: 'MC-2024-009', - issuer: 'EMA Medical Centre — Addis Ababa', - issueDate: '2024-03-20', - expiryDate: '2026-03-20', - fileName: 'medical_cert.pdf', - fileType: 'pdf', - }, - payment: { - method: 'CBE Bank Transfer', - ref: 'CBE-TXN-20240510-001', - date: '2025-05-10', - status: 'confirmed' as 'confirmed' | 'pending' | 'rejected', - receiptFileName: 'payment_receipt.pdf', - receiptFileType: 'pdf', - }, -}; - -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- -const STATUS_COLOR: Record = { - pending_review: 'yellow', approved: 'teal', correction_required: 'orange', rejected: 'red', -}; -const STATUS_LABEL: Record = { - pending_review: 'Pending Review', approved: 'Approved', correction_required: 'Correction Required', rejected: 'Rejected', -}; -const PAYMENT_COLOR = { confirmed: 'teal', pending: 'yellow', rejected: 'red' } as const; - -const DEMO_PDF = 'data:application/pdf;base64,JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoKMiAwIG9iago8PC9UeXBlL1BhZ2VzL0tpZHNbMyAwIFJdL0NvdW50IDE+PgplbmRvYmoKMyAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDIgMCBSL01lZGlhQm94WzAgMCA2MTIgNzkyXT4+CmVuZG9iagp4cmVmCjAgNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDkgMDAwMDAgbiAKMDAwMDAwMDA1OCAwMDAwMCBuIAowMDAwMDAwMTE1IDAwMDAwIG4gCnRyYWlsZXIKPDwvU2l6ZSA0L1Jvb3QgMSAwIFI+PgpzdGFydHhyZWYKMjIwCiUlRU9G'; - -function getDocUrl(fileName: string) { - return fileName.endsWith('.pdf') ? DEMO_PDF : `https://placehold.co/600x400/e9ecef/6c757d?text=${encodeURIComponent(fileName)}`; -} - -// --------------------------------------------------------------------------- -// Inline document viewer -// --------------------------------------------------------------------------- -function DocViewer({ fileName, fileType, label }: { fileName: string; fileType: string; label: string }) { - const [open, setOpen] = useState(false); - const url = getDocUrl(fileName); - return ( - <> - - - - - -
- {label} - {fileName} -
- {fileType.toUpperCase()} -
- - {fileType === 'pdf' - ?