From 6330c9ea5505a2bed2dc8362132a6265c7496648 Mon Sep 17 00:00:00 2001 From: Estifo77 <139631617+Estifo77@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:25:30 +0300 Subject: [PATCH] applying loader on pages --- .../dashboard/pages/DashboardPage/index.tsx | 8 +--- .../features/exam/pages/ExamDetailPage.tsx | 7 +--- .../pages/CertificatesPage/index.tsx | 13 ++++--- .../dashboard/pages/DashboardPage/index.tsx | 8 +--- .../endorsement/pages/EndorsementPage.tsx | 8 +--- .../features/exams/pages/ExamsPage/index.tsx | 8 +--- .../pages/LicenseApplicationPage.tsx | 8 +--- .../components/RequireOperations.tsx | 14 ++----- .../components/RequireSeafarerProfile.tsx | 14 ++----- .../auth/src/lib/components/AuthBootstrap.tsx | 2 +- .../ui/src/lib/theme/maritime-loader-theme.ts | 38 +++++++++++++------ 11 files changed, 53 insertions(+), 75 deletions(-) diff --git a/apps/backoffice/src/app/features/dashboard/pages/DashboardPage/index.tsx b/apps/backoffice/src/app/features/dashboard/pages/DashboardPage/index.tsx index 443b66eae..927ca47a3 100644 --- a/apps/backoffice/src/app/features/dashboard/pages/DashboardPage/index.tsx +++ b/apps/backoffice/src/app/features/dashboard/pages/DashboardPage/index.tsx @@ -11,7 +11,7 @@ import { } from '@mantine/core'; import { IconChevronRight } from '@tabler/icons-react'; import { useGetAssignedToMeQuery, useGetQueueQuery } from '@ema-platform/api'; -import { AdvancedTable, useServerTable } from '@ema-platform/ui'; +import { AdvancedTable, PageLoader, useServerTable } from '@ema-platform/ui'; import { dashboardQueueColumns } from './columns'; /** @@ -28,11 +28,7 @@ export function DashboardPage() { const table = useServerTable(); if (queue.isLoading || mine.isLoading) { - return ( -
- -
- ); + return ; } const unclaimed = queue.data?.items ?? []; diff --git a/apps/backoffice/src/app/features/exam/pages/ExamDetailPage.tsx b/apps/backoffice/src/app/features/exam/pages/ExamDetailPage.tsx index e49efe907..6c09dd93b 100644 --- a/apps/backoffice/src/app/features/exam/pages/ExamDetailPage.tsx +++ b/apps/backoffice/src/app/features/exam/pages/ExamDetailPage.tsx @@ -54,6 +54,7 @@ import { QuestionAssigner } from '../components/QuestionAssigner'; import { RecordResultModal } from '../../result/components/RecordResultModal'; import { ExamCandidatesPanel } from '../components/ExamCandidatesPanel'; import { ExamIncidentsPanel } from '../components/ExamIncidentsPanel'; +import { PageLoader } from '@ema-platform/ui'; import type { ExamStatus, QuestionBrief } from '../types/exam'; const STATUS_COLOR: Record = { @@ -129,11 +130,7 @@ export function ExamDetailPage() { }, [allQuestions, exam?.certificationId, exam?.form]); if (isLoading) - return ( -
- -
- ); + return ; if (isError || !exam) { return ( diff --git a/apps/portal/src/app/features/certificates/pages/CertificatesPage/index.tsx b/apps/portal/src/app/features/certificates/pages/CertificatesPage/index.tsx index 42ab94351..bdba090ea 100644 --- a/apps/portal/src/app/features/certificates/pages/CertificatesPage/index.tsx +++ b/apps/portal/src/app/features/certificates/pages/CertificatesPage/index.tsx @@ -31,7 +31,12 @@ import { useGetMySeaTimeQuery, } from '@ema-platform/api'; import { useCurrentProfile, usePermissions } from '@ema-platform/auth'; -import { AdvancedTable, notify, useServerTable } from '@ema-platform/ui'; +import { + AdvancedTable, + PageLoader, + notify, + useServerTable, +} from '@ema-platform/ui'; import { useDateDisplayer } from '@ema-platform/shared'; import { certificateColumns } from './columns'; @@ -107,11 +112,7 @@ export function CertificatesPage() { } if (loadingProfile || loadingApplications) { - return ( - - - - ); + return ; } const pagedIssued = issuedTable.paginate(issued); diff --git a/apps/portal/src/app/features/dashboard/pages/DashboardPage/index.tsx b/apps/portal/src/app/features/dashboard/pages/DashboardPage/index.tsx index f7ed4a652..17f44e7c4 100644 --- a/apps/portal/src/app/features/dashboard/pages/DashboardPage/index.tsx +++ b/apps/portal/src/app/features/dashboard/pages/DashboardPage/index.tsx @@ -36,7 +36,7 @@ import { useGetMyApplicationsQuery, useGetMyLicensesQuery, } from '@ema-platform/api'; -import { AdvancedTable, useServerTable } from '@ema-platform/ui'; +import { AdvancedTable, PageLoader, useServerTable } from '@ema-platform/ui'; import type { IssuedLicense, LicenseApplication } from '@ema-platform/api'; import { LicenseCatalogue } from '../../../licensing/components/LicenseCatalogue'; import { LicenseCard, useRenewLicense } from '../../../licensing/components/LicenseCard'; @@ -108,11 +108,7 @@ export function DashboardPage() { } if (isLoading) { - return ( -
- -
- ); + return ; } return ( diff --git a/apps/portal/src/app/features/endorsement/pages/EndorsementPage.tsx b/apps/portal/src/app/features/endorsement/pages/EndorsementPage.tsx index ac7ae28d1..fa33be9d1 100644 --- a/apps/portal/src/app/features/endorsement/pages/EndorsementPage.tsx +++ b/apps/portal/src/app/features/endorsement/pages/EndorsementPage.tsx @@ -31,7 +31,7 @@ import { useGetMyLicensesQuery, } from '@ema-platform/api'; import { useCurrentProfile } from '@ema-platform/auth'; -import { notify } from '@ema-platform/ui'; +import { PageLoader, notify } from '@ema-platform/ui'; import { useDateDisplayer } from '@ema-platform/shared'; const ENDORSEMENT_TYPE_KEYS = ['ENDORSEMENT_COC', 'ENDORSEMENT_GOC']; @@ -94,11 +94,7 @@ export function EndorsementPage() { } if (loadingProfile || loadingApplications) { - return ( - - - - ); + return ; } return ( diff --git a/apps/portal/src/app/features/exams/pages/ExamsPage/index.tsx b/apps/portal/src/app/features/exams/pages/ExamsPage/index.tsx index b4cb0e0cf..17b42f336 100644 --- a/apps/portal/src/app/features/exams/pages/ExamsPage/index.tsx +++ b/apps/portal/src/app/features/exams/pages/ExamsPage/index.tsx @@ -12,7 +12,7 @@ import { Title, } from '@mantine/core'; import { IconClipboardList } from '@tabler/icons-react'; -import { AdvancedTable, notify, useServerTable } from '@ema-platform/ui'; +import { AdvancedTable, PageLoader, notify, useServerTable } from '@ema-platform/ui'; import { useDateDisplayer } from '@ema-platform/shared'; import { useApiQuery, @@ -178,11 +178,7 @@ export function ExamsPage() { }; if (loadingOpen || loadingMine || loadingResults) { - return ( - - - - ); + return ; } const pagedRegistrations = registrationTable.paginate(mine ?? []); diff --git a/apps/portal/src/app/features/licensing/pages/LicenseApplicationPage.tsx b/apps/portal/src/app/features/licensing/pages/LicenseApplicationPage.tsx index 3c95453c2..33c2cdb48 100644 --- a/apps/portal/src/app/features/licensing/pages/LicenseApplicationPage.tsx +++ b/apps/portal/src/app/features/licensing/pages/LicenseApplicationPage.tsx @@ -53,7 +53,7 @@ import { type ValidationIssue, type Vessel, } from '@ema-platform/api'; -import { getCountryCode, getCountryName, ModalFooter } from '@ema-platform/ui'; +import { getCountryCode, getCountryName, ModalFooter, PageLoader } from '@ema-platform/ui'; import { LICENSE_PERMISSIONS, PORTAL_PERMISSIONS, @@ -212,11 +212,7 @@ export function LicenseApplicationPage() { ); if (loadingConfig || !config || !appId || !application) { - return ( -
- -
- ); + return ; } const readOnly = !['DRAFT', 'RESUBMIT_REQUIRED'].includes(application.status); diff --git a/apps/portal/src/app/features/onboarding/components/RequireOperations.tsx b/apps/portal/src/app/features/onboarding/components/RequireOperations.tsx index 3e0cde509..e4f0f0c8e 100644 --- a/apps/portal/src/app/features/onboarding/components/RequireOperations.tsx +++ b/apps/portal/src/app/features/onboarding/components/RequireOperations.tsx @@ -1,6 +1,6 @@ import { Navigate, useLocation } from 'react-router-dom'; -import { Center, Loader } from '@mantine/core'; import { useGetMyOperatorTypesQuery } from '@ema-platform/api'; +import { PageLoader } from '@ema-platform/ui'; /** * Sends an applicant who has not said what they operate as to the step that @@ -75,11 +75,7 @@ export function RequireOperations({ children }: { children: React.ReactNode }) { } if (isLoading) { - return ( -
- -
- ); + return ; } // A failed lookup must not lock anyone out of the portal — the server still @@ -93,11 +89,7 @@ export function RequireOperations({ children }: { children: React.ReactNode }) { // the same tick; deciding on the pre-save cache bounced the applicant // straight back to the screen they had just completed. if (isFetching) { - return ( -
- -
- ); + return ; } return ; } diff --git a/apps/portal/src/app/features/profile/components/RequireSeafarerProfile.tsx b/apps/portal/src/app/features/profile/components/RequireSeafarerProfile.tsx index 350b0b014..b86057a1e 100644 --- a/apps/portal/src/app/features/profile/components/RequireSeafarerProfile.tsx +++ b/apps/portal/src/app/features/profile/components/RequireSeafarerProfile.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { Center, Loader } from '@mantine/core'; import { Navigate, useLocation, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { notify } from '@ema-platform/ui'; +import { PageLoader, notify } from '@ema-platform/ui'; import { PROFILE_FIELD_SECTION, useCurrentProfile, @@ -75,11 +75,7 @@ export function RequireSeafarerProfile({ children }: { children: React.ReactNode if (!gated) return <>{children}; if (isLoading) { - return ( -
- -
- ); + return ; } // A failed lookup must not lock anyone out — the server still refuses the @@ -93,11 +89,7 @@ export function RequireSeafarerProfile({ children }: { children: React.ReactNode // headed back here in the same tick — deciding on the pre-save cache would // bounce them off the screen they just finished. if (isFetching) { - return ( -
- -
- ); + return ; } const target = PROFILE_FIELD_SECTION[gaps[0]]; diff --git a/libs/auth/src/lib/components/AuthBootstrap.tsx b/libs/auth/src/lib/components/AuthBootstrap.tsx index de5395ddb..9a821d4b0 100644 --- a/libs/auth/src/lib/components/AuthBootstrap.tsx +++ b/libs/auth/src/lib/components/AuthBootstrap.tsx @@ -71,7 +71,7 @@ export function AuthBootstrap({ children }: { children: ReactNode }) { // Rendering the router before the session resolves would let the guards // redirect based on a state that is about to change. - if (!ready) return ; + if (!ready) return ; return <>{children}; } diff --git a/libs/ui/src/lib/theme/maritime-loader-theme.ts b/libs/ui/src/lib/theme/maritime-loader-theme.ts index f030b4b19..f38ef3c68 100644 --- a/libs/ui/src/lib/theme/maritime-loader-theme.ts +++ b/libs/ui/src/lib/theme/maritime-loader-theme.ts @@ -1,31 +1,47 @@ -import { Button, createTheme, Loader, type MantineLoaderComponent } from '@mantine/core'; +import { + ActionIcon, + Button, + createTheme, + Input, + Loader, + Select, + TextInput, + type MantineLoaderComponent, +} from '@mantine/core'; import { MaritimeLoader } from '../components/MaritimeLoader'; /** - * Registers the branded ship loader as the default Mantine `Loader` type, and - * opts `Button`'s inline loading state back out to the stock oval — a 1.88:1 - * ship does not fit a button's loader slot. - * - * Merge into an app theme with `mergeThemeOverrides(appTheme, maritimeLoaderTheme)` - * rather than importing this in `libs/shared`: `libs/ui` already depends on - * `libs/shared`, so the reverse import would be circular. + * Registers the branded Ethiopian Maritime Authority loader as the default Mantine `Loader` type, + * sets prominent 80px size for page/section loaders, and opts inline control loaders + * (buttons, inputs, select fields) back out to the compact oval spinner. */ export const maritimeLoaderTheme = createTheme({ components: { Loader: Loader.extend({ defaultProps: { - // Mantine types custom loaders as ForwardRefExoticComponent; a plain - // function component satisfies the runtime contract (it forwards a - // ref as a normal prop under React 19) but not the structural type. loaders: { ...Loader.defaultLoaders, maritime: MaritimeLoader as unknown as MantineLoaderComponent, }, type: 'maritime', + size: 80, }, }), Button: Button.extend({ defaultProps: { loaderProps: { type: 'oval' } }, }), + ActionIcon: ActionIcon.extend({ + defaultProps: { loaderProps: { type: 'oval' } }, + }), + Input: Input.extend({ + defaultProps: { loaderProps: { type: 'oval' } }, + }), + TextInput: TextInput.extend({ + defaultProps: { loaderProps: { type: 'oval' } }, + }), + Select: Select.extend({ + defaultProps: { loaderProps: { type: 'oval' } }, + }), }, }); +