@controleonline/ui-common 1.2.98 → 1.2.100

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.
@@ -70,6 +70,16 @@ export const INTEGRATION_LIST = [
70
70
  accent: '#166534',
71
71
  icon: 'file-text',
72
72
  },
73
+ {
74
+ key: 'sem-parar',
75
+ label: 'Sem Parar',
76
+ route: 'IntegrationConfigPage',
77
+ routeParams: {
78
+ providerKey: 'sem-parar',
79
+ },
80
+ accent: '#0EA5E9',
81
+ icon: 'truck',
82
+ },
73
83
  ];
74
84
 
75
85
  export const INTEGRATION_CONFIGS = {
@@ -257,6 +267,67 @@ export const INTEGRATION_CONFIGS = {
257
267
  ],
258
268
  fields: [],
259
269
  },
270
+
271
+ 'sem-parar': {
272
+ key: 'sem-parar',
273
+ label: 'Sem Parar',
274
+ accent: '#0EA5E9',
275
+ icon: 'truck',
276
+ description:
277
+ 'Credenciais da empresa para emissao de vale-pedagio via Sem Parar.',
278
+ saveLabel: 'Salvar Sem Parar',
279
+ // Backend (api-platform-integration SemPararConfig) reads a single private JSON key.
280
+ bundleKey: 'SEM_PARAR',
281
+ visibility: 'private',
282
+ requiredKeys: ['ENABLED', 'CLIENT_ID', 'CLIENT_SECRET', 'USERNAME', 'PASSWORD'],
283
+ fields: [
284
+ {
285
+ key: 'ENABLED',
286
+ label: 'Ativo',
287
+ type: 'select',
288
+ options: [
289
+ {value: '1', label: 'Sim'},
290
+ {value: '0', label: 'Nao'},
291
+ ],
292
+ },
293
+ {
294
+ key: 'ENVIRONMENT',
295
+ label: 'Ambiente',
296
+ type: 'select',
297
+ options: [
298
+ {value: 'sandbox', label: 'Sandbox'},
299
+ {value: 'production', label: 'Producao'},
300
+ ],
301
+ },
302
+ {
303
+ key: 'CLIENT_ID',
304
+ label: 'Client ID',
305
+ placeholder: 'Client ID Sem Parar',
306
+ },
307
+ {
308
+ key: 'CLIENT_SECRET',
309
+ label: 'Client secret',
310
+ placeholder: 'Client secret Sem Parar',
311
+ secureTextEntry: true,
312
+ },
313
+ {
314
+ key: 'USERNAME',
315
+ label: 'Usuario',
316
+ placeholder: 'Usuario da API',
317
+ },
318
+ {
319
+ key: 'PASSWORD',
320
+ label: 'Senha',
321
+ placeholder: 'Senha da API',
322
+ secureTextEntry: true,
323
+ },
324
+ {
325
+ key: 'CONVENIADO',
326
+ label: 'Conveniado',
327
+ placeholder: 'Codigo do conveniado (se aplicavel)',
328
+ },
329
+ ],
330
+ },
260
331
  };
261
332
 
262
333
  export const getIntegrationListItem = key =>
@@ -0,0 +1,13 @@
1
+ import eventBus from '../components/EventBus';
2
+
3
+ const key = 'product-catalog-cache-revision';
4
+ let revision = '0';
5
+ let sequence = 0;
6
+ export const getProductCatalogCacheRevision = () => {
7
+ try { return localStorage.getItem(key) || revision; } catch { return revision; }
8
+ };
9
+ export const invalidateProductCatalogCache = () => {
10
+ revision = `${Date.now()}:${++sequence}`;
11
+ try { localStorage.setItem(key, revision); } catch { /* In-memory invalidation still applies. */ }
12
+ eventBus.emit('product-catalog-cache:cleared');
13
+ };
@@ -30,17 +30,17 @@ const setLocation = value => {
30
30
  Object.defineProperty(globalThis, 'location', {
31
31
  configurable: true,
32
32
  enumerable: true,
33
- writable: true,
34
- value,
35
- })
36
- }
37
-
38
- const restoreLocation = () => {
39
- if (originalLocationDescriptor) {
40
- Object.defineProperty(globalThis, 'location', originalLocationDescriptor)
41
- return
42
- }
43
-
33
+ writable: true,
34
+ value,
35
+ })
36
+ }
37
+
38
+ const restoreLocation = () => {
39
+ if (originalLocationDescriptor) {
40
+ Object.defineProperty(globalThis, 'location', originalLocationDescriptor)
41
+ return
42
+ }
43
+
44
44
  delete globalThis.location
45
45
  }
