mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-29 15:18:12 +00:00
feat: implement ModalFooter component for consistent modal action layout
This commit is contained in:
@@ -44,7 +44,7 @@ import {
|
||||
useUpdateLicenseTemplateMutation,
|
||||
type LicenseTemplate,
|
||||
} from '@ema-platform/api';
|
||||
import { EmptyState, ErrorState, PageHeader } from '@ema-platform/ui';
|
||||
import { EmptyState, ErrorState, ModalFooter, PageHeader } from '@ema-platform/ui';
|
||||
import { authStorage, usePermissions } from '@ema-platform/auth';
|
||||
import { PERMISSIONS } from '../../../layouts/nav-config';
|
||||
|
||||
@@ -529,7 +529,7 @@ export function CertificateDesignerPage() {
|
||||
'Starts from the live design, or the built-in layout if this type has none.',
|
||||
)}
|
||||
</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={() => setNewOpen(false)}>
|
||||
{t('common.cancel', 'Cancel')}
|
||||
</Button>
|
||||
@@ -550,7 +550,7 @@ export function CertificateDesignerPage() {
|
||||
>
|
||||
{t('designer.create', 'Create')}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</Container>
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IconEdit, IconTrash, IconPlus, IconInfoCircle, IconCertificate } from '@tabler/icons-react';
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, ModalFooter, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import {
|
||||
useGetCertificationsQuery,
|
||||
useCreateCertificationMutation,
|
||||
@@ -199,10 +199,10 @@ export function CertificationPage() {
|
||||
|
||||
<Modal opened={deleteOpened} onClose={closeDelete} title={t('certification.confirmDelete')} size="sm">
|
||||
<Text mb="md">{t('certification.deleteConfirmText', { name: deleteTarget?.name?.[locale] })}</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDelete} size="sm">{t('certification.cancel')}</Button>
|
||||
<Button color="red" onClick={handleDelete} size="sm">{t('certification.delete')}</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
useErrorHandler,
|
||||
AdvancedTable,
|
||||
useServerTable,
|
||||
ModalFooter,
|
||||
type AdvancedColumn,
|
||||
} from "@ema-platform/ui";
|
||||
import { LocationPage } from "../../location/pages/LocationPage";
|
||||
@@ -388,14 +389,14 @@ function ProfessionTab() {
|
||||
name: deleteTarget?.name?.[locale] ?? "",
|
||||
})}
|
||||
</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDelete} size="sm">
|
||||
{t("configuration.cancel")}
|
||||
</Button>
|
||||
<Button color="red" onClick={confirmDeleteProf} size="sm">
|
||||
{t("configuration.delete")}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
IconX,
|
||||
IconDetails
|
||||
} from "@tabler/icons-react";
|
||||
import { notify, useErrorHandler } from "@ema-platform/ui";
|
||||
import { notify, useErrorHandler, ModalFooter } from "@ema-platform/ui";
|
||||
import {
|
||||
useGetExamQuery,
|
||||
useUpdateExamMutation,
|
||||
@@ -494,14 +494,14 @@ export function ExamDetailPage() {
|
||||
mode="manual"
|
||||
actions={setWhatAction}
|
||||
/>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeAssign} size="sm">
|
||||
{t("exam.cancel")}
|
||||
</Button>
|
||||
<Button onClick={handleAssign} size="sm" loading={isAssigning}>
|
||||
{t("exam.saveAssignments")}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -531,14 +531,14 @@ export function ExamDetailPage() {
|
||||
onChange={setDraftQuestions}
|
||||
mode="random"
|
||||
/>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeAssign} size="sm">
|
||||
{t("exam.cancel")}
|
||||
</Button>
|
||||
<Button onClick={handleAssign} size="sm" loading={isAssigning}>
|
||||
{t("exam.saveAssignments")}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
IconClipboardList,
|
||||
IconDetails,
|
||||
} from "@tabler/icons-react";
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, type AdvancedColumn } from "@ema-platform/ui";
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, ModalFooter, type AdvancedColumn } from "@ema-platform/ui";
|
||||
import { useGetCertificationsQuery } from "../../certification/api/certification-api";
|
||||
import {
|
||||
useGetExamsQuery,
|
||||
@@ -600,14 +600,14 @@ export function ExamPage() {
|
||||
name: deleteTarget?.title?.[locale] ?? "",
|
||||
})}
|
||||
</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDelete} size="sm">
|
||||
{t("exam.cancel")}
|
||||
</Button>
|
||||
<Button color="red" onClick={handleDelete} size="sm">
|
||||
{t("exam.delete")}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
Alert,
|
||||
Button,
|
||||
Checkbox,
|
||||
Group,
|
||||
Modal,
|
||||
Select,
|
||||
Stack,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
} from '@mantine/core';
|
||||
import { IconAlertTriangle } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ModalFooter } from '@ema-platform/ui';
|
||||
import type { ResolvedAction } from '../config/actions';
|
||||
|
||||
/** Reason codes offered per action. Free text is always available too. */
|
||||
@@ -290,7 +290,7 @@ export function DecisionConfirmModal({
|
||||
/>
|
||||
)}
|
||||
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={onClose}>
|
||||
{t('common.cancel', 'Cancel')}
|
||||
</Button>
|
||||
@@ -310,7 +310,7 @@ export function DecisionConfirmModal({
|
||||
>
|
||||
{t(action.labelKey)}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ import {
|
||||
useScheduleInspectionMutation,
|
||||
type RemarkTargetType,
|
||||
} from '@ema-platform/api';
|
||||
import { ErrorState } from '@ema-platform/ui';
|
||||
import { ErrorState, ModalFooter } from '@ema-platform/ui';
|
||||
import { usePermissions } from '@ema-platform/auth';
|
||||
import { useAppSelector } from '../../../store/hooks';
|
||||
import { DecisionBar } from '../components/DecisionBar';
|
||||
@@ -894,7 +894,7 @@ export function LicenseReviewPage() {
|
||||
value={inspectionDate}
|
||||
onChange={(e) => setInspectionDate(e.currentTarget.value)}
|
||||
/>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Tooltip
|
||||
label={t('review.pickDate', 'Pick a date and time first')}
|
||||
disabled={Boolean(inspectionDate)}
|
||||
@@ -924,7 +924,7 @@ export function LicenseReviewPage() {
|
||||
>
|
||||
<IconCheck size={18} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
||||
@@ -942,7 +942,7 @@ export function LicenseReviewPage() {
|
||||
autosize
|
||||
minRows={3}
|
||||
/>
|
||||
<Group grow>
|
||||
<ModalFooter grow>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="teal"
|
||||
@@ -989,7 +989,7 @@ export function LicenseReviewPage() {
|
||||
>
|
||||
<IconX size={18} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</Container>
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconSettings, IconMap, IconInfoCircle, IconPlus } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { notify, useErrorHandler } from '@ema-platform/ui';
|
||||
import { notify, useErrorHandler, ModalFooter } from '@ema-platform/ui';
|
||||
import { LocationTree } from '../components/LocationTree';
|
||||
import { LocationDetail } from '../components/LocationDetail';
|
||||
import { LocationForm } from '../components/LocationForm';
|
||||
@@ -226,14 +226,14 @@ export function LocationPage() {
|
||||
name: selectedLocation?.names[locale] ?? '',
|
||||
})}
|
||||
</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDeleteModal} size="sm">
|
||||
{t('location.cancel')}
|
||||
</Button>
|
||||
<Button color="red" onClick={handleDeleteConfirm} size="sm">
|
||||
{t('location.delete')}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
<LocationTypeModal opened={typeModalOpened} onClose={closeTypeModal} />
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
IconInfoCircle,
|
||||
IconLock,
|
||||
} from '@tabler/icons-react';
|
||||
import { notify } from '@ema-platform/ui';
|
||||
import { notify, ModalFooter } from '@ema-platform/ui';
|
||||
import {
|
||||
extractErrorMessage,
|
||||
localized,
|
||||
@@ -364,14 +364,14 @@ function FeeEditModal({
|
||||
</>
|
||||
)}
|
||||
|
||||
<Group justify="flex-end" mt="xs">
|
||||
<ModalFooter mt="xs">
|
||||
<Button variant="default" onClick={onClose} disabled={isLoading}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={save} loading={isLoading}>
|
||||
Save fees
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IconEdit, IconTrash, IconPlus, IconInfoCircle } from '@tabler/icons-react';
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import { notify, useErrorHandler, AdvancedTable, useServerTable, ModalFooter, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import { useGetCertificationsQuery } from '../../certification/api/certification-api';
|
||||
import {
|
||||
useGetQuestionsQuery,
|
||||
@@ -255,10 +255,10 @@ export function QuestionPage() {
|
||||
|
||||
<Modal opened={deleteOpened} onClose={closeDelete} title={t('question.confirmDelete')} size="sm">
|
||||
<Text mb="md">{t('question.deleteConfirmText')}</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDelete} size="sm">{t('question.cancel')}</Button>
|
||||
<Button color="red" onClick={handleDelete} size="sm">{t('question.delete')}</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
Alert,
|
||||
} from '@mantine/core';
|
||||
import { IconInfoCircle, IconCheck, IconX } from '@tabler/icons-react';
|
||||
import { notify, useErrorHandler } from '@ema-platform/ui';
|
||||
import { notify, useErrorHandler, ModalFooter } from '@ema-platform/ui';
|
||||
import { useApiQuery } from '@ema-platform/api';
|
||||
import { useCreateResultMutation, useUpdateResultMutation } from '../api/result-api';
|
||||
import type { Exam } from '../../exam/types/exam';
|
||||
@@ -195,12 +195,12 @@ export function RecordResultModal({
|
||||
size="sm"
|
||||
/>
|
||||
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={onClose} size="sm">{t('result.cancel')}</Button>
|
||||
<Button onClick={handleSave} size="sm" loading={isSaving}>
|
||||
{t('result.saveResult')}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
IconChartBar,
|
||||
IconSearch,
|
||||
} from '@tabler/icons-react';
|
||||
import { notify, BilingualInput, useErrorHandler, AdvancedTable, useServerTable, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import { notify, BilingualInput, useErrorHandler, AdvancedTable, useServerTable, ModalFooter, type AdvancedColumn } from '@ema-platform/ui';
|
||||
import type { BilingualValue } from '@ema-platform/ui';
|
||||
import { useGetResultsQuery, useLazyGetResultQuery, useDeleteResultMutation, useUpdateResultMutation } from '../api/result-api';
|
||||
import { useGetExamsQuery } from '../../exam/api/exam-api';
|
||||
@@ -462,7 +462,7 @@ export function ResultPage() {
|
||||
</>
|
||||
)}
|
||||
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={handleDetailClose} size="sm">{t('result.close')}</Button>
|
||||
<Button
|
||||
onClick={handleDetailSave}
|
||||
@@ -472,7 +472,7 @@ export function ResultPage() {
|
||||
>
|
||||
{t('result.save')}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
) : (
|
||||
<Text c="dimmed" ta="center" py="xl">{t('result.noData')}</Text>
|
||||
@@ -481,10 +481,10 @@ export function ResultPage() {
|
||||
|
||||
<Modal opened={deleteOpened} onClose={closeDelete} title={t('result.confirmDelete')} size="sm">
|
||||
<Text mb="md">{t('result.deleteConfirmText')}</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closeDelete} size="sm">{t('result.cancel')}</Button>
|
||||
<Button color="red" onClick={handleDelete} size="sm">{t('result.delete')}</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
{/* Choose exam, then record */}
|
||||
@@ -501,10 +501,10 @@ export function ResultPage() {
|
||||
searchable
|
||||
required
|
||||
/>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={closePicker} size="sm">{t('result.cancel')}</Button>
|
||||
<Button onClick={startRecord} size="sm" disabled={!pickerExamId}>{t('result.continue')}</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
IconSettings,
|
||||
IconTrash,
|
||||
} from '@tabler/icons-react';
|
||||
import { notify } from '@ema-platform/ui';
|
||||
import { notify, ModalFooter } from '@ema-platform/ui';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -495,12 +495,12 @@ export function VesselRegistrationFormBuilderPage() {
|
||||
onChange={(e) => setDraftRequired(e.currentTarget.checked)}
|
||||
/>
|
||||
<Divider />
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={() => setDrawerOpen(false)}>Cancel</Button>
|
||||
<Button color="teal" onClick={saveField}>
|
||||
{isNew ? 'Add Field' : 'Save Changes'}
|
||||
</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Drawer>
|
||||
|
||||
@@ -516,10 +516,10 @@ export function VesselRegistrationFormBuilderPage() {
|
||||
Are you sure you want to remove <strong>{deleteTarget?.label}</strong> from the form?
|
||||
This cannot be undone.
|
||||
</Text>
|
||||
<Group justify="flex-end">
|
||||
<ModalFooter>
|
||||
<Button variant="default" onClick={() => setDeleteTarget(null)}>Cancel</Button>
|
||||
<Button color="red" onClick={confirmDelete}>Delete Field</Button>
|
||||
</Group>
|
||||
</ModalFooter>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user