@isaiahiroko/tilmart-ngx-apps-buyer 0.2.5 → 0.2.7

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.
@@ -126,11 +126,11 @@ class HelpComponent extends BaseDirective {
126
126
  return TOPICS.find((t) => t.value === this.topic)?.label ?? 'Support request';
127
127
  }
128
128
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: HelpComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
129
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: HelpComponent, isStandalone: false, selector: "x-help", usesInheritance: true, ngImport: i0, template: "<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/message\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> \u2014 {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks \u2014 your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending\u2026' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n", styles: [".x-help{max-width:640px;margin:0 auto;padding:24px 20px 64px}.x-help h1{font-size:28px;font-weight:800;color:var(--color-text);margin-bottom:16px}.x-help h2{font-size:18px;font-weight:800;color:var(--color-text);margin:0 0 14px}.x-help-quick{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:24px}.x-help-quick a{border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:9px 14px;font-size:13px;font-weight:700;color:var(--color-accent-hover);text-decoration:none}.x-help-quick a:hover{border-color:var(--color-accent)}.x-help-card,.x-help-done{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);padding:22px}.x-help-field{display:block;margin-bottom:14px}.x-help-field span{display:block;font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);margin-bottom:7px}.x-help-field input,.x-help-field select,.x-help-field textarea{width:100%;box-sizing:border-box;padding:12px 14px;border:1px solid var(--color-border);border-radius:var(--radius-lg);font:inherit;font-size:14.5px;background:var(--color-surface);color:var(--color-text);outline:none}.x-help-contact{display:grid;grid-template-columns:1fr 1fr;gap:12px}.x-help-err{font-size:12.5px;color:var(--color-danger);margin-bottom:12px}.x-help-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-lg);padding:12px 20px;font-size:14px;font-weight:800;cursor:pointer}.x-help-btn:disabled{opacity:.55;cursor:default}@media(max-width:520px){.x-help-contact{grid-template-columns:1fr}}.x-help-articles{display:flex;flex-direction:column;gap:20px;margin:24px 0}.x-help-topic-title{font-size:15px;font-weight:700;margin:0 0 8px;color:var(--color-text)}.x-help-topic-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.x-help-topic-list a{font-size:14px;font-weight:600;color:var(--color-brand);text-decoration:none}.x-help-topic-list a:hover{text-decoration:underline}.x-help-topic-summary{font-size:13px;color:var(--color-text-muted)}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
129
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: HelpComponent, isStandalone: false, selector: "x-help", usesInheritance: true, ngImport: i0, template: "<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/2348168399828\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> \u2014 {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks \u2014 your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending\u2026' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n", styles: [".x-help{max-width:640px;margin:0 auto;padding:24px 20px 64px}.x-help h1{font-size:28px;font-weight:800;color:var(--color-text);margin-bottom:16px}.x-help h2{font-size:18px;font-weight:800;color:var(--color-text);margin:0 0 14px}.x-help-quick{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:24px}.x-help-quick a{border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:9px 14px;font-size:13px;font-weight:700;color:var(--color-accent-hover);text-decoration:none}.x-help-quick a:hover{border-color:var(--color-accent)}.x-help-card,.x-help-done{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);padding:22px}.x-help-field{display:block;margin-bottom:14px}.x-help-field span{display:block;font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);margin-bottom:7px}.x-help-field input,.x-help-field select,.x-help-field textarea{width:100%;box-sizing:border-box;padding:12px 14px;border:1px solid var(--color-border);border-radius:var(--radius-lg);font:inherit;font-size:14.5px;background:var(--color-surface);color:var(--color-text);outline:none}.x-help-contact{display:grid;grid-template-columns:1fr 1fr;gap:12px}.x-help-err{font-size:12.5px;color:var(--color-danger);margin-bottom:12px}.x-help-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-lg);padding:12px 20px;font-size:14px;font-weight:800;cursor:pointer}.x-help-btn:disabled{opacity:.55;cursor:default}@media(max-width:520px){.x-help-contact{grid-template-columns:1fr}}.x-help-articles{display:flex;flex-direction:column;gap:20px;margin:24px 0}.x-help-topic-title{font-size:15px;font-weight:700;margin:0 0 8px;color:var(--color-text)}.x-help-topic-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.x-help-topic-list a{font-size:14px;font-weight:600;color:var(--color-brand);text-decoration:none}.x-help-topic-list a:hover{text-decoration:underline}.x-help-topic-summary{font-size:13px;color:var(--color-text-muted)}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
130
130
  }
131
131
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: HelpComponent, decorators: [{
132
132
  type: Component,
133
- args: [{ standalone: false, selector: 'x-help', template: "<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/message\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> \u2014 {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks \u2014 your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending\u2026' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n", styles: [".x-help{max-width:640px;margin:0 auto;padding:24px 20px 64px}.x-help h1{font-size:28px;font-weight:800;color:var(--color-text);margin-bottom:16px}.x-help h2{font-size:18px;font-weight:800;color:var(--color-text);margin:0 0 14px}.x-help-quick{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:24px}.x-help-quick a{border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:9px 14px;font-size:13px;font-weight:700;color:var(--color-accent-hover);text-decoration:none}.x-help-quick a:hover{border-color:var(--color-accent)}.x-help-card,.x-help-done{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);padding:22px}.x-help-field{display:block;margin-bottom:14px}.x-help-field span{display:block;font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);margin-bottom:7px}.x-help-field input,.x-help-field select,.x-help-field textarea{width:100%;box-sizing:border-box;padding:12px 14px;border:1px solid var(--color-border);border-radius:var(--radius-lg);font:inherit;font-size:14.5px;background:var(--color-surface);color:var(--color-text);outline:none}.x-help-contact{display:grid;grid-template-columns:1fr 1fr;gap:12px}.x-help-err{font-size:12.5px;color:var(--color-danger);margin-bottom:12px}.x-help-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-lg);padding:12px 20px;font-size:14px;font-weight:800;cursor:pointer}.x-help-btn:disabled{opacity:.55;cursor:default}@media(max-width:520px){.x-help-contact{grid-template-columns:1fr}}.x-help-articles{display:flex;flex-direction:column;gap:20px;margin:24px 0}.x-help-topic-title{font-size:15px;font-weight:700;margin:0 0 8px;color:var(--color-text)}.x-help-topic-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.x-help-topic-list a{font-size:14px;font-weight:600;color:var(--color-brand);text-decoration:none}.x-help-topic-list a:hover{text-decoration:underline}.x-help-topic-summary{font-size:13px;color:var(--color-text-muted)}\n"] }]
133
+ args: [{ standalone: false, selector: 'x-help', template: "<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/2348168399828\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> \u2014 {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks \u2014 your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending\u2026' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n", styles: [".x-help{max-width:640px;margin:0 auto;padding:24px 20px 64px}.x-help h1{font-size:28px;font-weight:800;color:var(--color-text);margin-bottom:16px}.x-help h2{font-size:18px;font-weight:800;color:var(--color-text);margin:0 0 14px}.x-help-quick{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:24px}.x-help-quick a{border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:9px 14px;font-size:13px;font-weight:700;color:var(--color-accent-hover);text-decoration:none}.x-help-quick a:hover{border-color:var(--color-accent)}.x-help-card,.x-help-done{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);padding:22px}.x-help-field{display:block;margin-bottom:14px}.x-help-field span{display:block;font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-text-muted);margin-bottom:7px}.x-help-field input,.x-help-field select,.x-help-field textarea{width:100%;box-sizing:border-box;padding:12px 14px;border:1px solid var(--color-border);border-radius:var(--radius-lg);font:inherit;font-size:14.5px;background:var(--color-surface);color:var(--color-text);outline:none}.x-help-contact{display:grid;grid-template-columns:1fr 1fr;gap:12px}.x-help-err{font-size:12.5px;color:var(--color-danger);margin-bottom:12px}.x-help-btn{background:var(--color-accent);color:var(--color-accent-fg);border:0;border-radius:var(--radius-lg);padding:12px 20px;font-size:14px;font-weight:800;cursor:pointer}.x-help-btn:disabled{opacity:.55;cursor:default}@media(max-width:520px){.x-help-contact{grid-template-columns:1fr}}.x-help-articles{display:flex;flex-direction:column;gap:20px;margin:24px 0}.x-help-topic-title{font-size:15px;font-weight:700;margin:0 0 8px;color:var(--color-text)}.x-help-topic-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.x-help-topic-list a{font-size:14px;font-weight:600;color:var(--color-brand);text-decoration:none}.x-help-topic-list a:hover{text-decoration:underline}.x-help-topic-summary{font-size:13px;color:var(--color-text-muted)}\n"] }]
134
134
  }] });
135
135
 
136
136
  // P6.14, SUP-01 — `/help/:slug`. The docs renderer for one published
@@ -217,4 +217,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
217
217
  }] });
218
218
 
219
219
  export { HelpModule };
220
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs.map
220
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs","sources":["../../../projects/buyer/src/lib/pages/help/help.component.ts","../../../projects/buyer/src/lib/pages/help/help.component.html","../../../projects/buyer/src/lib/pages/help/help-article.component.ts","../../../projects/buyer/src/lib/pages/help/help-article.component.html","../../../projects/buyer/src/lib/pages/help/help.module.ts"],"sourcesContent":["import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, ControlService, notify, using } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of, takeUntil } from 'rxjs';\n\n// Articles that make up the self-serve help centre (SUP-01). Ops files a\n// help doc by setting one of these as the Article's `category`.\nexport const HELP_CATEGORIES = [\n 'getting-started',\n 'orders-delivery',\n 'payments-refunds',\n 'returns-warranty',\n 'account',\n 'faq',\n];\n\nconst HELP_CATEGORY_LABELS: Record<string, string> = {\n 'getting-started': 'Getting started',\n 'orders-delivery': 'Orders & delivery',\n 'payments-refunds': 'Payments & refunds',\n 'returns-warranty': 'Returns & warranty',\n account: 'Your account',\n faq: 'FAQ',\n};\n\nconst TOPICS = [\n { value: 'order', label: 'An order or delivery' },\n { value: 'payment', label: 'A payment or refund' },\n { value: 'return', label: 'A return or warranty claim' },\n { value: 'product', label: 'A product question' },\n { value: 'account', label: 'My account' },\n { value: 'other', label: 'Something else' },\n];\n\n// P5.14 / P6.14, SUP-01/03 — the storefront help centre. Self-serve help\n// articles (CMS `Article`s, `/help/:slug` renders one) + a contact form\n// that opens a support ticket (`ComplaintLog`, type `support_request`).\n@Component({\n standalone: false,\n selector: 'x-help',\n templateUrl: './help.component.html',\n styleUrl: './help.component.scss',\n})\nexport class HelpComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly controlService = inject(ControlService);\n\n readonly topics = TOPICS;\n\n topic = '';\n subject = '';\n message = '';\n email = '';\n phone = '';\n orderNumber = '';\n\n submitting = false;\n error = '';\n done = false;\n\n // SUP-01 — the help-article index, grouped by category.\n groups: { key: string; label: string; articles: { slug: string; title: string; summary?: string }[] }[] = [];\n\n override init = () => {\n this.orderNumber = this.route.snapshot.queryParamMap.get('order') ?? '';\n if (this.orderNumber) this.topic = 'order';\n this.loadArticles();\n };\n\n private loadArticles(): void {\n this.apiService\n .on('apps/commerce/article')\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const now = Date.now();\n const help = ((res?.data ?? []) as any[]).filter(\n (a) =>\n HELP_CATEGORIES.includes(a.category) &&\n a.status === 'published' &&\n (!a.publishAt || Date.parse(a.publishAt) <= now),\n );\n const byCat = new Map<string, any[]>();\n for (const a of help) {\n const list = byCat.get(a.category) ?? [];\n list.push(a);\n byCat.set(a.category, list);\n }\n this.groups = HELP_CATEGORIES.filter((key) => byCat.has(key)).map((key) => ({\n key,\n label: HELP_CATEGORY_LABELS[key] ?? key,\n articles: (byCat.get(key) ?? [])\n .sort((x, y) => String(x.title).localeCompare(String(y.title)))\n .map((a) => ({ slug: a.slug, title: a.title, summary: a.summary })),\n }));\n }),\n );\n }\n\n get canSubmit(): boolean {\n return (\n !!this.topic &&\n !!this.message.trim() &&\n (this.controlService.isLoggedIn() || !!this.email.trim() || !!this.phone.trim())\n );\n }\n\n async submit(): Promise<void> {\n if (this.submitting || !this.canSubmit) return;\n this.submitting = true;\n this.error = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/complaint-log')\n .create({\n type: 'support_request',\n channel: 'web',\n subject: this.subject.trim() || this.topicLabel(),\n note: this.message.trim(),\n priority: this.topic === 'payment' ? 'high' : 'normal',\n contactEmail: this.email.trim() || undefined,\n contactPhone: this.phone.trim() || undefined,\n } as any)\n .pipe(catchError((err) => of({ status: 'error', message: String(err) }))),\n );\n if (res?.status === 'error') {\n this.error = 'Could not send your message. Please try again.';\n return;\n }\n this.done = true;\n notify('Message sent — we’ll be in touch', undefined, 'success');\n } catch {\n this.error = 'Could not send your message. Please try again.';\n } finally {\n this.submitting = false;\n }\n }\n\n private topicLabel(): string {\n return TOPICS.find((t) => t.value === this.topic)?.label ?? 'Support request';\n }\n}\n","<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/2348168399828\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> — {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks — your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending…' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n","import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, using } from '@thescaffold/ngx-core';\nimport { takeUntil } from 'rxjs';\nimport { SeoService } from '../../services/seo.service';\nimport { HELP_CATEGORIES } from './help.component';\n\n// P6.14, SUP-01 — `/help/:slug`. The docs renderer for one published\n// help `Article` (rich body via sanitised `[innerHTML]`), with the\n// other articles in the same category as \"related\".\n@Component({\n standalone: false,\n selector: 'x-help-article',\n templateUrl: './help-article.component.html',\n})\nexport class HelpArticleComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly seo = inject(SeoService);\n private readonly source = this.apiService.on('apps/commerce/article');\n\n loading = true;\n notFound = false;\n article?: { title: string; body?: string; category?: string; readMinutes?: number };\n related: { slug: string; title: string }[] = [];\n\n override init = () => {\n this.route.paramMap.pipe(takeUntil(this.$)).subscribe((params) => {\n const slug = params.get('slug');\n if (slug) this.load(slug);\n });\n };\n\n private load(slug: string): void {\n this.loading = true;\n this.notFound = false;\n this.article = undefined;\n this.source\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const now = Date.now();\n const published = ((res?.data ?? []) as any[]).filter(\n (a) =>\n HELP_CATEGORIES.includes(a.category) &&\n a.status === 'published' &&\n (!a.publishAt || Date.parse(a.publishAt) <= now),\n );\n const raw = published.find((a) => a.slug === slug);\n if (!raw) {\n this.notFound = true;\n this.loading = false;\n return;\n }\n this.article = {\n title: raw.title,\n body: raw.body,\n category: raw.category,\n readMinutes: raw.readMinutes,\n };\n this.related = published\n .filter((a) => a.category === raw.category && a.slug !== raw.slug)\n .slice(0, 5)\n .map((a) => ({ slug: a.slug, title: a.title }));\n void this.seo.apply({ entityType: 'article', entityId: raw.id });\n this.loading = false;\n }),\n );\n }\n}\n","@if (loading) {\n <div class=\"x-ha-loading\">Loading…</div>\n} @else if (notFound) {\n <div class=\"x-ha-missing\">\n <p>We couldn't find that help article.</p>\n <a routerLink=\"/help\">Back to Help</a>\n </div>\n} @else if (article) {\n <article class=\"x-ha\">\n <a class=\"x-ha-back\" routerLink=\"/help\">← Help</a>\n <h1 class=\"x-ha-title\">{{ article.title }}</h1>\n @if (article.readMinutes) {\n <div class=\"x-ha-meta\">{{ article.readMinutes }} min read</div>\n }\n <div class=\"x-ha-body\" [innerHTML]=\"article.body\"></div>\n </article>\n\n @if (related.length) {\n <section class=\"x-ha-related\">\n <h2>Related</h2>\n <ul>\n @for (r of related; track r.slug) {\n <li><a [routerLink]=\"['/help', r.slug]\">{{ r.title }}</a></li>\n }\n </ul>\n </section>\n }\n\n <div class=\"x-ha-still\">\n Still stuck? <a routerLink=\"/help\">Send us a message</a>.\n </div>\n}\n\n<style>\n .x-ha { max-width: 720px; margin: 0 auto; }\n .x-ha-loading, .x-ha-missing { padding: 32px 16px; color: var(--color-text-muted); }\n .x-ha-missing { text-align: center; }\n .x-ha-back { font-size: 12.5px; font-weight: 600; color: var(--color-text-muted); text-decoration: none; }\n .x-ha-title { font-size: 28px; font-weight: 800; margin: 8px 0 6px; color: var(--color-text); }\n .x-ha-meta { font-size: 12.5px; color: var(--color-text-muted); margin-bottom: 20px; }\n .x-ha-body { font-size: 15.5px; line-height: 1.7; color: var(--color-text); }\n .x-ha-body :is(h2, h3) { margin-top: 1.6em; }\n .x-ha-body a { color: var(--color-brand); }\n .x-ha-related { max-width: 720px; margin: 32px auto 0; border-top: 1px solid var(--color-border); padding-top: 20px; }\n .x-ha-related h2 { font-size: 15px; font-weight: 700; margin: 0 0 10px; }\n .x-ha-related ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }\n .x-ha-related a { color: var(--color-brand); text-decoration: none; font-weight: 600; font-size: 14px; }\n .x-ha-still { max-width: 720px; margin: 24px auto 0; font-size: 13.5px; color: var(--color-text-muted); }\n .x-ha-still a { color: var(--color-brand); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { HelpArticleComponent } from './help-article.component';\nimport { HelpComponent } from './help.component';\n\n@NgModule({\n declarations: [HelpComponent, HelpArticleComponent],\n imports: [\n SharedModule,\n RouterModule.forChild([\n { path: '', component: HelpComponent },\n { path: ':slug', component: HelpArticleComponent },\n ]),\n ],\n})\nexport class HelpModule {}\n"],"names":["i2","i1"],"mappings":"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"}
@@ -350,6 +350,27 @@ class ProductComponent extends BaseDirective {
350
350
  });
351
351
  };
352
352
  }