46
46
 
@@ -59,101 +59,101 @@ after(() => {
59
59
 
60
60
  test('prefers the persisted public ip for web runtime devices', () => {
61
61
  setLocation({hostname: '10.0.0.15'})
62
-
63
- try {
64
- assert.equal(
65
- getRuntimeFooterPrimaryText({
66
- device: {
67
- alias: 'app',
68
- appVersion: '1.3.6',
69
- deviceType: 'web',
70
- id: 'web-12',
71
- externalIp: '198.51.100.21',
72
- metadata: {
73
- network: {
74
- publicIp: '198.51.100.21',
75
- },
76
- },
77
- },
78
- appVersion: '1.3.6',
79
- deviceConfig: {
80
- device: {
81
- metadata: {
82
- network: {
83
- publicIp: '203.0.113.42',
84
- },
85
- },
86
- },
87
- configs: {
88
- 'config-version': '1.3.5',
89
- },
90
- },
91
- }),
92
- 'web (203.0.113.42) / v1.3.6',
93
- )
94
-
95
- const debugInfo = getRuntimeFooterDebugInfo({
96
- device: {
97
- alias: 'app',
98
- appVersion: '1.3.6',
99
- deviceType: 'web',
100
- id: 'web-12',
101
- externalIp: '198.51.100.21',
102
- metadata: {
103
- network: {
104
- publicIp: '198.51.100.21',
105
- },
106
- },
107
- },
108
- appVersion: '1.3.6',
109
- deviceConfig: {
110
- device: {
111
- metadata: {
112
- network: {
113
- publicIp: '203.0.113.42',
114
- },
115
- },
116
- },
117
- configs: {
118
- 'config-version': '1.3.5',
119
- },
120
- },
121
- })
122
-
123
- assert.equal(debugInfo.runtimeDetailSource, 'device_config.device.metadata.network.publicIp')
124
- assert.equal(debugInfo.rawValues.storedDeviceMetadataPublicIp, '203.0.113.42')
125
- assert.equal(debugInfo.rawValues.deviceMetadataPublicIp, '198.51.100.21')
126
- } finally {
127
- restoreLocation()
128
- }
129
- })
130
-
131
- test('normalizes localhost to the loopback address on web', () => {
132
- setLocation({hostname: 'localhost'})
133
-
134
- try {
135
- assert.equal(getRuntimeFooterWebHost(), '127.0.0.1')
136
- } finally {
137
- restoreLocation()
138
- }
139
- })
140
-
62
+
63
+ try {
64
+ assert.equal(
65
+ getRuntimeFooterPrimaryText({
66
+ device: {
67
+ alias: 'app',
68
+ appVersion: '1.3.6',
69
+ deviceType: 'web',
70
+ id: 'web-12',
71
+ externalIp: '198.51.100.21',
72
+ metadata: {
73
+ network: {
74
+ publicIp: '198.51.100.21',
75
+ },
76
+ },
77
+ },
78
+ appVersion: '1.3.6',
79
+ deviceConfig: {
80
+ device: {
81
+ metadata: {
82
+ network: {
83
+ publicIp: '203.0.113.42',
84
+ },
85
+ },
86
+ },
87
+ configs: {
88
+ 'config-version': '1.3.5',
89
+ },
90
+ },
91
+ }),
92
+ 'web (203.0.113.42) / v1.3.6',
93
+ )
94
+
95
+ const debugInfo = getRuntimeFooterDebugInfo({
96
+ device: {
97
+ alias: 'app',
98
+ appVersion: '1.3.6',
99
+ deviceType: 'web',
100
+ id: 'web-12',
101
+ externalIp: '198.51.100.21',
102
+ metadata: {
103
+ network: {
104
+ publicIp: '198.51.100.21',
105
+ },
106
+ },
107
+ },
108
+ appVersion: '1.3.6',
109
+ deviceConfig: {
110
+ device: {
111
+ metadata: {
112
+ network: {
113
+ publicIp: '203.0.113.42',
114
+ },
115
+ },
116
+ },
117
+ configs: {
118
+ 'config-version': '1.3.5',
119
+ },
120
+ },
121
+ })
122
+
123
+ assert.equal(debugInfo.runtimeDetailSource, 'device_config.device.metadata.network.publicIp')
124
+ assert.equal(debugInfo.rawValues.storedDeviceMetadataPublicIp, '203.0.113.42')
125
+ assert.equal(debugInfo.rawValues.deviceMetadataPublicIp, '198.51.100.21')
126
+ } finally {
127
+ restoreLocation()
128
+ }
129
+ })
130
+
131
+ test('normalizes localhost to the loopback address on web', () => {
132
+ setLocation({hostname: 'localhost'})
133
+
134
+ try {
135
+ assert.equal(getRuntimeFooterWebHost(), '127.0.0.1')
136
+ } finally {
137
+ restoreLocation()
138
+ }
139
+ })
140
+
141
141
  test('falls back to the browser hostname for web when no persisted public ip exists', () => {
142
142
  setLocation({hostname: 'localhost'})
143
-
144
- try {
145
- const candidates = getRuntimeFooterWebIdentifierCandidates({
146
- device: {
147
- deviceType: 'web',
148
- id: 'web-12',
149
- },
150
- deviceConfig: {},
151
- })
152
-
153
- assert.equal(candidates[0]?.value, '127.0.0.1')
154
- assert.equal(candidates[0]?.source, 'location.hostname')
155
- } finally {
156
- restoreLocation()
143
+
144
+ try {
145
+ const candidates = getRuntimeFooterWebIdentifierCandidates({
146
+ device: {
147
+ deviceType: 'web',
148
+ id: 'web-12',
149
+ },
150
+ deviceConfig: {},
151
+ })
152
+
153
+ assert.equal(candidates[0]?.value, '127.0.0.1')
154
+ assert.equal(candidates[0]?.source, 'location.hostname')
155
+ } finally {
156
+ restoreLocation()
157
157
  }
158
158
  })
159
159
 
@@ -191,91 +191,91 @@ test('recognizes backend web devices by their persisted runtime metadata or devi
191
191
 
192
192
  test('reads the persisted config-version for non-web runtimes', () => {
193
193
  assert.equal(
194
- getRuntimeFooterStoredVersion({
195
- configs: JSON.stringify({
196
- 'config-version': '1.3.5',
197
- }),
198
- }),
199
- 'v1.3.5',
200
- )
201
-
202
- assert.equal(
203
- getRuntimeFooterPrimaryText({
204
- device: {
205
- alias: 'PDV',
206
- appVersion: '1.3.7',
207
- deviceType: 'android',
208
- id: 'native-12',
209
- },
210
- appVersion: '1.3.6',
211
- deviceConfig: {
212
- device: {
213
- device: '229252771069b294',
214
- },
215
- configs: {
216
- 'config-version': '1.3.5',
217
- },
218
- },
219
- }),
220
- 'PDV (229252771069b294) / v1.3.7',
221
- )
222
- })
223
-
194
+ getRuntimeFooterStoredVersion({
195
+ configs: JSON.stringify({
196
+ 'config-version': '1.3.5',
197
+ }),
198
+ }),
199
+ 'v1.3.5',
200
+ )
201
+
202
+ assert.equal(
203
+ getRuntimeFooterPrimaryText({
204
+ device: {
205
+ alias: 'PDV',
206
+ appVersion: '1.3.7',
207
+ deviceType: 'android',
208
+ id: 'native-12',
209
+ },
210
+ appVersion: '1.3.6',
211
+ deviceConfig: {
212
+ device: {
213
+ device: '229252771069b294',
214
+ },
215
+ configs: {
216
+ 'config-version': '1.3.5',
217
+ },
218
+ },
219
+ }),
220
+ 'PDV (229252771069b294) / v1.3.7',
221
+ )
222
+ })
223
+
224
224
  test('prefers the backend device identifier used by the devices page', () => {
225
225
  assert.equal(
226
226
  getRuntimeFooterPrimaryText({
227
227
  device: {
228
228
  alias: 'PDV',
229
- appVersion: '1.3.7',
230
- deviceType: 'android',
231
- id: 'd41ac8afb9f178eb',
232
- },
233
- appVersion: '1.3.6',
234
- deviceConfig: {
235
- device: {
236
- device: '229252771069b294',
237
- metadata: {
238
- app: {
239
- version: '1.3.7',
240
- },
241
- },
242
- },
243
- configs: {
244
- 'config-version': '1.3.7',
245
- },
246
- },
247
- }),
248
- 'PDV (229252771069b294) / v1.3.7',
249
- )
250
-
251
- const debugInfo = getRuntimeFooterDebugInfo({
252
- device: {
253
- alias: 'PDV',
254
- appVersion: '1.3.7',
255
- deviceType: 'android',
256
- id: 'd41ac8afb9f178eb',
257
- },
258
- appVersion: '1.3.6',
259
- deviceConfig: {
260
- device: {
261
- device: '229252771069b294',
262
- metadata: {
263
- app: {
264
- version: '1.3.7',
265
- },
266
- },
267
- },
268
- configs: {
269
- 'config-version': '1.3.7',
270
- },
271
- },
272
- })
273
-
274
- assert.equal(debugInfo.versionLabel, 'v1.3.7')
275
- assert.equal(debugInfo.displayName, 'PDV (229252771069b294)')
276
- assert.equal(debugInfo.runtimeDetail, '229252771069b294')
277
- assert.equal(debugInfo.runtimeDetailSource, 'device_config.device.device')
278
- assert.equal(debugInfo.versionCandidates[0]?.source, 'device_config.device.metadata.app.version')
229
+ appVersion: '1.3.7',
230
+ deviceType: 'android',
231
+ id: 'd41ac8afb9f178eb',
232
+ },
233
+ appVersion: '1.3.6',
234
+ deviceConfig: {
235
+ device: {
236
+ device: '229252771069b294',
237
+ metadata: {
238
+ app: {
239
+ version: '1.3.7',
240
+ },
241
+ },
242
+ },
243
+ configs: {
244
+ 'config-version': '1.3.7',
245
+ },
246
+ },
247
+ }),
248
+ 'PDV (229252771069b294) / v1.3.7',
249
+ )
250
+
251
+ const debugInfo = getRuntimeFooterDebugInfo({
252
+ device: {
253
+ alias: 'PDV',
254
+ appVersion: '1.3.7',
255
+ deviceType: 'android',
256
+ id: 'd41ac8afb9f178eb',
257
+ },
258
+ appVersion: '1.3.6',
259
+ deviceConfig: {
260
+ device: {
261
+ device: '229252771069b294',
262
+ metadata: {
263
+ app: {
264
+ version: '1.3.7',
265
+ },
266
+ },
267
+ },
268
+ configs: {
269
+ 'config-version': '1.3.7',
270
+ },
271
+ },
272
+ })
273
+
274
+ assert.equal(debugInfo.versionLabel, 'v1.3.7')
275
+ assert.equal(debugInfo.displayName, 'PDV (229252771069b294)')
276
+ assert.equal(debugInfo.runtimeDetail, '229252771069b294')
277
+ assert.equal(debugInfo.runtimeDetailSource, 'device_config.device.device')
278
+ assert.equal(debugInfo.versionCandidates[0]?.source, 'device_config.device.metadata.app.version')
279
279
  assert.equal(debugInfo.rawValues.deviceId, 'd41ac8afb9f178eb')
