@controleonline/ui-common 1.2.89 → 1.2.91
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/docs/compact-order-history-1047.md +25 -0
- package/package.json +1 -1
- package/src/react/components/CopyDeviceConfigModal.js +7 -4
- package/src/react/components/DefaultProvider.native.configuration.js +275 -0
- package/src/react/components/DefaultProvider.native.js +24 -534
- package/src/react/components/DefaultProvider.native.lifecycle.js +323 -0
- package/src/react/components/DefaultProvider.web.configuration.js +327 -0
- package/src/react/components/DefaultProvider.web.js +23 -603
- package/src/react/components/DefaultProvider.web.lifecycle.js +336 -0
- package/src/react/components/resolveDomainThemeColors.js +5 -0
- package/src/react/pages/Connections.js +5 -7
- package/src/react/pages/MercadoLivreIntegrationPage.js +5 -75
- package/src/react/pages/mercadoLivreIntegrationHelpers.js +79 -0
- package/src/tests/browser/manager/bottom-navigation-role-toolbar.spec.js +14 -0
- package/src/tests/browser/manager/connections.spec.js +18 -0
- package/src/tests/browser/manager/device-detail-alias-save.spec.js +3 -1
- package/src/tests/browser/manager/device-detail-copy-config.spec.js +6 -0
- package/src/tests/browser/manager/device-detail-pdv-current-company.spec.js +3 -1
- package/src/tests/browser/manager/devices-current.spec.js +345 -343
- package/src/tests/browser/manager/devices-type-filters.spec.js +2 -0
- package/src/tests/browser/manager/managerSession.fixture.js +28 -0
- package/src/tests/react/components/DefaultProviderAuthority.test.js +4 -1
- package/src/tests/react/components/providerEffects.fingerprint.json +47 -0
- package/src/tests/react/components/providerEffects.test.js +24 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import {useEffect} from 'react';
|
|
2
|
+
|
|
3
|
+
// Extracted bootstrap effects retain their dependency arrays and invocation order.
|
|
4
|
+
|
|
5
|
+
export function useWebTranslationRefresh({setTranslateVersion}) {
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
global.refreshTranslationsUI = () => {
|
|
8
|
+
setTranslateVersion(version => version + 1);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
if (global.refreshTranslationsUI) {
|
|
13
|
+
delete global.refreshTranslationsUI;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}, []);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useWebTranslationReset({isLogged, isPublicRouteActive, setTranslateReady, setActiveTranslateBootstrapKey, translateBootstrapKeyRef, translateActions}) {
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (isLogged && !isPublicRouteActive) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setTranslateReady(true);
|
|
26
|
+
setActiveTranslateBootstrapKey('');
|
|
27
|
+
translateBootstrapKeyRef.current = '';
|
|
28
|
+
translateActions.setMessages({});
|
|
29
|
+
translateActions.setPendingMessages?.({});
|
|
30
|
+
|
|
31
|
+
if (global.t) {
|
|
32
|
+
delete global.t;
|
|
33
|
+
}
|
|
34
|
+
}, [isLogged, isPublicRouteActive, translateActions]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function useWebDeviceConfigReset({deviceConfigPeopleIri, lastDeviceConfigPeopleIriRef, setDeviceConfigFetched, setDeviceRuntimeConfigSynced, deviceConfigsActions}) {
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (
|
|
40
|
+
!deviceConfigPeopleIri ||
|
|
41
|
+
lastDeviceConfigPeopleIriRef.current === deviceConfigPeopleIri
|
|
42
|
+
) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
lastDeviceConfigPeopleIriRef.current = deviceConfigPeopleIri;
|
|
47
|
+
setDeviceConfigFetched(false);
|
|
48
|
+
setDeviceRuntimeConfigSynced(false);
|
|
49
|
+
deviceConfigsActions.setItem({});
|
|
50
|
+
}, [deviceConfigPeopleIri, deviceConfigsActions]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function useWebRuntimeIp({isLogged, api, getRuntimeIpFromResponse, setWebRuntimeIp, user}) {
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!isLogged) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let cancelled = false;
|
|
60
|
+
|
|
61
|
+
api
|
|
62
|
+
.fetch('runtime/ip', {
|
|
63
|
+
method: 'GET',
|
|
64
|
+
})
|
|
65
|
+
.then(response => {
|
|
66
|
+
const nextRuntimeIp = getRuntimeIpFromResponse(response);
|
|
67
|
+
if (!nextRuntimeIp || cancelled) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setWebRuntimeIp(currentIp =>
|
|
72
|
+
currentIp === nextRuntimeIp ? currentIp : nextRuntimeIp,
|
|
73
|
+
);
|
|
74
|
+
})
|
|
75
|
+
.catch(() => {});
|
|
76
|
+
|
|
77
|
+
return () => {
|
|
78
|
+
cancelled = true;
|
|
79
|
+
};
|
|
80
|
+
}, [isLogged, user?.id]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function useWebWebDeviceIdentity({isLogged, isShopClientApp, buildWebDevice, lastWebDeviceSyncRef, setDevice, deviceActions, packageVersion, user, webRuntimeIp}) {
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!isLogged && !isShopClientApp) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const nextDevice = buildWebDevice();
|
|
90
|
+
if (!nextDevice) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const signature = JSON.stringify({
|
|
95
|
+
id: nextDevice.id,
|
|
96
|
+
appVersion: nextDevice.appVersion,
|
|
97
|
+
appName: nextDevice.appName,
|
|
98
|
+
type: nextDevice.type,
|
|
99
|
+
metadata: nextDevice.metadata || {},
|
|
100
|
+
externalIp: nextDevice.externalIp || null,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (lastWebDeviceSyncRef.current === signature) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
lastWebDeviceSyncRef.current = signature;
|
|
108
|
+
setDevice(nextDevice);
|
|
109
|
+
localStorage.setItem('device', JSON.stringify(nextDevice));
|
|
110
|
+
deviceActions.setItem(nextDevice);
|
|
111
|
+
localStorage.removeItem('master-device');
|
|
112
|
+
}, [deviceActions, isLogged, isShopClientApp, packageVersion, user?.id, webRuntimeIp]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function useWebMainCompany({isShopClientApp, device, peopleActions}) {
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (isShopClientApp || device?.id) {
|
|
118
|
+
peopleActions.mainCompany().catch(() => {});
|
|
119
|
+
}
|
|
120
|
+
}, [device?.id, isShopClientApp, peopleActions]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function useWebDeviceRegistration({isLogged, device, currentCompany, canAdministerCompany, mainCompany, user, deviceActions, buildDeviceRegistrationPayload, app_type, hasDeviceRecordChanges, runtimeDeviceType, setDevice}) {
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!isLogged || !device?.id) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Device registration changes tenant context and is not valid without an
|
|
130
|
+
// active company or administrative authority for that company.
|
|
131
|
+
if (
|
|
132
|
+
!currentCompany?.id ||
|
|
133
|
+
!canAdministerCompany({company: currentCompany, mainCompany, user})
|
|
134
|
+
) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let cancelled = false;
|
|
139
|
+
|
|
140
|
+
const syncDeviceRegistration = async () => {
|
|
141
|
+
const items = await deviceActions.getItems({
|
|
142
|
+
device: device.id,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (cancelled) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const existingDevice =
|
|
150
|
+
Array.isArray(items) && items.length > 0 ? items[0] : null;
|
|
151
|
+
const nextDevice = buildDeviceRegistrationPayload({
|
|
152
|
+
deviceInfo: device,
|
|
153
|
+
appType: app_type,
|
|
154
|
+
existingDevice,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (!hasDeviceRecordChanges({existingDevice, nextDevice})) {
|
|
158
|
+
const nextLocalDevice = {
|
|
159
|
+
...device,
|
|
160
|
+
entityId: existingDevice?.id || device?.entityId || null,
|
|
161
|
+
entityIri:
|
|
162
|
+
existingDevice?.['@id'] ||
|
|
163
|
+
device?.entityIri ||
|
|
164
|
+
(existingDevice?.id ? `/devices/${existingDevice.id}` : null),
|
|
165
|
+
alias: existingDevice?.alias || nextDevice.alias,
|
|
166
|
+
type: device?.type || runtimeDeviceType,
|
|
167
|
+
metadata: existingDevice?.metadata || nextDevice.metadata,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
if (JSON.stringify(nextLocalDevice) !== JSON.stringify(device)) {
|
|
171
|
+
setDevice(nextLocalDevice);
|
|
172
|
+
localStorage.setItem('device', JSON.stringify(nextLocalDevice));
|
|
173
|
+
deviceActions.setItem(nextLocalDevice);
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const savedDevice = await deviceActions.save(nextDevice);
|
|
179
|
+
if (cancelled || !savedDevice) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const nextLocalDevice = {
|
|
184
|
+
...device,
|
|
185
|
+
entityId: savedDevice?.id || device?.entityId || null,
|
|
186
|
+
entityIri:
|
|
187
|
+
savedDevice?.['@id'] ||
|
|
188
|
+
device?.entityIri ||
|
|
189
|
+
(savedDevice?.id ? `/devices/${savedDevice.id}` : null),
|
|
190
|
+
alias: savedDevice.alias || nextDevice.alias,
|
|
191
|
+
type: device?.type || runtimeDeviceType,
|
|
192
|
+
metadata: savedDevice.metadata || nextDevice.metadata,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (JSON.stringify(nextLocalDevice) !== JSON.stringify(device)) {
|
|
196
|
+
setDevice(nextLocalDevice);
|
|
197
|
+
localStorage.setItem('device', JSON.stringify(nextLocalDevice));
|
|
198
|
+
deviceActions.setItem(nextLocalDevice);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
syncDeviceRegistration().catch(() => {});
|
|
203
|
+
|
|
204
|
+
return () => {
|
|
205
|
+
cancelled = true;
|
|
206
|
+
};
|
|
207
|
+
}, [
|
|
208
|
+
device?.appVersion,
|
|
209
|
+
device?.batteryLevel,
|
|
210
|
+
device?.buildNumber,
|
|
211
|
+
device?.deviceType,
|
|
212
|
+
device?.externalIp,
|
|
213
|
+
device?.id,
|
|
214
|
+
device?.manufacturer,
|
|
215
|
+
device?.model,
|
|
216
|
+
device?.systemVersion,
|
|
217
|
+
isLogged,
|
|
218
|
+
currentCompany,
|
|
219
|
+
mainCompany,
|
|
220
|
+
runtimeDeviceType,
|
|
221
|
+
user,
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function useWebPrinters({isShopClientApp, isLogged, currentCompany, printerActions}) {
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (isShopClientApp || !isLogged || !currentCompany?.id) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
printerActions
|
|
232
|
+
.ensureCompanyPrintersLoaded({people: currentCompany.id})
|
|
233
|
+
.catch(() => {});
|
|
234
|
+
}, [currentCompany?.id, isLogged, isShopClientApp, printerActions]);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function useWebPaymentTypes({isShopClientApp, companyConfigs, currentCompany, device_config, walletPaymentTypeRequestRef, walletPaymentTypeLoadedKeyRef, paymentTypeActions, mainConfigsDiscovered, resolveDevicePaymentTypeIds, api, selectPosWalletPaymentTypes, getPaymentGateway}) {
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
const paymentConfigSource = isShopClientApp
|
|
240
|
+
? Object.keys(companyConfigs || {}).length > 0
|
|
241
|
+
? companyConfigs
|
|
242
|
+
: currentCompany?.configs
|
|
243
|
+
: device_config?.configs;
|
|
244
|
+
|
|
245
|
+
if (!currentCompany?.id || !paymentConfigSource) {
|
|
246
|
+
walletPaymentTypeRequestRef.current = {key: '', promise: null};
|
|
247
|
+
walletPaymentTypeLoadedKeyRef.current = '';
|
|
248
|
+
paymentTypeActions.setItems([]);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!isShopClientApp && !mainConfigsDiscovered) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const paymentTypeSignature = resolveDevicePaymentTypeIds(paymentConfigSource)
|
|
257
|
+
.sort()
|
|
258
|
+
.join(',');
|
|
259
|
+
const requestKey = `${currentCompany.id}:${paymentTypeSignature}`;
|
|
260
|
+
|
|
261
|
+
if (walletPaymentTypeLoadedKeyRef.current === requestKey) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const existingRequestPromise =
|
|
266
|
+
walletPaymentTypeRequestRef.current.key === requestKey &&
|
|
267
|
+
walletPaymentTypeRequestRef.current.promise
|
|
268
|
+
? walletPaymentTypeRequestRef.current.promise
|
|
269
|
+
: null;
|
|
270
|
+
|
|
271
|
+
let isMounted = true;
|
|
272
|
+
|
|
273
|
+
const requestPromise =
|
|
274
|
+
existingRequestPromise ||
|
|
275
|
+
api.fetch('wallet_payment_types', {
|
|
276
|
+
params: {
|
|
277
|
+
people: `/people/${currentCompany.id}`,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (!existingRequestPromise) {
|
|
282
|
+
walletPaymentTypeRequestRef.current = {
|
|
283
|
+
key: requestKey,
|
|
284
|
+
promise: requestPromise,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
requestPromise
|
|
289
|
+
.then(response => {
|
|
290
|
+
if (!isMounted) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const walletPaymentTypes = Array.isArray(response?.member)
|
|
295
|
+
? response.member
|
|
296
|
+
: Array.isArray(response?.['hydra:member'])
|
|
297
|
+
? response['hydra:member']
|
|
298
|
+
: Array.isArray(response)
|
|
299
|
+
? response
|
|
300
|
+
: [];
|
|
301
|
+
paymentTypeActions.setItems(
|
|
302
|
+
selectPosWalletPaymentTypes({
|
|
303
|
+
walletPaymentTypes,
|
|
304
|
+
deviceConfigs: paymentConfigSource,
|
|
305
|
+
companyConfigs,
|
|
306
|
+
gateway: getPaymentGateway(device_config || paymentConfigSource),
|
|
307
|
+
}),
|
|
308
|
+
);
|
|
309
|
+
walletPaymentTypeLoadedKeyRef.current = requestKey;
|
|
310
|
+
})
|
|
311
|
+
.catch(() => {
|
|
312
|
+
if (isMounted) {
|
|
313
|
+
paymentTypeActions.setItems([]);
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
.finally(() => {
|
|
317
|
+
if (
|
|
318
|
+
walletPaymentTypeRequestRef.current.key === requestKey &&
|
|
319
|
+
walletPaymentTypeRequestRef.current.promise === requestPromise
|
|
320
|
+
) {
|
|
321
|
+
walletPaymentTypeRequestRef.current = {key: '', promise: null};
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
return () => {
|
|
326
|
+
isMounted = false;
|
|
327
|
+
};
|
|
328
|
+
}, [
|
|
329
|
+
companyConfigs,
|
|
330
|
+
currentCompany?.configs,
|
|
331
|
+
currentCompany?.id,
|
|
332
|
+
device_config?.configs,
|
|
333
|
+
isShopClientApp,
|
|
334
|
+
paymentTypeActions,
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
@@ -209,13 +209,11 @@ export default function Connections() {
|
|
|
209
209
|
showColumnFiltersButton
|
|
210
210
|
onRowPress={openWhatsAppChannel}
|
|
211
211
|
renderCard={renderConnectionCard}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
storeName: 'connections',
|
|
218
|
-
}}
|
|
212
|
+
showSearch
|
|
213
|
+
searchPlaceholder={
|
|
214
|
+
tt('connections_label', 'search') || 'Buscar conexao, telefone ou status'
|
|
215
|
+
}
|
|
216
|
+
searchKey="search"
|
|
219
217
|
totalItemsLabel="connections"
|
|
220
218
|
visibleColumnsPreferenceKey="connections"
|
|
221
219
|
accentColor={brandColors.primary}
|
|
@@ -23,6 +23,10 @@ import {
|
|
|
23
23
|
} from '@controleonline/../../src/styles/branding';
|
|
24
24
|
|
|
25
25
|
import styles from './IntegrationConfigPage.styles';
|
|
26
|
+
import {
|
|
27
|
+
normalizeTextValue, isConnected, formatApiError, resolveFrontOAuthRedirectUri,
|
|
28
|
+
replaceFrontOAuthStatus, formatOAuthStatusError,
|
|
29
|
+
} from './mercadoLivreIntegrationHelpers';
|
|
26
30
|
|
|
27
31
|
const PROVIDER = {
|
|
28
32
|
key: 'mercadolivre',
|
|
@@ -45,81 +49,6 @@ const shadowStyle = Platform.select({
|
|
|
45
49
|
web: {boxShadow: '0 10px 24px rgba(15,23,42,0.08)'},
|
|
46
50
|
});
|
|
47
51
|
|
|
48
|
-
const normalizeTextValue = value => String(value ?? '').trim();
|
|
49
|
-
|
|
50
|
-
const isConnected = value =>
|
|
51
|
-
value === true ||
|
|
52
|
-
value === 1 ||
|
|
53
|
-
value === '1' ||
|
|
54
|
-
String(value).trim().toLowerCase() === 'true';
|
|
55
|
-
|
|
56
|
-
const formatApiError = error =>
|
|
57
|
-
error?.message ||
|
|
58
|
-
error?.description ||
|
|
59
|
-
error?.error ||
|
|
60
|
-
tt('marketplace_error', 'mercadoLivreLoad') ||
|
|
61
|
-
'Nao foi possivel carregar a integracao Mercado Livre.';
|
|
62
|
-
|
|
63
|
-
const MERCADO_LIVRE_OAUTH_QUERY_KEYS = [
|
|
64
|
-
'code',
|
|
65
|
-
'state',
|
|
66
|
-
'error',
|
|
67
|
-
'error_description',
|
|
68
|
-
'mercadolivre_connected',
|
|
69
|
-
'mercadolivre_error',
|
|
70
|
-
'mercadolivre_message',
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
const resolveFrontOAuthRedirectUri = () => {
|
|
74
|
-
if (Platform.OS !== 'web' || typeof window === 'undefined') {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const url = new URL(window.location.href);
|
|
79
|
-
MERCADO_LIVRE_OAUTH_QUERY_KEYS.forEach(key => url.searchParams.delete(key));
|
|
80
|
-
url.hash = '';
|
|
81
|
-
|
|
82
|
-
return url.toString();
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const replaceFrontOAuthStatus = statusParams => {
|
|
86
|
-
if (Platform.OS !== 'web' || typeof window === 'undefined') {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const url = new URL(window.location.href);
|
|
91
|
-
MERCADO_LIVRE_OAUTH_QUERY_KEYS.forEach(key => url.searchParams.delete(key));
|
|
92
|
-
Object.entries(statusParams || {}).forEach(([key, value]) => {
|
|
93
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
94
|
-
url.searchParams.set(key, String(value));
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
window.history.replaceState({}, document.title, url.toString());
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const formatOAuthStatusError = (error, message) => {
|
|
101
|
-
const messageText = normalizeTextValue(message);
|
|
102
|
-
if (messageText) {
|
|
103
|
-
return `${
|
|
104
|
-
tt('marketplace_error', 'mercadoLivreConnectWithMessage') ||
|
|
105
|
-
'Nao foi possivel conectar o Mercado Livre:'
|
|
106
|
-
} ${messageText}`;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const errorText = normalizeTextValue(error);
|
|
110
|
-
if (!errorText) {
|
|
111
|
-
return (
|
|
112
|
-
tt('marketplace_error', 'mercadoLivreConnect') ||
|
|
113
|
-
'Nao foi possivel conectar o Mercado Livre.'
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return `${
|
|
118
|
-
tt('marketplace_error', 'mercadoLivreConnect') ||
|
|
119
|
-
'Nao foi possivel conectar o Mercado Livre.'
|
|
120
|
-
} (${errorText}).`;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
52
|
export default function MercadoLivreIntegrationPage() {
|
|
124
53
|
const peopleStore = useStore('people');
|
|
125
54
|
const themeStore = useStore('theme');
|
|
@@ -513,6 +442,7 @@ export default function MercadoLivreIntegrationPage() {
|
|
|
513
442
|
</View>
|
|
514
443
|
|
|
515
444
|
<TouchableOpacity
|
|
445
|
+
accessibilityRole="button"
|
|
516
446
|
style={[
|
|
517
447
|
styles.saveButton,
|
|
518
448
|
{backgroundColor: PROVIDER.button},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {Platform} from 'react-native';
|
|
2
|
+
|
|
3
|
+
const tt = (type, key) => global.t?.t('configs', type, key);
|
|
4
|
+
|
|
5
|
+
export const normalizeTextValue = value => String(value ?? '').trim();
|
|
6
|
+
|
|
7
|
+
export const isConnected = value =>
|
|
8
|
+
value === true ||
|
|
9
|
+
value === 1 ||
|
|
10
|
+
value === '1' ||
|
|
11
|
+
String(value).trim().toLowerCase() === 'true';
|
|
12
|
+
|
|
13
|
+
export const formatApiError = error =>
|
|
14
|
+
error?.message ||
|
|
15
|
+
error?.description ||
|
|
16
|
+
error?.error ||
|
|
17
|
+
tt('marketplace_error', 'mercadoLivreLoad') ||
|
|
18
|
+
'Nao foi possivel carregar a integracao Mercado Livre.';
|
|
19
|
+
|
|
20
|
+
const MERCADO_LIVRE_OAUTH_QUERY_KEYS = [
|
|
21
|
+
'code',
|
|
22
|
+
'state',
|
|
23
|
+
'error',
|
|
24
|
+
'error_description',
|
|
25
|
+
'mercadolivre_connected',
|
|
26
|
+
'mercadolivre_error',
|
|
27
|
+
'mercadolivre_message',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export const resolveFrontOAuthRedirectUri = () => {
|
|
31
|
+
if (Platform.OS !== 'web' || typeof window === 'undefined') {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const url = new URL(window.location.href);
|
|
36
|
+
MERCADO_LIVRE_OAUTH_QUERY_KEYS.forEach(key => url.searchParams.delete(key));
|
|
37
|
+
url.hash = '';
|
|
38
|
+
|
|
39
|
+
return url.toString();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const replaceFrontOAuthStatus = statusParams => {
|
|
43
|
+
if (Platform.OS !== 'web' || typeof window === 'undefined') {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const url = new URL(window.location.href);
|
|
48
|
+
MERCADO_LIVRE_OAUTH_QUERY_KEYS.forEach(key => url.searchParams.delete(key));
|
|
49
|
+
Object.entries(statusParams || {}).forEach(([key, value]) => {
|
|
50
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
51
|
+
url.searchParams.set(key, String(value));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
window.history.replaceState({}, document.title, url.toString());
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const formatOAuthStatusError = (error, message) => {
|
|
58
|
+
const messageText = normalizeTextValue(message);
|
|
59
|
+
if (messageText) {
|
|
60
|
+
return `${
|
|
61
|
+
tt('marketplace_error', 'mercadoLivreConnectWithMessage') ||
|
|
62
|
+
'Nao foi possivel conectar o Mercado Livre:'
|
|
63
|
+
} ${messageText}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const errorText = normalizeTextValue(error);
|
|
67
|
+
if (!errorText) {
|
|
68
|
+
return (
|
|
69
|
+
tt('marketplace_error', 'mercadoLivreConnect') ||
|
|
70
|
+
'Nao foi possivel conectar o Mercado Livre.'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return `${
|
|
75
|
+
tt('marketplace_error', 'mercadoLivreConnect') ||
|
|
76
|
+
'Nao foi possivel conectar o Mercado Livre.'
|
|
77
|
+
} (${errorText}).`;
|
|
78
|
+
};
|
|
79
|
+
|
|
@@ -141,9 +141,23 @@ const installSession = async (page, {companyId = 3} = {}) => {
|
|
|
141
141
|
active: 1,
|
|
142
142
|
mycompany: companyId,
|
|
143
143
|
roles: ['ROLE_ADMIN'],
|
|
144
|
+
name: 'Test User',
|
|
145
|
+
realname: 'Test User',
|
|
146
|
+
username: 'tester',
|
|
144
147
|
}),
|
|
145
148
|
);
|
|
146
149
|
set('config', JSON.stringify({language: 'pt-br'}));
|
|
150
|
+
// Resolve menu labels locally; the mock API does not provide translations.
|
|
151
|
+
const labels = {
|
|
152
|
+
home: 'Início', opportunities: 'Oportunidades',
|
|
153
|
+
customers: 'Clientes', profile: 'Perfil',
|
|
154
|
+
};
|
|
155
|
+
const companyMessages = {
|
|
156
|
+
menu: {menu: labels}, configs: {toolbar: labels},
|
|
157
|
+
};
|
|
158
|
+
set('translates', JSON.stringify({
|
|
159
|
+
'pt-br': {companies: {3: companyMessages, 9: companyMessages}},
|
|
160
|
+
}));
|
|
147
161
|
set('app-type', 'MANAGER');
|
|
148
162
|
set(
|
|
149
163
|
'device',
|
|
@@ -64,6 +64,13 @@ const mockConnectionsApi = async page => {
|
|
|
64
64
|
return route.fulfill({status: 204, headers: CORS_HEADERS, body: ''});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
if (pathname === 'people/companies/my') {
|
|
68
|
+
return route.fulfill({
|
|
69
|
+
status: 200, headers: jsonHeaders(),
|
|
70
|
+
body: JSON.stringify(collection([company])),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
67
74
|
if (pathname === 'companies' || pathname.startsWith('people/')) {
|
|
68
75
|
return route.fulfill({
|
|
69
76
|
status: 200,
|
|
@@ -103,9 +110,20 @@ const mockConnectionsApi = async page => {
|
|
|
103
110
|
active: 1,
|
|
104
111
|
mycompany: 3,
|
|
105
112
|
roles: ['ROLE_ADMIN'],
|
|
113
|
+
name: 'Test User',
|
|
114
|
+
realname: 'Test User',
|
|
115
|
+
username: 'tester',
|
|
106
116
|
}),
|
|
107
117
|
);
|
|
108
118
|
set('config', JSON.stringify({language: 'pt-br'}));
|
|
119
|
+
set('translates', JSON.stringify({
|
|
120
|
+
'pt-br': {companies: {3: {configs: {
|
|
121
|
+
connections_title: {connections: 'Conexões'},
|
|
122
|
+
connections_label: {
|
|
123
|
+
whatsApp: 'WhatsApp', search: 'Buscar conexao, telefone ou status',
|
|
124
|
+
},
|
|
125
|
+
}}}},
|
|
126
|
+
}));
|
|
109
127
|
set('app-type', 'ERP');
|
|
110
128
|
set(
|
|
111
129
|
'device',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {installManagerSession} = require('./managerSession.fixture');
|
|
1
2
|
/**
|
|
2
3
|
* Smoke browser: Manager /device-detail alias save updates header without refresh.
|
|
3
4
|
* fluxo: manager-devices
|
|
@@ -16,7 +17,7 @@ const { API_ORIGIN } = require('../../../../../../../src/tests/browser/apiOrigin
|
|
|
16
17
|
const APP_VERSION = packageJson?.version || '1.0.0';
|
|
17
18
|
const CURRENT_DEVICE_ID = 'web-7';
|
|
18
19
|
const DEVICE_ENTITY_ID = 396;
|
|
19
|
-
const INITIAL_ALIAS = 'Caixa
|
|
20
|
+
const INITIAL_ALIAS = 'Caixa Santa Redonda';
|
|
20
21
|
const NEXT_ALIAS = 'Caixa Renomeado #382';
|
|
21
22
|
|
|
22
23
|
const CORS_HEADERS = {
|
|
@@ -86,6 +87,7 @@ const MODULES_MAX_500 = [
|
|
|
86
87
|
];
|
|
87
88
|
|
|
88
89
|
const mockDevicesApi = async (page) => {
|
|
90
|
+
await installManagerSession(page);
|
|
89
91
|
const company = {
|
|
90
92
|
id: 3,
|
|
91
93
|
name: 'Teste',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {installManagerSession} = require('./managerSession.fixture');
|
|
1
2
|
/**
|
|
2
3
|
* Smoke browser: Manager /device-detail copy configs from another device.
|
|
3
4
|
* fluxo: manager-devices
|
|
@@ -110,6 +111,7 @@ const otherTenant = createDeviceConfig({
|
|
|
110
111
|
});
|
|
111
112
|
|
|
112
113
|
const mockCopyApi = async (page) => {
|
|
114
|
+
await installManagerSession(page);
|
|
113
115
|
const company = {
|
|
114
116
|
id: 3,
|
|
115
117
|
name: 'Teste',
|
|
@@ -328,6 +330,10 @@ test.describe('device-detail copy config (browser smoke #629)', () => {
|
|
|
328
330
|
await expect(page.getByTestId('copy-device-config-hint')).toContainText(
|
|
329
331
|
DEST_ALIAS,
|
|
330
332
|
);
|
|
333
|
+
// The translated prefix cannot supply a fixture alias: target identity is dynamic.
|
|
334
|
+
await expect(page.getByTestId('copy-device-config-hint')).not.toContainText(
|
|
335
|
+
SRC_ALIAS,
|
|
336
|
+
);
|
|
331
337
|
await shot('02-copy-modal-picker.png');
|
|
332
338
|
|
|
333
339
|
await expect(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {installManagerSession} = require('./managerSession.fixture');
|
|
1
2
|
/**
|
|
2
3
|
* Smoke browser: DeviceConfig PDV detail opens without currentCompany ReferenceError.
|
|
3
4
|
* fluxo: device-configuracao
|
|
@@ -91,6 +92,7 @@ const createDeviceConfig = ({id, type, device = currentDevice}) => ({
|
|
|
91
92
|
});
|
|
92
93
|
|
|
93
94
|
const mockDevicesApi = async page => {
|
|
95
|
+
await installManagerSession(page);
|
|
94
96
|
const company = {
|
|
95
97
|
id: 3,
|
|
96
98
|
name: 'Teste',
|
|
@@ -248,7 +250,7 @@ test.describe('device-detail PDV currentCompany (#704)', () => {
|
|
|
248
250
|
|
|
249
251
|
await page.getByTestId(`device-config-${PDV_CONFIG_ID}`).click();
|
|
250
252
|
await expect(page).toHaveURL(/device-detail/, {timeout: 15000});
|
|
251
|
-
await expect(page.getByText('
|
|
253
|
+
await expect(page.getByText('Detalhes do Device', {exact: true})).toBeVisible({
|
|
252
254
|
timeout: 15000,
|
|
253
255
|
});
|
|
254
256
|
await writeEvidence(
|