@lminii/material-react-table-mcp 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/README.md +68 -0
  2. package/data/MIGRATION.md +136 -0
  3. package/data/api.json +5379 -0
  4. package/data/examples/advanced.js +215 -0
  5. package/data/examples/advanced.tsx +309 -0
  6. package/data/examples/aggregation-and-grouping.js +116 -0
  7. package/data/examples/aggregation-and-grouping.tsx +153 -0
  8. package/data/examples/aggregation-multi.js +89 -0
  9. package/data/examples/aggregation-multi.tsx +105 -0
  10. package/data/examples/alternate-column-filtering.js +38 -0
  11. package/data/examples/alternate-column-filtering.tsx +49 -0
  12. package/data/examples/alternate-detail-panel.js +65 -0
  13. package/data/examples/alternate-detail-panel.tsx +81 -0
  14. package/data/examples/alternate-pagination.js +17 -0
  15. package/data/examples/alternate-pagination.tsx +23 -0
  16. package/data/examples/basic.js +86 -0
  17. package/data/examples/basic.tsx +109 -0
  18. package/data/examples/chart-detail-panel.js +69 -0
  19. package/data/examples/chart-detail-panel.tsx +89 -0
  20. package/data/examples/column-actions-space.js +34 -0
  21. package/data/examples/column-actions-space.tsx +44 -0
  22. package/data/examples/column-alignment.js +58 -0
  23. package/data/examples/column-alignment.tsx +70 -0
  24. package/data/examples/custom-column-actions.js +74 -0
  25. package/data/examples/custom-column-actions.tsx +109 -0
  26. package/data/examples/custom-column-filtering-ui.js +59 -0
  27. package/data/examples/custom-column-filtering-ui.tsx +89 -0
  28. package/data/examples/custom-headless.js +85 -0
  29. package/data/examples/custom-headless.tsx +125 -0
  30. package/data/examples/custom-top-toolbar.js +60 -0
  31. package/data/examples/custom-top-toolbar.tsx +88 -0
  32. package/data/examples/customize-display-columns.js +72 -0
  33. package/data/examples/customize-display-columns.tsx +85 -0
  34. package/data/examples/customize-filter-components.js +78 -0
  35. package/data/examples/customize-filter-components.tsx +101 -0
  36. package/data/examples/customize-filter-modes.js +59 -0
  37. package/data/examples/customize-filter-modes.tsx +73 -0
  38. package/data/examples/customize-filter-variants.js +98 -0
  39. package/data/examples/customize-filter-variants.tsx +116 -0
  40. package/data/examples/customize-global-filter-component.js +37 -0
  41. package/data/examples/customize-global-filter-component.tsx +52 -0
  42. package/data/examples/customize-remove-column-grouping.js +75 -0
  43. package/data/examples/customize-remove-column-grouping.tsx +94 -0
  44. package/data/examples/customize-row-selection.js +43 -0
  45. package/data/examples/customize-row-selection.tsx +54 -0
  46. package/data/examples/customize-table-styles.js +81 -0
  47. package/data/examples/customize-table-styles.tsx +100 -0
  48. package/data/examples/disable-column-actions.js +26 -0
  49. package/data/examples/disable-column-actions.tsx +37 -0
  50. package/data/examples/disable-column-hiding.js +74 -0
  51. package/data/examples/disable-column-hiding.tsx +90 -0
  52. package/data/examples/disable-density-toggle.js +37 -0
  53. package/data/examples/disable-density-toggle.tsx +49 -0
  54. package/data/examples/dynamic-columns.js +124 -0
  55. package/data/examples/dynamic-columns.tsx +189 -0
  56. package/data/examples/editing-crud-cell.js +288 -0
  57. package/data/examples/editing-crud-cell.tsx +377 -0
  58. package/data/examples/editing-crud-modal.js +275 -0
  59. package/data/examples/editing-crud-modal.tsx +370 -0
  60. package/data/examples/editing-crud-row.js +255 -0
  61. package/data/examples/editing-crud-row.tsx +333 -0
  62. package/data/examples/editing-crud-table.js +280 -0
  63. package/data/examples/editing-crud-table.tsx +369 -0
  64. package/data/examples/editing-crud-tree.js +328 -0
  65. package/data/examples/editing-crud-tree.tsx +416 -0
  66. package/data/examples/enable-cell-actions.js +52 -0
  67. package/data/examples/enable-cell-actions.tsx +76 -0
  68. package/data/examples/enable-click-to-copy.js +33 -0
  69. package/data/examples/enable-click-to-copy.tsx +39 -0
  70. package/data/examples/enable-column-grouping.js +69 -0
  71. package/data/examples/enable-column-grouping.tsx +120 -0
  72. package/data/examples/enable-column-ordering.js +37 -0
  73. package/data/examples/enable-column-ordering.tsx +48 -0
  74. package/data/examples/enable-column-pinning.js +58 -0
  75. package/data/examples/enable-column-pinning.tsx +69 -0
  76. package/data/examples/enable-column-resizing.js +45 -0
  77. package/data/examples/enable-column-resizing.tsx +56 -0
  78. package/data/examples/enable-column-virtualization.js +19 -0
  79. package/data/examples/enable-column-virtualization.tsx +27 -0
  80. package/data/examples/enable-detail-panel-conditionally.js +61 -0
  81. package/data/examples/enable-detail-panel-conditionally.tsx +78 -0
  82. package/data/examples/enable-detail-panel-virtualized.js +64 -0
  83. package/data/examples/enable-detail-panel-virtualized.tsx +80 -0
  84. package/data/examples/enable-expanding-tree.js +87 -0
  85. package/data/examples/enable-expanding-tree.tsx +110 -0
  86. package/data/examples/enable-filter-facet-values.js +52 -0
  87. package/data/examples/enable-filter-facet-values.tsx +65 -0
  88. package/data/examples/enable-row-dragging.js +102 -0
  89. package/data/examples/enable-row-dragging.tsx +137 -0
  90. package/data/examples/enable-row-numbers-original.js +37 -0
  91. package/data/examples/enable-row-numbers-original.tsx +48 -0
  92. package/data/examples/enable-row-numbers-static.js +37 -0
  93. package/data/examples/enable-row-numbers-static.tsx +48 -0
  94. package/data/examples/enable-row-ordering.js +40 -0
  95. package/data/examples/enable-row-ordering.tsx +57 -0
  96. package/data/examples/enable-row-pinning-select.js +64 -0
  97. package/data/examples/enable-row-pinning-select.tsx +76 -0
  98. package/data/examples/enable-row-pinning-static.js +39 -0
  99. package/data/examples/enable-row-pinning-static.tsx +50 -0
  100. package/data/examples/enable-row-pinning-sticky.js +57 -0
  101. package/data/examples/enable-row-pinning-sticky.tsx +69 -0
  102. package/data/examples/enable-row-selection.js +71 -0
  103. package/data/examples/enable-row-selection.tsx +96 -0
  104. package/data/examples/enable-row-virtualization.js +85 -0
  105. package/data/examples/enable-row-virtualization.tsx +101 -0
  106. package/data/examples/enable-sticky-header.js +47 -0
  107. package/data/examples/enable-sticky-header.tsx +59 -0
  108. package/data/examples/expanding-tree-expanded.js +98 -0
  109. package/data/examples/expanding-tree-expanded.tsx +121 -0
  110. package/data/examples/expanding-tree-flat-parse.js +102 -0
  111. package/data/examples/expanding-tree-flat-parse.tsx +125 -0
  112. package/data/examples/expanding-tree-root-expanded.js +120 -0
  113. package/data/examples/expanding-tree-root-expanded.tsx +151 -0
  114. package/data/examples/export-to-csv.js +84 -0
  115. package/data/examples/export-to-csv.tsx +114 -0
  116. package/data/examples/export-to-pdf.js +76 -0
  117. package/data/examples/export-to-pdf.tsx +104 -0
  118. package/data/examples/external-toolbar.js +82 -0
  119. package/data/examples/external-toolbar.tsx +108 -0
  120. package/data/examples/font-awesome-icons.js +62 -0
  121. package/data/examples/font-awesome-icons.tsx +106 -0
  122. package/data/examples/infinite-scrolling.js +137 -0
  123. package/data/examples/infinite-scrolling.tsx +208 -0
  124. package/data/examples/lazy-detail-panel.js +164 -0
  125. package/data/examples/lazy-detail-panel.tsx +262 -0
  126. package/data/examples/lazy-sub-rows.js +118 -0
  127. package/data/examples/lazy-sub-rows.tsx +190 -0
  128. package/data/examples/linear-progress.js +48 -0
  129. package/data/examples/linear-progress.tsx +66 -0
  130. package/data/examples/loading.js +34 -0
  131. package/data/examples/loading.tsx +50 -0
  132. package/data/examples/localization-i18n-ar.js +40 -0
  133. package/data/examples/localization-i18n-ar.tsx +65 -0
  134. package/data/examples/localization-i18n-az.js +38 -0
  135. package/data/examples/localization-i18n-az.tsx +60 -0
  136. package/data/examples/localization-i18n-bg.js +38 -0
  137. package/data/examples/localization-i18n-bg.tsx +60 -0
  138. package/data/examples/localization-i18n-cs.js +38 -0
  139. package/data/examples/localization-i18n-cs.tsx +60 -0
  140. package/data/examples/localization-i18n-da.js +38 -0
  141. package/data/examples/localization-i18n-da.tsx +60 -0
  142. package/data/examples/localization-i18n-de.js +38 -0
  143. package/data/examples/localization-i18n-de.tsx +60 -0
  144. package/data/examples/localization-i18n-el.js +38 -0
  145. package/data/examples/localization-i18n-el.tsx +60 -0
  146. package/data/examples/localization-i18n-en.js +38 -0
  147. package/data/examples/localization-i18n-en.tsx +60 -0
  148. package/data/examples/localization-i18n-es.js +38 -0
  149. package/data/examples/localization-i18n-es.tsx +60 -0
  150. package/data/examples/localization-i18n-et.js +38 -0
  151. package/data/examples/localization-i18n-et.tsx +60 -0
  152. package/data/examples/localization-i18n-fa.js +40 -0
  153. package/data/examples/localization-i18n-fa.tsx +66 -0
  154. package/data/examples/localization-i18n-fi.js +38 -0
  155. package/data/examples/localization-i18n-fi.tsx +60 -0
  156. package/data/examples/localization-i18n-fr.js +38 -0
  157. package/data/examples/localization-i18n-fr.tsx +60 -0
  158. package/data/examples/localization-i18n-he.js +40 -0
  159. package/data/examples/localization-i18n-he.tsx +66 -0
  160. package/data/examples/localization-i18n-hr.js +38 -0
  161. package/data/examples/localization-i18n-hr.tsx +60 -0
  162. package/data/examples/localization-i18n-hu.js +38 -0
  163. package/data/examples/localization-i18n-hu.tsx +60 -0
  164. package/data/examples/localization-i18n-hy.js +40 -0
  165. package/data/examples/localization-i18n-hy.tsx +65 -0
  166. package/data/examples/localization-i18n-id.js +38 -0
  167. package/data/examples/localization-i18n-id.tsx +60 -0
  168. package/data/examples/localization-i18n-it.js +38 -0
  169. package/data/examples/localization-i18n-it.tsx +60 -0
  170. package/data/examples/localization-i18n-ja.js +38 -0
  171. package/data/examples/localization-i18n-ja.tsx +60 -0
  172. package/data/examples/localization-i18n-ko.js +38 -0
  173. package/data/examples/localization-i18n-ko.tsx +60 -0
  174. package/data/examples/localization-i18n-nl.js +38 -0
  175. package/data/examples/localization-i18n-nl.tsx +60 -0
  176. package/data/examples/localization-i18n-no.js +38 -0
  177. package/data/examples/localization-i18n-no.tsx +60 -0
  178. package/data/examples/localization-i18n-np.js +38 -0
  179. package/data/examples/localization-i18n-np.tsx +60 -0
  180. package/data/examples/localization-i18n-pl.js +38 -0
  181. package/data/examples/localization-i18n-pl.tsx +60 -0
  182. package/data/examples/localization-i18n-pt-BR.js +38 -0
  183. package/data/examples/localization-i18n-pt-BR.tsx +60 -0
  184. package/data/examples/localization-i18n-pt.js +38 -0
  185. package/data/examples/localization-i18n-pt.tsx +60 -0
  186. package/data/examples/localization-i18n-ro.js +38 -0
  187. package/data/examples/localization-i18n-ro.tsx +60 -0
  188. package/data/examples/localization-i18n-ru.js +38 -0
  189. package/data/examples/localization-i18n-ru.tsx +60 -0
  190. package/data/examples/localization-i18n-sk.js +38 -0
  191. package/data/examples/localization-i18n-sk.tsx +60 -0
  192. package/data/examples/localization-i18n-sr-Cyrl-RS.js +38 -0
  193. package/data/examples/localization-i18n-sr-Cyrl-RS.tsx +60 -0
  194. package/data/examples/localization-i18n-sr-Latn-RS.js +38 -0
  195. package/data/examples/localization-i18n-sr-Latn-RS.tsx +60 -0
  196. package/data/examples/localization-i18n-sv.js +38 -0
  197. package/data/examples/localization-i18n-sv.tsx +60 -0
  198. package/data/examples/localization-i18n-tr.js +38 -0
  199. package/data/examples/localization-i18n-tr.tsx +60 -0
  200. package/data/examples/localization-i18n-uk.js +38 -0
  201. package/data/examples/localization-i18n-uk.tsx +60 -0
  202. package/data/examples/localization-i18n-vi.js +38 -0
  203. package/data/examples/localization-i18n-vi.tsx +60 -0
  204. package/data/examples/localization-i18n-zh-hans.js +38 -0
  205. package/data/examples/localization-i18n-zh-hans.tsx +60 -0
  206. package/data/examples/localization-i18n-zh-hant.js +38 -0
  207. package/data/examples/localization-i18n-zh-hant.tsx +60 -0
  208. package/data/examples/manual-selection.js +81 -0
  209. package/data/examples/manual-selection.tsx +105 -0
  210. package/data/examples/minimal.js +66 -0
  211. package/data/examples/minimal.tsx +78 -0
  212. package/data/examples/mui-theme.js +109 -0
  213. package/data/examples/mui-theme.tsx +136 -0
  214. package/data/examples/multi-sorting.js +48 -0
  215. package/data/examples/multi-sorting.tsx +58 -0
  216. package/data/examples/persistent-state.js +126 -0
  217. package/data/examples/persistent-state.tsx +184 -0
  218. package/data/examples/react-query.js +122 -0
  219. package/data/examples/react-query.tsx +182 -0
  220. package/data/examples/remote.js +113 -0
  221. package/data/examples/remote.tsx +150 -0
  222. package/data/examples/row-actions-buttons.js +54 -0
  223. package/data/examples/row-actions-buttons.tsx +89 -0
  224. package/data/examples/row-actions-menu-items.js +36 -0
  225. package/data/examples/row-actions-menu-items.tsx +64 -0
  226. package/data/examples/single-row-selection.js +74 -0
  227. package/data/examples/single-row-selection.tsx +98 -0
  228. package/data/examples/virtualized.js +122 -0
  229. package/data/examples/virtualized.tsx +138 -0
  230. package/data/guides/accessibility.md +119 -0
  231. package/data/guides/aggregation.md +210 -0
  232. package/data/guides/async-loading.md +132 -0
  233. package/data/guides/best-practices.md +363 -0
  234. package/data/guides/cell-actions.md +139 -0
  235. package/data/guides/click-to-copy.md +67 -0
  236. package/data/guides/column-actions.md +69 -0
  237. package/data/guides/column-filtering.md +366 -0
  238. package/data/guides/column-grouping.md +192 -0
  239. package/data/guides/column-hiding.md +133 -0
  240. package/data/guides/column-ordering-dnd.md +99 -0
  241. package/data/guides/column-pinning.md +72 -0
  242. package/data/guides/column-resizing.md +157 -0
  243. package/data/guides/column-size.md +162 -0
  244. package/data/guides/customize-components.md +395 -0
  245. package/data/guides/customize-icons.md +35 -0
  246. package/data/guides/data-columns.md +292 -0
  247. package/data/guides/density-toggle.md +46 -0
  248. package/data/guides/detail-panel.md +195 -0
  249. package/data/guides/display-columns.md +135 -0
  250. package/data/guides/editing.md +367 -0
  251. package/data/guides/expanding-sub-rows.md +194 -0
  252. package/data/guides/full-screen-toggle.md +63 -0
  253. package/data/guides/global-filtering.md +237 -0
  254. package/data/guides/localization.md +57 -0
  255. package/data/guides/memoization.md +157 -0
  256. package/data/guides/pagination.md +171 -0
  257. package/data/guides/row-actions.md +116 -0
  258. package/data/guides/row-numbers.md +24 -0
  259. package/data/guides/row-ordering-dnd.md +51 -0
  260. package/data/guides/row-pinning.md +96 -0
  261. package/data/guides/row-selection.md +237 -0
  262. package/data/guides/sorting.md +190 -0
  263. package/data/guides/state-management.md +165 -0
  264. package/data/guides/sticky-header.md +41 -0
  265. package/data/guides/table-event-listeners.md +103 -0
  266. package/data/guides/toolbar-customization.md +251 -0
  267. package/data/guides/virtualization.md +183 -0
  268. package/data/index.json +1930 -0
  269. package/data/reference/mrt-components.md +183 -0
  270. package/data/reference/mrt-hooks.md +125 -0
  271. package/data/skills/README.md +81 -0
  272. package/data/skills/composable-components/SKILL.md +189 -0
  273. package/data/skills/customization/SKILL.md +190 -0
  274. package/data/skills/drag-and-drop-ordering/SKILL.md +227 -0
  275. package/data/skills/editing/SKILL.md +243 -0
  276. package/data/skills/filtering/SKILL.md +213 -0
  277. package/data/skills/getting-started/SKILL.md +213 -0
  278. package/data/skills/localization/SKILL.md +182 -0
  279. package/data/skills/migrate-v3-to-v4/SKILL.md +161 -0
  280. package/data/skills/state-and-server-data/SKILL.md +200 -0
  281. package/data/skills/virtualization/SKILL.md +203 -0
  282. package/dist/data.js +159 -0
  283. package/dist/index.js +244 -0
  284. package/package.json +50 -0
