@controleonline/ui-common 1.2.71 → 1.2.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.github/actions/workers/manager/action.yml +147 -0
  2. package/.github/actions/workers/qa/action.yml +44 -0
  3. package/.github/actions/workers/security/action.yml +44 -0
  4. package/.github/actions/workers/technical-documenter/action.yml +51 -0
  5. package/.github/workflows/manager-worker.yml +168 -0
  6. package/.github/workflows/publish-npm.yml +45 -0
  7. package/.gitmodules +3 -0
  8. package/AGENTS.md +6 -0
  9. package/README.md +14 -0
  10. package/package.json +3 -2
  11. package/src/api/fetch.js +1 -1
  12. package/src/api/index.js +92 -22
  13. package/src/react/components/AddImportModal.js +94 -110
  14. package/src/react/components/BottomNavigationBar.config.js +211 -231
  15. package/src/react/components/CategoryForm.js +52 -35
  16. package/src/react/components/DefaultProvider.native.js +131 -95
  17. package/src/react/components/DefaultProvider.web.js +148 -74
  18. package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
  19. package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
  20. package/src/react/components/RuntimeInfoFooter.js +164 -104
  21. package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
  22. package/src/react/components/UnifiedPaymentBar.js +7 -4
  23. package/src/react/components/UserAvatar.js +160 -0
  24. package/src/react/components/integrations/IntegrationHero/index.js +48 -0
  25. package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
  26. package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
  27. package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
  28. package/src/react/config/deviceConfigBootstrap.js +5 -3
  29. package/src/react/pages/Connections.js +229 -0
  30. package/src/react/pages/Connections.styles.js +222 -0
  31. package/src/react/pages/DeviceDetailPage.js +2865 -0
  32. package/src/react/pages/DeviceDetailPage.styles.js +308 -0
  33. package/src/react/pages/Devices/currentDevice.js +194 -0
  34. package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
  35. package/src/react/pages/Devices/deviceTypes/all.js +23 -0
  36. package/src/react/pages/Devices/deviceTypes/device.js +25 -0
  37. package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
  38. package/src/react/pages/Devices/deviceTypes/display.js +26 -0
  39. package/src/react/pages/Devices/deviceTypes/index.js +145 -0
  40. package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
  41. package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
  42. package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
  43. package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
  44. package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
  45. package/src/react/pages/Devices.js +183 -0
  46. package/src/react/pages/Devices.styles.js +353 -0
  47. package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
  48. package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
  49. package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
  50. package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
  51. package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
  52. package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
  53. package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
  54. package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
  55. package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
  56. package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
  57. package/src/react/pages/Food99IntegrationPage.js +1 -0
  58. package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
  59. package/src/react/pages/GenericLogPage.js +42 -167
  60. package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
  61. package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
  62. package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
  63. package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
  64. package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
  65. package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
  66. package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
  67. package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
  68. package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
  69. package/src/react/pages/IFoodIntegrationPage.js +1 -0
  70. package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
  71. package/src/react/pages/Imports.js +214 -166
  72. package/src/react/pages/IntegrationConfigPage.js +744 -0
  73. package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
  74. package/src/react/pages/Integrations.js +299 -0
  75. package/src/react/pages/Integrations.styles.js +130 -0
  76. package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
  77. package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
  78. package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
  79. package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
  80. package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
  81. package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
  82. package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
  83. package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
  84. package/src/react/pages/PrinterDeviceFormPage.js +521 -0
  85. package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
  86. package/src/react/pages/WhatsAppConnectionPage.js +459 -0
  87. package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
  88. package/src/react/pages/integrationsCatalog.js +399 -0
  89. package/src/react/services/Cielo/Cielo.js +193 -193
  90. package/src/react/utils/categoryContexts.js +46 -0
  91. package/src/react/utils/entityDisplay.js +222 -217
  92. package/src/react/utils/fileUrl.js +39 -20
  93. package/src/react/utils/integrationPage.js +16 -0
  94. package/src/react/utils/runtimeFooter.js +40 -22
  95. package/src/react/utils/runtimeLanguage.js +50 -9
  96. package/src/react/utils/runtimeMenu.js +191 -131
  97. package/src/react/utils/runtimeZoom.js +43 -0
  98. package/src/react/utils/shopConfig.js +27 -15
  99. package/src/react/utils/shopFranchises.js +126 -1
  100. package/src/react/utils/storeColumns.js +23 -4
  101. package/src/react/utils/userAvatar.js +104 -0
  102. package/src/store/categories/index.js +48 -20
  103. package/src/store/device_config/index.js +62 -21
  104. package/src/store/entity_log/index.js +22 -1
  105. package/src/store/imports/customActions.js +51 -0
  106. package/src/store/imports/index.js +89 -88
  107. package/src/store/status/index.js +11 -11
  108. package/src/store/themes/index.js +22 -0
  109. package/src/store/timezones/index.js +3 -1
  110. package/src/tests/browser/manager/connections.spec.js +143 -0
  111. package/src/tests/browser/manager/devices-current.spec.js +343 -0
  112. package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
  113. package/src/tests/react/api/deviceHeaders.test.js +114 -0
  114. package/src/tests/react/components/AddImportModal.test.js +166 -0
  115. package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
  116. package/src/tests/react/components/UserAvatar.test.js +52 -0
  117. package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
  118. package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
  119. package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
  120. package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
  121. package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
  122. package/src/tests/react/services/Cielo.test.js +190 -190
  123. package/src/tests/react/store/categoriesOrdering.test.js +26 -0
  124. package/src/tests/react/utils/appDomain.test.js +62 -0
  125. package/src/tests/react/utils/entityDisplay.test.js +2 -2
  126. package/src/tests/react/utils/fileUrl.test.js +3 -3
  127. package/src/tests/react/utils/formatter.test.mjs +33 -0
  128. package/src/tests/react/utils/runtimeFooter.test.js +29 -4
  129. package/src/tests/react/utils/runtimeLanguage.test.js +79 -9
  130. package/src/tests/react/utils/runtimeMenu.test.js +198 -134
  131. package/src/tests/react/utils/runtimeZoom.test.js +38 -0
  132. package/src/tests/react/utils/shopConfig.test.js +10 -9
  133. package/src/tests/react/utils/shopFranchises.test.js +43 -0
  134. package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
  135. package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
  136. package/src/tests/react/utils/translate.test.mjs +141 -349
  137. package/src/tests/react/utils/userAvatar.test.js +63 -0
  138. package/src/utils/appDomain.js +15 -4
  139. package/src/utils/formatter.js +104 -16
  140. package/src/utils/integrationConfigs.js +80 -80
  141. package/src/utils/translate.js +222 -438
  142. package/src/utils/translateDiscovery.js +96 -0
  143. package/src/utils/translateNormalize.js +33 -0
  144. package/src/utils/translatePending.js +92 -0
  145. package/src/utils/translateStorage.js +142 -0
  146. package/.github/agents/developer.agent.md +0 -30
  147. package/.github/agents/devops.agent.md +0 -30
  148. package/.github/agents/qa.agent.md +0 -30
  149. package/.github/agents/security.agent.md +0 -30
  150. package/.github/workflows/npmjs.yml +0 -35
