@controleonline/ui-default 1.0.270 → 1.0.272

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 (89) hide show
  1. package/.github/workflows/integration-source-gate.yml +68 -0
  2. package/.github/workflows/manager-worker.yml +19 -0
  3. package/AGENTS.md +46 -50
  4. package/docs/technical/Contrato-de-colunas.md +67 -0
  5. package/docs/technical/Default-Components.md +76 -0
  6. package/docs/technical/DefaultForm.md +80 -0
  7. package/docs/technical/DefaultInput-e-DefaultSelect.md +73 -0
  8. package/docs/technical/DefaultTable.md +203 -0
  9. package/docs/wiki.md +1 -0
  10. package/package.json +22 -21
  11. package/scripts/validate-wiki-pointer.cjs +13 -0
  12. package/src/react/components/address/DefaultAddress.js +435 -0
  13. package/src/react/components/address/DefaultAddress.styles.js +133 -0
  14. package/src/react/components/address/DefaultAddressMapPane.js +55 -0
  15. package/src/react/components/address/LatLonReadonlyFields.js +51 -0
  16. package/src/react/components/address/defaultAddressHelpers.js +163 -0
  17. package/src/react/components/address/defaultAddressStyles.js +136 -0
  18. package/src/react/components/address/defaultAddressUtils.js +129 -0
  19. package/src/react/components/extra-data/DefaultExtraData.js +152 -0
  20. package/src/react/components/extra-data/DefaultExtraData.styles.js +61 -0
  21. package/src/react/components/files/DefaultFile.js +231 -46
  22. package/src/react/components/files/DefaultFileColumn.js +123 -0
  23. package/src/react/components/files/DefaultFileColumn.styles.js +52 -0
  24. package/src/react/components/files/DefaultFileColumn.utils.js +104 -0
  25. package/src/react/components/filters/CompactFilterSelector.js +51 -35
  26. package/src/react/components/filters/DefaultColumnFilter.js +58 -41
  27. package/src/react/components/filters/DefaultExternalFilters.js +331 -265
  28. package/src/react/components/form/DefaultForm.js +99 -79
  29. package/src/react/components/help/DefaultTooltip.js +59 -33
  30. package/src/react/components/help/DefaultTooltip.styles.js +23 -3
  31. package/src/react/components/inputs/DefaultColorInput.js +153 -0
  32. package/src/react/components/inputs/DefaultFeatherIconPicker.js +146 -0
  33. package/src/react/components/inputs/DefaultFeatherIconPicker.styles.js +113 -0
  34. package/src/react/components/inputs/DefaultInput.js +69 -5
  35. package/src/react/components/inputs/DefaultInput.styles.js +26 -0
  36. package/src/react/components/inputs/DefaultSelect.js +134 -123
  37. package/src/react/components/inputs/defaultInputUtils.js +69 -43
  38. package/src/react/components/map/DefaultMap.native.js +73 -73
  39. package/src/react/components/map/DefaultMap.shared.js +911 -762
  40. package/src/react/components/map/DefaultMap.web.js +124 -68
  41. package/src/react/components/table/DefaultColumnMenu.js +109 -108
  42. package/src/react/components/table/DefaultDebug.js +44 -37
  43. package/src/react/components/table/DefaultSearchModal.js +9 -1
  44. package/src/react/components/table/DefaultTable.grouping.js +98 -0
  45. package/src/react/components/table/DefaultTable.js +213 -107
  46. package/src/react/components/table/DefaultTable.styles.js +367 -314
  47. package/src/react/components/table/DefaultTableBody.js +13 -8
  48. package/src/react/components/table/DefaultTableCards.js +20 -1
  49. package/src/react/components/table/DefaultTableControls.js +180 -205
  50. package/src/react/components/table/DefaultTableImportModal.js +108 -0
  51. package/src/react/components/table/DefaultTableInput.js +1 -0
  52. package/src/react/components/table/DefaultTableRowActions.js +1 -1
  53. package/src/react/components/table/DefaultTableRows.js +224 -363
  54. package/src/react/components/table/DefaultTableSearch.js +28 -5
  55. package/src/react/components/table/DefaultTableToolbar.js +92 -3
  56. package/src/react/components/table/useDefaultTablePagination.js +56 -7
  57. package/src/react/components/table/useDefaultTableStoreSync.js +164 -0
  58. package/src/react/components/upload/DefaultUpload.js +436 -0
  59. package/src/react/components/upload/DefaultUpload.styles.js +153 -0
  60. package/src/react/components/upload/DefaultUploadAttachmentsList.js +138 -0
  61. package/src/react/components/upload/DefaultUploadManagerModal.js +247 -0
  62. package/src/react/components/upload/defaultUploadHelpers.js +108 -0
  63. package/src/react/components/upload/defaultUploadLibrary.js +248 -0
  64. package/src/react/components/upload/fileUpload.js +93 -0
  65. package/src/react/hooks/usePostalCodeLookup.js +145 -0
  66. package/src/react/index.js +6 -0
  67. package/src/react/services/addressFormUtils.js +196 -0
  68. package/src/react/services/addressGeo.js +227 -0
  69. package/src/react/utils/tableVisibleColumnsPreferences.js +29 -12
  70. package/src/tests/react/components/address/defaultAddressHelpers.test.js +104 -0
  71. package/src/tests/react/components/files/DefaultFile.test.js +6 -6
  72. package/src/tests/react/components/form/DefaultForm.test.js +123 -0
  73. package/src/tests/react/components/inputs/DefaultSelect.test.js +108 -79
  74. package/src/tests/react/components/table/DefaultTable.grouping.test.js +49 -0
  75. package/src/tests/react/components/table/DefaultTable.test.js +53 -2
  76. package/src/tests/react/components/table/DefaultTableControls.filters.test.mjs +21 -0
  77. package/src/tests/react/components/table/resolveRowBackgroundColor.test.mjs +45 -0
  78. package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +161 -0
  79. package/src/tests/react/components/upload/DefaultUpload.test.js +353 -0
  80. package/src/tests/react/components/upload/defaultUploadLibrary.test.js +82 -0
  81. package/src/tests/react/components/upload/peopleMediaLibraryPreview.test.mjs +57 -0
  82. package/src/tests/react/hooks/usePostalCodeLookup.test.js +40 -0
  83. package/src/tests/react/services/SMOKE-637-cep-hydrate.md +45 -0
  84. package/src/tests/react/services/addressFormUtils.test.js +176 -0
  85. package/src/tests/react/services/addressGeoLookup.async.test.js +104 -0
  86. package/src/tests/react/services/addressGeoLookup.test.js +105 -0
  87. package/src/tests/react/services/smoke-637/form-cep-12941040.png +0 -0
  88. package/src/tests/react/services/smoke-637/index.html +132 -0
  89. package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +84 -48
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
- import { useWindowDimensions } from 'react-native';
2
+ import { useWindowDimensions, View } from 'react-native';
3
3
  import { useStore } from '@store';