@@ -0,0 +1,328 @@
1
+ import { lazy, Suspense, useMemo, useState } from 'react';
2
+ import { MaterialReactTable, createRow, useMaterialReactTable, } from 'material-react-table';
3
+ import { Box, Button, IconButton, Tooltip, darken, lighten, } from '@mui/material';
4
+ import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient, } from '@tanstack/react-query';
5
+ import { fakeData, usStates } from './makeData';
6
+ import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
7
+ import EditIcon from '@mui/icons-material/Edit';
8
+ import DeleteIcon from '@mui/icons-material/Delete';
9
+ const Example = () => {
10
+ const [creatingRowIndex, setCreatingRowIndex] = useState();
11
+ const [validationErrors, setValidationErrors] = useState({});
12
+ const columns = useMemo(() => [
13
+ {
14
+ accessorKey: 'id',
15
+ header: 'Id',
16
+ enableEditing: false,
17
+ size: 80,
18
+ },
19
+ {
20
+ accessorKey: 'firstName',
21
+ header: 'First Name',
22
+ muiEditTextFieldProps: {
23
+ required: true,
24
+ error: !!validationErrors?.firstName,
25
+ helperText: validationErrors?.firstName,
26
+ //remove any previous validation errors when user focuses on the input
27
+ onFocus: () => setValidationErrors({
28
+ ...validationErrors,
29
+ firstName: undefined,
30
+ }),
31
+ //optionally add validation checking for onBlur or onChange
32
+ },
33
+ },
34
+ {
35
+ accessorKey: 'lastName',
36
+ header: 'Last Name',
37
+ muiEditTextFieldProps: {
38
+ required: true,
39
+ error: !!validationErrors?.lastName,
40
+ helperText: validationErrors?.lastName,
41
+ //remove any previous validation errors when user focuses on the input
42
+ onFocus: () => setValidationErrors({
43
+ ...validationErrors,
44
+ lastName: undefined,
45
+ }),
46
+ },
47
+ },
48
+ {
49
+ accessorKey: 'city',
50
+ header: 'City',
51
+ muiEditTextFieldProps: {
52
+ required: true,
53
+ error: !!validationErrors?.city,
54
+ helperText: validationErrors?.city,
55
+ //remove any previous validation errors when user focuses on the input
56
+ onFocus: () => setValidationErrors({
57
+ ...validationErrors,
58
+ city: undefined,
59
+ }),
60
+ },
61
+ },
62
+ {
63
+ accessorKey: 'state',
64
+ header: 'State',
65
+ editVariant: 'select',
66
+ editSelectOptions: usStates,
67
+ muiEditTextFieldProps: {
68
+ select: true,
69
+ error: !!validationErrors?.state,
70
+ helperText: validationErrors?.state,
71
+ },
72
+ },
73
+ ], [validationErrors]);
74
+ //call CREATE hook
75
+ const { mutateAsync: createUser, isPending: isCreatingUser } = useCreateUser();
76
+ //call READ hook
77
+ const { data: fetchedUsers = [], isError: isLoadingUsersError, isFetching: isFetchingUsers, isLoading: isLoadingUsers, } = useGetUsers();
78
+ //call UPDATE hook
79
+ const { mutateAsync: updateUser, isPending: isUpdatingUser } = useUpdateUser();
80
+ //call DELETE hook
81
+ const { mutateAsync: deleteUser, isPending: isDeletingUser } = useDeleteUser();
82
+ //CREATE action
83
+ const handleCreateUser = async ({ values, row, table, }) => {
84
+ const newValidationErrors = validateUser(values);
85
+ if (Object.values(newValidationErrors).some((error) => error)) {
86
+ setValidationErrors(newValidationErrors);
87
+ return;
88
+ }
89
+ setValidationErrors({});
90
+ await createUser({ ...values, managerId: row.original.managerId });
91
+ table.setCreatingRow(null); //exit creating mode
92
+ };
93
+ //UPDATE action
94
+ const handleSaveUser = async ({ values, table, }) => {
95
+ const newValidationErrors = validateUser(values);
96
+ if (Object.values(newValidationErrors).some((error) => error)) {
97
+ setValidationErrors(newValidationErrors);
98
+ return;
99
+ }
100
+ setValidationErrors({});
101
+ await updateUser(values);
102
+ table.setEditingRow(null); //exit editing mode
103
+ };
104
+ //DELETE action
105
+ const openDeleteConfirmModal = (row) => {
106
+ if (window.confirm('Are you sure you want to delete this user?')) {
107
+ deleteUser(row.original.id);
108
+ }
109
+ };
110
+ const table = useMaterialReactTable({
111
+ columns,
112
+ data: fetchedUsers,
113
+ createDisplayMode: 'row', // ('modal', and 'custom' are also available)
114
+ editDisplayMode: 'row', // ('modal', 'cell', 'table', and 'custom' are also available)
115
+ enableColumnPinning: true,
116
+ enableEditing: true,
117
+ enableExpanding: true,
118
+ positionCreatingRow: creatingRowIndex, //index where new row is inserted before
119
+ getRowId: (row) => row.id,
120
+ muiToolbarAlertBannerProps: isLoadingUsersError
121
+ ? {
122
+ color: 'error',
123
+ children: 'Error loading data',
124
+ }
125
+ : undefined,
126
+ muiTableContainerProps: {
127
+ sx: {
128
+ minHeight: '500px',
129
+ },
130
+ },
131
+ muiTableBodyRowProps: ({ row }) => ({
132
+ //conditional styling based on row depth
133
+ sx: (theme) => ({
134
+ td: {
135
+ backgroundColor: darken(lighten(theme.palette.background.paper, 0.1), row.depth * (theme.palette.mode === 'dark' ? 0.2 : 0.1)),
136
+ },
137
+ }),
138
+ }),
139
+ onCreatingRowCancel: () => setValidationErrors({}),
140
+ onCreatingRowSave: handleCreateUser,
141
+ onEditingRowCancel: () => setValidationErrors({}),
142
+ onEditingRowSave: handleSaveUser,
143
+ renderRowActions: ({ row, staticRowIndex, table }) => (<Box sx={{ display: 'flex', gap: '1rem' }}>
144
+ <Tooltip title="Edit">
145
+ <IconButton onClick={() => table.setEditingRow(row)}>
146
+ <EditIcon />
147
+ </IconButton>
148
+ </Tooltip>
149
+ <Tooltip title="Delete">
150
+ <IconButton color="error" onClick={() => openDeleteConfirmModal(row)}>
151
+ <DeleteIcon />
152
+ </IconButton>
153
+ </Tooltip>
154
+ <Tooltip title="Add Subordinate">
155
+ <IconButton onClick={() => {
156
+ setCreatingRowIndex((staticRowIndex || 0) + 1);
157
+ table.setCreatingRow(createRow(table, {
158
+ id: null,
159
+ firstName: '',
160
+ lastName: '',
161
+ city: '',
162
+ state: '',
163
+ managerId: row.id,
164
+ subRows: [],
165
+ }, -1, row.depth + 1));
166
+ }}>
167
+ <PersonAddAltIcon />
168
+ </IconButton>
169
+ </Tooltip>
170
+ </Box>),
171
+ renderTopToolbarCustomActions: ({ table }) => (<Button startIcon={<PersonAddAltIcon />} variant="contained" onClick={() => {
172
+ setCreatingRowIndex(table.getRowModel().rows.length); //create new row at bottom of table
173
+ table.setCreatingRow(true);
174
+ }}>
175
+ Create New User
176
+ </Button>),
177
+ initialState: {
178
+ columnPinning: { end: [], start: ['mrt-row-actions'] },
179
+ expanded: true,
180
+ pagination: { pageSize: 20, pageIndex: 0 },
181
+ },
182
+ state: {
183
+ isLoading: isLoadingUsers,
184
+ isSaving: isCreatingUser || isUpdatingUser || isDeletingUser,
185
+ showAlertBanner: isLoadingUsersError,
186
+ showProgressBars: isFetchingUsers,
187
+ },
188
+ });
189
+ return <MaterialReactTable table={table}/>;
190
+ };
191
+ //CREATE hook (post new user to api)
192
+ function useCreateUser() {
193
+ const queryClient = useQueryClient();
194
+ return useMutation({
195
+ mutationFn: async (user) => {
196
+ console.info('create user', user);
197
+ //send api update request here
198
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
199
+ return Promise.resolve();
200
+ },
201
+ //client side optimistic update
202
+ onMutate: (newUserInfo) => {
203
+ queryClient.setQueryData(['users'], (_prevUsers) => {
204
+ const prevUsers = JSON.parse(JSON.stringify(_prevUsers));
205
+ newUserInfo.subRows = [];
206
+ if (newUserInfo.managerId) {
207
+ const manager = findUserInTree(newUserInfo.managerId, prevUsers);
208
+ if (manager) {
209
+ manager.subRows = [
210
+ ...(manager.subRows || []),
211
+ {
212
+ ...newUserInfo,
213
+ id: `${manager.id}.${(manager.subRows?.length || 0) + 1}`,
214
+ },
215
+ ];
216
+ }
217
+ }
218
+ else {
219
+ prevUsers.push({
220
+ ...newUserInfo,
221
+ id: `${prevUsers.length + 1}`,
222
+ });
223
+ }
224
+ return [...prevUsers];
225
+ });
226
+ },
227
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
228
+ });
229
+ }
230
+ //READ hook (get users from api)
231
+ function useGetUsers() {
232
+ return useQuery({
233
+ queryKey: ['users'],
234
+ queryFn: async () => {
235
+ //send api request here
236
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
237
+ return Promise.resolve(fakeData);
238
+ },
239
+ refetchOnWindowFocus: false,
240
+ });
241
+ }
242
+ //UPDATE hook (put user in api)
243
+ function useUpdateUser() {
244
+ const queryClient = useQueryClient();
245
+ return useMutation({
246
+ mutationFn: async (user) => {
247
+ console.info('update user', user);
248
+ //send api update request here
249
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
250
+ return Promise.resolve();
251
+ },
252
+ //client side optimistic update
253
+ onMutate: (newUserInfo) => {
254
+ queryClient.setQueryData(['users'], (prevUsers) => {
255
+ let user = findUserInTree(newUserInfo.id, prevUsers);
256
+ user = { ...user, ...newUserInfo };
257
+ return [...prevUsers];
258
+ });
259
+ },
260
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
261
+ });
262
+ }
263
+ //DELETE hook (delete user in api)
264
+ function useDeleteUser() {
265
+ const queryClient = useQueryClient();
266
+ return useMutation({
267
+ mutationFn: async (userId) => {
268
+ console.info('delete user', userId);
269
+ //send api update request here
270
+ await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
271
+ return Promise.resolve();
272
+ },
273
+ //client side optimistic update
274
+ onMutate: (userId) => {
275
+ queryClient.setQueryData(['users'], (prevUsers) => {
276
+ const newUsers = JSON.parse(JSON.stringify(prevUsers));
277
+ //remove user
278
+ const user = findUserInTree(userId, newUsers);
279
+ if (user) {
280
+ const manager = findUserInTree(user.managerId, newUsers);
281
+ if (manager) {
282
+ manager.subRows = manager.subRows?.filter((subUser) => subUser.id !== user.id);
283
+ }
284
+ else {
285
+ return newUsers.filter((user) => user.id !== userId);
286
+ }
287
+ }
288
+ return [...newUsers];
289
+ });
290
+ },
291
+ // onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
292
+ });
293
+ }
294
+ //react query setup in App.tsx
295
+ const ReactQueryDevtoolsProduction = lazy(() => import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
296
+ default: d.ReactQueryDevtools,
297
+ })));
298
+ const queryClient = new QueryClient();
299
+ export default function App() {
300
+ return (<QueryClientProvider client={queryClient}>
301
+ <Example />
302
+ <Suspense fallback={null}>
303
+ <ReactQueryDevtoolsProduction />
304
+ </Suspense>
305
+ </QueryClientProvider>);
306
+ }
307
+ const validateRequired = (value) => !!value.length;
308
+ function validateUser(user) {
309
+ return {
310
+ firstName: !validateRequired(user.firstName)
311
+ ? 'First Name is Required'
312
+ : '',
313
+ lastName: !validateRequired(user.lastName) ? 'Last Name is Required' : '',
314
+ };
315
+ }
316
+ function findUserInTree(managerId, users) {
317
+ for (let i = 0; i < users.length; i++) {
318
+ if (users[i].id === managerId) {
319
+ return users[i];
320
+ }
321
+ if (users[i].subRows) {
322
+ const found = findUserInTree(managerId, users[i].subRows);
323
+ if (found)
324
+ return found;
325
+ }
326
+ }
327
+ return null;
328
+ }