@teddy-dev/frontend 1.0.1

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 (112) hide show
  1. package/algolia/algolia-loader.js +56 -0
  2. package/algolia/algolia-search.js +222 -0
  3. package/auth/teddy-auth-login.js +29 -0
  4. package/auth/teddy-auth-profile.js +58 -0
  5. package/auth/teddy-auth-register.js +52 -0
  6. package/auth/teddy-auth-reset.js +39 -0
  7. package/auth/teddy-auth.js +92 -0
  8. package/bantoa/bantoa-product.js +64 -0
  9. package/bantoa/bantoa-search.js +46 -0
  10. package/bantoa/bantoa-stylemix.js +43 -0
  11. package/bantoa/bantoa.js +21 -0
  12. package/cart/teddy-cart-controller.js +163 -0
  13. package/cart/teddy-cart-customer.js +86 -0
  14. package/cart/teddy-cart-discounts.js +55 -0
  15. package/cart/teddy-cart-promo-apply.js +24 -0
  16. package/cart/teddy-cart-promo-error.js +38 -0
  17. package/cart/teddy-cart-promo-loading.js +20 -0
  18. package/cart/teddy-cart-promo.js +96 -0
  19. package/components/mc-btn.js +38 -0
  20. package/components/mc-card-render.js +33 -0
  21. package/components/mc-cart-counter.js +14 -0
  22. package/components/mc-cart-error.js +35 -0
  23. package/components/mc-cart-quantity.js +43 -0
  24. package/components/mc-cart-remove.js +32 -0
  25. package/components/mc-copy.js +33 -0
  26. package/components/mc-element.js +84 -0
  27. package/components/mc-form-errors.js +35 -0
  28. package/components/mc-form-success.js +31 -0
  29. package/components/mc-form.js +223 -0
  30. package/components/mc-input-area.js +13 -0
  31. package/components/mc-input-checkbox-group.js +52 -0
  32. package/components/mc-input-checkbox.js +12 -0
  33. package/components/mc-input-password.js +39 -0
  34. package/components/mc-input-places.js +43 -0
  35. package/components/mc-input-quantity.js +43 -0
  36. package/components/mc-input-select.js +14 -0
  37. package/components/mc-input-text.js +12 -0
  38. package/components/mc-input.js +137 -0
  39. package/components/mc-loader.js +21 -0
  40. package/components/mc-modal.js +69 -0
  41. package/components/mc-password-eye.js +24 -0
  42. package/components/mc-password-tips.js +60 -0
  43. package/components/mc-qrcode.js +41 -0
  44. package/components/mc-range.js +108 -0
  45. package/components/mc-read-more.js +56 -0
  46. package/components/mc-recommended.js +50 -0
  47. package/components/mc-referrer.js +20 -0
  48. package/components/mc-splash-controller.js +32 -0
  49. package/components/mc-splash-link.js +65 -0
  50. package/components/mc-stoq.js +30 -0
  51. package/components/mc-swiper.js +333 -0
  52. package/components/mc-video.js +61 -0
  53. package/css/bootstrap-lg.css +2762 -0
  54. package/css/bootstrap-lg.min.css +1 -0
  55. package/css/bootstrap-md.css +2762 -0
  56. package/css/bootstrap-md.min.css +1 -0
  57. package/css/bootstrap-sm.css +2762 -0
  58. package/css/bootstrap-sm.min.css +1 -0
  59. package/css/bootstrap-xl.css +2790 -0
  60. package/css/bootstrap-xl.min.css +1 -0
  61. package/css/bootstrap-xxl.css +2762 -0
  62. package/css/bootstrap-xxl.min.css +1 -0
  63. package/css/bootstrap.css +9824 -0
  64. package/css/bootstrap.min.css +5 -0
  65. package/css/mc-form-errors.css +3 -0
  66. package/css/mc-loader.css +6 -0
  67. package/css/mc-password-eye.css +6 -0
  68. package/css/mc-password-tips.css +6 -0
  69. package/css/mc-read-more.css +14 -0
  70. package/css/mc-video.css +4 -0
  71. package/css/mc-wishlist-hero-btn.css +7 -0
  72. package/loader.js +110 -0
  73. package/loyalty/teddy-loyalty-create.js +40 -0
  74. package/loyalty/teddy-loyalty-redeem.js +38 -0
  75. package/loyalty/teddy-loyalty.js +214 -0
  76. package/package.json +20 -0
  77. package/res/mc-events.js +43 -0
  78. package/res/mc-shopify.js +439 -0
  79. package/res/mc-utils.js +119 -0
  80. package/res/mc-vue.js +9350 -0
  81. package/returns/teddy-return-iban.js +115 -0
  82. package/returns/teddy-return-list.js +165 -0
  83. package/returns/teddy-return-request.js +353 -0
  84. package/scripts/publish-store.js +62 -0
  85. package/test/auth-login-error.json +4 -0
  86. package/test/auth-login-success.json +13 -0
  87. package/test/auth-password-change-error.json +4 -0
  88. package/test/auth-password-change-success.json +3 -0
  89. package/test/auth-register-error.json +4 -0
  90. package/test/auth-register-success.json +12 -0
  91. package/test/auth-reset-error.json +4 -0
  92. package/test/auth-reset-success.json +3 -0
  93. package/test/loyalty-error.json +4 -0
  94. package/test/loyalty-noinfo.json +18 -0
  95. package/test/loyalty-redeem-error.json +4 -0
  96. package/test/loyalty-redeem-success.json +11 -0
  97. package/test/loyalty-success.json +143 -0
  98. package/test/returns-create-success.json +1 -0
  99. package/test/returns-get-success.json +35 -0
  100. package/test/returns-get-tracking.json +30 -0
  101. package/test/returns-list-empty.json +4 -0
  102. package/test/returns-list-success.json +59 -0
  103. package/test/returns-search-manual.json +67 -0
  104. package/test/returns-search-success.json +76 -0
  105. package/test/wishlist-error.json +4 -0
  106. package/test/wishlist-success.json +3 -0
  107. package/wishlist/teddy-wishlist-btn.js +55 -0
  108. package/wishlist/teddy-wishlist-clear.js +18 -0
  109. package/wishlist/teddy-wishlist-counter.js +35 -0
  110. package/wishlist/teddy-wishlist-item.js +46 -0
  111. package/wishlist/teddy-wishlist-page.js +59 -0
  112. package/wishlist/teddy-wishlist.js +131 -0
