@rocketsearch/vue-uappi 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Dados de produto vindos da própria Uappi.
3
+ *
4
+ * A Rocket decide ordem/filtro/paginação; o card mostra o produto como a loja o tem
5
+ * (preço, parcelamento, selos, rota). É o mesmo desenho da Linx, que pedia só id,price
6
+ * à Rocket e renderizava pelo widget nativo product_list_by_id.
7
+ *
8
+ * Aqui o equivalente é a vitrine "últimos vistos" da Front API: recebe uma lista de ids
9
+ * e devolve os produtos completos, na ordem pedida (conferido na homolog Daikin com 24
10
+ * ids). Produto inativo/indisponível é omitido — por isso a reordenação abaixo.
11
+ */
12
+
13
+ // `uappiUrl` = origem da loja (o VITE_REQUEST_URL do tema). Mesmo cliente do tema: fetch
14
+ // em /api/v2/front com o app-token fixo da plataforma.
15
+ export async function fetchUappiProducts (uappiUrl, ids) {
16
+ const list = (ids || []).map(String).filter(Boolean);
17
+ if (!list.length) return [];
18
+
19
+ const params = new URLSearchParams({ productId: 0, seenProducts: list.join(';'), limit: list.length });
20
+ const res = await fetch(uappiUrl + '/api/v2/front/showcase/products/ultimos-vistos?' + params, {
21
+ headers: { 'app-token': 'wapstore', Accept: 'application/json' }
22
+ });
23
+ if (!res.ok) throw new Error('Uappi respondeu ' + res.status);
24
+ const data = await res.json();
25
+ const byId = {};
26
+ ((data && data.produtos) || []).forEach((p) => {
27
+ if (p && p.id != null) byId[String(p.id)] = p;
28
+ });
29
+ return list.map(id => byId[id]).filter(Boolean);
30
+ }
31
+
32
+ // Tamanhos de imagem da Uappi, do menor para o maior. Se o pedido não existir no
33
+ // produto, usa o vizinho mais próximo (mesma regra do mediaSize da Linx).
34
+ const IMAGE_SIZES = ['thumb', 'small', 'medium', 'big', 'zoom'];
35
+
36
+ export function productImage (product, size) {
37
+ const imagens = product && product.midias && product.midias.imagens;
38
+ const arquivos = Array.isArray(imagens) && imagens[0] && imagens[0].arquivos;
39
+ if (!arquivos) return '';
40
+
41
+ let start = IMAGE_SIZES.indexOf(String(size || '').toLowerCase());
42
+ if (start < 0) start = IMAGE_SIZES.indexOf('medium');
43
+ for (let step = 0; step < IMAGE_SIZES.length; step++) {
44
+ const up = IMAGE_SIZES[start + step];
45
+ if (up && arquivos[up]) return arquivos[up];
46
+ const down = IMAGE_SIZES[start - step];
47
+ if (down && arquivos[down]) return arquivos[down];
48
+ }
49
+ return '';
50
+ }
51
+
52
+ export function productPath (product) {
53
+ if (product && product.rota && product.rota.route) return product.rota.route;
54
+ if (product && product.url) {
55
+ try {
56
+ return new URL(product.url).pathname;
57
+ }
58
+ catch (e) {
59
+ return product.url;
60
+ }
61
+ }
62
+ return '';
63
+ }
64
+
65
+ export function productPrice (product) {
66
+ const precos = product && product.precos;
67
+ if (!precos) return null;
68
+ const value = precos.por != null ? precos.por : precos.vista;
69
+ const n = Number(value);
70
+ return isFinite(n) && n > 0 ? n : null;
71
+ }
72
+
73
+ export function formatCurrency (value) {
74
+ if (typeof value !== 'number' || isNaN(value)) return '';
75
+ return value.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
76
+ }