mkfashion-sdk 2.3.0 → 2.3.2

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 (3) hide show
  1. package/index.html +66 -46
  2. package/package.json +1 -1
  3. package/src/mkfashion.js +72 -446
package/index.html CHANGED
@@ -1,67 +1,87 @@
1
1
  <!DOCTYPE html>
2
- <html>
3
-
2
+ <html lang="pt-BR">
4
3
  <head>
5
4
  <meta charset="UTF-8">
6
- <title>Integração mKFashion</title>
7
- <!-- Para testar localmente, use o caminho local -->
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Provador Virtual</title>
8
7
  <script src="./src/mkfashion.js"></script>
9
- <!-- Para produção, use o CDN: -->
10
- <!-- <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script> -->
11
- <style>
12
- .btn-provar {
13
- background: #000;
14
- color: #fff;
15
- padding: 12px 24px;
16
- border: none;
17
- border-radius: 8px;
18
- cursor: pointer;
19
- font-size: 16px;
20
- display: none;
21
- }
22
-
23
- .btn-provar:hover {
24
- background: #333;
25
- }
26
- </style>
27
8
  </head>
28
-
29
9
  <body>
30
10
 
31
- <h1>Produto XYZ</h1>
32
- <p>SKU: 165230</p>
33
-
34
- <button class="btn-provar" id="btn-provar">
35
- Provador Virtual
36
- </button>
11
+ <button id="btn-provar" style="display: none;">Provar Virtualmente</button>
37
12
 
38
13
  <script>