@@ -0,0 +1,155 @@
1
+ // Configurações fixas e helpers específicos da integração 99Food.
2
+ export const MINIMUM_REQUIRED_ITEMS = 5;
3
+
4
+ export const statusLabelMap = {
5
+ 1: 'Online',
6
+ 2: 'Offline',
7
+ };
8
+
9
+ export const subStatusLabelMap = {
10
+ 1: 'Pronta',
11
+ 2: 'Pausada',
12
+ 3: 'Fechada',
13
+ };
14
+
15
+ export const filterTabs = [
16
+ { key: 'all', label: 'Todos' },
17
+ { key: 'eligible', label: 'Elegiveis' },
18
+ { key: 'selected', label: 'Selecionados' },
19
+ { key: 'blocked', label: 'Com bloqueio' },
20
+ ];
21
+
22
+ export const publishStateLabelMap = {
23
+ submitted: 'Enviado',
24
+ processing: 'Processando',
25
+ published: 'Publicado',
26
+ failed: 'Falhou',
27
+ sync_error: 'Sync pendente',
28
+ };
29
+
30
+ export const publishStateToneMap = {
31
+ submitted: '#2563EB',
32
+ processing: '#e67e22',
33
+ published: '#16A34A',
34
+ failed: '#DC2626',
35
+ sync_error: '#7C3AED',
36
+ };
37
+
38
+ export const deliveryMethodOptions = [
39
+ { value: '2', label: 'Loja (2)' },
40
+ { value: '1', label: 'Entrega 99 (1)' },
41
+ ];
42
+
43
+ export const formatFood99ApiError = error => {
44
+ if (!error) return 'Nao foi possivel concluir a operacao.';
45
+ if (typeof error === 'string') return error;
46
+
47
+ if (Array.isArray(error?.message)) {
48
+ return error.message
49
+ .map(item => item?.message || item?.title || String(item))
50
+ .filter(Boolean)
51
+ .join('\n');
52
+ }
53
+
54
+ return error?.message || error?.description || error?.errmsg || 'Nao foi possivel concluir a operacao.';
55
+ };
56
+
57
+ export const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
58
+
59
+ export const normalizeTaskId = value => {
60
+ if (value === null || value === undefined || value === '') return null;
61
+ return String(value);
62
+ };
63
+
64
+ export const resolveFood99HistoryFromTime = () => {
65
+ try {
66
+ const parts = new Intl.DateTimeFormat('en-CA', {
67
+ timeZone: 'America/Sao_Paulo',
68
+ year: 'numeric',
69
+ month: '2-digit',
70
+ day: '2-digit',
71
+ })
72
+ .formatToParts(new Date())
73
+ .reduce((accumulator, part) => {
74
+ if (part.type !== 'literal') {
75
+ accumulator[part.type] = part.value;
76
+ }
77
+
78
+ return accumulator;
79
+ }, {});
80
+
81
+ if (!parts.year || !parts.month || !parts.day) {
82
+ return null;
83
+ }
84
+
85
+ return `${parts.year}-${parts.month}-${parts.day}T00:00:00-03:00`;
86
+ } catch {
87
+ return null;
88
+ }
89
+ };
90
+
91
+ export const sanitizeTimeInput = value => {
92
+ const digits = String(value || '')
93
+ .replace(/\D/g, '')
94
+ .slice(0, 4);
95
+
96
+ if (digits.length <= 2) return digits;
97
+ return `${digits.slice(0, 2)}:${digits.slice(2)}`;
98
+ };
99
+
100
+ export const isValidTimeInput = value => /^([01]\d|2[0-3]):[0-5]\d$/.test(String(value || '').trim());
101
+
102
+ export const sanitizeRadiusInput = value => {
103
+ const normalized = String(value || '').replace(/[^0-9.,]/g, '').replace(',', '.');
104
+ const [integerPart, ...decimals] = normalized.split('.');
105
+ if (decimals.length === 0) return integerPart;
106
+ return `${integerPart}.${decimals.join('').slice(0, 2)}`;
107
+ };
108
+
109
+ export const sanitizeConfirmMethodInput = value =>
110
+ String(value || '')
111
+ .replace(/\D/g, '')
112
+ .slice(0, 3);
113
+
114
+ export const normalizeDeliveryMethodCode = value => {
115
+ const normalized = String(value || '').trim();
116
+ if (normalized === '1' || normalized === '2') return normalized;
117
+
118
+ const lower = normalized.toLowerCase();
119
+ if (lower.includes('99') || lower.includes('platform') || lower.includes('didi')) return '1';
120
+
121
+ if (
122
+ lower.includes('store') ||
123
+ lower.includes('shop') ||
124
+ lower.includes('merchant') ||
125
+ lower.includes('self') ||
126
+ lower.includes('loja')
127
+ ) {
128
+ return '2';
129
+ }
130
+
131
+ return '';
132
+ };
133
+
134
+ export const formatDeliveryMethodLabel = value => {
135
+ const code = normalizeDeliveryMethodCode(value);
136
+ if (code === '2') return 'Loja';
137
+ if (code === '1') return 'Entrega 99';
138
+
139
+ const raw = String(value || '').trim();
140
+ return raw || '-';
141
+ };
142
+
143
+ export const getPublishStateLabel = state => publishStateLabelMap[state] || 'Sem envio recente';
144
+
145
+ export const createEmptyStoreSettingsDraft = () => ({
146
+ deliveryRadiusKm: '',
147
+ openTime: '',
148
+ closeTime: '',
149
+ deliveryMethod: '',
150
+ confirmMethod: '',
151
+ deliveryAreaId: '',
152
+ settlementWalletId: '',
153
+ });
154
+
155
+ export const isErrnoSuccess = errno => String(errno ?? '').trim() === '0';
@@ -0,0 +1 @@
1
+ export { default } from './Food99IntegrationPage/index';
@@ -0,0 +1 @@
1
+ export { default } from './Food99IntegrationPage/styles';
@@ -3,7 +3,6 @@ import {
3
3
  ActivityIndicator,
4
4
  ScrollView,
5
5
  Text,
6
- TextInput,
7
6
  TouchableOpacity,
8
7
  View,
9
8
  } from 'react-native';
