feat: add RowActions component for enhanced row-level actions in data grids
- Introduced RowActions component to manage row-level actions with tooltips and dropdown menus. - Created types for row actions and page actions to standardize action properties. - Implemented utility function to map action intents to Mantine theme colors. - Updated CoreAppShell component to support optional slots for better flexibility. - Added enterprise module structure with context hooks for managing module state and actions. - Implemented draft management for forms to enhance user experience during data entry. - Established context providers for detail, form, and index pages to streamline data handling. - Updated dependencies to ensure compatibility with the latest versions.
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import { useMemo, useState, useEffect, ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from '@repo/core-i18n';
|
||||
import { BaseEntity, BaseRemoteDataServices } from '@repo/core-api/data-services';
|
||||
|
||||
import { ModuleConfigEntity, SinglePageFormState, SinglePageModalState } from '../entities/entity';
|
||||
import {
|
||||
EnterpriseConfigContext,
|
||||
EnterpriseDataServiceContext,
|
||||
EnterpriseSelectionContext,
|
||||
EnterpriseNavigationContext,
|
||||
EnterpriseModalContext,
|
||||
EnterpriseTranslationContext,
|
||||
} from '../hooks/use-module.context';
|
||||
|
||||
export interface EnterpriseModuleProviderProps<E extends BaseEntity> {
|
||||
children: ReactNode;
|
||||
config: ModuleConfigEntity<E>;
|
||||
dataServices: BaseRemoteDataServices<E>;
|
||||
}
|
||||
|
||||
export function EnterpriseModuleProvider<E extends BaseEntity>(props: EnterpriseModuleProviderProps<E>) {
|
||||
const { children, config, dataServices } = props;
|
||||
const navigate = useNavigate();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1. Config Slice (Static)
|
||||
// ---------------------------------------------------------------------------
|
||||
const configSlice = useMemo(() => ({ config }), [config]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1b. Translation Slice (Dedicated context — decoupled from config)
|
||||
// ---------------------------------------------------------------------------
|
||||
const namespaces = useMemo(
|
||||
() => [config.translationNamespace, 'common'],
|
||||
[config.translationNamespace],
|
||||
);
|
||||
const { t } = useTranslation(namespaces);
|
||||
const translationSlice = useMemo(() => ({ t: t as (key: string, options?: Record<string, unknown>) => string }), [t]);
|
||||
|
||||
// Set document title — uses explicit tabTitle or falls back to translation key 'title'
|
||||
useEffect(() => {
|
||||
const title = config.tabTitle || t('title');
|
||||
if (title) {
|
||||
document.title = title;
|
||||
}
|
||||
}, [config.tabTitle, t]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 2. Data Service Slice (Stable refs)
|
||||
// ---------------------------------------------------------------------------
|
||||
const dataServiceSlice = useMemo(() => {
|
||||
return { dataServices, privilege: undefined };
|
||||
}, [dataServices]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 3. Selection Slice (Dynamic state)
|
||||
// ---------------------------------------------------------------------------
|
||||
const [selectedRows, setSelectedRows] = useState<E[]>([]);
|
||||
const [metaData, setMetaData] = useState<any>(null);
|
||||
const [filterData, setFilterData] = useState<any>(null);
|
||||
|
||||
const selectionSlice = useMemo(
|
||||
() => ({
|
||||
selectedRows,
|
||||
setSelectedRows,
|
||||
metaData,
|
||||
setMetaData,
|
||||
filterData,
|
||||
setFilterData,
|
||||
}),
|
||||
[selectedRows, metaData, filterData],
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 4. Modal Slice (For Single Page mode)
|
||||
// ---------------------------------------------------------------------------
|
||||
const [formState, setFormState] = useState<SinglePageFormState>({ open: false, formType: 'CREATE' });
|
||||
const [detailState, setDetailState] = useState<SinglePageModalState>({ open: false });
|
||||
|
||||
const modalSlice = useMemo(
|
||||
() => ({ formState, setFormState, detailState, setDetailState }),
|
||||
[formState, detailState],
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5. Navigation Slice
|
||||
// ---------------------------------------------------------------------------
|
||||
const navigationSlice = useMemo(() => {
|
||||
const isSingle = config.moduleCategory === 'SINGLE_PAGE';
|
||||
|
||||
return {
|
||||
navigateToIndex: () => {
|
||||
if (isSingle) {
|
||||
setFormState({ open: false, formType: 'CREATE' });
|
||||
setDetailState({ open: false });
|
||||
} else {
|
||||
navigate(`${config.webUrl}/index`);
|
||||
}
|
||||
},
|
||||
navigateToCreate: () => {
|
||||
if (isSingle) {
|
||||
setFormState({ open: true, formType: 'DUPLICATE' });
|
||||
} else {
|
||||
navigate(`${config.webUrl}/create`);
|
||||
}
|
||||
},
|
||||
navigateToEdit: (id: string) => {
|
||||
if (isSingle) {
|
||||
setFormState({ open: true, formType: 'EDIT', dataId: id });
|
||||
} else {
|
||||
navigate(`${config.webUrl}/edit/${id}`);
|
||||
}
|
||||
},
|
||||
navigateToDetail: (id: string) => {
|
||||
if (isSingle) {
|
||||
setDetailState({ open: true, dataId: id });
|
||||
} else {
|
||||
navigate(`${config.webUrl}/detail/${id}`);
|
||||
}
|
||||
},
|
||||
navigateToDuplicate: (id: string) => {
|
||||
if (isSingle) {
|
||||
setFormState({ open: true, formType: 'DUPLICATE', dataId: id });
|
||||
} else {
|
||||
navigate(`${config.webUrl}/duplicate/${id}`);
|
||||
}
|
||||
},
|
||||
};
|
||||
}, [config.moduleCategory, config.webUrl, navigate]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Render
|
||||
// ---------------------------------------------------------------------------
|
||||
return (
|
||||
<EnterpriseConfigContext.Provider value={configSlice}>
|
||||
<EnterpriseTranslationContext.Provider value={translationSlice}>
|
||||
<EnterpriseDataServiceContext.Provider value={dataServiceSlice}>
|
||||
<EnterpriseNavigationContext.Provider value={navigationSlice}>
|
||||
<EnterpriseSelectionContext.Provider value={selectionSlice}>
|
||||
<EnterpriseModalContext.Provider value={modalSlice}>{children}</EnterpriseModalContext.Provider>
|
||||
</EnterpriseSelectionContext.Provider>
|
||||
</EnterpriseNavigationContext.Provider>
|
||||
</EnterpriseDataServiceContext.Provider>
|
||||
</EnterpriseTranslationContext.Provider>
|
||||
</EnterpriseConfigContext.Provider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user