39
- // 1. Verifica disponibilidade e configura botão
40
- mkfashion.isAvailable('309728').then(function (disponivel) {
41
- if (disponivel) {
14
+ (function() {
15
+ var projectid = '698c7cc61d3129430f15dddc';
16
+ var identifier = '16255';
17
+
18
+ function initMkFashion() {
19
+ mkfashion.addToCart(function(payload) {
20
+ console.log('Adicionando ao carrinho:', payload);
21
+
22
+ var variantSku = payload.selectedIdentifier;
42
23
 
43
- // 2. Registra callback do carrinho (ANTES de abrir)
44
- mkfashion.addToCart(function (payload) {
45
- console.log('Payload completo:', JSON.stringify(payload, null, 2));
24
+ fetch('/cart/add.js', {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ },
29
+ body: JSON.stringify({
30
+ items: [{
31
+ quantity: 1,
32
+ id: variantSku
33
+ }]
34
+ })
35
+ })
36
+ .then(function(response) {
37
+ return response.json();
38
+ })
39
+ .then(function(data) {
40
+ console.log('Produto adicionado:', data);
41
+ // document.dispatchEvent(new CustomEvent('cart:updated'));
42
+ })
43
+ .catch(function(error) {
44
+ console.error('Erro carrinho:', error);
45
+ });
46
46
  });
47
47
 
48
+ mkfashion.isAvailable(projectid, identifier)
49
+ .then(function(disponivel) {
50
+ if (disponivel) {
51
+ var button = document.getElementById('btn-provar');
48
52
 
49
- console.log('✅ Produto SKU 306636 disponível para prova virtual');
50
- var btn = document.getElementById('btn-provar');
51
- btn.style.display = 'inline-block';
53
+ if (button) {
54
+ button.style.display = 'inline-block';
52
55
 
53
- btn.onclick = function () {
54
- mkfashion.open({
55
- store: 'gregory',
56
- identifier: '165182'
56
+ button.onclick = function() {
57
+ mkfashion.open({
58
+ projectid: projectid,
59
+ identifier: identifier
60
+ });
61
+ };
62
+ }
63
+ }
64
+ })
65
+ .catch(function(error) {
66
+ console.error('Erro disponibilidade MK Fashion:', error);
57
67
  });
58
- };
68
+ }
69
+
70
+ function waitForMkFashion() {
71
+ if (typeof mkfashion !== 'undefined') {
72
+ initMkFashion();
73
+ } else {
74
+ setTimeout(waitForMkFashion, 100);
75
+ }
76
+ }
77
+
78
+ if (document.readyState === "loading") {
79
+ document.addEventListener("DOMContentLoaded", waitForMkFashion);
59
80
  } else {
60
- console.log('❌ Produto SKU 306636 NÃO disponível para prova virtual');
81
+ waitForMkFashion();
61
82
  }
62
- });
83
+ })();
63
84
  </script>
64
85
 
65
86
  </body>
66
-
67
87
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mkfashion-sdk",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "SDK para integrar o provador virtual mKFashion com suporte a Wake Commerce",
5
5
  "main": "src/mkfashion.js",
6
6
  "scripts": {
package/src/mkfashion.js CHANGED
@@ -1,36 +1,15 @@
1
1
  /**
2
- * @fileoverview mKFashion SDK - Integração de Provador Virtual
3
- * SDK para integrar o provador virtual mKFashion em qualquer site.
4
- * Fornece métodos para abrir o provador virtual, verificar disponibilidade
5
- * de produtos e gerenciar interações com o carrinho.
6
- *
2
+ * mKFashion SDK - Integração de Provador Virtual
7
3
  * @version 1.0.0
8
4
  * @author metaKosmos
9
5
  *
10
6
  * @example
11
- * // Instalação via unpkg
12
7
  * <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script>
13
8
  *
14
- * @example
15
- * // Uso básico - Abrir provador virtual
16
- * mkfashion.open({
17
- * projectId: 'gregory', // aliases: projectid, store
18
- * identifier: '308088' // alias: sku
19
- * });
20
- *
21
- * @example
22
- * // Verificar disponibilidade antes de mostrar botão
23
- * const disponivel = await mkfashion.isAvailable('gregory', '165230');
24
- * if (disponivel) {
25
- * // Mostrar botão de prova virtual
26
- * }
9
+ * mkfashion.open({ projectId: 'gregory', identifier: '308088' });
27
10
  *
28
- * @example
29
- * // Tratar adicionar ao carrinho
30
11
  * mkfashion.addToCart((payload) => {
31
- * console.log('Produto:', payload.product);
32
- * console.log('Tamanho:', payload.size);
33
- * // Adicionar ao seu carrinho e-commerce
12
+ * console.log(payload.name, payload.selectedSize, payload.selectedIdentifier);
34
13
  * });
35
14
  */
36
15
 
@@ -38,81 +17,25 @@ const mkfashion = {
38
17
 
39
18
  // ============ CONFIGURACAO ============
40
19
 
41
- /**
42
- * URL base da aplicação visualizador
43
- * @type {string}
44
- * @default 'https://mkfashion.mk3dlabs.com/visualizer'
45
- */
46
20
  appUrl: 'https://mkfashion.mk3dlabs.com/visualizer',
47
-
48
- /**
49
- * URL base da API mKFashion
50
- * @type {string}
51
- * @default 'https://mkfashion-new-api.mk3dlabs.com'
52
- */
53
21
  apiUrl: 'https://mkfashion-new-api.mk3dlabs.com',
22
+ debug: false,
54
23
 
55
24
  // DEV - Descomentar para desenvolvimento local
56
25
  // appUrl: 'http://localhost:5174',
57
26
  // apiUrl: 'http://localhost:3007',
58
27
 
59
- /**
60
- * Habilita logs de debug no console
61
- * @type {boolean}
62
- * @default false
63
- */
64
- debug: false,
65
-
66
28
  // ============ ESTADO INTERNO ============
67
29
 
68
- /**
69
- * Elemento iframe do visualizador
70
- * @private
71
- * @type {?HTMLIFrameElement}
72
- */
73
30
  _iframe: null,
74
-
75
- /**
76
- * Elemento div do modal overlay
77
- * @private
78
- * @type {?HTMLDivElement}
79
- */
80
31
  _modal: null,
81
-
82
- /**
83
- * Indica se o modal está aberto
84
- * @private
85
- * @type {boolean}
86
- */
87
32
  _isOpen: false,
88
-
89
- /**
90
- * Configuração atual da sessão
91
- * @private
92
- * @type {?{projectId: string, identifier: string, width: number|string, height: number|string}}
93
- */
94
33
  _config: null,
95
-
96
- /**
97
- * Cache dos dados do último callback add_to_cart
98
- * Usado por getProduct() para evitar chamadas API desnecessárias
99
- * @private
100
- * @type {?Object}
101
- */
102
34
  _lastCartData: null,
35
+ _lastCartProductData: null, // cache completo do produto (para getProduct)
36
+ _escHandler: null,
37
+ _messageHandler: null,
103
38
 
104
- /**
105
- * Callbacks de eventos registrados
106
- * @private
107
- * @type {{
108
- * onReady: ?Function,
109
- * onClose: ?Function,
110
- * onAddToCart: ?Function,
111
- * onGenerationComplete: ?Function,
112
- * onProductLoaded: ?Function,
113
- * onError: ?Function
114
- * }}
115
- */
116
39
  _callbacks: {
117
40
  onReady: null,
118
41
  onClose: null,
@@ -122,51 +45,17 @@ const mkfashion = {
122
45
  onError: null
123
46
  },
124
47
 
125
- /**
126
- * Handler de evento ESC para fechar modal
127
- * @private
128
- * @type {?Function}
129
- */
130
- _escHandler: null,
131
-
132
- /**
133
- * Handler de evento postMessage para comunicação com iframe
134
- * @private
135
- * @type {?Function}
136
- */
137
- _messageHandler: null,
138
-
139
48
  // ============ METODOS PUBLICOS ============
140
49
 
141
50
  /**
142
- * Abre o modal do provador virtual para um produto específico
51
+ * Abre o modal do provador virtual.
52
+ * Valida disponibilidade antes de abrir.
143
53
  *
144
- * Valida a disponibilidade do produto antes de abrir. Se o produto não estiver
145
- * disponível para prova virtual, exibe um alerta e cancela a operação.
146
- *
147
- * @async
148
- * @param {Object} options - Opções de configuração
54
+ * @param {Object} options
149
55
  * @param {string} options.projectId - ID do projeto (aliases: projectid, store)
150
56
  * @param {string} options.identifier - Identificador do produto (alias: sku)
151
- * @param {number|string} [options.width=430] - Largura do modal em pixels ou valor CSS
152
- * @param {number|string} [options.height=800] - Altura do modal em pixels ou valor CSS
153
- * @returns {Promise<void>} Resolve quando o modal é aberto, ou rejeita em caso de erro
154
- *
155
- * @example
156
- * // Abrir com alias de loja
157
- * await mkfashion.open({
158
- * projectId: 'gregory',
159
- * identifier: '308088'
160
- * });
161
- *
162
- * @example
163
- * // Abrir com dimensões customizadas
164
- * await mkfashion.open({
165
- * store: 'gregory', // alias para projectId
166
- * sku: '308088', // alias para identifier
167
- * width: 500,
168
- * height: '90vh'
169
- * });
57
+ * @param {number|string} [options.width=430]
58
+ * @param {number|string} [options.height=800]
170
59
  */
171
60
  async open(options = {}) {
172
61
  if (this._isOpen) {
@@ -174,12 +63,10 @@ const mkfashion = {
174
63
  return
175
64
  }
176
65
 
177
- // Normaliza opções (compatibilidade com nomes alternativos)
178
66
  const raw = options.projectId || options.projectid || options.store
179
67
  const projectId = this._resolveProjectId(raw)
180
68
  const identifier = options.identifier || options.sku
181
69
 
182
- // Valida opções obrigatórias
183
70
  if (!projectId) {
184
71
  console.error('[mKFashion] projectId e obrigatorio')
185
72
  return
@@ -189,7 +76,6 @@ const mkfashion = {
189
76
  return
190
77
  }
191
78
 
192
- // Verifica disponibilidade antes de abrir
193
79
  try {
194
80
  const availability = await this.getAvailability(projectId, identifier)
195
81
  if (!availability.available) {
@@ -203,7 +89,6 @@ const mkfashion = {
203
89
  return
204
90
  }
205
91
 
206
- // Salva configuração
207
92
  this._config = {
208
93
  projectId: projectId,
209
94
  identifier: identifier,
@@ -218,15 +103,7 @@ const mkfashion = {
218
103
  this._log('Aberto', this._config)
219
104
  },
220
105
 
221
- /**
222
- * Fecha o modal do provador virtual
223
- *
224
- * Remove o modal do DOM e limpa os event listeners.
225
- * Dispara o callback onClose se registrado.
226
- *
227
- * @example
228
- * mkfashion.close();
229
- */
106
+ /** Fecha o modal do provador virtual */
230
107
  close() {
231
108
  if (!this._isOpen) {
232
109
  this._log('Ja esta fechado')
@@ -241,41 +118,12 @@ const mkfashion = {
241
118
  },
242
119
 
243
120
  /**
244
- * Registra um callback para tratar eventos de adicionar ao carrinho
245
- *
246
- * Chamado quando o usuário seleciona um tamanho e adiciona o produto ao carrinho
247
- * do visualizador. O payload inclui todos os dados do produto, tamanho selecionado
248
- * e múltiplos aliases de identificador para compatibilidade.
249
- *
250
- * @param {Function} callback - Função a ser chamada no add-to-cart
251
- * @param {Object} callback.payload - Dados do carrinho
252
- * @param {string} callback.payload.projectId - ID do projeto
253
- * @param {string} callback.payload.identifier - Identificador do produto
254
- * @param {string} [callback.payload.sku] - Alias do identifier (apenas projetos Gregory)
255
- * @param {Object} callback.payload.size - Objeto do tamanho selecionado
256
- * @param {string} callback.payload.size.label - Label do tamanho (ex: "M", "42")
257
- * @param {number} callback.payload.size.produtoVarianteId - ID da variante para analytics
258
- * @param {Object} callback.payload.product - Dados completos do produto
259
- *
260
- * @example
261
- * mkfashion.addToCart((payload) => {
262
- * const { size, product } = payload;
121
+ * Registra callback de adicionar ao carrinho.
263
122
  *
264
- * // Adicionar ao carrinho na sua plataforma e-commerce
265
- * MeuCarrinho.adicionar({
266
- * productId: payload.identifier,
267
- * variantId: size.produtoVarianteId,
268
- * quantidade: 1
269
- * });
123
+ * Payload simplificado (não-Gregory):
124
+ * { mainIdentifier, selectedIdentifier, name, price, sizePrice, selectedSize, productUrl, tryonImageUrl }
270
125
  *
271
- * // Rastrear analytics
272
- * gtag('event', 'add_to_cart', {
273
- * items: [{
274
- * item_id: payload.identifier,
275
- * item_variant: size.label
276
- * }]
277
- * });
278
- * });
126
+ * Projetos Gregory mantêm estrutura legada completa.
279
127
  */
280
128
  addToCart(callback) {
281
129
  if (typeof callback === 'function') {
@@ -286,17 +134,6 @@ const mkfashion = {
286
134
  }
287
135
  },
288
136
 
289
- /**
290
- * Registra um callback para executar quando o visualizador estiver pronto
291
- *
292
- * @param {Function} callback - Função a ser chamada quando pronto
293
- * @param {Object} callback.data - Dados do evento ready do visualizador
294
- *
295
- * @example
296
- * mkfashion.onReady((data) => {
297
- * console.log('Visualizador pronto:', data);
298
- * });
299
- */
300
137
  onReady(callback) {
301
138
  if (typeof callback === 'function') {
302
139
  this._callbacks.onReady = callback
@@ -304,17 +141,6 @@ const mkfashion = {
304
141
  }
305
142
  },
306
143
 
307
- /**
308
- * Registra um callback para executar quando o modal fechar
309
- *
310
- * @param {Function} callback - Função a ser chamada ao fechar
311
- *
312
- * @example
313
- * mkfashion.onClose(() => {
314
- * console.log('Modal fechado');
315
- * // Limpeza ou analytics
316
- * });
317
- */
318
144
  onClose(callback) {
319
145
  if (typeof callback === 'function') {
320
146
  this._callbacks.onClose = callback
@@ -322,17 +148,6 @@ const mkfashion = {
322
148
  }
323
149
  },
324
150
 
325
- /**
326
- * Registra um callback para executar quando a geração de imagem for concluída
327
- *
328
- * @param {Function} callback - Função a ser chamada quando a geração completar
329
- * @param {Object} callback.data - Dados da geração concluída
330
- *
331
- * @example
332
- * mkfashion.onGenerationComplete((data) => {
333
- * console.log('Geração concluída:', data);
334
- * });
335
- */
336
151
  onGenerationComplete(callback) {
337
152
  if (typeof callback === 'function') {
338
153
  this._callbacks.onGenerationComplete = callback
@@ -340,17 +155,6 @@ const mkfashion = {
340
155
  }
341
156
  },
342
157
 
343
- /**
344
- * Registra um callback para tratar erros do visualizador
345
- *
346
- * @param {Function} callback - Função a ser chamada em caso de erro
347
- * @param {Object} callback.data - Dados do erro
348
- *
349
- * @example
350
- * mkfashion.onError((data) => {
351
- * console.error('Erro no visualizador:', data);
352
- * });
353
- */
354
158
  onError(callback) {
355
159
  if (typeof callback === 'function') {
356
160
  this._callbacks.onError = callback
@@ -358,17 +162,6 @@ const mkfashion = {
358
162
  }
359
163
  },
360
164
 
361
- /**
362
- * Registra um callback para executar quando o produto for carregado
363
- *
364
- * @param {Function} callback - Função a ser chamada quando produto carregar
365
- * @param {Object} callback.data - Dados do produto carregado
366
- *
367
- * @example
368
- * mkfashion.onProductLoaded((data) => {
369
- * console.log('Produto carregado:', data);
370
- * });
371
- */
372
165
  onProductLoaded(callback) {
373
166
  if (typeof callback === 'function') {
374
167
  this._callbacks.onProductLoaded = callback
@@ -376,14 +169,7 @@ const mkfashion = {
376
169
  }
377
170
  },
378
171
 
379
- /**
380
- * Reinicia a experiência do provador virtual
381
- *
382
- * Recarrega o iframe com a mesma configuração, reiniciando a sessão.
383
- *
384
- * @example
385
- * mkfashion.restart();
386
- */
172
+ /** Recarrega o iframe com a mesma configuração */
387
173
  restart() {
388
174
  if (!this._iframe || !this._config) {
389
175
  this._log('Nenhum iframe ativo')
@@ -394,21 +180,14 @@ const mkfashion = {
394
180
  this._log('Reiniciado')
395
181
  },
396
182
 
397
- /**
398
- * Destrói completamente a instância do SDK
399
- *
400
- * Fecha o modal, remove todos os event listeners, limpa cache e reseta callbacks.
401
- * Use quando não for mais utilizar o SDK na página.
402
- *
403
- * @example
404
- * mkfashion.destroy();
405
- */
183
+ /** Fecha modal, remove listeners, limpa cache e reseta callbacks */
406
184
  destroy() {
407
185
  this.close()
408
186
  this._iframe = null
409
187
  this._modal = null
410
188
  this._config = null
411
189
  this._lastCartData = null
190
+ this._lastCartProductData = null
412
191
  this._callbacks = {
413
192
  onReady: null,
414
193
  onClose: null,
@@ -420,16 +199,6 @@ const mkfashion = {
420
199
  this._log('Destruído')
421
200
  },
422
201
 
423
- /**
424
- * Retorna o estado atual do SDK
425
- *
426
- * @returns {{isOpen: boolean, config: ?Object}} Estado atual com isOpen e config
427
- *
428
- * @example
429
- * const status = mkfashion.getStatus();
430
- * console.log('Está aberto?', status.isOpen);
431
- * console.log('Configuração:', status.config);
432
- */
433
202
  getStatus() {
434
203
  return {
435
204
  isOpen: this._isOpen,
@@ -438,29 +207,10 @@ const mkfashion = {
438
207
  },
439
208
 
440
209
  /**
441
- * Verifica se o produto está disponível para try-on (versão simplificada)
442
- *
443
- * Retorna apenas true/false ao invés dos dados completos.
444
- * Se apenas um parâmetro for passado, assume que é o identifier e usa projeto padrão.
445
- *
446
- * @async
447
- * @param {string} projectId - ID do projeto (ex: 'gregory') ou identifier se único parâmetro
448
- * @param {string} [identifier] - Identificador do produto
449
- * @returns {Promise<boolean>} true se disponível, false caso contrário
450
- *
451
- * @example
452
- * // Com projectId e identifier
453
- * const disponivel = await mkfashion.isAvailable('gregory', '308088');
454
- * if (disponivel) {
455
- * // Mostrar botão
456
- * }
457
- *
458
- * @example
459
- * // Apenas identifier (usa projeto padrão)
460
- * const disponivel = await mkfashion.isAvailable('308088');
210
+ * Retorna true/false se produto está disponível para try-on.
211
+ * Se apenas 1 parâmetro, assume que é o identifier (usa projeto padrão).
461
212
  */
462
213
  async isAvailable(projectId, identifier) {
463
- // Se apenas 1 parâmetro, assume que é o identifier
464
214
  if (!identifier) {
465
215
  identifier = projectId
466
216
  projectId = '698c7e791d3129430f15dddd'
@@ -473,29 +223,7 @@ const mkfashion = {
473
223
  }
474
224
  },
475
225
 
476
- /**
477
- * Verifica disponibilidade do produto via API (retorna dados completos)
478
- *
479
- * @async
480
- * @param {string} projectId - ID do projeto (ex: 'gregory' ou UUID)
481
- * @param {string} identifier - Identificador do produto
482
- * @returns {Promise<Object>} Dados de disponibilidade da API com:
483
- * - available: boolean - Se produto está disponível
484
- * - message: string - Mensagem descritiva
485
- * - (outros campos conforme API)
486
- * @throws {Error} Se projectId ou identifier estiver faltando
487
- * @throws {Error} Se a requisição da API falhar
488
- *
489
- * @example
490
- * try {
491
- * const dados = await mkfashion.getAvailability('gregory', '308088');
492
- * if (dados.available) {
493
- * console.log('Disponível!', dados.message);
494
- * }
495
- * } catch (erro) {
496
- * console.error('Erro ao verificar:', erro);
497
- * }
498
- */
226
+ /** Verifica disponibilidade via API (retorna dados completos) */
499
227
  async getAvailability(projectId, identifier) {
500
228
  if (!projectId) {
501
229
  return Promise.reject(new Error('projectId e obrigatorio'))
@@ -526,17 +254,6 @@ const mkfashion = {
526
254
  }
527
255
  },
528
256
 
529
- /**
530
- * Lista todos os produtos disponíveis para try-on
531
- *
532
- * @async
533
- * @returns {Promise<Array>} Lista de produtos disponíveis
534
- * @throws {Error} Se a requisição da API falhar
535
- *
536
- * @example
537
- * const produtos = await mkfashion.getAvailableProducts();
538
- * console.log(`${produtos.length} produtos disponíveis`);
539
- */
540
257
  async getAvailableProducts() {
541
258
  this._log('Buscando produtos disponíveis')
542
259
 
@@ -558,19 +275,6 @@ const mkfashion = {
558
275
  }
559
276
  },
560
277
 
561
- /**
562
- * Busca feedbacks enviados pelos usuários (para testes e analytics)
563
- *
564
- * @async
565
- * @param {number} [page=1] - Página a buscar
566
- * @param {number} [limit=20] - Itens por página
567
- * @returns {Promise<Object>} Lista paginada de feedbacks
568
- * @throws {Error} Se a requisição da API falhar
569
- *
570
- * @example
571
- * const feedbacks = await mkfashion.getFeedback(1, 10);
572
- * console.log('Feedbacks:', feedbacks);
573
- */
574
278
  async getFeedback(page = 1, limit = 20) {
575
279
  this._log('Buscando feedbacks', { page, limit })
576
280
 
@@ -592,33 +296,8 @@ const mkfashion = {
592
296
  },
593
297
 
594
298
  /**
595
- * Busca dados completos do produto incluindo tamanhos, preços e estoque
596
- *
597
- * Este método implementa cache inteligente e lógica de fallback:
598
- * 1. Retorna dados cacheados se disponíveis do callback add_to_cart anterior
599
- * 2. Faz chamada API para /products/{projectId}/{identifier}
600
- * 3. Se retornar 404 e identifier parecer uma variante, tenta novamente com productId do config
601
- *
602
- * @async
603
- * @param {string} projectId - ID do projeto (ex: 'gregory' ou UUID)
604
- * @param {string} identifier - Identificador do produto (pode ser productId ou variantSku)
605
- * @returns {Promise<Object>} Dados do produto com estrutura:
606
- * - success: boolean
607
- * - data: Objeto do produto (compatibilidade com bundle Gregory)
608
- * - product: Objeto do produto (compatibilidade com código legado)
609
- * @throws {Error} Se projectId ou identifier estiver faltando
610
- * @throws {Error} Se a requisição da API falhar
611
- *
612
- * @example
613
- * // Buscar dados do produto
614
- * const resultado = await mkfashion.getProduct('gregory', '308088');
615
- * console.log(resultado.data.sizes); // Para bundle Gregory
616
- * console.log(resultado.product.price); // Para código legado
617
- *
618
- * @example
619
- * // Funciona com SKU de variante (usa fallback)
620
- * const resultado = await mkfashion.getProduct('gregory', '302509');
621
- * // Se 302509 for uma variante, tenta novamente com productId principal
299
+ * Busca dados do produto via API.
300
+ * Usa cache do add_to_cart se disponível. Fallback automático se identifier for variantSku.
622
301
  */
623
302
  async getProduct(projectId, identifier) {
624
303
  if (!projectId) {
@@ -628,12 +307,10 @@ const mkfashion = {
628
307
  return Promise.reject(new Error('identifier e obrigatorio'))
629
308
  }
630
309
 
631
- // Se temos dados cacheados do add_to_cart, retorna direto (evita chamada API)
632
- // Isso resolve o caso onde o caller passa variantSku ao invés de productId
633
- if (this._lastCartData?.product) {
634
- const cached = this._lastCartData
310
+ // Retorna do cache se disponível (evita chamada API após add_to_cart)
311
+ if (this._lastCartProductData?.product) {
312
+ const cached = this._lastCartProductData
635
313
  const product = cached.product
636
- // Verifica se o identifier bate com algum campo do produto cacheado
637
314
  const isMatch = identifier === cached.identifier ||
638
315
  identifier === product.identifier ||
639
316
  identifier === product.variantSku ||
@@ -641,8 +318,6 @@ const mkfashion = {
641
318
  String(identifier) === String(product.produtoVarianteId)
642
319
  if (isMatch) {
643
320
  this._log('Produto retornado do cache (add_to_cart)', { identifier })
644
- // Retorna com ambas as chaves (data + product) para compatibilidade
645
- // Bundle Gregory usa t.data.produtoVarianteId
646
321
  return { success: true, data: product, product: product }
647
322
  }
648
323
  }
@@ -655,8 +330,7 @@ const mkfashion = {
655
330
  const response = await fetch(url)
656
331
 
657
332
  if (!response.ok) {
658
- // Fallback: se retornou 404 e temos o identifier do config (productId correto),
659
- // tenta com ele (caller pode ter passado variantSku ao invés de productId)
333
+ // Fallback: tenta com productId do config caso caller tenha passado variantSku
660
334
  if (response.status === 404 && this._config?.identifier && this._config.identifier !== identifier) {
661
335
  this._log(`Identifier ${identifier} não encontrado, tentando com productId: ${this._config.identifier}`)
662
336
  const fallbackUrl = `${this.apiUrl}/products/${resolved}/${this._config.identifier}`
@@ -683,12 +357,6 @@ const mkfashion = {
683
357
 
684
358
  // ============ METODOS PRIVADOS ============
685
359
 
686
- /**
687
- * Registra mensagens de debug se o modo debug estiver habilitado
688
- * @private
689
- * @param {string} message - Mensagem para registrar
690
- * @param {*} [data] - Dados opcionais para registrar
691
- */
692
360
  _log(message, data = null) {
693
361
  if (this.debug) {
694
362
  if (data) {
@@ -699,45 +367,21 @@ const mkfashion = {
699
367
  }
700
368
  },
701
369
 
702
- /**
703
- * Mapeamento de aliases de ID de projeto
704
- * Mapeia nomes amigáveis de loja para UUIDs internos de projeto
705
- * @private
706
- * @type {Object.<string, string>}
707
- */
708
370
  _storeAliases: {
709
371
  'gregory': '698c7e791d3129430f15dddd'
710
372
  },
711
373
 
712
- /**
713
- * Resolve ID de projeto a partir de alias ou UUID
714
- * @private
715
- * @param {string} projectId - ID do projeto ou alias (ex: 'gregory')
716
- * @returns {string} UUID do projeto resolvido
717
- */
718
374
  _resolveProjectId(projectId) {
719
375
  if (!projectId) return '698c7e791d3129430f15dddd'
720
376
  const key = String(projectId).toLowerCase()
721
377
  return this._storeAliases[key] || projectId
722
378
  },
723
379
 
724
- /**
725
- * Verifica se o projeto é Gregory (requer aliases legados)
726
- * @private
727
- * @param {string} projectId - UUID do projeto já resolvido
728
- * @returns {boolean}
729
- */
730
380
  _isGregoryProject(projectId) {
731
381
  return projectId === '698c7e791d3129430f15dddd' ||
732
382
  String(projectId).toLowerCase() === 'gregory'
733
383
  },
734
384
 
735
- /**
736
- * Dispara um callback registrado se ele existir
737
- * @private
738
- * @param {string} name - Nome do callback (ex: 'onReady')
739
- * @param {*} [data] - Dados para passar ao callback
740
- */
741
385
  _triggerCallback(name, data = null) {
742
386
  if (this._callbacks && typeof this._callbacks[name] === 'function') {
743
387
  try {
@@ -749,20 +393,10 @@ const mkfashion = {
749
393
  }
750
394
  },
751
395
 
752
- /**
753
- * Constrói a URL do iframe para o visualizador
754
- * @private
755
- * @returns {string} URL completa com projectId e identifier
756
- */
757
396
  _buildUrl() {
758
397
  return `${this.appUrl}/${this._config.projectId}/${this._config.identifier}`
759
398
  },
760
399
 
761
- /**
762
- * Cria e exibe o overlay modal com iframe
763
- * Gerencia estado de loading, animações e event listeners
764
- * @private
765
- */
766
400
  _openModal() {
767
401
  this._modal = document.createElement('div')
768
402
  this._modal.style.cssText = `
@@ -781,7 +415,6 @@ const mkfashion = {
781
415
  transition: opacity 0.3s ease;
782
416
  `
783
417
 
784
- // Container para loading + iframe
785
418
  const container = document.createElement('div')
786
419
  const { width, height } = this._config
787
420
  container.style.cssText = `
@@ -798,7 +431,6 @@ const mkfashion = {
798
431
  transition: transform 0.3s ease;
799
432
  `
800
433
 
801
- // Loading indicator (mostra imediatamente)
802
434
  const loader = document.createElement('div')
803
435
  loader.className = 'mkfashion-loader'
804
436
  loader.innerHTML = `
@@ -840,7 +472,6 @@ const mkfashion = {
840
472
  `
841
473
  container.appendChild(loader)
842
474
 
843
- // Iframe (carrega em background)
844
475
  this._iframe = this._createIframe()
845
476
  this._iframe.style.cssText = `
846
477
  position: absolute;
@@ -853,7 +484,6 @@ const mkfashion = {
853
484
  transition: opacity 0.3s ease;
854
485
  `
855
486
 
856
- // Quando iframe carregar, esconde o loading
857
487
  this._iframe.onload = () => {
858
488
  loader.style.opacity = '0'
859
489
  this._iframe.style.opacity = '1'
@@ -864,7 +494,6 @@ const mkfashion = {
864
494
  this._modal.appendChild(container)
865
495
  document.body.appendChild(this._modal)
866
496
 
867
- // Guarda referencia do container
868
497
  this._container = container
869
498
 
870
499
  requestAnimationFrame(() => {
@@ -886,11 +515,6 @@ const mkfashion = {
886
515
  document.addEventListener('keydown', this._escHandler)
887
516
  },
888
517
 
889
- /**
890
- * Fecha e remove o modal do DOM
891
- * Inclui animação de fade-out
892
- * @private
893
- */
894
518
  _closeModal() {
895
519
  if (!this._modal) return
896
520
 
@@ -910,11 +534,6 @@ const mkfashion = {
910
534
  }
911
535
  },
912
536
 
913
- /**
914
- * Cria o elemento iframe configurado
915
- * @private
916
- * @returns {HTMLIFrameElement} Elemento iframe configurado
917
- */
918
537
  _createIframe() {
919
538
  const { width, height } = this._config
920
539
  const iframe = document.createElement('iframe')
@@ -927,11 +546,6 @@ const mkfashion = {
927
546
  return iframe
928
547
  },
929
548
 
930
- /**
931
- * Configura listener postMessage para comunicação com iframe
932
- * Trata eventos: close_request, ready, add_to_cart, generation_complete, etc.
933
- * @private
934
- */
935
549
  _setupMessageListener() {
936
550
  this._messageHandler = (event) => {
937
551
  if (!event.data || event.data.source !== 'mkfashion-app') {
@@ -963,40 +577,57 @@ const mkfashion = {
963
577
  case 'add_to_cart':
964
578
  this._log('Adicionar ao carrinho', data)
965
579
 
966
- // Prioriza valores do frontend (data), usa _config como fallback
967
580
  const identifierValue = data.identifier || this._config.identifier
968
581
  const projectIdValue = data.projectId || this._config.projectId
969
582
 
970
- const callbackPayload = {
971
- ...data, // spread primeiro
972
- size: data?.size || null,
973
- product: data?.product || null,
974
- // Prioriza data (frontend), usa _config como fallback
975
- projectId: projectIdValue,
976
- identifier: identifierValue
583
+ // Cache interno completo (para getProduct)
584
+ this._lastCartProductData = {
585
+ identifier: identifierValue,
586
+ product: data?.product || null
977
587
  }
978
588
 
979
- // Aliases legados para projetos Gregory
980
- if (callbackPayload.product && this._isGregoryProject(projectIdValue)) {
981
- // Bundle Gregory usa n.sku no top-level para analytics
982
- callbackPayload.sku = identifierValue
983
-
984
- const p = callbackPayload.product
985
- p.productID = identifierValue
986
- p.Identifier = identifierValue
987
- p.nome = p.name
988
- p.cor = p.color
989
- p.preco = { de: p.compareAtPrice, por: p.price }
990
- // Fallback: variantSku > produtoVarianteId > identifier
991
- p.sizeSku = p.variantSku || p.produtoVarianteId || identifierValue
992
- p.productVariantId = p.produtoVarianteId || p.variantSku
993
- p.imagem = p.originalImageUrl
994
- p.url = p.productUrl
589
+ let callbackPayload
590
+
591
+ if (this._isGregoryProject(projectIdValue)) {
592
+ // Fluxo Gregory - payload legado completo
593
+ callbackPayload = {
594
+ ...data,
595
+ size: data?.size || null,
596
+ product: data?.product || null,
597
+ projectId: projectIdValue,
598
+ identifier: identifierValue
599
+ }
600
+
601
+ if (callbackPayload.product) {
602
+ callbackPayload.sku = identifierValue
603
+
604
+ const p = callbackPayload.product
605
+ p.productID = identifierValue
606
+ p.Identifier = identifierValue
607
+ p.nome = p.name
608
+ p.cor = p.color
609
+ p.preco = { de: p.compareAtPrice, por: p.price }
610
+ p.sizeSku = p.variantSku || p.produtoVarianteId || identifierValue
611
+ p.productVariantId = p.produtoVarianteId || p.variantSku
612
+ p.imagem = p.originalImageUrl
613
+ p.url = p.productUrl
614
+ }
615
+ } else {
616
+ // Fluxo simplificado
617
+ const product = data?.product || {}
618
+ callbackPayload = {
619
+ mainIdentifier: identifierValue,
620
+ selectedIdentifier: product.variantSku || null,
621
+ name: product.name || null,
622
+ price: product.price || null,
623
+ sizePrice: product.sizePrice || null,
624
+ selectedSize: data?.size || null,
625
+ productUrl: product.productUrl || null,
626
+ tryonImageUrl: product.tryonImageUrl || null
627
+ }
995
628
  }
996
629
 
997
- // Cache dos dados para getProduct (evita chamada API desnecessária)
998
630
  this._lastCartData = callbackPayload
999
-
1000
631
  this._triggerCallback('onAddToCart', callbackPayload)
1001
632
  break
1002
633
 
@@ -1019,10 +650,6 @@ const mkfashion = {
1019
650
  this._log('Listener de mensagens ativado')
1020
651
  },
1021
652
 
1022
- /**
1023
- * Remove listener postMessage
1024
- * @private
1025
- */
1026
653
  _removeMessageListener() {
1027
654
  if (this._messageHandler) {
1028
655
  window.removeEventListener('message', this._messageHandler)
@@ -1032,7 +659,6 @@ const mkfashion = {
1032
659
  }
1033
660
  }
1034
661
 
1035
- // Disponibiliza globalmente
1036
662
  if (typeof window !== 'undefined') {
1037
663
  window.mkfashion = mkfashion
1038
664
  }