4
- import DefaultTableCards from './DefaultTableCards';
5
- import DefaultTableRows from './DefaultTableRows';
6
- import { DEFAULT_COMPACT_BREAKPOINT } from './DefaultTable.utils';
4
+ import DefaultTableCards from './DefaultTableCards';
5
+ import DefaultTableRows from './DefaultTableRows';
6
+ import { DEFAULT_COMPACT_BREAKPOINT } from './DefaultTable.utils';
7
+ import styles from './DefaultTable.styles';
7
8
 
8
9
  const DefaultTableBody = ({ storeName }) => {
9
10
  const store = useStore(storeName);
@@ -18,9 +19,13 @@ const DefaultTableBody = ({ storeName }) => {
18
19
  configs.initialViewMode ||
19
20
  'table';
20
21
 
21
- return effectiveViewMode === 'cards'
22
- ? <DefaultTableCards storeName={storeName} />
23
- : <DefaultTableRows storeName={storeName} />;
24
- };
22
+ return (
23
+ <View style={styles.body}>
24
+ {effectiveViewMode === 'cards'
25
+ ? <DefaultTableCards storeName={storeName} />
26
+ : <DefaultTableRows storeName={storeName} />}
27
+ </View>
28
+ );
29
+ };
25
30
 
26
31
  export default DefaultTableBody;
@@ -31,6 +31,16 @@ const DefaultTableCards = ({ storeName }) => {
31
31
  liveItems: store?.getters?.items,
32
32
  sortedData: configs.sortedData,
33
33
  });
