ts-glitter 21.5.3 → 21.5.5

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 (79) hide show
  1. package/lowcode/Entry.js +1 -1
  2. package/lowcode/Entry.ts +1 -1
  3. package/lowcode/cms-plugin/account-info.js +79 -67
  4. package/lowcode/cms-plugin/account-info.ts +327 -311
  5. package/lowcode/cms-plugin/information/information-module.ts +3 -1
  6. package/lowcode/cms-plugin/list-header-option.js +1 -0
  7. package/lowcode/cms-plugin/list-header-option.ts +1 -0
  8. package/lowcode/cms-plugin/shopping-information.js +468 -0
  9. package/lowcode/cms-plugin/shopping-information.ts +557 -0
  10. package/lowcode/cms-plugin/shopping-market-shopee.js +283 -231
  11. package/lowcode/cms-plugin/shopping-market-shopee.ts +401 -361
  12. package/lowcode/cms-plugin/shopping-order-manager.js +16 -4
  13. package/lowcode/cms-plugin/shopping-order-manager.ts +18 -3
  14. package/lowcode/glitter-base/global/language.js +4 -1
  15. package/lowcode/glitter-base/global/language.ts +4 -2
  16. package/lowcode/glitter-base/route/shopee.js +48 -11
  17. package/lowcode/glitter-base/route/shopee.ts +119 -80
  18. package/lowcode/glitterBundle/plugins/html-render.js +121 -90
  19. package/lowcode/glitterBundle/plugins/html-render.ts +367 -318
  20. package/lowcode/modules/image-library.js +2 -3
  21. package/lowcode/modules/image-library.ts +21 -7
  22. package/lowcode/public-components/checkout/index.js +90 -41
  23. package/lowcode/public-components/checkout/index.ts +101 -49
  24. package/lowcode/public-components/footer/footer-initial.js +11 -2
  25. package/lowcode/public-components/footer/footer-initial.ts +29 -18
  26. package/lowcode/public-components/headers/header-class.js +47 -35
  27. package/lowcode/public-components/headers/header-class.ts +54 -38
  28. package/lowcode/public-components/layout-plugin/social-links-01.js +122 -3
  29. package/lowcode/public-components/layout-plugin/social-links-01.ts +135 -10
  30. package/lowcode/public-components/product/pd-card-01.js +23 -14
  31. package/lowcode/public-components/product/pd-card-01.ts +25 -14
  32. package/lowcode/public-components/product/pd-card-02.js +23 -16
  33. package/lowcode/public-components/product/pd-card-02.ts +25 -16
  34. package/lowcode/public-components/product/pd-card-03.js +25 -16
  35. package/lowcode/public-components/product/pd-card-03.ts +27 -16
  36. package/lowcode/public-components/terms-related/index.js +13 -2
  37. package/lowcode/public-components/terms-related/index.ts +15 -2
  38. package/lowcode/public-components/user-manager/um-class.js +490 -501
  39. package/lowcode/public-components/user-manager/um-class.ts +872 -882
  40. package/lowcode/public-components/user-manager/um-info.js +41 -40
  41. package/lowcode/public-components/user-manager/um-info.ts +54 -56
  42. package/lowcode/public-components/user-manager/um-login.js +10 -13
  43. package/lowcode/public-components/user-manager/um-login.ts +15 -23
  44. package/lowcode/public-components/user-manager/um-orderlist.js +60 -51
  45. package/lowcode/public-components/user-manager/um-orderlist.ts +289 -275
  46. package/lowcode/public-components/user-manager/um-rebate.js +104 -82
  47. package/lowcode/public-components/user-manager/um-rebate.ts +294 -267
  48. package/lowcode/public-components/user-manager/um-receive.js +582 -0
  49. package/lowcode/public-components/user-manager/um-receive.ts +599 -0
  50. package/lowcode/public-components/user-manager/um-wishlist.js +72 -68
  51. package/lowcode/public-components/user-manager/um-wishlist.ts +240 -230
  52. package/package.json +1 -1
  53. package/src/api-public/controllers/shopee.js +17 -0
  54. package/src/api-public/controllers/shopee.js.map +1 -1
  55. package/src/api-public/controllers/shopee.ts +32 -0
  56. package/src/api-public/services/monitor.d.ts +1 -0
  57. package/src/api-public/services/post.js +17 -7
  58. package/src/api-public/services/post.js.map +1 -1
  59. package/src/api-public/services/rebate.js +2 -11
  60. package/src/api-public/services/rebate.js.map +1 -1
  61. package/src/api-public/services/rebate.ts +5 -12
  62. package/src/api-public/services/shopee.d.ts +23 -2
  63. package/src/api-public/services/shopee.js +230 -111
  64. package/src/api-public/services/shopee.js.map +1 -1
  65. package/src/api-public/services/shopee.ts +1012 -838
  66. package/src/api-public/services/user.js +2 -2
  67. package/src/api-public/services/user.js.map +1 -1
  68. package/src/api-public/services/user.ts +3 -3
  69. package/src/index.js +17 -7
  70. package/src/index.js.map +1 -1
  71. package/src/modules/tool.d.ts +4 -4
  72. package/src/modules/tool.js +2 -1
  73. package/src/modules/tool.js.map +1 -1
  74. package/src/services/backend-service.js +17 -7
  75. package/src/services/backend-service.js.map +1 -1
  76. package/src/services/template.d.ts +1 -1
  77. package/src/services/template.js +24 -18
  78. package/src/services/template.js.map +1 -1
  79. package/src/services/template.ts +34 -37
