@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,88 @@
1
+ import {PDV_DEVICE_TYPE, normalizeDeviceType} from '@controleonline/ui-common/src/react/utils/printerDevices';
2
+ import {
3
+ getPaymentGateway,
4
+ PAYMENT_GATEWAY_CIELO,
5
+ PAYMENT_GATEWAY_INFINITE_PAY,
6
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
7
+ import {createDeviceTypeTab} from './shared';
8
+
9
+ const emptyState = {
10
+ icon: 'shopping-bag',
11
+ title: 'Nenhum pdv encontrado',
12
+ description: 'A empresa ativa ainda nao possui devices cadastrados neste filtro.',
13
+ };
14
+
15
+ export const PDV_CIELO_FILTER = 'PDV_CIELO';
16
+ export const PDV_INFINITE_PAY_FILTER = 'PDV_INFINITE_PAY';
17
+ export const PDV_SUBFILTER_KEYS = [
18
+ PDV_CIELO_FILTER,
19
+ PDV_INFINITE_PAY_FILTER,
20
+ ];
21
+
22
+ const pdvDeviceType = {
23
+ key: PDV_DEVICE_TYPE,
24
+ label: 'PDVs',
25
+ itemLabel: 'PDV',
26
+ icon: 'shopping-bag',
27
+ matches: type => normalizeDeviceType(type) === PDV_DEVICE_TYPE,
28
+ shouldDisplay: () => true,
29
+ getAccent: ({hex}) => hex.success,
30
+ getEmptyState: () => emptyState,
31
+ TabComponent: createDeviceTypeTab({
32
+ label: 'PDVs',
33
+ queryTypes: [PDV_DEVICE_TYPE],
34
+ emptyState,
35
+ offerCurrentPdvSetup: true,
36
+ }),
37
+ };
38
+
39
+ const createPdvGatewayDeviceType = ({
40
+ key,
41
+ label,
42
+ gateway,
43
+ title,
44
+ accentResolver,
45
+ }) => {
46
+ const gatewayEmptyState = {
47
+ icon: 'shopping-bag',
48
+ title,
49
+ description:
50
+ 'A empresa ativa ainda nao possui devices cadastrados neste filtro.',
51
+ };
52
+
53
+ return {
54
+ key,
55
+ label,
56
+ itemLabel: 'PDV',
57
+ icon: 'shopping-bag',
58
+ matches: () => false,
59
+ shouldDisplay: () => true,
60
+ getAccent: accentResolver,
61
+ getEmptyState: () => gatewayEmptyState,
62
+ TabComponent: createDeviceTypeTab({
63
+ label,
64
+ pageSize: 200,
65
+ queryTypes: [PDV_DEVICE_TYPE],
66
+ emptyState: gatewayEmptyState,
67
+ clientFilter: deviceConfig => getPaymentGateway(deviceConfig) === gateway,
68
+ }),
69
+ };
70
+ };
71
+
72
+ export const pdvCieloDeviceType = createPdvGatewayDeviceType({
73
+ key: PDV_CIELO_FILTER,
74
+ label: 'Cielo',
75
+ gateway: PAYMENT_GATEWAY_CIELO,
76
+ title: 'Nenhum pdv Cielo encontrado',
77
+ accentResolver: ({hex, brandColors}) => brandColors?.primary || hex.primary,
78
+ });
79
+
80
+ export const pdvInfinitePayDeviceType = createPdvGatewayDeviceType({
81
+ key: PDV_INFINITE_PAY_FILTER,
82
+ label: 'Infinite Pay',
83
+ gateway: PAYMENT_GATEWAY_INFINITE_PAY,
84
+ title: 'Nenhum pdv Infinite Pay encontrado',
85
+ accentResolver: ({brandColors, hex}) => brandColors?.primary || hex.success,
86
+ });
87
+
88
+ export default pdvDeviceType;
@@ -0,0 +1,37 @@
1
+ import {getNetworkDeviceProfile} from '@controleonline/ui-common/src/react/utils/networkDeviceProfiles';
2
+ import {
3
+ isPrinterDeviceType,
4
+ normalizeDeviceType,
5
+ PRINT_DEVICE_TYPE,
6
+ PRINTER_DEVICE_TYPE,
7
+ } from '@controleonline/ui-common/src/react/utils/printerDevices';
8
+ import {createDeviceTypeTab} from './shared';
9
+
10
+ const printerProfile = getNetworkDeviceProfile('PRINT');
11
+ const emptyState = {
12
+ icon: printerProfile.icon,
13
+ title: printerProfile.emptyTitle,
14
+ description: printerProfile.emptyDescription,
15
+ };
16
+
17
+ const printerDeviceType = {
18
+ key: printerProfile.filterKey,
19
+ label: printerProfile.filterLabel,
20
+ itemLabel: printerProfile.itemLabel,
21
+ icon: printerProfile.icon,
22
+ matches: type => isPrinterDeviceType(normalizeDeviceType(type)),
23
+ shouldDisplay: () => true,
24
+ getAccent: ({brandColors, hex}) => brandColors?.primary || hex.primary,
25
+ getEmptyState: () => emptyState,
26
+ detailRouteName: printerProfile.detailRouteName,
27
+ createRouteName: printerProfile.formRouteName,
28
+ createActionLabel: printerProfile.createActionLabel,
29
+ createHelperText: printerProfile.createHelperText,
30
+ TabComponent: createDeviceTypeTab({
31
+ label: printerProfile.filterLabel,
32
+ queryTypes: [PRINT_DEVICE_TYPE, PRINTER_DEVICE_TYPE],
33
+ emptyState,
34
+ }),
35
+ };
36
+
37
+ export default printerDeviceType;
@@ -0,0 +1,453 @@
1
+ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
2
+ import {
3
+ ActivityIndicator,
4
+ Text,
5
+ TouchableOpacity,
6
+ View,
7
+ } from 'react-native';
8
+ import {useFocusEffect, useNavigation} from '@react-navigation/native';
9
+ import {useStore} from '@store';
10
+ import {app_type} from '@appType';
11
+ import {
12
+ buildProviderManagedDeviceConfigs,
13
+ parseConfigsObject,
14
+ } from '@controleonline/ui-common/src/react/config/deviceConfigBootstrap';
15
+ import {
16
+ getDeviceConfigType,
17
+ isManagedNetworkDeviceType,
18
+ normalizeDeviceType,
19
+ PDV_DEVICE_TYPE,
20
+ } from '@controleonline/ui-common/src/react/utils/printerDevices';
21
+ import {
22
+ normalizeDeviceId,
23
+ normalizeEntityId,
24
+ } from '@controleonline/ui-common/src/react/utils/paymentDevices';
25
+ import {resolveOperationalDeviceType} from '@controleonline/ui-common/src/react/utils/deviceRuntime';
26
+ import {resolveThemePalette, withOpacity} from '@controleonline/../../src/styles/branding';
27
+ import {colors} from '@controleonline/../../src/styles/colors';
28
+ import Icon from 'react-native-vector-icons/Feather';
29
+ import DefaultTable from '@controleonline/ui-default/src/react/components/table/DefaultTable';
30
+ import {
31
+ findDeviceConfigByType,
32
+ getRuntimeDeviceIdentifier,
33
+ groupDeviceConfigs,
34
+ hasCurrentPdvConfig,
35
+ isCurrentDeviceGroup,
36
+ prioritizeCurrentDeviceGroups,
37
+ readStoredRuntimeDevice,
38
+ } from '../currentDevice';
39
+ import styles from '../../Devices.styles';
40
+ import DeviceGroupCard from './DeviceGroupCard';
41
+ import {useDeviceNetworkConnectivity} from './useDeviceNetworkConnectivity';
42
+ import {
43
+ PAGE_SIZE,
44
+ API_PAGE_SIZE,
45
+ tt,
46
+ hex,
47
+ mergeDeviceConfigs,
48
+ isPosDeviceOpen,
49
+ getPrinterConnectivityMeta,
50
+ getDeviceIconName,
51
+ getDeviceItemTypeLabel,
52
+ getDeviceBadgeLabel,
53
+ getDeviceTypeAccent,
54
+ getPosStatusLabel,
55
+ getPosOperationModeLabel,
56
+ getDeviceDetailRoute,
57
+ getDeviceListIdentifier,
58
+ buildDeviceListParams,
59
+ isPdvPrinterEnabled,
60
+ } from './deviceListHelpers';
61
+
62
+ const deviceTableColumns = [
63
+ {
64
+ name: 'key',
65
+ label: 'id',
66
+ isIdentity: true,
67
+ sortable: false,
68
+ format: value => value,
69
+ },
70
+ {
71
+ name: 'alias',
72
+ label: 'device',
73
+ sortable: true,
74
+ format: value => value || '',
75
+ },
76
+ {
77
+ name: 'typeLabel',
78
+ label: 'type',
79
+ sortable: true,
80
+ format: value => value || '',
81
+ },
82
+ ];
83
+
84
+ export const createDeviceTypeTab = ({
85
+ label,
86
+ pageSize = PAGE_SIZE,
87
+ queryTypes = [],
88
+ emptyState,
89
+ clientFilter = null,
90
+ offerCurrentPdvSetup = false,
91
+ }) => {
92
+ const DeviceTypeTab = () => {
93
+ const navigation = useNavigation();
94
+ const peopleStore = useStore('people');
95
+ const deviceStore = useStore('device');
96
+ const deviceConfigStore = useStore('device_config');
97
+ const themeStore = useStore('theme');
98
+
99
+ const {currentCompany} = peopleStore.getters;
100
+ const {colors: themeColors} = themeStore.getters;
101
+
102
+ const brandColors = useMemo(
103
+ () =>
104
+ resolveThemePalette(
105
+ {...themeColors, ...(currentCompany?.theme?.colors || {})},
106
+ colors,
107
+ ),
108
+ [themeColors, currentCompany?.id],
109
+ );
110
+
111
+ const [deviceConfigs, setDeviceConfigs] = useState([]);
112
+ const [loading, setLoading] = useState(false);
113
+ const [refreshing, setRefreshing] = useState(false);
114
+ const [error, setError] = useState('');
115
+ const [creatingPdv, setCreatingPdv] = useState(false);
116
+ const [runtimeDevice, setRuntimeDevice] = useState(() =>
117
+ readStoredRuntimeDevice(),
118
+ );
119
+ const networkConnectivityByDevice = useDeviceNetworkConnectivity(deviceConfigs);
120
+
121
+ const fetchingRef = useRef(false);
122
+ const companyId = String(currentCompany?.id || '').trim();
123
+ const runtimeDeviceIdentifier =
124
+ getRuntimeDeviceIdentifier(runtimeDevice);
125
+ const runtimeDeviceType = normalizeDeviceType(
126
+ resolveOperationalDeviceType({
127
+ appType: app_type,
128
+ deviceInfo: runtimeDevice,
129
+ }),
130
+ );
131
+ const filteredDeviceConfigs = useMemo(() => {
132
+ if (typeof clientFilter !== 'function') {
133
+ return deviceConfigs;
134
+ }
135
+
136
+ return (Array.isArray(deviceConfigs) ? deviceConfigs : []).filter(
137
+ deviceConfig => clientFilter(deviceConfig),
138
+ );
139
+ }, [clientFilter, deviceConfigs]);
140
+ const visibleDeviceGroups = useMemo(() => {
141
+ const groups = prioritizeCurrentDeviceGroups(
142
+ groupDeviceConfigs(filteredDeviceConfigs, {
143
+ includeRuntimeDevice: offerCurrentPdvSetup,
144
+ runtimeDevice,
145
+ }),
146
+ runtimeDeviceIdentifier,
147
+ );
148
+ return (Array.isArray(groups) ? groups : []).map(group => {
149
+ const primary = group?.deviceConfigs?.[0];
150
+ const type = primary
151
+ ? getDeviceConfigType(primary)
152
+ : runtimeDeviceType || 'DEVICE';
153
+ return {
154
+ ...group,
155
+ id: group?.key || group?.device?.id || group?.device?.device,
156
+ alias:
157
+ group?.device?.alias ||
158
+ group?.device?.device ||
159
+ primary?.device?.alias ||
160
+ 'Dispositivo',
161
+ typeLabel: getDeviceItemTypeLabel(type),
162
+ primaryConfig: primary,
163
+ };
164
+ });
165
+ }, [
166
+ filteredDeviceConfigs,
167
+ offerCurrentPdvSetup,
168
+ runtimeDevice,
169
+ runtimeDeviceIdentifier,
170
+ runtimeDeviceType,
171
+ ]);
172
+ const currentDeviceGroup = useMemo(
173
+ () =>
174
+ visibleDeviceGroups.find(deviceGroup =>
175
+ isCurrentDeviceGroup({
176
+ deviceGroup,
177
+ runtimeDeviceIdentifier,
178
+ }),
179
+ ) || null,
180
+ [runtimeDeviceIdentifier, visibleDeviceGroups],
181
+ );
182
+ const currentDeviceConfigs = currentDeviceGroup?.deviceConfigs || [];
183
+
184
+ const fetchDeviceConfigs = useCallback(
185
+ async (mode = 'loading') => {
186
+ if (!companyId || fetchingRef.current) {
187
+ if (!companyId) {
188
+ setDeviceConfigs([]);
189
+ setError('');
190
+ setLoading(false);
191
+ setRefreshing(false);
192
+ }
193
+ return;
194
+ }
195
+
196
+ fetchingRef.current = true;
197
+
198
+ if (mode === 'loading') {
199
+ setLoading(true);
200
+ }
201
+
202
+ if (mode === 'refresh') {
203
+ setRefreshing(true);
204
+ }
205
+
206
+ try {
207
+ const requestPageSize = Math.max(pageSize, API_PAGE_SIZE);
208
+ let page = 1;
209
+ let loadedItems = [];
210
+ let reportedTotal = 0;
211
+
212
+ while (true) {
213
+ const pageItems = await deviceConfigStore.actions.getItems(
214
+ buildDeviceListParams({
215
+ companyId,
216
+ page,
217
+ pageSize: requestPageSize,
218
+ queryTypes,
219
+ }),
220
+ );
221
+ const previousLength = loadedItems.length;
222
+ loadedItems = mergeDeviceConfigs(loadedItems, pageItems);
223
+ reportedTotal = Math.max(
224
+ reportedTotal,
225
+ Number(
226
+ deviceConfigStore.getters.totalItems ||
227
+ loadedItems.length ||
228
+ 0,
229
+ ),
230
+ );
231
+
232
+ if (
233
+ !Array.isArray(pageItems) ||
234
+ pageItems.length === 0 ||
235
+ loadedItems.length >= reportedTotal ||
236
+ loadedItems.length === previousLength
237
+ ) {
238
+ break;
239
+ }
240
+
241
+ page += 1;
242
+ }
243
+
244
+ setDeviceConfigs(loadedItems);
245
+ setError('');
246
+ } catch (fetchError) {
247
+ setDeviceConfigs([]);
248
+
249
+ setError(
250
+ fetchError?.message || 'Nao foi possivel carregar os dispositivos.',
251
+ );
252
+ } finally {
253
+ fetchingRef.current = false;
254
+ setLoading(false);
255
+ setRefreshing(false);
256
+ }
257
+ },
258
+ [
259
+ companyId,
260
+ deviceConfigStore.actions,
261
+ deviceConfigStore.getters,
262
+ pageSize,
263
+ queryTypes,
264
+ ],
265
+ );
266
+
267
+ useFocusEffect(
268
+ useCallback(() => {
269
+ setRuntimeDevice(readStoredRuntimeDevice());
270
+ fetchDeviceConfigs('loading');
271
+ }, [fetchDeviceConfigs]),
272
+ );
273
+
274
+
275
+ const goToDetail = useCallback(
276
+ deviceConfig => {
277
+ const deviceType = getDeviceConfigType(deviceConfig);
278
+ const nextDevice = deviceConfig?.device || {};
279
+ const nextDeviceId = normalizeEntityId(nextDevice?.id || nextDevice?.['@id']);
280
+ const nextConfigs = parseConfigsObject(deviceConfig?.configs);
281
+
282
+ deviceStore.actions.setItem(nextDevice);
283
+ deviceConfigStore.actions.setItem({
284
+ ...deviceConfig,
285
+ configs: nextConfigs,
286
+ });
287
+
288
+ navigation.navigate(getDeviceDetailRoute(deviceType), {
289
+ deviceId: nextDeviceId,
290
+ });
291
+ },
292
+ [deviceConfigStore.actions, deviceStore.actions, navigation],
293
+ );
294
+
295
+ const currentPdvExists = useMemo(
296
+ () =>
297
+ hasCurrentPdvConfig(
298
+ currentDeviceConfigs,
299
+ runtimeDeviceIdentifier,
300
+ ),
301
+ [currentDeviceConfigs, runtimeDeviceIdentifier],
302
+ );
303
+ const showCurrentPdvSetup = Boolean(
304
+ offerCurrentPdvSetup &&
305
+ !loading &&
306
+ runtimeDeviceIdentifier &&
307
+ !currentPdvExists,
308
+ );
309
+
310
+ const handleCreateCurrentPdv = useCallback(async () => {
311
+ if (
312
+ creatingPdv ||
313
+ !companyId ||
314
+ !runtimeDeviceIdentifier ||
315
+ currentPdvExists
316
+ ) {
317
+ return;
318
+ }
319
+
320
+ setCreatingPdv(true);
321
+ setError('');
322
+
323
+ try {
324
+ const {nextConfigs} = buildProviderManagedDeviceConfigs({
325
+ configs: {},
326
+ appVersion: runtimeDevice?.appVersion,
327
+ deviceInfo: runtimeDevice,
328
+ });
329
+ const savedDeviceConfig =
330
+ await deviceConfigStore.actions.addDeviceConfigs({
331
+ device: runtimeDeviceIdentifier,
332
+ people: `/people/${companyId}`,
333
+ type: PDV_DEVICE_TYPE,
334
+ configs: JSON.stringify(nextConfigs),
335
+ });
336
+
337
+ await fetchDeviceConfigs('refresh');
338
+
339
+ if (savedDeviceConfig?.id && savedDeviceConfig?.device) {
340
+ goToDetail(savedDeviceConfig);
341
+ }
342
+ } catch (createError) {
343
+ setError(
344
+ createError?.message ||
345
+ 'Nao foi possivel configurar este dispositivo como PDV.',
346
+ );
347
+ } finally {
348
+ setCreatingPdv(false);
349
+ }
350
+ }, [
351
+ companyId,
352
+ creatingPdv,
353
+ currentPdvExists,
354
+ deviceConfigStore.actions,
355
+ fetchDeviceConfigs,
356
+ goToDetail,
357
+ runtimeDevice,
358
+ runtimeDeviceIdentifier,
359
+ ]);
360
+
361
+ const handleRefresh = useCallback(() => {
362
+ fetchDeviceConfigs('refresh');
363
+ }, [fetchDeviceConfigs]);
364
+
365
+ const renderGroupCard = useCallback(
366
+ cardProps => (
367
+ <DeviceGroupCard
368
+ {...cardProps}
369
+ brandColors={brandColors}
370
+ creatingPdv={creatingPdv}
371
+ goToDetail={goToDetail}
372
+ handleCreateCurrentPdv={handleCreateCurrentPdv}
373
+ networkConnectivityByDevice={networkConnectivityByDevice}
374
+ queryTypes={queryTypes}
375
+ runtimeDeviceIdentifier={runtimeDeviceIdentifier}
376
+ runtimeDeviceType={runtimeDeviceType}
377
+ showCurrentPdvSetup={showCurrentPdvSetup}
378
+ />
379
+ ),
380
+ [
381
+ brandColors,
382
+ creatingPdv,
383
+ goToDetail,
384
+ handleCreateCurrentPdv,
385
+ networkConnectivityByDevice,
386
+ queryTypes,
387
+ runtimeDeviceIdentifier,
388
+ runtimeDeviceType,
389
+ showCurrentPdvSetup,
390
+ ],
391
+ );
392
+
393
+ return (
394
+ <View style={styles.tabContent}>
395
+ <View style={styles.listMetaRow}>
396
+ <Text style={styles.listMetaTitle}>{label}</Text>
397
+ <Text style={styles.listMetaText}>
398
+ {`${visibleDeviceGroups.length} dispositivo(s) • ${
399
+ filteredDeviceConfigs.length
400
+ } configuracao(oes)`}
401
+ </Text>
402
+ </View>
403
+
404
+ {loading ? (
405
+ <View style={styles.loadingBox}>
406
+ <ActivityIndicator size="small" color={brandColors.primary} />
407
+ <Text style={styles.loadingText}>Carregando dispositivos...</Text>
408
+ </View>
409
+ ) : null}
410
+
411
+ {error ? (
412
+ <View style={styles.inlineMessageBox}>
413
+ <Text style={styles.inlineMessageText}>{error}</Text>
414
+ </View>
415
+ ) : null}
416
+
417
+ <DefaultTable
418
+ storeName="device_config"
419
+ data={visibleDeviceGroups}
420
+ columns={deviceTableColumns}
421
+ initialViewMode="cards"
422
+ forceCardsOnCompact
423
+ showToolbar
424
+ showSearch={false}
425
+ showRowActions={false}
426
+ showColumnFiltersButton={false}
427
+ showTotalItemsInFooter
428
+ isLoading={loading}
429
+ onRefresh={handleRefresh}
430
+ renderCard={renderGroupCard}
431
+ onRowPress={group => {
432
+ const primary = group?.primaryConfig || group?.configs?.[0];
433
+ if (primary) {
434
+ goToDetail(primary);
435
+ }
436
+ }}
437
+ searchProps={{
438
+ compact: true,
439
+ placeholder: tt('device_filter', 'search') || 'Buscar dispositivo',
440
+ searchKey: 'search',
441
+ storeName: 'device_config',
442
+ }}
443
+ totalItemsLabel="devices"
444
+ visibleColumnsPreferenceKey="device_config_devices"
445
+ accentColor={brandColors.primary || hex.primary}
446
+ />
447
+ </View>
448
+ );
449
+ };
450
+
451
+ return DeviceTypeTab;
452
+ };
453
+ // TODO(store-first): quando este arquivo for mexido, mover a leitura para stores, remover api.fetch e evitar repassar dados em objetos quando o store ja resolver isso.