34
+ const cardListProps =
35
+ configs.cardListProps && typeof configs.cardListProps === 'object'
36
+ ? configs.cardListProps
37
+ : {};
38
+ const {
39
+ contentContainerStyle,
40
+ key: cardListKey,
41
+ listKey,
42
+ ...flatListProps
43
+ } = cardListProps;
34
44
  const isLoading = Boolean(store?.getters?.isLoadingList || store?.getters?.isLoading);
35
45
  const emptyStateLabel = isLoading
36
46
  ? global.t?.t(storeName, 'label', 'loading')
@@ -39,6 +49,7 @@ const DefaultTableCards = ({ storeName }) => {
39
49
  const tableMutedColor = palette.textSecondary;
40
50
  const tableSurfaceColor = palette.background;
41
51
  const tableTextColor = palette.text;
52
+ const hasBottomAddButton = configs.addButtonPlacement === 'bottom';
42
53
  const handleListScroll = event => {
43
54
  if (shouldTriggerEndReachedFromScroll(event)) {
44
55
  configs.onEndReached?.();
@@ -159,11 +170,17 @@ const DefaultTableCards = ({ storeName }) => {
159
170
 
160
171
  return (
161
172
  <FlatList
173
+ key={listKey || cardListKey || `cards-${flatListProps.numColumns || 1}`}
174
+ {...flatListProps}
162
175
  data={sortedData}
163
176
  keyExtractor={getRowKey}
164
177
  renderItem={({ item, index }) => renderCardItem(item, index)}
165
178
  style={styles.cardsScroll}
166
- contentContainerStyle={styles.cardsGrid}
179
+ contentContainerStyle={[
180
+ styles.cardsGrid,
181
+ contentContainerStyle,
182
+ hasBottomAddButton ? styles.cardsGridWithBottomAdd : null,
183
+ ]}
167
184
  ListEmptyComponent={(
168
185
  <DefaultTableEmptyState
169
186
  emptyStateLabel={emptyStateLabel}
@@ -180,6 +197,8 @@ const DefaultTableCards = ({ storeName }) => {
180
197
  onScrollBeginDrag={configs.onScrollBeginDrag || undefined}
181
198
  onEndReached={configs.onEndReached}
182
199
  onEndReachedThreshold={END_REACHED_THRESHOLD}
200
+ onRefresh={configs.onRefresh}
201
+ refreshing={Boolean(configs.refreshing)}
183
202
  scrollEventThrottle={120}
184
203
  showsVerticalScrollIndicator={false}
185
204
  />
@@ -1,205 +1,180 @@
1
- import React from 'react';
2
- import { Text, TouchableOpacity } from 'react-native';
3
- import Icon from 'react-native-vector-icons/Feather';
4
- import { useStore } from '@store';
5
- import DefaultColumnMenu from './DefaultColumnMenu';
6
- import DefaultDebug from './DefaultDebug';
7
- import DefaultFiltersModal from './DefaultFiltersModal';
8
- import DefaultModalButton from './DefaultModalButton';
9
- import styles from './DefaultTable.styles';
10
- import { normalizeText } from '../inputs/defaultInputUtils';
11
- import {
12
- persistTableViewModePreference,
13
- resolveDefaultTablePreferenceScope,
14
- } from '../../utils/tableVisibleColumnsPreferences';
15
- import { shouldIncludeColumn } from './DefaultTable.utils';
16
- import useDefaultTableTheme from './useDefaultTableTheme';
17
-
18
- const DefaultTableControls = ({ storeName }) => {
19
- const store = useStore(storeName);
20
- const configs = store?.getters?.configs || {};
21
- const effectiveViewMode =
22
- configs.effectiveViewMode ||
23
- configs.viewMode ||
24
- configs.initialViewMode ||
25
- 'table';
26
- const tablePreferenceScope =
27
- configs.tablePreferenceScope ||
28
- resolveDefaultTablePreferenceScope({ storeName });
29
- const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
30
- const filters = store?.getters?.filters || {};
31
- const hasFilterableColumns = columns.some(
32
- column =>
33
- configs.showColumnFiltersButton !== false &&
34
- shouldIncludeColumn(column) &&
35
- column?.filter !== false &&
36
- column?.filters !== false,
37
- );
38
- const tableFiltersVisible = Boolean(configs.tableFiltersVisible);
39
- const activeFilterCount = Object.values(filters).filter(value => normalizeText(value) !== '').length;
40
- const addConfig = store?.getters?.add;
41
- const shouldRenderAddButton =
42
- (addConfig === true || configs.add === true) &&
43
- (typeof configs.onAdd === 'function' || typeof store?.actions?.save === 'function');
44
- const { tableButtonColors } = useDefaultTableTheme();
45
- const {
46
- backgroundColor,
47
- borderColor,
48
- iconColor,
49
- pressedBackgroundColor,
50
- pressedBorderColor,
51
- pressedIconColor,
52
- textColor,
53
- } = tableButtonColors;
54
-
55
- const buttonStyle = [
56
- styles.toolbarButton,
57
- { borderColor, backgroundColor },
58
- ];
59
- const pressedStyle = {
60
- backgroundColor: pressedBackgroundColor,
61
- borderColor: pressedBorderColor,
62
- };
63
- const updateConfigs = nextConfigs => {
64
- if (typeof store?.actions?.setConfigs === 'function') {
65
- store.actions.setConfigs(nextConfigs);
66
- return;
67
- }
68
-
69
- if (store?.getters) {
70
- store.getters.configs = nextConfigs;
71
- }
72
- };
73
- const nextViewMode = effectiveViewMode === 'table' ? 'cards' : 'table';
74
-
75
- return (
76
- <>
77
- <DefaultDebug storeName={storeName} />
78
- {hasFilterableColumns && effectiveViewMode === 'table' ? (
79
- <TouchableOpacity
80
- style={[
81
- ...buttonStyle,
82
- tableFiltersVisible ? pressedStyle : null,
83
- ]}
84
- activeOpacity={0.82}
85
- onPress={() =>
86
- updateConfigs({
87
- ...configs,
88
- tableFiltersVisible: !tableFiltersVisible,
89
- })
90
- }
91
- >
92
- <Icon
93
- name="filter"
94
- size={14}
95
- color={tableFiltersVisible ? pressedIconColor : textColor}
96
- />
97
- {activeFilterCount > 0 ? (
98
- <Text
99
- style={[
100
- styles.toolbarBadgeText,
101
- { color: tableFiltersVisible ? pressedIconColor : textColor },
102
- ]}
103
- >
104
- {activeFilterCount}
105
- </Text>
106
- ) : null}
107
- </TouchableOpacity>
108
- ) : null}
109
- {hasFilterableColumns && effectiveViewMode === 'cards' ? (
110
- <DefaultModalButton
111
- renderButton={({ isOpen, open }) => (
112
- <TouchableOpacity
113
- style={[
114
- ...buttonStyle,
115
- isOpen ? pressedStyle : null,
116
- ]}
117
- activeOpacity={0.82}
118
- onPress={open}
119
- >
120
- <Icon
121
- name="filter"
122
- size={14}
123
- color={isOpen ? pressedIconColor : textColor}
124
- />
125
- {activeFilterCount > 0 ? (
126
- <Text
127
- style={[
128
- styles.toolbarBadgeText,
129
- { color: isOpen ? pressedIconColor : textColor },
130
- ]}>
131
- {activeFilterCount}
132
- </Text>
133
- ) : null}
134
- </TouchableOpacity>
135
- )}
136
- >
137
- {({ close, isOpen }) => (
138
- <DefaultFiltersModal
139
- storeName={storeName}
140
- visible={isOpen}
141
- onClose={close}
142
- />
143
- )}
144
- </DefaultModalButton>
145
- ) : null}
146
- <TouchableOpacity
147
- style={buttonStyle}
148
- activeOpacity={0.82}
149
- onPress={() => {
150
- const nextConfigs = {
151
- ...configs,
152
- effectiveViewMode: nextViewMode,
153
- viewMode: nextViewMode,
154
- };
155
-
156
- persistTableViewModePreference(tablePreferenceScope, nextConfigs.viewMode);
157
- updateConfigs(nextConfigs);
158
- }}
159
- >
160
- <Icon
161
- name={nextViewMode === 'cards' ? 'grid' : 'list'}
162
- size={14}
163
- color={textColor}
164
- />
165
- </TouchableOpacity>
166
- <DefaultModalButton
167
- renderButton={({ isOpen, toggle }) => (
168
- <TouchableOpacity
169
- style={[
170
- ...buttonStyle,
171
- isOpen ? pressedStyle : null,
172
- ]}
173
- activeOpacity={0.82}
174
- onPress={toggle}
175
- >
176
- <Icon name="columns" size={14} color={isOpen ? pressedIconColor : textColor} />
177
- </TouchableOpacity>
178
- )}
179
- >
180
- {({ close, isOpen }) => (
181
- <DefaultColumnMenu
182
- storeName={storeName}
183
- visible={isOpen}
184
- onClose={close}
185
- />
186
- )}
187
- </DefaultModalButton>
188
- {shouldRenderAddButton ? (
189
- <TouchableOpacity
190
- style={[
191
- styles.toolbarButton,
192
- styles.toolbarAddButton,
193
- { backgroundColor: backgroundColor, borderColor: backgroundColor },
194
- ]}
195
- activeOpacity={0.85}
196
- onPress={() => configs.onAdd?.()}
197
- >
198
- <Icon name="plus" size={16} color={textColor} />
199
- </TouchableOpacity>
200
- ) : null}
201
- </>
202
- );
203
- };
204
-
205
- export default DefaultTableControls;
1
+ // fluxo: outros | etapa: order-history-page-filtro | https://github.com/ControleOnline/app-community/wiki/Smoke-Test-Flows
2
+ import React from 'react';
3
+ import { Text, TouchableOpacity } from 'react-native';
4
+ import Icon from 'react-native-vector-icons/Feather';
5
+ import { useStore } from '@store';
6
+ import DefaultColumnMenu from './DefaultColumnMenu';
7
+ import DefaultDebug from './DefaultDebug';
8
+ import DefaultFiltersModal from './DefaultFiltersModal';
9
+ import DefaultModalButton from './DefaultModalButton';
10
+ import styles from './DefaultTable.styles';
11
+ import { normalizeText } from '../inputs/defaultInputUtils';
12
+ import {
13
+ persistTableViewModePreference,
14
+ resolveDefaultTablePreferenceScope,
15
+ } from '../../utils/tableVisibleColumnsPreferences';
16
+ import { shouldIncludeColumn } from './DefaultTable.utils';
17
+ import useDefaultTableTheme from './useDefaultTableTheme';
18
+
19
+ const DefaultTableControls = ({ storeName }) => {
20
+ const store = useStore(storeName);
21
+ const configs = store?.getters?.configs || {};
22
+ const effectiveViewMode =
23
+ configs.effectiveViewMode ||
24
+ configs.viewMode ||
25
+ configs.initialViewMode ||
26
+ 'table';
27
+ const tablePreferenceScope =
28
+ configs.tablePreferenceScope ||
29
+ resolveDefaultTablePreferenceScope({ storeName });
30
+ const columns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
31
+ const filters = store?.getters?.filters || {};
32
+ const hasFilterableColumns = columns.some(
33
+ column =>
34
+ configs.showColumnFiltersButton !== false &&
35
+ shouldIncludeColumn(column) &&
36
+ column?.filter !== false &&
37
+ column?.filters !== false,
38
+ );
39
+ const activeFilterCount = Object.values(filters).filter(value => normalizeText(value) !== '').length;
40
+ const addConfig = store?.getters?.add;
41
+ const addButtonPlacement = normalizeText(configs.addButtonPlacement) || 'toolbar';
42
+ const shouldRenderAddButton =
43
+ addButtonPlacement === 'toolbar' &&
44
+ (addConfig === true || configs.add === true) &&
45
+ (typeof configs.onAdd === 'function' || typeof store?.actions?.save === 'function');
46
+ const { tableButtonColors } = useDefaultTableTheme();
47
+ const {
48
+ backgroundColor,
49
+ borderColor,
50
+ iconColor,
51
+ pressedBackgroundColor,
52
+ pressedBorderColor,
53
+ pressedIconColor,
54
+ textColor,
55
+ } = tableButtonColors;
56
+
57
+ const buttonStyle = [
58
+ styles.toolbarButton,
59
+ { borderColor, backgroundColor },
60
+ ];
61
+ const pressedStyle = {
62
+ backgroundColor: pressedBackgroundColor,
63
+ borderColor: pressedBorderColor,
64
+ };
65
+ const updateConfigs = nextConfigs => {
66
+ if (typeof store?.actions?.setConfigs === 'function') {
67
+ store.actions.setConfigs(nextConfigs);
68
+ return;
69
+ }
70
+
71
+ if (store?.getters) {
72
+ store.getters.configs = nextConfigs;
73
+ }
74
+ };
75
+ const nextViewMode = effectiveViewMode === 'table' ? 'cards' : 'table';
76
+
77
+ return (
78
+ <>
79
+ <DefaultDebug storeName={storeName} />
80
+ {/* app-community#811: LISTA (table) e CARD abrem o mesmo DefaultFiltersModal */}
81
+ {hasFilterableColumns ? (
82
+ <DefaultModalButton
83
+ renderButton={({ isOpen, open }) => (
84
+ <TouchableOpacity
85
+ accessibilityLabel="Filtros"
86
+ testID="default-table-filter-button"
87
+ style={[
88
+ ...buttonStyle,
89
+ isOpen ? pressedStyle : null,
90
+ ]}
91
+ activeOpacity={0.82}
92
+ onPress={open}
93
+ >
94
+ <Icon
95
+ name="filter"
96
+ size={14}
97
+ color={isOpen ? pressedIconColor : textColor}
98
+ />
99
+ {activeFilterCount > 0 ? (
100
+ <Text
101
+ style={[
102
+ styles.toolbarBadgeText,
103
+ { color: isOpen ? pressedIconColor : textColor },
104
+ ]}
105
+ >
106
+ {activeFilterCount}
107
+ </Text>
108
+ ) : null}
109
+ </TouchableOpacity>
110
+ )}
111
+ >
112
+ {({ close, isOpen }) => (
113
+ <DefaultFiltersModal
114
+ storeName={storeName}
115
+ visible={isOpen}
116
+ onClose={close}
117
+ />
118
+ )}
119
+ </DefaultModalButton>
120
+ ) : null}
121
+ <TouchableOpacity
122
+ style={buttonStyle}
123
+ activeOpacity={0.82}
124
+ onPress={() => {
125
+ const nextConfigs = {
126
+ ...configs,
127
+ effectiveViewMode: nextViewMode,
128
+ viewMode: nextViewMode,
129
+ };
130
+
131
+ persistTableViewModePreference(tablePreferenceScope, nextConfigs.viewMode);
132
+ updateConfigs(nextConfigs);
133
+ }}
134
+ >
135
+ <Icon
136
+ name={nextViewMode === 'cards' ? 'grid' : 'list'}
137
+ size={14}
138
+ color={textColor}
139
+ />
140
+ </TouchableOpacity>
141
+ <DefaultModalButton
142
+ renderButton={({ isOpen, toggle }) => (
143
+ <TouchableOpacity
144
+ style={[
145
+ ...buttonStyle,
146
+ isOpen ? pressedStyle : null,
147
+ ]}
148
+ activeOpacity={0.82}
149
+ onPress={toggle}
150
+ >
151
+ <Icon name="columns" size={14} color={isOpen ? pressedIconColor : textColor} />
152
+ </TouchableOpacity>
153
+ )}
154
+ >
155
+ {({ close, isOpen }) => (
156
+ <DefaultColumnMenu
157
+ storeName={storeName}
158
+ visible={isOpen}
159
+ onClose={close}
160
+ />
161
+ )}
162
+ </DefaultModalButton>
163
+ {shouldRenderAddButton ? (
164
+ <TouchableOpacity
165
+ style={[
166
+ styles.toolbarButton,
167
+ styles.toolbarAddButton,
168
+ { backgroundColor: backgroundColor, borderColor: backgroundColor },
169
+ ]}
170
+ activeOpacity={0.85}
171
+ onPress={() => configs.onAdd?.()}
172
+ >
173
+ <Icon name="plus" size={16} color={textColor} />
174
+ </TouchableOpacity>
175
+ ) : null}
176
+ </>
177
+ );
178
+ };
179
+
180
+ export default DefaultTableControls;
@@ -0,0 +1,108 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Modal } from 'react-native';
3
+ import ImportsPage from '@controleonline/ui-common/src/react/pages/Imports';
4
+ import { useStore } from '@store';
5
+
6
+ const normalizeText = value => String(value ?? '').trim();
7
+
8
+ const FORBIDDEN_EXTENSION_TOKENS = new Set(['*', '*.*', '.', '', '.*']);
9
+
10
+ export const sanitizeAllowedExtensions = (extensions, fallback = ['csv']) => {
11
+ const source = Array.isArray(extensions) ? extensions : [];
12
+ const cleaned = source
13
+ .map(item => normalizeText(item).replace(/^\./, '').toLowerCase())
14
+ .filter(item => item && !FORBIDDEN_EXTENSION_TOKENS.has(item) && !item.includes('*'));
15
+
16
+ if (cleaned.length === 0) {
17
+ return (fallback || ['csv'])
18
+ .map(item => normalizeText(item).replace(/^\./, '').toLowerCase())
19
+ .filter(item => item && !FORBIDDEN_EXTENSION_TOKENS.has(item) && !item.includes('*'));
20
+ }
21
+
22
+ return [...new Set(cleaned)];
23
+ };
24
+
25
+ const translateConfigKey = key => {
26
+ if (!Array.isArray(key) || key.length < 3) {
27
+ return '';
28
+ }
29
+
30
+ return normalizeText(global.t?.t?.(key[0], key[1], key[2]));
31
+ };
32
+
33
+ const resolveConfiguredText = ({ config, fallbackKey, literalKey, translationKey }) => {
34
+ const literalValue = normalizeText(config?.[literalKey]);
35
+ if (literalValue) {
36
+ return literalValue;
37
+ }
38
+
39
+ const configuredTranslation = translateConfigKey(config?.[translationKey]);
40
+ if (configuredTranslation) {
41
+ return configuredTranslation;
42
+ }
43
+
44
+ return normalizeText(global.t?.t?.('defaultTable', 'label', fallbackKey));
45
+ };
46
+
47
+ const DefaultTableImportModal = ({
48
+ onClose,
49
+ storeName,
50
+ visible,
51
+ importType: importTypeProp,
52
+ allowedExtensions: allowedExtensionsProp,
53
+ title: titleProp,
54
+ }) => {
55
+ const store = useStore(storeName);
56
+ const configs = store?.getters?.configs || {};
57
+ const resolvedConfig = configs.import || {};
58
+ const importType =
59
+ normalizeText(importTypeProp) || normalizeText(resolvedConfig.importType) || 'csv';
60
+ const allowedExtensions = sanitizeAllowedExtensions(
61
+ allowedExtensionsProp || resolvedConfig.allowedExtensions,
62
+ importType === 'invoice_tax' || importType === 'xml' ? ['xml', 'zip'] : ['csv'],
63
+ );
64
+
65
+ const context = useMemo(
66
+ () => ({
67
+ context: importType,
68
+ storeName,
69
+ allowedExtensions,
70
+ title:
71
+ normalizeText(titleProp) ||
72
+ resolveConfiguredText({
73
+ config: resolvedConfig,
74
+ fallbackKey: 'import',
75
+ literalKey: 'title',
76
+ translationKey: 'titleKey',
77
+ }),
78
+ searchPlaceholder: resolveConfiguredText({
79
+ config: resolvedConfig,
80
+ fallbackKey: 'importSearch',
81
+ literalKey: 'searchPlaceholder',
82
+ translationKey: 'searchPlaceholderKey',
83
+ }),
84
+ }),
85
+ [
86
+ allowedExtensions,
87
+ importType,
88
+ resolvedConfig.searchPlaceholder,
89
+ resolvedConfig.searchPlaceholderKey,
90
+ resolvedConfig.title,
91
+ resolvedConfig.titleKey,
92
+ storeName,
93
+ titleProp,
94
+ ],
95
+ );
96
+
97
+ if (!importType) {
98
+ return null;
99
+ }
100
+
101
+ return (
102
+ <Modal visible={visible} animationType="slide" transparent={false}>
103
+ <ImportsPage context={context} onClose={onClose} />
104
+ </Modal>
105
+ );
106
+ };
107
+
108
+ export default DefaultTableImportModal;
@@ -72,6 +72,7 @@ const DefaultTableInput = ({
72
72
  column={column}
73
73
  columns={columns}
74
74
  containerStyle={options.containerStyle}
75
+ defaultColor={options.defaultColor || configs.defaultColor}
75
76
  displayValue={options.displayValue}
76
77
  editing={isEditing}
77
78
  getOptionsForColumn={configs.getOptionsForColumn}
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
 
3
- const DEFAULT_ROW_ACTIONS_WIDTH = 96;
3
+ const DEFAULT_ROW_ACTIONS_WIDTH = 140;
4
4
 
5
5
  const isReactComponentType = value =>
6
6
  value &&