Skip to content

Commit 55a8954

Browse files
committed
feat(datagrid/dialogs): introduce DataGridDialogManager with form and footer orchestration
- Add DialogManager to orchestrate dialog behavior based on ActionMode - Implement mode-specific titles, descriptions and submit labels - Support default footer with dynamic submit button label - Allow custom footer via renderFooter override - Ensure cancel logic resets action mode and closes dialog - Use the Sheet component as the controlled dialog container
1 parent 405781a commit 55a8954

File tree

2 files changed

+116
-23
lines changed

2 files changed

+116
-23
lines changed

src/DataGrid.tsx

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,28 @@
1-
// file: src/DataGrid.tsx
1+
// file: src/components/DataGrid.tsx
22

3-
'use client';
3+
import { ReactNode } from 'react';
44

5-
import DataGridView from './DataGridView';
6-
import { DataGridProvider } from './context/DataGridProvider';
7-
import type { Identifiable, DataGridMode } from './context/DataGridState';
8-
import type { DataGridEventsProps } from './hooks/useGridEvents';
5+
import { DataGridProvider } from '@context';
6+
import type { Identifiable } from '@contracts';
7+
import { DataGridDialogManager } from '@components';
98

10-
export interface DataGridProps<T extends Identifiable> extends DataGridEventsProps<T> {
11-
data: T[];
12-
initialTake?: number;
13-
initialTotalRows?: number;
14-
mode?: DataGridMode;
9+
interface DataGridProps<T extends Identifiable> {
10+
rows: T[];
11+
children?: ReactNode;
1512
}
1613

1714
export default function DataGrid<T extends Identifiable>({
18-
data,
19-
initialTake = 10,
20-
initialTotalRows = data.length,
21-
mode,
22-
...events
15+
rows,
16+
children,
2317
}: DataGridProps<T>) {
2418
return (
25-
<DataGridProvider<T>
26-
initialData={data}
27-
initialTake={initialTake}
28-
initialTotalRows={initialTotalRows}
29-
mode={mode}
30-
>
31-
<DataGridView<T> {...events} />
19+
<DataGridProvider<T> initialRows={rows}>
20+
{children}
21+
22+
<DataGridDialogManager
23+
onSubmit={() => console.log('Form submitted!')}
24+
renderForm={(_) => <>FormDialog</>}
25+
/>
3226
</DataGridProvider>
3327
);
3428
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
'use client';
2+
3+
import { ReactNode } from 'react';
4+
import { useActions } from '@hooks';
5+
import { Sheet, SheetContent, SheetFooter, SheetHeader } from '@components';
6+
7+
interface FormContext {
8+
onSubmit: () => Promise<void> | void;
9+
onCancel: () => void;
10+
}
11+
12+
interface DataGridDialogsProps {
13+
renderForm: (ctx: FormContext) => ReactNode;
14+
renderFooter?: (ctx: FormContext) => ReactNode;
15+
onSubmit: () => Promise<void> | void;
16+
onCancel?: () => void;
17+
}
18+
19+
/**
20+
* Dialog orchestrator for DataGrid.
21+
* Supports: create, update, delete, import.
22+
* Explicitly DOES NOT support multi-row delete.
23+
*/
24+
export function DataGridDialogManager({
25+
renderForm,
26+
renderFooter,
27+
onSubmit,
28+
onCancel,
29+
}: DataGridDialogsProps) {
30+
const actions = useActions();
31+
32+
/** Always close dialog by resetting mode + triggering optional callback */
33+
const close = () => {
34+
actions.reset();
35+
onCancel?.();
36+
};
37+
38+
// ---- Dialog Titles Per Mode ----
39+
const titles: Record<string, string> = {
40+
create: 'Create Record',
41+
update: 'Update Record',
42+
delete: 'Delete Record',
43+
import: 'Import Data',
44+
};
45+
46+
const descriptions: Record<string, string> = {
47+
create: 'Add a new entry',
48+
update: 'Modify the selected entry',
49+
delete: 'This action cannot be undone',
50+
import: 'Upload a file to import',
51+
};
52+
53+
// ---- Primary Button Labels Per Mode ----
54+
const submitLabels: Record<string, string> = {
55+
create: 'Create',
56+
update: 'Update',
57+
delete: 'Delete',
58+
import: 'Import',
59+
};
60+
61+
const title = titles[actions.mode] ?? 'Dialog';
62+
const description = descriptions[actions.mode] ?? '';
63+
const submitLabel = submitLabels[actions.mode] ?? 'Submit';
64+
65+
// Context to pass to form + footer
66+
const formCtx: FormContext = {
67+
onSubmit,
68+
onCancel: close,
69+
};
70+
71+
// ---- Default Footer (used if no override is provided) ----
72+
const defaultFooter = (
73+
<>
74+
<button onClick={close}>Cancel</button>
75+
<button
76+
onClick={onSubmit}
77+
style={{
78+
color: actions.mode === 'delete' ? 'white' : 'inherit',
79+
background: actions.mode === 'delete' ? '#d32f2f' : 'inherit',
80+
}}
81+
>
82+
{submitLabel}
83+
</button>
84+
</>
85+
);
86+
87+
return (
88+
<Sheet
89+
open={!['idle', 'reload'].includes(actions.mode)}
90+
onOpenChange={() => actions.set('idle')}
91+
>
92+
<SheetHeader title={title} description={description} onClose={close} />
93+
94+
<SheetContent>{renderForm(formCtx)}</SheetContent>
95+
96+
<SheetFooter>{renderFooter ? renderFooter(formCtx) : defaultFooter}</SheetFooter>
97+
</Sheet>
98+
);
99+
}

0 commit comments

Comments
 (0)