280
280
  assert.equal(debugInfo.rawValues.storedDeviceIdentifier, '229252771069b294')
281
281
  })
@@ -417,11 +417,11 @@ test('falls back to the local device id when the backend identifier is unavailab
417
417
  const candidates = getRuntimeFooterNativeIdentifierCandidates({
418
418
  device: {
419
419
  id: 'local-device-99',
420
- },
421
- deviceConfig: {
422
- device: {},
423
- },
424
- })
420
+ },
421
+ deviceConfig: {
422
+ device: {},
423
+ },
424
+ })
425
425
 
426
426
  assert.equal(candidates[0]?.value, 'local-device-99')
427
427
  assert.equal(candidates[0]?.source, 'device.id')
@@ -0,0 +1,22 @@
1
+ const assert = require('node:assert/strict');
2
+ const {test} = require('node:test');
3
+ const {readStoredSessionToken} = require('../../../utils/storedSessionToken');
4
+
5
+ for (const prefix of ['', '__q_objt|']) {
6
+ for (const field of ['token', 'api_key']) {
7
+ test(`reads ${field} from ${prefix ? 'wrapped' : 'plain'} session`, () => {
8
+ const storage = {getItem: key => key === 'session' ? prefix + JSON.stringify({[field]: 'synthetic-token'}) : null};
9
+ assert.equal(readStoredSessionToken(storage), 'synthetic-token');
10
+ });
11
+ }
12
+ }
13
+ test('prefers the canonical token field when both are present', () => {
14
+ assert.equal(readStoredSessionToken({getItem: () => JSON.stringify({token: 'current', api_key: 'old'})}), 'current');
15
+ });
16
+ test('missing, malformed and inaccessible sessions have no token', () => {
17
+ for (const raw of [null, '', 'broken', '__q_objt|broken', '{}', 'null']) {
18
+ assert.equal(readStoredSessionToken({getItem: () => raw}), '');
19
+ }
20
+ assert.equal(readStoredSessionToken({getItem: () => {throw new Error('unavailable');}}), '');
21
+ assert.equal(readStoredSessionToken(null), '');
22
+ });
@@ -1,6 +1,7 @@
1
1
  export const CIELO_CONFIG_KEY = 'CIELO';