353
+ // `longDesc` can carry an imported "Galary Image: <drive link>" line
354
+ // verbatim. Pull those links out of the prose; render the product's own
355
+ // (tilmart-hosted) gallery when it has one, else the linked image itself.
356
+ get descView() {
357
+ const raw = this.product?.longDesc ?? '';
358
+ const ids = [];
359
+ const text = raw
360
+ .replace(/\b(?:galary|gallery|image)[ \w]*:\s*(https?:\/\/\S+)/gi, (_m, url) => {
361
+ const id = url.match(/drive\.google\.com\/file\/d\/([\w-]+)/)?.[1] ?? url.match(/[?&]id=([\w-]+)/)?.[1];
362
+ if (id)
363
+ ids.push(id);
364
+ return '';
365
+ })
366
+ .replace(/https?:\/\/drive\.google\.com\/\S+/gi, '')
367
+ .replace(/[ \t]{2,}/g, ' ')
368
+ .trim();
369
+ const images = this.media.length
370
+ ? []
371
+ : ids.map((id) => `https://drive.google.com/thumbnail?id=${id}&sz=w1200`);
372
+ return { text, images };
373
+ }
353
374
  get activeImageUrl() {
354
375
  return this.media[this.activeImageIndex]?.url;
355
376
  }
@@ -806,11 +827,11 @@ class ProductComponent extends BaseDirective {
806
827
  }));
807
828
  }
808
829
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ProductComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
809
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ProductComponent, isStandalone: false, selector: "x-product", usesInheritance: true, ngImport: i0, template: "@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price \u2014 vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price\u2026</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}\u00D7</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We\u2019ll email you the moment it\u2019s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it\u2019s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel\u2026\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ product.longDesc }}</p>\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n", styles: [".x-pdp-breadcrumb{font-size:12px;color:var(--color-text-muted);margin-bottom:16px}.x-pdp-breadcrumb a{color:var(--color-text-muted);text-decoration:none}.x-pdp-breadcrumb a:hover{text-decoration:underline}.x-pdp-layout{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-bottom:32px}@media(max-width:900px){.x-pdp-layout{grid-template-columns:1fr}}.x-pdp-gallery-main{aspect-ratio:1/1;background:var(--color-surface-2);border-radius:var(--radius-md);overflow:hidden}.x-pdp-gallery-main img{width:100%;height:100%;object-fit:contain}.x-pdp-gallery-placeholder{width:100%;height:100%;background-image:repeating-linear-gradient(45deg,var(--color-surface-2),var(--color-surface-2) 10px,var(--color-surface-3) 10px,var(--color-surface-3) 20px)}.x-pdp-gallery-thumbs{display:flex;gap:8px;margin-top:8px}.x-pdp-thumb{width:56px;height:56px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);padding:0;overflow:hidden;cursor:pointer}.x-pdp-thumb img{width:100%;height:100%;object-fit:contain}.x-pdp-thumb-active{border-color:var(--color-brand)}.x-pdp-buybox{display:flex;flex-direction:column;gap:8px}.x-pdp-brand{font-family:var(--font-mono);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted)}.x-pdp-title{font-family:var(--font-sans);font-size:24px;font-weight:800;color:var(--color-text);margin:0}.x-pdp-model{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted)}.x-pdp-short-desc{font-size:14px;color:var(--color-text);max-width:480px}.x-pdp-variants{display:flex;flex-wrap:wrap;gap:8px}.x-pdp-variant-btn{font-family:var(--font-mono);font-size:12px;padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);cursor:pointer}.x-pdp-variant-active{border-color:var(--color-brand);color:var(--color-brand)}.x-pdp-price-loading,.x-pdp-no-price{font-size:13px;color:var(--color-text-muted)}.x-pdp-buy-row{display:flex;align-items:center;gap:16px;margin-top:8px}.x-pdp-add-btn{flex:1;font-family:var(--font-sans);font-weight:700;font-size:14px;padding:12px 20px;border:0;border-radius:var(--radius-sm);background:var(--color-brand);color:#fff;cursor:pointer}.x-pdp-add-btn:disabled{opacity:.5;cursor:not-allowed}.x-pdp-oos{margin-top:12px;padding:14px;border:1px solid var(--color-border);border-radius:var(--radius-sm)}.x-pdp-oos-label{font-weight:700;font-size:13px;color:var(--color-text)}.x-pdp-oos-hint,.x-pdp-oos-done{font-size:13px;color:var(--color-text-muted);margin:4px 0 10px}.x-pdp-oos-form{display:flex;gap:10px}.x-pdp-oos-input{flex:1;font-family:var(--font-sans);font-size:14px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface, #fff);color:var(--color-text)}.x-pdp-compat{margin-bottom:32px}.x-pdp-compat-search{position:relative;max-width:420px;margin-bottom:12px}.x-pdp-compat-input{width:100%;font-size:13px;padding:8px 12px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text)}.x-pdp-compat-candidates{position:absolute;top:100%;left:0;right:0;z-index:10;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);overflow:hidden}.x-pdp-compat-candidate{display:block;width:100%;text-align:left;padding:8px 12px;font-size:13px;background:none;border:0;color:var(--color-text);cursor:pointer}.x-pdp-compat-candidate:hover{background:var(--color-surface-2)}.x-pdp-related{margin-bottom:32px}.x-pdp-related-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.x-pdp-tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--color-border);margin-bottom:16px}.x-pdp-tab{font-family:var(--font-mono);font-size:12px;padding:10px 14px;background:none;border:0;border-bottom:2px solid transparent;color:var(--color-text-muted);cursor:pointer}.x-pdp-tab-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-pdp-long-desc{font-size:14px;color:var(--color-text);max-width:720px;margin-bottom:16px}.x-pdp-empty{padding:24px 0;color:var(--color-text-muted);font-size:13px}.x-pdp-documents{margin-top:20px}.x-pdp-documents-title{font-weight:700;font-size:13px;margin-bottom:8px}.x-pdp-document{display:block;font-size:13px;color:var(--color-brand);text-decoration:none;margin-bottom:4px}.x-pdp-document:hover{text-decoration:underline}.x-pdp-shipping p{font-size:13px;color:var(--color-text);max-width:560px}.x-pdp-not-found{padding:48px 16px;text-align:center;color:var(--color-text-muted)}.x-pdp-bundle{margin:12px 0 4px}.x-pdp-bundle-save{display:flex;align-items:baseline;gap:8px;margin-top:4px}.x-pdp-bundle-was{font-size:13px;color:var(--color-text-muted);text-decoration:line-through}.x-pdp-bundle-badge{font-size:13px;font-weight:600;color:var(--color-success, #1a7f37)}.x-pdp-bundle-note{font-size:12px;color:var(--color-text-muted);margin-top:2px}.x-pdp-bundle-items{margin:12px 0;padding:12px;background:var(--color-surface-2);border-radius:var(--radius-md)}.x-pdp-bundle-items-title{font-size:13px;font-weight:600;margin-bottom:8px}.x-pdp-bundle-item{display:flex;align-items:center;gap:8px;font-size:13px;padding:4px 0}.x-pdp-bundle-item-img{width:32px;height:32px;object-fit:contain;border-radius:var(--radius-sm);background:var(--color-surface-1)}.x-pdp-bundle-item-qty{color:var(--color-text-muted);font-variant-numeric:tabular-nums}.x-pdp-bundle-item-name{color:var(--color-text);text-decoration:none}a.x-pdp-bundle-item-name:hover{text-decoration:underline;color:var(--color-brand)}.x-pdp-bundle-item-opt{font-size:11px;color:var(--color-text-muted);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:0 4px}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i3.QuantityStepperComponent, selector: "x-tilmart-quantity-stepper", inputs: ["value", "min", "size"], outputs: ["inc", "dec"] }, { kind: "component", type: i3.SectionHeaderComponent, selector: "x-tilmart-section-header", inputs: ["title", "actionLabel", "actionUrl", "actionHref"], outputs: ["action"] }, { kind: "component", type: i3.PriceComponent, selector: "x-tilmart-price", inputs: ["amount", "currency", "compareAtAmount", "perUnitAmount", "perUnitLabel", "showVat", "size"] }, { kind: "component", type: i3.ProductCardComponent, selector: "x-tilmart-product-card", inputs: ["href", "imageUrl", "brandName", "name", "specLine", "rating", "ratingCount", "price", "compareAtPrice", "perUnitAmount", "perUnitLabel", "inStock", "stockLabel", "badges", "wishlisted", "compareSelected"], outputs: ["addToCart", "specs", "wishlistChange", "compareChange"] }, { kind: "component", type: i3.SpecTableComponent, selector: "x-tilmart-spec-table", inputs: ["groups"] }, { kind: "component", type: i3.CompatVerdictComponent, selector: "x-tilmart-compat-verdict", inputs: ["loading", "verdict", "findings"], outputs: ["applyFix"] }, { kind: "component", type: ReviewsPanelComponent, selector: "x-pdp-reviews", inputs: ["productId"] }, { kind: "component", type: QnaPanelComponent, selector: "x-pdp-qna", inputs: ["productId"] }, { kind: "pipe", type: i2$1.DecimalPipe, name: "number" }] }); }
830
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ProductComponent, isStandalone: false, selector: "x-product", usesInheritance: true, ngImport: i0, template: "@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price \u2014 vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price\u2026</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount * quantity\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n @if (quantity > 1) {\n <div class=\"x-pdp-bundle-note\">{{ quantity }} \u00D7 unit price</div>\n }\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}\u00D7</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We\u2019ll email you the moment it\u2019s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it\u2019s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel\u2026\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ descView.text }}</p>\n @for (src of descView.images; track src) {\n <img class=\"x-pdp-desc-img\" [src]=\"src\" [alt]=\"product.name\" loading=\"lazy\" />\n }\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n", styles: [".x-pdp-breadcrumb{font-size:12px;color:var(--color-text-muted);margin-bottom:16px}.x-pdp-breadcrumb a{color:var(--color-text-muted);text-decoration:none}.x-pdp-breadcrumb a:hover{text-decoration:underline}.x-pdp-layout{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-bottom:32px}@media(max-width:900px){.x-pdp-layout{grid-template-columns:1fr}}.x-pdp-gallery-main{aspect-ratio:1/1;background:var(--color-surface-2);border-radius:var(--radius-md);overflow:hidden}.x-pdp-gallery-main img{width:100%;height:100%;object-fit:contain}.x-pdp-gallery-placeholder{width:100%;height:100%;background-image:repeating-linear-gradient(45deg,var(--color-surface-2),var(--color-surface-2) 10px,var(--color-surface-3) 10px,var(--color-surface-3) 20px)}.x-pdp-gallery-thumbs{display:flex;gap:8px;margin-top:8px}.x-pdp-thumb{width:56px;height:56px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);padding:0;overflow:hidden;cursor:pointer}.x-pdp-thumb img{width:100%;height:100%;object-fit:contain}.x-pdp-thumb-active{border-color:var(--color-brand)}.x-pdp-buybox{display:flex;flex-direction:column;gap:8px}.x-pdp-brand{font-family:var(--font-mono);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted)}.x-pdp-title{font-family:var(--font-sans);font-size:24px;font-weight:800;color:var(--color-text);margin:0}.x-pdp-model{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted)}.x-pdp-short-desc{font-size:14px;color:var(--color-text);max-width:480px}.x-pdp-variants{display:flex;flex-wrap:wrap;gap:8px}.x-pdp-variant-btn{font-family:var(--font-mono);font-size:12px;padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);cursor:pointer}.x-pdp-variant-active{border-color:var(--color-brand);color:var(--color-brand)}.x-pdp-price-loading,.x-pdp-no-price{font-size:13px;color:var(--color-text-muted)}.x-pdp-buy-row{display:flex;align-items:center;gap:16px;margin-top:8px}.x-pdp-add-btn{flex:1;font-family:var(--font-sans);font-weight:700;font-size:14px;padding:12px 20px;border:0;border-radius:var(--radius-sm);background:var(--color-brand);color:#fff;cursor:pointer}.x-pdp-add-btn:disabled{opacity:.5;cursor:not-allowed}.x-pdp-oos{margin-top:12px;padding:14px;border:1px solid var(--color-border);border-radius:var(--radius-sm)}.x-pdp-oos-label{font-weight:700;font-size:13px;color:var(--color-text)}.x-pdp-oos-hint,.x-pdp-oos-done{font-size:13px;color:var(--color-text-muted);margin:4px 0 10px}.x-pdp-oos-form{display:flex;gap:10px}.x-pdp-oos-input{flex:1;font-family:var(--font-sans);font-size:14px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface, #fff);color:var(--color-text)}.x-pdp-compat{margin-bottom:32px}.x-pdp-compat-search{position:relative;max-width:420px;margin-bottom:12px}.x-pdp-compat-input{width:100%;font-size:13px;padding:8px 12px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text)}.x-pdp-compat-candidates{position:absolute;top:100%;left:0;right:0;z-index:10;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);overflow:hidden}.x-pdp-compat-candidate{display:block;width:100%;text-align:left;padding:8px 12px;font-size:13px;background:none;border:0;color:var(--color-text);cursor:pointer}.x-pdp-compat-candidate:hover{background:var(--color-surface-2)}.x-pdp-related{margin-bottom:32px}.x-pdp-related-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.x-pdp-tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--color-border);margin-bottom:16px}.x-pdp-tab{font-family:var(--font-mono);font-size:12px;padding:10px 14px;background:none;border:0;border-bottom:2px solid transparent;color:var(--color-text-muted);cursor:pointer}.x-pdp-tab-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-pdp-long-desc{font-size:14px;color:var(--color-text);max-width:720px;margin-bottom:16px}.x-pdp-empty{padding:24px 0;color:var(--color-text-muted);font-size:13px}.x-pdp-documents{margin-top:20px}.x-pdp-documents-title{font-weight:700;font-size:13px;margin-bottom:8px}.x-pdp-document{display:block;font-size:13px;color:var(--color-brand);text-decoration:none;margin-bottom:4px}.x-pdp-document:hover{text-decoration:underline}.x-pdp-shipping p{font-size:13px;color:var(--color-text);max-width:560px}.x-pdp-not-found{padding:48px 16px;text-align:center;color:var(--color-text-muted)}.x-pdp-bundle{margin:12px 0 4px}.x-pdp-bundle-save{display:flex;align-items:baseline;gap:8px;margin-top:4px}.x-pdp-bundle-was{font-size:13px;color:var(--color-text-muted);text-decoration:line-through}.x-pdp-bundle-badge{font-size:13px;font-weight:600;color:var(--color-success, #1a7f37)}.x-pdp-bundle-note{font-size:12px;color:var(--color-text-muted);margin-top:2px}.x-pdp-bundle-items{margin:12px 0;padding:12px;background:var(--color-surface-2);border-radius:var(--radius-md)}.x-pdp-bundle-items-title{font-size:13px;font-weight:600;margin-bottom:8px}.x-pdp-bundle-item{display:flex;align-items:center;gap:8px;font-size:13px;padding:4px 0}.x-pdp-bundle-item-img{width:32px;height:32px;object-fit:contain;border-radius:var(--radius-sm);background:var(--color-surface-1)}.x-pdp-bundle-item-qty{color:var(--color-text-muted);font-variant-numeric:tabular-nums}.x-pdp-bundle-item-name{color:var(--color-text);text-decoration:none}a.x-pdp-bundle-item-name:hover{text-decoration:underline;color:var(--color-brand)}.x-pdp-bundle-item-opt{font-size:11px;color:var(--color-text-muted);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:0 4px}.x-pdp-long-desc{white-space:pre-line}.x-pdp-desc-img{display:block;max-width:100%;height:auto;margin:12px 0;border-radius:8px}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i3.QuantityStepperComponent, selector: "x-tilmart-quantity-stepper", inputs: ["value", "min", "size"], outputs: ["inc", "dec"] }, { kind: "component", type: i3.SectionHeaderComponent, selector: "x-tilmart-section-header", inputs: ["title", "actionLabel", "actionUrl", "actionHref"], outputs: ["action"] }, { kind: "component", type: i3.PriceComponent, selector: "x-tilmart-price", inputs: ["amount", "currency", "compareAtAmount", "perUnitAmount", "perUnitLabel", "showVat", "size"] }, { kind: "component", type: i3.ProductCardComponent, selector: "x-tilmart-product-card", inputs: ["href", "imageUrl", "brandName", "name", "specLine", "rating", "ratingCount", "price", "compareAtPrice", "perUnitAmount", "perUnitLabel", "inStock", "stockLabel", "badges", "wishlisted", "compareSelected"], outputs: ["addToCart", "specs", "wishlistChange", "compareChange"] }, { kind: "component", type: i3.SpecTableComponent, selector: "x-tilmart-spec-table", inputs: ["groups"] }, { kind: "component", type: i3.CompatVerdictComponent, selector: "x-tilmart-compat-verdict", inputs: ["loading", "verdict", "findings"], outputs: ["applyFix"] }, { kind: "component", type: ReviewsPanelComponent, selector: "x-pdp-reviews", inputs: ["productId"] }, { kind: "component", type: QnaPanelComponent, selector: "x-pdp-qna", inputs: ["productId"] }, { kind: "pipe", type: i2$1.DecimalPipe, name: "number" }] }); }
810
831
  }
811
832
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ProductComponent, decorators: [{
812
833
  type: Component,
813
- args: [{ standalone: false, selector: 'x-product', template: "@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price \u2014 vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price\u2026</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}\u00D7</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We\u2019ll email you the moment it\u2019s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it\u2019s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel\u2026\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ product.longDesc }}</p>\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n", styles: [".x-pdp-breadcrumb{font-size:12px;color:var(--color-text-muted);margin-bottom:16px}.x-pdp-breadcrumb a{color:var(--color-text-muted);text-decoration:none}.x-pdp-breadcrumb a:hover{text-decoration:underline}.x-pdp-layout{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-bottom:32px}@media(max-width:900px){.x-pdp-layout{grid-template-columns:1fr}}.x-pdp-gallery-main{aspect-ratio:1/1;background:var(--color-surface-2);border-radius:var(--radius-md);overflow:hidden}.x-pdp-gallery-main img{width:100%;height:100%;object-fit:contain}.x-pdp-gallery-placeholder{width:100%;height:100%;background-image:repeating-linear-gradient(45deg,var(--color-surface-2),var(--color-surface-2) 10px,var(--color-surface-3) 10px,var(--color-surface-3) 20px)}.x-pdp-gallery-thumbs{display:flex;gap:8px;margin-top:8px}.x-pdp-thumb{width:56px;height:56px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);padding:0;overflow:hidden;cursor:pointer}.x-pdp-thumb img{width:100%;height:100%;object-fit:contain}.x-pdp-thumb-active{border-color:var(--color-brand)}.x-pdp-buybox{display:flex;flex-direction:column;gap:8px}.x-pdp-brand{font-family:var(--font-mono);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted)}.x-pdp-title{font-family:var(--font-sans);font-size:24px;font-weight:800;color:var(--color-text);margin:0}.x-pdp-model{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted)}.x-pdp-short-desc{font-size:14px;color:var(--color-text);max-width:480px}.x-pdp-variants{display:flex;flex-wrap:wrap;gap:8px}.x-pdp-variant-btn{font-family:var(--font-mono);font-size:12px;padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);cursor:pointer}.x-pdp-variant-active{border-color:var(--color-brand);color:var(--color-brand)}.x-pdp-price-loading,.x-pdp-no-price{font-size:13px;color:var(--color-text-muted)}.x-pdp-buy-row{display:flex;align-items:center;gap:16px;margin-top:8px}.x-pdp-add-btn{flex:1;font-family:var(--font-sans);font-weight:700;font-size:14px;padding:12px 20px;border:0;border-radius:var(--radius-sm);background:var(--color-brand);color:#fff;cursor:pointer}.x-pdp-add-btn:disabled{opacity:.5;cursor:not-allowed}.x-pdp-oos{margin-top:12px;padding:14px;border:1px solid var(--color-border);border-radius:var(--radius-sm)}.x-pdp-oos-label{font-weight:700;font-size:13px;color:var(--color-text)}.x-pdp-oos-hint,.x-pdp-oos-done{font-size:13px;color:var(--color-text-muted);margin:4px 0 10px}.x-pdp-oos-form{display:flex;gap:10px}.x-pdp-oos-input{flex:1;font-family:var(--font-sans);font-size:14px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface, #fff);color:var(--color-text)}.x-pdp-compat{margin-bottom:32px}.x-pdp-compat-search{position:relative;max-width:420px;margin-bottom:12px}.x-pdp-compat-input{width:100%;font-size:13px;padding:8px 12px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text)}.x-pdp-compat-candidates{position:absolute;top:100%;left:0;right:0;z-index:10;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);overflow:hidden}.x-pdp-compat-candidate{display:block;width:100%;text-align:left;padding:8px 12px;font-size:13px;background:none;border:0;color:var(--color-text);cursor:pointer}.x-pdp-compat-candidate:hover{background:var(--color-surface-2)}.x-pdp-related{margin-bottom:32px}.x-pdp-related-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.x-pdp-tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--color-border);margin-bottom:16px}.x-pdp-tab{font-family:var(--font-mono);font-size:12px;padding:10px 14px;background:none;border:0;border-bottom:2px solid transparent;color:var(--color-text-muted);cursor:pointer}.x-pdp-tab-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-pdp-long-desc{font-size:14px;color:var(--color-text);max-width:720px;margin-bottom:16px}.x-pdp-empty{padding:24px 0;color:var(--color-text-muted);font-size:13px}.x-pdp-documents{margin-top:20px}.x-pdp-documents-title{font-weight:700;font-size:13px;margin-bottom:8px}.x-pdp-document{display:block;font-size:13px;color:var(--color-brand);text-decoration:none;margin-bottom:4px}.x-pdp-document:hover{text-decoration:underline}.x-pdp-shipping p{font-size:13px;color:var(--color-text);max-width:560px}.x-pdp-not-found{padding:48px 16px;text-align:center;color:var(--color-text-muted)}.x-pdp-bundle{margin:12px 0 4px}.x-pdp-bundle-save{display:flex;align-items:baseline;gap:8px;margin-top:4px}.x-pdp-bundle-was{font-size:13px;color:var(--color-text-muted);text-decoration:line-through}.x-pdp-bundle-badge{font-size:13px;font-weight:600;color:var(--color-success, #1a7f37)}.x-pdp-bundle-note{font-size:12px;color:var(--color-text-muted);margin-top:2px}.x-pdp-bundle-items{margin:12px 0;padding:12px;background:var(--color-surface-2);border-radius:var(--radius-md)}.x-pdp-bundle-items-title{font-size:13px;font-weight:600;margin-bottom:8px}.x-pdp-bundle-item{display:flex;align-items:center;gap:8px;font-size:13px;padding:4px 0}.x-pdp-bundle-item-img{width:32px;height:32px;object-fit:contain;border-radius:var(--radius-sm);background:var(--color-surface-1)}.x-pdp-bundle-item-qty{color:var(--color-text-muted);font-variant-numeric:tabular-nums}.x-pdp-bundle-item-name{color:var(--color-text);text-decoration:none}a.x-pdp-bundle-item-name:hover{text-decoration:underline;color:var(--color-brand)}.x-pdp-bundle-item-opt{font-size:11px;color:var(--color-text-muted);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:0 4px}\n"] }]
834
+ args: [{ standalone: false, selector: 'x-product', template: "@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price \u2014 vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price\u2026</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount * quantity\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n @if (quantity > 1) {\n <div class=\"x-pdp-bundle-note\">{{ quantity }} \u00D7 unit price</div>\n }\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}\u00D7</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We\u2019ll email you the moment it\u2019s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it\u2019s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel\u2026\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ descView.text }}</p>\n @for (src of descView.images; track src) {\n <img class=\"x-pdp-desc-img\" [src]=\"src\" [alt]=\"product.name\" loading=\"lazy\" />\n }\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n", styles: [".x-pdp-breadcrumb{font-size:12px;color:var(--color-text-muted);margin-bottom:16px}.x-pdp-breadcrumb a{color:var(--color-text-muted);text-decoration:none}.x-pdp-breadcrumb a:hover{text-decoration:underline}.x-pdp-layout{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-bottom:32px}@media(max-width:900px){.x-pdp-layout{grid-template-columns:1fr}}.x-pdp-gallery-main{aspect-ratio:1/1;background:var(--color-surface-2);border-radius:var(--radius-md);overflow:hidden}.x-pdp-gallery-main img{width:100%;height:100%;object-fit:contain}.x-pdp-gallery-placeholder{width:100%;height:100%;background-image:repeating-linear-gradient(45deg,var(--color-surface-2),var(--color-surface-2) 10px,var(--color-surface-3) 10px,var(--color-surface-3) 20px)}.x-pdp-gallery-thumbs{display:flex;gap:8px;margin-top:8px}.x-pdp-thumb{width:56px;height:56px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);padding:0;overflow:hidden;cursor:pointer}.x-pdp-thumb img{width:100%;height:100%;object-fit:contain}.x-pdp-thumb-active{border-color:var(--color-brand)}.x-pdp-buybox{display:flex;flex-direction:column;gap:8px}.x-pdp-brand{font-family:var(--font-mono);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--color-text-muted)}.x-pdp-title{font-family:var(--font-sans);font-size:24px;font-weight:800;color:var(--color-text);margin:0}.x-pdp-model{font-family:var(--font-mono);font-size:12px;color:var(--color-text-muted)}.x-pdp-short-desc{font-size:14px;color:var(--color-text);max-width:480px}.x-pdp-variants{display:flex;flex-wrap:wrap;gap:8px}.x-pdp-variant-btn{font-family:var(--font-mono);font-size:12px;padding:6px 10px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);cursor:pointer}.x-pdp-variant-active{border-color:var(--color-brand);color:var(--color-brand)}.x-pdp-price-loading,.x-pdp-no-price{font-size:13px;color:var(--color-text-muted)}.x-pdp-buy-row{display:flex;align-items:center;gap:16px;margin-top:8px}.x-pdp-add-btn{flex:1;font-family:var(--font-sans);font-weight:700;font-size:14px;padding:12px 20px;border:0;border-radius:var(--radius-sm);background:var(--color-brand);color:#fff;cursor:pointer}.x-pdp-add-btn:disabled{opacity:.5;cursor:not-allowed}.x-pdp-oos{margin-top:12px;padding:14px;border:1px solid var(--color-border);border-radius:var(--radius-sm)}.x-pdp-oos-label{font-weight:700;font-size:13px;color:var(--color-text)}.x-pdp-oos-hint,.x-pdp-oos-done{font-size:13px;color:var(--color-text-muted);margin:4px 0 10px}.x-pdp-oos-form{display:flex;gap:10px}.x-pdp-oos-input{flex:1;font-family:var(--font-sans);font-size:14px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-surface, #fff);color:var(--color-text)}.x-pdp-compat{margin-bottom:32px}.x-pdp-compat-search{position:relative;max-width:420px;margin-bottom:12px}.x-pdp-compat-input{width:100%;font-size:13px;padding:8px 12px;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text)}.x-pdp-compat-candidates{position:absolute;top:100%;left:0;right:0;z-index:10;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);overflow:hidden}.x-pdp-compat-candidate{display:block;width:100%;text-align:left;padding:8px 12px;font-size:13px;background:none;border:0;color:var(--color-text);cursor:pointer}.x-pdp-compat-candidate:hover{background:var(--color-surface-2)}.x-pdp-related{margin-bottom:32px}.x-pdp-related-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.x-pdp-tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--color-border);margin-bottom:16px}.x-pdp-tab{font-family:var(--font-mono);font-size:12px;padding:10px 14px;background:none;border:0;border-bottom:2px solid transparent;color:var(--color-text-muted);cursor:pointer}.x-pdp-tab-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-pdp-long-desc{font-size:14px;color:var(--color-text);max-width:720px;margin-bottom:16px}.x-pdp-empty{padding:24px 0;color:var(--color-text-muted);font-size:13px}.x-pdp-documents{margin-top:20px}.x-pdp-documents-title{font-weight:700;font-size:13px;margin-bottom:8px}.x-pdp-document{display:block;font-size:13px;color:var(--color-brand);text-decoration:none;margin-bottom:4px}.x-pdp-document:hover{text-decoration:underline}.x-pdp-shipping p{font-size:13px;color:var(--color-text);max-width:560px}.x-pdp-not-found{padding:48px 16px;text-align:center;color:var(--color-text-muted)}.x-pdp-bundle{margin:12px 0 4px}.x-pdp-bundle-save{display:flex;align-items:baseline;gap:8px;margin-top:4px}.x-pdp-bundle-was{font-size:13px;color:var(--color-text-muted);text-decoration:line-through}.x-pdp-bundle-badge{font-size:13px;font-weight:600;color:var(--color-success, #1a7f37)}.x-pdp-bundle-note{font-size:12px;color:var(--color-text-muted);margin-top:2px}.x-pdp-bundle-items{margin:12px 0;padding:12px;background:var(--color-surface-2);border-radius:var(--radius-md)}.x-pdp-bundle-items-title{font-size:13px;font-weight:600;margin-bottom:8px}.x-pdp-bundle-item{display:flex;align-items:center;gap:8px;font-size:13px;padding:4px 0}.x-pdp-bundle-item-img{width:32px;height:32px;object-fit:contain;border-radius:var(--radius-sm);background:var(--color-surface-1)}.x-pdp-bundle-item-qty{color:var(--color-text-muted);font-variant-numeric:tabular-nums}.x-pdp-bundle-item-name{color:var(--color-text);text-decoration:none}a.x-pdp-bundle-item-name:hover{text-decoration:underline;color:var(--color-brand)}.x-pdp-bundle-item-opt{font-size:11px;color:var(--color-text-muted);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:0 4px}.x-pdp-long-desc{white-space:pre-line}.x-pdp-desc-img{display:block;max-width:100%;height:auto;margin:12px 0;border-radius:8px}\n"] }]
814
835
  }] });
