@controleonline/ui-default 1.0.270 → 1.0.273

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 (100) hide show
  1. package/.github/workflows/integration-source-gate.yml +68 -0
  2. package/.github/workflows/manager-worker.yml +19 -0
  3. package/.github/workflows/publish-npm.yml +91 -0
  4. package/AGENTS.md +46 -50
  5. package/docs/technical/Contrato-de-colunas.md +67 -0
  6. package/docs/technical/Default-Components.md +76 -0
  7. package/docs/technical/DefaultForm.md +80 -0
  8. package/docs/technical/DefaultInput-e-DefaultSelect.md +73 -0
  9. package/docs/technical/DefaultTable.md +272 -0
  10. package/docs/wiki.md +1 -0
  11. package/package.json +4 -3
  12. package/scripts/validate-wiki-pointer.cjs +13 -0
  13. package/src/react/components/address/DefaultAddress.js +446 -0
  14. package/src/react/components/address/DefaultAddress.styles.js +133 -0
  15. package/src/react/components/address/DefaultAddressCoordFields.js +59 -0
  16. package/src/react/components/address/DefaultAddressMapPane.js +55 -0
  17. package/src/react/components/address/LatLonReadonlyFields.js +51 -0
  18. package/src/react/components/address/defaultAddressHelpers.js +163 -0
  19. package/src/react/components/address/defaultAddressStyles.js +148 -0
  20. package/src/react/components/address/defaultAddressUtils.js +129 -0
  21. package/src/react/components/extra-data/DefaultExtraData.js +152 -0
  22. package/src/react/components/extra-data/DefaultExtraData.styles.js +61 -0
  23. package/src/react/components/files/DefaultFile.js +231 -46
  24. package/src/react/components/files/DefaultFileColumn.js +123 -0
  25. package/src/react/components/files/DefaultFileColumn.styles.js +52 -0
  26. package/src/react/components/files/DefaultFileColumn.utils.js +104 -0
  27. package/src/react/components/filters/CompactFilterSelector.js +51 -35
  28. package/src/react/components/filters/DefaultColumnFilter.js +60 -48
  29. package/src/react/components/filters/DefaultExternalFilters.js +324 -265
  30. package/src/react/components/filters/filterValue.js +65 -0
  31. package/src/react/components/form/DefaultForm.js +99 -79
  32. package/src/react/components/help/DefaultTooltip.js +48 -12
  33. package/src/react/components/help/DefaultTooltip.styles.js +20 -0
  34. package/src/react/components/inputs/DefaultColorInput.js +153 -0
  35. package/src/react/components/inputs/DefaultFeatherIconPicker.js +146 -0
  36. package/src/react/components/inputs/DefaultFeatherIconPicker.styles.js +113 -0
  37. package/src/react/components/inputs/DefaultInput.js +296 -141
  38. package/src/react/components/inputs/DefaultInput.styles.js +26 -0
  39. package/src/react/components/inputs/DefaultSelect.js +134 -123
  40. package/src/react/components/inputs/defaultInputUtils.js +262 -213
  41. package/src/react/components/map/DefaultMap.native.js +73 -73
  42. package/src/react/components/map/DefaultMap.shared.js +911 -762
  43. package/src/react/components/map/DefaultMap.web.js +124 -68
  44. package/src/react/components/table/DefaultColumnMenu.js +22 -3
  45. package/src/react/components/table/DefaultDebug.js +44 -37
  46. package/src/react/components/table/DefaultSearchModal.js +9 -1
  47. package/src/react/components/table/DefaultTable.grouping.js +98 -0
  48. package/src/react/components/table/DefaultTable.js +217 -111
  49. package/src/react/components/table/DefaultTable.styles.js +369 -310
  50. package/src/react/components/table/DefaultTable.utils.js +38 -4
  51. package/src/react/components/table/DefaultTableBody.js +13 -8
  52. package/src/react/components/table/DefaultTableCards.js +20 -1
  53. package/src/react/components/table/DefaultTableControls.js +180 -205
  54. package/src/react/components/table/DefaultTableImportModal.js +108 -0
  55. package/src/react/components/table/DefaultTableInput.js +1 -0
  56. package/src/react/components/table/DefaultTableRowActions.js +1 -1
  57. package/src/react/components/table/DefaultTableRows.js +357 -325
  58. package/src/react/components/table/DefaultTableSearch.js +28 -5
  59. package/src/react/components/table/DefaultTableToolbar.js +92 -3
  60. package/src/react/components/table/useDefaultTablePagination.js +56 -7
  61. package/src/react/components/table/useDefaultTableStoreSync.js +164 -0
  62. package/src/react/components/upload/DefaultUpload.js +406 -0
  63. package/src/react/components/upload/DefaultUpload.styles.js +153 -0
  64. package/src/react/components/upload/DefaultUploadAttachmentsList.js +146 -0
  65. package/src/react/components/upload/DefaultUploadManagerModal.js +247 -0
  66. package/src/react/components/upload/defaultUploadHelpers.js +108 -0
  67. package/src/react/components/upload/defaultUploadLibrary.js +248 -0
  68. package/src/react/components/upload/fileUpload.js +93 -0
  69. package/src/react/hooks/usePostalCodeLookup.js +159 -0
  70. package/src/react/index.js +6 -0
  71. package/src/react/services/addressFormUtils.js +262 -0
  72. package/src/react/services/addressGeo.js +230 -0
  73. package/src/react/utils/tableVisibleColumnsPreferences.js +113 -15
  74. package/src/tests/react/components/address/defaultAddressHelpers.test.js +104 -0
  75. package/src/tests/react/components/files/DefaultFile.test.js +22 -6
  76. package/src/tests/react/components/files/DefaultFileColumn.company.test.js +24 -0
  77. package/src/tests/react/components/form/DefaultForm.test.js +123 -0
  78. package/src/tests/react/components/help/DefaultTooltip.test.js +93 -0
  79. package/src/tests/react/components/inputs/DefaultSelect.test.js +108 -79
  80. package/src/tests/react/components/table/DefaultTable.grouping.test.js +49 -0
  81. package/src/tests/react/components/table/DefaultTable.test.js +53 -2
  82. package/src/tests/react/components/table/DefaultTable.utils.test.js +10 -0
  83. package/src/tests/react/components/table/DefaultTableControls.filters.test.mjs +21 -0
  84. package/src/tests/react/components/table/DefaultTableRowActions.test.js +23 -0
  85. package/src/tests/react/components/table/DefaultTableRows.rowActions.test.js +152 -0
  86. package/src/tests/react/components/table/resolveRowBackgroundColor.test.mjs +45 -0
  87. package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +161 -0
  88. package/src/tests/react/components/upload/DefaultUpload.test.js +353 -0
  89. package/src/tests/react/components/upload/defaultUploadLibrary.test.js +104 -0
  90. package/src/tests/react/components/upload/peopleMediaLibraryPreview.test.mjs +57 -0
  91. package/src/tests/react/filters/filterValue.test.js +46 -0
  92. package/src/tests/react/hooks/usePostalCodeLookup.test.js +107 -0
  93. package/src/tests/react/inputs/defaultInputUtils.test.js +9 -1
  94. package/src/tests/react/services/SMOKE-637-cep-hydrate.md +45 -0
  95. package/src/tests/react/services/addressFormUtils.test.js +179 -0
  96. package/src/tests/react/services/addressGeoLookup.async.test.js +104 -0
  97. package/src/tests/react/services/addressGeoLookup.test.js +105 -0
  98. package/src/tests/react/services/smoke-637/form-cep-12941040.png +0 -0
  99. package/src/tests/react/services/smoke-637/index.html +132 -0
  100. package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +96 -49
