@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.
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs → isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs} +3 -3
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-buyer-help.module-Rq3SuDLX.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs → isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs} +24 -3
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-buyer-product.module-DEFPefnb.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-buyer.mjs +4 -4
- package/package.json +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-buyer-help.module-CTL4vRKb.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-buyer-product.module-BvWmbiHx.mjs.map +0 -1
|
@@ -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 & 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 & warranty</a>\n <a href=\"https://wa.me/
|
|
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 & 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 & 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 & 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 & warranty</a>\n <a href=\"https://wa.me/
|
|
133
|
+
args: [{ standalone: false, selector: 'x-help', template: "<div class=\"x-help\">\n <h1>Help & 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 & 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-
|
|
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 & 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 & 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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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-
|
|
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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 +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 & 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 & 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 & returns\n </button>\n <button type=\"button\" class=\"x-pdp-tab\" [class.x-pdp-tab-active]=\"activeTab === 'qna'\" (click)=\"setTab('qna')\">\n Q&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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"}
|