@@ -11,8 +10,7 @@ import {SafeAreaView} from 'react-native-safe-area-context';
11
10
  import {useFocusEffect} from '@react-navigation/native';
12
11
  import Icon from 'react-native-vector-icons/MaterialIcons';
13
12
  import {useStore} from '@store';
14
- import CompactFilterSelector from '@controleonline/ui-default/src/react/components/filters/CompactFilterSelector';
15
- import DateShortcutFilter from '@controleonline/ui-default/src/react/components/filters/DateShortcutFilter';
13
+ import DefaultExternalFilters from '@controleonline/ui-default/src/react/components/filters/DefaultExternalFilters';
16
14
  import EntityLogContent from '@controleonline/ui-common/src/react/components/EntityLogContent';
17
15
  import Formatter from '@controleonline/ui-common/src/utils/formatter';
18
16
  import {resolveStoreConfigByClassName} from '@controleonline/ui-common/src/react/utils/storeColumns';
@@ -185,41 +183,14 @@ const buildTypeOptions = items => {
185
183
  });
186
184
 
187
185
  return [
188
- {key: 'all', label: 'Todos'},
186
+ {value: '', label: 'Todos'},
189
187
  ...Array.from(typeKeys).map(key => ({
190
- key,
188
+ value: key,
191
189
  label: getTypeMeta(key).label,
192
190
  })),
193
191
  ];