2
2
  export const NEW_RELIC_CONFIG_KEY = 'NEW_RELIC';
3
3
  export const SPOTIFY_CONFIG_KEY = 'SPOTIFY';
4
+ export const SEM_PARAR_CONFIG_KEY = 'SEM_PARAR';
4
5
 
5
6
  export const DEFAULT_CIELO_CONFIG = {
6
7
  ACCESS_TOKEN: '',
@@ -23,6 +24,21 @@ export const DEFAULT_SPOTIFY_CONFIG = {
23
24
  CLIENT_SECRET: '',
24
25
  };
25
26
 
27
+ /**
28
+ * Company-scoped Sem Parar credentials for vale-pedágio emission.
29
+ * ENABLED: "1" | "0"
30
+ * ENVIRONMENT: "sandbox" | "production"
31
+ */
32
+ export const DEFAULT_SEM_PARAR_CONFIG = {
33
+ ENABLED: '0',
34
+ CLIENT_ID: '',
35
+ CLIENT_SECRET: '',
36
+ USERNAME: '',
37
+ PASSWORD: '',
38
+ ENVIRONMENT: 'sandbox',
39
+ CONVENIADO: '',
40
+ };
41
+
26
42
  const isConfigMap = value =>
27
43
  value && typeof value === 'object' && !Array.isArray(value);
28
44
 
@@ -78,3 +94,10 @@ export const resolveSpotifyConfig = configs =>
78
94
  SPOTIFY_CONFIG_KEY,
79
95
  DEFAULT_SPOTIFY_CONFIG,
80
96
  );
97
+
98
+ export const resolveSemPararConfig = configs =>
99
+ resolveIntegrationConfig(
100
+ configs,
101
+ SEM_PARAR_CONFIG_KEY,
102
+ DEFAULT_SEM_PARAR_CONFIG,
103
+ );
@@ -0,0 +1,18 @@
1
+ // Quasar LocalStorage serializes objects with this marker; plain JSON is also used.
2
+ const OBJECT_PREFIX = '__q_objt|';
3
+
4
+ const readStoredSessionToken = (storage = typeof localStorage === 'undefined' ? null : localStorage) => {
5
+ try {
6
+ const raw = storage?.getItem?.('session');
7
+ if (!raw) return '';
8
+ const json = typeof raw === 'string' && raw.startsWith(OBJECT_PREFIX)
9
+ ? raw.slice(OBJECT_PREFIX.length)
10
+ : raw;
11
+ const session = JSON.parse(json);
12
+ return session?.token || session?.api_key || '';
13
+ } catch {
14
+ return '';
15
+ }
16
+ };
17
+
18
+ module.exports = {readStoredSessionToken};