@controleonline/ui-default 1.0.264 → 1.0.266
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/AGENTS.md +3 -2
- package/package.json +21 -18
- package/src/react/components/errors/DefaultErrors.js +64 -82
- package/src/react/components/filters/CompactFilterSelector.js +58 -23
- package/src/react/components/filters/CompactFilterSelector.styles.js +17 -5
- package/src/react/components/filters/DefaultColumnFilter.js +177 -45
- package/src/react/components/filters/DefaultExternalFilters.js +201 -143
- package/src/react/components/filters/DefaultSearch.js +27 -25
- package/src/react/components/form/DefaultForm.js +72 -53
- package/src/react/components/form/DefaultForm.styles.js +71 -66
- package/src/react/components/inputs/DefaultDateInput.js +150 -0
- package/src/react/components/inputs/DefaultInput.js +44 -11
- package/src/react/components/inputs/DefaultInput.styles.js +6 -0
- package/src/react/components/inputs/DefaultSelect.js +200 -43
- package/src/react/components/inputs/defaultInputUtils.js +40 -19
- package/src/react/components/table/DefaultColumnMenu.js +108 -0
- package/src/react/components/table/DefaultDebug.js +234 -0
- package/src/react/components/table/DefaultFiltersModal.js +142 -0
- package/src/react/components/table/DefaultModalButton.js +18 -0
- package/src/react/components/table/DefaultSearchModal.js +49 -0
- package/src/react/components/table/DefaultTable.js +322 -1964
- package/src/react/components/table/DefaultTable.styles.js +234 -102
- package/src/react/components/table/DefaultTable.utils.js +502 -0
- package/src/react/components/table/DefaultTableBody.js +26 -0
- package/src/react/components/table/DefaultTableCards.js +171 -0
- package/src/react/components/table/DefaultTableControls.js +205 -0
- package/src/react/components/table/DefaultTableEmptyState.js +22 -0
- package/src/react/components/table/DefaultTableFooter.js +172 -0
- package/src/react/components/table/DefaultTableInput.js +145 -0
- package/src/react/components/table/DefaultTableRows.js +344 -0
- package/src/react/components/table/DefaultTableSearch.js +100 -0
- package/src/react/components/table/DefaultTableToolbar.js +98 -0
- package/src/react/components/table/DefaultToolbarAction.js +56 -0
- package/src/react/components/table/useDefaultTablePagination.js +370 -0
- package/src/react/components/table/useDefaultTableSorting.js +126 -0
- package/src/react/components/table/useDefaultTableTheme.js +52 -0
- package/src/react/utils/tableVisibleColumnsPreferences.js +239 -211
- package/src/store/default/actions.js +51 -13
- package/src/store/default/getters.js +10 -8
- package/src/store/default/mutation_types.js +4 -2
- package/src/store/default/mutations.js +10 -1
- package/src/tests/react/components/form/DefaultForm.test.js +81 -0
- package/src/tests/react/components/inputs/DefaultSelect.test.js +106 -14
- package/src/tests/react/components/table/DefaultTable.test.js +1318 -334
- package/src/tests/react/store/defaultActions.test.js +59 -0
- package/src/tests/react/utils/tableVisibleColumnsPreferences.test.js +247 -168
|
@@ -1,478 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
Modal,
|
|
6
|
-
ScrollView,
|
|
7
|
-
Text,
|
|
8
|
-
TouchableOpacity,
|
|
9
|
-
View,
|
|
10
|
-
useWindowDimensions,
|
|
11
|
-
} from 'react-native';
|
|
12
|
-
import { useIsFocused } from '@react-navigation/native';
|
|
13
|
-
import Icon from 'react-native-vector-icons/Feather';
|
|
14
|
-
import { getAllStores, useStore } from '@store';
|
|
1
|
+
import React, { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { TouchableOpacity, View, useWindowDimensions } from 'react-native';
|
|
3
|
+
import { useIsFocused, useRoute } from '@react-navigation/native';
|
|
4
|
+
import { useStore } from '@store';
|
|
15
5
|
import { useMessage } from '@controleonline/ui-common/src/react/components/MessageService';
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import { formatStoreColumnLabel } from '@controleonline/ui-common/src/react/utils/storeColumns';
|
|
20
|
-
import { resolveThemePalette } from '@controleonline/../../src/styles/branding';
|
|
21
|
-
import { colors } from '@controleonline/../../src/styles/colors';
|
|
22
|
-
import DefaultColumnFilter from '../filters/DefaultColumnFilter';
|
|
23
|
-
import DefaultSearch from '../filters/DefaultSearch';
|
|
24
|
-
import DefaultForm from '../form/DefaultForm';
|
|
25
|
-
import DefaultInput from '../inputs/DefaultInput';
|
|
26
|
-
import {
|
|
27
|
-
formatSaveValue,
|
|
28
|
-
getColumnKey,
|
|
29
|
-
isEditableColumn,
|
|
30
|
-
normalizeId,
|
|
31
|
-
normalizeOptionKey,
|
|
32
|
-
normalizeText,
|
|
33
|
-
resolveStoreNameFromList,
|
|
34
|
-
resolveCellText,
|
|
35
|
-
resolveEditValue,
|
|
36
|
-
} from '../inputs/defaultInputUtils';
|
|
6
|
+
import Icon from 'react-native-vector-icons/Feather';
|
|
7
|
+
import { normalizeText } from '../inputs/defaultInputUtils';
|
|
8
|
+
import { DEFAULT_COMPACT_BREAKPOINT, isObject, stableSerialize } from './DefaultTable.utils';
|
|
37
9
|
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
persistVisibleColumnsPreference,
|
|
41
|
-
resolveStoredTableSortPreference,
|
|
10
|
+
resolveDefaultTablePreferenceScope,
|
|
11
|
+
resolveStoredTableFiltersPreference,
|
|
42
12
|
resolveStoredTableViewModePreference,
|
|
43
13
|
resolveStoredVisibleColumnsPreference,
|
|
14
|
+
sanitizeTableFiltersPreference,
|
|
44
15
|
sanitizeVisibleColumnsPreference,
|
|
45
16
|
} from '../../utils/tableVisibleColumnsPreferences';
|
|
46
|
-
import
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
'categories',
|
|
68
|
-
'paymentType',
|
|
69
|
-
'wallet',
|
|
70
|
-
]);
|
|
71
|
-
|
|
72
|
-
const resolveListLoadParams = ({currentCompanyId, listStoreName}) => {
|
|
73
|
-
if (!currentCompanyId || !COMPANY_SCOPED_LIST_STORES.has(listStoreName)) {
|
|
74
|
-
return {};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return listStoreName === 'categories'
|
|
78
|
-
? {company: currentCompanyId}
|
|
79
|
-
: {people: currentCompanyId};
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const resolveColumnListLoadParams = ({
|
|
83
|
-
column,
|
|
84
|
-
currentCompanyId,
|
|
85
|
-
requestParams = {},
|
|
86
|
-
}) => {
|
|
87
|
-
const listStoreName = resolveStoreNameFromList(column?.list);
|
|
88
|
-
const companyScopedParams = resolveListLoadParams({
|
|
89
|
-
currentCompanyId,
|
|
90
|
-
listStoreName,
|
|
91
|
-
});
|
|
92
|
-
const resolvedCustomParams = typeof column?.listRequestParams === 'function'
|
|
93
|
-
? column.listRequestParams({currentCompanyId, requestParams})
|
|
94
|
-
: column?.listRequestParams;
|
|
95
|
-
const customParams =
|
|
96
|
-
resolvedCustomParams &&
|
|
97
|
-
typeof resolvedCustomParams === 'object' &&
|
|
98
|
-
!Array.isArray(resolvedCustomParams)
|
|
99
|
-
? resolvedCustomParams
|
|
100
|
-
: {};
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
...companyScopedParams,
|
|
104
|
-
...customParams,
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const isObject = value =>
|
|
109
|
-
value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
110
|
-
|
|
111
|
-
const getRowKey = (row, index = 0) =>
|
|
112
|
-
String(row?.['@id'] || row?.id || index);
|
|
113
|
-
|
|
114
|
-
const stableSerialize = value => {
|
|
115
|
-
if (value === null || value === undefined) {
|
|
116
|
-
return 'null';
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (Array.isArray(value)) {
|
|
120
|
-
return `[${value.map(item => stableSerialize(item)).join(',')}]`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (value instanceof Date) {
|
|
124
|
-
return JSON.stringify(value.toISOString());
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (isObject(value)) {
|
|
128
|
-
return `{${Object.keys(value)
|
|
129
|
-
.sort()
|
|
130
|
-
.map(key => `${JSON.stringify(key)}:${stableSerialize(value[key])}`)
|
|
131
|
-
.join(',')}}`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return JSON.stringify(value);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const resolveDateRangeQuery = value => {
|
|
138
|
-
if (!value || typeof value !== 'object') {
|
|
139
|
-
return {};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const shortcut = value.shortcut || value.value || 'all';
|
|
143
|
-
const customRange = value.customRange || { from: '', to: '' };
|
|
144
|
-
const dateRange = getDateRange(shortcut, customRange, {
|
|
145
|
-
relativeMode: 'rolling',
|
|
146
|
-
useCurrentMoment: true,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
after: dateRange?.after || '',
|
|
151
|
-
before: dateRange?.before || '',
|
|
152
|
-
};
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
const resolveFilterQueryValue = value => {
|
|
156
|
-
if (Array.isArray(value)) {
|
|
157
|
-
return value
|
|
158
|
-
.map(item => resolveFilterQueryValue(item))
|
|
159
|
-
.filter(item => item !== '' && item !== null && item !== undefined);
|
|
17
|
+
import DefaultTableBody from './DefaultTableBody';
|
|
18
|
+
import DefaultTableFooter from './DefaultTableFooter';
|
|
19
|
+
import DefaultTableToolbar from './DefaultTableToolbar';
|
|
20
|
+
import styles from './DefaultTable.styles';
|
|
21
|
+
import { useDefaultTablePagination } from './useDefaultTablePagination';
|
|
22
|
+
import {
|
|
23
|
+
useDefaultTableSortedData,
|
|
24
|
+
useDefaultTableSortState,
|
|
25
|
+
} from './useDefaultTableSorting';
|
|
26
|
+
import useDefaultTableTheme from './useDefaultTableTheme';
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
mergeSortedDataWithLiveItems,
|
|
30
|
+
resolveColumnListLoadParams,
|
|
31
|
+
shouldTriggerEndReachedFromScroll,
|
|
32
|
+
} from './DefaultTable.utils';
|
|
33
|
+
|
|
34
|
+
const publishStoreValue = (store, actionName, value, getterName) => {
|
|
35
|
+
if (typeof store?.actions?.[actionName] === 'function') {
|
|
36
|
+
store.actions[actionName](value);
|
|
37
|
+
return;
|
|
160
38
|
}
|
|
161
39
|
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
value.value ?? value.id ?? value['@id'] ?? value.key ?? '',
|
|
165
|
-
);
|
|
40
|
+
if (store?.getters) {
|
|
41
|
+
store.getters[getterName] = value;
|
|
166
42
|
}
|
|
167
|
-
|
|
168
|
-
return normalizeText(value);
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const normalizeCollectionItems = response => {
|
|
172
|
-
if (Array.isArray(response)) return response;
|
|
173
|
-
if (Array.isArray(response?.member)) return response.member;
|
|
174
|
-
if (Array.isArray(response?.['hydra:member'])) return response['hydra:member'];
|
|
175
|
-
|
|
176
|
-
return [];
|
|
177
43
|
};
|
|
178
|
-
|
|
179
|
-
const resolveHasMore = ({ hasMore, dataLength, totalItems }) => {
|
|
180
|
-
if (hasMore !== null && hasMore !== undefined) {
|
|
181
|
-
return hasMore;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const resolvedTotalItems = Number(totalItems);
|
|
185
|
-
if (!Number.isFinite(resolvedTotalItems)) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return dataLength < resolvedTotalItems;
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
const humanizeSummaryLabel = value =>
|
|
193
|
-
normalizeText(value)
|
|
194
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
195
|
-
.replace(/[._-]+/g, ' ')
|
|
196
|
-
.replace(/\s+/g, ' ')
|
|
197
|
-
.trim();
|
|
198
|
-
|
|
199
|
-
const isMoneySummaryPath = path =>
|
|
200
|
-
/(amount|price|total|value|paid|open|receivable|payable|pending)/i.test(
|
|
201
|
-
Array.isArray(path) ? path.join('.') : normalizeText(path),
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
const normalizeSummaryMoneyValue = value => {
|
|
205
|
-
if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
|
|
206
|
-
|
|
207
|
-
const rawValue = normalizeText(value).replace(/[^0-9,.-]/g, '');
|
|
208
|
-
if (!rawValue) return 0;
|
|
209
|
-
|
|
210
|
-
const normalizedValue = rawValue.includes(',')
|
|
211
|
-
? rawValue.replace(/\./g, '').replace(',', '.')
|
|
212
|
-
: rawValue;
|
|
213
|
-
const parsedValue = Number(normalizedValue);
|
|
214
|
-
|
|
215
|
-
return Number.isFinite(parsedValue) ? parsedValue : 0;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
const getSummaryOperations = column => {
|
|
219
|
-
if (typeof column?.summary === 'string') return [column.summary];
|
|
220
|
-
if (Array.isArray(column?.summary)) return column.summary;
|
|
221
|
-
if (isObject(column?.summary)) {
|
|
222
|
-
return Object.entries(column.summary)
|
|
223
|
-
.filter(([, value]) => value)
|
|
224
|
-
.map(([operation]) => operation);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return SUMMARY_OPERATIONS.filter(operation => column?.[operation] === true);
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const getSummaryField = (column, operation) => {
|
|
231
|
-
if (isObject(column?.summary)) {
|
|
232
|
-
const summaryField = column.summary[operation];
|
|
233
|
-
if (typeof summaryField === 'string') return summaryField;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return getColumnKey(column);
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
const formatSummaryValue = ({ column, columns, path, storeName, value }) => {
|
|
240
|
-
const columnKey = column ? getColumnKey(column) : '';
|
|
241
|
-
const shouldFormatMoney = isMoneySummaryPath(path) || isMoneySummaryPath(columnKey);
|
|
242
|
-
|
|
243
|
-
if (shouldFormatMoney) {
|
|
244
|
-
return Formatter.formatMoney(normalizeSummaryMoneyValue(value));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (column) {
|
|
248
|
-
return resolveCellText({
|
|
249
|
-
column,
|
|
250
|
-
columns,
|
|
251
|
-
row: { [columnKey]: value },
|
|
252
|
-
storeName,
|
|
253
|
-
value,
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return normalizeText(value);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const flattenSummaryEntries = ({
|
|
261
|
-
path = [],
|
|
262
|
-
summaryLabels = {},
|
|
263
|
-
usedPaths,
|
|
264
|
-
value,
|
|
265
|
-
}) => {
|
|
266
|
-
if (!isObject(value)) {
|
|
267
|
-
const pathKey = path.join('.');
|
|
268
|
-
if (!pathKey || usedPaths.has(pathKey)) return [];
|
|
269
|
-
|
|
270
|
-
const fallbackLabel = humanizeSummaryLabel(path[path.length - 1] || pathKey);
|
|
271
|
-
|
|
272
|
-
return [{
|
|
273
|
-
key: pathKey,
|
|
274
|
-
label: summaryLabels[pathKey] || summaryLabels[path[path.length - 1]] || fallbackLabel,
|
|
275
|
-
path,
|
|
276
|
-
value,
|
|
277
|
-
}];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return Object.entries(value).flatMap(([key, childValue]) =>
|
|
281
|
-
flattenSummaryEntries({
|
|
282
|
-
path: [...path, key],
|
|
283
|
-
summaryLabels,
|
|
284
|
-
usedPaths,
|
|
285
|
-
value: childValue,
|
|
286
|
-
}),
|
|
287
|
-
);
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const isSortableColumn = column => column?.sortable === true;
|
|
291
|
-
|
|
292
|
-
const getSortField = column => column?.sortField || getColumnKey(column);
|
|
293
44
|
|
|
294
|
-
const
|
|
295
|
-
if (
|
|
296
|
-
|
|
45
|
+
const assignGetterValue = (store, getterName, value) => {
|
|
46
|
+
if (store?.getters) {
|
|
47
|
+
store.getters[getterName] = value;
|
|
297
48
|
}
|
|
298
|
-
|
|
299
|
-
for (const column of columns) {
|
|
300
|
-
if (!column || column?.defaultSort === undefined || column?.defaultSort === null || column?.defaultSort === false) {
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const field = getSortField(column);
|
|
305
|
-
const defaultSort = column.defaultSort;
|
|
306
|
-
|
|
307
|
-
if (defaultSort && typeof defaultSort === 'object' && !Array.isArray(defaultSort)) {
|
|
308
|
-
const resolvedDirection = normalizeText(defaultSort.direction || defaultSort.order || 'desc').toLowerCase();
|
|
309
|
-
const resolvedField = normalizeText(
|
|
310
|
-
defaultSort.field || defaultSort.sortField || defaultSort.key || defaultSort.name || field,
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
direction: resolvedDirection === 'asc' ? 'asc' : 'desc',
|
|
315
|
-
field: resolvedField || field,
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (typeof defaultSort === 'string') {
|
|
320
|
-
const normalizedSort = normalizeText(defaultSort).toLowerCase();
|
|
321
|
-
if (normalizedSort === 'asc' || normalizedSort === 'desc') {
|
|
322
|
-
return {
|
|
323
|
-
direction: normalizedSort,
|
|
324
|
-
field,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return {
|
|
329
|
-
direction: 'desc',
|
|
330
|
-
field: normalizeText(defaultSort) || field,
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (defaultSort === true) {
|
|
335
|
-
return {
|
|
336
|
-
direction: 'asc',
|
|
337
|
-
field,
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return null;
|
|
343
49
|
};
|
|
344
50
|
|
|
345
|
-
const sanitizeStoredSortPreference = ({
|
|
346
|
-
columns = [],
|
|
347
|
-
fallbackSort = null,
|
|
348
|
-
sort = null,
|
|
349
|
-
}) => {
|
|
350
|
-
const normalizedFallback =
|
|
351
|
-
fallbackSort &&
|
|
352
|
-
typeof fallbackSort === 'object' &&
|
|
353
|
-
typeof fallbackSort.field === 'string' &&
|
|
354
|
-
fallbackSort.field.trim()
|
|
355
|
-
? {
|
|
356
|
-
direction: fallbackSort.direction === 'asc' ? 'asc' : 'desc',
|
|
357
|
-
field: fallbackSort.field.trim(),
|
|
358
|
-
}
|
|
359
|
-
: null;
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
!sort ||
|
|
363
|
-
typeof sort !== 'object' ||
|
|
364
|
-
typeof sort.field !== 'string' ||
|
|
365
|
-
!sort.field.trim()
|
|
366
|
-
) {
|
|
367
|
-
return normalizedFallback;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const normalizedDirection = sort.direction === 'asc' ? 'asc' : 'desc';
|
|
371
|
-
const normalizedField = sort.field.trim();
|
|
372
|
-
const sortableFields = new Set(
|
|
373
|
-
(Array.isArray(columns) ? columns : [])
|
|
374
|
-
.filter(isSortableColumn)
|
|
375
|
-
.map(column => getSortField(column))
|
|
376
|
-
.filter(Boolean),
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
if (!sortableFields.has(normalizedField)) {
|
|
380
|
-
return normalizedFallback;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return {
|
|
384
|
-
direction: normalizedDirection,
|
|
385
|
-
field: normalizedField,
|
|
386
|
-
};
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
const readValueByPath = (object, path) => {
|
|
390
|
-
if (!object || !path) return object;
|
|
391
|
-
|
|
392
|
-
return String(path)
|
|
393
|
-
.split('.')
|
|
394
|
-
.reduce((currentValue, key) => {
|
|
395
|
-
if (currentValue === null || currentValue === undefined) return currentValue;
|
|
396
|
-
return currentValue?.[key];
|
|
397
|
-
}, object);
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
const normalizeSortText = value =>
|
|
401
|
-
normalizeText(value)
|
|
402
|
-
.normalize('NFD')
|
|
403
|
-
.replace(/[\u0300-\u036f]/g, '')
|
|
404
|
-
.toLowerCase();
|
|
405
|
-
|
|
406
|
-
const isDateLikeColumn = column =>
|
|
407
|
-
column?.inputType === 'date' ||
|
|
408
|
-
column?.inputType === 'date-range' ||
|
|
409
|
-
column?.type === 'date' ||
|
|
410
|
-
column?.type === 'range-date' ||
|
|
411
|
-
/date/i.test(getColumnKey(column));
|
|
412
|
-
|
|
413
|
-
const resolveSortComparable = ({ column, row, storeName, columns }) => {
|
|
414
|
-
const fieldName = getColumnKey(column);
|
|
415
|
-
const sortField = getSortField(column);
|
|
416
|
-
const rawValue = sortField === fieldName ? row?.[fieldName] : readValueByPath(row, sortField);
|
|
417
|
-
|
|
418
|
-
if (isDateLikeColumn(column)) {
|
|
419
|
-
const dateValue =
|
|
420
|
-
rawValue && typeof rawValue === 'object'
|
|
421
|
-
? rawValue?.value ??
|
|
422
|
-
rawValue?.date ??
|
|
423
|
-
rawValue?.createdAt ??
|
|
424
|
-
rawValue?.updatedAt ??
|
|
425
|
-
rawValue?.['@id'] ??
|
|
426
|
-
rawValue?.[fieldName] ??
|
|
427
|
-
rawValue
|
|
428
|
-
: rawValue;
|
|
429
|
-
const parsedDate = Date.parse(dateValue);
|
|
430
|
-
return Number.isFinite(parsedDate) ? parsedDate : Number.NEGATIVE_INFINITY;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const resolvedValue = sortField === fieldName
|
|
434
|
-
? resolveCellText({
|
|
435
|
-
column,
|
|
436
|
-
columns,
|
|
437
|
-
row,
|
|
438
|
-
storeName,
|
|
439
|
-
})
|
|
440
|
-
: normalizeText(rawValue ?? resolveCellText({
|
|
441
|
-
column,
|
|
442
|
-
columns,
|
|
443
|
-
row,
|
|
444
|
-
storeName,
|
|
445
|
-
}));
|
|
446
|
-
|
|
447
|
-
const normalizedNumber = Number(
|
|
448
|
-
String(resolvedValue).replace(/[^0-9,.-]/g, '').replace(',', '.'),
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
if (Number.isFinite(normalizedNumber) && String(resolvedValue).match(/[0-9]/)) {
|
|
452
|
-
return normalizedNumber;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return normalizeSortText(resolvedValue);
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
const getColumnStyle = column => {
|
|
459
|
-
const key = getColumnKey(column);
|
|
460
|
-
if (column?.isIdentity) return [styles.cell, styles.identityCell];
|
|
461
|
-
if (['price', 'total', 'amount', 'value'].includes(key)) {
|
|
462
|
-
return [styles.cell, styles.moneyCell];
|
|
463
|
-
}
|
|
464
|
-
return styles.cell;
|
|
465
|
-
};
|
|
466
|
-
|
|
467
|
-
const getColumnMinWidth = column => {
|
|
468
|
-
const key = getColumnKey(column);
|
|
469
|
-
if (column?.isIdentity) return IDENTITY_CELL_MIN_WIDTH;
|
|
470
|
-
if (['price', 'total', 'amount', 'value'].includes(key)) {
|
|
471
|
-
return MONEY_CELL_MIN_WIDTH;
|
|
472
|
-
}
|
|
473
|
-
return DEFAULT_CELL_MIN_WIDTH;
|
|
474
|
-
};
|
|
475
|
-
|
|
476
51
|
const DefaultTable = ({
|
|
477
52
|
accentColor = null,
|
|
478
53
|
actions = {},
|
|
@@ -481,1591 +56,374 @@ const DefaultTable = ({
|
|
|
481
56
|
columns = [],
|
|
482
57
|
data = undefined,
|
|
483
58
|
filters = {},
|
|
59
|
+
footerComponent = null,
|
|
484
60
|
forceCardsOnCompact = true,
|
|
485
61
|
getOptionsForColumn = null,
|
|
486
62
|
hasMore = null,
|
|
487
63
|
initialViewMode = 'table',
|
|
488
|
-
pageSize = null,
|
|
489
64
|
isLoading = false,
|
|
65
|
+
onAdd = null,
|
|
66
|
+
onDataLoaded = null,
|
|
490
67
|
onEditRow = null,
|
|
491
68
|
onEndReached = null,
|
|
492
|
-
onMomentumScrollBegin = null,
|
|
493
|
-
onScrollBeginDrag = null,
|
|
494
|
-
onAdd = null,
|
|
495
69
|
onFilterChange = null,
|
|
70
|
+
onMomentumScrollBegin = null,
|
|
496
71
|
onRowPress = null,
|
|
497
72
|
onSaved = null,
|
|
73
|
+
onScrollBeginDrag = null,
|
|
498
74
|
onSortChange = null,
|
|
499
|
-
|
|
500
|
-
|
|
75
|
+
pageSize = null,
|
|
76
|
+
pinRowActions = true,
|
|
501
77
|
renderCard = null,
|
|
502
|
-
|
|
503
|
-
|
|
78
|
+
requestParams = {},
|
|
79
|
+
rowActionsComponent = null,
|
|
80
|
+
rowStyle = null,
|
|
504
81
|
showColumnFiltersButton = true,
|
|
505
|
-
showTotalItemsInFooter = true,
|
|
506
|
-
showTotalItemsInCompactToolbar = false,
|
|
507
82
|
showRowActions = true,
|
|
508
|
-
|
|
83
|
+
showToolbar = true,
|
|
84
|
+
showTotalItemsInCompactToolbar = false,
|
|
85
|
+
showTotalItemsInFooter = true,
|
|
509
86
|
sort = null,
|
|
510
87
|
storeName = '',
|
|
511
|
-
summary =
|
|
512
|
-
summaryLabels =
|
|
513
|
-
|
|
514
|
-
totalItemsLabel = null,
|
|
515
|
-
totalItemsText = null,
|
|
516
|
-
footerComponent = null,
|
|
88
|
+
summary = undefined,
|
|
89
|
+
summaryLabels = {},
|
|
90
|
+
toolbarActions = [],
|
|
517
91
|
visibleColumnsPreferenceKey = '',
|
|
518
92
|
}) => {
|
|
519
93
|
const { width } = useWindowDimensions();
|
|
94
|
+
const route = useRoute?.();
|
|
520
95
|
const store = useStore(storeName);
|
|
521
|
-
const
|
|
522
|
-
const
|
|
523
|
-
const
|
|
524
|
-
const
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
const
|
|
529
|
-
const [savingCell, setSavingCell] = useState(null);
|
|
530
|
-
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
|
531
|
-
const [tableContainerWidth, setTableContainerWidth] = useState(0);
|
|
532
|
-
const endReachedLockRef = useRef(false);
|
|
533
|
-
const loadedListStoresRef = useRef(new Set());
|
|
534
|
-
const previousPaginationStateRef = useRef({
|
|
535
|
-
dataLength: Array.isArray(data) ? data.length : 0,
|
|
536
|
-
filtersKey: JSON.stringify(filters || {}),
|
|
537
|
-
sortDirection: sort?.direction,
|
|
538
|
-
sortField: sort?.field,
|
|
539
|
-
});
|
|
540
|
-
const visibleColumnsSeed = useMemo(
|
|
96
|
+
const isFocused = useIsFocused();
|
|
97
|
+
const configsSignatureRef = useRef('');
|
|
98
|
+
const { showError } = useMessage() || {};
|
|
99
|
+
const { themeColors } = useDefaultTableTheme(accentColor);
|
|
100
|
+
const floatingAddBackgroundColor =
|
|
101
|
+
themeColors.buttonBackground || themeColors.primary || accentColor || '#2563EB';
|
|
102
|
+
const floatingAddIconColor = themeColors.buttonText || '#FFFFFF';
|
|
103
|
+
const tablePreferenceScope = useMemo(
|
|
541
104
|
() =>
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
visibleColumns: resolveStoredVisibleColumnsPreference(
|
|
547
|
-
visibleColumnsStorageKey,
|
|
548
|
-
),
|
|
105
|
+
resolveDefaultTablePreferenceScope({
|
|
106
|
+
preferenceKey: visibleColumnsPreferenceKey,
|
|
107
|
+
route,
|
|
108
|
+
storeName,
|
|
549
109
|
}),
|
|
550
|
-
[
|
|
110
|
+
[route?.key, route?.name, storeName, visibleColumnsPreferenceKey],
|
|
551
111
|
);
|
|
552
|
-
const
|
|
553
|
-
() =>
|
|
554
|
-
|
|
555
|
-
visibleColumnsPreferenceKey,
|
|
556
|
-
initialViewMode,
|
|
557
|
-
),
|
|
558
|
-
[initialViewMode, visibleColumnsPreferenceKey],
|
|
112
|
+
const storedViewMode = useMemo(
|
|
113
|
+
() => resolveStoredTableViewModePreference(tablePreferenceScope, null),
|
|
114
|
+
[initialViewMode, tablePreferenceScope],
|
|
559
115
|
);
|
|
560
|
-
const [visibleColumns, setVisibleColumns] = useState(() => visibleColumnsSeed);
|
|
561
|
-
const [viewMode, setViewMode] = useState(() => viewModeSeed);
|
|
562
|
-
const [compactViewMode, setCompactViewMode] = useState(null);
|
|
563
|
-
const { currentCompany } = peopleStore.getters || {};
|
|
564
|
-
const { colors: themeColors } = themeStore.getters;
|
|
565
|
-
const themeTokens = useMemo(
|
|
566
|
-
() => ({...themeColors, ...(currentCompany?.theme?.colors || {})}),
|
|
567
|
-
[currentCompany?.theme?.colors, themeColors],
|
|
568
|
-
);
|
|
569
|
-
const palette = useMemo(
|
|
570
|
-
() => resolveThemePalette(themeTokens, colors),
|
|
571
|
-
[themeTokens],
|
|
572
|
-
);
|
|
573
|
-
const resolvedAccentColor = accentColor || palette.primary;
|
|
574
|
-
const tableHeaderColor = themeTokens['bg-headers-light'] || resolvedAccentColor;
|
|
575
|
-
const tableEvenColor = themeTokens.listItemEvenRow || themeTokens['bg-even-light'] || palette.background;
|
|
576
|
-
const tableOddColor = themeTokens.listItemOddRow || themeTokens['bg-odd-light'] || palette.background;
|
|
577
|
-
const tableBorderColor = palette.border;
|
|
578
|
-
const tableSurfaceColor = palette.background;
|
|
579
|
-
const tableTextColor = palette.text;
|
|
580
|
-
const tableMutedColor = palette.textSecondary;
|
|
581
|
-
const panelBackgroundColor = themeColors.panelBackground;
|
|
582
|
-
const panelBorderColor = themeColors.panelBorder;
|
|
583
|
-
const modalBackgroundColor = themeColors.modalBackground;
|
|
584
|
-
const modalBorderColor = themeColors.modalBorder;
|
|
585
|
-
const modalCloseIconColor = themeColors.modalCloseIcon;
|
|
586
|
-
const modalHeaderTextColor = themeColors.modalHeaderText;
|
|
587
|
-
const modalOverlayColor = themeColors.modalOverlay;
|
|
588
|
-
const modalTextColor = themeColors.modalText;
|
|
589
|
-
const checkboxBorderColor = themeColors.checkboxBorder;
|
|
590
|
-
const checkboxSelectedMarkColor = themeColors.checkboxSelectedMark;
|
|
591
|
-
const toolbarBackgroundColor = themeColors.toolbarBackground;
|
|
592
|
-
const toolbarBorderColor = themeColors.toolbarBorder;
|
|
593
|
-
const toolbarCountBackgroundColor = themeColors.badgeBackground;
|
|
594
|
-
const toolbarCountTextColor = themeColors.badgeText;
|
|
595
|
-
const tableActionBackgroundColor = themeColors.tableActionBackground;
|
|
596
|
-
const tableActionBorderColor = themeColors.tableActionBorder;
|
|
597
|
-
const tableActionTextColor = themeColors.tableActionIcon;
|
|
598
|
-
const tableButtonBackgroundColor = themeColors.buttonBackground;
|
|
599
|
-
const tableButtonBorderColor = themeColors.buttonBorder;
|
|
600
|
-
const tableButtonIconColor = themeColors.buttonIcon;
|
|
601
|
-
const tableButtonPressedBackgroundColor = themeColors.buttonPressedBackground;
|
|
602
|
-
const tableButtonPressedBorderColor = themeColors.buttonPressedBorder;
|
|
603
|
-
const tableButtonPressedIconColor = themeColors.buttonPressedIcon;
|
|
604
|
-
const tableButtonTextColor = themeColors.buttonText;
|
|
605
|
-
const tableFilterBackgroundColor = themeColors.tableFilterBackground;
|
|
606
|
-
const tableFilterBorderColor = themeColors.tableFilterBorder;
|
|
607
|
-
const tableFilterTextColor = themeColors.tableFilterText;
|
|
608
|
-
const isFocused = useIsFocused();
|
|
609
|
-
const {showError} = useMessage() || {};
|
|
610
|
-
const autoMode = data === undefined && normalizeText(storeName) !== '';
|
|
611
|
-
const searchKey = searchProps?.searchKey || 'search';
|
|
612
|
-
const storeActions = store?.actions || {};
|
|
613
116
|
const resolvedActions = useMemo(
|
|
614
117
|
() => ({
|
|
615
|
-
...
|
|
118
|
+
...(store?.actions || {}),
|
|
616
119
|
...(actions || {}),
|
|
617
120
|
}),
|
|
618
|
-
[actions,
|
|
121
|
+
[actions, store?.actions],
|
|
619
122
|
);
|
|
123
|
+
const autoMode = data === undefined && normalizeText(storeName) !== '';
|
|
620
124
|
const storeColumns = Array.isArray(store?.getters?.columns) ? store.getters.columns : [];
|
|
621
125
|
const columnsForTable = storeColumns.length > 0 ? storeColumns : columns;
|
|
622
126
|
const storeFilters = isObject(store?.getters?.filters) ? store.getters.filters : {};
|
|
623
127
|
const requestParamsSeed = isObject(requestParams) ? requestParams : {};
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
fallbackSort: sort || defaultSortSeed || null,
|
|
637
|
-
sort: resolveStoredTableSortPreference(visibleColumnsPreferenceKey),
|
|
638
|
-
}),
|
|
639
|
-
[columnsForTable, defaultSortSeed, sort, visibleColumnsPreferenceKey],
|
|
640
|
-
);
|
|
641
|
-
const [autoSort, setAutoSort] = useState(() => storedSortSeed);
|
|
642
|
-
const [autoHasLoaded, setAutoHasLoaded] = useState(false);
|
|
643
|
-
const [autoLoading, setAutoLoading] = useState(false);
|
|
644
|
-
const [autoLoadingMore, setAutoLoadingMore] = useState(false);
|
|
645
|
-
const [autoLastPageCount, setAutoLastPageCount] = useState(0);
|
|
646
|
-
const autoRequestIdRef = useRef(0);
|
|
647
|
-
const autoLoadedQueryKeyRef = useRef('');
|
|
648
|
-
const autoErroredQueryKeyRef = useRef('');
|
|
649
|
-
const autoPageRef = useRef(0);
|
|
650
|
-
const pageSizeNumber = Number(requestParamsSeed.itemsPerPage || pageSize || 50) || 50;
|
|
651
|
-
const resolvedSort = autoMode ? autoSort : sort;
|
|
652
|
-
const resolvedFilters = autoMode ? autoFilters : (filters || {});
|
|
653
|
-
const resolvedSearchValue = normalizeText(resolvedFilters?.[searchKey]);
|
|
654
|
-
const resolvedGetOptionsForColumn = useCallback(
|
|
655
|
-
column => {
|
|
656
|
-
const explicitOptions = getOptionsForColumn?.(column);
|
|
657
|
-
if (Array.isArray(explicitOptions)) return explicitOptions;
|
|
658
|
-
|
|
659
|
-
const columnKey = getColumnKey(column);
|
|
660
|
-
return Array.isArray(listOptionsByColumn[columnKey])
|
|
661
|
-
? listOptionsByColumn[columnKey]
|
|
662
|
-
: undefined;
|
|
663
|
-
},
|
|
664
|
-
[getOptionsForColumn, listOptionsByColumn],
|
|
665
|
-
);
|
|
666
|
-
|
|
667
|
-
useEffect(() => {
|
|
668
|
-
setListOptionsByColumn({});
|
|
669
|
-
loadedListStoresRef.current.clear();
|
|
670
|
-
}, [currentCompany?.id]);
|
|
671
|
-
|
|
672
|
-
const loadListOptionsForColumns = useCallback(
|
|
673
|
-
(targetColumns = []) => {
|
|
674
|
-
const columnsToLoad = (Array.isArray(targetColumns) ? targetColumns : []).filter(
|
|
675
|
-
column => normalizeText(column?.list),
|
|
676
|
-
);
|
|
677
|
-
|
|
678
|
-
if (columnsToLoad.length === 0) {
|
|
679
|
-
return Promise.resolve([]);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
const stores = getAllStores?.() || {};
|
|
683
|
-
const loadPromises = [];
|
|
684
|
-
|
|
685
|
-
columnsToLoad.forEach(column => {
|
|
686
|
-
const explicitOptions = getOptionsForColumn?.(column);
|
|
687
|
-
if (Array.isArray(explicitOptions)) {
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
const listStoreName = resolveStoreNameFromList(column.list);
|
|
692
|
-
const actionName = resolveListActionName(column.list);
|
|
693
|
-
const listStore = stores?.[listStoreName];
|
|
694
|
-
const listAction = listStore?.actions?.[actionName];
|
|
695
|
-
|
|
696
|
-
const listLoadParams = resolveColumnListLoadParams({
|
|
697
|
-
column,
|
|
698
|
-
currentCompanyId: currentCompany?.id,
|
|
699
|
-
requestParams: requestParamsSeed,
|
|
700
|
-
});
|
|
701
|
-
const isCompanyScopedList = Object.keys(listLoadParams).length > 0;
|
|
702
|
-
|
|
703
|
-
if (!listStoreName || typeof listAction !== 'function') {
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
if (
|
|
708
|
-
!isCompanyScopedList &&
|
|
709
|
-
Array.isArray(listStore?.getters?.items) &&
|
|
710
|
-
listStore.getters.items.length > 0
|
|
711
|
-
) {
|
|
712
|
-
const columnKey = getColumnKey(column);
|
|
713
|
-
setListOptionsByColumn(current => ({
|
|
714
|
-
...current,
|
|
715
|
-
[columnKey]: normalizeCollectionItems(listStore.getters.items),
|
|
716
|
-
}));
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
const columnKey = getColumnKey(column);
|
|
721
|
-
const loadKey = `${columnKey}:${listStoreName}:${actionName}:${stableSerialize(listLoadParams)}`;
|
|
722
|
-
if (loadedListStoresRef.current.has(loadKey)) {
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
loadedListStoresRef.current.add(loadKey);
|
|
727
|
-
loadPromises.push(
|
|
728
|
-
Promise.resolve(
|
|
729
|
-
listAction({
|
|
730
|
-
...listLoadParams,
|
|
731
|
-
itemsPerPage: LIST_OPTIONS_PAGE_SIZE,
|
|
732
|
-
__storeMeta: {
|
|
733
|
-
dedupeKey: `default-table-list-options:${loadKey}`,
|
|
734
|
-
skipSystemError: true,
|
|
735
|
-
},
|
|
736
|
-
}),
|
|
737
|
-
)
|
|
738
|
-
.then(response => ({columnKey, items: normalizeCollectionItems(response)}))
|
|
739
|
-
.catch(() => {
|
|
740
|
-
loadedListStoresRef.current.delete(loadKey);
|
|
741
|
-
return {columnKey, items: []};
|
|
742
|
-
}),
|
|
743
|
-
);
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
if (loadPromises.length === 0) {
|
|
747
|
-
return Promise.resolve([]);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
return Promise.all(loadPromises).then(results => {
|
|
751
|
-
const nextOptionsByColumn = Object.fromEntries(
|
|
752
|
-
results.map(result => [result.columnKey, result.items]),
|
|
753
|
-
);
|
|
754
|
-
|
|
755
|
-
if (Object.keys(nextOptionsByColumn).length > 0) {
|
|
756
|
-
setListOptionsByColumn(current => ({
|
|
757
|
-
...current,
|
|
758
|
-
...nextOptionsByColumn,
|
|
759
|
-
}));
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
return results;
|
|
763
|
-
});
|
|
764
|
-
},
|
|
765
|
-
[currentCompany?.id, getOptionsForColumn, requestParamsSeed],
|
|
766
|
-
);
|
|
767
|
-
|
|
768
|
-
const buildRequestQuery = useCallback(
|
|
769
|
-
(page, append = false) => {
|
|
770
|
-
const query = {
|
|
771
|
-
...requestParamsSeed,
|
|
772
|
-
itemsPerPage: pageSizeNumber,
|
|
773
|
-
page,
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
if (autoSort?.field && autoSort?.direction) {
|
|
777
|
-
query[`order[${autoSort.field}]`] = autoSort.direction;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
Object.entries(autoFilters || {}).forEach(([fieldName, value]) => {
|
|
781
|
-
if (!fieldName) return;
|
|
782
|
-
|
|
783
|
-
if (fieldName === searchKey) {
|
|
784
|
-
const normalizedSearch = normalizeText(value).replace(/^#/, '');
|
|
785
|
-
if (normalizedSearch) {
|
|
786
|
-
query.search = normalizedSearch;
|
|
787
|
-
if (searchKey !== 'search') {
|
|
788
|
-
query[searchKey] = normalizedSearch;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
const column = columnsForTable.find(item => getColumnKey(item) === fieldName);
|
|
795
|
-
|
|
796
|
-
if (column?.inputType === 'date-range' || column?.type === 'range-date') {
|
|
797
|
-
const dateRange = resolveDateRangeQuery(value);
|
|
798
|
-
if (dateRange.after) {
|
|
799
|
-
query[`${fieldName}[after]`] = dateRange.after;
|
|
800
|
-
}
|
|
801
|
-
if (dateRange.before) {
|
|
802
|
-
query[`${fieldName}[before]`] = dateRange.before;
|
|
803
|
-
}
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
const normalizedValue = resolveFilterQueryValue(value);
|
|
808
|
-
if (Array.isArray(normalizedValue)) {
|
|
809
|
-
if (normalizedValue.length > 0) {
|
|
810
|
-
query[fieldName] = normalizedValue;
|
|
811
|
-
}
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
128
|
+
const resolvedTotalItems = store?.getters?.totalItems;
|
|
129
|
+
const currentConfigs = store?.getters?.configs || {};
|
|
130
|
+
const isCompactView = width > 0 && width <= compactBreakpoint;
|
|
131
|
+
const addConfig = store?.getters?.add;
|
|
132
|
+
const shouldRenderFloatingAddButton =
|
|
133
|
+
showToolbar === false &&
|
|
134
|
+
(addConfig === true || add === true) &&
|
|
135
|
+
(typeof onAdd === 'function' || typeof store?.actions?.save === 'function');
|
|
136
|
+
|
|
137
|
+
if (storeColumns.length === 0 && Array.isArray(columns) && columns.length > 0) {
|
|
138
|
+
assignGetterValue(store, 'columns', columns);
|
|
139
|
+
}
|
|
814
140
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
});
|
|
141
|
+
if (data !== undefined && Array.isArray(data)) {
|
|
142
|
+
assignGetterValue(store, 'items', data);
|
|
143
|
+
}
|
|
819
144
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
145
|
+
const { requestSort, resolvedSort } = useDefaultTableSortState({
|
|
146
|
+
autoMode,
|
|
147
|
+
columnsForTable,
|
|
148
|
+
onSortChange,
|
|
149
|
+
sort,
|
|
150
|
+
tablePreferenceScope,
|
|
151
|
+
});
|
|
152
|
+
const {
|
|
153
|
+
buildRequestQuery,
|
|
154
|
+
currentPage,
|
|
155
|
+
handleEndReached,
|
|
156
|
+
resolvedData,
|
|
157
|
+
} = useDefaultTablePagination({
|
|
158
|
+
autoMode,
|
|
159
|
+
columnsForTable,
|
|
160
|
+
data,
|
|
161
|
+
filters: storeFilters,
|
|
162
|
+
hasMore,
|
|
163
|
+
isFocused,
|
|
164
|
+
isLoading,
|
|
165
|
+
onEndReached,
|
|
166
|
+
pageSize,
|
|
167
|
+
requestParams: requestParamsSeed,
|
|
168
|
+
resolvedActions,
|
|
169
|
+
resolvedSort,
|
|
170
|
+
resolvedTotalItems,
|
|
171
|
+
showError,
|
|
172
|
+
store,
|
|
173
|
+
storeName,
|
|
174
|
+
});
|
|
175
|
+
const sortedData = useDefaultTableSortedData({
|
|
176
|
+
resolvedData,
|
|
177
|
+
resolvedSort,
|
|
178
|
+
storeName,
|
|
179
|
+
tableColumns: columnsForTable,
|
|
180
|
+
});
|
|
181
|
+
const debugFallbackParameters = useMemo(() => {
|
|
182
|
+
if (autoMode) {
|
|
183
|
+
return buildRequestQuery(currentPage || 1, false);
|
|
184
|
+
}
|
|
823
185
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
186
|
+
return {
|
|
187
|
+
filters: storeFilters,
|
|
188
|
+
requestParams: requestParamsSeed,
|
|
189
|
+
sort: resolvedSort || null,
|
|
190
|
+
};
|
|
191
|
+
}, [autoMode, buildRequestQuery, currentPage, requestParamsSeed, resolvedSort, storeFilters]);
|
|
192
|
+
const effectiveViewMode =
|
|
193
|
+
currentConfigs.viewMode ||
|
|
194
|
+
storedViewMode ||
|
|
195
|
+
(isCompactView && forceCardsOnCompact !== false ? 'cards' : initialViewMode);
|
|
196
|
+
const tableFiltersVisible = Boolean(currentConfigs.tableFiltersVisible);
|
|
197
|
+
const defaultTableConfigs = useMemo(
|
|
198
|
+
() => ({
|
|
199
|
+
add,
|
|
200
|
+
compactBreakpoint,
|
|
201
|
+
debugFallbackParameters,
|
|
202
|
+
effectiveViewMode,
|
|
203
|
+
filters,
|
|
204
|
+
footerComponent,
|
|
205
|
+
forceCardsOnCompact,
|
|
206
|
+
getOptionsForColumn,
|
|
207
|
+
initialViewMode,
|
|
208
|
+
onAdd,
|
|
209
|
+
onDataLoaded,
|
|
210
|
+
onEditRow,
|
|
211
|
+
onEndReached: handleEndReached,
|
|
212
|
+
onFilterChange,
|
|
213
|
+
onMomentumScrollBegin,
|
|
214
|
+
onRowPress,
|
|
215
|
+
onSaved,
|
|
216
|
+
onScrollBeginDrag,
|
|
217
|
+
pinRowActions,
|
|
218
|
+
renderCard,
|
|
219
|
+
requestParams: requestParamsSeed,
|
|
220
|
+
requestSort,
|
|
221
|
+
resolvedSort,
|
|
222
|
+
rowActionsComponent,
|
|
223
|
+
rowStyle,
|
|
224
|
+
showColumnFiltersButton,
|
|
225
|
+
showRowActions,
|
|
226
|
+
showToolbar,
|
|
227
|
+
showTotalItemsInCompactToolbar,
|
|
228
|
+
showTotalItemsInFooter,
|
|
229
|
+
sortedData,
|
|
230
|
+
summary,
|
|
231
|
+
summaryLabels,
|
|
232
|
+
tableFiltersVisible,
|
|
233
|
+
tablePreferenceScope,
|
|
234
|
+
toolbarActions,
|
|
235
|
+
viewMode: effectiveViewMode,
|
|
236
|
+
}),
|
|
237
|
+
[
|
|
238
|
+
add,
|
|
239
|
+
compactBreakpoint,
|
|
240
|
+
debugFallbackParameters,
|
|
241
|
+
effectiveViewMode,
|
|
242
|
+
filters,
|
|
243
|
+
footerComponent,
|
|
244
|
+
forceCardsOnCompact,
|
|
245
|
+
getOptionsForColumn,
|
|
246
|
+
handleEndReached,
|
|
247
|
+
initialViewMode,
|
|
248
|
+
onAdd,
|
|
249
|
+
onDataLoaded,
|
|
250
|
+
onEditRow,
|
|
251
|
+
onFilterChange,
|
|
252
|
+
onMomentumScrollBegin,
|
|
253
|
+
onRowPress,
|
|
254
|
+
onSaved,
|
|
255
|
+
onScrollBeginDrag,
|
|
256
|
+
pinRowActions,
|
|
257
|
+
renderCard,
|
|
258
|
+
requestParamsSeed,
|
|
259
|
+
requestSort,
|
|
260
|
+
resolvedSort,
|
|
261
|
+
rowActionsComponent,
|
|
262
|
+
rowStyle,
|
|
263
|
+
showColumnFiltersButton,
|
|
264
|
+
showRowActions,
|
|
265
|
+
showToolbar,
|
|
266
|
+
showTotalItemsInCompactToolbar,
|
|
267
|
+
showTotalItemsInFooter,
|
|
268
|
+
sortedData,
|
|
269
|
+
summary,
|
|
270
|
+
summaryLabels,
|
|
271
|
+
tableFiltersVisible,
|
|
272
|
+
tablePreferenceScope,
|
|
273
|
+
toolbarActions,
|
|
274
|
+
],
|
|
827
275
|
);
|
|
828
|
-
const
|
|
276
|
+
const defaultTableConfigsSignature = useMemo(
|
|
829
277
|
() =>
|
|
830
278
|
stableSerialize({
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
279
|
+
add,
|
|
280
|
+
compactBreakpoint,
|
|
281
|
+
debugFallbackParameters,
|
|
282
|
+
effectiveViewMode,
|
|
283
|
+
filters,
|
|
284
|
+
forceCardsOnCompact,
|
|
285
|
+
initialViewMode,
|
|
286
|
+
pinRowActions,
|
|
287
|
+
resolvedSort,
|
|
288
|
+
showColumnFiltersButton,
|
|
289
|
+
showRowActions,
|
|
290
|
+
showToolbar,
|
|
291
|
+
showTotalItemsInCompactToolbar,
|
|
292
|
+
showTotalItemsInFooter,
|
|
293
|
+
storedViewMode,
|
|
294
|
+
tableFiltersVisible,
|
|
295
|
+
sortedDataLength: sortedData.length,
|
|
296
|
+
toolbarActionsLength: Array.isArray(toolbarActions) ? toolbarActions.length : 0,
|
|
836
297
|
}),
|
|
837
|
-
[
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
const query = buildRequestQuery(page, append);
|
|
859
|
-
|
|
860
|
-
return Promise.resolve(resolvedActions.getItems(query))
|
|
861
|
-
.then(response => {
|
|
862
|
-
if (autoRequestIdRef.current !== requestId) {
|
|
863
|
-
return response;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
const pageItems = normalizeCollectionItems(response);
|
|
867
|
-
autoPageRef.current = page;
|
|
868
|
-
autoLoadedQueryKeyRef.current = autoQuerySignature;
|
|
869
|
-
autoErroredQueryKeyRef.current = '';
|
|
870
|
-
setAutoHasLoaded(true);
|
|
871
|
-
setAutoLastPageCount(pageItems.length);
|
|
872
|
-
return pageItems;
|
|
873
|
-
})
|
|
874
|
-
.catch(error => {
|
|
875
|
-
if (autoRequestIdRef.current === requestId) {
|
|
876
|
-
autoErroredQueryKeyRef.current = autoQuerySignature;
|
|
877
|
-
showError?.(error?.message || 'Nao foi possivel carregar os registros.');
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
return [];
|
|
881
|
-
})
|
|
882
|
-
.finally(() => {
|
|
883
|
-
if (autoRequestIdRef.current === requestId) {
|
|
884
|
-
setAutoLoading(false);
|
|
885
|
-
setAutoLoadingMore(false);
|
|
886
|
-
endReachedLockRef.current = false;
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
},
|
|
890
|
-
[autoMode, autoQuerySignature, buildRequestQuery, resolvedActions, showError],
|
|
891
|
-
);
|
|
892
|
-
|
|
893
|
-
const availableColumns = useMemo(
|
|
894
|
-
() => columnsForTable.filter(column => shouldIncludeColumn(column)),
|
|
895
|
-
[columnsForTable],
|
|
298
|
+
[
|
|
299
|
+
add,
|
|
300
|
+
compactBreakpoint,
|
|
301
|
+
debugFallbackParameters,
|
|
302
|
+
effectiveViewMode,
|
|
303
|
+
filters,
|
|
304
|
+
forceCardsOnCompact,
|
|
305
|
+
initialViewMode,
|
|
306
|
+
pinRowActions,
|
|
307
|
+
resolvedSort,
|
|
308
|
+
showColumnFiltersButton,
|
|
309
|
+
showRowActions,
|
|
310
|
+
showToolbar,
|
|
311
|
+
showTotalItemsInCompactToolbar,
|
|
312
|
+
showTotalItemsInFooter,
|
|
313
|
+
storedViewMode,
|
|
314
|
+
tableFiltersVisible,
|
|
315
|
+
sortedData.length,
|
|
316
|
+
toolbarActions,
|
|
317
|
+
],
|
|
896
318
|
);
|
|
897
|
-
|
|
898
|
-
useEffect(() => {
|
|
899
|
-
setVisibleColumns(prev =>
|
|
900
|
-
stableSerialize(prev) === stableSerialize(visibleColumnsSeed)
|
|
901
|
-
? prev
|
|
902
|
-
: visibleColumnsSeed
|
|
903
|
-
);
|
|
904
|
-
}, [visibleColumnsSeed]);
|
|
905
|
-
|
|
906
|
-
useEffect(() => {
|
|
907
|
-
setViewMode(viewModeSeed);
|
|
908
|
-
}, [viewModeSeed]);
|
|
909
319
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
setAutoSort(prev =>
|
|
914
|
-
stableSerialize(prev) === stableSerialize(storedSortSeed)
|
|
915
|
-
? prev
|
|
916
|
-
: storedSortSeed,
|
|
917
|
-
);
|
|
918
|
-
}, [autoMode, storedSortSeed]);
|
|
919
|
-
|
|
920
|
-
useEffect(() => {
|
|
921
|
-
if (!autoMode) return;
|
|
922
|
-
|
|
923
|
-
setAutoFilters(prev => {
|
|
924
|
-
if (stableSerialize(prev) === stableSerialize(storeFilters)) {
|
|
925
|
-
return prev;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
return storeFilters;
|
|
929
|
-
});
|
|
930
|
-
}, [autoMode, storeFilters]);
|
|
320
|
+
if (store?.getters) {
|
|
321
|
+
assignGetterValue(store, 'configs', defaultTableConfigs);
|
|
322
|
+
}
|
|
931
323
|
|
|
932
324
|
useEffect(() => {
|
|
933
|
-
if (
|
|
934
|
-
if (typeof resolvedActions.getItems !== 'function') return;
|
|
935
|
-
if (
|
|
936
|
-
autoLoading ||
|
|
937
|
-
autoLoadingMore ||
|
|
938
|
-
autoLoadedQueryKeyRef.current === autoQuerySignature ||
|
|
939
|
-
autoErroredQueryKeyRef.current === autoQuerySignature
|
|
940
|
-
) {
|
|
325
|
+
if (storeColumns.length > 0 || !Array.isArray(columns) || columns.length === 0) {
|
|
941
326
|
return;
|
|
942
327
|
}
|
|
943
328
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
}, [
|
|
947
|
-
autoLoading,
|
|
948
|
-
autoLoadingMore,
|
|
949
|
-
autoMode,
|
|
950
|
-
autoQuerySignature,
|
|
951
|
-
isFocused,
|
|
952
|
-
loadAutoPage,
|
|
953
|
-
resolvedActions,
|
|
954
|
-
]);
|
|
955
|
-
|
|
956
|
-
const tableColumns = useMemo(
|
|
957
|
-
() => columnsForTable.filter(column => shouldIncludeColumn(column) && visibleColumns[getColumnKey(column)] !== false),
|
|
958
|
-
[columnsForTable, visibleColumns],
|
|
959
|
-
);
|
|
960
|
-
|
|
961
|
-
const editableColumns = useMemo(
|
|
962
|
-
() => tableColumns.filter(isEditableColumn),
|
|
963
|
-
[tableColumns],
|
|
964
|
-
);
|
|
329
|
+
publishStoreValue(store, 'setColumns', columns, 'columns');
|
|
330
|
+
}, [columns, store, storeColumns.length]);
|
|
965
331
|
|
|
966
|
-
const activeFilterCount = useMemo(
|
|
967
|
-
() => Object.values(resolvedFilters || {}).filter(value => normalizeText(value) !== '').length,
|
|
968
|
-
[resolvedFilters],
|
|
969
|
-
);
|
|
970
|
-
const hasRowActions =
|
|
971
|
-
showRowActions !== false &&
|
|
972
|
-
(editableColumns.length > 0 || typeof onEditRow === 'function');
|
|
973
|
-
const storeAddConfig = store?.getters?.add;
|
|
974
|
-
const addConfig = add !== null && add !== undefined ? add : storeAddConfig;
|
|
975
|
-
const hasAddInstruction = addConfig === true || (isObject(addConfig) && addConfig.enabled !== false);
|
|
976
|
-
const shouldRenderAddButton =
|
|
977
|
-
hasAddInstruction &&
|
|
978
|
-
(typeof onAdd === 'function' || typeof resolvedActions.save === 'function');
|
|
979
|
-
const resolvedIsLoading = autoMode ? (autoLoading || autoLoadingMore) : Boolean(isLoading);
|
|
980
|
-
const resolvedData = autoMode
|
|
981
|
-
? (autoHasLoaded && Array.isArray(store?.getters?.items) ? store.getters.items : [])
|
|
982
|
-
: (Array.isArray(data) ? data : []);
|
|
983
|
-
const tableMinimumWidth = useMemo(
|
|
984
|
-
() =>
|
|
985
|
-
tableColumns.reduce(
|
|
986
|
-
(totalWidth, column) => totalWidth + getColumnMinWidth(column),
|
|
987
|
-
hasRowActions ? ACTIONS_CELL_WIDTH : 0,
|
|
988
|
-
),
|
|
989
|
-
[hasRowActions, tableColumns],
|
|
990
|
-
);
|
|
991
|
-
const tableWidth = Math.max(tableContainerWidth, tableMinimumWidth);
|
|
992
|
-
const tableLayoutStyle = useMemo(
|
|
993
|
-
() => (tableWidth > 0 ? { minWidth: tableWidth, width: tableWidth } : null),
|
|
994
|
-
[tableWidth],
|
|
995
|
-
);
|
|
996
|
-
const isCompactView = width > 0 && width <= compactBreakpoint;
|
|
997
|
-
const shouldForceCardsOnCompact = forceCardsOnCompact !== false;
|
|
998
|
-
const effectiveViewMode =
|
|
999
|
-
isCompactView && shouldForceCardsOnCompact
|
|
1000
|
-
? (compactViewMode || 'cards')
|
|
1001
|
-
: viewMode;
|
|
1002
332
|
useEffect(() => {
|
|
1003
|
-
if (!
|
|
1004
|
-
setCompactViewMode(null);
|
|
333
|
+
if (data === undefined || !Array.isArray(data)) {
|
|
1005
334
|
return;
|
|
1006
335
|
}
|
|
1007
336
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
setCompactViewMode(null);
|
|
1014
|
-
}, [isCompactView, shouldForceCardsOnCompact]);
|
|
1015
|
-
const emptyStateLabel = resolvedIsLoading
|
|
1016
|
-
? global.t?.t(storeName, 'label', 'loading') || 'Carregando...'
|
|
1017
|
-
: 'Nenhum registro encontrado';
|
|
1018
|
-
const storeTotalItems = store?.getters?.totalItems;
|
|
1019
|
-
const resolvedTotalItems = totalItems !== null && totalItems !== undefined
|
|
1020
|
-
? totalItems
|
|
1021
|
-
: storeTotalItems;
|
|
1022
|
-
const totalItemsNumber = Number(resolvedTotalItems);
|
|
1023
|
-
const shouldRenderTotalItems =
|
|
1024
|
-
resolvedTotalItems !== null &&
|
|
1025
|
-
resolvedTotalItems !== undefined &&
|
|
1026
|
-
Number.isFinite(totalItemsNumber);
|
|
1027
|
-
const shouldRenderFooterTotalItems =
|
|
1028
|
-
shouldRenderTotalItems &&
|
|
1029
|
-
showTotalItemsInFooter !== false;
|
|
1030
|
-
const shouldRenderCompactToolbarTotalItems =
|
|
1031
|
-
showTotalItemsInCompactToolbar === true &&
|
|
1032
|
-
isCompactView &&
|
|
1033
|
-
shouldRenderTotalItems;
|
|
1034
|
-
const resolvedTotalItemsText =
|
|
1035
|
-
normalizeText(totalItemsText) !== ''
|
|
1036
|
-
? totalItemsText
|
|
1037
|
-
: shouldRenderTotalItems
|
|
1038
|
-
? `${totalItemsNumber} ${totalItemsLabel || global.t?.t(storeName, 'label', 'items') || 'registros'}`
|
|
1039
|
-
: '';
|
|
1040
|
-
const storeSummary = store?.getters?.summary;
|
|
1041
|
-
const resolvedSummary = summary !== null && summary !== undefined ? summary : storeSummary;
|
|
1042
|
-
const shouldReadSummary = resolvedSummary !== false && isObject(resolvedSummary);
|
|
1043
|
-
const summaryEntries = useMemo(() => {
|
|
1044
|
-
if (!shouldReadSummary) return [];
|
|
1045
|
-
|
|
1046
|
-
const labels = summaryLabels || {};
|
|
1047
|
-
const usedPaths = new Set();
|
|
1048
|
-
const columnEntries = tableColumns.flatMap(column => {
|
|
1049
|
-
const operations = getSummaryOperations(column);
|
|
1050
|
-
if (!operations.length) return [];
|
|
1051
|
-
|
|
1052
|
-
const columnLabel = formatStoreColumnLabel({
|
|
1053
|
-
columns: columnsForTable,
|
|
1054
|
-
fieldName: getColumnKey(column),
|
|
1055
|
-
fallbackLabel: column?.label || getColumnKey(column),
|
|
1056
|
-
storeName,
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
return operations.map(operation => {
|
|
1060
|
-
const fieldName = getSummaryField(column, operation);
|
|
1061
|
-
const path = [operation, fieldName];
|
|
1062
|
-
const pathKey = path.join('.');
|
|
1063
|
-
const value = resolvedSummary?.[operation]?.[fieldName];
|
|
1064
|
-
if (value === undefined) return null;
|
|
1065
|
-
|
|
1066
|
-
usedPaths.add(pathKey);
|
|
1067
|
-
|
|
1068
|
-
return {
|
|
1069
|
-
key: pathKey,
|
|
1070
|
-
label: labels[pathKey] || (operations.length > 1 ? `${columnLabel} ${operation}` : columnLabel),
|
|
1071
|
-
path,
|
|
1072
|
-
value,
|
|
1073
|
-
column,
|
|
1074
|
-
};
|
|
1075
|
-
}).filter(Boolean);
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
|
-
const genericEntries = flattenSummaryEntries({
|
|
1079
|
-
summaryLabels: labels,
|
|
1080
|
-
usedPaths,
|
|
1081
|
-
value: resolvedSummary,
|
|
1082
|
-
});
|
|
1083
|
-
|
|
1084
|
-
return [...columnEntries, ...genericEntries].filter(entry =>
|
|
1085
|
-
entry?.value !== undefined &&
|
|
1086
|
-
entry?.value !== null &&
|
|
1087
|
-
normalizeText(entry.value) !== '',
|
|
1088
|
-
);
|
|
1089
|
-
}, [columnsForTable, resolvedSummary, shouldReadSummary, storeName, summaryLabels, tableColumns]);
|
|
1090
|
-
const shouldRenderFooterBar =
|
|
1091
|
-
(shouldRenderFooterTotalItems && !shouldRenderCompactToolbarTotalItems) ||
|
|
1092
|
-
summaryEntries.length > 0;
|
|
1093
|
-
const footerProps = {
|
|
1094
|
-
columns: columnsForTable,
|
|
1095
|
-
resolvedAccentColor,
|
|
1096
|
-
resolvedTotalItemsText,
|
|
1097
|
-
shouldRenderCompactToolbarTotalItems,
|
|
1098
|
-
shouldRenderFooterTotalItems,
|
|
1099
|
-
storeName,
|
|
1100
|
-
summaryEntries,
|
|
1101
|
-
summaryLabels,
|
|
1102
|
-
tableBorderColor,
|
|
1103
|
-
tableMutedColor,
|
|
1104
|
-
tableSurfaceColor,
|
|
1105
|
-
tableTextColor,
|
|
1106
|
-
toolbarCountBackgroundColor,
|
|
1107
|
-
toolbarCountTextColor,
|
|
1108
|
-
};
|
|
1109
|
-
|
|
1110
|
-
const sortedData = useMemo(() => {
|
|
1111
|
-
const items = Array.isArray(resolvedData) ? [...resolvedData] : [];
|
|
1112
|
-
const sortField = resolvedSort?.field;
|
|
1113
|
-
const sortDirection = resolvedSort?.direction === 'desc' ? 'desc' : 'asc';
|
|
1114
|
-
const sortColumn = tableColumns.find(column => getSortField(column) === sortField);
|
|
1115
|
-
|
|
1116
|
-
if (!sortField || !sortColumn) return items;
|
|
1117
|
-
|
|
1118
|
-
return items.sort((left, right) => {
|
|
1119
|
-
const leftValue = resolveSortComparable({
|
|
1120
|
-
column: sortColumn,
|
|
1121
|
-
columns: tableColumns,
|
|
1122
|
-
row: left,
|
|
1123
|
-
storeName,
|
|
1124
|
-
});
|
|
1125
|
-
const rightValue = resolveSortComparable({
|
|
1126
|
-
column: sortColumn,
|
|
1127
|
-
columns: tableColumns,
|
|
1128
|
-
row: right,
|
|
1129
|
-
storeName,
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
const comparison =
|
|
1133
|
-
typeof leftValue === 'number' && typeof rightValue === 'number'
|
|
1134
|
-
? leftValue - rightValue
|
|
1135
|
-
: normalizeSortText(leftValue).localeCompare(normalizeSortText(rightValue));
|
|
1136
|
-
|
|
1137
|
-
return sortDirection === 'desc' ? comparison * -1 : comparison;
|
|
1138
|
-
});
|
|
1139
|
-
}, [resolvedData, resolvedSort?.direction, resolvedSort?.field, storeName, tableColumns]);
|
|
1140
|
-
|
|
1141
|
-
const resolvedHasMore = useMemo(
|
|
1142
|
-
() => {
|
|
1143
|
-
if (autoMode) {
|
|
1144
|
-
if (Number.isFinite(Number(resolvedTotalItems)) && Number(resolvedTotalItems) > 0) {
|
|
1145
|
-
return sortedData.length < Number(resolvedTotalItems);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
return autoLastPageCount >= pageSizeNumber && sortedData.length > 0;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
return resolveHasMore({
|
|
1152
|
-
hasMore,
|
|
1153
|
-
dataLength: sortedData.length,
|
|
1154
|
-
totalItems: resolvedTotalItems,
|
|
1155
|
-
});
|
|
1156
|
-
},
|
|
1157
|
-
[autoLastPageCount, autoMode, hasMore, pageSizeNumber, resolvedTotalItems, sortedData.length],
|
|
1158
|
-
);
|
|
1159
|
-
|
|
1160
|
-
useEffect(() => {
|
|
1161
|
-
const nextPaginationState = {
|
|
1162
|
-
dataLength: sortedData.length,
|
|
1163
|
-
filtersKey: stableSerialize(resolvedFilters || {}),
|
|
1164
|
-
sortDirection: resolvedSort?.direction,
|
|
1165
|
-
sortField: resolvedSort?.field,
|
|
1166
|
-
};
|
|
1167
|
-
|
|
1168
|
-
const previousPaginationState = previousPaginationStateRef.current;
|
|
1169
|
-
const didPaginationStateChange =
|
|
1170
|
-
previousPaginationState.dataLength !== nextPaginationState.dataLength ||
|
|
1171
|
-
previousPaginationState.filtersKey !== nextPaginationState.filtersKey ||
|
|
1172
|
-
previousPaginationState.sortDirection !== nextPaginationState.sortDirection ||
|
|
1173
|
-
previousPaginationState.sortField !== nextPaginationState.sortField;
|
|
1174
|
-
|
|
1175
|
-
if (didPaginationStateChange) {
|
|
1176
|
-
endReachedLockRef.current = false;
|
|
1177
|
-
previousPaginationStateRef.current = nextPaginationState;
|
|
1178
|
-
}
|
|
1179
|
-
}, [resolvedFilters, resolvedSort?.direction, resolvedSort?.field, sortedData]);
|
|
337
|
+
publishStoreValue(store, 'setItems', data, 'items');
|
|
338
|
+
}, [data, store]);
|
|
1180
339
|
|
|
1181
340
|
useEffect(() => {
|
|
1182
|
-
if (
|
|
341
|
+
if (!columnsForTable.length) {
|
|
1183
342
|
return;
|
|
1184
343
|
}
|
|
1185
344
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
const beginEdit = useCallback((row, column) => {
|
|
1190
|
-
if (!isEditableColumn(column)) return;
|
|
1191
|
-
setEditingCell(`${row?.id || row?.['@id']}:${getColumnKey(column)}`);
|
|
1192
|
-
}, []);
|
|
1193
|
-
|
|
1194
|
-
const clearEdit = useCallback(() => {
|
|
1195
|
-
setEditingCell(null);
|
|
1196
|
-
}, []);
|
|
1197
|
-
|
|
1198
|
-
const saveCell = useCallback((row, column, nextValue) => {
|
|
1199
|
-
const fieldName = getColumnKey(column);
|
|
1200
|
-
if (!fieldName || typeof resolvedActions.save !== 'function') {
|
|
1201
|
-
clearEdit();
|
|
1202
|
-
return Promise.resolve(null);
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
const currentValue = resolveEditValue(column, row);
|
|
1206
|
-
const normalizedNextValue = nextValue && typeof nextValue === 'object'
|
|
1207
|
-
? normalizeOptionKey(nextValue)
|
|
1208
|
-
: normalizeText(nextValue);
|
|
1209
|
-
|
|
1210
|
-
if (normalizeText(currentValue) === normalizeText(normalizedNextValue)) {
|
|
1211
|
-
clearEdit();
|
|
1212
|
-
return Promise.resolve(null);
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
const cellKey = `${row?.id || row?.['@id']}:${fieldName}`;
|
|
1216
|
-
const payload = {
|
|
1217
|
-
id: normalizeId(row?.['@id'] || row?.id),
|
|
1218
|
-
[fieldName]: formatSaveValue(column, nextValue, row),
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
setSavingCell(cellKey);
|
|
1222
|
-
|
|
1223
|
-
return resolvedActions.save(payload)
|
|
1224
|
-
.then(savedItem => {
|
|
1225
|
-
onSaved?.(savedItem || { ...row, [fieldName]: nextValue }, row);
|
|
1226
|
-
return savedItem;
|
|
1227
|
-
})
|
|
1228
|
-
.catch(error => {
|
|
1229
|
-
console.error(error);
|
|
1230
|
-
return null;
|
|
1231
|
-
})
|
|
1232
|
-
.finally(() => {
|
|
1233
|
-
setSavingCell(null);
|
|
1234
|
-
clearEdit();
|
|
1235
|
-
});
|
|
1236
|
-
}, [clearEdit, onSaved, resolvedActions]);
|
|
1237
|
-
|
|
1238
|
-
const requestSort = useCallback(column => {
|
|
1239
|
-
if (!isSortableColumn(column)) return;
|
|
1240
|
-
|
|
1241
|
-
const fieldName = getSortField(column);
|
|
1242
|
-
const nextDirection =
|
|
1243
|
-
resolvedSort?.field === fieldName && resolvedSort?.direction === 'asc'
|
|
1244
|
-
? 'desc'
|
|
1245
|
-
: 'asc';
|
|
1246
|
-
const nextSort = {
|
|
1247
|
-
direction: nextDirection,
|
|
1248
|
-
field: fieldName,
|
|
1249
|
-
};
|
|
1250
|
-
|
|
1251
|
-
if (visibleColumnsPreferenceKey) {
|
|
1252
|
-
persistTableSortPreference(
|
|
1253
|
-
visibleColumnsPreferenceKey,
|
|
1254
|
-
nextSort,
|
|
1255
|
-
);
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
if (autoMode) {
|
|
1259
|
-
setAutoSort(nextSort);
|
|
345
|
+
const storedVisibleColumns = resolveStoredVisibleColumnsPreference(tablePreferenceScope);
|
|
346
|
+
if (!storedVisibleColumns) {
|
|
1260
347
|
return;
|
|
1261
348
|
}
|
|
1262
349
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
]);
|
|
1271
|
-
|
|
1272
|
-
const openEditModal = useCallback(row => {
|
|
1273
|
-
if (typeof onEditRow === 'function') {
|
|
1274
|
-
onEditRow(row);
|
|
350
|
+
const nextVisibleColumns = sanitizeVisibleColumnsPreference({
|
|
351
|
+
columns: columnsForTable,
|
|
352
|
+
visibleColumns: storedVisibleColumns,
|
|
353
|
+
});
|
|
354
|
+
const currentVisibleColumns = store?.getters?.visibleColumns || {};
|
|
355
|
+
|
|
356
|
+
if (stableSerialize(currentVisibleColumns) === stableSerialize(nextVisibleColumns)) {
|
|
1275
357
|
return;
|
|
1276
358
|
}
|
|
1277
359
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}, [onEditRow]);
|
|
360
|
+
publishStoreValue(store, 'setVisibleColumns', nextVisibleColumns, 'visibleColumns');
|
|
361
|
+
}, [columnsForTable, store, tablePreferenceScope]);
|
|
1281
362
|
|
|
1282
|
-
|
|
1283
|
-
if (
|
|
1284
|
-
onAdd();
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
if (!columnsForTable.length || Object.keys(storeFilters).length > 0) {
|
|
1285
365
|
return;
|
|
1286
366
|
}
|
|
1287
367
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
setFormMode('create');
|
|
1291
|
-
setEditingRow({});
|
|
1292
|
-
}, [onAdd, resolvedActions]);
|
|
1293
|
-
|
|
1294
|
-
const closeEditModal = useCallback(() => {
|
|
1295
|
-
setEditingRow(null);
|
|
1296
|
-
setFormMode('edit');
|
|
1297
|
-
}, []);
|
|
1298
|
-
|
|
1299
|
-
const commitFilters = useCallback(nextFilters => {
|
|
1300
|
-
const resolvedNextFilters = isObject(nextFilters) ? nextFilters : {};
|
|
1301
|
-
|
|
1302
|
-
if (autoMode) {
|
|
1303
|
-
setAutoFilters(resolvedNextFilters);
|
|
1304
|
-
resolvedActions.setFilters?.(resolvedNextFilters);
|
|
368
|
+
const storedFilters = resolveStoredTableFiltersPreference(tablePreferenceScope);
|
|
369
|
+
if (!storedFilters) {
|
|
1305
370
|
return;
|
|
1306
371
|
}
|
|
1307
372
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
const updateFilter = useCallback((fieldName, value) => {
|
|
1312
|
-
const nextFilters = { ...(resolvedFilters || {}) };
|
|
1313
|
-
const isEmpty =
|
|
1314
|
-
value === null ||
|
|
1315
|
-
value === undefined ||
|
|
1316
|
-
normalizeText(value) === '' ||
|
|
1317
|
-
(Array.isArray(value) && value.length === 0);
|
|
1318
|
-
|
|
1319
|
-
if (isEmpty) delete nextFilters[fieldName];
|
|
1320
|
-
else nextFilters[fieldName] = value;
|
|
1321
|
-
|
|
1322
|
-
commitFilters(nextFilters);
|
|
1323
|
-
}, [commitFilters, resolvedFilters]);
|
|
1324
|
-
|
|
1325
|
-
const toggleColumn = useCallback(column => {
|
|
1326
|
-
const fieldName = getColumnKey(column);
|
|
1327
|
-
if (!fieldName) return;
|
|
1328
|
-
|
|
1329
|
-
setVisibleColumns(prev => {
|
|
1330
|
-
const next = {
|
|
1331
|
-
...sanitizeVisibleColumnsPreference({
|
|
1332
|
-
columns: columnsForTable,
|
|
1333
|
-
visibleColumns: prev,
|
|
1334
|
-
}),
|
|
1335
|
-
[fieldName]: prev[fieldName] === false,
|
|
1336
|
-
};
|
|
1337
|
-
|
|
1338
|
-
resolvedActions?.setVisibleColumns?.(next);
|
|
1339
|
-
if (visibleColumnsStorageKey) {
|
|
1340
|
-
persistVisibleColumnsPreference(
|
|
1341
|
-
visibleColumnsStorageKey,
|
|
1342
|
-
next,
|
|
1343
|
-
);
|
|
1344
|
-
}
|
|
1345
|
-
return next;
|
|
373
|
+
const nextFilters = sanitizeTableFiltersPreference({
|
|
374
|
+
columns: columnsForTable,
|
|
375
|
+
filters: storedFilters,
|
|
1346
376
|
});
|
|
1347
|
-
}, [
|
|
1348
|
-
resolvedActions,
|
|
1349
|
-
columnsForTable,
|
|
1350
|
-
visibleColumnsStorageKey,
|
|
1351
|
-
]);
|
|
1352
|
-
|
|
1353
|
-
const toggleViewMode = useCallback(() => {
|
|
1354
|
-
const currentViewMode =
|
|
1355
|
-
isCompactView && shouldForceCardsOnCompact
|
|
1356
|
-
? (compactViewMode || 'cards')
|
|
1357
|
-
: viewMode;
|
|
1358
|
-
const nextViewMode = currentViewMode === 'table' ? 'cards' : 'table';
|
|
1359
|
-
|
|
1360
|
-
if (isCompactView && shouldForceCardsOnCompact) {
|
|
1361
|
-
setCompactViewMode(nextViewMode);
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
setViewMode(nextViewMode);
|
|
1365
|
-
|
|
1366
|
-
if (!visibleColumnsPreferenceKey) {
|
|
1367
|
-
return;
|
|
1368
|
-
}
|
|
1369
377
|
|
|
1370
|
-
|
|
1371
|
-
visibleColumnsPreferenceKey,
|
|
1372
|
-
nextViewMode,
|
|
1373
|
-
);
|
|
1374
|
-
}, [
|
|
1375
|
-
compactViewMode,
|
|
1376
|
-
isCompactView,
|
|
1377
|
-
shouldForceCardsOnCompact,
|
|
1378
|
-
viewMode,
|
|
1379
|
-
visibleColumnsPreferenceKey,
|
|
1380
|
-
]);
|
|
1381
|
-
|
|
1382
|
-
const handleEndReached = useCallback(() => {
|
|
1383
|
-
if (
|
|
1384
|
-
!resolvedHasMore ||
|
|
1385
|
-
resolvedIsLoading ||
|
|
1386
|
-
endReachedLockRef.current === true
|
|
1387
|
-
) {
|
|
378
|
+
if (Object.keys(nextFilters).length === 0) {
|
|
1388
379
|
return;
|
|
1389
380
|
}
|
|
1390
381
|
|
|
1391
|
-
|
|
382
|
+
publishStoreValue(store, 'setFilters', nextFilters, 'filters');
|
|
383
|
+
}, [columnsForTable, store, storeFilters, tablePreferenceScope]);
|
|
1392
384
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
loadAutoPage(nextPage, { append: true });
|
|
385
|
+
useEffect(() => {
|
|
386
|
+
if (configsSignatureRef.current === defaultTableConfigsSignature) {
|
|
1396
387
|
return;
|
|
1397
388
|
}
|
|
1398
389
|
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
}, [autoMode, loadAutoPage, onEndReached, resolvedHasMore, resolvedIsLoading]);
|
|
1403
|
-
|
|
1404
|
-
const handleLayout = useCallback(event => {
|
|
1405
|
-
const nextWidth = Math.floor(event?.nativeEvent?.layout?.width || 0);
|
|
1406
|
-
if (nextWidth > 0) setTableContainerWidth(nextWidth);
|
|
1407
|
-
}, []);
|
|
1408
|
-
|
|
1409
|
-
const renderEditableCell = (row, column) => {
|
|
1410
|
-
const fieldName = getColumnKey(column);
|
|
1411
|
-
const cellKey = `${row?.id || row?.['@id']}:${fieldName}`;
|
|
1412
|
-
const isEditing = editingCell === cellKey;
|
|
1413
|
-
const isSaving = savingCell === cellKey;
|
|
1414
|
-
const shouldDelegatePress =
|
|
1415
|
-
typeof onRowPress === 'function' &&
|
|
1416
|
-
!isEditableColumn(column);
|
|
1417
|
-
|
|
1418
|
-
return (
|
|
1419
|
-
<View
|
|
1420
|
-
style={[getColumnStyle(column), isEditing ? styles.editingCell : null]}
|
|
1421
|
-
pointerEvents={shouldDelegatePress ? 'none' : 'auto'}
|
|
1422
|
-
>
|
|
1423
|
-
<DefaultInput
|
|
1424
|
-
accentColor={resolvedAccentColor}
|
|
1425
|
-
column={column}
|
|
1426
|
-
columns={columnsForTable}
|
|
1427
|
-
editing={isEditing}
|
|
1428
|
-
getOptionsForColumn={resolvedGetOptionsForColumn}
|
|
1429
|
-
onBeforeOpen={() => loadListOptionsForColumns([column])}
|
|
1430
|
-
onCancelEditing={clearEdit}
|
|
1431
|
-
onSave={value => saveCell(row, column, value)}
|
|
1432
|
-
onStartEditing={() => beginEdit(row, column)}
|
|
1433
|
-
row={row}
|
|
1434
|
-
saving={isSaving}
|
|
1435
|
-
storeName={storeName}
|
|
1436
|
-
variant="cell"
|
|
1437
|
-
/>
|
|
1438
|
-
</View>
|
|
1439
|
-
);
|
|
1440
|
-
};
|
|
1441
|
-
|
|
1442
|
-
const renderColumnFilter = column => {
|
|
1443
|
-
return (
|
|
1444
|
-
<DefaultColumnFilter
|
|
1445
|
-
accentColor={resolvedAccentColor}
|
|
1446
|
-
column={column}
|
|
1447
|
-
filters={resolvedFilters}
|
|
1448
|
-
onBeforeOpen={column?.list ? () => loadListOptionsForColumns([column]) : null}
|
|
1449
|
-
getOptionsForColumn={resolvedGetOptionsForColumn}
|
|
1450
|
-
onChange={updateFilter}
|
|
1451
|
-
storeName={storeName}
|
|
1452
|
-
style={getColumnStyle(column)}
|
|
1453
|
-
/>
|
|
1454
|
-
);
|
|
1455
|
-
};
|
|
1456
|
-
|
|
1457
|
-
const renderToolbarAction = action => {
|
|
1458
|
-
if (!action || action.hidden) return null;
|
|
1459
|
-
|
|
1460
|
-
const isActive = action.active === true;
|
|
1461
|
-
const hasLabel = normalizeText(action.label) !== '';
|
|
1462
|
-
const actionColor = action.color || tableActionTextColor;
|
|
1463
|
-
|
|
1464
|
-
return (
|
|
1465
|
-
<TouchableOpacity
|
|
1466
|
-
key={action.key || action.icon || action.label}
|
|
1467
|
-
accessibilityRole="button"
|
|
1468
|
-
accessibilityLabel={action.accessibilityLabel || action.label || action.key || action.icon}
|
|
1469
|
-
style={[
|
|
1470
|
-
styles.toolbarButton,
|
|
1471
|
-
{ backgroundColor: tableActionBackgroundColor, borderColor: tableActionBorderColor },
|
|
1472
|
-
action.style,
|
|
1473
|
-
]}
|
|
1474
|
-
activeOpacity={0.82}
|
|
1475
|
-
disabled={action.disabled === true}
|
|
1476
|
-
onPress={action.onPress}
|
|
1477
|
-
>
|
|
1478
|
-
{action.icon ? (
|
|
1479
|
-
<Icon
|
|
1480
|
-
name={action.icon}
|
|
1481
|
-
size={action.iconSize || 14}
|
|
1482
|
-
color={actionColor}
|
|
1483
|
-
/>
|
|
1484
|
-
) : null}
|
|
1485
|
-
{hasLabel ? (
|
|
1486
|
-
<Text style={[styles.toolbarActionLabel, { color: actionColor }, action.labelStyle]} numberOfLines={1}>
|
|
1487
|
-
{action.label}
|
|
1488
|
-
</Text>
|
|
1489
|
-
) : null}
|
|
1490
|
-
{action.badge !== undefined && action.badge !== null ? (
|
|
1491
|
-
<Text style={[styles.toolbarBadgeText, { color: action.badgeColor || tableActionTextColor }]}>
|
|
1492
|
-
{action.badge}
|
|
1493
|
-
</Text>
|
|
1494
|
-
) : null}
|
|
1495
|
-
</TouchableOpacity>
|
|
1496
|
-
);
|
|
1497
|
-
};
|
|
1498
|
-
|
|
1499
|
-
const renderToolbarActions = () =>
|
|
1500
|
-
Array.isArray(toolbarActions) && toolbarActions.length > 0 ? (
|
|
1501
|
-
<View style={styles.toolbarActionGroup}>{toolbarActions.map(renderToolbarAction)}</View>
|
|
1502
|
-
) : null;
|
|
1503
|
-
|
|
1504
|
-
const getColumnByField = useCallback(
|
|
1505
|
-
fieldName => columnsForTable.find(column => getColumnKey(column) === fieldName),
|
|
1506
|
-
[columnsForTable],
|
|
1507
|
-
);
|
|
1508
|
-
|
|
1509
|
-
const buildRowHelpers = useCallback(
|
|
1510
|
-
row => {
|
|
1511
|
-
const openEdit = () => openEditModal(row);
|
|
1512
|
-
const openRow = typeof onRowPress === 'function' ? () => onRowPress(row) : null;
|
|
1513
|
-
const renderValue = (fieldName, fallback = '-') => {
|
|
1514
|
-
const column = getColumnByField(fieldName);
|
|
1515
|
-
if (!column) return fallback;
|
|
1516
|
-
return resolveCellText({ column, columns: columnsForTable, row, storeName });
|
|
1517
|
-
};
|
|
1518
|
-
const renderField = (fieldName, options = {}) => {
|
|
1519
|
-
const column = getColumnByField(fieldName);
|
|
1520
|
-
if (!column) return null;
|
|
1521
|
-
|
|
1522
|
-
const cellKey = `${row?.id || row?.['@id']}:${fieldName}`;
|
|
1523
|
-
const isEditing = editingCell === cellKey;
|
|
1524
|
-
const isSaving = savingCell === cellKey;
|
|
1525
|
-
|
|
1526
|
-
return (
|
|
1527
|
-
<DefaultInput
|
|
1528
|
-
accentColor={options.accentColor || resolvedAccentColor}
|
|
1529
|
-
column={column}
|
|
1530
|
-
columns={columnsForTable}
|
|
1531
|
-
containerStyle={options.containerStyle}
|
|
1532
|
-
displayValue={options.displayValue}
|
|
1533
|
-
editing={isEditing}
|
|
1534
|
-
getOptionsForColumn={resolvedGetOptionsForColumn}
|
|
1535
|
-
inputStyle={options.inputStyle}
|
|
1536
|
-
label={options.label}
|
|
1537
|
-
numberOfLines={options.numberOfLines}
|
|
1538
|
-
onBeforeOpen={() => loadListOptionsForColumns([column])}
|
|
1539
|
-
onCancelEditing={clearEdit}
|
|
1540
|
-
onSave={value => saveCell(row, column, value)}
|
|
1541
|
-
onStartEditing={() => beginEdit(row, column)}
|
|
1542
|
-
readTextStyle={options.readTextStyle || options.textStyle}
|
|
1543
|
-
row={row}
|
|
1544
|
-
saving={isSaving}
|
|
1545
|
-
showLabel={options.showLabel}
|
|
1546
|
-
storeName={storeName}
|
|
1547
|
-
variant={options.variant || 'card'}
|
|
1548
|
-
/>
|
|
1549
|
-
);
|
|
1550
|
-
};
|
|
1551
|
-
|
|
1552
|
-
return {
|
|
1553
|
-
openEdit,
|
|
1554
|
-
openRow,
|
|
1555
|
-
renderField,
|
|
1556
|
-
renderValue,
|
|
1557
|
-
};
|
|
1558
|
-
},
|
|
1559
|
-
[
|
|
1560
|
-
resolvedAccentColor,
|
|
1561
|
-
beginEdit,
|
|
1562
|
-
clearEdit,
|
|
1563
|
-
columnsForTable,
|
|
1564
|
-
editingCell,
|
|
1565
|
-
getColumnByField,
|
|
1566
|
-
resolvedGetOptionsForColumn,
|
|
1567
|
-
openEditModal,
|
|
1568
|
-
onRowPress,
|
|
1569
|
-
saveCell,
|
|
1570
|
-
savingCell,
|
|
1571
|
-
storeName,
|
|
1572
|
-
],
|
|
1573
|
-
);
|
|
1574
|
-
|
|
1575
|
-
const resolveRowStyle = useCallback(
|
|
1576
|
-
(row, index) => {
|
|
1577
|
-
if (typeof rowStyle === 'function') {
|
|
1578
|
-
return rowStyle(row, index);
|
|
1579
|
-
}
|
|
390
|
+
configsSignatureRef.current = defaultTableConfigsSignature;
|
|
391
|
+
publishStoreValue(store, 'setConfigs', defaultTableConfigs, 'configs');
|
|
392
|
+
}, [defaultTableConfigs, defaultTableConfigsSignature, store]);
|
|
1580
393
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
);
|
|
1585
|
-
|
|
1586
|
-
const renderCardItem = (row, index = 0) => {
|
|
1587
|
-
const helpers = buildRowHelpers(row);
|
|
1588
|
-
const rowStyleValue = resolveRowStyle(row, index);
|
|
1589
|
-
|
|
1590
|
-
if (typeof renderCard === 'function') {
|
|
1591
|
-
return (
|
|
1592
|
-
<View key={row?.['@id'] || row?.id} style={[styles.cardItem, rowStyleValue]}>
|
|
1593
|
-
{renderCard({
|
|
1594
|
-
item: row,
|
|
1595
|
-
openEdit: helpers.openEdit,
|
|
1596
|
-
openRow: helpers.openRow,
|
|
1597
|
-
renderField: helpers.renderField,
|
|
1598
|
-
renderValue: helpers.renderValue,
|
|
1599
|
-
row,
|
|
1600
|
-
})}
|
|
1601
|
-
{hasRowActions ? (
|
|
1602
|
-
<View style={styles.cardActions}>
|
|
1603
|
-
<TouchableOpacity
|
|
1604
|
-
style={[styles.iconButton, { borderColor: tableBorderColor, backgroundColor: tableSurfaceColor }]}
|
|
1605
|
-
activeOpacity={0.82}
|
|
1606
|
-
onPress={helpers.openEdit}>
|
|
1607
|
-
<Icon name="edit-2" size={14} color={tableMutedColor} />
|
|
1608
|
-
</TouchableOpacity>
|
|
1609
|
-
</View>
|
|
1610
|
-
) : null}
|
|
1611
|
-
</View>
|
|
1612
|
-
);
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
return (
|
|
1616
|
-
<View
|
|
1617
|
-
key={row?.['@id'] || row?.id}
|
|
1618
|
-
style={[
|
|
1619
|
-
styles.defaultCard,
|
|
1620
|
-
{ backgroundColor: tableSurfaceColor, borderColor: tableBorderColor },
|
|
1621
|
-
rowStyleValue,
|
|
1622
|
-
]}
|
|
1623
|
-
>
|
|
1624
|
-
{tableColumns.map(column => (
|
|
1625
|
-
<View key={getColumnKey(column)} style={styles.defaultCardLine}>
|
|
1626
|
-
<Text style={[styles.defaultCardLabel, { color: tableMutedColor }]}>
|
|
1627
|
-
{formatStoreColumnLabel({
|
|
1628
|
-
columns: columnsForTable,
|
|
1629
|
-
fieldName: getColumnKey(column),
|
|
1630
|
-
fallbackLabel: column?.label || getColumnKey(column),
|
|
1631
|
-
storeName,
|
|
1632
|
-
})}
|
|
1633
|
-
</Text>
|
|
1634
|
-
{helpers.renderField(getColumnKey(column), {
|
|
1635
|
-
readTextStyle: [styles.defaultCardValue, { color: tableTextColor }],
|
|
1636
|
-
numberOfLines: 1,
|
|
1637
|
-
})}
|
|
1638
|
-
</View>
|
|
1639
|
-
))}
|
|
1640
|
-
{hasRowActions ? (
|
|
1641
|
-
<TouchableOpacity
|
|
1642
|
-
style={[styles.cardEditButton, { borderColor: tableBorderColor, backgroundColor: tableSurfaceColor }]}
|
|
1643
|
-
activeOpacity={0.82}
|
|
1644
|
-
onPress={helpers.openEdit}>
|
|
1645
|
-
<Icon name="edit-2" size={14} color={tableMutedColor} />
|
|
1646
|
-
</TouchableOpacity>
|
|
1647
|
-
) : null}
|
|
1648
|
-
</View>
|
|
1649
|
-
);
|
|
1650
|
-
};
|
|
1651
|
-
|
|
1652
|
-
const renderEmptyState = isTable => {
|
|
1653
|
-
return (
|
|
1654
|
-
<View style={[styles.emptyBox, isTable ? tableLayoutStyle : null]}>
|
|
1655
|
-
{resolvedIsLoading ? (
|
|
1656
|
-
<StateStore compact loading={emptyStateLabel} />
|
|
1657
|
-
) : (
|
|
1658
|
-
<Text style={[styles.emptyText, { color: tableMutedColor }]}>{emptyStateLabel}</Text>
|
|
1659
|
-
)}
|
|
1660
|
-
</View>
|
|
1661
|
-
);
|
|
1662
|
-
};
|
|
394
|
+
useEffect(() => {
|
|
395
|
+
onDataLoaded?.(sortedData);
|
|
396
|
+
}, [onDataLoaded, sortedData]);
|
|
1663
397
|
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
398
|
+
return (
|
|
399
|
+
<View
|
|
400
|
+
style={[
|
|
401
|
+
styles.wrap,
|
|
402
|
+
{
|
|
403
|
+
borderColor: themeColors.panelBorder,
|
|
404
|
+
backgroundColor: themeColors.panelBackground,
|
|
405
|
+
},
|
|
406
|
+
]}
|
|
407
|
+
>
|
|
408
|
+
{showToolbar !== false ? <DefaultTableToolbar storeName={storeName} /> : null}
|
|
409
|
+
<DefaultTableBody storeName={storeName} />
|
|
410
|
+
<DefaultTableFooter storeName={storeName} />
|
|
411
|
+
{shouldRenderFloatingAddButton ? (
|
|
412
|
+
<TouchableOpacity
|
|
413
|
+
accessibilityRole="button"
|
|
414
|
+
accessibilityLabel={global.t?.t(storeName, 'button', 'add') || 'Adicionar'}
|
|
415
|
+
activeOpacity={0.84}
|
|
1672
416
|
style={[
|
|
1673
|
-
styles.
|
|
1674
|
-
{
|
|
417
|
+
styles.floatingAddButton,
|
|
418
|
+
{ backgroundColor: floatingAddBackgroundColor },
|
|
1675
419
|
]}
|
|
420
|
+
onPress={() => onAdd?.()}
|
|
1676
421
|
>
|
|
1677
|
-
<
|
|
1678
|
-
</
|
|
1679
|
-
</View>
|
|
1680
|
-
);
|
|
1681
|
-
};
|
|
1682
|
-
|
|
1683
|
-
const renderTableItem = ({ item: row, index }) => {
|
|
1684
|
-
const hasRowPress = typeof onRowPress === 'function';
|
|
1685
|
-
const RowComponent = hasRowPress ? TouchableOpacity : View;
|
|
1686
|
-
const rowStyleValue = resolveRowStyle(row, index);
|
|
1687
|
-
const rowPressProps = hasRowPress
|
|
1688
|
-
? {
|
|
1689
|
-
activeOpacity: 0.84,
|
|
1690
|
-
onPress: () => onRowPress(row),
|
|
1691
|
-
}
|
|
1692
|
-
: {};
|
|
1693
|
-
const rowBackgroundColor = index % 2 === 0 ? tableOddColor : tableEvenColor;
|
|
1694
|
-
|
|
1695
|
-
return (
|
|
1696
|
-
<RowComponent
|
|
1697
|
-
key={getRowKey(row)}
|
|
1698
|
-
style={[
|
|
1699
|
-
styles.row,
|
|
1700
|
-
tableLayoutStyle,
|
|
1701
|
-
{ backgroundColor: rowBackgroundColor, borderBottomColor: tableBorderColor },
|
|
1702
|
-
rowStyleValue,
|
|
1703
|
-
]}
|
|
1704
|
-
{...rowPressProps}
|
|
1705
|
-
>
|
|
1706
|
-
{tableColumns.map(column => (
|
|
1707
|
-
<React.Fragment key={getColumnKey(column)}>
|
|
1708
|
-
{renderEditableCell(row, column)}
|
|
1709
|
-
</React.Fragment>
|
|
1710
|
-
))}
|
|
1711
|
-
{hasRowActions ? (
|
|
1712
|
-
<View style={[styles.cell, styles.actionsCell]}>
|
|
1713
|
-
<TouchableOpacity
|
|
1714
|
-
style={[styles.iconButton, { borderColor: tableBorderColor, backgroundColor: tableSurfaceColor }]}
|
|
1715
|
-
activeOpacity={0.82}
|
|
1716
|
-
onPress={() => openEditModal(row)}>
|
|
1717
|
-
<Icon name="edit-2" size={14} color={tableMutedColor} />
|
|
1718
|
-
</TouchableOpacity>
|
|
1719
|
-
</View>
|
|
1720
|
-
) : null}
|
|
1721
|
-
</RowComponent>
|
|
1722
|
-
);
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
const renderEditModal = () => {
|
|
1726
|
-
const isCreate = formMode === 'create';
|
|
1727
|
-
|
|
1728
|
-
return (
|
|
1729
|
-
<Modal visible={Boolean(editingRow)} transparent animationType="fade" onRequestClose={closeEditModal}>
|
|
1730
|
-
<View style={[styles.modalOverlay, { backgroundColor: modalOverlayColor }]}>
|
|
1731
|
-
<View style={[styles.modalCard, { borderColor: modalBorderColor, backgroundColor: modalBackgroundColor }]}>
|
|
1732
|
-
<View style={[styles.modalHeader, { borderBottomColor: modalBorderColor }]}>
|
|
1733
|
-
<Text style={[styles.modalTitle, { color: modalHeaderTextColor }]}>
|
|
1734
|
-
{isCreate
|
|
1735
|
-
? global.t?.t(storeName, 'button', 'add') || 'Adicionar'
|
|
1736
|
-
: global.t?.t(storeName, 'button', 'edit') || 'Editar'}
|
|
1737
|
-
</Text>
|
|
1738
|
-
<TouchableOpacity
|
|
1739
|
-
style={[styles.modalCloseButton, { borderColor: modalBorderColor, backgroundColor: modalBackgroundColor }]}
|
|
1740
|
-
onPress={closeEditModal}>
|
|
1741
|
-
<Icon name="x" size={18} color={modalCloseIconColor} />
|
|
1742
|
-
</TouchableOpacity>
|
|
1743
|
-
</View>
|
|
1744
|
-
|
|
1745
|
-
<DefaultForm
|
|
1746
|
-
accentColor={resolvedAccentColor}
|
|
1747
|
-
actions={resolvedActions}
|
|
1748
|
-
columns={isCreate ? columnsForTable : editableColumns}
|
|
1749
|
-
getOptionsForColumn={resolvedGetOptionsForColumn}
|
|
1750
|
-
mode={formMode}
|
|
1751
|
-
onBeforeOpen={column => loadListOptionsForColumns([column])}
|
|
1752
|
-
onCancel={closeEditModal}
|
|
1753
|
-
onSaved={(savedItem, originalRow) => {
|
|
1754
|
-
onSaved?.(savedItem, originalRow);
|
|
1755
|
-
closeEditModal();
|
|
1756
|
-
}}
|
|
1757
|
-
row={editingRow || {}}
|
|
1758
|
-
storeName={storeName}
|
|
1759
|
-
/>
|
|
1760
|
-
</View>
|
|
1761
|
-
</View>
|
|
1762
|
-
</Modal>
|
|
1763
|
-
);
|
|
1764
|
-
};
|
|
1765
|
-
|
|
1766
|
-
const renderColumnMenuModal = () => {
|
|
1767
|
-
if (!isColumnMenuOpen) return null;
|
|
1768
|
-
|
|
1769
|
-
return (
|
|
1770
|
-
<Modal visible transparent animationType="fade" onRequestClose={() => setIsColumnMenuOpen(false)}>
|
|
1771
|
-
<View style={[styles.modalOverlay, { backgroundColor: modalOverlayColor }]}>
|
|
1772
|
-
<View style={[styles.modalCard, styles.columnMenuModalCard, { borderColor: modalBorderColor, backgroundColor: modalBackgroundColor }]}>
|
|
1773
|
-
<View style={[styles.modalHeader, { borderBottomColor: modalBorderColor }]}>
|
|
1774
|
-
<Text style={[styles.modalTitle, { color: modalHeaderTextColor }]} numberOfLines={1}>
|
|
1775
|
-
Colunas
|
|
1776
|
-
</Text>
|
|
1777
|
-
<TouchableOpacity
|
|
1778
|
-
style={[styles.modalCloseButton, { borderColor: modalBorderColor, backgroundColor: modalBackgroundColor }]}
|
|
1779
|
-
activeOpacity={0.82}
|
|
1780
|
-
onPress={() => setIsColumnMenuOpen(false)}
|
|
1781
|
-
>
|
|
1782
|
-
<Icon name="x" size={16} color={modalCloseIconColor} />
|
|
1783
|
-
</TouchableOpacity>
|
|
1784
|
-
</View>
|
|
1785
|
-
<ScrollView style={styles.columnMenuModalBody} contentContainerStyle={styles.columnMenuModalList}>
|
|
1786
|
-
{availableColumns.map(column => {
|
|
1787
|
-
const fieldName = getColumnKey(column);
|
|
1788
|
-
const label = formatStoreColumnLabel({
|
|
1789
|
-
columns: columnsForTable,
|
|
1790
|
-
fieldName,
|
|
1791
|
-
fallbackLabel: column?.label || fieldName,
|
|
1792
|
-
storeName,
|
|
1793
|
-
});
|
|
1794
|
-
const checked = visibleColumns[fieldName] !== false;
|
|
1795
|
-
|
|
1796
|
-
return (
|
|
1797
|
-
<TouchableOpacity key={fieldName} style={styles.columnMenuItem} activeOpacity={0.82} onPress={() => toggleColumn(column)}>
|
|
1798
|
-
<Icon name={checked ? 'check-square' : 'square'} size={16} color={checked ? checkboxSelectedMarkColor : checkboxBorderColor} />
|
|
1799
|
-
<Text style={[styles.columnMenuText, { color: modalTextColor }]} numberOfLines={1}>{label}</Text>
|
|
1800
|
-
</TouchableOpacity>
|
|
1801
|
-
);
|
|
1802
|
-
})}
|
|
1803
|
-
</ScrollView>
|
|
1804
|
-
</View>
|
|
1805
|
-
</View>
|
|
1806
|
-
</Modal>
|
|
1807
|
-
);
|
|
1808
|
-
};
|
|
1809
|
-
|
|
1810
|
-
return (
|
|
1811
|
-
<View style={[styles.wrap, { borderColor: panelBorderColor, backgroundColor: panelBackgroundColor }]} onLayout={handleLayout}>
|
|
1812
|
-
<View style={[styles.toolbar, { borderBottomColor: toolbarBorderColor, backgroundColor: toolbarBackgroundColor }]}>
|
|
1813
|
-
{shouldRenderCompactToolbarTotalItems ? (
|
|
1814
|
-
<View style={styles.toolbarCompactLead}>
|
|
1815
|
-
<View style={[styles.toolbarCountPill, { backgroundColor: toolbarCountBackgroundColor }]}>
|
|
1816
|
-
<Text
|
|
1817
|
-
style={[styles.toolbarCountText, { color: toolbarCountTextColor }]}
|
|
1818
|
-
numberOfLines={1}
|
|
1819
|
-
adjustsFontSizeToFit
|
|
1820
|
-
minimumFontScale={0.82}
|
|
1821
|
-
>
|
|
1822
|
-
{resolvedTotalItemsText}
|
|
1823
|
-
</Text>
|
|
1824
|
-
</View>
|
|
1825
|
-
{searchProps ? (
|
|
1826
|
-
<DefaultSearch
|
|
1827
|
-
accentColor={resolvedAccentColor}
|
|
1828
|
-
compact
|
|
1829
|
-
storeName={storeName}
|
|
1830
|
-
{...searchProps}
|
|
1831
|
-
filters={autoMode ? resolvedFilters : searchProps?.filters}
|
|
1832
|
-
onChangeFilters={autoMode ? commitFilters : searchProps?.onChangeFilters}
|
|
1833
|
-
value={autoMode ? resolvedSearchValue : searchProps?.value}
|
|
1834
|
-
style={[styles.toolbarSearch, styles.toolbarCompactSearch, searchProps?.style]}
|
|
1835
|
-
/>
|
|
1836
|
-
) : null}
|
|
1837
|
-
{renderToolbarActions()}
|
|
1838
|
-
</View>
|
|
1839
|
-
) : null}
|
|
1840
|
-
|
|
1841
|
-
<View style={shouldRenderCompactToolbarTotalItems ? styles.toolbarCompactActions : styles.toolbarLeft}>
|
|
1842
|
-
{!shouldRenderCompactToolbarTotalItems && searchProps ? (
|
|
1843
|
-
<DefaultSearch
|
|
1844
|
-
accentColor={resolvedAccentColor}
|
|
1845
|
-
compact
|
|
1846
|
-
storeName={storeName}
|
|
1847
|
-
{...searchProps}
|
|
1848
|
-
filters={autoMode ? resolvedFilters : searchProps?.filters}
|
|
1849
|
-
onChangeFilters={autoMode ? commitFilters : searchProps?.onChangeFilters}
|
|
1850
|
-
value={autoMode ? resolvedSearchValue : searchProps?.value}
|
|
1851
|
-
style={[styles.toolbarSearch, searchProps?.style]}
|
|
1852
|
-
/>
|
|
1853
|
-
) : null}
|
|
1854
|
-
{!shouldRenderCompactToolbarTotalItems ? renderToolbarActions() : null}
|
|
1855
|
-
{showColumnFiltersButton ? (
|
|
1856
|
-
<TouchableOpacity
|
|
1857
|
-
style={[
|
|
1858
|
-
styles.toolbarButton,
|
|
1859
|
-
{ borderColor: tableButtonBorderColor, backgroundColor: tableButtonBackgroundColor },
|
|
1860
|
-
showColumnFilters
|
|
1861
|
-
? { backgroundColor: tableButtonPressedBackgroundColor, borderColor: tableButtonPressedBorderColor }
|
|
1862
|
-
: null,
|
|
1863
|
-
]}
|
|
1864
|
-
activeOpacity={0.82}
|
|
1865
|
-
onPress={() => setShowColumnFilters(prev => !prev)}
|
|
1866
|
-
>
|
|
1867
|
-
<Icon
|
|
1868
|
-
name="filter"
|
|
1869
|
-
size={14}
|
|
1870
|
-
color={showColumnFilters ? tableButtonPressedIconColor : tableButtonIconColor}
|
|
1871
|
-
/>
|
|
1872
|
-
{activeFilterCount > 0 ? (
|
|
1873
|
-
<Text
|
|
1874
|
-
style={[
|
|
1875
|
-
styles.toolbarBadgeText,
|
|
1876
|
-
{ color: showColumnFilters ? tableButtonPressedIconColor : tableButtonIconColor },
|
|
1877
|
-
]}>
|
|
1878
|
-
{activeFilterCount}
|
|
1879
|
-
</Text>
|
|
1880
|
-
) : null}
|
|
1881
|
-
</TouchableOpacity>
|
|
1882
|
-
) : null}
|
|
1883
|
-
<TouchableOpacity
|
|
1884
|
-
style={[
|
|
1885
|
-
styles.toolbarButton,
|
|
1886
|
-
{ borderColor: tableButtonBorderColor, backgroundColor: tableButtonBackgroundColor },
|
|
1887
|
-
effectiveViewMode !== 'table'
|
|
1888
|
-
? { backgroundColor: tableButtonPressedBackgroundColor, borderColor: tableButtonPressedBorderColor }
|
|
1889
|
-
: null,
|
|
1890
|
-
]}
|
|
1891
|
-
activeOpacity={0.82}
|
|
1892
|
-
onPress={toggleViewMode}
|
|
1893
|
-
>
|
|
1894
|
-
<Icon
|
|
1895
|
-
name={effectiveViewMode === 'table' ? 'list' : 'grid'}
|
|
1896
|
-
size={14}
|
|
1897
|
-
color={effectiveViewMode !== 'table' ? tableButtonPressedIconColor : tableButtonIconColor}
|
|
1898
|
-
/>
|
|
1899
|
-
</TouchableOpacity>
|
|
1900
|
-
<TouchableOpacity
|
|
1901
|
-
style={[styles.toolbarButton, { borderColor: tableButtonBorderColor, backgroundColor: tableButtonBackgroundColor }]}
|
|
1902
|
-
activeOpacity={0.82}
|
|
1903
|
-
onPress={() => setIsColumnMenuOpen(prev => !prev)}>
|
|
1904
|
-
<Icon name="columns" size={14} color={tableButtonTextColor} />
|
|
1905
|
-
</TouchableOpacity>
|
|
1906
|
-
{shouldRenderAddButton ? (
|
|
1907
|
-
<TouchableOpacity
|
|
1908
|
-
style={[
|
|
1909
|
-
styles.toolbarButton,
|
|
1910
|
-
styles.toolbarAddButton,
|
|
1911
|
-
{ backgroundColor: tableButtonBackgroundColor, borderColor: tableButtonBackgroundColor },
|
|
1912
|
-
]}
|
|
1913
|
-
activeOpacity={0.85}
|
|
1914
|
-
onPress={openAddForm}
|
|
1915
|
-
>
|
|
1916
|
-
<Icon name="plus" size={16} color={tableButtonTextColor} />
|
|
1917
|
-
</TouchableOpacity>
|
|
1918
|
-
) : null}
|
|
1919
|
-
</View>
|
|
1920
|
-
|
|
1921
|
-
</View>
|
|
1922
|
-
|
|
1923
|
-
{effectiveViewMode === 'cards' ? (
|
|
1924
|
-
<FlatList
|
|
1925
|
-
data={sortedData}
|
|
1926
|
-
keyExtractor={getRowKey}
|
|
1927
|
-
renderItem={({ item, index }) => renderCardItem(item, index)}
|
|
1928
|
-
style={styles.cardsScroll}
|
|
1929
|
-
contentContainerStyle={styles.cardsGrid}
|
|
1930
|
-
ListEmptyComponent={renderEmptyState(false)}
|
|
1931
|
-
ListFooterComponent={null}
|
|
1932
|
-
nestedScrollEnabled
|
|
1933
|
-
onMomentumScrollBegin={onMomentumScrollBegin || undefined}
|
|
1934
|
-
onScrollBeginDrag={onScrollBeginDrag || undefined}
|
|
1935
|
-
onEndReached={handleEndReached}
|
|
1936
|
-
onEndReachedThreshold={END_REACHED_THRESHOLD}
|
|
1937
|
-
showsVerticalScrollIndicator={false}
|
|
1938
|
-
/>
|
|
1939
|
-
) : (
|
|
1940
|
-
<ScrollView horizontal style={styles.scroll}>
|
|
1941
|
-
<View style={[styles.content, tableLayoutStyle]}>
|
|
1942
|
-
<View style={[styles.headerRow, tableLayoutStyle, { backgroundColor: tableHeaderColor, borderBottomColor: tableBorderColor }]}>
|
|
1943
|
-
{tableColumns.map(column => {
|
|
1944
|
-
const fieldName = getColumnKey(column);
|
|
1945
|
-
const label = formatStoreColumnLabel({
|
|
1946
|
-
columns: columnsForTable,
|
|
1947
|
-
fieldName,
|
|
1948
|
-
fallbackLabel: column?.label || fieldName,
|
|
1949
|
-
storeName,
|
|
1950
|
-
});
|
|
1951
|
-
|
|
1952
|
-
const sortFieldName = getSortField(column);
|
|
1953
|
-
|
|
1954
|
-
return (
|
|
1955
|
-
<TouchableOpacity
|
|
1956
|
-
key={fieldName}
|
|
1957
|
-
style={getColumnStyle(column)}
|
|
1958
|
-
activeOpacity={isSortableColumn(column) ? 0.8 : 1}
|
|
1959
|
-
onPress={() => requestSort(column)}
|
|
1960
|
-
>
|
|
1961
|
-
<View style={styles.sortableHeader}>
|
|
1962
|
-
<Text style={[styles.headerText, { color: tableTextColor }]} numberOfLines={1}>{label}</Text>
|
|
1963
|
-
{isSortableColumn(column) && resolvedSort?.field === sortFieldName ? (
|
|
1964
|
-
<Icon name={resolvedSort?.direction === 'desc' ? 'chevron-down' : 'chevron-up'} size={12} color={tableTextColor} />
|
|
1965
|
-
) : isSortableColumn(column) ? (
|
|
1966
|
-
<Icon name="chevrons-up" size={12} color={tableBorderColor} />
|
|
1967
|
-
) : null}
|
|
1968
|
-
{resolvedFilters?.[fieldName] ? <Icon name="filter" size={11} color={tableTextColor} /> : null}
|
|
1969
|
-
</View>
|
|
1970
|
-
</TouchableOpacity>
|
|
1971
|
-
);
|
|
1972
|
-
})}
|
|
1973
|
-
{hasRowActions ? (
|
|
1974
|
-
<View style={[styles.cell, styles.actionsCell]}>
|
|
1975
|
-
<Text style={[styles.headerText, { color: tableTextColor }]}>Acoes</Text>
|
|
1976
|
-
</View>
|
|
1977
|
-
) : null}
|
|
1978
|
-
</View>
|
|
1979
|
-
|
|
1980
|
-
{showColumnFiltersButton && showColumnFilters ? (
|
|
1981
|
-
<View style={[styles.filterRow, tableLayoutStyle, { backgroundColor: tableSurfaceColor, borderBottomColor: tableBorderColor }]}>
|
|
1982
|
-
{tableColumns.map(column => (
|
|
1983
|
-
<React.Fragment key={getColumnKey(column)}>
|
|
1984
|
-
{renderColumnFilter(column)}
|
|
1985
|
-
</React.Fragment>
|
|
1986
|
-
))}
|
|
1987
|
-
{hasRowActions ? <View style={[styles.cell, styles.actionsCell]} /> : null}
|
|
1988
|
-
</View>
|
|
1989
|
-
) : null}
|
|
1990
|
-
|
|
1991
|
-
<FlatList
|
|
1992
|
-
data={sortedData}
|
|
1993
|
-
keyExtractor={getRowKey}
|
|
1994
|
-
renderItem={renderTableItem}
|
|
1995
|
-
style={styles.tableList}
|
|
1996
|
-
contentContainerStyle={styles.tableListContent}
|
|
1997
|
-
ListEmptyComponent={renderEmptyState(true)}
|
|
1998
|
-
ListFooterComponent={null}
|
|
1999
|
-
nestedScrollEnabled
|
|
2000
|
-
onMomentumScrollBegin={onMomentumScrollBegin || undefined}
|
|
2001
|
-
onScrollBeginDrag={onScrollBeginDrag || undefined}
|
|
2002
|
-
onEndReached={handleEndReached}
|
|
2003
|
-
onEndReachedThreshold={END_REACHED_THRESHOLD}
|
|
2004
|
-
showsVerticalScrollIndicator={false}
|
|
2005
|
-
/>
|
|
2006
|
-
</View>
|
|
2007
|
-
</ScrollView>
|
|
2008
|
-
)}
|
|
2009
|
-
|
|
2010
|
-
{renderLoadingOverlay()}
|
|
2011
|
-
|
|
2012
|
-
{footerComponent ? (
|
|
2013
|
-
React.isValidElement(footerComponent) ? (
|
|
2014
|
-
footerComponent
|
|
2015
|
-
) : (
|
|
2016
|
-
React.createElement(footerComponent, footerProps)
|
|
2017
|
-
)
|
|
2018
|
-
) : shouldRenderFooterBar ? (
|
|
2019
|
-
<View style={[styles.footerBar, { backgroundColor: tableSurfaceColor, borderTopColor: tableBorderColor }]}>
|
|
2020
|
-
{summaryEntries.length > 0 ? (
|
|
2021
|
-
<View style={styles.footerSummaryList}>
|
|
2022
|
-
{summaryEntries.map(entry => (
|
|
2023
|
-
<View key={entry.key} style={styles.footerSummaryItem}>
|
|
2024
|
-
<Text style={[styles.footerSummaryLabel, { color: tableMutedColor }]} numberOfLines={1}>
|
|
2025
|
-
{entry.label}
|
|
2026
|
-
</Text>
|
|
2027
|
-
<Text
|
|
2028
|
-
style={[
|
|
2029
|
-
styles.footerSummaryValue,
|
|
2030
|
-
entry.path?.[0] === 'sum' || isMoneySummaryPath(entry.path)
|
|
2031
|
-
? { color: resolvedAccentColor }
|
|
2032
|
-
: { color: tableTextColor },
|
|
2033
|
-
]}
|
|
2034
|
-
numberOfLines={1}
|
|
2035
|
-
adjustsFontSizeToFit
|
|
2036
|
-
minimumFontScale={0.78}
|
|
2037
|
-
>
|
|
2038
|
-
{formatSummaryValue({
|
|
2039
|
-
column: entry.column,
|
|
2040
|
-
columns: columnsForTable,
|
|
2041
|
-
path: entry.path,
|
|
2042
|
-
storeName,
|
|
2043
|
-
value: entry.value,
|
|
2044
|
-
})}
|
|
2045
|
-
</Text>
|
|
2046
|
-
</View>
|
|
2047
|
-
))}
|
|
2048
|
-
</View>
|
|
2049
|
-
) : null}
|
|
2050
|
-
{shouldRenderFooterTotalItems && !shouldRenderCompactToolbarTotalItems ? (
|
|
2051
|
-
<View style={[styles.footerCountPill, { backgroundColor: toolbarCountBackgroundColor }]}>
|
|
2052
|
-
<Text
|
|
2053
|
-
style={[styles.footerCountText, { color: toolbarCountTextColor }]}
|
|
2054
|
-
numberOfLines={1}
|
|
2055
|
-
adjustsFontSizeToFit
|
|
2056
|
-
minimumFontScale={0.82}
|
|
2057
|
-
>
|
|
2058
|
-
{resolvedTotalItemsText}
|
|
2059
|
-
</Text>
|
|
2060
|
-
</View>
|
|
2061
|
-
) : null}
|
|
2062
|
-
</View>
|
|
422
|
+
<Icon name="plus" size={24} color={floatingAddIconColor} />
|
|
423
|
+
</TouchableOpacity>
|
|
2063
424
|
) : null}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
};
|
|
2070
|
-
|
|
2071
|
-
export default DefaultTable;
|
|
425
|
+
</View>
|
|
426
|
+
);
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
export default DefaultTable;
|