815
836
  function formatSpecValue(value, dataType) {
816
837
  switch (dataType) {
@@ -849,4 +870,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
849
870
  }] });
850
871
 
851
872
  export { ProductModule };
852
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs.map
873
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs","sources":["../../../projects/buyer/src/lib/pages/product/reviews-panel.component.ts","../../../projects/buyer/src/lib/pages/product/reviews-panel.component.html","../../../projects/buyer/src/lib/pages/product/qna-panel.component.ts","../../../projects/buyer/src/lib/pages/product/qna-panel.component.html","../../../projects/buyer/src/lib/pages/product/product.component.ts","../../../projects/buyer/src/lib/pages/product/product.component.html","../../../projects/buyer/src/lib/pages/product/product.module.ts"],"sourcesContent":["import { Component, Input, OnInit, inject } from '@angular/core';\nimport { ApiService, ControlService, notify } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of } from 'rxjs';\n\ninterface ReviewVm {\n id: string;\n rating: number;\n title?: string;\n body?: string;\n isVerifiedPurchase: boolean;\n helpfulCount: number;\n replyBody?: string;\n createdAt?: string;\n}\n\ninterface SummaryVm {\n count: number;\n average: number;\n distribution: Record<string, number>;\n subRatingAverages: Record<string, number>;\n verifiedCount: number;\n}\n\n// P5.11, UGC-01 — the PDP reviews tab. Rating summary + published\n// reviews + a submit form (the verified-purchase gate + auto-publish is\n// server-side in ReviewsWorkflow).\n@Component({\n standalone: false,\n selector: 'x-pdp-reviews',\n templateUrl: './reviews-panel.component.html',\n styleUrl: './reviews-panel.component.scss',\n})\nexport class ReviewsPanelComponent implements OnInit {\n private readonly apiService = inject(ApiService);\n private readonly controlService = inject(ControlService);\n\n @Input() productId = '';\n\n loading = true;\n summary: SummaryVm | null = null;\n reviews: ReviewVm[] = [];\n customerId = '';\n\n formOpen = false;\n submitting = false;\n formError = '';\n form = { rating: 0, title: '', body: '' };\n readonly stars = [1, 2, 3, 4, 5];\n\n get isLoggedIn(): boolean {\n return this.controlService.isLoggedIn();\n }\n\n get subRatingKeys(): string[] {\n return Object.keys(this.summary?.subRatingAverages ?? {});\n }\n\n async ngOnInit(): Promise<void> {\n if (!this.productId) {\n this.loading = false;\n return;\n }\n await this.resolveCustomer();\n await this.load();\n }\n\n private async resolveCustomer(): Promise<void> {\n const userId = this.controlService.getContext()?.userId;\n if (!userId) return;\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/customer')\n .getMany({ userId, perPage: 1 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n this.customerId = (res?.data ?? [])[0]?.id ?? '';\n }\n\n private async load(): Promise<void> {\n const [summary, reviews] = await Promise.all([\n firstValueFrom(\n this.apiService\n .get(`apps/commerce/review/product/${this.productId}/summary`)\n .pipe(catchError(() => of(undefined))),\n ),\n firstValueFrom(\n this.apiService\n .on('apps/commerce/review')\n .getMany({\n productId: this.productId,\n status: 'published',\n perPage: 50,\n } as any)\n .pipe(catchError(() => of({ data: [] }))),\n ),\n ]);\n this.summary = (summary as any)?.data ?? null;\n this.reviews = ((reviews as any)?.data ?? []).map((r: any) => ({\n id: r.id,\n rating: Number(r.rating ?? 0),\n title: r.title,\n body: r.body,\n isVerifiedPurchase: !!r.isVerifiedPurchase,\n helpfulCount: Number(r.helpfulCount ?? 0),\n replyBody: r.replyBody,\n createdAt: r.createdAt,\n }));\n this.loading = false;\n }\n\n async submit(): Promise<void> {\n if (this.submitting) return;\n if (!this.form.rating) {\n this.formError = 'Pick a star rating.';\n return;\n }\n this.submitting = true;\n this.formError = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/review/submit', {\n targetType: 'product',\n productId: this.productId,\n customerId: this.customerId || undefined,\n rating: this.form.rating,\n title: this.form.title || undefined,\n body: this.form.body || undefined,\n }),\n );\n if (res?.status === 'error') {\n this.formError =\n res?.message === 'already-reviewed'\n ? \"You've already reviewed this product.\"\n : res?.message ?? 'Could not submit your review.';\n return;\n }\n this.formOpen = false;\n this.form = { rating: 0, title: '', body: '' };\n const published = res?.data?.status === 'published';\n notify(\n published ? 'Thanks — your review is live' : 'Thanks — your review is awaiting moderation',\n undefined,\n 'success',\n );\n if (published) await this.load();\n } catch (err: any) {\n this.formError = err?.error?.message ?? 'Could not submit your review.';\n } finally {\n this.submitting = false;\n }\n }\n\n async markHelpful(review: ReviewVm): Promise<void> {\n if (!this.customerId) {\n notify('Sign in to vote', undefined, 'error');\n return;\n }\n try {\n const res: any = await firstValueFrom(\n this.apiService.post(`apps/commerce/review/${review.id}/helpful`, {\n customerId: this.customerId,\n helpful: true,\n }),\n );\n if (res?.data?.helpfulCount != null) review.helpfulCount = res.data.helpfulCount;\n } catch {\n // best-effort\n }\n }\n\n barWidth(star: number): string {\n const n = this.summary?.distribution?.[String(star)] ?? 0;\n const total = this.summary?.count ?? 0;\n return total ? `${Math.round((n / total) * 100)}%` : '0%';\n }\n}\n","@if (loading) {\n <div class=\"x-pdp-empty\">Loading reviews…</div>\n} @else {\n @if (summary && summary.count > 0) {\n <div class=\"x-rv-summary\">\n <div class=\"x-rv-score\">\n <div class=\"x-rv-avg\">{{ summary.average }}</div>\n <div class=\"x-rv-stars\" aria-hidden=\"true\">\n @for (s of stars; track s) {\n <span [class.on]=\"s <= summary.average\">★</span>\n }\n </div>\n <div class=\"x-rv-count\">\n {{ summary.count }} review{{ summary.count === 1 ? '' : 's' }}\n @if (summary.verifiedCount) {\n · {{ summary.verifiedCount }} verified\n }\n </div>\n </div>\n <div class=\"x-rv-bars\">\n @for (s of [5, 4, 3, 2, 1]; track s) {\n <div class=\"x-rv-bar-row\">\n <span>{{ s }}★</span>\n <span class=\"x-rv-bar\"><span [style.width]=\"barWidth(s)\"></span></span>\n <span>{{ summary.distribution[s + ''] || 0 }}</span>\n </div>\n }\n </div>\n @if (subRatingKeys.length) {\n <div class=\"x-rv-subs\">\n @for (k of subRatingKeys; track k) {\n <div class=\"x-rv-sub\">\n <span>{{ k }}</span>\n <strong>{{ summary.subRatingAverages[k] }}</strong>\n </div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"x-pdp-empty\">No reviews yet — be the first.</div>\n }\n\n @if (formOpen) {\n <div class=\"x-rv-form\">\n <div class=\"x-rv-star-pick\">\n @for (s of stars; track s) {\n <button type=\"button\" [class.on]=\"s <= form.rating\" (click)=\"form.rating = s\">★</button>\n }\n </div>\n <input class=\"x-rv-input\" [(ngModel)]=\"form.title\" placeholder=\"Sum it up (optional)\" />\n <textarea class=\"x-rv-input\" rows=\"3\" [(ngModel)]=\"form.body\" placeholder=\"What did you think?\"></textarea>\n @if (formError) {\n <div class=\"x-rv-err\">{{ formError }}</div>\n }\n <button class=\"x-rv-btn\" [disabled]=\"submitting\" (click)=\"submit()\">\n {{ submitting ? 'Submitting…' : 'Post review' }}\n </button>\n <button class=\"x-rv-btn-ghost\" (click)=\"formOpen = false\">Cancel</button>\n </div>\n } @else {\n <button class=\"x-rv-btn\" (click)=\"formOpen = true\">Write a review</button>\n }\n\n @for (r of reviews; track r.id) {\n <div class=\"x-rv-item\">\n <div class=\"x-rv-item-head\">\n <span class=\"x-rv-stars\" aria-hidden=\"true\">\n @for (s of stars; track s) {\n <span [class.on]=\"s <= r.rating\">★</span>\n }\n </span>\n @if (r.isVerifiedPurchase) {\n <span class=\"x-rv-verified\">Verified purchase</span>\n }\n </div>\n @if (r.title) {\n <strong>{{ r.title }}</strong>\n }\n @if (r.body) {\n <p>{{ r.body }}</p>\n }\n @if (r.replyBody) {\n <div class=\"x-rv-reply\"><strong>Response from Tilmart:</strong> {{ r.replyBody }}</div>\n }\n <button class=\"x-rv-helpful\" (click)=\"markHelpful(r)\">\n Helpful @if (r.helpfulCount) { ({{ r.helpfulCount }}) }\n </button>\n </div>\n }\n}\n","import { Component, Input, OnInit, inject } from '@angular/core';\nimport { ApiService, ControlService, notify } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of } from 'rxjs';\n\ninterface AnswerVm {\n id: string;\n body: string;\n isOfficial: boolean;\n createdAt?: string;\n}\n\ninterface QuestionVm {\n id: string;\n body: string;\n createdAt?: string;\n answers: AnswerVm[];\n answering: boolean;\n draft: string;\n}\n\n// P5.11, UGC-04 — the PDP Q&A tab. Published questions + answers, an\n// \"ask a question\" form and an inline answer box.\n@Component({\n standalone: false,\n selector: 'x-pdp-qna',\n templateUrl: './qna-panel.component.html',\n styleUrl: './reviews-panel.component.scss',\n})\nexport class QnaPanelComponent implements OnInit {\n private readonly apiService = inject(ApiService);\n private readonly controlService = inject(ControlService);\n\n @Input() productId = '';\n\n loading = true;\n questions: QuestionVm[] = [];\n customerId = '';\n\n askOpen = false;\n asking = false;\n askError = '';\n askDraft = '';\n\n async ngOnInit(): Promise<void> {\n if (!this.productId) {\n this.loading = false;\n return;\n }\n const userId = this.controlService.getContext()?.userId;\n if (userId) {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/customer')\n .getMany({ userId, perPage: 1 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n this.customerId = (res?.data ?? [])[0]?.id ?? '';\n }\n await this.load();\n }\n\n private async load(): Promise<void> {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/question')\n .getMany({\n productId: this.productId,\n status: 'published',\n perPage: 50,\n } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n const rows: any[] = res?.data ?? [];\n this.questions = await Promise.all(\n rows.map(async (q) => {\n const ans: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/answer')\n .getMany({ questionId: q.id, status: 'published', perPage: 20 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n return {\n id: q.id,\n body: q.body,\n createdAt: q.createdAt,\n answers: (ans?.data ?? []).map((a: any) => ({\n id: a.id,\n body: a.body,\n isOfficial: !!a.isOfficial,\n createdAt: a.createdAt,\n })),\n answering: false,\n draft: '',\n } as QuestionVm;\n }),\n );\n this.loading = false;\n }\n\n async ask(): Promise<void> {\n if (this.asking || !this.askDraft.trim()) return;\n this.asking = true;\n this.askError = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/question/ask', {\n productId: this.productId,\n customerId: this.customerId || undefined,\n body: this.askDraft.trim(),\n }),\n );\n if (res?.status === 'error') {\n this.askError = res?.message ?? 'Could not post your question.';\n return;\n }\n this.askOpen = false;\n this.askDraft = '';\n notify('Thanks — your question is awaiting moderation', undefined, 'success');\n } catch (err: any) {\n this.askError = err?.error?.message ?? 'Could not post your question.';\n } finally {\n this.asking = false;\n }\n }\n\n async answer(q: QuestionVm): Promise<void> {\n if (!q.draft.trim()) return;\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/answer/post', {\n questionId: q.id,\n customerId: this.customerId || undefined,\n body: q.draft.trim(),\n }),\n );\n if (res?.status === 'error') {\n notify(res?.message ?? 'Could not post your answer.', undefined, 'error');\n return;\n }\n q.answering = false;\n q.draft = '';\n notify('Thanks — your answer is awaiting moderation', undefined, 'success');\n } catch {\n notify('Could not post your answer.', undefined, 'error');\n }\n }\n}\n","@if (loading) {\n <div class=\"x-pdp-empty\">Loading questions…</div>\n} @else {\n @if (askOpen) {\n <div class=\"x-rv-form\">\n <textarea\n class=\"x-rv-input\"\n rows=\"2\"\n [(ngModel)]=\"askDraft\"\n placeholder=\"Ask about fit, specs, compatibility…\"\n ></textarea>\n @if (askError) {\n <div class=\"x-rv-err\">{{ askError }}</div>\n }\n <button class=\"x-rv-btn\" [disabled]=\"asking\" (click)=\"ask()\">\n {{ asking ? 'Posting…' : 'Post question' }}\n </button>\n <button class=\"x-rv-btn-ghost\" (click)=\"askOpen = false\">Cancel</button>\n </div>\n } @else {\n <button class=\"x-rv-btn\" (click)=\"askOpen = true\">Ask a question</button>\n }\n\n @for (q of questions; track q.id) {\n <div class=\"x-rv-item\">\n <strong>Q: {{ q.body }}</strong>\n @for (a of q.answers; track a.id) {\n <p>\n <strong>A:</strong> {{ a.body }}\n @if (a.isOfficial) {\n <span class=\"x-rv-verified\">Tilmart</span>\n }\n </p>\n }\n @if (q.answering) {\n <textarea class=\"x-rv-input\" rows=\"2\" [(ngModel)]=\"q.draft\" placeholder=\"Your answer\"></textarea>\n <button class=\"x-rv-btn\" (click)=\"answer(q)\">Post answer</button>\n <button class=\"x-rv-btn-ghost\" (click)=\"q.answering = false\">Cancel</button>\n } @else {\n <button class=\"x-rv-helpful\" (click)=\"q.answering = true\">Answer this</button>\n }\n </div>\n } @empty {\n <div class=\"x-pdp-empty\">No questions yet.</div>\n }\n}\n","import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { CompatVerdictFinding } from '@isaiahiroko/tilmart-ngx-ui';\nimport { Observable, catchError, firstValueFrom, forkJoin, map, of, switchMap, takeUntil } from 'rxjs';\nimport { blobUrl } from '../../data/media';\nimport { ProductCardVm, SearchResultItemDto } from '../../data/search-result-card';\nimport { CartAddService } from '../../services/cart-add.service';\nimport { CompareTrayService } from '../../services/compare-tray.service';\nimport { SeoService } from '../../services/seo.service';\n\nconst RELATION_TYPE_LABELS: Record<string, string> = {\n bought_together: 'Frequently bought together',\n required_accessory: 'You also need',\n recommended_accessory: 'Recommended accessories',\n compatible_with: 'Compatible with',\n upgrade: 'Upgrade path',\n replaces: 'Replaces',\n};\n\n// P2.8, PDP-01/02/09/10 — gallery, grouped spec table with plain-language\n// disclosure, tabs (specs/reviews/shipping/Q&A — reviews and Q&A are\n// documented no-ops, `Review`/`Question` don't exist until P5.10/later),\n// price box, buy row. PDP-03's \"will this work for me\" runtime/generation\n// estimates need `SizingWorkflow` (P3, unbuilt) and are NOT attempted\n// here — only the part of PDP-04/PDP-06 that P2.9 actually built for:\n// \"works with what I already have\" against an arbitrary catalogue pick\n// (no `MySystem`/saved-systems entity exists yet, P5).\n//\n// Every list endpoint here is fetched as one broad, unfiltered page and\n// joined/filtered client-side (same convention as every other page this\n// phase) — `perPage: 1000` on the genuinely workspace-wide ones\n// (attribute values, variants, media, documents) rather than the 200 used\n// elsewhere, since a real catalogue's `ProductAttributeValue` table alone\n// is easily 15 rows x 400 SKUs. **This is a real, documented R1-scale\n// ceiling** (TRD §10.4's own \"~400 SKUs\" framing), not an oversight —\n// spec/gallery data would start silently truncating past a few thousand\n// total rows workspace-wide. A real `?productId=` filtered endpoint is\n// the actual fix, whenever this stops being good enough.\n@Component({\n standalone: false,\n selector: 'x-product',\n templateUrl: './product.component.html',\n styleUrl: './product.component.scss',\n})\nexport class ProductComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly seo = inject(SeoService);\n readonly cartAdd = inject(CartAddService);\n readonly compareTray = inject(CompareTrayService);\n private readonly productSource = this.apiService.on('apps/commerce/product');\n private readonly variantSource = this.apiService.on('apps/commerce/product-variant');\n private readonly mediaSource = this.apiService.on('apps/commerce/product-media');\n private readonly documentSource = this.apiService.on('apps/commerce/product-document');\n private readonly attrValueSource = this.apiService.on('apps/commerce/product-attribute-value');\n private readonly attrDefSource = this.apiService.on('apps/commerce/attribute-definition');\n private readonly categorySource = this.apiService.on('apps/commerce/category');\n private readonly brandSource = this.apiService.on('apps/commerce/brand');\n private readonly searchSource = this.apiService.on('apps/commerce/search');\n private readonly relationSource = this.apiService.on('apps/commerce/product-relation');\n private readonly kitSource = this.apiService.on('apps/commerce/kit');\n\n private allProducts: any[] = [];\n private allVariants: any[] = [];\n private allMedia: any[] = [];\n\n product?: any;\n notFound = false;\n brandName?: string;\n categoryData?: any;\n\n variants: any[] = [];\n selectedVariant?: any;\n\n media: { blobId: string; altText: string; url: string; thumb: string }[] = [];\n activeImageIndex = 0;\n\n documents: any[] = [];\n\n specGroups: { label: string; rows: SpecRowVm[] }[] = [];\n\n price?: { amount: number; currency: string };\n priceLoading = false;\n quantity = 1;\n\n // PDP-08 — back-in-stock signup for the selected variant.\n stockAvailable?: number;\n bisEmail = '';\n bisSubmitting = false;\n bisSubmitted = false;\n private readonly stockNotificationSource = this.apiService.on(\n 'apps/commerce/stock-notification',\n );\n\n // PROMO-05 — a `type = kit` product shows its bundle price against the\n // component sum, plus what's inside.\n kit?: {\n amount: number;\n currency: string;\n pricingMode: string;\n componentSum: number;\n savings: number;\n savingsPct: number;\n items: {\n name: string;\n quantity: number;\n lineTotal?: number;\n isRequired: boolean;\n imageUrl?: string;\n slug?: string;\n }[];\n };\n kitLoading = false;\n\n activeTab: 'specs' | 'reviews' | 'shipping' | 'qna' = 'specs';\n\n compatQuery = '';\n compatCandidates: SearchResultItemDto[] = [];\n compatSelected?: SearchResultItemDto;\n compatVerdict: 'pass' | 'warn' | 'block' | null = null;\n compatFindings: CompatVerdictFinding[] = [];\n compatLoading = false;\n\n relatedGroups: { type: string; label: string; items: ProductCardVm[] }[] = [];\n\n // `longDesc` can carry an imported \"Galary Image: <drive link>\" line\n // verbatim. Pull those links out of the prose; render the product's own\n // (tilmart-hosted) gallery when it has one, else the linked image itself.\n get descView(): { text: string; images: string[] } {\n const raw: string = this.product?.longDesc ?? '';\n const ids: string[] = [];\n const text = raw\n .replace(/\\b(?:galary|gallery|image)[ \\w]*:\\s*(https?:\\/\\/\\S+)/gi, (_m, url: string) => {\n const id = url.match(/drive\\.google\\.com\\/file\\/d\\/([\\w-]+)/)?.[1] ?? url.match(/[?&]id=([\\w-]+)/)?.[1];\n if (id) ids.push(id);\n return '';\n })\n .replace(/https?:\\/\\/drive\\.google\\.com\\/\\S+/gi, '')\n .replace(/[ \\t]{2,}/g, ' ')\n .trim();\n const images = this.media.length\n ? []\n : ids.map((id) => `https://drive.google.com/thumbnail?id=${id}&sz=w1200`);\n return { text, images };\n }\n\n get activeImageUrl(): string | undefined {\n return this.media[this.activeImageIndex]?.url;\n }\n\n override init = () => {\n this.route.paramMap.pipe(takeUntil(this.$)).subscribe((params) => {\n const slug = params.get('slug');\n if (!slug) return;\n this.loadProduct(slug);\n });\n };\n\n // Cards link here with `#specs` — the router's anchor scrolling can't\n // help since the target only exists once the product has loaded.\n private scrollToFragment(): void {\n const fragment = this.route.snapshot.fragment;\n if (!fragment) return;\n if (fragment === 'specs') this.activeTab = 'specs';\n setTimeout(() => document.getElementById(fragment)?.scrollIntoView({ behavior: 'smooth' }), 0);\n }\n\n // Server-side filters (`?slug=`, `?productId=` …) rather than paging the\n // whole catalogue: the CRUD list caps `perPage` at 200 (so \"everything\"\n // silently truncated) and a PDP on a slow link shouldn't pull every SKU.\n private loadProduct(slug: string): void {\n this.product = undefined;\n this.notFound = false;\n this.allProducts = [];\n this.allVariants = [];\n this.allMedia = [];\n this.productSource\n .getMany({ slug, page: 1, perPage: 1 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const product = (response?.data ?? []).find((p: any) => p.slug === slug);\n if (!product) {\n this.notFound = true;\n return;\n }\n this.allProducts = [product];\n this.product = product;\n void this.seo.apply({ entityType: 'product', entityId: product.id });\n this.loadDetails(product);\n }),\n );\n }\n\n private loadDetails(product: any): void {\n forkJoin({\n variants: this.variantSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n media: this.mediaSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n documents: this.documentSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n relations: this.relationSource.getMany({\n fromProductId: product.id,\n page: 1,\n perPage: 200,\n } as any),\n brand: product.brandId ? this.brandSource.getOne(product.brandId) : of(null),\n category: product.primaryCategoryId\n ? this.categorySource.getOne(product.primaryCategoryId)\n : of(null),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using(({ variants, media, documents, relations, brand, category }: any) => {\n this.allVariants = variants?.data ?? [];\n this.allMedia = media?.data ?? [];\n\n this.variants = this.allVariants.filter((v: any) => v.productId === product.id);\n this.media = this.allMedia\n .filter((m: any) => m.productId === product.id)\n .sort((a: any, b: any) => a.position - b.position)\n .map((m: any) => ({ blobId: m.blobId, altText: m.altText, url: blobUrl(m.blobId, 1200)!, thumb: blobUrl(m.blobId, 160)! }));\n this.documents = (documents?.data ?? [])\n .filter((d: any) => d.productId === product.id)\n .map((d: any) => ({ ...d, url: blobUrl(d.blobId) }));\n this.brandName = brand?.data?.name;\n this.categoryData = category?.data;\n\n this.selectedVariant = this.variants[0];\n this.scrollToFragment();\n if (this.selectedVariant) {\n this.loadPrice();\n this.loadStock();\n }\n if (this.categoryData) {\n this.loadSpecs(this.categoryData);\n }\n if (product.type === 'kit') {\n this.loadKit(product);\n }\n\n this.loadRelated(product, relations?.data ?? []);\n }),\n );\n }\n\n // CAT-09/PDP-08 — \"frequently bought with this\" etc. Related-accessory\n // suggestions are run through `evaluateCompatibility` before display\n // (this entity's own doc comment says as much) and dropped if the pair\n // comes back `block` — surfacing an accessory the compatibility engine\n // itself would reject on add-to-cart is worse than not suggesting it.\n private loadRelated(product: any, relations: any[]): void {\n const relatedIds = relations\n .filter((r) => r.fromProductId === product.id)\n .map((r) => r.toProductId as string);\n if (!relatedIds.length) {\n this.relatedGroups = [];\n return;\n }\n this.hydrate({ productIds: relatedIds })\n .pipe(takeUntil(this.$))\n .subscribe(() => this.renderRelated(product, relations));\n }\n\n // Pulls just the referenced products (+ their variants and media) into\n // the page caches — a handful of by-id reads instead of the catalogue.\n private hydrate(refs: { productIds?: string[]; variantIds?: string[] }): Observable<void> {\n const knownVariants = new Set(this.allVariants.map((v) => v.id));\n const variantIds = Array.from(new Set(refs.variantIds ?? [])).filter(\n (id) => !knownVariants.has(id),\n );\n\n const variantsById$: Observable<any[]> = variantIds.length\n ? forkJoin(\n variantIds.map((id) =>\n this.variantSource.getOne(id).pipe(\n map((r: any) => r?.data),\n catchError(() => of(undefined)),\n ),\n ),\n ).pipe(map((rows) => rows.filter(Boolean)))\n : of([]);\n\n return variantsById$.pipe(\n switchMap((fetchedVariants: any[]) => {\n this.allVariants.push(...fetchedVariants);\n const knownProducts = new Set(this.allProducts.map((p) => p.id));\n const productIds = Array.from(\n new Set([...(refs.productIds ?? []), ...fetchedVariants.map((v) => v.productId)]),\n ).filter((id) => !knownProducts.has(id));\n if (!productIds.length) return of(undefined);\n return forkJoin(\n productIds.map((id) =>\n forkJoin({\n product: this.productSource.getOne(id).pipe(\n map((r: any) => r?.data),\n catchError(() => of(undefined)),\n ),\n variants: this.variantSource\n .getMany({ productId: id, page: 1, perPage: 50 } as any)\n .pipe(\n map((r: any) => r?.data ?? []),\n catchError(() => of([])),\n ),\n media: this.mediaSource\n .getMany({ productId: id, page: 1, perPage: 20 } as any)\n .pipe(\n map((r: any) => r?.data ?? []),\n catchError(() => of([])),\n ),\n }),\n ),\n ).pipe(\n map((rows) => {\n for (const row of rows) {\n if (!row.product) continue;\n this.allProducts.push(row.product);\n for (const v of row.variants) {\n if (!this.allVariants.some((x) => x.id === v.id)) this.allVariants.push(v);\n }\n this.allMedia.push(...row.media);\n }\n }),\n );\n }),\n map(() => undefined),\n );\n }\n\n private renderRelated(product: any, relations: any[]): void {\n const outgoing = relations\n .filter((r) => r.fromProductId === product.id)\n .map((relation) => ({\n relation,\n relatedProduct: this.allProducts.find((p) => p.id === relation.toProductId),\n relatedVariant: this.allVariants.find((v) => v.productId === relation.toProductId),\n }))\n .filter((entry) => entry.relatedProduct && entry.relatedVariant);\n\n if (!outgoing.length || !this.selectedVariant) {\n this.relatedGroups = [];\n return;\n }\n\n const checks = outgoing.map((entry) =>\n forkJoin({\n // One candidate's evaluation failing shouldn't hide every other\n // related suggestion — falls back to \"not blocked\" rather than\n // erroring the whole batch.\n compat: this.apiService\n .post('apps/commerce/compatibility/evaluate', {\n selection: [\n { variantId: this.selectedVariant.id, quantity: 1 },\n { variantId: entry.relatedVariant.id, quantity: 1 },\n ],\n })\n .pipe(catchError(() => of(undefined))),\n // A related product may have no seeded price yet (P1's own\n // known state) — resolves to `undefined` rather than failing\n // the whole `forkJoin` and dropping every related suggestion.\n price: this.apiService\n .get(`apps/commerce/product-variant/${entry.relatedVariant.id}/price`)\n .pipe(catchError(() => of(undefined))),\n }),\n );\n\n forkJoin(checks)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((results: any[]) => {\n const groups = new Map<string, ProductCardVm[]>();\n\n outgoing.forEach((entry, index) => {\n const { compat, price } = results[index] ?? {};\n if (compat?.data?.verdict === 'block') return;\n\n const relatedMedia = this.allMedia\n .filter((m) => m.productId === entry.relatedProduct.id)\n .sort((a, b) => a.position - b.position)[0];\n\n const card: ProductCardVm = {\n productId: entry.relatedProduct.id,\n variantId: entry.relatedVariant?.id,\n slug: entry.relatedProduct.slug,\n href: ['/p', entry.relatedProduct.slug ?? entry.relatedProduct.id],\n imageUrl: blobUrl(relatedMedia?.blobId),\n name: entry.relatedProduct.name,\n price: price?.data?.amount ?? 0,\n currency: price?.data?.currency ?? 'NGN',\n inStock: true,\n badges: [],\n };\n\n if (!groups.has(entry.relation.type)) groups.set(entry.relation.type, []);\n groups.get(entry.relation.type)!.push(card);\n });\n\n this.relatedGroups = Array.from(groups.entries()).map(([type, items]) => ({\n type,\n label: RELATION_TYPE_LABELS[type] ?? type,\n items,\n }));\n }),\n );\n }\n\n selectVariant(variant: any): void {\n this.selectedVariant = variant;\n this.loadPrice();\n this.loadStock();\n if (this.categoryData) {\n this.loadSpecs(this.categoryData);\n }\n }\n\n get outOfStock(): boolean {\n return this.stockAvailable != null && this.stockAvailable <= 0;\n }\n\n private loadStock(): void {\n if (!this.selectedVariant) return;\n const variantId = this.selectedVariant.id;\n this.stockAvailable = undefined;\n this.bisSubmitted = false;\n // Aggregate read — raw `stock-level` rows are ops-only (guests get 401).\n this.apiService\n .get(`apps/commerce/product-variant/${variantId}/availability`)\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (res: any) => {\n if (this.selectedVariant?.id !== variantId) return;\n this.stockAvailable = Number(res?.data?.available) || 0;\n },\n // Unknown stock must not block a purchase — the cart re-checks.\n error: () => {\n this.stockAvailable = undefined;\n },\n });\n }\n\n async submitBackInStock(): Promise<void> {\n const email = this.bisEmail.trim();\n if (!email || !this.selectedVariant || this.bisSubmitting) return;\n this.bisSubmitting = true;\n try {\n await firstValueFrom(\n this.stockNotificationSource.create({\n variantId: this.selectedVariant.id,\n email,\n channel: 'email',\n } as any),\n );\n this.bisSubmitted = true;\n this.bisEmail = '';\n notify('We’ll email you when it’s back.', undefined, 'success');\n } catch {\n notify('Could not save your request. Try again.', undefined, 'error');\n } finally {\n this.bisSubmitting = false;\n }\n }\n\n private loadPrice(): void {\n if (!this.selectedVariant) return;\n this.priceLoading = true;\n this.apiService\n .get(`apps/commerce/product-variant/${this.selectedVariant.id}/price`, {\n quantity: this.quantity,\n })\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (response: any) => {\n this.price = response?.data;\n this.priceLoading = false;\n },\n error: () => {\n this.price = undefined;\n this.priceLoading = false;\n },\n });\n }\n\n onQuantityChange(quantity: number): void {\n this.quantity = Math.max(1, quantity);\n this.loadPrice();\n }\n\n // PROMO-05 — resolve the bundle price + the \"what's included\" list for\n // a kit product. `Kit` is keyed by productId but the price endpoint\n // takes the Kit row id, so this fetches the (small) kit table and\n // matches. The breakdown carries per-component totals; names/images\n // come from the products + media already loaded for the page.\n private loadKit(product: any): void {\n this.kit = undefined;\n this.kitLoading = true;\n this.kitSource\n .getMany({ productId: product.id, page: 1, perPage: 1 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const kit = (response?.data ?? []).find((k: any) => k.productId === product.id);\n if (!kit) {\n this.kitLoading = false;\n return;\n }\n this.apiService\n .get(`apps/commerce/kit/${kit.id}/price`)\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (priced: any) => {\n const data = priced?.data;\n if (!data) {\n this.kitLoading = false;\n return;\n }\n this.hydrate({\n variantIds: (data.breakdown ?? []).map((row: any) => row.variantId),\n })\n .pipe(takeUntil(this.$))\n .subscribe(() => {\n this.kitLoading = false;\n this.applyKit(data);\n });\n },\n error: () => {\n this.kitLoading = false;\n },\n });\n }),\n );\n }\n\n private applyKit(data: any): void {\n this.kit = {\n amount: data.amount,\n currency: data.currency,\n pricingMode: data.pricingMode,\n componentSum: data.componentSum,\n savings: data.savings,\n savingsPct: data.savingsPct,\n items: (data.breakdown ?? []).map((row: any) => {\n const variant = this.allVariants.find((v) => v.id === row.variantId);\n const cProduct = variant\n ? this.allProducts.find((p) => p.id === variant.productId)\n : undefined;\n const media = cProduct\n ? this.allMedia\n .filter((m) => m.productId === cProduct.id)\n .sort((a, b) => a.position - b.position)[0]\n : undefined;\n return {\n name: cProduct?.name ?? variant?.sku ?? 'Component',\n quantity: row.quantity,\n lineTotal: row.lineTotal,\n isRequired: row.isRequired,\n imageUrl: blobUrl(media?.blobId, 160),\n slug: cProduct?.slug,\n };\n }),\n };\n }\n\n private loadSpecs(category: any): void {\n if (!category.attributeTemplateId) {\n this.specGroups = [];\n return;\n }\n const productId = this.product.id;\n const variantId = this.selectedVariant?.id;\n forkJoin({\n definitions: this.attrDefSource.getMany({\n templateId: category.attributeTemplateId,\n page: 1,\n perPage: 200,\n } as any),\n productValues: this.attrValueSource.getMany({ productId, page: 1, perPage: 200 } as any),\n variantValues: variantId\n ? this.attrValueSource.getMany({ variantId, page: 1, perPage: 200 } as any)\n : of({ data: [] }),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using(({ definitions, productValues: pv, variantValues: vv }: any) => {\n const defs = (definitions?.data ?? [])\n .filter(\n (d: any) => d.templateId === category.attributeTemplateId && d.showInSpecTable,\n )\n .sort((a: any, b: any) => a.position - b.position);\n const productValues = (pv?.data ?? []).filter((v: any) => v.productId === productId);\n const variantValues = (vv?.data ?? []).filter((v: any) => v.variantId === variantId);\n\n const groups = new Map<string, SpecRowVm[]>();\n for (const def of defs) {\n const value =\n variantValues.find((v: any) => v.attributeDefinitionId === def.id) ??\n productValues.find((v: any) => v.attributeDefinitionId === def.id);\n if (!value) continue;\n\n const group = def.group || 'General';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push({\n key: def.key,\n label: def.label,\n value: formatSpecValue(value, def.dataType),\n unit: def.unit,\n plainLanguage: def.plainLanguage,\n });\n }\n this.specGroups = Array.from(groups.entries()).map(([label, rows]) => ({\n label,\n rows,\n }));\n }),\n );\n }\n\n setTab(tab: 'specs' | 'reviews' | 'shipping' | 'qna'): void {\n this.activeTab = tab;\n }\n\n onAddToCart(): void {\n if (!this.product || !this.selectedVariant || this.outOfStock) return;\n // A kit is priced as a bundle — the price box already shows that amount.\n const price = this.kit\n ? { amount: this.kit.amount, currency: this.kit.currency }\n : this.price;\n this.cartAdd.add({\n variantId: this.selectedVariant.id,\n productId: this.product.id,\n name: this.product.name,\n slug: this.product.slug,\n imageUrl: this.media[0]?.thumb,\n unitPrice: price?.amount,\n currency: price?.currency,\n quantity: this.quantity,\n });\n }\n\n searchCompatCandidates(): void {\n const q = this.compatQuery.trim();\n if (!q) {\n this.compatCandidates = [];\n return;\n }\n this.searchSource\n .create({ q, page: 1, perPage: 5 })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const items: SearchResultItemDto[] = response?.data?.items ?? [];\n this.compatCandidates = items.filter((item) => item.productId !== this.product?.id);\n }),\n );\n }\n\n selectCompatCandidate(candidate: SearchResultItemDto): void {\n this.compatSelected = candidate;\n this.compatCandidates = [];\n this.compatQuery = candidate.name;\n\n if (!this.selectedVariant?.id || !candidate.variantId) return;\n\n this.compatLoading = true;\n this.compatVerdict = null;\n this.apiService\n .post('apps/commerce/compatibility/evaluate', {\n selection: [\n { variantId: this.selectedVariant.id, quantity: 1 },\n { variantId: candidate.variantId, quantity: 1 },\n ],\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n this.compatVerdict = response?.data?.verdict ?? null;\n this.compatFindings = response?.data?.findings ?? [];\n this.compatLoading = false;\n }),\n );\n }\n}\n\ninterface SpecRowVm {\n key: string;\n label: string;\n value: string;\n unit?: string;\n plainLanguage?: string;\n}\n\nfunction formatSpecValue(value: any, dataType: string): string {\n switch (dataType) {\n case 'boolean':\n return value.valueBool ? 'Yes' : 'No';\n case 'range':\n return `${value.valueNumber}–${value.valueNumberHigh}`;\n case 'number':\n return String(value.valueNumber);\n default:\n return value.valueText ?? '';\n }\n}\n","@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price — vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price…</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount * quantity\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n @if (quantity > 1) {\n <div class=\"x-pdp-bundle-note\">{{ quantity }} × unit price</div>\n }\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}×</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We’ll email you the moment it’s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it’s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel…\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ descView.text }}</p>\n @for (src of descView.images; track src) {\n <img class=\"x-pdp-desc-img\" [src]=\"src\" [alt]=\"product.name\" loading=\"lazy\" />\n }\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { TilmartElementsModule } from '@isaiahiroko/tilmart-ngx-ui';\nimport { ProductComponent } from './product.component';\nimport { QnaPanelComponent } from './qna-panel.component';\nimport { ReviewsPanelComponent } from './reviews-panel.component';\n\n@NgModule({\n declarations: [ProductComponent, ReviewsPanelComponent, QnaPanelComponent],\n imports: [\n SharedModule,\n ElementsModule,\n TilmartElementsModule,\n RouterModule.forChild([{ path: '', component: ProductComponent }]),\n ],\n})\nexport class ProductModule {}\n"],"names":["i2","i3","i4","i5.ReviewsPanelComponent","i6.QnaPanelComponent","i7","i1"],"mappings":"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"}
@@ -127,7 +127,7 @@ class PagesModule {
127
127
  },
