mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-07 20:05:42 +00:00
Adding license generation functionality
This commit is contained in:
@@ -5,7 +5,7 @@ import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { logout } from '@ema-platform/auth';
|
||||
import { AppHeader, AppSidebar } from '@ema-platform/ui';
|
||||
import type { NavItem } from '@ema-platform/ui';
|
||||
import type { NavItem, NavSection } from '@ema-platform/ui';
|
||||
import {
|
||||
IconBook2,
|
||||
IconChartBar,
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
IconGauge,
|
||||
IconShieldOff,
|
||||
IconShip,
|
||||
IconMapPin,
|
||||
IconStack2,
|
||||
IconTruck,
|
||||
} from '@tabler/icons-react';
|
||||
@@ -34,36 +35,66 @@ import { notify } from '@ema-platform/ui';
|
||||
import { SUPPORTED_LANGUAGES } from '../i18n/config';
|
||||
import { useAppDispatch, useAppSelector } from '../store/hooks';
|
||||
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ to: '/dashboard', label: 'nav.dashboard', icon: IconLayoutDashboard },
|
||||
{ to: '/um/user-management/dashboard', label: 'nav.userManagement', icon: IconUserShield },
|
||||
{ to: '/seaman-book-queue', label: 'nav.seamanBookQueue', icon: IconBook2 },
|
||||
{ to: '/vessel-registration-head-dashboard', label: 'nav.vesselRegistrationHeadDashboard', icon: IconGauge },
|
||||
{ to: '/vessel-registration-queue', label: 'nav.vesselRegistrationQueue', icon: IconAnchor },
|
||||
{ to: '/vessel-registration-queue/new', label: 'nav.vesselFormBuilder', icon: IconFilePlus },
|
||||
{ to: '/vessel-registration-report', label: 'nav.vesselRegistrationReport', icon: IconChartBar },
|
||||
{ to: '/vessel-ownership-transfer', label: 'nav.ownershipTransferQueue', icon: IconFileDescription },
|
||||
{ to: '/logistics-head-dashboard', label: 'nav.logisticsHeadDashboard', icon: IconGauge },
|
||||
{ to: '/freight-forwarder-license', label: 'nav.freightForwarderLicense', icon: IconTruck },
|
||||
{ to: '/shipping-agent-license', label: 'nav.shippingAgentLicense', icon: IconShip },
|
||||
{ to: '/combined-license', label: 'nav.combinedLicense', icon: IconStack2 },
|
||||
{ to: '/joint-investment-license', label: 'nav.jointInvestmentLicense', icon: IconUsers },
|
||||
{ to: '/mto-license', label: 'nav.mtoLicense', icon: IconTruck },
|
||||
{ to: '/waiver', label: 'nav.waiver', icon: IconShieldOff },
|
||||
{ to: '/coc-queue', label: 'nav.cocQueue', icon: IconShieldCheck },
|
||||
{ to: '/endorsement-queue', label: 'nav.endorsementQueue', icon: IconRubberStamp },
|
||||
{ to: '/seafarer-registry', label: 'nav.seafarerRegistry', icon: IconUsers },
|
||||
{ to: '/applications', label: 'nav.applications', icon: IconFileDescription },
|
||||
{ to: '/payment-config', label: 'nav.paymentConfig', icon: IconCreditCard },
|
||||
{ to: '/analytics', label: 'nav.analytics', icon: IconChartBar },
|
||||
{ to: '/medical-verification', label: 'nav.medicalVerification', icon: IconHeart },
|
||||
{ to: '/questions', label: 'nav.questions', icon: IconQuestionMark },
|
||||
{ to: '/exams', label: 'nav.exams', icon: IconClipboardList },
|
||||
{ to: '/exam-results', label: 'nav.examResults', icon: IconReport },
|
||||
{ to: '/configuration', label: 'nav.configuration', icon: IconSettings },
|
||||
{ to: '/profile', label: 'nav.profile', icon: IconUser },
|
||||
/**
|
||||
* Grouped so a reviewer can find things, and flagged so they can tell what
|
||||
* actually works: `soon` marks screens with no backend behind them yet.
|
||||
*/
|
||||
const NAV_SECTIONS: NavSection[] = [
|
||||
{
|
||||
items: [{ to: '/dashboard', label: 'nav.dashboard', icon: IconLayoutDashboard }],
|
||||
},
|
||||
{
|
||||
label: 'nav.groupLicensing',
|
||||
items: [
|
||||
{ to: '/licence-review', label: 'nav.licenceReview', icon: IconTruck },
|
||||
{ to: '/logistics-head-dashboard', label: 'nav.logisticsHeadDashboard', icon: IconGauge },
|
||||
{ to: '/payment-config', label: 'nav.paymentConfig', icon: IconCreditCard },
|
||||
{ to: '/waiver', label: 'nav.waiver', icon: IconShieldOff, soon: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'nav.groupSeafarer',
|
||||
items: [
|
||||
{ to: '/seafarer-registry', label: 'nav.seafarerRegistry', icon: IconUsers },
|
||||
{ to: '/coc-queue', label: 'nav.cocQueue', icon: IconShieldCheck, soon: true },
|
||||
{ to: '/seaman-book-queue', label: 'nav.seamanBookQueue', icon: IconBook2, soon: true },
|
||||
{ to: '/endorsement-queue', label: 'nav.endorsementQueue', icon: IconRubberStamp, soon: true },
|
||||
{ to: '/medical-verification', label: 'nav.medicalVerification', icon: IconHeart, soon: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'nav.groupExaminations',
|
||||
items: [
|
||||
{ to: '/questions', label: 'nav.questions', icon: IconQuestionMark },
|
||||
{ to: '/exams', label: 'nav.exams', icon: IconClipboardList },
|
||||
{ to: '/exam-results', label: 'nav.examResults', icon: IconReport },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'nav.groupVessels',
|
||||
items: [
|
||||
{ to: '/vessel-registration-queue', label: 'nav.vesselRegistrationQueue', icon: IconAnchor, soon: true },
|
||||
{ to: '/vessel-ownership-transfer', label: 'nav.ownershipTransferQueue', icon: IconFileDescription, soon: true },
|
||||
{ to: '/vessel-registration-queue/new', label: 'nav.vesselFormBuilder', icon: IconFilePlus, soon: true },
|
||||
{ to: '/vessel-registration-report', label: 'nav.vesselRegistrationReport', icon: IconChartBar, soon: true },
|
||||
{ to: '/vessel-registration-head-dashboard', label: 'nav.vesselRegistrationHeadDashboard', icon: IconGauge, soon: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'nav.groupAdministration',
|
||||
items: [
|
||||
{ to: '/um/user-management/dashboard', label: 'nav.userManagement', icon: IconUserShield },
|
||||
{ to: '/configuration', label: 'nav.configuration', icon: IconSettings },
|
||||
{ to: '/locations', label: 'nav.locations', icon: IconMapPin },
|
||||
{ to: '/analytics', label: 'nav.analytics', icon: IconChartBar, soon: true },
|
||||
{ to: '/profile', label: 'nav.profile', icon: IconUser },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/** Flat list used for breadcrumbs and active-route lookup. */
|
||||
const NAV_ITEMS: NavItem[] = NAV_SECTIONS.flatMap((section) => section.items);
|
||||
|
||||
const HEADER_HEIGHT = 116;
|
||||
|
||||
export function BackofficeLayout() {
|
||||
@@ -87,13 +118,28 @@ export function BackofficeLayout() {
|
||||
}, [dispatch, navigate]);
|
||||
|
||||
const segments = location.pathname.split('/').filter(Boolean);
|
||||
// Label each crumb from the nav item it corresponds to, falling back to a
|
||||
// readable form of the path segment. Every crumb was previously labelled
|
||||
// "Dashboard", which made the trail useless.
|
||||
const crumbs = [
|
||||
{ label: t('nav.dashboard'), path: '/dashboard' },
|
||||
...segments
|
||||
.map((_, i) => '/' + segments.slice(0, i + 1).join('/'))
|
||||
.filter((path) => path !== '/dashboard')
|
||||
.filter((path) => !path.startsWith('/um'))
|
||||
.map((path) => ({ label: t('nav.dashboard'), path })),
|
||||
.map((path) => {
|
||||
const match = NAV_ITEMS.find((item) => item.to === path);
|
||||
if (match) return { label: t(match.label), path };
|
||||
const segment = path.split('/').pop() ?? '';
|
||||
// Ids get a generic label rather than a raw uuid in the trail.
|
||||
const isId = /^[0-9a-f-]{8,}$/i.test(segment) || /^\d+$/.test(segment);
|
||||
return {
|
||||
label: isId
|
||||
? t('nav.details', 'Details')
|
||||
: segment.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()),
|
||||
path,
|
||||
};
|
||||
}),
|
||||
];
|
||||
|
||||
const go = (item: NavItem) => {
|
||||
@@ -164,7 +210,9 @@ export function BackofficeLayout() {
|
||||
<button
|
||||
key={item.to}
|
||||
onClick={() => go(item)}
|
||||
title={item.soon ? `${t(item.label)} — ${t('nav.soon', 'Soon')}` : undefined}
|
||||
style={{
|
||||
opacity: item.soon ? 0.55 : 1,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: rem(6),
|
||||
@@ -214,7 +262,7 @@ export function BackofficeLayout() {
|
||||
}}
|
||||
>
|
||||
<AppSidebar
|
||||
navItems={NAV_ITEMS}
|
||||
navItems={NAV_SECTIONS}
|
||||
collapsed={collapsed}
|
||||
activePath={location.pathname}
|
||||
onToggleCollapse={handleToggleCollapse}
|
||||
|
||||
Reference in New Issue
Block a user