@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.
- package/.github/workflows/integration-source-gate.yml +68 -0
- package/.github/workflows/manager-worker.yml +19 -0
- package/.github/workflows/publish-npm.yml +91 -0
- package/AGENTS.md +46 -50
- package/docs/technical/Contrato-de-colunas.md +67 -0
- package/docs/technical/Default-Components.md +76 -0
- package/docs/technical/DefaultForm.md +80 -0
- package/docs/technical/DefaultInput-e-DefaultSelect.md +73 -0
- package/docs/technical/DefaultTable.md +272 -0
- package/docs/wiki.md +1 -0
- package/package.json +4 -3
- package/scripts/validate-wiki-pointer.cjs +13 -0
- package/src/react/components/address/DefaultAddress.js +446 -0
- package/src/react/components/address/DefaultAddress.styles.js +133 -0
- package/src/react/components/address/DefaultAddressCoordFields.js +59 -0
- package/src/react/components/address/DefaultAddressMapPane.js +55 -0
- package/src/react/components/address/LatLonReadonlyFields.js +51 -0
- package/src/react/components/address/defaultAddressHelpers.js +163 -0
- package/src/react/components/address/defaultAddressStyles.js +148 -0
- package/src/react/components/address/defaultAddressUtils.js +129 -0
- package/src/react/components/extra-data/DefaultExtraData.js +152 -0
- package/src/react/components/extra-data/DefaultExtraData.styles.js +61 -0
- package/src/react/components/files/DefaultFile.js +231 -46
- package/src/react/components/files/DefaultFileColumn.js +123 -0
- package/src/react/components/files/DefaultFileColumn.styles.js +52 -0
- package/src/react/components/files/DefaultFileColumn.utils.js +104 -0
- package/src/react/components/filters/CompactFilterSelector.js +51 -35
- package/src/react/components/filters/DefaultColumnFilter.js +60 -48
- package/src/react/components/filters/DefaultExternalFilters.js +324 -265
- package/src/react/components/filters/filterValue.js +65 -0
- package/src/react/components/form/DefaultForm.js +99 -79
- package/src/react/components/help/DefaultTooltip.js +48 -12
- package/src/react/components/help/DefaultTooltip.styles.js +20 -0
- package/src/react/components/inputs/DefaultColorInput.js +153 -0
- package/src/react/components/inputs/DefaultFeatherIconPicker.js +146 -0
- package/src/react/components/inputs/DefaultFeatherIconPicker.styles.js +113 -0
- package/src/react/components/inputs/DefaultInput.js +296 -141
- package/src/react/components/inputs/DefaultInput.styles.js +26 -0
- package/src/react/components/inputs/DefaultSelect.js +134 -123
- package/src/react/components/inputs/defaultInputUtils.js +262 -213
- package/src/react/components/map/DefaultMap.native.js +73 -73
- package/src/react/components/map/DefaultMap.shared.js +911 -762
- package/src/react/components/map/DefaultMap.web.js +124 -68
- package/src/react/components/table/DefaultColumnMenu.js +22 -3
- package/src/react/components/table/DefaultDebug.js +44 -37
- package/src/react/components/table/DefaultSearchModal.js +9 -1
- package/src/react/components/table/DefaultTable.grouping.js +98 -0
- package/src/react/components/table/DefaultTable.js +217 -111
- package/src/react/components/table/DefaultTable.styles.js +369 -310
- package/src/react/components/table/DefaultTable.utils.js +38 -4
- package/src/react/components/table/DefaultTableBody.js +13 -8
- package/src/react/components/table/DefaultTableCards.js +20 -1
- package/src/react/components/table/DefaultTableControls.js +180 -205
- package/src/react/components/table/DefaultTableImportModal.js +108 -0
- package/src/react/components/table/DefaultTableInput.js +1 -0
- package/src/react/components/table/DefaultTableRowActions.js +1 -1
- package/src/react/components/table/DefaultTableRows.js +357 -325
- package/src/react/components/table/DefaultTableSearch.js +28 -5
- package/src/react/components/table/DefaultTableToolbar.js +92 -3
- package/src/react/components/table/useDefaultTablePagination.js +56 -7
- package/src/react/components/table/useDefaultTableStoreSync.js +164 -0
- package/src/react/components/upload/DefaultUpload.js +406 -0
- package/src/react/components/upload/DefaultUpload.styles.js +153 -0
- package/src/react/components/upload/DefaultUploadAttachmentsList.js +146 -0
- package/src/react/components/upload/DefaultUploadManagerModal.js +247 -0
- package/src/react/components/upload/defaultUploadHelpers.js +108 -0
- package/src/react/components/upload/defaultUploadLibrary.js +248 -0
- package/src/react/components/upload/fileUpload.js +93 -0
- package/src/react/hooks/usePostalCodeLookup.js +159 -0
- package/src/react/index.js +6 -0
- package/src/react/services/addressFormUtils.js +262 -0
- package/src/react/services/addressGeo.js +230 -0
- package/src/react/utils/tableVisibleColumnsPreferences.js +113 -15
- package/src/tests/react/components/address/defaultAddressHelpers.test.js +104 -0
- package/src/tests/react/components/files/DefaultFile.test.js +22 -6
- package/src/tests/react/components/files/DefaultFileColumn.company.test.js +24 -0
- package/src/tests/react/components/form/DefaultForm.test.js +123 -0
- package/src/tests/react/components/help/DefaultTooltip.test.js +93 -0
- package/src/tests/react/components/inputs/DefaultSelect.test.js +108 -79
- package/src/tests/react/components/table/DefaultTable.grouping.test.js +49 -0
- package/src/tests/react/components/table/DefaultTable.test.js +53 -2
- package/src/tests/react/components/table/DefaultTable.utils.test.js +10 -0
- package/src/tests/react/components/table/DefaultTableControls.filters.test.mjs +21 -0
- package/src/tests/react/components/table/DefaultTableRowActions.test.js +23 -0
- package/src/tests/react/components/table/DefaultTableRows.rowActions.test.js +152 -0
- package/src/tests/react/components/table/resolveRowBackgroundColor.test.mjs +45 -0
- package/src/tests/react/components/table/useDefaultTableStoreSync.test.js +161 -0
- package/src/tests/react/components/upload/DefaultUpload.test.js +353 -0
- package/src/tests/react/components/upload/defaultUploadLibrary.test.js +104 -0
- package/src/tests/react/components/upload/peopleMediaLibraryPreview.test.mjs +57 -0
- package/src/tests/react/filters/filterValue.test.js +46 -0
- package/src/tests/react/hooks/usePostalCodeLookup.test.js +107 -0
- package/src/tests/react/inputs/defaultInputUtils.test.js +9 -1
- package/src/tests/react/services/SMOKE-637-cep-hydrate.md +45 -0
- package/src/tests/react/services/addressFormUtils.test.js +179 -0
- package/src/tests/react/services/addressGeoLookup.async.test.js +104 -0
- package/src/tests/react/services/addressGeoLookup.test.js +105 -0
- package/src/tests/react/services/smoke-637/form-cep-12941040.png +0 -0
- package/src/tests/react/services/smoke-637/index.html +132 -0
- package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +96 -49
|
@@ -438,6 +438,42 @@ export const normalizeSortText = value =>
|
|
|
438
438
|
.replace(/[\u0300-\u036f]/g, '')
|
|
439
439
|
.toLowerCase();
|
|
440
440
|
|
|
441
|
+
export const parseSortNumber = value => {
|
|
442
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
443
|
+
if (value == null) return NaN;
|
|
444
|
+
|
|
445
|
+
const raw = String(value).trim();
|
|
446
|
+
if (!raw || !/[0-9]/.test(raw)) return NaN;
|
|
447
|
+
|
|
448
|
+
const compact = raw.replace(/[^0-9,.-]/g, '');
|
|
449
|
+
if (!compact) return NaN;
|
|
450
|
+
|
|
451
|
+
const hasComma = compact.includes(',');
|
|
452
|
+
const hasDot = compact.includes('.');
|
|
453
|
+
let normalized = compact;
|
|
454
|
+
|
|
455
|
+
if (hasComma && hasDot) {
|
|
456
|
+
normalized = compact.lastIndexOf(',') > compact.lastIndexOf('.')
|
|
457
|
+
? compact.replace(/\./g, '').replace(',', '.')
|
|
458
|
+
: compact.replace(/,/g, '');
|
|
459
|
+
} else if (hasComma) {
|
|
460
|
+
const parts = compact.split(',');
|
|
461
|
+
normalized = parts.length === 2 && parts[1].length <= 2
|
|
462
|
+
? `${parts[0].replace(/\./g, '')}.${parts[1]}`
|
|
463
|
+
: compact.replace(/,/g, '');
|
|
464
|
+
} else if (hasDot) {
|
|
465
|
+
const parts = compact.split('.');
|
|
466
|
+
if (parts.length > 2) {
|
|
467
|
+
normalized = compact.replace(/\./g, '');
|
|
468
|
+
} else if (parts.length === 2 && parts[1].length === 3 && parts[0].length <= 3) {
|
|
469
|
+
normalized = compact.replace(/\./g, '');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const parsed = Number(normalized);
|
|
474
|
+
return Number.isFinite(parsed) ? parsed : NaN;
|
|
475
|
+
};
|
|
476
|
+
|
|
441
477
|
export const resolveSortComparable = ({ column, row, storeName, columns }) => {
|
|
442
478
|
const fieldName = getColumnKey(column);
|
|
443
479
|
const sortField = getSortField(column);
|
|
@@ -472,11 +508,9 @@ export const resolveSortComparable = ({ column, row, storeName, columns }) => {
|
|
|
472
508
|
storeName,
|
|
473
509
|
}));
|
|
474
510
|
|
|
475
|
-
const normalizedNumber =
|
|
476
|
-
String(resolvedValue).replace(/[^0-9,.-]/g, '').replace(',', '.'),
|
|
477
|
-
);
|
|
511
|
+
const normalizedNumber = parseSortNumber(resolvedValue);
|
|
478
512
|
|
|
479
|
-
if (Number.isFinite(normalizedNumber)
|
|
513
|
+
if (Number.isFinite(normalizedNumber)) {
|
|
480
514
|
return normalizedNumber;
|
|
481
515
|
}
|
|
482
516
|
|
|
@@ -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
|
|
22
|
-
|
|
23
|
-
|
|
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={
|
|
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
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
configs.
|
|
24
|
-
configs.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
column
|
|
36
|
-
column?.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const activeFilterCount = Object.values(filters).filter(value => normalizeText(value) !== '').length;
|
|
40
|
-
const addConfig = store?.getters?.add;
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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}
|