128
128
  {
129
129
  path: 'p/:slug',
130
- loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs').then((m) => m.ProductModule),
130
+ loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs').then((m) => m.ProductModule),
131
131
  },
132
132
  {
133
133
  path: 'search',
@@ -169,7 +169,7 @@ class PagesModule {
169
169
  // ComplaintLog support ticket). The storefront shell's
170
170
  // "WhatsApp support" / help links point here.
171
171
  path: 'help',
172
- loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs').then((m) => m.HelpModule),
172
+ loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs').then((m) => m.HelpModule),
173
173
  },
174
174
  {
175
175
  // P6.11 — CMS-02 Learn hub (`/learn` index + `/learn/:slug`).
@@ -289,7 +289,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
289
289
  },
290
290
  {
291
291
  path: 'p/:slug',
292
- loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs').then((m) => m.ProductModule),
292
+ loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs').then((m) => m.ProductModule),
293
293
  },
294
294
  {
295
295
  path: 'search',
@@ -331,7 +331,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
331
331
  // ComplaintLog support ticket). The storefront shell's
332
332
  // "WhatsApp support" / help links point here.
333
333
  path: 'help',
334
- loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs').then((m) => m.HelpModule),
334
+ loadChildren: () => import('./isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs').then((m) => m.HelpModule),
335
335
  },
336
336
  {
337
337
  // P6.11 — CMS-02 Learn hub (`/learn` index + `/learn/:slug`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isaiahiroko/tilmart-ngx-apps-buyer",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "peerDependencies": {
5
5
  "@angular/animations": "^21.1.3",
6
6
  "@angular/common": "^21.1.3",
@@ -1 +0,0 @@
1
- {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs","sources":["../../../projects/buyer/src/lib/pages/help/help.component.ts","../../../projects/buyer/src/lib/pages/help/help.component.html","../../../projects/buyer/src/lib/pages/help/help-article.component.ts","../../../projects/buyer/src/lib/pages/help/help-article.component.html","../../../projects/buyer/src/lib/pages/help/help.module.ts"],"sourcesContent":["import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, ControlService, notify, using } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of, takeUntil } from 'rxjs';\n\n// Articles that make up the self-serve help centre (SUP-01). Ops files a\n// help doc by setting one of these as the Article's `category`.\nexport const HELP_CATEGORIES = [\n 'getting-started',\n 'orders-delivery',\n 'payments-refunds',\n 'returns-warranty',\n 'account',\n 'faq',\n];\n\nconst HELP_CATEGORY_LABELS: Record<string, string> = {\n 'getting-started': 'Getting started',\n 'orders-delivery': 'Orders & delivery',\n 'payments-refunds': 'Payments & refunds',\n 'returns-warranty': 'Returns & warranty',\n account: 'Your account',\n faq: 'FAQ',\n};\n\nconst TOPICS = [\n { value: 'order', label: 'An order or delivery' },\n { value: 'payment', label: 'A payment or refund' },\n { value: 'return', label: 'A return or warranty claim' },\n { value: 'product', label: 'A product question' },\n { value: 'account', label: 'My account' },\n { value: 'other', label: 'Something else' },\n];\n\n// P5.14 / P6.14, SUP-01/03 — the storefront help centre. Self-serve help\n// articles (CMS `Article`s, `/help/:slug` renders one) + a contact form\n// that opens a support ticket (`ComplaintLog`, type `support_request`).\n@Component({\n standalone: false,\n selector: 'x-help',\n templateUrl: './help.component.html',\n styleUrl: './help.component.scss',\n})\nexport class HelpComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly controlService = inject(ControlService);\n\n readonly topics = TOPICS;\n\n topic = '';\n subject = '';\n message = '';\n email = '';\n phone = '';\n orderNumber = '';\n\n submitting = false;\n error = '';\n done = false;\n\n // SUP-01 — the help-article index, grouped by category.\n groups: { key: string; label: string; articles: { slug: string; title: string; summary?: string }[] }[] = [];\n\n override init = () => {\n this.orderNumber = this.route.snapshot.queryParamMap.get('order') ?? '';\n if (this.orderNumber) this.topic = 'order';\n this.loadArticles();\n };\n\n private loadArticles(): void {\n this.apiService\n .on('apps/commerce/article')\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const now = Date.now();\n const help = ((res?.data ?? []) as any[]).filter(\n (a) =>\n HELP_CATEGORIES.includes(a.category) &&\n a.status === 'published' &&\n (!a.publishAt || Date.parse(a.publishAt) <= now),\n );\n const byCat = new Map<string, any[]>();\n for (const a of help) {\n const list = byCat.get(a.category) ?? [];\n list.push(a);\n byCat.set(a.category, list);\n }\n this.groups = HELP_CATEGORIES.filter((key) => byCat.has(key)).map((key) => ({\n key,\n label: HELP_CATEGORY_LABELS[key] ?? key,\n articles: (byCat.get(key) ?? [])\n .sort((x, y) => String(x.title).localeCompare(String(y.title)))\n .map((a) => ({ slug: a.slug, title: a.title, summary: a.summary })),\n }));\n }),\n );\n }\n\n get canSubmit(): boolean {\n return (\n !!this.topic &&\n !!this.message.trim() &&\n (this.controlService.isLoggedIn() || !!this.email.trim() || !!this.phone.trim())\n );\n }\n\n async submit(): Promise<void> {\n if (this.submitting || !this.canSubmit) return;\n this.submitting = true;\n this.error = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/complaint-log')\n .create({\n type: 'support_request',\n channel: 'web',\n subject: this.subject.trim() || this.topicLabel(),\n note: this.message.trim(),\n priority: this.topic === 'payment' ? 'high' : 'normal',\n contactEmail: this.email.trim() || undefined,\n contactPhone: this.phone.trim() || undefined,\n } as any)\n .pipe(catchError((err) => of({ status: 'error', message: String(err) }))),\n );\n if (res?.status === 'error') {\n this.error = 'Could not send your message. Please try again.';\n return;\n }\n this.done = true;\n notify('Message sent — we’ll be in touch', undefined, 'success');\n } catch {\n this.error = 'Could not send your message. Please try again.';\n } finally {\n this.submitting = false;\n }\n }\n\n private topicLabel(): string {\n return TOPICS.find((t) => t.value === this.topic)?.label ?? 'Support request';\n }\n}\n","<div class=\"x-help\">\n <h1>Help &amp; support</h1>\n\n <div class=\"x-help-quick\">\n <a routerLink=\"/track\">Track an order</a>\n <a routerLink=\"/account/orders\">My orders</a>\n <a routerLink=\"/account/returns\">Returns &amp; warranty</a>\n <a href=\"https://wa.me/message\" target=\"_blank\" rel=\"noopener\">WhatsApp us</a>\n </div>\n\n @if (groups.length) {\n <div class=\"x-help-articles\">\n @for (group of groups; track group.key) {\n <div class=\"x-help-topic\">\n <h2 class=\"x-help-topic-title\">{{ group.label }}</h2>\n <ul class=\"x-help-topic-list\">\n @for (a of group.articles; track a.slug) {\n <li>\n <a [routerLink]=\"['/help', a.slug]\">{{ a.title }}</a>\n @if (a.summary) { <span class=\"x-help-topic-summary\"> — {{ a.summary }}</span> }\n </li>\n }\n </ul>\n </div>\n }\n </div>\n }\n\n @if (done) {\n <div class=\"x-help-done\">\n <h2>Thanks — your message is in</h2>\n <p>Our team will reply by email or phone. For anything urgent about a\n delivery, WhatsApp us and reply <strong>AGENT</strong>.</p>\n </div>\n } @else {\n <div class=\"x-help-card\">\n <h2>Send us a message</h2>\n\n <label class=\"x-help-field\">\n <span>What's it about?</span>\n <select aria-label=\"What is it about?\" [(ngModel)]=\"topic\">\n <option value=\"\">Choose a topic</option>\n @for (t of topics; track t.value) {\n <option [value]=\"t.value\">{{ t.label }}</option>\n }\n </select>\n </label>\n\n @if (topic === 'order' || topic === 'return') {\n <label class=\"x-help-field\">\n <span>Order number (if you have it)</span>\n <input [(ngModel)]=\"orderNumber\" placeholder=\"TIL-260906-ABCDE\" />\n </label>\n }\n\n <label class=\"x-help-field\">\n <span>Subject (optional)</span>\n <input [(ngModel)]=\"subject\" />\n </label>\n\n <label class=\"x-help-field\">\n <span>Your message</span>\n <textarea rows=\"4\" [(ngModel)]=\"message\"></textarea>\n </label>\n\n <div class=\"x-help-contact\">\n <label class=\"x-help-field\">\n <span>Email</span>\n <input type=\"email\" [(ngModel)]=\"email\" />\n </label>\n <label class=\"x-help-field\">\n <span>Phone</span>\n <input type=\"tel\" [(ngModel)]=\"phone\" />\n </label>\n </div>\n\n @if (error) {\n <div class=\"x-help-err\">{{ error }}</div>\n }\n <button type=\"button\" class=\"x-help-btn\" [disabled]=\"!canSubmit || submitting\" (click)=\"submit()\">\n {{ submitting ? 'Sending…' : 'Send message' }}\n </button>\n </div>\n }\n</div>\n","import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, using } from '@thescaffold/ngx-core';\nimport { takeUntil } from 'rxjs';\nimport { SeoService } from '../../services/seo.service';\nimport { HELP_CATEGORIES } from './help.component';\n\n// P6.14, SUP-01 — `/help/:slug`. The docs renderer for one published\n// help `Article` (rich body via sanitised `[innerHTML]`), with the\n// other articles in the same category as \"related\".\n@Component({\n standalone: false,\n selector: 'x-help-article',\n templateUrl: './help-article.component.html',\n})\nexport class HelpArticleComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly seo = inject(SeoService);\n private readonly source = this.apiService.on('apps/commerce/article');\n\n loading = true;\n notFound = false;\n article?: { title: string; body?: string; category?: string; readMinutes?: number };\n related: { slug: string; title: string }[] = [];\n\n override init = () => {\n this.route.paramMap.pipe(takeUntil(this.$)).subscribe((params) => {\n const slug = params.get('slug');\n if (slug) this.load(slug);\n });\n };\n\n private load(slug: string): void {\n this.loading = true;\n this.notFound = false;\n this.article = undefined;\n this.source\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const now = Date.now();\n const published = ((res?.data ?? []) as any[]).filter(\n (a) =>\n HELP_CATEGORIES.includes(a.category) &&\n a.status === 'published' &&\n (!a.publishAt || Date.parse(a.publishAt) <= now),\n );\n const raw = published.find((a) => a.slug === slug);\n if (!raw) {\n this.notFound = true;\n this.loading = false;\n return;\n }\n this.article = {\n title: raw.title,\n body: raw.body,\n category: raw.category,\n readMinutes: raw.readMinutes,\n };\n this.related = published\n .filter((a) => a.category === raw.category && a.slug !== raw.slug)\n .slice(0, 5)\n .map((a) => ({ slug: a.slug, title: a.title }));\n void this.seo.apply({ entityType: 'article', entityId: raw.id });\n this.loading = false;\n }),\n );\n }\n}\n","@if (loading) {\n <div class=\"x-ha-loading\">Loading…</div>\n} @else if (notFound) {\n <div class=\"x-ha-missing\">\n <p>We couldn't find that help article.</p>\n <a routerLink=\"/help\">Back to Help</a>\n </div>\n} @else if (article) {\n <article class=\"x-ha\">\n <a class=\"x-ha-back\" routerLink=\"/help\">← Help</a>\n <h1 class=\"x-ha-title\">{{ article.title }}</h1>\n @if (article.readMinutes) {\n <div class=\"x-ha-meta\">{{ article.readMinutes }} min read</div>\n }\n <div class=\"x-ha-body\" [innerHTML]=\"article.body\"></div>\n </article>\n\n @if (related.length) {\n <section class=\"x-ha-related\">\n <h2>Related</h2>\n <ul>\n @for (r of related; track r.slug) {\n <li><a [routerLink]=\"['/help', r.slug]\">{{ r.title }}</a></li>\n }\n </ul>\n </section>\n }\n\n <div class=\"x-ha-still\">\n Still stuck? <a routerLink=\"/help\">Send us a message</a>.\n </div>\n}\n\n<style>\n .x-ha { max-width: 720px; margin: 0 auto; }\n .x-ha-loading, .x-ha-missing { padding: 32px 16px; color: var(--color-text-muted); }\n .x-ha-missing { text-align: center; }\n .x-ha-back { font-size: 12.5px; font-weight: 600; color: var(--color-text-muted); text-decoration: none; }\n .x-ha-title { font-size: 28px; font-weight: 800; margin: 8px 0 6px; color: var(--color-text); }\n .x-ha-meta { font-size: 12.5px; color: var(--color-text-muted); margin-bottom: 20px; }\n .x-ha-body { font-size: 15.5px; line-height: 1.7; color: var(--color-text); }\n .x-ha-body :is(h2, h3) { margin-top: 1.6em; }\n .x-ha-body a { color: var(--color-brand); }\n .x-ha-related { max-width: 720px; margin: 32px auto 0; border-top: 1px solid var(--color-border); padding-top: 20px; }\n .x-ha-related h2 { font-size: 15px; font-weight: 700; margin: 0 0 10px; }\n .x-ha-related ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }\n .x-ha-related a { color: var(--color-brand); text-decoration: none; font-weight: 600; font-size: 14px; }\n .x-ha-still { max-width: 720px; margin: 24px auto 0; font-size: 13.5px; color: var(--color-text-muted); }\n .x-ha-still a { color: var(--color-brand); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { HelpArticleComponent } from './help-article.component';\nimport { HelpComponent } from './help.component';\n\n@NgModule({\n declarations: [HelpComponent, HelpArticleComponent],\n imports: [\n SharedModule,\n RouterModule.forChild([\n { path: '', component: HelpComponent },\n { path: ':slug', component: HelpArticleComponent },\n ]),\n ],\n})\nexport class HelpModule {}\n"],"names":["i2","i1"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs","sources":["../../../projects/buyer/src/lib/pages/product/reviews-panel.component.ts","../../../projects/buyer/src/lib/pages/product/reviews-panel.component.html","../../../projects/buyer/src/lib/pages/product/qna-panel.component.ts","../../../projects/buyer/src/lib/pages/product/qna-panel.component.html","../../../projects/buyer/src/lib/pages/product/product.component.ts","../../../projects/buyer/src/lib/pages/product/product.component.html","../../../projects/buyer/src/lib/pages/product/product.module.ts"],"sourcesContent":["import { Component, Input, OnInit, inject } from '@angular/core';\nimport { ApiService, ControlService, notify } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of } from 'rxjs';\n\ninterface ReviewVm {\n id: string;\n rating: number;\n title?: string;\n body?: string;\n isVerifiedPurchase: boolean;\n helpfulCount: number;\n replyBody?: string;\n createdAt?: string;\n}\n\ninterface SummaryVm {\n count: number;\n average: number;\n distribution: Record<string, number>;\n subRatingAverages: Record<string, number>;\n verifiedCount: number;\n}\n\n// P5.11, UGC-01 — the PDP reviews tab. Rating summary + published\n// reviews + a submit form (the verified-purchase gate + auto-publish is\n// server-side in ReviewsWorkflow).\n@Component({\n standalone: false,\n selector: 'x-pdp-reviews',\n templateUrl: './reviews-panel.component.html',\n styleUrl: './reviews-panel.component.scss',\n})\nexport class ReviewsPanelComponent implements OnInit {\n private readonly apiService = inject(ApiService);\n private readonly controlService = inject(ControlService);\n\n @Input() productId = '';\n\n loading = true;\n summary: SummaryVm | null = null;\n reviews: ReviewVm[] = [];\n customerId = '';\n\n formOpen = false;\n submitting = false;\n formError = '';\n form = { rating: 0, title: '', body: '' };\n readonly stars = [1, 2, 3, 4, 5];\n\n get isLoggedIn(): boolean {\n return this.controlService.isLoggedIn();\n }\n\n get subRatingKeys(): string[] {\n return Object.keys(this.summary?.subRatingAverages ?? {});\n }\n\n async ngOnInit(): Promise<void> {\n if (!this.productId) {\n this.loading = false;\n return;\n }\n await this.resolveCustomer();\n await this.load();\n }\n\n private async resolveCustomer(): Promise<void> {\n const userId = this.controlService.getContext()?.userId;\n if (!userId) return;\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/customer')\n .getMany({ userId, perPage: 1 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n this.customerId = (res?.data ?? [])[0]?.id ?? '';\n }\n\n private async load(): Promise<void> {\n const [summary, reviews] = await Promise.all([\n firstValueFrom(\n this.apiService\n .get(`apps/commerce/review/product/${this.productId}/summary`)\n .pipe(catchError(() => of(undefined))),\n ),\n firstValueFrom(\n this.apiService\n .on('apps/commerce/review')\n .getMany({\n productId: this.productId,\n status: 'published',\n perPage: 50,\n } as any)\n .pipe(catchError(() => of({ data: [] }))),\n ),\n ]);\n this.summary = (summary as any)?.data ?? null;\n this.reviews = ((reviews as any)?.data ?? []).map((r: any) => ({\n id: r.id,\n rating: Number(r.rating ?? 0),\n title: r.title,\n body: r.body,\n isVerifiedPurchase: !!r.isVerifiedPurchase,\n helpfulCount: Number(r.helpfulCount ?? 0),\n replyBody: r.replyBody,\n createdAt: r.createdAt,\n }));\n this.loading = false;\n }\n\n async submit(): Promise<void> {\n if (this.submitting) return;\n if (!this.form.rating) {\n this.formError = 'Pick a star rating.';\n return;\n }\n this.submitting = true;\n this.formError = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/review/submit', {\n targetType: 'product',\n productId: this.productId,\n customerId: this.customerId || undefined,\n rating: this.form.rating,\n title: this.form.title || undefined,\n body: this.form.body || undefined,\n }),\n );\n if (res?.status === 'error') {\n this.formError =\n res?.message === 'already-reviewed'\n ? \"You've already reviewed this product.\"\n : res?.message ?? 'Could not submit your review.';\n return;\n }\n this.formOpen = false;\n this.form = { rating: 0, title: '', body: '' };\n const published = res?.data?.status === 'published';\n notify(\n published ? 'Thanks — your review is live' : 'Thanks — your review is awaiting moderation',\n undefined,\n 'success',\n );\n if (published) await this.load();\n } catch (err: any) {\n this.formError = err?.error?.message ?? 'Could not submit your review.';\n } finally {\n this.submitting = false;\n }\n }\n\n async markHelpful(review: ReviewVm): Promise<void> {\n if (!this.customerId) {\n notify('Sign in to vote', undefined, 'error');\n return;\n }\n try {\n const res: any = await firstValueFrom(\n this.apiService.post(`apps/commerce/review/${review.id}/helpful`, {\n customerId: this.customerId,\n helpful: true,\n }),\n );\n if (res?.data?.helpfulCount != null) review.helpfulCount = res.data.helpfulCount;\n } catch {\n // best-effort\n }\n }\n\n barWidth(star: number): string {\n const n = this.summary?.distribution?.[String(star)] ?? 0;\n const total = this.summary?.count ?? 0;\n return total ? `${Math.round((n / total) * 100)}%` : '0%';\n }\n}\n","@if (loading) {\n <div class=\"x-pdp-empty\">Loading reviews…</div>\n} @else {\n @if (summary && summary.count > 0) {\n <div class=\"x-rv-summary\">\n <div class=\"x-rv-score\">\n <div class=\"x-rv-avg\">{{ summary.average }}</div>\n <div class=\"x-rv-stars\" aria-hidden=\"true\">\n @for (s of stars; track s) {\n <span [class.on]=\"s <= summary.average\">★</span>\n }\n </div>\n <div class=\"x-rv-count\">\n {{ summary.count }} review{{ summary.count === 1 ? '' : 's' }}\n @if (summary.verifiedCount) {\n · {{ summary.verifiedCount }} verified\n }\n </div>\n </div>\n <div class=\"x-rv-bars\">\n @for (s of [5, 4, 3, 2, 1]; track s) {\n <div class=\"x-rv-bar-row\">\n <span>{{ s }}★</span>\n <span class=\"x-rv-bar\"><span [style.width]=\"barWidth(s)\"></span></span>\n <span>{{ summary.distribution[s + ''] || 0 }}</span>\n </div>\n }\n </div>\n @if (subRatingKeys.length) {\n <div class=\"x-rv-subs\">\n @for (k of subRatingKeys; track k) {\n <div class=\"x-rv-sub\">\n <span>{{ k }}</span>\n <strong>{{ summary.subRatingAverages[k] }}</strong>\n </div>\n }\n </div>\n }\n </div>\n } @else {\n <div class=\"x-pdp-empty\">No reviews yet — be the first.</div>\n }\n\n @if (formOpen) {\n <div class=\"x-rv-form\">\n <div class=\"x-rv-star-pick\">\n @for (s of stars; track s) {\n <button type=\"button\" [class.on]=\"s <= form.rating\" (click)=\"form.rating = s\">★</button>\n }\n </div>\n <input class=\"x-rv-input\" [(ngModel)]=\"form.title\" placeholder=\"Sum it up (optional)\" />\n <textarea class=\"x-rv-input\" rows=\"3\" [(ngModel)]=\"form.body\" placeholder=\"What did you think?\"></textarea>\n @if (formError) {\n <div class=\"x-rv-err\">{{ formError }}</div>\n }\n <button class=\"x-rv-btn\" [disabled]=\"submitting\" (click)=\"submit()\">\n {{ submitting ? 'Submitting…' : 'Post review' }}\n </button>\n <button class=\"x-rv-btn-ghost\" (click)=\"formOpen = false\">Cancel</button>\n </div>\n } @else {\n <button class=\"x-rv-btn\" (click)=\"formOpen = true\">Write a review</button>\n }\n\n @for (r of reviews; track r.id) {\n <div class=\"x-rv-item\">\n <div class=\"x-rv-item-head\">\n <span class=\"x-rv-stars\" aria-hidden=\"true\">\n @for (s of stars; track s) {\n <span [class.on]=\"s <= r.rating\">★</span>\n }\n </span>\n @if (r.isVerifiedPurchase) {\n <span class=\"x-rv-verified\">Verified purchase</span>\n }\n </div>\n @if (r.title) {\n <strong>{{ r.title }}</strong>\n }\n @if (r.body) {\n <p>{{ r.body }}</p>\n }\n @if (r.replyBody) {\n <div class=\"x-rv-reply\"><strong>Response from Tilmart:</strong> {{ r.replyBody }}</div>\n }\n <button class=\"x-rv-helpful\" (click)=\"markHelpful(r)\">\n Helpful @if (r.helpfulCount) { ({{ r.helpfulCount }}) }\n </button>\n </div>\n }\n}\n","import { Component, Input, OnInit, inject } from '@angular/core';\nimport { ApiService, ControlService, notify } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, of } from 'rxjs';\n\ninterface AnswerVm {\n id: string;\n body: string;\n isOfficial: boolean;\n createdAt?: string;\n}\n\ninterface QuestionVm {\n id: string;\n body: string;\n createdAt?: string;\n answers: AnswerVm[];\n answering: boolean;\n draft: string;\n}\n\n// P5.11, UGC-04 — the PDP Q&A tab. Published questions + answers, an\n// \"ask a question\" form and an inline answer box.\n@Component({\n standalone: false,\n selector: 'x-pdp-qna',\n templateUrl: './qna-panel.component.html',\n styleUrl: './reviews-panel.component.scss',\n})\nexport class QnaPanelComponent implements OnInit {\n private readonly apiService = inject(ApiService);\n private readonly controlService = inject(ControlService);\n\n @Input() productId = '';\n\n loading = true;\n questions: QuestionVm[] = [];\n customerId = '';\n\n askOpen = false;\n asking = false;\n askError = '';\n askDraft = '';\n\n async ngOnInit(): Promise<void> {\n if (!this.productId) {\n this.loading = false;\n return;\n }\n const userId = this.controlService.getContext()?.userId;\n if (userId) {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/customer')\n .getMany({ userId, perPage: 1 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n this.customerId = (res?.data ?? [])[0]?.id ?? '';\n }\n await this.load();\n }\n\n private async load(): Promise<void> {\n const res: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/question')\n .getMany({\n productId: this.productId,\n status: 'published',\n perPage: 50,\n } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n const rows: any[] = res?.data ?? [];\n this.questions = await Promise.all(\n rows.map(async (q) => {\n const ans: any = await firstValueFrom(\n this.apiService\n .on('apps/commerce/answer')\n .getMany({ questionId: q.id, status: 'published', perPage: 20 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n );\n return {\n id: q.id,\n body: q.body,\n createdAt: q.createdAt,\n answers: (ans?.data ?? []).map((a: any) => ({\n id: a.id,\n body: a.body,\n isOfficial: !!a.isOfficial,\n createdAt: a.createdAt,\n })),\n answering: false,\n draft: '',\n } as QuestionVm;\n }),\n );\n this.loading = false;\n }\n\n async ask(): Promise<void> {\n if (this.asking || !this.askDraft.trim()) return;\n this.asking = true;\n this.askError = '';\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/question/ask', {\n productId: this.productId,\n customerId: this.customerId || undefined,\n body: this.askDraft.trim(),\n }),\n );\n if (res?.status === 'error') {\n this.askError = res?.message ?? 'Could not post your question.';\n return;\n }\n this.askOpen = false;\n this.askDraft = '';\n notify('Thanks — your question is awaiting moderation', undefined, 'success');\n } catch (err: any) {\n this.askError = err?.error?.message ?? 'Could not post your question.';\n } finally {\n this.asking = false;\n }\n }\n\n async answer(q: QuestionVm): Promise<void> {\n if (!q.draft.trim()) return;\n try {\n const res: any = await firstValueFrom(\n this.apiService.post('apps/commerce/answer/post', {\n questionId: q.id,\n customerId: this.customerId || undefined,\n body: q.draft.trim(),\n }),\n );\n if (res?.status === 'error') {\n notify(res?.message ?? 'Could not post your answer.', undefined, 'error');\n return;\n }\n q.answering = false;\n q.draft = '';\n notify('Thanks — your answer is awaiting moderation', undefined, 'success');\n } catch {\n notify('Could not post your answer.', undefined, 'error');\n }\n }\n}\n","@if (loading) {\n <div class=\"x-pdp-empty\">Loading questions…</div>\n} @else {\n @if (askOpen) {\n <div class=\"x-rv-form\">\n <textarea\n class=\"x-rv-input\"\n rows=\"2\"\n [(ngModel)]=\"askDraft\"\n placeholder=\"Ask about fit, specs, compatibility…\"\n ></textarea>\n @if (askError) {\n <div class=\"x-rv-err\">{{ askError }}</div>\n }\n <button class=\"x-rv-btn\" [disabled]=\"asking\" (click)=\"ask()\">\n {{ asking ? 'Posting…' : 'Post question' }}\n </button>\n <button class=\"x-rv-btn-ghost\" (click)=\"askOpen = false\">Cancel</button>\n </div>\n } @else {\n <button class=\"x-rv-btn\" (click)=\"askOpen = true\">Ask a question</button>\n }\n\n @for (q of questions; track q.id) {\n <div class=\"x-rv-item\">\n <strong>Q: {{ q.body }}</strong>\n @for (a of q.answers; track a.id) {\n <p>\n <strong>A:</strong> {{ a.body }}\n @if (a.isOfficial) {\n <span class=\"x-rv-verified\">Tilmart</span>\n }\n </p>\n }\n @if (q.answering) {\n <textarea class=\"x-rv-input\" rows=\"2\" [(ngModel)]=\"q.draft\" placeholder=\"Your answer\"></textarea>\n <button class=\"x-rv-btn\" (click)=\"answer(q)\">Post answer</button>\n <button class=\"x-rv-btn-ghost\" (click)=\"q.answering = false\">Cancel</button>\n } @else {\n <button class=\"x-rv-helpful\" (click)=\"q.answering = true\">Answer this</button>\n }\n </div>\n } @empty {\n <div class=\"x-pdp-empty\">No questions yet.</div>\n }\n}\n","import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { CompatVerdictFinding } from '@isaiahiroko/tilmart-ngx-ui';\nimport { Observable, catchError, firstValueFrom, forkJoin, map, of, switchMap, takeUntil } from 'rxjs';\nimport { blobUrl } from '../../data/media';\nimport { ProductCardVm, SearchResultItemDto } from '../../data/search-result-card';\nimport { CartAddService } from '../../services/cart-add.service';\nimport { CompareTrayService } from '../../services/compare-tray.service';\nimport { SeoService } from '../../services/seo.service';\n\nconst RELATION_TYPE_LABELS: Record<string, string> = {\n bought_together: 'Frequently bought together',\n required_accessory: 'You also need',\n recommended_accessory: 'Recommended accessories',\n compatible_with: 'Compatible with',\n upgrade: 'Upgrade path',\n replaces: 'Replaces',\n};\n\n// P2.8, PDP-01/02/09/10 — gallery, grouped spec table with plain-language\n// disclosure, tabs (specs/reviews/shipping/Q&A — reviews and Q&A are\n// documented no-ops, `Review`/`Question` don't exist until P5.10/later),\n// price box, buy row. PDP-03's \"will this work for me\" runtime/generation\n// estimates need `SizingWorkflow` (P3, unbuilt) and are NOT attempted\n// here — only the part of PDP-04/PDP-06 that P2.9 actually built for:\n// \"works with what I already have\" against an arbitrary catalogue pick\n// (no `MySystem`/saved-systems entity exists yet, P5).\n//\n// Every list endpoint here is fetched as one broad, unfiltered page and\n// joined/filtered client-side (same convention as every other page this\n// phase) — `perPage: 1000` on the genuinely workspace-wide ones\n// (attribute values, variants, media, documents) rather than the 200 used\n// elsewhere, since a real catalogue's `ProductAttributeValue` table alone\n// is easily 15 rows x 400 SKUs. **This is a real, documented R1-scale\n// ceiling** (TRD §10.4's own \"~400 SKUs\" framing), not an oversight —\n// spec/gallery data would start silently truncating past a few thousand\n// total rows workspace-wide. A real `?productId=` filtered endpoint is\n// the actual fix, whenever this stops being good enough.\n@Component({\n standalone: false,\n selector: 'x-product',\n templateUrl: './product.component.html',\n styleUrl: './product.component.scss',\n})\nexport class ProductComponent extends BaseDirective {\n private readonly route = inject(ActivatedRoute);\n private readonly seo = inject(SeoService);\n readonly cartAdd = inject(CartAddService);\n readonly compareTray = inject(CompareTrayService);\n private readonly productSource = this.apiService.on('apps/commerce/product');\n private readonly variantSource = this.apiService.on('apps/commerce/product-variant');\n private readonly mediaSource = this.apiService.on('apps/commerce/product-media');\n private readonly documentSource = this.apiService.on('apps/commerce/product-document');\n private readonly attrValueSource = this.apiService.on('apps/commerce/product-attribute-value');\n private readonly attrDefSource = this.apiService.on('apps/commerce/attribute-definition');\n private readonly categorySource = this.apiService.on('apps/commerce/category');\n private readonly brandSource = this.apiService.on('apps/commerce/brand');\n private readonly searchSource = this.apiService.on('apps/commerce/search');\n private readonly relationSource = this.apiService.on('apps/commerce/product-relation');\n private readonly kitSource = this.apiService.on('apps/commerce/kit');\n\n private allProducts: any[] = [];\n private allVariants: any[] = [];\n private allMedia: any[] = [];\n\n product?: any;\n notFound = false;\n brandName?: string;\n categoryData?: any;\n\n variants: any[] = [];\n selectedVariant?: any;\n\n media: { blobId: string; altText: string; url: string; thumb: string }[] = [];\n activeImageIndex = 0;\n\n documents: any[] = [];\n\n specGroups: { label: string; rows: SpecRowVm[] }[] = [];\n\n price?: { amount: number; currency: string };\n priceLoading = false;\n quantity = 1;\n\n // PDP-08 — back-in-stock signup for the selected variant.\n stockAvailable?: number;\n bisEmail = '';\n bisSubmitting = false;\n bisSubmitted = false;\n private readonly stockNotificationSource = this.apiService.on(\n 'apps/commerce/stock-notification',\n );\n\n // PROMO-05 — a `type = kit` product shows its bundle price against the\n // component sum, plus what's inside.\n kit?: {\n amount: number;\n currency: string;\n pricingMode: string;\n componentSum: number;\n savings: number;\n savingsPct: number;\n items: {\n name: string;\n quantity: number;\n lineTotal?: number;\n isRequired: boolean;\n imageUrl?: string;\n slug?: string;\n }[];\n };\n kitLoading = false;\n\n activeTab: 'specs' | 'reviews' | 'shipping' | 'qna' = 'specs';\n\n compatQuery = '';\n compatCandidates: SearchResultItemDto[] = [];\n compatSelected?: SearchResultItemDto;\n compatVerdict: 'pass' | 'warn' | 'block' | null = null;\n compatFindings: CompatVerdictFinding[] = [];\n compatLoading = false;\n\n relatedGroups: { type: string; label: string; items: ProductCardVm[] }[] = [];\n\n get activeImageUrl(): string | undefined {\n return this.media[this.activeImageIndex]?.url;\n }\n\n override init = () => {\n this.route.paramMap.pipe(takeUntil(this.$)).subscribe((params) => {\n const slug = params.get('slug');\n if (!slug) return;\n this.loadProduct(slug);\n });\n };\n\n // Cards link here with `#specs` — the router's anchor scrolling can't\n // help since the target only exists once the product has loaded.\n private scrollToFragment(): void {\n const fragment = this.route.snapshot.fragment;\n if (!fragment) return;\n if (fragment === 'specs') this.activeTab = 'specs';\n setTimeout(() => document.getElementById(fragment)?.scrollIntoView({ behavior: 'smooth' }), 0);\n }\n\n // Server-side filters (`?slug=`, `?productId=` …) rather than paging the\n // whole catalogue: the CRUD list caps `perPage` at 200 (so \"everything\"\n // silently truncated) and a PDP on a slow link shouldn't pull every SKU.\n private loadProduct(slug: string): void {\n this.product = undefined;\n this.notFound = false;\n this.allProducts = [];\n this.allVariants = [];\n this.allMedia = [];\n this.productSource\n .getMany({ slug, page: 1, perPage: 1 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const product = (response?.data ?? []).find((p: any) => p.slug === slug);\n if (!product) {\n this.notFound = true;\n return;\n }\n this.allProducts = [product];\n this.product = product;\n void this.seo.apply({ entityType: 'product', entityId: product.id });\n this.loadDetails(product);\n }),\n );\n }\n\n private loadDetails(product: any): void {\n forkJoin({\n variants: this.variantSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n media: this.mediaSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n documents: this.documentSource.getMany({ productId: product.id, page: 1, perPage: 200 } as any),\n relations: this.relationSource.getMany({\n fromProductId: product.id,\n page: 1,\n perPage: 200,\n } as any),\n brand: product.brandId ? this.brandSource.getOne(product.brandId) : of(null),\n category: product.primaryCategoryId\n ? this.categorySource.getOne(product.primaryCategoryId)\n : of(null),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using(({ variants, media, documents, relations, brand, category }: any) => {\n this.allVariants = variants?.data ?? [];\n this.allMedia = media?.data ?? [];\n\n this.variants = this.allVariants.filter((v: any) => v.productId === product.id);\n this.media = this.allMedia\n .filter((m: any) => m.productId === product.id)\n .sort((a: any, b: any) => a.position - b.position)\n .map((m: any) => ({ blobId: m.blobId, altText: m.altText, url: blobUrl(m.blobId, 1200)!, thumb: blobUrl(m.blobId, 160)! }));\n this.documents = (documents?.data ?? [])\n .filter((d: any) => d.productId === product.id)\n .map((d: any) => ({ ...d, url: blobUrl(d.blobId) }));\n this.brandName = brand?.data?.name;\n this.categoryData = category?.data;\n\n this.selectedVariant = this.variants[0];\n this.scrollToFragment();\n if (this.selectedVariant) {\n this.loadPrice();\n this.loadStock();\n }\n if (this.categoryData) {\n this.loadSpecs(this.categoryData);\n }\n if (product.type === 'kit') {\n this.loadKit(product);\n }\n\n this.loadRelated(product, relations?.data ?? []);\n }),\n );\n }\n\n // CAT-09/PDP-08 — \"frequently bought with this\" etc. Related-accessory\n // suggestions are run through `evaluateCompatibility` before display\n // (this entity's own doc comment says as much) and dropped if the pair\n // comes back `block` — surfacing an accessory the compatibility engine\n // itself would reject on add-to-cart is worse than not suggesting it.\n private loadRelated(product: any, relations: any[]): void {\n const relatedIds = relations\n .filter((r) => r.fromProductId === product.id)\n .map((r) => r.toProductId as string);\n if (!relatedIds.length) {\n this.relatedGroups = [];\n return;\n }\n this.hydrate({ productIds: relatedIds })\n .pipe(takeUntil(this.$))\n .subscribe(() => this.renderRelated(product, relations));\n }\n\n // Pulls just the referenced products (+ their variants and media) into\n // the page caches — a handful of by-id reads instead of the catalogue.\n private hydrate(refs: { productIds?: string[]; variantIds?: string[] }): Observable<void> {\n const knownVariants = new Set(this.allVariants.map((v) => v.id));\n const variantIds = Array.from(new Set(refs.variantIds ?? [])).filter(\n (id) => !knownVariants.has(id),\n );\n\n const variantsById$: Observable<any[]> = variantIds.length\n ? forkJoin(\n variantIds.map((id) =>\n this.variantSource.getOne(id).pipe(\n map((r: any) => r?.data),\n catchError(() => of(undefined)),\n ),\n ),\n ).pipe(map((rows) => rows.filter(Boolean)))\n : of([]);\n\n return variantsById$.pipe(\n switchMap((fetchedVariants: any[]) => {\n this.allVariants.push(...fetchedVariants);\n const knownProducts = new Set(this.allProducts.map((p) => p.id));\n const productIds = Array.from(\n new Set([...(refs.productIds ?? []), ...fetchedVariants.map((v) => v.productId)]),\n ).filter((id) => !knownProducts.has(id));\n if (!productIds.length) return of(undefined);\n return forkJoin(\n productIds.map((id) =>\n forkJoin({\n product: this.productSource.getOne(id).pipe(\n map((r: any) => r?.data),\n catchError(() => of(undefined)),\n ),\n variants: this.variantSource\n .getMany({ productId: id, page: 1, perPage: 50 } as any)\n .pipe(\n map((r: any) => r?.data ?? []),\n catchError(() => of([])),\n ),\n media: this.mediaSource\n .getMany({ productId: id, page: 1, perPage: 20 } as any)\n .pipe(\n map((r: any) => r?.data ?? []),\n catchError(() => of([])),\n ),\n }),\n ),\n ).pipe(\n map((rows) => {\n for (const row of rows) {\n if (!row.product) continue;\n this.allProducts.push(row.product);\n for (const v of row.variants) {\n if (!this.allVariants.some((x) => x.id === v.id)) this.allVariants.push(v);\n }\n this.allMedia.push(...row.media);\n }\n }),\n );\n }),\n map(() => undefined),\n );\n }\n\n private renderRelated(product: any, relations: any[]): void {\n const outgoing = relations\n .filter((r) => r.fromProductId === product.id)\n .map((relation) => ({\n relation,\n relatedProduct: this.allProducts.find((p) => p.id === relation.toProductId),\n relatedVariant: this.allVariants.find((v) => v.productId === relation.toProductId),\n }))\n .filter((entry) => entry.relatedProduct && entry.relatedVariant);\n\n if (!outgoing.length || !this.selectedVariant) {\n this.relatedGroups = [];\n return;\n }\n\n const checks = outgoing.map((entry) =>\n forkJoin({\n // One candidate's evaluation failing shouldn't hide every other\n // related suggestion — falls back to \"not blocked\" rather than\n // erroring the whole batch.\n compat: this.apiService\n .post('apps/commerce/compatibility/evaluate', {\n selection: [\n { variantId: this.selectedVariant.id, quantity: 1 },\n { variantId: entry.relatedVariant.id, quantity: 1 },\n ],\n })\n .pipe(catchError(() => of(undefined))),\n // A related product may have no seeded price yet (P1's own\n // known state) — resolves to `undefined` rather than failing\n // the whole `forkJoin` and dropping every related suggestion.\n price: this.apiService\n .get(`apps/commerce/product-variant/${entry.relatedVariant.id}/price`)\n .pipe(catchError(() => of(undefined))),\n }),\n );\n\n forkJoin(checks)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((results: any[]) => {\n const groups = new Map<string, ProductCardVm[]>();\n\n outgoing.forEach((entry, index) => {\n const { compat, price } = results[index] ?? {};\n if (compat?.data?.verdict === 'block') return;\n\n const relatedMedia = this.allMedia\n .filter((m) => m.productId === entry.relatedProduct.id)\n .sort((a, b) => a.position - b.position)[0];\n\n const card: ProductCardVm = {\n productId: entry.relatedProduct.id,\n variantId: entry.relatedVariant?.id,\n slug: entry.relatedProduct.slug,\n href: ['/p', entry.relatedProduct.slug ?? entry.relatedProduct.id],\n imageUrl: blobUrl(relatedMedia?.blobId),\n name: entry.relatedProduct.name,\n price: price?.data?.amount ?? 0,\n currency: price?.data?.currency ?? 'NGN',\n inStock: true,\n badges: [],\n };\n\n if (!groups.has(entry.relation.type)) groups.set(entry.relation.type, []);\n groups.get(entry.relation.type)!.push(card);\n });\n\n this.relatedGroups = Array.from(groups.entries()).map(([type, items]) => ({\n type,\n label: RELATION_TYPE_LABELS[type] ?? type,\n items,\n }));\n }),\n );\n }\n\n selectVariant(variant: any): void {\n this.selectedVariant = variant;\n this.loadPrice();\n this.loadStock();\n if (this.categoryData) {\n this.loadSpecs(this.categoryData);\n }\n }\n\n get outOfStock(): boolean {\n return this.stockAvailable != null && this.stockAvailable <= 0;\n }\n\n private loadStock(): void {\n if (!this.selectedVariant) return;\n const variantId = this.selectedVariant.id;\n this.stockAvailable = undefined;\n this.bisSubmitted = false;\n // Aggregate read — raw `stock-level` rows are ops-only (guests get 401).\n this.apiService\n .get(`apps/commerce/product-variant/${variantId}/availability`)\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (res: any) => {\n if (this.selectedVariant?.id !== variantId) return;\n this.stockAvailable = Number(res?.data?.available) || 0;\n },\n // Unknown stock must not block a purchase — the cart re-checks.\n error: () => {\n this.stockAvailable = undefined;\n },\n });\n }\n\n async submitBackInStock(): Promise<void> {\n const email = this.bisEmail.trim();\n if (!email || !this.selectedVariant || this.bisSubmitting) return;\n this.bisSubmitting = true;\n try {\n await firstValueFrom(\n this.stockNotificationSource.create({\n variantId: this.selectedVariant.id,\n email,\n channel: 'email',\n } as any),\n );\n this.bisSubmitted = true;\n this.bisEmail = '';\n notify('We’ll email you when it’s back.', undefined, 'success');\n } catch {\n notify('Could not save your request. Try again.', undefined, 'error');\n } finally {\n this.bisSubmitting = false;\n }\n }\n\n private loadPrice(): void {\n if (!this.selectedVariant) return;\n this.priceLoading = true;\n this.apiService\n .get(`apps/commerce/product-variant/${this.selectedVariant.id}/price`, {\n quantity: this.quantity,\n })\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (response: any) => {\n this.price = response?.data;\n this.priceLoading = false;\n },\n error: () => {\n this.price = undefined;\n this.priceLoading = false;\n },\n });\n }\n\n onQuantityChange(quantity: number): void {\n this.quantity = Math.max(1, quantity);\n this.loadPrice();\n }\n\n // PROMO-05 — resolve the bundle price + the \"what's included\" list for\n // a kit product. `Kit` is keyed by productId but the price endpoint\n // takes the Kit row id, so this fetches the (small) kit table and\n // matches. The breakdown carries per-component totals; names/images\n // come from the products + media already loaded for the page.\n private loadKit(product: any): void {\n this.kit = undefined;\n this.kitLoading = true;\n this.kitSource\n .getMany({ productId: product.id, page: 1, perPage: 1 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const kit = (response?.data ?? []).find((k: any) => k.productId === product.id);\n if (!kit) {\n this.kitLoading = false;\n return;\n }\n this.apiService\n .get(`apps/commerce/kit/${kit.id}/price`)\n .pipe(takeUntil(this.$))\n .subscribe({\n next: (priced: any) => {\n const data = priced?.data;\n if (!data) {\n this.kitLoading = false;\n return;\n }\n this.hydrate({\n variantIds: (data.breakdown ?? []).map((row: any) => row.variantId),\n })\n .pipe(takeUntil(this.$))\n .subscribe(() => {\n this.kitLoading = false;\n this.applyKit(data);\n });\n },\n error: () => {\n this.kitLoading = false;\n },\n });\n }),\n );\n }\n\n private applyKit(data: any): void {\n this.kit = {\n amount: data.amount,\n currency: data.currency,\n pricingMode: data.pricingMode,\n componentSum: data.componentSum,\n savings: data.savings,\n savingsPct: data.savingsPct,\n items: (data.breakdown ?? []).map((row: any) => {\n const variant = this.allVariants.find((v) => v.id === row.variantId);\n const cProduct = variant\n ? this.allProducts.find((p) => p.id === variant.productId)\n : undefined;\n const media = cProduct\n ? this.allMedia\n .filter((m) => m.productId === cProduct.id)\n .sort((a, b) => a.position - b.position)[0]\n : undefined;\n return {\n name: cProduct?.name ?? variant?.sku ?? 'Component',\n quantity: row.quantity,\n lineTotal: row.lineTotal,\n isRequired: row.isRequired,\n imageUrl: blobUrl(media?.blobId, 160),\n slug: cProduct?.slug,\n };\n }),\n };\n }\n\n private loadSpecs(category: any): void {\n if (!category.attributeTemplateId) {\n this.specGroups = [];\n return;\n }\n const productId = this.product.id;\n const variantId = this.selectedVariant?.id;\n forkJoin({\n definitions: this.attrDefSource.getMany({\n templateId: category.attributeTemplateId,\n page: 1,\n perPage: 200,\n } as any),\n productValues: this.attrValueSource.getMany({ productId, page: 1, perPage: 200 } as any),\n variantValues: variantId\n ? this.attrValueSource.getMany({ variantId, page: 1, perPage: 200 } as any)\n : of({ data: [] }),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using(({ definitions, productValues: pv, variantValues: vv }: any) => {\n const defs = (definitions?.data ?? [])\n .filter(\n (d: any) => d.templateId === category.attributeTemplateId && d.showInSpecTable,\n )\n .sort((a: any, b: any) => a.position - b.position);\n const productValues = (pv?.data ?? []).filter((v: any) => v.productId === productId);\n const variantValues = (vv?.data ?? []).filter((v: any) => v.variantId === variantId);\n\n const groups = new Map<string, SpecRowVm[]>();\n for (const def of defs) {\n const value =\n variantValues.find((v: any) => v.attributeDefinitionId === def.id) ??\n productValues.find((v: any) => v.attributeDefinitionId === def.id);\n if (!value) continue;\n\n const group = def.group || 'General';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push({\n key: def.key,\n label: def.label,\n value: formatSpecValue(value, def.dataType),\n unit: def.unit,\n plainLanguage: def.plainLanguage,\n });\n }\n this.specGroups = Array.from(groups.entries()).map(([label, rows]) => ({\n label,\n rows,\n }));\n }),\n );\n }\n\n setTab(tab: 'specs' | 'reviews' | 'shipping' | 'qna'): void {\n this.activeTab = tab;\n }\n\n onAddToCart(): void {\n if (!this.product || !this.selectedVariant || this.outOfStock) return;\n // A kit is priced as a bundle — the price box already shows that amount.\n const price = this.kit\n ? { amount: this.kit.amount, currency: this.kit.currency }\n : this.price;\n this.cartAdd.add({\n variantId: this.selectedVariant.id,\n productId: this.product.id,\n name: this.product.name,\n slug: this.product.slug,\n imageUrl: this.media[0]?.thumb,\n unitPrice: price?.amount,\n currency: price?.currency,\n quantity: this.quantity,\n });\n }\n\n searchCompatCandidates(): void {\n const q = this.compatQuery.trim();\n if (!q) {\n this.compatCandidates = [];\n return;\n }\n this.searchSource\n .create({ q, page: 1, perPage: 5 })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n const items: SearchResultItemDto[] = response?.data?.items ?? [];\n this.compatCandidates = items.filter((item) => item.productId !== this.product?.id);\n }),\n );\n }\n\n selectCompatCandidate(candidate: SearchResultItemDto): void {\n this.compatSelected = candidate;\n this.compatCandidates = [];\n this.compatQuery = candidate.name;\n\n if (!this.selectedVariant?.id || !candidate.variantId) return;\n\n this.compatLoading = true;\n this.compatVerdict = null;\n this.apiService\n .post('apps/commerce/compatibility/evaluate', {\n selection: [\n { variantId: this.selectedVariant.id, quantity: 1 },\n { variantId: candidate.variantId, quantity: 1 },\n ],\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((response: any) => {\n this.compatVerdict = response?.data?.verdict ?? null;\n this.compatFindings = response?.data?.findings ?? [];\n this.compatLoading = false;\n }),\n );\n }\n}\n\ninterface SpecRowVm {\n key: string;\n label: string;\n value: string;\n unit?: string;\n plainLanguage?: string;\n}\n\nfunction formatSpecValue(value: any, dataType: string): string {\n switch (dataType) {\n case 'boolean':\n return value.valueBool ? 'Yes' : 'No';\n case 'range':\n return `${value.valueNumber}–${value.valueNumberHigh}`;\n case 'number':\n return String(value.valueNumber);\n default:\n return value.valueText ?? '';\n }\n}\n","@if (product) {\n <nav class=\"x-pdp-breadcrumb\">\n <a routerLink=\"/\">Home</a>\n @if (categoryData) {\n <span> / </span>\n <a [routerLink]=\"['/c', categoryData.slug]\">{{ categoryData.name }}</a>\n }\n <span> / </span>\n <span>{{ product.name }}</span>\n </nav>\n\n <div class=\"x-pdp-layout\">\n <div class=\"x-pdp-gallery\">\n <div class=\"x-pdp-gallery-main\">\n @if (activeImageUrl) {\n <img [src]=\"activeImageUrl\" [alt]=\"media[activeImageIndex].altText\" fetchpriority=\"high\" decoding=\"async\" />\n } @else {\n <div class=\"x-pdp-gallery-placeholder\" aria-hidden=\"true\"></div>\n }\n </div>\n @if (media.length > 1) {\n <div class=\"x-pdp-gallery-thumbs\">\n @for (item of media; track item.blobId; let i = $index) {\n <button\n type=\"button\"\n class=\"x-pdp-thumb\"\n [class.x-pdp-thumb-active]=\"i === activeImageIndex\"\n (click)=\"activeImageIndex = i\"\n >\n <img [src]=\"item.thumb\" [alt]=\"item.altText\" width=\"64\" height=\"64\" loading=\"lazy\" decoding=\"async\" />\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"x-pdp-buybox\">\n @if (brandName) {\n <div class=\"x-pdp-brand\">{{ brandName }}</div>\n }\n <h1 class=\"x-pdp-title\">{{ product.name }}</h1>\n @if (product.model) {\n <div class=\"x-pdp-model\">Model: {{ product.model }}</div>\n }\n\n @if (product.shortDesc) {\n <p class=\"x-pdp-short-desc\">{{ product.shortDesc }}</p>\n }\n\n @if (variants.length > 1) {\n <div class=\"x-pdp-variants\">\n @for (variant of variants; track variant.id) {\n <button\n type=\"button\"\n class=\"x-pdp-variant-btn\"\n [class.x-pdp-variant-active]=\"selectedVariant?.id === variant.id\"\n (click)=\"selectVariant(variant)\"\n >\n {{ variant.sku }}\n </button>\n }\n </div>\n }\n\n @if (kit) {\n <div class=\"x-pdp-bundle\">\n <x-tilmart-price [amount]=\"kit.amount\" [currency]=\"kit.currency\" size=\"lg\"></x-tilmart-price>\n @if (kit.savings > 0) {\n <div class=\"x-pdp-bundle-save\">\n <span class=\"x-pdp-bundle-was\">{{ kit.currency }} {{ kit.componentSum | number: '1.0-0' }}</span>\n <span class=\"x-pdp-bundle-badge\">Save {{ kit.currency }} {{ kit.savings | number: '1.0-0' }} ({{ kit.savingsPct }}%)</span>\n </div>\n <div class=\"x-pdp-bundle-note\">Bundle price — vs buying the parts separately.</div>\n }\n </div>\n } @else if (priceLoading || kitLoading) {\n <div class=\"x-pdp-price-loading\">Loading price…</div>\n } @else if (price) {\n <x-tilmart-price [amount]=\"price.amount\" [currency]=\"price.currency\" size=\"lg\"></x-tilmart-price>\n } @else {\n <div class=\"x-pdp-no-price\">Price not available yet.</div>\n }\n\n @if (kit && kit.items.length) {\n <div class=\"x-pdp-bundle-items\">\n <div class=\"x-pdp-bundle-items-title\">What's included</div>\n @for (item of kit.items; track item.name) {\n <div class=\"x-pdp-bundle-item\">\n @if (item.imageUrl) {\n <img class=\"x-pdp-bundle-item-img\" [src]=\"item.imageUrl\" [alt]=\"item.name\" />\n }\n <span class=\"x-pdp-bundle-item-qty\">{{ item.quantity }}×</span>\n @if (item.slug) {\n <a class=\"x-pdp-bundle-item-name\" [routerLink]=\"['/p', item.slug]\">{{ item.name }}</a>\n } @else {\n <span class=\"x-pdp-bundle-item-name\">{{ item.name }}</span>\n }\n @if (!item.isRequired) {\n <span class=\"x-pdp-bundle-item-opt\">optional</span>\n }\n </div>\n }\n </div>\n }\n\n @if (outOfStock) {\n <div class=\"x-pdp-oos\">\n <div class=\"x-pdp-oos-label\">Out of stock</div>\n @if (bisSubmitted) {\n <p class=\"x-pdp-oos-done\">We’ll email you the moment it’s back.</p>\n } @else {\n <p class=\"x-pdp-oos-hint\">Get an email when it’s available again.</p>\n <form class=\"x-pdp-oos-form\" (ngSubmit)=\"submitBackInStock()\">\n <input\n type=\"email\"\n class=\"x-pdp-oos-input\"\n placeholder=\"you@email.com\"\n required\n [(ngModel)]=\"bisEmail\"\n name=\"bisEmail\"\n />\n <button\n type=\"submit\"\n class=\"x-pdp-add-btn\"\n [disabled]=\"bisSubmitting || !bisEmail\"\n >\n Notify me\n </button>\n </form>\n }\n </div>\n } @else {\n <div class=\"x-pdp-buy-row\">\n <x-tilmart-quantity-stepper\n [value]=\"quantity\"\n (inc)=\"onQuantityChange(quantity + 1)\"\n (dec)=\"onQuantityChange(quantity - 1)\"\n ></x-tilmart-quantity-stepper>\n <button type=\"button\" class=\"x-pdp-add-btn\" (click)=\"onAddToCart()\">Add to cart</button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"x-pdp-compat\">\n <x-tilmart-section-header title=\"Works with what I already have\"></x-tilmart-section-header>\n <div class=\"x-pdp-compat-search\">\n <input\n type=\"search\"\n class=\"x-pdp-compat-input\"\n placeholder=\"Search your inverter, battery, or panel…\"\n [(ngModel)]=\"compatQuery\"\n (ngModelChange)=\"searchCompatCandidates()\"\n />\n @if (compatCandidates.length) {\n <div class=\"x-pdp-compat-candidates\">\n @for (candidate of compatCandidates; track candidate.productId) {\n <button\n type=\"button\"\n class=\"x-pdp-compat-candidate\"\n (click)=\"selectCompatCandidate(candidate)\"\n >\n {{ candidate.name }}\n </button>\n }\n </div>\n }\n </div>\n @if (compatSelected) {\n <x-tilmart-compat-verdict\n [loading]=\"compatLoading\"\n [verdict]=\"compatVerdict\"\n [findings]=\"compatFindings\"\n ></x-tilmart-compat-verdict>\n }\n </div>\n\n @for (group of relatedGroups; track group.type) {\n <div class=\"x-pdp-related\">\n <x-tilmart-section-header [title]=\"group.label\"></x-tilmart-section-header>\n <div class=\"x-pdp-related-grid\">\n @for (item of group.items; track item.productId) {\n <x-tilmart-product-card\n [href]=\"item.href\"\n [imageUrl]=\"item.imageUrl\"\n [name]=\"item.name\"\n [price]=\"item.price\"\n [inStock]=\"item.inStock\"\n [badges]=\"item.badges\"\n (addToCart)=\"cartAdd.addCard(item)\"\n (specs)=\"cartAdd.viewSpecs(item)\"\n ></x-tilmart-product-card>\n }\n </div>\n </div>\n }\n\n <div class=\"x-pdp-tabs\" id=\"specs\">\n <div class=\"x-pdp-tab-bar\">\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'specs'\" (click)=\"setTab('specs')\">\n Specs\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'reviews'\" (click)=\"setTab('reviews')\">\n Reviews\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'shipping'\" (click)=\"setTab('shipping')\">\n Shipping &amp; returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&amp;A\n </button>\n </div>\n\n <div class=\"x-pdp-tab-panel\">\n @switch (activeTab) {\n @case ('specs') {\n @if (product.longDesc) {\n <p class=\"x-pdp-long-desc\">{{ product.longDesc }}</p>\n }\n @if (specGroups.length) {\n <x-tilmart-spec-table [groups]=\"specGroups\"></x-tilmart-spec-table>\n } @else {\n <div class=\"x-pdp-empty\">No specifications published yet.</div>\n }\n @if (documents.length) {\n <div class=\"x-pdp-documents\">\n <div class=\"x-pdp-documents-title\">Documents</div>\n @for (doc of documents; track doc.id) {\n <a class=\"x-pdp-document\" [href]=\"doc.url\" target=\"_blank\" rel=\"noopener\">\n {{ doc.title }}\n </a>\n }\n </div>\n }\n }\n @case ('reviews') {\n <x-pdp-reviews [productId]=\"product.id\"></x-pdp-reviews>\n }\n @case ('shipping') {\n <div class=\"x-pdp-shipping\">\n <p>Delivery cost and timing are calculated at checkout based on your location.</p>\n <p>Returns are accepted within the manufacturer's warranty terms.</p>\n </div>\n }\n @case ('qna') {\n <x-pdp-qna [productId]=\"product.id\"></x-pdp-qna>\n }\n }\n </div>\n </div>\n} @else if (notFound) {\n <div class=\"x-pdp-not-found\">Product not found.</div>\n} @else {\n <x-element-loader></x-element-loader>\n}\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { TilmartElementsModule } from '@isaiahiroko/tilmart-ngx-ui';\nimport { ProductComponent } from './product.component';\nimport { QnaPanelComponent } from './qna-panel.component';\nimport { ReviewsPanelComponent } from './reviews-panel.component';\n\n@NgModule({\n declarations: [ProductComponent, ReviewsPanelComponent, QnaPanelComponent],\n imports: [\n SharedModule,\n ElementsModule,\n TilmartElementsModule,\n RouterModule.forChild([{ path: '', component: ProductComponent }]),\n ],\n})\nexport class ProductModule {}\n"],"names":["i2","i3","i4","i5.ReviewsPanelComponent","i6.QnaPanelComponent","i7","i1"],"mappings":"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"}