feat: enhance confirmation dialogs and form error handling; add new utility functions
This commit is contained in:
+5
@@ -63,6 +63,11 @@ export const ACTION_TRANSLATION_MAP: Record<string, { titleKey: string; confirmK
|
||||
confirmKey: 'common:actions.hold',
|
||||
descriptionKey: 'common:confirmDialog.hold.description',
|
||||
},
|
||||
[ModuleAction.SAVE]: {
|
||||
titleKey: 'common:confirmDialog.save.title',
|
||||
confirmKey: 'common:actions.save',
|
||||
descriptionKey: 'common:confirmDialog.save.description',
|
||||
},
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -190,53 +190,6 @@ export interface TranslationSlice {
|
||||
t: (key: string, options?: Record<string, unknown>) => string;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page-Level Configurations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Lifecycle interceptors for form processing.
|
||||
* @template E The base database entity.
|
||||
* @template TFormData The payload structure (defaults to Partial<E> for DTOs).
|
||||
*/
|
||||
export interface EnterpriseFormLifecycleHooks<E extends BaseEntity, TFormData = Partial<E>> {
|
||||
onValidate?: (data: TFormData) => Promise<boolean>;
|
||||
beforeSave?: (data: TFormData) => Promise<TFormData>;
|
||||
/** Overrides the default repository save implementation. */
|
||||
save?: (data: TFormData) => Promise<E>;
|
||||
afterSave?: (result: E) => Promise<void>;
|
||||
afterGetData?: (data: E) => Promise<TFormData>;
|
||||
}
|
||||
|
||||
interface BasePageConfig {
|
||||
children?: ReactNode;
|
||||
px?: string | number;
|
||||
py?: string | number;
|
||||
pageHeaderProps?: Omit<ModulePageHeaderProps, 'actions' | 'moduleKey'>;
|
||||
}
|
||||
export interface EnterpriseIndexPageConfig extends BasePageConfig {
|
||||
customPageActions?: (actions: PageActionsProps['actions']) => PageActionsProps['actions'];
|
||||
onClickCreate?: (key: string) => void;
|
||||
}
|
||||
|
||||
export interface EnterpriseFormPageConfig<E extends BaseEntity = BaseEntity> extends EnterpriseFormLifecycleHooks<E> {
|
||||
children?: ReactNode;
|
||||
showPageHeader?: boolean;
|
||||
useDefaultPadding?: boolean;
|
||||
customHiddenActions?: (data: Partial<E>, defaultHidden: string[]) => string[];
|
||||
/** Strongly typed event handler for custom form interactions. */
|
||||
onCustomActionClick?: (key: ModuleActionType, data?: unknown) => void;
|
||||
|
||||
draftConfig?: DraftConfig;
|
||||
/** Type-safe array of entity keys to exclude during an update operation. */
|
||||
ignoreKeyUpdate?: (keyof E)[];
|
||||
/** Type-safe array of entity keys to exclude when duplicating a record. */
|
||||
ignoreKeyDuplicate?: (keyof E)[];
|
||||
initialValue?: Partial<E>;
|
||||
|
||||
presetDuplicate?: (data: E) => Promise<Partial<E>>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Action Confirmation Modal Configuration
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -336,10 +289,46 @@ export interface BulkActionResult {
|
||||
messages?: string[];
|
||||
}
|
||||
|
||||
export interface PrivilegeEntity {
|
||||
ALLOW_VIEW: boolean;
|
||||
ALLOW_CREATE: boolean;
|
||||
ALLOW_EDIT: boolean;
|
||||
ALLOW_DELETE: boolean;
|
||||
|
||||
ALLOW_PRINT: boolean;
|
||||
ALLOW_PRINT_COPY: boolean;
|
||||
|
||||
ALLOW_APPROVAL: boolean;
|
||||
ALLOW_ACTIVATE: boolean;
|
||||
ALLOW_DEACTIVATE: boolean;
|
||||
|
||||
ALLOW_CONFIRM: boolean;
|
||||
ALLOW_CANCEL: boolean;
|
||||
ALLOW_ROLLBACK: boolean;
|
||||
ALLOW_HOLD: boolean;
|
||||
|
||||
ALLOW_LOGS: boolean;
|
||||
ALLOW_NOTES: boolean;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page-Level Configurations
|
||||
// ---------------------------------------------------------------------------
|
||||
interface BasePageConfig {
|
||||
children?: ReactNode;
|
||||
px?: string | number;
|
||||
py?: string | number;
|
||||
pageHeaderProps?: Omit<ModulePageHeaderProps, 'actions' | 'moduleKey'>;
|
||||
}
|
||||
export interface EnterpriseIndexPageConfig extends BasePageConfig {
|
||||
customPageActions?: (actions: PageActionsProps['actions']) => PageActionsProps['actions'];
|
||||
onClickCreate?: (key: string) => void;
|
||||
}
|
||||
|
||||
export interface EnterpriseDetailPageConfig<E extends BaseEntity = BaseEntity> extends BasePageConfig {
|
||||
editMode?: 'FULL' | 'PARTIAL';
|
||||
customPageActions?: (data: E, actions: PageActionsProps['actions']) => PageActionsProps['actions'];
|
||||
onDetailLoaded?: (data: E) => void;
|
||||
onDataLoaded?: (data: E) => void;
|
||||
|
||||
showHighlightData?: boolean;
|
||||
showHighlightDataOnBreadcrumbs?: boolean;
|
||||
@@ -375,24 +364,24 @@ export interface EnterpriseDetailPageConfig<E extends BaseEntity = BaseEntity> e
|
||||
holdModalConfig?: ActionModalConfig;
|
||||
}
|
||||
|
||||
export interface PrivilegeEntity {
|
||||
ALLOW_VIEW: boolean;
|
||||
ALLOW_CREATE: boolean;
|
||||
ALLOW_EDIT: boolean;
|
||||
ALLOW_DELETE: boolean;
|
||||
export interface EnterpriseFormPageConfig<E extends BaseEntity = BaseEntity> extends BasePageConfig {
|
||||
formPageType: FormPageType;
|
||||
customPageActions?: (data: E, actions: PageActionsProps['actions']) => PageActionsProps['actions'];
|
||||
onDataLoaded?: (data: E) => void;
|
||||
|
||||
ALLOW_PRINT: boolean;
|
||||
ALLOW_PRINT_COPY: boolean;
|
||||
showHighlightData?: boolean;
|
||||
showHighlightDataOnBreadcrumbs?: boolean;
|
||||
highlightDataKey?: string;
|
||||
|
||||
ALLOW_APPROVAL: boolean;
|
||||
ALLOW_ACTIVATE: boolean;
|
||||
ALLOW_DEACTIVATE: boolean;
|
||||
/** Key to reference status data in the entity, used to render the status badge automatically. @default 'status' */
|
||||
statusKey?: string;
|
||||
/** Custom callback to provide dynamic status badge properties */
|
||||
getCustomStatusBadgeConfig?: (status: string) => Partial<import('@mantine/core').BadgeProps>;
|
||||
|
||||
ALLOW_CONFIRM: boolean;
|
||||
ALLOW_CANCEL: boolean;
|
||||
ALLOW_ROLLBACK: boolean;
|
||||
ALLOW_HOLD: boolean;
|
||||
|
||||
ALLOW_LOGS: boolean;
|
||||
ALLOW_NOTES: boolean;
|
||||
/** Type-safe array of entity keys to exclude during an update operation. */
|
||||
ignoreKeyUpdate?: (keyof E)[];
|
||||
/** Type-safe array of entity keys to exclude when duplicating a record. */
|
||||
ignoreKeyDuplicate?: (keyof E)[];
|
||||
initialValueCreate?: Partial<E>;
|
||||
presetDuplicate?(payload: any): Promise<any>;
|
||||
}
|
||||
|
||||
@@ -20,17 +20,17 @@ import { shortcutsData } from '../../../constants';
|
||||
export function EnterpriseDetailPageProvider<E extends BaseEntity = BaseEntity>(props: EnterpriseDetailPageConfig<E>) {
|
||||
const {
|
||||
children,
|
||||
editMode = 'FULL',
|
||||
pageHeaderProps,
|
||||
px,
|
||||
py,
|
||||
|
||||
editMode = 'FULL',
|
||||
showHighlightData = true,
|
||||
showHighlightDataOnBreadcrumbs = true,
|
||||
highlightDataKey = 'code',
|
||||
statusKey = 'status',
|
||||
getCustomStatusBadgeConfig,
|
||||
onDetailLoaded,
|
||||
onDataLoaded,
|
||||
|
||||
customPageActions,
|
||||
onClickCreate,
|
||||
@@ -77,7 +77,7 @@ export function EnterpriseDetailPageProvider<E extends BaseEntity = BaseEntity>(
|
||||
if (response && response.data) {
|
||||
const data = response.data?.data;
|
||||
setDetailData(data as E);
|
||||
if (onDetailLoaded) onDetailLoaded(data as E);
|
||||
if (onDataLoaded) onDataLoaded(data as E);
|
||||
}
|
||||
} catch (error: any) {
|
||||
notifications.show({
|
||||
@@ -377,7 +377,7 @@ export function EnterpriseDetailPageProvider<E extends BaseEntity = BaseEntity>(
|
||||
|
||||
/** Platform-aware shortcut label for the Create action. */
|
||||
const CREATE_SHORTCUT_LABEL = useMemo(() => {
|
||||
const shortcutData = shortcutsData.find((s) => s.key === 'collapse_sidebar');
|
||||
const shortcutData = shortcutsData.find((s) => s.key === 'create_data');
|
||||
return IS_MACOS ? shortcutData?.macKeyIcons.join(' ') : shortcutData?.winKeyIcons.join(' ');
|
||||
}, [IS_MACOS]);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export function EnterpriseIndexPageProvider(props: EnterpriseIndexPageConfig) {
|
||||
|
||||
/** Platform-aware shortcut label for the Create action. */
|
||||
const CREATE_SHORTCUT_LABEL = useMemo(() => {
|
||||
const shortcutData = shortcutsData.find((s) => s.key === 'collapse_sidebar');
|
||||
const shortcutData = shortcutsData.find((s) => s.key === 'create_data');
|
||||
return IS_MACOS ? shortcutData?.macKeyIcons.join(' ') : shortcutData?.winKeyIcons.join(' ');
|
||||
}, [IS_MACOS]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user