@@ -0,0 +1,56 @@
1
+ await loadComponent('./components/mc-element.js', false);
2
+ await loadComponent('./res/mc-shopify.js', false);
3
+
4
+ class AlgoliaLoader extends McElement {
5
+ template;
6
+
7
+ connectedCallback() {
8
+ this.template = this.innerHTML;
9
+ if(window.lastAlgoliaResponse) this.onLoad({detail: window.lastAlgoliaResponse});
10
+ window.addEventListener('algolia-search-complete', this.onLoad.bind(this));
11
+ this.addEventListener('click', this.onClick.bind(this));
12
+
13
+ const observer = new IntersectionObserver((entries) => {
14
+ entries.forEach(entry => {
15
+ if(entry.isIntersecting) {
16
+ this.onClick();
17
+ }
18
+ });
19
+ }, { rootMargin: '300px' });
20
+
21
+ observer.observe(this);
22
+ }
23
+
24
+ onClick = (e) => {
25
+ e?.preventDefault();
26
+ window.dispatchEvent(new CustomEvent('algolia-load-more'));
27
+ }
28
+
29
+ onLoad = (e) => {
30
+ const data = e.detail;
31
+ console.log('algolia-search-complete', data);
32
+
33
+ if(!data) {
34
+ console.log('AlgoliaLoader onLoad: no data'); return;
35
+ }
36
+ if(data.page == undefined) {
37
+ console.log('AlgoliaLoader onLoad: no page'); return;
38
+ }
39
+ if(data.page+1 >= data.nbPages) {
40
+ console.log('AlgoliaLoader onLoad: no more pages');
41
+ this.deactivate(); return;
42
+ }
43
+
44
+ console.log('AlgoliaLoader onLoad: updating', data);
45
+ const shown = data.hitsPerPage * (data.page + 1);
46
+ const total = data.nbHits;
47
+
48
+ this.innerHTML = this.template.replace('${shown}', shown).replace('${total}', total);
49
+ this.activate();
50
+ }
51
+ }
52
+
53
+ if (!customElements.get('algolia-loader')) {
54
+ customElements.define('algolia-loader', AlgoliaLoader);
55
+ }
56
+ window.AlgoliaLoader = AlgoliaLoader;
@@ -0,0 +1,222 @@
1
+ const {createApp} = await import('../res/mc-vue.js');
2
+ await loadComponent('./components/mc-element.js', false);
3
+
4
+ class AlgoliaSearch extends McElement {
5
+ connectedCallback() {
6
+ console.log('AlgoliaSearch init');
7
+ this.init();
8
+ }
9
+
10
+ init = () => {
11
+ const cmp = this;
12
+
13
+ if(!cmp.dataset.apiKey || !cmp.dataset.appId) {
14
+ console.error('AlgoliaSearch: apiKey or appId not defined');
15
+ return;
16
+ }
17
+ if(!cmp.dataset.productsIndex && !cmp.dataset.suggestionsIndex && !cmp.dataset.collectionsIndex) {
18
+ console.error('AlgoliaSearch: at least one of productsIndex, suggestionsIndex or collectionsIndex must be defined');
19
+ return;
20
+ }
21
+
22
+ const app = createApp({
23
+ delimiters: ['${', '}'], // setta i delimitatori di vue, altrimenti se usiamo gli standard va in conflitto con liquid
24
+ data: () => {
25
+ return {
26
+ loading: false,
27
+ query: '',
28
+ products: [],
29
+ suggestions: [],
30
+ collections: [],
31
+ queryProductIndex: -1,
32
+ querySuggestionIndex: -1,
33
+ queryCollectionIndex: -1
34
+ }
35
+ },
36
+ methods: {
37
+
38
+ search() {
39
+ if (this.query.length < 3) {
40
+ this.loading = false;
41
+ this.products = [];
42
+ this.suggestions = [];
43
+ this.collections = [];
44
+ return;
45
+ }
46
+
47
+ this.loading = true;
48
+ axios({
49
+ method: 'post',
50
+ url: `https://${cmp.dataset.appId}.algolia.net/1/indexes/*/queries`,
51
+ headers: {
52
+ "content-type": "application/json",
53
+ "x-algolia-api-key": cmp.dataset.apiKey,
54
+ "x-algolia-application-id": cmp.dataset.appId
55
+ },
56
+ data: this.getRequest()
57
+ }).then((response) => {
58
+ this.onSuccess(response);
59
+ }).catch((error) => {
60
+ this.onError(error);
61
+ }).finally(() => {
62
+ this.loading = false;
63
+ });
64
+ },
65
+
66
+ getRequest() {
67
+ const requests = [];
68
+ if(cmp.dataset.productsIndex === undefined || cmp.dataset.productsIndex.length == 0){
69
+ this.queryProductIndex = -1;
70
+ console.warn('AlgoliaSearch: productsIndex not defined, products search disabled');
71
+ }
72
+ if(cmp.dataset.suggestionsIndex === undefined || cmp.dataset.suggestionsIndex.length == 0){
73
+ this.querySuggestionIndex = -1;
74
+ console.warn('AlgoliaSearch: suggestionsIndex not defined, suggestions search disabled');
75
+ }
76
+ if(cmp.dataset.collectionsIndex === undefined || cmp.dataset.collectionsIndex.length == 0){
77
+ this.queryCollectionIndex = -1;
78
+ console.warn('AlgoliaSearch: collectionsIndex not defined, collections search disabled');
79
+ }
80
+
81
+ if(cmp.dataset.suggestionsIndex !== undefined) {
82
+ requests.push({
83
+ indexName: cmp.dataset.suggestionsIndex,
84
+ query: this.query,
85
+ distinct: true,
86
+ attributesToHighlight: [],
87
+ attributesToSnippet: [],
88
+ hitsPerPage: parseInt(cmp.dataset.suggestionsMax) || 4,
89
+ page: 0,
90
+ attributesToRetrieve: ["query"],
91
+ facets: ["*"]
92
+ });
93
+ this.querySuggestionIndex = requests.length - 1;
94
+ }
95
+ if(cmp.dataset.productsIndex !== undefined) {
96
+ requests.push({
97
+ indexName: cmp.dataset.productsIndex,
98
+ query: this.query,
99
+ attributesToRetrieve: ["handle"],
100
+ distinct: true,
101
+ attributesToHighlight: [],
102
+ attributesToSnippet: [],
103
+ hitsPerPage: parseInt(cmp.dataset.productsMax) || 4,
104
+ page: 0,
105
+ facets: ["*"]
106
+ });
107
+ this.queryProductIndex = requests.length - 1;
108
+ }
109
+ if(cmp.dataset.collectionsIndex !== undefined) {
110
+ requests.push({
111
+ indexName: cmp.dataset.collectionsIndex,
112
+ attributesToRetrieve: ["url", "path"],
113
+ query: this.query,
114
+ distinct: true,
115
+ attributesToHighlight: [],
116
+ attributesToSnippet: [],
117
+ hitsPerPage: parseInt(cmp.dataset.collectionsMax) || 4,
118
+ page: 0,
119
+ facets: ["*"]
120
+ });
121
+ this.queryCollectionIndex = requests.length - 1;
122
+ }
123
+ return {requests};
124
+ },
125
+
126
+ onSuccess(response) {
127
+ if(!response.data.results) {
128
+ this.onError('No results');
129
+ return;
130
+ }
131
+
132
+ this.mapProducts(response);
133
+ this.mapSuggestions(response);
134
+ this.mapCollections(response);
135
+ },
136
+
137
+ mapProducts(response) {
138
+ if(this.queryProductIndex < 0) {
139
+ this.products = [];
140
+ return;
141
+ }
142
+ const hits = response.data.results[this.queryProductIndex]?.hits;
143
+ if(!hits) {
144
+ this.products = [];
145
+ return;
146
+ }
147
+ this.products = hits.filter(hit => hit.handle != undefined && hit.handle != null);
148
+ },
149
+
150
+ mapSuggestions(response) {
151
+ if(this.querySuggestionIndex < 0) {
152
+ this.suggestions = [];
153
+ return;
154
+ }
155
+ const hits = response.data.results[this.querySuggestionIndex]?.hits;
156
+ if(!hits) {
157
+ this.suggestions = [];
158
+ return;
159
+ }
160
+
161
+ this.suggestions = hits.map(hit => {
162
+ if(!hit.query) {
163
+ return null;
164
+ }
165
+ return {
166
+ query: hit.query,
167
+ title: hit.query.replace(new RegExp(this.query, 'gi'), match => `<strong>${match}</strong>`)
168
+ };
169
+ }).filter(s => s != null);
170
+ },
171
+
172
+ mapCollections(response) {
173
+ if(this.queryCollectionIndex < 0) {
174
+ this.collections = [];
175
+ return;
176
+ }
177
+ const hits = response.data.results[this.queryCollectionIndex]?.hits;
178
+ if(!hits) {
179
+ this.collections = [];
180
+ return;
181
+ }
182
+ this.collections = hits.map(hit => {
183
+ if(!hit.url || !hit.path) {
184
+ console.warn('AlgoliaSearch: collection hit without url or path', hit);
185
+ return null;
186
+ }
187
+ return {
188
+ url: hit.url,
189
+ path: hit.path,
190
+ title: hit.path.replace(new RegExp(this.query, 'gi'), match => `<strong>${match}</strong>`)
191
+ };
192
+ }).filter(c => c != null);
193
+ },
194
+
195
+ onError(error) {
196
+ this.products = [];
197
+ this.suggestions = [];
198
+ this.collections = [];
199
+ console.error('AlgoliaSearch error', error);
200
+ },
201
+
202
+ suggest(suggestion) {
203
+ this.query = suggestion;
204
+ this.search();
205
+ }
206
+ },
207
+ computed: {
208
+ showResults() {
209
+ return this.products.length > 0 || this.suggestions.length > 0 || this.collections.length > 0;
210
+ }
211
+
212
+ }
213
+ });
214
+ app.config.compilerOptions.isCustomElement = tag => tag.includes('-'); // per evitare che vue vada in conflitto con i custom element
215
+ app.mount(this);
216
+ }
217
+ }
218
+
219
+ if (!customElements.get('algolia-search')) {
220
+ customElements.define('algolia-search', AlgoliaSearch);
221
+ }
222
+ window.AlgoliaSearch = AlgoliaSearch;
@@ -0,0 +1,29 @@
1
+ await loadComponent('./auth/teddy-auth.js', false);
2
+
3
+ class TeddyAuthLogin extends TeddyAuth {
4
+
5
+ // formatto i dati per il payload sovrascrivendo il metodo getData
6
+ getData = () => {
7
+ const formData = new FormData(this.form);
8
+
9
+ this.data = {};
10
+
11
+ Array.from(formData.entries()).forEach(([key, value]) => {
12
+ this.data[key] = value;
13
+ });
14
+ this.data.sessionId = this.getSessionId();
15
+ this.data.mergeCart = true;
16
+ this.data.callingSystem = 6;
17
+ console.log('TeddyAuthLogin.getData', this.data);
18
+ }
19
+
20
+ success = (response) => {
21
+ this.multipassSuccess(response);
22
+ }
23
+
24
+ }
25
+
26
+ if (!customElements.get('teddy-auth-login')) {
27
+ customElements.define('teddy-auth-login', TeddyAuthLogin);
28
+ }
29
+ window.TeddyAuthLogin = TeddyAuthLogin;
@@ -0,0 +1,58 @@
1
+ await loadComponent('./auth/teddy-auth.js', false);
2
+ await loadComponent('./components/mc-form-success.js', false);
3
+
4
+ class TeddyAuthProfile extends TeddyAuth {
5
+
6
+ // formatto i dati per il payload sovrascrivendo il metodo getData
7
+ getData = () => {
8
+ const formData = new FormData(this.form);
9
+
10
+ this.data = {};
11
+ Array.from(formData.entries()).forEach(([key, value]) => {
12
+ if(key == 'birthday' && this.data?.dayOfBirth == undefined){
13
+ this.data.dayOfBirth = `${new Date(value).getDate()}`.padStart(2, '0');
14
+ this.data.monthOfBirth = `${(new Date(value).getMonth() + 1)}`.padStart(2, '0');
15
+ this.data.yearOfBirth = `${new Date(value).getFullYear()}`;
16
+ }
17
+ else if(key.includes('.')) {
18
+ const [parent, child] = key.split('.');
19
+ this.data[parent] = this.data[parent] || {};
20
+ this.data[parent][child] = value == 'true';
21
+ } else {
22
+ if(value === 'true') value = true;
23
+ if(value === 'false') value = false;
24
+ this.data[key] = value;
25
+ }
26
+ });
27
+
28
+ this.data.preferences = this.data.preferences || {};
29
+ this.data.preferences.newsletter = this.data.preferences.newsletter || false;
30
+ this.data.preferences.sms = this.data.preferences.sms || false;
31
+ this.data.preferences.profiling = this.data.preferences.profiling || false;
32
+
33
+ this.data.callingSystem = 6;
34
+ this.data.sessionId = this.getSessionId();
35
+ console.log('TeddyAuthProfile.getData', this.data);
36
+ }
37
+
38
+ success = (response) => {
39
+ const data = response.data;
40
+ if(!data.success){
41
+ this.error(data);
42
+ return;
43
+ }
44
+ const success = this.querySelector('mc-form-success');
45
+ if(!success) return;
46
+ if(!theme.t.success.profile_updated) {
47
+ console.error('Profile updated message not found');
48
+ return;
49
+ }
50
+ success.showMessage(theme.t.success.profile_updated);
51
+ }
52
+
53
+ }
54
+
55
+ if (!customElements.get('teddy-auth-profile')) {
56
+ customElements.define('teddy-auth-profile', TeddyAuthProfile);
57
+ }
58
+ window.TeddyAuthProfile = TeddyAuthProfile;
@@ -0,0 +1,52 @@
1
+ await loadComponent('./auth/teddy-auth.js', false);
2
+
3
+ class TeddyAuthRegister extends TeddyAuth {
4
+
5
+ // formatto i dati per il payload sovrascrivendo il metodo getData
6
+ getData = () => {
7
+ const formData = new FormData(this.form);
8
+
9
+ this.data = {};
10
+
11
+ Array.from(formData.entries()).forEach(([key, value]) => {
12
+ if(key == 'birthday' && this.data?.dayOfBirth == undefined){
13
+ this.data.dayOfBirth = `${new Date(value).getDate()}`.padStart(2, '0');
14
+ this.data.monthOfBirth = `${(new Date(value).getMonth() + 1)}`.padStart(2, '0');
15
+ this.data.yearOfBirth = `${new Date(value).getFullYear()}`;
16
+ }
17
+ else if (key == 'authSMSNotification' || key == 'authEmailNotification' || key == 'authDataProfiling') {
18
+ // Convert boolean values to string
19
+ this.data[key] = value == 1;
20
+ }
21
+ else {
22
+ this.data[key] = value;
23
+ }
24
+ });
25
+ if(this.data.authSMSNotification === undefined) {
26
+ this.data.authSMSNotification = false;
27
+ }
28
+ if(this.data.authEmailNotification === undefined) {
29
+ this.data.authEmailNotification = false;
30
+ }
31
+ if(this.data.authDataProfiling === undefined) {
32
+ this.data.authDataProfiling = false;
33
+ }
34
+ if(this.data.importantDate === undefined) {
35
+ this.data.importantDate = '';
36
+ }
37
+ this.data.requestLoyaltyCard = true;
38
+ this.data.sessionId = this.getSessionId();
39
+ this.data.callingSystem = 6;
40
+ console.log('TeddyAuthRegister.getData', this.data);
41
+ }
42
+
43
+ success = (response) => {
44
+ this.multipassSuccess(response);
45
+ }
46
+
47
+ }
48
+
49
+ if (!customElements.get('teddy-auth-register')) {
50
+ customElements.define('teddy-auth-register', TeddyAuthRegister);
51
+ }
52
+ window.TeddyAuthRegister = TeddyAuthRegister;
@@ -0,0 +1,39 @@
1
+ await loadComponent('./auth/teddy-auth.js', false);
2
+ await loadComponent('./components/mc-form-success.js', false);
3
+
4
+ class TeddyAuthReset extends TeddyAuth {
5
+
6
+ // formatto i dati per il payload sovrascrivendo il metodo getData
7
+ getData = () => {
8
+ const formData = new FormData(this.form);
9
+
10
+ this.data = {};
11
+ Array.from(formData.entries()).forEach(([key, value]) => {
12
+ this.data[key] = value;
13
+ });
14
+ this.data.callingSystem = "6";
15
+ this.data.sessionId = this.getSessionId();
16
+ console.log('TeddyAuthReset.getData', this.data);
17
+ }
18
+
19
+ success = (response) => {
20
+ const data = response.data;
21
+ if(!data.success){
22
+ this.error(data);
23
+ return;
24
+ }
25
+ const success = this.querySelector('mc-form-success');
26
+ if(!success) return;
27
+ if(!theme.t.success.password_changed) {
28
+ console.error('Password changed message not found');
29
+ return;
30
+ }
31
+ success.showMessage(theme.t.success.password_changed);
32
+ }
33
+
34
+ }
35
+
36
+ if (!customElements.get('teddy-auth-reset')) {
37
+ customElements.define('teddy-auth-reset', TeddyAuthReset);
38
+ }
39
+ window.TeddyAuthReset = TeddyAuthReset;
@@ -0,0 +1,92 @@
1
+ import '../res/mc-events.js';
2
+ await loadComponent('./components/mc-loader.js', false);
3
+ await loadComponent('./components/mc-form.js', false);
4
+ await loadComponent('./res/mc-utils.js', false);
5
+ await loadComponent('./res/mc-events.js', false);
6
+
7
+ class TeddyAuth extends McForm {
8
+
9
+ connectedCallback() {
10
+ this.init();
11
+ this.addEventListener(MCEVENTS.FORM_SUBMIT, this.onSubmit.bind(this));
12
+ this.addEventListener(MCEVENTS.FORM_COMPLETED, this.onComplete.bind(this));
13
+ }
14
+
15
+ onSubmit = () => {
16
+ const loader = this.querySelector('mc-loader');
17
+ if(loader) {
18
+ loader.activate();
19
+ }
20
+ }
21
+
22
+ onComplete = () => {
23
+ const loader = this.querySelector('mc-loader');
24
+ if(loader) {
25
+ loader.deactivate();
26
+ }
27
+ }
28
+
29
+ // ottengo il sessionId dalla localStorage o lo genero se non esiste
30
+ getSessionId = () => {
31
+ return TeddyAuth.getSessionId();
32
+ }
33
+
34
+ // ottengo il sessionId dalla localStorage o lo genero se non esiste
35
+ static getSessionId = () => {
36
+ if(localStorage.getItem('sessionId') === null) {
37
+ localStorage.setItem('sessionId', TeddyAuth.generateSessionId());
38
+ }
39
+ return localStorage.getItem('sessionId');
40
+ }
41
+
42
+ // genero un ID di sessione unico e sicuro
43
+ static generateSessionId = (length = 24) => {
44
+ const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
45
+ let result = '';
46
+ const cryptoObj = window.crypto || window.msCrypto; // supporto IE11
47
+
48
+ if (cryptoObj && cryptoObj.getRandomValues) {
49
+ const randomValues = new Uint32Array(length);
50
+ cryptoObj.getRandomValues(randomValues);
51
+ for (let i = 0; i < length; i++) {
52
+ result += charset[randomValues[i] % charset.length];
53
+ }
54
+ } else {
55
+ // fallback meno sicuro
56
+ for (let i = 0; i < length; i++) {
57
+ result += charset[Math.floor(Math.random() * charset.length)];
58
+ }
59
+ }
60
+
61
+ return result;
62
+ }
63
+
64
+ error = (e) => {
65
+ McShopify.customEvent(MCEVENTS.FORM_ERROR, e, this);
66
+ let message = theme.t.errors.generic || 'An error occurred';
67
+ if(!theme?.t?.errors?.idm) {
68
+ console.error('TeddyAuth: Missing theme.t.errors.idm translation');
69
+ this.errors.showError(message);
70
+ return;
71
+ }
72
+ message = theme.t.errors.idm[e.error?.code] || theme.t.errors.idm[e.status] || theme.t.errors.idm.default || message;
73
+ console.error("TeddyAuth.error", message, e);
74
+ this.errors.showError(message);
75
+ }
76
+
77
+ multipassSuccess = (response) => {
78
+ const data = response.data;
79
+ console.log('TeddyAuth.multipassSuccess', data);
80
+ if(!data.success || data.error != undefined || !data.data?.multipassUrl) {
81
+ this.error(data);
82
+ return;
83
+ }
84
+ location.href = data.data.multipassUrl;
85
+ }
86
+
87
+ }
88
+
89
+ if (!customElements.get('teddy-auth')) {
90
+ customElements.define('teddy-auth', TeddyAuth);
91
+ }
92
+ window.TeddyAuth = TeddyAuth;
@@ -0,0 +1,64 @@
1
+ await loadComponent('./res/mc-events.js', false);
2
+ await loadComponent('./components/mc-element.js', false);
3
+
4
+ class BantoaProduct extends McElement {
5
+ connectedCallback() {
6
+ console.log("BantoaProduct: Connected", this.id);
7
+ if(!this.dataset.sku) {
8
+ console.error("BantoaProduct: No SKU found in the element.");
9
+ return;
10
+ }
11
+ if(!this.dataset.position){
12
+ console.error("BantoaProduct: No position found in the element.");
13
+ return;
14
+ }
15
+ if(window.isBantoaLoaded)
16
+ this.init();
17
+ window.addEventListener(MCEVENTS.BANTOA_LOADED, this.init.bind(this));
18
+ }
19
+
20
+ checkExists = () => {
21
+ axios({
22
+ url: `https://api.bantoa.com/api/visual?apikey=${bantoaKey}&onlycheckexist=1&code=${this.dataset.sku}&tm=1751548151`,
23
+ method: 'get',
24
+ }).then(r => {
25
+ if(r.data.productexist == 'ok'){
26
+ this.classList.remove('d-none');
27
+ }
28
+ })
29
+ .catch(e => {
30
+ console.error("BantoaProduct: Error checking product existence", e);
31
+ });
32
+ }
33
+
34
+ init = () => {
35
+ this.addEventListener('click', this.openViewer.bind(this));
36
+ this.checkExists();
37
+ }
38
+
39
+ openViewer = () => {
40
+ if(!window.isBantoaLoaded) {
41
+ console.warn("BantoaProduct: Bantoa tracker is not loaded.");
42
+ return;
43
+ }
44
+ const data = {
45
+ item: this.dataset.sku,
46
+ quality: '0.75',
47
+ max_results: 100,
48
+ min_results: 1,
49
+ position: this.dataset.position,
50
+ };
51
+ if(this.dataset.variant){
52
+ data.filter = {
53
+ sizes: this.dataset.variant
54
+ };
55
+ }
56
+ console.log("BantoaProduct: Opening viewer with data", data);
57
+ bnt_r_ai('visual', 'modal', data);
58
+ }
59
+ }
60
+
61
+ if (!customElements.get('bantoa-product')) {
62
+ customElements.define('bantoa-product', BantoaProduct);
63
+ }
64
+ window.BantoaProduct = BantoaProduct;
@@ -0,0 +1,46 @@
1
+ await loadComponent('./res/mc-events.js', false);
2
+ await loadComponent('./components/mc-element.js', false);
3
+ await loadComponent('./bantoa/bantoa.js', false);
4
+
5
+ class BantoaSearch extends McElement {
6
+ connectedCallback() {
7
+ if(!this.dataset.position){
8
+ console.error("BantoaSearch: No position found in the element.");
9
+ return;
10
+ }
11
+ this.addEventListener('click', this.openViewer.bind(this));
12
+ const url = new URL(window.location.href);
13
+ if(url.searchParams.has("bantoa")){
14
+ this.openViewer(this);
15
+ }
16
+ }
17
+
18
+ addParameterToUrl(){
19
+ const url = new URL(window.location.href);
20
+ url.searchParams.append("bantoa", "bantoa");
21
+ window.history.pushState({}, '', url)
22
+ }
23
+
24
+ openViewer = () => {
25
+ if(!window.isBantoaLoaded) {
26
+ console.warn("BantoaSearch: Bantoa tracker is not loaded.");
27
+ window.addEventListener(MCEVENTS.BANTOA_LOADED, () => this.openViewer());
28
+ return;
29
+ }
30
+ bnt_r_ai('visual', 'modal', {
31
+ quality: '0.75',
32
+ max_results: 100,
33
+ min_results: 1,
34
+ position: this.dataset.position,
35
+ });
36
+ const url = new URL(window.location.href);
37
+ if(!url.searchParams.has("bantoa")){
38
+ this.addParameterToUrl();
39
+ }
40
+ }
41
+ }
42
+
43
+ if (!customElements.get('bantoa-search')) {
44
+ customElements.define('bantoa-search', BantoaSearch);
45
+ }
46
+ window.BantoaSearch = BantoaSearch;