194
192
  };
195
193
 
196
- const buildQuickClassOptions = items => {
197
- const counts = new Map();
198
-
199
- items.forEach(log => {
200
- if (normalizeFilterKey(log?.type) !== 'entity' || !normalizeText(log?.class)) {
201
- return;
202
- }
203
-
204
- const key = getShortClassName(log.class);
205
- counts.set(key, (counts.get(key) || 0) + 1);
206
- });
207
-
208
- return Array.from(counts.entries())
209
- .sort((left, right) => {
210
- if (right[1] !== left[1]) {
211
- return right[1] - left[1];
212
- }
213
-
214
- return left[0].localeCompare(right[0], 'pt-BR');
215
- })
216
- .slice(0, 12)
217
- .map(([value]) => ({
218
- label: formatClassLabel(value),
219
- value,
220
- }));
221
- };
222
-
223
194
  function MetaBadge({meta, styles}) {
224
195
  return (
225
196
  <View
@@ -420,20 +391,18 @@ export default function GenericLogPage({navigation}) {
420
391
  status: 'idle',
421
392
  totalItems: 0,
422
393
  });
423
- const [selectedType, setSelectedType] = useState('all');
424
- const [dateFilterKey, setDateFilterKey] = useState('all');
425
- const [customRange, setCustomRange] = useState({
426
- from: '',
427
- to: '',
428
- });
429
- const [classFilterInput, setClassFilterInput] = useState('');
430
- const [appliedClassFilter, setAppliedClassFilter] = useState('');
394
+ const [filters, setFilters] = useState({});
431
395
  const [expandedEntityKey, setExpandedEntityKey] = useState('');
432
396
 
433
397
  const loadLogs = useCallback(async () => {
434
- const {after, before} = getDateRange(dateFilterKey, customRange, {
398
+ const dateFilter = filters.createdAt || {};
399
+ const {after, before} = getDateRange(
400
+ dateFilter.shortcut || dateFilter.value || 'all',
401
+ dateFilter.customRange || {from: '', to: ''},
402
+ {
435
403
  useCurrentMoment: true,
436
- });
404
+ },
405
+ );
437
406
 
438
407
  setLogsState(current => ({
439
408
  ...current,
@@ -443,10 +412,10 @@ export default function GenericLogPage({navigation}) {
443
412
 
444
413
  try {
445
414
  const response = await entityLogActions.getTimeline({
446
- ...(selectedType !== 'all' ? {type: selectedType} : {}),
415
+ ...(filters.type ? {type: filters.type} : {}),
447
416
  ...(after ? {'createdAt[after]': after} : {}),
448
417
  ...(before ? {'createdAt[before]': before} : {}),
449
- ...(appliedClassFilter ? {class: appliedClassFilter} : {}),
418
+ ...(filters.class ? {class: filters.class} : {}),
450
419
  });
451
420
 
452
421
  const items = Array.isArray(response?.items) ? response.items : [];
@@ -464,29 +433,31 @@ export default function GenericLogPage({navigation}) {
464
433
  totalItems: 0,
465
434
  });
466
435
  }
467
- }, [appliedClassFilter, customRange, dateFilterKey, entityLogActions, selectedType]);
436
+ }, [entityLogActions, filters]);
468
437
 
469
438
  const typeOptions = useMemo(
470
439
  () => buildTypeOptions(logsState.items),
471
440
  [logsState.items],
472
441
  );
473
442
 
474
- const quickClassOptions = useMemo(
475
- () => buildQuickClassOptions(logsState.items),
476
- [logsState.items],
477
- );
478
-
479
443
  const activeDateSummary = useMemo(
480
- () => resolveDateRangeSummary(dateFilterKey, customRange, {useCurrentMoment: true}),
481
- [customRange, dateFilterKey],
444
+ () => {
445
+ const dateFilter = filters.createdAt || {};
446
+ return resolveDateRangeSummary(
447
+ dateFilter.shortcut || dateFilter.value || 'all',
448
+ dateFilter.customRange || {from: '', to: ''},
449
+ {useCurrentMoment: true},
450
+ );
451
+ },
452
+ [filters.createdAt],
482
453
  );
483
454
 
484
455
  const hasActiveFilters = useMemo(
485
456
  () =>
486
- selectedType !== 'all' ||
487
- Boolean(appliedClassFilter) ||
457
+ Boolean(filters.type) ||
458
+ Boolean(filters.class) ||
488
459
  Boolean(activeDateSummary),
489
- [activeDateSummary, appliedClassFilter, selectedType],
460
+ [activeDateSummary, filters.class, filters.type],
490
461
  );
491
462
 
492
463
  const resultsSummary = useMemo(() => {
@@ -503,30 +474,13 @@ export default function GenericLogPage({navigation}) {
503
474
 
504
475
  return `${countLabel} no periodo ${activeDateSummary}`;
505
476
  }, [activeDateSummary, logsState.items.length, logsState.totalItems]);
506
- const selectedTypeLabel = useMemo(
507
- () => typeOptions.find(option => option.key === selectedType)?.label || 'Todos',
508
- [selectedType, typeOptions],
477
+ const getExternalFilterOptions = useCallback(
478
+ column => ((column?.name || column?.key) === 'type' ? typeOptions : []),
479
+ [typeOptions],
509
480
  );
510
- const selectedQuickClassLabel = useMemo(() => {
511
- if (!appliedClassFilter) {
512
- return 'Sugestoes';
513
- }
514
-
515
- return quickClassOptions.find(
516
- option => normalizeFilterKey(option.value) === normalizeFilterKey(appliedClassFilter),
517
- )?.label || formatClassLabel(appliedClassFilter);
518
- }, [appliedClassFilter, quickClassOptions]);
519
-
520
- const applyClassFilter = useCallback(() => {
521
- setAppliedClassFilter(normalizeText(classFilterInput));
522
- }, [classFilterInput]);
523
481
 
524
482
  const clearAllFilters = useCallback(() => {
525
- setSelectedType('all');
526
- setDateFilterKey('all');
527
- setCustomRange({from: '', to: ''});
528
- setClassFilterInput('');
529
- setAppliedClassFilter('');
483
+ setFilters({});
530
484
  setExpandedEntityKey('');
531
485
  }, []);
532
486
 
@@ -548,7 +502,7 @@ export default function GenericLogPage({navigation}) {
548
502
 
549
503
  useEffect(() => {
550
504
  setExpandedEntityKey('');
551
- }, [appliedClassFilter, dateFilterKey, logsState.items, selectedType]);
505
+ }, [filters, logsState.items]);
552
506
 
553
507
  useFocusEffect(
554
508
  useCallback(() => {
@@ -602,96 +556,17 @@ export default function GenericLogPage({navigation}) {
602
556
  ) : null}
603
557
  </View>
604
558
 
605
- <View style={styles.filterGroup}>
606
- <Text style={styles.filterLabel}>Periodo</Text>
607
- <DateShortcutFilter
608
- value={dateFilterKey}
609
- onChange={setDateFilterKey}
610
- customRange={customRange}
611
- onCustomRangeChange={setCustomRange}
612
- colors={{
613
- accent: '#2563EB',
614
- appBg: 'transparent',
615
- border: '#CBD5E1',
616
- borderSoft: '#E2E8F0',
617
- cardBg: '#FFFFFF',
618
- cardBgSoft: '#F8FAFC',
619
- danger: '#DC2626',
620
- isLight: true,
621
- panelBg: '#EFF6FF',
622
- pillTextDark: '#FFFFFF',
623
- textPrimary: '#0F172A',
624
- textSecondary: '#64748B',
625
- }}
626
- />
627
-
628
- {!!activeDateSummary && (
629
- <Text style={styles.filterHint}>Periodo atual: {activeDateSummary}</Text>
630
- )}
631
- </View>
632
-
633
- <View style={styles.filterGroup}>
634
- <Text style={styles.filterLabel}>Tipo de log</Text>
635
- <CompactFilterSelector
636
- icon="filter"
637
- label={selectedTypeLabel}
638
- title="Tipo de log"
639
- accentColor="#2563EB"
640
- active={selectedType !== 'all'}
641
- options={typeOptions}
642
- selectedKey={selectedType}
643
- onSelect={optionKey => {
644
- setSelectedType(optionKey);
645
- return true;
646
- }}
647
- />
648
- </View>
649
-
650
- <View style={styles.filterGroup}>
651
- <Text style={styles.filterLabel}>Classe / origem</Text>
652
- <View style={styles.textFilterRow}>
653
- <TextInput
654
- value={classFilterInput}
655
- onChangeText={setClassFilterInput}
656
- placeholder="Ex.: Integration, Device, execute_operation"
657
- placeholderTextColor="#94A3B8"
658
- autoCapitalize="none"
659
- autoCorrect={false}
660
- style={styles.textFilterInput}
661
- />
662
-
663
- <TouchableOpacity
664
- activeOpacity={0.9}
665
- onPress={applyClassFilter}
666
- style={styles.primaryButton}>
667
- <Text style={styles.primaryButtonText}>Aplicar</Text>
668
- </TouchableOpacity>
669
- </View>
670
-
671
- {!!appliedClassFilter && (
672
- <Text style={styles.filterHint}>Classe aplicada: {appliedClassFilter}</Text>
673
- )}
674
-
675
- {!!quickClassOptions.length && (
676
- <CompactFilterSelector
677
- icon="layers"
678
- label={selectedQuickClassLabel}
679
- title="Sugestoes de classe"
680
- accentColor="#2563EB"
681
- active={Boolean(appliedClassFilter)}
682
- options={quickClassOptions.map(option => ({
683
- key: option.value,
684
- label: option.label,
685
- }))}
686
- selectedKey={appliedClassFilter}
687
- onSelect={optionKey => {
688
- setClassFilterInput(optionKey);
689
- setAppliedClassFilter(optionKey);
690
- return true;
691
- }}
692
- />
693
- )}
694
- </View>
559
+ <DefaultExternalFilters
560
+ accentColor="#2563EB"
561
+ filters={filters}
562
+ getOptionsForColumn={getExternalFilterOptions}
563
+ onChangeFilters={setFilters}
564
+ storeName="entity_log"
565
+ />
566
+
567
+ {!!activeDateSummary && (
568
+ <Text style={styles.filterHint}>Periodo atual: {activeDateSummary}</Text>
569
+ )}
695
570
  </View>
696
571
 
697
572
  {logsState.status === 'loading' ? (
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ import Food99CatalogTab from '../../Food99IntegrationPage/components/Food99CatalogTab';
4
+
5
+ // Aba de cardápio do iFood, renderizada pelo mesmo componente compartilhado.
6
+ export default function IFoodCatalogTab(props) {
7
+ return <Food99CatalogTab {...props} providerKey="ifood" />;
8
+ }