@@ -1,5 +1,5 @@
1
- import React, { useEffect, useMemo, useRef } from 'react';
2
- import { TouchableOpacity, View, useWindowDimensions } from 'react-native';
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { Modal, Text, TouchableOpacity, View, useWindowDimensions } from 'react-native';
3
3
  import { NavigationRouteContext, useIsFocused } from '@react-navigation/native';
4
4
  import { useStore } from '@store';
5
5
  import { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
@@ -8,15 +8,12 @@ import { normalizeText } from '../inputs/defaultInputUtils';
8
8
  import { DEFAULT_COMPACT_BREAKPOINT, isObject, stableSerialize } from './DefaultTable.utils';
9
9
  import {
10
10
  resolveDefaultTablePreferenceScope,
11
- resolveStoredTableFiltersPreference,
12
11
  resolveStoredTableViewModePreference,
13
- resolveStoredVisibleColumnsPreference,
14
- sanitizeTableFiltersPreference,
15
- sanitizeVisibleColumnsPreference,
16
12
  } from '../../utils/tableVisibleColumnsPreferences';
17
13
  import DefaultTableBody from './DefaultTableBody';
18
14
  import DefaultTableFooter from './DefaultTableFooter';
19
15
  import DefaultTableToolbar from './DefaultTableToolbar';
16
+ import DefaultForm from '../form/DefaultForm';
20
17
  import styles from './DefaultTable.styles';
21
18
  import { useDefaultTablePagination } from './useDefaultTablePagination';
22
19
  import {
@@ -25,52 +22,50 @@ import {
25
22
  } from './useDefaultTableSorting';
26
23
  import useDefaultTableTheme from './useDefaultTableTheme';
27
24
 
25
+ import {
26
+ assignGetterValue,
27
+ useDefaultTableStoreSync,
28
+ } from './useDefaultTableStoreSync';
29
+
28
30
  export {
29
31
  mergeSortedDataWithLiveItems,
30
32
  resolveColumnListLoadParams,
31
33
  shouldTriggerEndReachedFromScroll,
32
34
  } from './DefaultTable.utils';
33
35
 
34
- const publishStoreValue = (store, actionName, value, getterName) => {
35
- if (typeof store?.actions?.[actionName] === 'function') {
36
- store.actions[actionName](value);
37
- return;
38
- }
39
-
40
- if (store?.getters) {
41
- store.getters[getterName] = value;
42
- }
43
- };
44
-
45
- const assignGetterValue = (store, getterName, value) => {
46
- if (store?.getters) {
47
- store.getters[getterName] = value;
48
- }
49
- };
50
-
51
36
  const DefaultTable = ({
52
37
  accentColor = null,
53
38
  actions = {},
54
39
  add = null,
40
+ addButtonPlacement = 'toolbar',
41
+ addLabel = '',
55
42
  compactBreakpoint = DEFAULT_COMPACT_BREAKPOINT,
43
+ cardListProps = {},
56
44
  columns = [],
57
45
  data = undefined,
46
+ defaultColor = '',
58
47
  filters = {},
59
48
  footerComponent = null,
60
49
  forceCardsOnCompact = true,
61
50
  getOptionsForColumn = null,
62
51
  hasMore = null,
52
+ importAction = null,
63
53
  initialViewMode = 'table',
64
54
  isLoading = false,
55
+ exportAction = null,
65
56
  onAdd = null,
66
57
  onDataLoaded = null,
67
58
  onEditRow = null,
68
59
  onEndReached = null,
60
+ onExport = null,
69
61
  onFilterChange = null,
62
+ onImport = null,
70
63
  onMomentumScrollBegin = null,
64
+ onRefresh = null,
71
65
  onRowPress = null,
72
66
  onSaved = null,
73
67
  onScrollBeginDrag = null,
68
+ onSelectionChange = null,
74
69
  onSortChange = null,
75
70
  pageSize = null,
76
71
  pinRowActions = true,
@@ -79,7 +74,10 @@ const DefaultTable = ({
79
74
  rowActionsComponent = null,
80
75
  rowActionsWidth = null,
81
76
  rowStyle = null,
77
+ searchKey = 'search',
78
+ searchPlaceholder = '',
82
79
  showColumnFiltersButton = true,
80
+ showSearch = null,
83
81
  showRowActions = true,
84
82
  showToolbar = true,
85
83
  showTotalItemsInCompactToolbar = false,
@@ -91,25 +89,29 @@ const DefaultTable = ({
91
89
  toolbarActions = [],
92
90
  visibleColumnsPreferenceKey = '',
93
91
  }) => {
92
+ const [isCreateFormOpen, setIsCreateFormOpen] = useState(false);
94
93
  const { width } = useWindowDimensions();
95
94
  const route = React.useContext(NavigationRouteContext);
96
95
  const store = useStore(storeName);
96
+ const peopleStore = useStore('people');
97
97
  const isFocused = useIsFocused();
98
- const configsSignatureRef = useRef('');
98
+ const storeDeclaredConfigsRef = useRef(null);
99
99
  const { showError } = useMessage() || {};
100
100
  const { tableBorderColors, themeColors } = useDefaultTableTheme(accentColor);
101
101
  const tablePanelBorderColor = tableBorderColors.containerBorderColor;
102
102
  const floatingAddBackgroundColor =
103
103
  themeColors.buttonBackground || themeColors.primary || accentColor;
104
104
  const floatingAddIconColor = themeColors.buttonText;
105
+ const currentCompanyId = peopleStore?.getters?.currentCompany?.id;
105
106
  const tablePreferenceScope = useMemo(
106
107
  () =>
107
108
  resolveDefaultTablePreferenceScope({
109
+ companyId: currentCompanyId,
108
110
  preferenceKey: visibleColumnsPreferenceKey,
109
111
  route,
110
112
  storeName,
111
113
  }),
112
- [route?.key, route?.name, storeName, visibleColumnsPreferenceKey],
114
+ [currentCompanyId, route?.key, route?.name, storeName, visibleColumnsPreferenceKey],
113
115
  );
114
116
  const storedViewMode = useMemo(
115
117
  () => resolveStoredTableViewModePreference(tablePreferenceScope, null),
@@ -128,13 +130,25 @@ const DefaultTable = ({
128
130
  const storeFilters = isObject(store?.getters?.filters) ? store.getters.filters : {};
129
131
  const requestParamsSeed = isObject(requestParams) ? requestParams : {};
130
132
  const resolvedTotalItems = store?.getters?.totalItems;
131
- const currentConfigs = store?.getters?.configs || {};
133
+ if (storeDeclaredConfigsRef.current === null) {
134
+ storeDeclaredConfigsRef.current = isObject(store?.getters?.configs)
135
+ ? store.getters.configs
136
+ : {};
137
+ }
138
+
139
+ const storeDeclaredConfigs = storeDeclaredConfigsRef.current || {};
140
+ const currentConfigs = {
141
+ ...storeDeclaredConfigs,
142
+ ...(store?.getters?.configs || {}),
143
+ };
144
+ const storeSelectable = storeDeclaredConfigs.selectable === true;
132
145
  const isCompactView = width > 0 && width <= compactBreakpoint;
133
146
  const addConfig = store?.getters?.add;
134
- const shouldRenderFloatingAddButton =
135
- showToolbar === false &&
136
- (addConfig === true || add === true) &&
137
- (typeof onAdd === 'function' || typeof store?.actions?.save === 'function');
147
+ const normalizedAddButtonPlacement = normalizeText(addButtonPlacement) || 'toolbar';
148
+ const resolvedAddLabel =
149
+ normalizeText(addLabel) ||
150
+ normalizeText(global.t?.t(storeName, 'button', 'add')) ||
151
+ 'Adicionar';
138
152
 
139
153
  if (storeColumns.length === 0 && Array.isArray(columns) && columns.length > 0) {
140
154
  assignGetterValue(store, 'columns', columns);
@@ -155,7 +169,9 @@ const DefaultTable = ({
155
169
  buildRequestQuery,
156
170
  currentPage,
157
171
  handleEndReached,
172
+ handleRefresh,
158
173
  resolvedData,
174
+ resolvedIsRefreshing,
159
175
  } = useDefaultTablePagination({
160
176
  autoMode,
161
177
  columnsForTable,
@@ -165,6 +181,7 @@ const DefaultTable = ({
165
181
  isFocused,
166
182
  isLoading,
167
183
  onEndReached,
184
+ onRefresh,
168
185
  pageSize,
169
186
  requestParams: requestParamsSeed,
170
187
  resolvedActions,
@@ -180,11 +197,43 @@ const DefaultTable = ({
180
197
  storeName,
181
198
  tableColumns: columnsForTable,
182
199
  });
200
+ const closeCreateForm = useCallback(() => setIsCreateFormOpen(false), []);
201
+ const canUseDefaultCreateForm = typeof resolvedActions?.save === 'function';
202
+ const handleAdd = useCallback(() => {
203
+ if (typeof onAdd === 'function') {
204
+ return onAdd();
205
+ }
206
+ if (!canUseDefaultCreateForm) {
207
+ return null;
208
+ }
209
+ setIsCreateFormOpen(true);
210
+ return null;
211
+ }, [canUseDefaultCreateForm, onAdd]);
212
+ const resolvedOnAdd = typeof onAdd === 'function' || canUseDefaultCreateForm
213
+ ? handleAdd
214
+ : null;
215
+ const hasAddAction =
216
+ (addConfig === true || add === true) &&
217
+ typeof resolvedOnAdd === 'function';
218
+ const shouldRenderFloatingAddButton =
219
+ hasAddAction &&
220
+ (normalizedAddButtonPlacement === 'floating' || showToolbar === false);
221
+ const shouldRenderBottomAddButton =
222
+ hasAddAction &&
223
+ showToolbar !== false &&
224
+ normalizedAddButtonPlacement === 'bottom';
225
+ const handleDefaultCreateSaved = useCallback(
226
+ savedItem => {
227
+ closeCreateForm();
228
+ onSaved?.(savedItem, null);
229
+ handleRefresh?.();
230
+ },
231
+ [closeCreateForm, handleRefresh, onSaved],
232
+ );
183
233
  const debugFallbackParameters = useMemo(() => {
184
234
  if (autoMode) {
185
235
  return buildRequestQuery(currentPage || 1, false);
186
236
  }
187
-
188
237
  return {
189
238
  filters: storeFilters,
190
239
  requestParams: requestParamsSeed,
@@ -198,24 +247,36 @@ const DefaultTable = ({
198
247
  const tableFiltersVisible = Boolean(currentConfigs.tableFiltersVisible);
199
248
  const defaultTableConfigs = useMemo(
200
249
  () => ({
250
+ ...storeDeclaredConfigs,
201
251
  add,
252
+ addButtonPlacement: normalizedAddButtonPlacement,
253
+ addLabel: resolvedAddLabel,
254
+ cardListProps,
202
255
  compactBreakpoint,
203
256
  debugFallbackParameters,
257
+ defaultColor,
204
258
  effectiveViewMode,
205
259
  filters,
206
260
  footerComponent,
207
261
  forceCardsOnCompact,
208
262
  getOptionsForColumn,
263
+ import: storeDeclaredConfigs.import,
264
+ importAction,
209
265
  initialViewMode,
210
- onAdd,
266
+ exportAction,
267
+ onAdd: resolvedOnAdd,
211
268
  onDataLoaded,
212
269
  onEditRow,
213
270
  onEndReached: handleEndReached,
271
+ onExport,
214
272
  onFilterChange,
273
+ onImport,
215
274
  onMomentumScrollBegin,
275
+ onRefresh: handleRefresh,
216
276
  onRowPress,
217
277
  onSaved,
218
278
  onScrollBeginDrag,
279
+ onSelectionChange,
219
280
  pinRowActions,
220
281
  renderCard,
221
282
  requestParams: requestParamsSeed,
@@ -224,52 +285,77 @@ const DefaultTable = ({
224
285
  rowActionsComponent,
225
286
  rowActionsWidth,
226
287
  rowStyle,
288
+ searchKey,
289
+ searchPlaceholder,
290
+ selectable: storeSelectable,
227
291
  showColumnFiltersButton,
228
- showRowActions,
292
+ showSearch,
293
+ showRowActions: storeDeclaredConfigs.showRowActions === false ? false : showRowActions,
229
294
  showToolbar,
230
295
  showTotalItemsInCompactToolbar,
231
296
  showTotalItemsInFooter,
232
297
  sortedData,
233
- summary,
234
- summaryLabels,
298
+ summary: summary !== undefined ? summary : store?.getters?.summary,
299
+ summaryLabels: Object.keys(summaryLabels || {}).length
300
+ ? summaryLabels
301
+ : storeDeclaredConfigs.summaryLabels || {},
235
302
  tableFiltersVisible,
303
+ refreshing: resolvedIsRefreshing,
236
304
  tablePreferenceScope,
237
305
  toolbarActions,
238
306
  viewMode: effectiveViewMode,
239
307
  }),
240
308
  [
241
309
  add,
310
+ normalizedAddButtonPlacement,
311
+ resolvedAddLabel,
312
+ cardListProps,
242
313
  compactBreakpoint,
243
314
  debugFallbackParameters,
315
+ defaultColor,
244
316
  effectiveViewMode,
245
317
  filters,
246
318
  footerComponent,
247
319
  forceCardsOnCompact,
248
320
  getOptionsForColumn,
249
321
  handleEndReached,
322
+ handleRefresh,
323
+ resolvedOnAdd,
324
+ storeDeclaredConfigs,
325
+ storeSelectable,
326
+ importAction,
250
327
  initialViewMode,
251
- onAdd,
328
+ exportAction,
252
329
  onDataLoaded,
253
330
  onEditRow,
331
+ onExport,
254
332
  onFilterChange,
333
+ onImport,
255
334
  onMomentumScrollBegin,
335
+ onRefresh,
256
336
  onRowPress,
257
337
  onSaved,
258
338
  onScrollBeginDrag,
339
+ onSelectionChange,
259
340
  pinRowActions,
260
341
  renderCard,
261
342
  requestParamsSeed,
262
343
  requestSort,
344
+ resolvedIsRefreshing,
263
345
  resolvedSort,
264
346
  rowActionsComponent,
265
347
  rowActionsWidth,
266
348
  rowStyle,
349
+ searchKey,
350
+ searchPlaceholder,
267
351
  showColumnFiltersButton,
352
+ showSearch,
268
353
  showRowActions,
269
354
  showToolbar,
270
355
  showTotalItemsInCompactToolbar,
271
356
  showTotalItemsInFooter,
272
357
  sortedData,
358
+ store,
273
359
  summary,
274
360
  summaryLabels,
275
361
  tableFiltersVisible,
@@ -280,17 +366,29 @@ const DefaultTable = ({
280
366
  const defaultTableConfigsSignature = useMemo(
281
367
  () =>
282
368
  stableSerialize({
369
+ configuredImport: storeDeclaredConfigs.import || null,
283
370
  add,
371
+ addButtonPlacement: normalizedAddButtonPlacement,
372
+ addLabel: resolvedAddLabel,
373
+ cardListProps,
284
374
  compactBreakpoint,
375
+ defaultColor,
285
376
  effectiveViewMode,
286
377
  filters,
287
378
  forceCardsOnCompact,
379
+ hasExportAction: Boolean(exportAction || onExport),
380
+ hasImportAction: Boolean(storeDeclaredConfigs.import || importAction || onImport),
288
381
  initialViewMode,
289
382
  pinRowActions,
290
383
  rowActionsComponentType: rowActionsComponent ? typeof rowActionsComponent : '',
291
384
  rowActionsWidth,
385
+ resolvedIsRefreshing,
292
386
  resolvedSort,
387
+ searchKey,
388
+ searchPlaceholder,
389
+ selectable: storeSelectable,
293
390
  showColumnFiltersButton,
391
+ showSearch,
294
392
  showRowActions,
295
393
  showToolbar,
296
394
  showTotalItemsInCompactToolbar,
@@ -302,17 +400,31 @@ const DefaultTable = ({
302
400
  }),
303
401
  [
304
402
  add,
403
+ normalizedAddButtonPlacement,
404
+ resolvedAddLabel,
405
+ cardListProps,
305
406
  compactBreakpoint,
407
+ defaultColor,
306
408
  debugFallbackParameters,
307
409
  effectiveViewMode,
308
410
  filters,
309
411
  forceCardsOnCompact,
412
+ storeDeclaredConfigs,
413
+ storeSelectable,
414
+ exportAction,
415
+ importAction,
310
416
  initialViewMode,
417
+ onExport,
418
+ onImport,
311
419
  pinRowActions,
312
420
  rowActionsComponent,
313
421
  rowActionsWidth,
422
+ resolvedIsRefreshing,
314
423
  resolvedSort,
424
+ searchKey,
425
+ searchPlaceholder,
315
426
  showColumnFiltersButton,
427
+ showSearch,
316
428
  showRowActions,
317
429
  showToolbar,
318
430
  showTotalItemsInCompactToolbar,
@@ -324,79 +436,22 @@ const DefaultTable = ({
324
436
  ],
325
437
  );
326
438
 
327
- if (store?.getters) {
328
- assignGetterValue(store, 'configs', defaultTableConfigs);
329
- }
330
-
331
- useEffect(() => {
332
- if (storeColumns.length > 0 || !Array.isArray(columns) || columns.length === 0) {
333
- return;
334
- }
335
-
336
- publishStoreValue(store, 'setColumns', columns, 'columns');
337
- }, [columns, store, storeColumns.length]);
338
-
339
- useEffect(() => {
340
- if (data === undefined || !Array.isArray(data)) {
341
- return;
342
- }
343
-
344
- publishStoreValue(store, 'setItems', data, 'items');
345
- }, [data, store]);
346
-
347
- useEffect(() => {
348
- if (!columnsForTable.length) {
349
- return;
350
- }
351
-
352
- const storedVisibleColumns = resolveStoredVisibleColumnsPreference(tablePreferenceScope);
353
- if (!storedVisibleColumns) {
354
- return;
355
- }
356
-
357
- const nextVisibleColumns = sanitizeVisibleColumnsPreference({
358
- columns: columnsForTable,
359
- visibleColumns: storedVisibleColumns,
360
- });
361
- const currentVisibleColumns = store?.getters?.visibleColumns || {};
362
-
363
- if (stableSerialize(currentVisibleColumns) === stableSerialize(nextVisibleColumns)) {
364
- return;
365
- }
366
-
367
- publishStoreValue(store, 'setVisibleColumns', nextVisibleColumns, 'visibleColumns');
368
- }, [columnsForTable, store, tablePreferenceScope]);
369
-
370
- useEffect(() => {
371
- if (!columnsForTable.length || Object.keys(storeFilters).length > 0) {
372
- return;
373
- }
374
-
375
- const storedFilters = resolveStoredTableFiltersPreference(tablePreferenceScope);
376
- if (!storedFilters) {
377
- return;
378
- }
379
-
380
- const nextFilters = sanitizeTableFiltersPreference({
381
- columns: columnsForTable,
382
- filters: storedFilters,
383
- });
384
-
385
- if (Object.keys(nextFilters).length === 0) {
386
- return;
387
- }
388
-
389
- publishStoreValue(store, 'setFilters', nextFilters, 'filters');
390
- }, [columnsForTable, store, storeFilters, tablePreferenceScope]);
391
-
392
- useEffect(() => {
393
- if (configsSignatureRef.current === defaultTableConfigsSignature) {
394
- return;
395
- }
396
-
397
- configsSignatureRef.current = defaultTableConfigsSignature;
398
- publishStoreValue(store, 'setConfigs', defaultTableConfigs, 'configs');
399
- }, [defaultTableConfigs, defaultTableConfigsSignature, store]);
439
+ // Do not mutate store.configs during render. A new configs object is built
440
+ // every pass; writing it here retriggers subscribers and React #185 when
441
+ // opening Adicionar on DefaultTable (categories). Sync only in the hook
442
+ // when defaultTableConfigsSignature changes.
443
+ useDefaultTableStoreSync({
444
+ columns,
445
+ columnsForTable,
446
+ data,
447
+ defaultTableConfigs,
448
+ defaultTableConfigsSignature,
449
+ store,
450
+ storeColumnsLength: storeColumns.length,
451
+ storeFilters,
452
+ storeName,
453
+ tablePreferenceScope,
454
+ });
400
455
 
401
456
  useEffect(() => {
402
457
  onDataLoaded?.(sortedData);
@@ -416,20 +471,71 @@ const DefaultTable = ({
416
471
  {showToolbar !== false ? <DefaultTableToolbar storeName={storeName} /> : null}
417
472
  <DefaultTableBody storeName={storeName} />
418
473
  <DefaultTableFooter storeName={storeName} />
474
+ {shouldRenderBottomAddButton ? (
475
+ <View style={styles.bottomAddBar}>
476
+ <TouchableOpacity
477
+ accessibilityRole="button"
478
+ accessibilityLabel={resolvedAddLabel}
479
+ activeOpacity={0.84}
480
+ style={[
481
+ styles.bottomAddButton,
482
+ { backgroundColor: floatingAddBackgroundColor },
483
+ ]}
484
+ onPress={resolvedOnAdd}
485
+ >
486
+ <Icon name="plus" size={18} color={floatingAddIconColor} />
487
+ <Text style={[styles.bottomAddText, { color: floatingAddIconColor }]}>
488
+ {resolvedAddLabel}
489
+ </Text>
490
+ </TouchableOpacity>
491
+ </View>
492
+ ) : null}
419
493
  {shouldRenderFloatingAddButton ? (
420
494
  <TouchableOpacity
421
495
  accessibilityRole="button"
422
- accessibilityLabel={global.t?.t(storeName, 'button', 'add') || 'Adicionar'}
496
+ accessibilityLabel={resolvedAddLabel}
423
497
  activeOpacity={0.84}
424
498
  style={[
425
499
  styles.floatingAddButton,
426
500
  { backgroundColor: floatingAddBackgroundColor },
427
501
  ]}
428
- onPress={() => onAdd?.()}
502
+ onPress={resolvedOnAdd}
429
503
  >
430
504
  <Icon name="plus" size={24} color={floatingAddIconColor} />
431
505
  </TouchableOpacity>
432
506
  ) : null}
507
+ <Modal
508
+ animationType="fade"
509
+ onRequestClose={closeCreateForm}
510
+ transparent
511
+ visible={isCreateFormOpen}
512
+ >
513
+ <View style={styles.modalOverlay}>
514
+ <View style={styles.modalCard}>
515
+ <View style={styles.modalHeader}>
516
+ <Text style={styles.modalTitle}>{resolvedAddLabel}</Text>
517
+ <TouchableOpacity
518
+ accessibilityRole="button"
519
+ accessibilityLabel={global.t?.t(storeName, 'button', 'cancel') || 'Cancelar'}
520
+ onPress={closeCreateForm}
521
+ style={styles.modalCloseButton}
522
+ >
523
+ <Icon name="x" size={16} color={themeColors.textPrimary || '#0F172A'} />
524
+ </TouchableOpacity>
525
+ </View>
526
+ <DefaultForm
527
+ actions={resolvedActions}
528
+ columns={columnsForTable}
529
+ getOptionsForColumn={getOptionsForColumn}
530
+ mode="create"
531
+ onCancel={closeCreateForm}
532
+ onSaved={handleDefaultCreateSaved}
533
+ row={requestParamsSeed}
534
+ storeName={storeName}
535
+ />
536
+ </View>
537
+ </View>
538
+ </Modal>
433
539
  </View>
434
540
  );
435
541
  };