@@ -96,20 +96,25 @@ export class HeaderClass {
96
96
  outline: 0;
97
97
  }
98
98
 
99
- .${classPrefix}-cart-container {
99
+ .${classPrefix}-cart-header {
100
100
  display: flex;
101
+ flex-direction: column;
101
102
  width: 100%;
102
- align-items: center;
103
+ margin-bottom: 12px;
103
104
  padding: 0;
104
- margin-bottom: 18px;
105
105
  padding: 12px;
106
106
  border-bottom: 1px solid #dddddd;
107
+ position: sticky;
108
+ top: 0;
109
+ background-color: #fff;
110
+ z-index: 2;
107
111
  }
108
112
 
109
- .${classPrefix}-cart-title {
110
- letter-spacing: 4px;
111
- font-size: 22px;
112
- font-weight: 700;
113
+ .${classPrefix}-cart-div {
114
+ display: flex;
115
+ align-items: center;
116
+ justify-content: space-between;
117
+ width: 100%;
113
118
  }
114
119
 
115
120
  .${classPrefix}-shipping-title {
@@ -175,20 +180,30 @@ export class HeaderClass {
175
180
  if (vm.loading) {
176
181
  return html ` <div class="w-100 vh-100 bg-white">${this.spinner()}</div>`;
177
182
  }
178
- return html ` <div class="position-relative">
179
- <div class="${classPrefix}-cart-container align-items-center">
180
- <div
181
- class="d-flex align-items-center justify-content-center fs-5 py-3 px-2"
182
- style="cursor:pointer;"
183
- onclick="${gvc.event(() => {
183
+ return html ` <div class="position-relative" style="padding-bottom: 120px;">
184
+ <div class="${classPrefix}-cart-header">
185
+ <div class="${classPrefix}-cart-div">
186
+ <div
187
+ class="d-flex align-items-center justify-content-center fs-5 py-3 px-2"
188
+ style="cursor:pointer;"
189
+ onclick="${gvc.event(() => {
184
190
  gvc.glitter.closeDrawer();
185
191
  })}"
186
- >
187
- <i class="fa-sharp fa-solid fa-angle-left"></i>
192
+ >
193
+ <i class="fa-sharp fa-solid fa-angle-left"></i>
194
+ </div>
195
+ <div class="flex-fill"></div>
196
+ ${goToCheckoutButton(ApiCart.globalCart)}
188
197
  </div>
189
- <div class="${classPrefix}-cart-title">${Language.text('cart')}</div>
190
- <div class="flex-fill"></div>
191
- ${goToCheckoutButton(ApiCart.globalCart)}
198
+ ${(() => {
199
+ if (vm.dataList.length === 0) {
200
+ return '';
201
+ }
202
+ const num = vm.dataList.reduce((sum, item) => sum + item.count * item.price, 0);
203
+ return html `<div class="text-end px-2 py-1 fw-bold">
204
+ ${Language.text('cart_subtotal')} $ ${num.toLocaleString()}
205
+ </div>`;
206
+ })()}
192
207
  </div>
193
208
  ${(() => {
194
209
  if (vm.dataList.length === 0) {
@@ -235,31 +250,28 @@ export class HeaderClass {
235
250
  </div>
236
251
  <div class="d-flex flex-column gap-1 flex-fill">
237
252
  <div class="${classPrefix}-title pe-3">${item.title}</div>
238
- <div class="${classPrefix}-spec ">
253
+ <div class="${classPrefix}-spec">
239
254
  ${(() => {
240
255
  const spec = (() => {
241
- if (item.spec) {
242
- return item.spec.map((dd, index) => {
243
- try {
244
- return (item.specs[index].option.find((d1) => {
245
- return d1.title === dd;
246
- }).language_title[Language.getLanguage()] || dd);
247
- }
248
- catch (e) {
249
- return dd;
250
- }
251
- });
252
- }
253
- else {
256
+ if (!item.spec)
254
257
  return [];
255
- }
258
+ return item.spec.map((dd, index) => {
259
+ try {
260
+ return (item.specs[index].option.find((d1) => {
261
+ return d1.title === dd;
262
+ }).language_title[Language.getLanguage()] || dd);
263
+ }
264
+ catch (e) {
265
+ return dd;
266
+ }
267
+ });
256
268
  })();
257
269
  return spec.join(' / ');
258
270
  })()}
259
271
  </div>
260
272
  <div class="d-flex align-items-center justify-content-between">
261
- <div class="d-flex align-items-center gap-1" style="font-size:14px;">
262
- ${Language.text('quantity')} :<select
273
+ <div class="d-flex align-items-center gap-2" style="font-size: 14px;">
274
+ ${Language.text('quantity')}<select
263
275
  class="${classPrefix}-select"
264
276
  style="width: 100px;"
265
277
  onchange="${gvc.event(e => {
@@ -121,20 +121,25 @@ export class HeaderClass {
121
121
  outline: 0;
122
122
  }
123
123
 
124
- .${classPrefix}-cart-container {
124
+ .${classPrefix}-cart-header {
125
125
  display: flex;
126
+ flex-direction: column;
126
127
  width: 100%;
127
- align-items: center;
128
+ margin-bottom: 12px;
128
129
  padding: 0;
129
- margin-bottom: 18px;
130
130
  padding: 12px;
131
131
  border-bottom: 1px solid #dddddd;
132
+ position: sticky;
133
+ top: 0;
134
+ background-color: #fff;
135
+ z-index: 2;
132
136
  }
133
137
 
134
- .${classPrefix}-cart-title {
135
- letter-spacing: 4px;
136
- font-size: 22px;
137
- font-weight: 700;
138
+ .${classPrefix}-cart-div {
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: space-between;
142
+ width: 100%;
138
143
  }
139
144
 
140
145
  .${classPrefix}-shipping-title {
@@ -203,20 +208,32 @@ export class HeaderClass {
203
208
  if (vm.loading) {
204
209
  return html` <div class="w-100 vh-100 bg-white">${this.spinner()}</div>`;
205
210
  }
206
- return html` <div class="position-relative">
207
- <div class="${classPrefix}-cart-container align-items-center">
208
- <div
209
- class="d-flex align-items-center justify-content-center fs-5 py-3 px-2"
210
- style="cursor:pointer;"
211
- onclick="${gvc.event(() => {
212
- gvc.glitter.closeDrawer();
213
- })}"
214
- >
215
- <i class="fa-sharp fa-solid fa-angle-left"></i>
211
+ return html` <div class="position-relative" style="padding-bottom: 120px;">
212
+ <div class="${classPrefix}-cart-header">
213
+ <div class="${classPrefix}-cart-div">
214
+ <div
215
+ class="d-flex align-items-center justify-content-center fs-5 py-3 px-2"
216
+ style="cursor:pointer;"
217
+ onclick="${gvc.event(() => {
218
+ gvc.glitter.closeDrawer();
219
+ })}"
220
+ >
221
+ <i class="fa-sharp fa-solid fa-angle-left"></i>
222
+ </div>
223
+ <div class="flex-fill"></div>
224
+ ${goToCheckoutButton(ApiCart.globalCart)}
216
225
  </div>
217
- <div class="${classPrefix}-cart-title">${Language.text('cart')}</div>
218
- <div class="flex-fill"></div>
219
- ${goToCheckoutButton(ApiCart.globalCart)}
226
+ ${(() => {
227
+ if (vm.dataList.length === 0) {
228
+ return '';
229
+ }
230
+
231
+ const num = vm.dataList.reduce((sum, item) => sum + item.count * item.price, 0);
232
+
233
+ return html`<div class="text-end px-2 py-1 fw-bold">
234
+ ${Language.text('cart_subtotal')} $ ${num.toLocaleString()}
235
+ </div>`;
236
+ })()}
220
237
  </div>
221
238
  ${(() => {
222
239
  if (vm.dataList.length === 0) {
@@ -263,31 +280,30 @@ export class HeaderClass {
263
280
  </div>
264
281
  <div class="d-flex flex-column gap-1 flex-fill">
265
282
  <div class="${classPrefix}-title pe-3">${item.title}</div>
266
- <div class="${classPrefix}-spec ">
283
+ <div class="${classPrefix}-spec">
267
284
  ${(() => {
268
285
  const spec: any = (() => {
269
- if (item.spec) {
270
- return item.spec.map((dd: string, index: number) => {
271
- try {
272
- return (
273
- (item.specs[index] as any).option.find((d1: any) => {
274
- return d1.title === dd;
275
- }).language_title[Language.getLanguage()] || dd
276
- );
277
- } catch (e) {
278
- return dd;
279
- }
280
- });
281
- } else {
282
- return [];
283
- }
286
+ if (!item.spec) return [];
287
+
288
+ return item.spec.map((dd, index) => {
289
+ try {
290
+ return (
291
+ (item.specs[index] as any).option.find((d1: any) => {
292
+ return d1.title === dd;
293
+ }).language_title[Language.getLanguage()] || dd
294
+ );
295
+ } catch (e) {
296
+ return dd;
297
+ }
298
+ });
284
299
  })();
300
+
285
301
  return spec.join(' / ');
286
302
  })()}
287
303
  </div>
288
304
  <div class="d-flex align-items-center justify-content-between">
289
- <div class="d-flex align-items-center gap-1" style="font-size:14px;">
290
- ${Language.text('quantity')} :<select
305
+ <div class="d-flex align-items-center gap-2" style="font-size: 14px;">
306
+ ${Language.text('quantity')}<select
291
307
  class="${classPrefix}-select"
292
308
  style="width: 100px;"
293
309
  onchange="${gvc.event(e => {
@@ -1,8 +1,127 @@
1
+ const html = String.raw;
2
+ const css = String.raw;
1
3
  export class SocialLinks01 {
2
4
  static main(obj) {
3
- console.log(obj);
4
- console.log(`formData=>`, obj.widget.formData);
5
- return `<div>hello</div>`;
5
+ function scrollToTop() {
6
+ window.scrollTo({
7
+ top: 0,
8
+ behavior: 'smooth',
9
+ });
10
+ }
11
+ const gvc = obj.gvc;
12
+ const vm = {
13
+ id: gvc.glitter.getUUID(),
14
+ };
15
+ const pageData = obj.widget.formData;
16
+ const socialList = pageData.social_list;
17
+ const supportSocial = ['fb', 'ig', 'line'];
18
+ const socialIMG = {
19
+ fb: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/5968764.png',
20
+ ig: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/Instagram_logo_2022.png',
21
+ line: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/LINE_Brand_icon.png',
22
+ other: 'https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/link-solid.svg',
23
+ };
24
+ const gotoTopImg = 'https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/arrow-up-to-line-light.svg';
25
+ gvc.addStyle(css `
26
+ .floating-action-panel {
27
+ position: fixed;
28
+ bottom: 30px;
29
+ right: 30px;
30
+ display: flex;
31
+ flex-direction: column; /* 垂直排列 */
32
+ align-items: center;
33
+ gap: 10px; /* 按鈕間距 */
34
+ z-index: 1000;
35
+ }
36
+
37
+ .social-links {
38
+ display: flex;
39
+ flex-direction: column;
40
+ gap: 8px;
41
+ }
42
+
43
+ .social-link {
44
+ color: #007bff;
45
+ text-decoration: none;
46
+ font-size: 14px;
47
+ }
48
+
49
+ .social-link:hover {
50
+ text-decoration: underline;
51
+ }
52
+
53
+ .social-link:hover {
54
+ text-decoration: underline;
55
+ }
56
+
57
+ .component-circle {
58
+ background-color: transparent;
59
+ border: none;
60
+ padding: 2px;
61
+ cursor: pointer;
62
+ border-radius: 50%;
63
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
64
+ }
65
+
66
+ .component-img {
67
+ width: 40px;
68
+ height: 40px;
69
+ object-fit: contain;
70
+ }
71
+
72
+ .component-circle:hover .component-img {
73
+ opacity: 0.8;
74
+ }
75
+
76
+ .up-to-top.hidden {
77
+ display: none;
78
+ }
79
+ `);
80
+ return gvc.bindView({
81
+ bind: vm.id,
82
+ view: () => {
83
+ return html `
84
+ <div class="floating-action-panel">
85
+ <div class="social-links">
86
+ ${socialList
87
+ .map(socialLink => {
88
+ var _a;
89
+ const imgSrc = supportSocial.includes(socialLink.social_type)
90
+ ? socialIMG[socialLink.social_type]
91
+ : socialIMG.other;
92
+ return html `
93
+ <a href="${socialLink.link}" class="component-circle">
94
+ <img src="${(_a = socialLink.icon) !== null && _a !== void 0 ? _a : imgSrc}" alt="Go to top" class="component-img" />
95
+ </a>
96
+ `;
97
+ })
98
+ .join('')}
99
+ </div>
100
+ <button
101
+ class="component-circle up-to-top hidden"
102
+ onclick="${gvc.event(() => {
103
+ scrollToTop();
104
+ })}"
105
+ >
106
+ <img src="${gotoTopImg}" alt="Go to top" class="component-img" />
107
+ </button>
108
+ </div>
109
+ `;
110
+ }, divCreate: {},
111
+ onInitial: () => {
112
+ window.onscroll = function () {
113
+ const scrollPosition = window.scrollY;
114
+ const threshold = window.innerHeight / 2;
115
+ const panel = document.querySelector('.up-to-top');
116
+ if (scrollPosition >= threshold) {
117
+ panel.classList.remove('hidden');
118
+ }
119
+ else {
120
+ panel.classList.add('hidden');
121
+ }
122
+ };
123
+ }
124
+ });
6
125
  }
7
126
  }
8
127
  window.glitter.setModule(import.meta.url, SocialLinks01);
@@ -1,15 +1,140 @@
1
1
  import { GVC } from '../../glitterBundle/GVController.js';
2
2
 
3
- export class SocialLinks01{
4
- public static main(obj:{
5
- gvc:GVC,
6
- widget:any,
7
- subData:any
8
- }){
9
- console.log(obj)
10
- console.log(`formData=>`,obj.widget.formData)
11
- return `<div>hello</div>`
3
+ interface SocialLink {
4
+ social_type: string;
5
+ link: string;
6
+ icon: string
7
+ }
8
+
9
+ const html = String.raw;
10
+ const css = String.raw;
11
+
12
+ export class SocialLinks01 {
13
+ public static main(obj: { gvc: GVC; widget: any; subData: any }) {
14
+ function scrollToTop() {
15
+ window.scrollTo({
16
+ top: 0,
17
+ behavior: 'smooth',
18
+ });
19
+ }
20
+ const gvc = obj.gvc;
21
+ const vm = {
22
+ id:gvc.glitter.getUUID(),
23
+ };
24
+
25
+ const pageData = obj.widget.formData;
26
+ const socialList: SocialLink[] = pageData.social_list;
27
+ const supportSocial = ['fb', 'ig', 'line'];
28
+ const socialIMG: Record<string, string> = {
29
+ fb: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/5968764.png',
30
+ ig: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/Instagram_logo_2022.png',
31
+ line: 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/LINE_Brand_icon.png',
32
+ other: 'https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/link-solid.svg',
33
+ };
34
+ const gotoTopImg = 'https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/arrow-up-to-line-light.svg';
35
+ gvc.addStyle(css`
36
+ .floating-action-panel {
37
+ position: fixed;
38
+ bottom: 30px;
39
+ right: 30px;
40
+ display: flex;
41
+ flex-direction: column; /* 垂直排列 */
42
+ align-items: center;
43
+ gap: 10px; /* 按鈕間距 */
44
+ z-index: 1000;
45
+ }
46
+
47
+ .social-links {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: 8px;
51
+ }
52
+
53
+ .social-link {
54
+ color: #007bff;
55
+ text-decoration: none;
56
+ font-size: 14px;
57
+ }
58
+
59
+ .social-link:hover {
60
+ text-decoration: underline;
61
+ }
62
+
63
+ .social-link:hover {
64
+ text-decoration: underline;
65
+ }
66
+
67
+ .component-circle {
68
+ background-color: transparent;
69
+ border: none;
70
+ padding: 2px;
71
+ cursor: pointer;
72
+ border-radius: 50%;
73
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
74
+ }
75
+
76
+ .component-img {
77
+ width: 40px;
78
+ height: 40px;
79
+ object-fit: contain;
80
+ }
81
+
82
+ .component-circle:hover .component-img {
83
+ opacity: 0.8;
84
+ }
85
+
86
+ .up-to-top.hidden {
87
+ display: none;
88
+ }
89
+ `);
90
+ return gvc.bindView({
91
+ bind:vm.id,
92
+ view:()=>{
93
+ return html`
94
+ <div class="floating-action-panel">
95
+ <div class="social-links">
96
+ ${socialList
97
+ .map(socialLink => {
98
+ const imgSrc = supportSocial.includes(socialLink.social_type)
99
+ ? socialIMG[socialLink.social_type]
100
+ : socialIMG.other;
101
+ return html`
102
+ <a href="${socialLink.link}" class="component-circle">
103
+ <img src="${socialLink.icon??imgSrc}" alt="Go to top" class="component-img" />
104
+ </a>
105
+ `;
106
+ })
107
+ .join('')}
108
+ </div>
109
+ <button
110
+ class="component-circle up-to-top hidden"
111
+ onclick="${gvc.event(() => {
112
+ scrollToTop();
113
+ })}"
114
+ >
115
+ <img src="${gotoTopImg}" alt="Go to top" class="component-img" />
116
+ </button>
117
+ </div>
118
+ `;
119
+ },divCreate:{}
120
+ ,onInitial:()=>{
121
+ (window as any).onscroll = function() {
122
+ const scrollPosition = window.scrollY;
123
+
124
+ const threshold = window.innerHeight / 2;
125
+
126
+ const panel = document.querySelector('.up-to-top');
127
+
128
+ if (scrollPosition >= threshold) {
129
+ panel!.classList.remove('hidden');
130
+ } else {
131
+ panel!.classList.add('hidden');
132
+ }
133
+ };
134
+ }
135
+ })
136
+
12
137
  }
13
138
  }
14
139
 
15
- (window as any).glitter.setModule(import.meta.url,SocialLinks01)
140
+ (window as any).glitter.setModule(import.meta.url, SocialLinks01);
@@ -216,20 +216,29 @@ export class ProductCard01 {
216
216
  })}"
217
217
  />
218
218
  <div class="child add-cart-child">
219
- <div
220
- class="w-100 h-100 p-3 add-cart-text"
221
- onclick="${gvc.event((e, event) => {
222
- event.stopPropagation();
223
- PdClass.addCartAction({
224
- gvc: gvc,
225
- titleFontColor: titleFontColor,
226
- prod: prod,
227
- vm: vm,
228
- });
229
- })}"
230
- >
231
- <i class="fa-regular fa-cart-shopping me-2"></i>${Language.text('add_to_cart')}
232
- </div>
219
+ ${(() => {
220
+ const isAllUnderstocking = prod.variants.every((item) => item.show_understocking === 'true');
221
+ const stockTotal = prod.variants.reduce((sum, item) => sum + item.stock, 0);
222
+ const isSoldOut = isAllUnderstocking && stockTotal === 0;
223
+ return html `<div
224
+ class="w-100 h-100 p-3 add-cart-text"
225
+ onclick="${gvc.event((_, event) => {
226
+ event.stopPropagation();
227
+ if (!isSoldOut) {
228
+ PdClass.addCartAction({
229
+ gvc: gvc,
230
+ titleFontColor: titleFontColor,
231
+ prod: prod,
232
+ vm: vm,
233
+ });
234
+ }
235
+ })}"
236
+ >
237
+ ${isSoldOut
238
+ ? html `<i class="fa-solid fa-ban me-2"></i>${Language.text('sold_out')}`
239
+ : html `<i class="fa-regular fa-cart-shopping me-2"></i>${Language.text('add_to_cart')}`}
240
+ </div>`;
241
+ })()}
233
242
  </div>
234
243
  </div>
235
244
  <div class="card-collapse-parent cursor_pointer">
@@ -233,20 +233,31 @@ export class ProductCard01 {
233
233
  })}"
234
234
  />
235
235
  <div class="child add-cart-child">
236
- <div
237
- class="w-100 h-100 p-3 add-cart-text"
238
- onclick="${gvc.event((e, event) => {
239
- event.stopPropagation();
240
- PdClass.addCartAction({
241
- gvc: gvc,
242
- titleFontColor: titleFontColor,
243
- prod: prod,
244
- vm: vm,
245
- });
246
- })}"
247
- >
248
- <i class="fa-regular fa-cart-shopping me-2"></i>${Language.text('add_to_cart')}
249
- </div>
236
+ ${(() => {
237
+ const isAllUnderstocking = prod.variants.every((item: any) => item.show_understocking === 'true');
238
+ const stockTotal = prod.variants.reduce((sum: number, item: any) => sum + item.stock, 0);
239
+ const isSoldOut = isAllUnderstocking && stockTotal === 0;
240
+
241
+ return html`<div
242
+ class="w-100 h-100 p-3 add-cart-text"
243
+ onclick="${gvc.event((_, event) => {
244
+ event.stopPropagation();
245
+
246
+ if (!isSoldOut) {
247
+ PdClass.addCartAction({
248
+ gvc: gvc,
249
+ titleFontColor: titleFontColor,
250
+ prod: prod,
251
+ vm: vm,
252
+ });
253
+ }
254
+ })}"
255
+ >
256
+ ${isSoldOut
257
+ ? html`<i class="fa-solid fa-ban me-2"></i>${Language.text('sold_out')}`
258
+ : html`<i class="fa-regular fa-cart-shopping me-2"></i>${Language.text('add_to_cart')}`}
259
+ </div>`;
260
+ })()}
250
261
  </div>
251
262
  </div>
252
263
  <div class="card-collapse-parent cursor_pointer">