@isaiahiroko/tilmart-ngx-apps-admin 0.2.0 → 0.2.3
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-admin-articles.module-OeLRnPwN.mjs → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs} +5 -5
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs +239 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs +76 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs +70 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-bulk-upload.module-BGTbsYUP.mjs +370 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-bulk-upload.module-BGTbsYUP.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-BwjfFXDU.mjs +562 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-BwjfFXDU.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs +94 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs +137 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs} +5 -5
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs +85 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs +123 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs +83 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs} +5 -5
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs +66 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs} +5 -5
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs} +4 -4
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-vldWwcAr.mjs +190 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-vldWwcAr.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs +114 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs +94 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs +78 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs → isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs} +9 -34
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs} +5 -5
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs.map} +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs +163 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs +81 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs +318 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs → isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs} +13 -32
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs +140 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs +102 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs.map +1 -0
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs} +6 -6
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs.map} +1 -1
- package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs → isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs} +9 -34
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +104 -72
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -1
- package/package.json +1 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +0 -294
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +0 -224
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs +0 -185
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +0 -274
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +0 -106
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +0 -105
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +0 -222
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +0 -107
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +0 -1
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs","sources":["../../../projects/admin/src/lib/pages/inbox/inbox.component.ts","../../../projects/admin/src/lib/pages/inbox/inbox.component.html","../../../projects/admin/src/lib/pages/inbox/inbox.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport {\n BaseDirective,\n ControlService,\n notify,\n using,\n} from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface TicketVm {\n id: string;\n type: string;\n subject?: string;\n note: string;\n status: string;\n channel?: string;\n priority?: string;\n category?: string;\n customerId?: string;\n orderId?: string;\n contactPhone?: string;\n contactEmail?: string;\n assignedTo?: string;\n resolutionCode?: string;\n internalNotes?: { by?: string; at: string; text: string }[];\n firstResponseAt?: string;\n slaDueAt?: string;\n resolvedAt?: string;\n createdAt: string;\n}\n\ninterface WaMessageVm {\n id: string;\n direction: string;\n text: string;\n createdAt: string;\n}\n\nconst PRIORITIES = ['urgent', 'high', 'normal', 'low'];\nconst STATUSES = ['open', 'in_progress', 'resolved', 'closed'];\nconst CATEGORIES = [\n 'order-issue',\n 'delivery',\n 'payment-refund',\n 'product-question',\n 'warranty-return',\n 'account',\n 'complaint',\n 'other',\n];\nconst RESOLUTION_CODES = [\n 'resolved-info-given',\n 'resolved-order-action',\n 'resolved-refund',\n 'resolved-replacement',\n 'resolved-no-fault',\n 'duplicate',\n 'no-response',\n];\nconst FILTERS = ['all', 'unassigned', 'mine', 'open', 'breaching'] as const;\ntype FilterKey = (typeof FILTERS)[number];\n\n// P7.5, SUP-02/SUP-03 — the unified support inbox. One queue over every\n// ComplaintLog regardless of channel (WhatsApp / phone / email / web\n// form), with a ticket detail pane: customer + linked-order context\n// (GET complaint-log/:id/context), priority / category / assignment /\n// status / resolution coding, an internal-notes thread, canned responses\n// (SupportMacro), an SLA countdown, and the inline WhatsApp thread when\n// the ticket came in over WhatsApp.\n@Component({\n standalone: false,\n selector: 'x-inbox',\n templateUrl: './inbox.component.html',\n})\nexport class InboxComponent extends BaseDirective {\n private readonly tickets = this.apiService.on('apps/commerce/complaint-log');\n private readonly macros = this.apiService.on('apps/commerce/support-macro');\n private readonly waSessions = this.apiService.on(\n 'apps/whatsapp/conversation-session',\n );\n private readonly waMessages = this.apiService.on('apps/whatsapp/message-log');\n\n readonly priorities = PRIORITIES;\n readonly statuses = STATUSES;\n readonly categories = CATEGORIES;\n readonly resolutionCodes = RESOLUTION_CODES;\n readonly filters = FILTERS;\n\n loading = true;\n all: TicketVm[] = [];\n filter: FilterKey = 'all';\n\n selected?: TicketVm;\n context: { customer?: any; order?: any } = {};\n contextLoading = false;\n macroList: any[] = [];\n reply = '';\n newNote = '';\n waThread: WaMessageVm[] = [];\n\n // agent identity for \"mine\" / assignment\n readonly agent =\n (this.controlService?.getMeta?.() as any)?.ref ?? 'agent';\n\n constructor(private readonly controlService: ControlService) {\n super();\n }\n\n override init = () => {\n this.load();\n this.macros\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.macroList = (res?.data ?? []).filter(\n (m: any) => m.enabled !== false,\n );\n }),\n );\n };\n\n load(): void {\n this.loading = true;\n this.tickets\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.all = (res?.data ?? []).sort(\n (a: TicketVm, b: TicketVm) =>\n this.rank(a) - this.rank(b) ||\n new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.all.find((t) => t.id === this.selected!.id);\n }\n }),\n );\n }\n\n private rank(t: TicketVm): number {\n if (t.resolvedAt || t.status === 'resolved' || t.status === 'closed') return 5;\n const p = { urgent: 0, high: 1, normal: 2, low: 3 }[t.priority ?? 'normal'];\n return p ?? 2;\n }\n\n get queue(): TicketVm[] {\n switch (this.filter) {\n case 'unassigned':\n return this.all.filter((t) => !t.assignedTo && !this.isDone(t));\n case 'mine':\n return this.all.filter((t) => t.assignedTo === this.agent);\n case 'open':\n return this.all.filter((t) => !this.isDone(t));\n case 'breaching':\n return this.all.filter((t) => this.isBreaching(t));\n default:\n return this.all;\n }\n }\n\n isDone(t: TicketVm): boolean {\n return !!t.resolvedAt || t.status === 'resolved' || t.status === 'closed';\n }\n\n isBreaching(t: TicketVm): boolean {\n if (this.isDone(t) || t.firstResponseAt || !t.slaDueAt) return false;\n return new Date(t.slaDueAt).getTime() < Date.now();\n }\n\n slaLabel(t: TicketVm): string {\n if (this.isDone(t)) return 'done';\n if (t.firstResponseAt) return 'responded';\n if (!t.slaDueAt) return '';\n const mins = Math.round(\n (new Date(t.slaDueAt).getTime() - Date.now()) / 60000,\n );\n if (mins < 0) return `${Math.abs(Math.round(mins / 60))}h over`;\n if (mins < 60) return `${mins}m left`;\n return `${Math.round(mins / 60)}h left`;\n }\n\n channelLabel(t: TicketVm): string {\n return (t.channel ?? 'web').replace(/_/g, ' ');\n }\n\n async select(t: TicketVm): Promise<void> {\n this.selected = t;\n this.reply = '';\n this.newNote = '';\n this.context = {};\n this.waThread = [];\n this.contextLoading = true;\n try {\n const res: any = await firstValueFrom(this.tickets.getOne(`${t.id}/context`));\n const data = res?.data?.data ?? res?.data ?? {};\n this.context = { customer: data.customer, order: data.order };\n } catch {\n this.context = {};\n } finally {\n this.contextLoading = false;\n }\n if (t.channel === 'whatsapp' && t.contactPhone) {\n this.loadWaThread(t.contactPhone);\n }\n }\n\n private loadWaThread(phone: string): void {\n this.waSessions\n .getMany({ perPage: 100 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const session = (res?.data ?? []).find(\n (s: any) => (s.phone ?? '').replace(/\\D/g, '') === phone.replace(/\\D/g, ''),\n );\n if (!session) return;\n this.waMessages\n .getMany({ perPage: 200, sessionId: session.id } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((mres: any) => {\n this.waThread = (mres?.data ?? [])\n .slice()\n .sort(\n (a: any, b: any) =>\n new Date(a.createdAt).getTime() -\n new Date(b.createdAt).getTime(),\n )\n .map((m: any) => ({\n id: m.id,\n direction: m.direction,\n text: m.text ?? m.templateName ?? '',\n createdAt: m.createdAt,\n }));\n }),\n );\n }),\n );\n }\n\n async patch(fields: Partial<TicketVm>): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.tickets.update(this.selected.id, fields as any));\n this.load();\n } catch {\n notify('Could not update the ticket.', undefined, 'error');\n }\n }\n\n assignToMe(): void {\n void this.patch({ assignedTo: this.agent, status: 'in_progress' });\n }\n\n async addNote(): Promise<void> {\n if (!this.selected || !this.newNote.trim()) return;\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/complaint-log/${this.selected.id}/note`,\n { text: this.newNote.trim(), by: this.agent },\n ),\n );\n this.newNote = '';\n this.load();\n } catch {\n notify('Could not add the note.', undefined, 'error');\n }\n }\n\n applyMacro(macro: any): void {\n this.reply = this.reply ? `${this.reply}\\n\\n${macro.body}` : macro.body;\n }\n\n async markReplied(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/complaint-log/${this.selected.id}/first-response`,\n {},\n ),\n );\n notify('Marked as first-responded — SLA clock stopped.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not mark the reply.', undefined, 'error');\n }\n }\n\n async resolve(code: string): Promise<void> {\n if (!this.selected || !code) return;\n await this.patch({\n status: 'resolved',\n resolutionCode: code,\n resolvedAt: new Date().toISOString() as any,\n });\n }\n\n // --- log a non-WhatsApp inbound (phone call, forwarded email) ---\n newOpen = false;\n draft = { channel: 'phone', subject: '', note: '', contactPhone: '', contactEmail: '' };\n\n async createTicket(): Promise<void> {\n if (!this.draft.note.trim()) return;\n try {\n await firstValueFrom(\n this.tickets.create({\n type: 'support_request',\n channel: this.draft.channel,\n subject: this.draft.subject || undefined,\n note: this.draft.note.trim(),\n priority: 'normal',\n contactPhone: this.draft.contactPhone || undefined,\n contactEmail: this.draft.contactEmail || undefined,\n loggedBy: this.agent,\n } as any),\n );\n this.newOpen = false;\n this.draft = { channel: 'phone', subject: '', note: '', contactPhone: '', contactEmail: '' };\n notify('Ticket logged.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not log the ticket.', undefined, 'error');\n }\n }\n}\n","<div class=\"x-page-head\">\n <div>\n <div class=\"x-page-title\">Support inbox</div>\n <div class=\"x-page-subtitle\">\n Every contact channel in one queue — WhatsApp, phone, email, web form.\n </div>\n </div>\n <button type=\"button\" class=\"x-ib-new-btn\" (click)=\"newOpen = !newOpen\">\n {{ newOpen ? 'Cancel' : 'Log a ticket' }}\n </button>\n</div>\n\n@if (newOpen) {\n <form class=\"x-ib-new\" (ngSubmit)=\"createTicket()\">\n <div class=\"x-ib-new-row\">\n <select [(ngModel)]=\"draft.channel\" name=\"channel\">\n <option value=\"phone\">Phone</option>\n <option value=\"email\">Email</option>\n <option value=\"web\">Web form</option>\n <option value=\"walk_in\">Walk-in</option>\n </select>\n <input placeholder=\"Subject\" [(ngModel)]=\"draft.subject\" name=\"subject\" />\n <input placeholder=\"Contact phone\" [(ngModel)]=\"draft.contactPhone\" name=\"phone\" />\n <input placeholder=\"Contact email\" [(ngModel)]=\"draft.contactEmail\" name=\"email\" />\n </div>\n <textarea placeholder=\"What did the customer contact us about?\" rows=\"2\" [(ngModel)]=\"draft.note\" name=\"note\"></textarea>\n <button type=\"submit\" class=\"x-ib-new-btn\" [disabled]=\"!draft.note.trim()\">Log ticket</button>\n </form>\n}\n\n<nav class=\"x-ib-filters\">\n @for (f of filters; track f) {\n <button type=\"button\" class=\"x-ib-filter\" [class.is-active]=\"filter === f\" (click)=\"filter = f\">\n {{ f }}\n </button>\n }\n</nav>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-ib-layout\">\n <div class=\"x-ib-queue\">\n @for (t of queue; track t.id) {\n <button\n type=\"button\"\n class=\"x-ib-ticket\"\n [class.is-active]=\"selected?.id === t.id\"\n [class.is-breaching]=\"isBreaching(t)\"\n (click)=\"select(t)\"\n >\n <div class=\"x-ib-ticket-top\">\n <span class=\"x-ib-chan\">{{ channelLabel(t) }}</span>\n @if (t.priority) { <span class=\"x-ib-prio x-ib-prio-{{ t.priority }}\">{{ t.priority }}</span> }\n <span class=\"x-ib-sla\" [class.is-bad]=\"isBreaching(t)\">{{ slaLabel(t) }}</span>\n </div>\n <div class=\"x-ib-ticket-subject\">{{ t.subject || t.type }}</div>\n <div class=\"x-ib-ticket-note\">{{ t.note }}</div>\n <div class=\"x-ib-ticket-meta\">\n <span>{{ t.status.replace('_', ' ') }}</span>\n @if (t.assignedTo) { <span>· {{ t.assignedTo }}</span> }\n </div>\n </button>\n } @empty {\n <div class=\"x-ib-empty\">Nothing in this view.</div>\n }\n </div>\n\n <div class=\"x-ib-detail\">\n @if (!selected) {\n <div class=\"x-ib-empty\">Select a ticket.</div>\n } @else {\n <div class=\"x-ib-d-head\">\n <div class=\"x-ib-d-title\">{{ selected.subject || selected.type }}</div>\n <div class=\"x-ib-d-sub\">\n {{ channelLabel(selected) }} · opened {{ selected.createdAt | date: 'short' }}\n </div>\n </div>\n\n <!-- context -->\n <div class=\"x-ib-context\">\n @if (contextLoading) {\n <span class=\"x-ib-muted\">Loading context…</span>\n } @else {\n <div class=\"x-ib-ctx-block\">\n <div class=\"x-ib-ctx-label\">Customer</div>\n @if (context.customer) {\n <div>{{ context.customer.name || '—' }}</div>\n <div class=\"x-ib-muted\">{{ context.customer.email }} {{ context.customer.phone }}</div>\n } @else {\n <div class=\"x-ib-muted\">{{ selected.contactEmail || selected.contactPhone || 'Not linked' }}</div>\n }\n </div>\n @if (context.order) {\n <div class=\"x-ib-ctx-block\">\n <div class=\"x-ib-ctx-label\">Linked order</div>\n <div><strong>{{ context.order.orderNumber }}</strong> · {{ context.order.status.replace('_', ' ') }}</div>\n <div class=\"x-ib-muted\">\n ₦{{ context.order.grandTotal | number: '1.0-0' }} ·\n {{ context.order.lines.length }} line(s)\n </div>\n </div>\n }\n }\n </div>\n\n <!-- controls -->\n <div class=\"x-ib-controls\">\n <label>Priority\n <select [ngModel]=\"selected.priority || 'normal'\" (ngModelChange)=\"patch({ priority: $event })\">\n @for (p of priorities; track p) { <option [value]=\"p\">{{ p }}</option> }\n </select>\n </label>\n <label>Category\n <select [ngModel]=\"selected.category || ''\" (ngModelChange)=\"patch({ category: $event })\">\n <option value=\"\">—</option>\n @for (c of categories; track c) { <option [value]=\"c\">{{ c }}</option> }\n </select>\n </label>\n <label>Status\n <select [ngModel]=\"selected.status\" (ngModelChange)=\"patch({ status: $event })\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s.replace('_', ' ') }}</option> }\n </select>\n </label>\n @if (selected.assignedTo !== agent) {\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"assignToMe()\">Assign to me</button>\n } @else {\n <span class=\"x-ib-muted\">Assigned to you</span>\n }\n </div>\n\n <!-- whatsapp thread -->\n @if (waThread.length) {\n <div class=\"x-ib-ctx-label\">WhatsApp thread</div>\n <div class=\"x-ib-wa\">\n @for (m of waThread; track m.id) {\n <div class=\"x-ib-wa-row\" [class.is-out]=\"m.direction === 'outbound'\">\n <div class=\"x-ib-wa-bubble\" [class.is-out]=\"m.direction === 'outbound'\">{{ m.text }}</div>\n </div>\n }\n </div>\n }\n\n <!-- reply + macros -->\n <div class=\"x-ib-ctx-label\">Reply</div>\n @if (macroList.length) {\n <div class=\"x-ib-macros\">\n @for (m of macroList; track m.id) {\n <button type=\"button\" class=\"x-ib-macro\" (click)=\"applyMacro(m)\">{{ m.title }}</button>\n }\n </div>\n }\n <textarea class=\"x-ib-reply\" rows=\"4\" [(ngModel)]=\"reply\" placeholder=\"Draft a reply (copy into WhatsApp / email), then mark it sent.\"></textarea>\n <div class=\"x-ib-reply-actions\">\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"markReplied()\">Mark replied (stops SLA)</button>\n @if (selected.firstResponseAt) {\n <span class=\"x-ib-muted\">First response {{ selected.firstResponseAt | date: 'short' }}</span>\n }\n </div>\n\n <!-- internal notes -->\n <div class=\"x-ib-ctx-label\">Internal notes</div>\n <div class=\"x-ib-notes\">\n @for (n of selected.internalNotes || []; track n.at) {\n <div class=\"x-ib-note\">\n <div class=\"x-ib-muted\">{{ n.by || 'agent' }} · {{ n.at | date: 'short' }}</div>\n <div>{{ n.text }}</div>\n </div>\n } @empty {\n <div class=\"x-ib-muted\">No notes yet.</div>\n }\n </div>\n <div class=\"x-ib-note-add\">\n <input [(ngModel)]=\"newNote\" placeholder=\"Add an internal note…\" (keyup.enter)=\"addNote()\" />\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"addNote()\">Add</button>\n </div>\n\n <!-- resolve -->\n <div class=\"x-ib-resolve\">\n <div class=\"x-ib-ctx-label\">Resolve</div>\n <div class=\"x-ib-resolve-codes\">\n @for (code of resolutionCodes; track code) {\n <button type=\"button\" class=\"x-ib-macro\" (click)=\"resolve(code)\">{{ code }}</button>\n }\n </div>\n @if (selected.resolutionCode) {\n <span class=\"x-ib-muted\">Resolved: {{ selected.resolutionCode }}</span>\n }\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n\n .x-ib-new-btn, .x-ib-btn { appearance: none; border: 1px solid var(--color-border); background: var(--color-surface, #fff); color: var(--color-text); border-radius: 8px; padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer; }\n .x-ib-new-btn:disabled { opacity: 0.5; }\n\n .x-ib-new { border: 1px solid var(--color-border); border-radius: 10px; padding: 14px; margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }\n .x-ib-new-row { display: flex; flex-wrap: wrap; gap: 8px; }\n .x-ib-new input, .x-ib-new select, .x-ib-new textarea { font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-ib-new input { flex: 1; min-width: 130px; }\n\n .x-ib-filters { display: flex; gap: 4px; margin-bottom: 14px; border-bottom: 1px solid var(--color-border); }\n .x-ib-filter { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 7px 12px; font-size: 12.5px; font-weight: 600; text-transform: capitalize; color: var(--color-text-muted); cursor: pointer; }\n .x-ib-filter.is-active { color: var(--color-text); border-bottom-color: var(--color-brand); }\n\n .x-ib-layout { display: grid; grid-template-columns: 320px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 820px) { .x-ib-layout { grid-template-columns: 1fr; } }\n\n .x-ib-queue { display: flex; flex-direction: column; gap: 6px; max-height: 70vh; overflow-y: auto; }\n .x-ib-ticket { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 10px; background: var(--color-surface, #fff); padding: 10px 12px; cursor: pointer; }\n .x-ib-ticket.is-active { border-color: var(--color-brand); }\n .x-ib-ticket.is-breaching { border-left: 3px solid var(--color-danger, #c0392b); }\n .x-ib-ticket-top { display: flex; gap: 6px; align-items: center; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); margin-bottom: 4px; }\n .x-ib-prio { font-weight: 700; }\n .x-ib-prio-urgent, .x-ib-prio-high { color: var(--color-danger, #c0392b); }\n .x-ib-sla { margin-left: auto; }\n .x-ib-sla.is-bad { color: var(--color-danger, #c0392b); font-weight: 700; }\n .x-ib-ticket-subject { font-size: 13.5px; font-weight: 700; color: var(--color-text); }\n .x-ib-ticket-note { font-size: 12px; color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .x-ib-ticket-meta { font-size: 11px; color: var(--color-text-muted); margin-top: 3px; text-transform: capitalize; }\n\n .x-ib-detail { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; }\n .x-ib-d-title { font-size: 16px; font-weight: 800; color: var(--color-text); }\n .x-ib-d-sub { font-size: 12px; color: var(--color-text-muted); text-transform: capitalize; margin-bottom: 12px; }\n .x-ib-context { display: flex; flex-wrap: wrap; gap: 16px; padding: 10px; background: color-mix(in srgb, var(--color-border) 20%, transparent); border-radius: 8px; margin-bottom: 12px; font-size: 13px; }\n .x-ib-ctx-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; color: var(--color-text-muted); margin: 14px 0 6px; }\n .x-ib-muted { color: var(--color-text-muted); font-size: 12px; }\n\n .x-ib-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }\n .x-ib-controls label { display: flex; flex-direction: column; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); gap: 3px; }\n .x-ib-controls select { font: inherit; padding: 5px 8px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); text-transform: capitalize; }\n\n .x-ib-wa { display: flex; flex-direction: column; gap: 5px; max-height: 240px; overflow-y: auto; padding: 8px; border: 1px solid var(--color-border); border-radius: 8px; }\n .x-ib-wa-row { display: flex; }\n .x-ib-wa-row.is-out { justify-content: flex-end; }\n .x-ib-wa-bubble { max-width: 75%; font-size: 12.5px; padding: 6px 10px; border-radius: 10px; background: color-mix(in srgb, var(--color-border) 30%, transparent); }\n .x-ib-wa-bubble.is-out { background: var(--color-brand); color: #fff; }\n\n .x-ib-macros, .x-ib-resolve-codes { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }\n .x-ib-macro { appearance: none; border: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); border-radius: 999px; padding: 3px 10px; font-size: 11.5px; cursor: pointer; }\n .x-ib-reply, .x-ib-note-add input, .x-ib-new textarea { width: 100%; font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); box-sizing: border-box; }\n .x-ib-reply-actions { display: flex; gap: 10px; align-items: center; margin-top: 6px; }\n\n .x-ib-notes { display: flex; flex-direction: column; gap: 6px; }\n .x-ib-note { font-size: 13px; border-left: 2px solid var(--color-border); padding-left: 8px; }\n .x-ib-note-add { display: flex; gap: 8px; margin-top: 8px; }\n .x-ib-note-add input { flex: 1; }\n\n .x-ib-resolve { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--color-border); }\n .x-ib-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';\nimport { InboxComponent } from './inbox.component';\n\n@NgModule({\n declarations: [InboxComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: InboxComponent }]),\n ],\n})\nexport class InboxModule {}\n"],"names":["i2","i3","i4","i1"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs","sources":["../../../projects/admin/src/lib/pages/inbox/inbox.component.ts","../../../projects/admin/src/lib/pages/inbox/inbox.component.html","../../../projects/admin/src/lib/pages/inbox/inbox.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport {\n BaseDirective,\n ControlService,\n notify,\n using,\n} from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface TicketVm {\n id: string;\n type: string;\n subject?: string;\n note: string;\n status: string;\n channel?: string;\n priority?: string;\n category?: string;\n customerId?: string;\n orderId?: string;\n contactPhone?: string;\n contactEmail?: string;\n assignedTo?: string;\n resolutionCode?: string;\n internalNotes?: { by?: string; at: string; text: string }[];\n firstResponseAt?: string;\n slaDueAt?: string;\n resolvedAt?: string;\n createdAt: string;\n}\n\ninterface WaMessageVm {\n id: string;\n direction: string;\n text: string;\n createdAt: string;\n}\n\nconst PRIORITIES = ['urgent', 'high', 'normal', 'low'];\nconst STATUSES = ['open', 'in_progress', 'resolved', 'closed'];\nconst CATEGORIES = [\n 'order-issue',\n 'delivery',\n 'payment-refund',\n 'product-question',\n 'warranty-return',\n 'account',\n 'complaint',\n 'other',\n];\nconst RESOLUTION_CODES = [\n 'resolved-info-given',\n 'resolved-order-action',\n 'resolved-refund',\n 'resolved-replacement',\n 'resolved-no-fault',\n 'duplicate',\n 'no-response',\n];\nconst FILTERS = ['all', 'unassigned', 'mine', 'open', 'breaching'] as const;\ntype FilterKey = (typeof FILTERS)[number];\n\n// P7.5, SUP-02/SUP-03 — the unified support inbox. One queue over every\n// ComplaintLog regardless of channel (WhatsApp / phone / email / web\n// form), with a ticket detail pane: customer + linked-order context\n// (GET complaint-log/:id/context), priority / category / assignment /\n// status / resolution coding, an internal-notes thread, canned responses\n// (SupportMacro), an SLA countdown, and the inline WhatsApp thread when\n// the ticket came in over WhatsApp.\n@Component({\n standalone: false,\n selector: 'x-inbox',\n templateUrl: './inbox.component.html',\n})\nexport class InboxComponent extends BaseDirective {\n private readonly tickets = this.apiService.on('apps/commerce/complaint-log');\n private readonly macros = this.apiService.on('apps/commerce/support-macro');\n private readonly waSessions = this.apiService.on(\n 'apps/whatsapp/conversation-session',\n );\n private readonly waMessages = this.apiService.on('apps/whatsapp/message-log');\n\n readonly priorities = PRIORITIES;\n readonly statuses = STATUSES;\n readonly categories = CATEGORIES;\n readonly resolutionCodes = RESOLUTION_CODES;\n readonly filters = FILTERS;\n\n loading = true;\n all: TicketVm[] = [];\n filter: FilterKey = 'all';\n\n selected?: TicketVm;\n context: { customer?: any; order?: any } = {};\n contextLoading = false;\n macroList: any[] = [];\n reply = '';\n newNote = '';\n waThread: WaMessageVm[] = [];\n\n // agent identity for \"mine\" / assignment\n readonly agent =\n (this.controlService?.getMeta?.() as any)?.ref ?? 'agent';\n\n constructor(private readonly controlService: ControlService) {\n super();\n }\n\n override init = () => {\n this.load();\n this.macros\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.macroList = (res?.data ?? []).filter(\n (m: any) => m.enabled !== false,\n );\n }),\n );\n };\n\n load(): void {\n this.loading = true;\n this.tickets\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.all = (res?.data ?? []).sort(\n (a: TicketVm, b: TicketVm) =>\n this.rank(a) - this.rank(b) ||\n new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.all.find((t) => t.id === this.selected!.id);\n }\n }),\n );\n }\n\n private rank(t: TicketVm): number {\n if (t.resolvedAt || t.status === 'resolved' || t.status === 'closed') return 5;\n const p = { urgent: 0, high: 1, normal: 2, low: 3 }[t.priority ?? 'normal'];\n return p ?? 2;\n }\n\n get queue(): TicketVm[] {\n switch (this.filter) {\n case 'unassigned':\n return this.all.filter((t) => !t.assignedTo && !this.isDone(t));\n case 'mine':\n return this.all.filter((t) => t.assignedTo === this.agent);\n case 'open':\n return this.all.filter((t) => !this.isDone(t));\n case 'breaching':\n return this.all.filter((t) => this.isBreaching(t));\n default:\n return this.all;\n }\n }\n\n isDone(t: TicketVm): boolean {\n return !!t.resolvedAt || t.status === 'resolved' || t.status === 'closed';\n }\n\n isBreaching(t: TicketVm): boolean {\n if (this.isDone(t) || t.firstResponseAt || !t.slaDueAt) return false;\n return new Date(t.slaDueAt).getTime() < Date.now();\n }\n\n slaLabel(t: TicketVm): string {\n if (this.isDone(t)) return 'done';\n if (t.firstResponseAt) return 'responded';\n if (!t.slaDueAt) return '';\n const mins = Math.round(\n (new Date(t.slaDueAt).getTime() - Date.now()) / 60000,\n );\n if (mins < 0) return `${Math.abs(Math.round(mins / 60))}h over`;\n if (mins < 60) return `${mins}m left`;\n return `${Math.round(mins / 60)}h left`;\n }\n\n channelLabel(t: TicketVm): string {\n return (t.channel ?? 'web').replace(/_/g, ' ');\n }\n\n async select(t: TicketVm): Promise<void> {\n this.selected = t;\n this.reply = '';\n this.newNote = '';\n this.context = {};\n this.waThread = [];\n this.contextLoading = true;\n try {\n const res: any = await firstValueFrom(this.tickets.getOne(`${t.id}/context`));\n const data = res?.data?.data ?? res?.data ?? {};\n this.context = { customer: data.customer, order: data.order };\n } catch {\n this.context = {};\n } finally {\n this.contextLoading = false;\n }\n if (t.channel === 'whatsapp' && t.contactPhone) {\n this.loadWaThread(t.contactPhone);\n }\n }\n\n private loadWaThread(phone: string): void {\n this.waSessions\n .getMany({ perPage: 100 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const session = (res?.data ?? []).find(\n (s: any) => (s.phone ?? '').replace(/\\D/g, '') === phone.replace(/\\D/g, ''),\n );\n if (!session) return;\n this.waMessages\n .getMany({ perPage: 200, sessionId: session.id } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((mres: any) => {\n this.waThread = (mres?.data ?? [])\n .slice()\n .sort(\n (a: any, b: any) =>\n new Date(a.createdAt).getTime() -\n new Date(b.createdAt).getTime(),\n )\n .map((m: any) => ({\n id: m.id,\n direction: m.direction,\n text: m.text ?? m.templateName ?? '',\n createdAt: m.createdAt,\n }));\n }),\n );\n }),\n );\n }\n\n async patch(fields: Partial<TicketVm>): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.tickets.update(this.selected.id, fields as any));\n this.load();\n } catch {\n notify('Could not update the ticket.', undefined, 'error');\n }\n }\n\n assignToMe(): void {\n void this.patch({ assignedTo: this.agent, status: 'in_progress' });\n }\n\n async addNote(): Promise<void> {\n if (!this.selected || !this.newNote.trim()) return;\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/complaint-log/${this.selected.id}/note`,\n { text: this.newNote.trim(), by: this.agent },\n ),\n );\n this.newNote = '';\n this.load();\n } catch {\n notify('Could not add the note.', undefined, 'error');\n }\n }\n\n applyMacro(macro: any): void {\n this.reply = this.reply ? `${this.reply}\\n\\n${macro.body}` : macro.body;\n }\n\n async markReplied(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/complaint-log/${this.selected.id}/first-response`,\n {},\n ),\n );\n notify('Marked as first-responded — SLA clock stopped.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not mark the reply.', undefined, 'error');\n }\n }\n\n async resolve(code: string): Promise<void> {\n if (!this.selected || !code) return;\n await this.patch({\n status: 'resolved',\n resolutionCode: code,\n resolvedAt: new Date().toISOString() as any,\n });\n }\n\n // --- log a non-WhatsApp inbound (phone call, forwarded email) ---\n newOpen = false;\n draft = { channel: 'phone', subject: '', note: '', contactPhone: '', contactEmail: '' };\n\n async createTicket(): Promise<void> {\n if (!this.draft.note.trim()) return;\n try {\n await firstValueFrom(\n this.tickets.create({\n type: 'support_request',\n channel: this.draft.channel,\n subject: this.draft.subject || undefined,\n note: this.draft.note.trim(),\n priority: 'normal',\n contactPhone: this.draft.contactPhone || undefined,\n contactEmail: this.draft.contactEmail || undefined,\n loggedBy: this.agent,\n } as any),\n );\n this.newOpen = false;\n this.draft = { channel: 'phone', subject: '', note: '', contactPhone: '', contactEmail: '' };\n notify('Ticket logged.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not log the ticket.', undefined, 'error');\n }\n }\n}\n","<div class=\"x-page-head\">\n <div>\n <div class=\"x-page-title\">Support inbox</div>\n <div class=\"x-page-subtitle\">\n Every contact channel in one queue — WhatsApp, phone, email, web form.\n </div>\n </div>\n <button type=\"button\" class=\"x-ib-new-btn\" (click)=\"newOpen = !newOpen\">\n {{ newOpen ? 'Cancel' : 'Log a ticket' }}\n </button>\n</div>\n\n@if (newOpen) {\n <form class=\"x-ib-new\" (ngSubmit)=\"createTicket()\">\n <div class=\"x-ib-new-row\">\n <select [(ngModel)]=\"draft.channel\" name=\"channel\">\n <option value=\"phone\">Phone</option>\n <option value=\"email\">Email</option>\n <option value=\"web\">Web form</option>\n <option value=\"walk_in\">Walk-in</option>\n </select>\n <input placeholder=\"Subject\" [(ngModel)]=\"draft.subject\" name=\"subject\" />\n <input placeholder=\"Contact phone\" [(ngModel)]=\"draft.contactPhone\" name=\"phone\" />\n <input placeholder=\"Contact email\" [(ngModel)]=\"draft.contactEmail\" name=\"email\" />\n </div>\n <textarea placeholder=\"What did the customer contact us about?\" rows=\"2\" [(ngModel)]=\"draft.note\" name=\"note\"></textarea>\n <button type=\"submit\" class=\"x-ib-new-btn\" [disabled]=\"!draft.note.trim()\">Log ticket</button>\n </form>\n}\n\n<nav class=\"x-ib-filters\">\n @for (f of filters; track f) {\n <button type=\"button\" class=\"x-ib-filter\" [class.is-active]=\"filter === f\" (click)=\"filter = f\">\n {{ f }}\n </button>\n }\n</nav>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-ib-layout\">\n <div class=\"x-ib-queue\">\n @for (t of queue; track t.id) {\n <button\n type=\"button\"\n class=\"x-ib-ticket\"\n [class.is-active]=\"selected?.id === t.id\"\n [class.is-breaching]=\"isBreaching(t)\"\n (click)=\"select(t)\"\n >\n <div class=\"x-ib-ticket-top\">\n <span class=\"x-ib-chan\">{{ channelLabel(t) }}</span>\n @if (t.priority) { <span class=\"x-ib-prio x-ib-prio-{{ t.priority }}\">{{ t.priority }}</span> }\n <span class=\"x-ib-sla\" [class.is-bad]=\"isBreaching(t)\">{{ slaLabel(t) }}</span>\n </div>\n <div class=\"x-ib-ticket-subject\">{{ t.subject || t.type }}</div>\n <div class=\"x-ib-ticket-note\">{{ t.note }}</div>\n <div class=\"x-ib-ticket-meta\">\n <span>{{ t.status.replace('_', ' ') }}</span>\n @if (t.assignedTo) { <span>· {{ t.assignedTo }}</span> }\n </div>\n </button>\n } @empty {\n <div class=\"x-ib-empty\">Nothing in this view.</div>\n }\n </div>\n\n <div class=\"x-ib-detail\">\n @if (!selected) {\n <div class=\"x-ib-empty\">Select a ticket.</div>\n } @else {\n <div class=\"x-ib-d-head\">\n <div class=\"x-ib-d-title\">{{ selected.subject || selected.type }}</div>\n <div class=\"x-ib-d-sub\">\n {{ channelLabel(selected) }} · opened {{ selected.createdAt | date: 'short' }}\n </div>\n </div>\n\n <!-- context -->\n <div class=\"x-ib-context\">\n @if (contextLoading) {\n <span class=\"x-ib-muted\">Loading context…</span>\n } @else {\n <div class=\"x-ib-ctx-block\">\n <div class=\"x-ib-ctx-label\">Customer</div>\n @if (context.customer) {\n <div>{{ context.customer.name || '—' }}</div>\n <div class=\"x-ib-muted\">{{ context.customer.email }} {{ context.customer.phone }}</div>\n } @else {\n <div class=\"x-ib-muted\">{{ selected.contactEmail || selected.contactPhone || 'Not linked' }}</div>\n }\n </div>\n @if (context.order) {\n <div class=\"x-ib-ctx-block\">\n <div class=\"x-ib-ctx-label\">Linked order</div>\n <div><strong>{{ context.order.orderNumber }}</strong> · {{ context.order.status.replace('_', ' ') }}</div>\n <div class=\"x-ib-muted\">\n ₦{{ context.order.grandTotal | number: '1.0-0' }} ·\n {{ context.order.lines.length }} line(s)\n </div>\n </div>\n }\n }\n </div>\n\n <!-- controls -->\n <div class=\"x-ib-controls\">\n <label>Priority\n <select [ngModel]=\"selected.priority || 'normal'\" (ngModelChange)=\"patch({ priority: $event })\">\n @for (p of priorities; track p) { <option [value]=\"p\">{{ p }}</option> }\n </select>\n </label>\n <label>Category\n <select [ngModel]=\"selected.category || ''\" (ngModelChange)=\"patch({ category: $event })\">\n <option value=\"\">—</option>\n @for (c of categories; track c) { <option [value]=\"c\">{{ c }}</option> }\n </select>\n </label>\n <label>Status\n <select [ngModel]=\"selected.status\" (ngModelChange)=\"patch({ status: $event })\">\n @for (s of statuses; track s) { <option [value]=\"s\">{{ s.replace('_', ' ') }}</option> }\n </select>\n </label>\n @if (selected.assignedTo !== agent) {\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"assignToMe()\">Assign to me</button>\n } @else {\n <span class=\"x-ib-muted\">Assigned to you</span>\n }\n </div>\n\n <!-- whatsapp thread -->\n @if (waThread.length) {\n <div class=\"x-ib-ctx-label\">WhatsApp thread</div>\n <div class=\"x-ib-wa\">\n @for (m of waThread; track m.id) {\n <div class=\"x-ib-wa-row\" [class.is-out]=\"m.direction === 'outbound'\">\n <div class=\"x-ib-wa-bubble\" [class.is-out]=\"m.direction === 'outbound'\">{{ m.text }}</div>\n </div>\n }\n </div>\n }\n\n <!-- reply + macros -->\n <div class=\"x-ib-ctx-label\">Reply</div>\n @if (macroList.length) {\n <div class=\"x-ib-macros\">\n @for (m of macroList; track m.id) {\n <button type=\"button\" class=\"x-ib-macro\" (click)=\"applyMacro(m)\">{{ m.title }}</button>\n }\n </div>\n }\n <textarea class=\"x-ib-reply\" rows=\"4\" [(ngModel)]=\"reply\" placeholder=\"Draft a reply (copy into WhatsApp / email), then mark it sent.\"></textarea>\n <div class=\"x-ib-reply-actions\">\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"markReplied()\">Mark replied (stops SLA)</button>\n @if (selected.firstResponseAt) {\n <span class=\"x-ib-muted\">First response {{ selected.firstResponseAt | date: 'short' }}</span>\n }\n </div>\n\n <!-- internal notes -->\n <div class=\"x-ib-ctx-label\">Internal notes</div>\n <div class=\"x-ib-notes\">\n @for (n of selected.internalNotes || []; track n.at) {\n <div class=\"x-ib-note\">\n <div class=\"x-ib-muted\">{{ n.by || 'agent' }} · {{ n.at | date: 'short' }}</div>\n <div>{{ n.text }}</div>\n </div>\n } @empty {\n <div class=\"x-ib-muted\">No notes yet.</div>\n }\n </div>\n <div class=\"x-ib-note-add\">\n <input [(ngModel)]=\"newNote\" placeholder=\"Add an internal note…\" (keyup.enter)=\"addNote()\" />\n <button type=\"button\" class=\"x-ib-btn\" (click)=\"addNote()\">Add</button>\n </div>\n\n <!-- resolve -->\n <div class=\"x-ib-resolve\">\n <div class=\"x-ib-ctx-label\">Resolve</div>\n <div class=\"x-ib-resolve-codes\">\n @for (code of resolutionCodes; track code) {\n <button type=\"button\" class=\"x-ib-macro\" (click)=\"resolve(code)\">{{ code }}</button>\n }\n </div>\n @if (selected.resolutionCode) {\n <span class=\"x-ib-muted\">Resolved: {{ selected.resolutionCode }}</span>\n }\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n\n .x-ib-new-btn, .x-ib-btn { appearance: none; border: 1px solid var(--color-border); background: var(--color-surface, #fff); color: var(--color-text); border-radius: 8px; padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer; }\n .x-ib-new-btn:disabled { opacity: 0.5; }\n\n .x-ib-new { border: 1px solid var(--color-border); border-radius: 10px; padding: 14px; margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }\n .x-ib-new-row { display: flex; flex-wrap: wrap; gap: 8px; }\n .x-ib-new input, .x-ib-new select, .x-ib-new textarea { font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-ib-new input { flex: 1; min-width: 130px; }\n\n .x-ib-filters { display: flex; gap: 4px; margin-bottom: 14px; border-bottom: 1px solid var(--color-border); }\n .x-ib-filter { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 7px 12px; font-size: 12.5px; font-weight: 600; text-transform: capitalize; color: var(--color-text-muted); cursor: pointer; }\n .x-ib-filter.is-active { color: var(--color-text); border-bottom-color: var(--color-brand); }\n\n .x-ib-layout { display: grid; grid-template-columns: 320px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 820px) { .x-ib-layout { grid-template-columns: 1fr; } }\n\n .x-ib-queue { display: flex; flex-direction: column; gap: 6px; max-height: 70vh; overflow-y: auto; }\n .x-ib-ticket { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 10px; background: var(--color-surface, #fff); padding: 10px 12px; cursor: pointer; }\n .x-ib-ticket.is-active { border-color: var(--color-brand); }\n .x-ib-ticket.is-breaching { border-left: 3px solid var(--color-danger, #c0392b); }\n .x-ib-ticket-top { display: flex; gap: 6px; align-items: center; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); margin-bottom: 4px; }\n .x-ib-prio { font-weight: 700; }\n .x-ib-prio-urgent, .x-ib-prio-high { color: var(--color-danger, #c0392b); }\n .x-ib-sla { margin-left: auto; }\n .x-ib-sla.is-bad { color: var(--color-danger, #c0392b); font-weight: 700; }\n .x-ib-ticket-subject { font-size: 13.5px; font-weight: 700; color: var(--color-text); }\n .x-ib-ticket-note { font-size: 12px; color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .x-ib-ticket-meta { font-size: 11px; color: var(--color-text-muted); margin-top: 3px; text-transform: capitalize; }\n\n .x-ib-detail { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; }\n .x-ib-d-title { font-size: 16px; font-weight: 800; color: var(--color-text); }\n .x-ib-d-sub { font-size: 12px; color: var(--color-text-muted); text-transform: capitalize; margin-bottom: 12px; }\n .x-ib-context { display: flex; flex-wrap: wrap; gap: 16px; padding: 10px; background: color-mix(in srgb, var(--color-border) 20%, transparent); border-radius: 8px; margin-bottom: 12px; font-size: 13px; }\n .x-ib-ctx-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; color: var(--color-text-muted); margin: 14px 0 6px; }\n .x-ib-muted { color: var(--color-text-muted); font-size: 12px; }\n\n .x-ib-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }\n .x-ib-controls label { display: flex; flex-direction: column; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); gap: 3px; }\n .x-ib-controls select { font: inherit; padding: 5px 8px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); text-transform: capitalize; }\n\n .x-ib-wa { display: flex; flex-direction: column; gap: 5px; max-height: 240px; overflow-y: auto; padding: 8px; border: 1px solid var(--color-border); border-radius: 8px; }\n .x-ib-wa-row { display: flex; }\n .x-ib-wa-row.is-out { justify-content: flex-end; }\n .x-ib-wa-bubble { max-width: 75%; font-size: 12.5px; padding: 6px 10px; border-radius: 10px; background: color-mix(in srgb, var(--color-border) 30%, transparent); }\n .x-ib-wa-bubble.is-out { background: var(--color-brand); color: #fff; }\n\n .x-ib-macros, .x-ib-resolve-codes { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }\n .x-ib-macro { appearance: none; border: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); border-radius: 999px; padding: 3px 10px; font-size: 11.5px; cursor: pointer; }\n .x-ib-reply, .x-ib-note-add input, .x-ib-new textarea { width: 100%; font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); box-sizing: border-box; }\n .x-ib-reply-actions { display: flex; gap: 10px; align-items: center; margin-top: 6px; }\n\n .x-ib-notes { display: flex; flex-direction: column; gap: 6px; }\n .x-ib-note { font-size: 13px; border-left: 2px solid var(--color-border); padding-left: 8px; }\n .x-ib-note-add { display: flex; gap: 8px; margin-top: 8px; }\n .x-ib-note-add input { flex: 1; }\n\n .x-ib-resolve { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--color-border); }\n .x-ib-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';\nimport { InboxComponent } from './inbox.component';\n\n@NgModule({\n declarations: [InboxComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: InboxComponent }]),\n ],\n})\nexport class InboxModule {}\n"],"names":["i2","i3","i4","i1"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { BaseDirective, using, titleCase } from '@thescaffold/ngx-core';
|
|
2
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
3
|
+
|
|
4
|
+
// R1 production-readiness pass — every admin list page built on
|
|
5
|
+
// `x-webget-collection` (customers, payments, referrals, promotions,
|
|
6
|
+
// coupons, stock, returns, claims, shipments, orders, routes,
|
|
7
|
+
// data-requests, users, …) renders a search box and a refresh icon that do
|
|
8
|
+
// nothing: `CollectionComponent` invokes `data.onSearch`/`data.onRefresh`
|
|
9
|
+
// internally (debounced, confirmed in the compiled
|
|
10
|
+
// `@thescaffold/ngx-ui` bundle), but no page ever supplied them — only
|
|
11
|
+
// `onPage` was ever wired. One shared base fixes all of them at once
|
|
12
|
+
// instead of patching each page's `toCollection` individually.
|
|
13
|
+
//
|
|
14
|
+
// A concrete page extends this, sets `dataSource`/`columns`/`pluralName`
|
|
15
|
+
// in field initializers, and gets `list$`/`init`/`list()` for free — same
|
|
16
|
+
// shape as every page's own hand-rolled version, just de-duplicated.
|
|
17
|
+
class ListPageDirective extends BaseDirective {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
this.page = 1;
|
|
21
|
+
this.perPage = 25;
|
|
22
|
+
this.list$ = new BehaviorSubject(null);
|
|
23
|
+
this.init = () => {
|
|
24
|
+
this.list();
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
list(page = this.page, perPage = this.perPage, query = this.query) {
|
|
28
|
+
this.page = page;
|
|
29
|
+
this.perPage = perPage;
|
|
30
|
+
this.query = query;
|
|
31
|
+
this.dataSource
|
|
32
|
+
.getMany({ page, perPage, ...(query ? { query } : {}) })
|
|
33
|
+
.pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
|
|
34
|
+
.subscribe(using((data) => this.list$.next(data)));
|
|
35
|
+
}
|
|
36
|
+
// Override to transform each row before it reaches the table (e.g. a
|
|
37
|
+
// formatted currency label). Identity by default.
|
|
38
|
+
mapRow(row) {
|
|
39
|
+
return row;
|
|
40
|
+
}
|
|
41
|
+
// Override to add collection-level extras (`links`, `class`, …) beyond
|
|
42
|
+
// the search/refresh/page wiring every page shares.
|
|
43
|
+
extraCollectionFields(_response) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
toCollection(response) {
|
|
47
|
+
const rows = (response?.data ?? []).map((row) => this.mapRow(row));
|
|
48
|
+
return {
|
|
49
|
+
title: titleCase(this.pluralName),
|
|
50
|
+
columns: this.columns,
|
|
51
|
+
rows,
|
|
52
|
+
hasHeaders: true,
|
|
53
|
+
hasTextFilter: true,
|
|
54
|
+
page: response?.meta?.current_page,
|
|
55
|
+
perPage: response?.meta?.per_page,
|
|
56
|
+
total: response?.meta?.total,
|
|
57
|
+
onPage: (page) => this.list(page),
|
|
58
|
+
onSearch: (query) => this.list(1, this.perPage, query),
|
|
59
|
+
onRefresh: () => this.list(this.page, this.perPage, this.query),
|
|
60
|
+
...this.extraCollectionFields(response),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { ListPageDirective as L };
|
|
66
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs","sources":["../../../projects/admin/src/lib/pages/_shared/list-page.base.ts"],"sourcesContent":["import { ApiService, BaseDirective, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, map, takeUntil } from 'rxjs';\n\n// R1 production-readiness pass — every admin list page built on\n// `x-webget-collection` (customers, payments, referrals, promotions,\n// coupons, stock, returns, claims, shipments, orders, routes,\n// data-requests, users, …) renders a search box and a refresh icon that do\n// nothing: `CollectionComponent` invokes `data.onSearch`/`data.onRefresh`\n// internally (debounced, confirmed in the compiled\n// `@thescaffold/ngx-ui` bundle), but no page ever supplied them — only\n// `onPage` was ever wired. One shared base fixes all of them at once\n// instead of patching each page's `toCollection` individually.\n//\n// A concrete page extends this, sets `dataSource`/`columns`/`pluralName`\n// in field initializers, and gets `list$`/`init`/`list()` for free — same\n// shape as every page's own hand-rolled version, just de-duplicated.\nexport abstract class ListPageDirective extends BaseDirective {\n protected abstract dataSource: ApiService;\n protected abstract columns: { key: string; value: string; type?: string }[];\n protected abstract pluralName: string;\n\n page = 1;\n perPage = 25;\n query?: string;\n\n list$ = new BehaviorSubject<any>(null);\n\n override init = () => {\n this.list();\n };\n\n list(page = this.page, perPage = this.perPage, query = this.query): void {\n this.page = page;\n this.perPage = perPage;\n this.query = query;\n this.dataSource\n .getMany({ page, perPage, ...(query ? { query } : {}) })\n .pipe(\n takeUntil(this.$),\n map((response: any) => this.toCollection(response)),\n )\n .subscribe(using((data) => this.list$.next(data)));\n }\n\n // Override to transform each row before it reaches the table (e.g. a\n // formatted currency label). Identity by default.\n protected mapRow(row: any): any {\n return row;\n }\n\n // Override to add collection-level extras (`links`, `class`, …) beyond\n // the search/refresh/page wiring every page shares.\n protected extraCollectionFields(_response: any): Record<string, any> {\n return {};\n }\n\n protected toCollection(response: any) {\n const rows = (response?.data ?? []).map((row: any) => this.mapRow(row));\n return {\n title: titleCase(this.pluralName),\n columns: this.columns,\n rows,\n hasHeaders: true,\n hasTextFilter: true,\n page: response?.meta?.current_page,\n perPage: response?.meta?.per_page,\n total: response?.meta?.total,\n onPage: (page: number) => this.list(page),\n onSearch: (query: string) => this.list(1, this.perPage, query),\n onRefresh: () => this.list(this.page, this.perPage, this.query),\n ...this.extraCollectionFields(response),\n };\n }\n}\n"],"names":[],"mappings":";;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACM,MAAgB,iBAAkB,SAAQ,aAAa,CAAA;AAA7D,IAAA,WAAA,GAAA;;QAKE,IAAA,CAAA,IAAI,GAAG,CAAC;QACR,IAAA,CAAA,OAAO,GAAG,EAAE;AAGZ,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,eAAe,CAAM,IAAI,CAAC;QAE7B,IAAA,CAAA,IAAI,GAAG,MAAK;YACnB,IAAI,CAAC,IAAI,EAAE;AACb,QAAA,CAAC;IA4CH;AA1CE,IAAA,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC,KAAK,EAAA;AAC/D,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC;aACF,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE;aACtD,IAAI,CACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EACjB,GAAG,CAAC,CAAC,QAAa,KAAK,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEpD,aAAA,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD;;;AAIU,IAAA,MAAM,CAAC,GAAQ,EAAA;AACvB,QAAA,OAAO,GAAG;IACZ;;;AAIU,IAAA,qBAAqB,CAAC,SAAc,EAAA;AAC5C,QAAA,OAAO,EAAE;IACX;AAEU,IAAA,YAAY,CAAC,QAAa,EAAA;QAClC,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,GAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvE,OAAO;AACL,YAAA,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI;AACJ,YAAA,UAAU,EAAE,IAAI;AAChB,YAAA,aAAa,EAAE,IAAI;AACnB,YAAA,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY;AAClC,YAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ;AACjC,YAAA,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK;YAC5B,MAAM,EAAE,CAAC,IAAY,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACzC,YAAA,QAAQ,EAAE,CAAC,KAAa,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC;AAC9D,YAAA,SAAS,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;AAC/D,YAAA,GAAG,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC;SACxC;IACH;AACD;;;;"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Component, NgModule } from '@angular/core';
|
|
3
|
-
import * as i1$
|
|
3
|
+
import * as i1$1 from '@angular/router';
|
|
4
4
|
import { RouterModule } from '@angular/router';
|
|
5
5
|
import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
-
import * as
|
|
6
|
+
import * as i2 from '@thescaffold/ngx-ui';
|
|
7
7
|
import { ElementsModule } from '@thescaffold/ngx-ui';
|
|
8
8
|
import { takeUntil, firstValueFrom } from 'rxjs';
|
|
9
9
|
import * as i1 from '@angular/forms';
|
|
@@ -81,7 +81,7 @@ class MacrosComponent extends BaseDirective {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
84
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: MacrosComponent, isStandalone: false, selector: "x-macros", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Canned responses</div>\n <div class=\"x-page-subtitle\">Reusable reply snippets for the support inbox.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-mc-layout\">\n <div class=\"x-mc-list\">\n <form class=\"x-mc-new\" (ngSubmit)=\"create()\">\n <input placeholder=\"New macro title\" [(ngModel)]=\"newTitle\" name=\"newTitle\" />\n <button type=\"submit\" [disabled]=\"!newTitle.trim()\">Add</button>\n </form>\n @for (m of macros; track m.id) {\n <button\n type=\"button\"\n class=\"x-mc-row\"\n [class.is-active]=\"selected?.id === m.id\"\n (click)=\"selected = m\"\n >\n <span class=\"x-mc-row-title\">{{ m.title }}</span>\n @if (m.category) { <span class=\"x-mc-row-cat\">{{ m.category }}</span> }\n @if (!m.enabled) { <span class=\"x-mc-row-off\">off</span> }\n </button>\n } @empty {\n <div class=\"x-mc-empty\">No macros yet.</div>\n }\n </div>\n\n <div class=\"x-mc-editor\">\n @if (!selected) {\n <div class=\"x-mc-empty\">Select a macro.</div>\n } @else {\n <label>Title <input [(ngModel)]=\"selected.title\" name=\"title\" /></label>\n <label>Category <input [(ngModel)]=\"selected.category\" name=\"category\" placeholder=\"e.g. delivery\" /></label>\n <label>Body\n <textarea rows=\"8\" [(ngModel)]=\"selected.body\" name=\"body\"></textarea>\n </label>\n <label class=\"x-mc-check\">\n <input type=\"checkbox\" [(ngModel)]=\"selected.enabled\" name=\"enabled\" /> Enabled\n </label>\n <div class=\"x-mc-actions\">\n <button type=\"button\" (click)=\"save()\">Save</button>\n <button type=\"button\" class=\"x-mc-del\" (click)=\"remove()\">Delete</button>\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { margin-bottom: 20px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mc-layout { display: grid; grid-template-columns: 280px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 760px) { .x-mc-layout { grid-template-columns: 1fr; } }\n .x-mc-new { display: flex; gap: 6px; margin-bottom: 10px; }\n .x-mc-new input { flex: 1; font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-new button, .x-mc-actions button { font: inherit; font-weight: 600; font-size: 12.5px; padding: 7px 12px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); cursor: pointer; }\n .x-mc-list { display: flex; flex-direction: column; gap: 4px; }\n .x-mc-row { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface, #fff); padding: 8px 10px; cursor: pointer; display: flex; gap: 6px; align-items: center; }\n .x-mc-row.is-active { border-color: var(--color-brand); }\n .x-mc-row-title { font-size: 13px; font-weight: 600; color: var(--color-text); }\n .x-mc-row-cat { font-size: 10.5px; color: var(--color-text-muted); text-transform: uppercase; }\n .x-mc-row-off { font-size: 10.5px; color: var(--color-danger, #c0392b); margin-left: auto; }\n .x-mc-editor { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }\n .x-mc-editor label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); }\n .x-mc-editor input:not([type=checkbox]), .x-mc-editor textarea { font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-check { flex-direction: row !important; align-items: center; gap: 6px; text-transform: none; }\n .x-mc-actions { display: flex; gap: 8px; }\n .x-mc-del { color: var(--color-danger, #c0392b); }\n .x-mc-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n", styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-mc-layout{display:grid;grid-template-columns:280px 1fr;gap:16px;align-items:start}@media(max-width:760px){.x-mc-layout{grid-template-columns:1fr}}.x-mc-new{display:flex;gap:6px;margin-bottom:10px}.x-mc-new input{flex:1;font:inherit;padding:7px 10px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text)}.x-mc-new button,.x-mc-actions button{font:inherit;font-weight:600;font-size:12.5px;padding:7px 12px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text);cursor:pointer}.x-mc-list{display:flex;flex-direction:column;gap:4px}.x-mc-row{text-align:left;appearance:none;border:1px solid var(--color-border);border-radius:8px;background:var(--color-surface, #fff);padding:8px 10px;cursor:pointer;display:flex;gap:6px;align-items:center}.x-mc-row.is-active{border-color:var(--color-brand)}.x-mc-row-title{font-size:13px;font-weight:600;color:var(--color-text)}.x-mc-row-cat{font-size:10.5px;color:var(--color-text-muted);text-transform:uppercase}.x-mc-row-off{font-size:10.5px;color:var(--color-danger, #c0392b);margin-left:auto}.x-mc-editor{border:1px solid var(--color-border);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:10px}.x-mc-editor label{display:flex;flex-direction:column;gap:4px;font-size:10.5px;text-transform:uppercase;letter-spacing:.03em;color:var(--color-text-muted)}.x-mc-editor input:not([type=checkbox]),.x-mc-editor textarea{font:inherit;padding:8px 10px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text)}.x-mc-check{flex-direction:row!important;align-items:center;gap:6px;text-transform:none}.x-mc-actions{display:flex;gap:8px}.x-mc-del{color:var(--color-danger, #c0392b)}.x-mc-empty{padding:24px;text-align:center;font-size:13px;color:var(--color-text-muted)}\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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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.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: "component", type:
|
|
84
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: MacrosComponent, isStandalone: false, selector: "x-macros", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Canned responses</div>\n <div class=\"x-page-subtitle\">Reusable reply snippets for the support inbox.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-mc-layout\">\n <div class=\"x-mc-list\">\n <form class=\"x-mc-new\" (ngSubmit)=\"create()\">\n <input placeholder=\"New macro title\" [(ngModel)]=\"newTitle\" name=\"newTitle\" />\n <button type=\"submit\" [disabled]=\"!newTitle.trim()\">Add</button>\n </form>\n @for (m of macros; track m.id) {\n <button\n type=\"button\"\n class=\"x-mc-row\"\n [class.is-active]=\"selected?.id === m.id\"\n (click)=\"selected = m\"\n >\n <span class=\"x-mc-row-title\">{{ m.title }}</span>\n @if (m.category) { <span class=\"x-mc-row-cat\">{{ m.category }}</span> }\n @if (!m.enabled) { <span class=\"x-mc-row-off\">off</span> }\n </button>\n } @empty {\n <div class=\"x-mc-empty\">No macros yet.</div>\n }\n </div>\n\n <div class=\"x-mc-editor\">\n @if (!selected) {\n <div class=\"x-mc-empty\">Select a macro.</div>\n } @else {\n <label>Title <input [(ngModel)]=\"selected.title\" name=\"title\" /></label>\n <label>Category <input [(ngModel)]=\"selected.category\" name=\"category\" placeholder=\"e.g. delivery\" /></label>\n <label>Body\n <textarea rows=\"8\" [(ngModel)]=\"selected.body\" name=\"body\"></textarea>\n </label>\n <label class=\"x-mc-check\">\n <input type=\"checkbox\" [(ngModel)]=\"selected.enabled\" name=\"enabled\" /> Enabled\n </label>\n <div class=\"x-mc-actions\">\n <button type=\"button\" (click)=\"save()\">Save</button>\n <button type=\"button\" class=\"x-mc-del\" (click)=\"remove()\">Delete</button>\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { margin-bottom: 20px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mc-layout { display: grid; grid-template-columns: 280px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 760px) { .x-mc-layout { grid-template-columns: 1fr; } }\n .x-mc-new { display: flex; gap: 6px; margin-bottom: 10px; }\n .x-mc-new input { flex: 1; font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-new button, .x-mc-actions button { font: inherit; font-weight: 600; font-size: 12.5px; padding: 7px 12px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); cursor: pointer; }\n .x-mc-list { display: flex; flex-direction: column; gap: 4px; }\n .x-mc-row { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface, #fff); padding: 8px 10px; cursor: pointer; display: flex; gap: 6px; align-items: center; }\n .x-mc-row.is-active { border-color: var(--color-brand); }\n .x-mc-row-title { font-size: 13px; font-weight: 600; color: var(--color-text); }\n .x-mc-row-cat { font-size: 10.5px; color: var(--color-text-muted); text-transform: uppercase; }\n .x-mc-row-off { font-size: 10.5px; color: var(--color-danger, #c0392b); margin-left: auto; }\n .x-mc-editor { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }\n .x-mc-editor label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); }\n .x-mc-editor input:not([type=checkbox]), .x-mc-editor textarea { font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-check { flex-direction: row !important; align-items: center; gap: 6px; text-transform: none; }\n .x-mc-actions { display: flex; gap: 8px; }\n .x-mc-del { color: var(--color-danger, #c0392b); }\n .x-mc-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n", styles: [".x-page-head{margin-bottom:20px}.x-page-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-page-subtitle{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-mc-layout{display:grid;grid-template-columns:280px 1fr;gap:16px;align-items:start}@media(max-width:760px){.x-mc-layout{grid-template-columns:1fr}}.x-mc-new{display:flex;gap:6px;margin-bottom:10px}.x-mc-new input{flex:1;font:inherit;padding:7px 10px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text)}.x-mc-new button,.x-mc-actions button{font:inherit;font-weight:600;font-size:12.5px;padding:7px 12px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text);cursor:pointer}.x-mc-list{display:flex;flex-direction:column;gap:4px}.x-mc-row{text-align:left;appearance:none;border:1px solid var(--color-border);border-radius:8px;background:var(--color-surface, #fff);padding:8px 10px;cursor:pointer;display:flex;gap:6px;align-items:center}.x-mc-row.is-active{border-color:var(--color-brand)}.x-mc-row-title{font-size:13px;font-weight:600;color:var(--color-text)}.x-mc-row-cat{font-size:10.5px;color:var(--color-text-muted);text-transform:uppercase}.x-mc-row-off{font-size:10.5px;color:var(--color-danger, #c0392b);margin-left:auto}.x-mc-editor{border:1px solid var(--color-border);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:10px}.x-mc-editor label{display:flex;flex-direction:column;gap:4px;font-size:10.5px;text-transform:uppercase;letter-spacing:.03em;color:var(--color-text-muted)}.x-mc-editor input:not([type=checkbox]),.x-mc-editor textarea{font:inherit;padding:8px 10px;border:1px solid var(--color-border);border-radius:6px;background:var(--color-surface, #fff);color:var(--color-text)}.x-mc-check{flex-direction:row!important;align-items:center;gap:6px;text-transform:none}.x-mc-actions{display:flex;gap:8px}.x-mc-del{color:var(--color-danger, #c0392b)}.x-mc-empty{padding:24px;text-align:center;font-size:13px;color:var(--color-text-muted)}\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.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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.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: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }] }); }
|
|
85
85
|
}
|
|
86
86
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosComponent, decorators: [{
|
|
87
87
|
type: Component,
|
|
@@ -91,7 +91,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
91
91
|
class MacrosModule {
|
|
92
92
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
93
93
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, declarations: [MacrosComponent], imports: [SharedModule,
|
|
94
|
-
ElementsModule, i1$
|
|
94
|
+
ElementsModule, i1$1.RouterModule] }); }
|
|
95
95
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, imports: [SharedModule,
|
|
96
96
|
ElementsModule,
|
|
97
97
|
RouterModule.forChild([{ path: '', component: MacrosComponent }])] }); }
|
|
@@ -109,4 +109,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
109
109
|
}] });
|
|
110
110
|
|
|
111
111
|
export { MacrosModule };
|
|
112
|
-
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-macros.module-
|
|
112
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs","sources":["../../../projects/admin/src/lib/pages/macros/macros.component.ts","../../../projects/admin/src/lib/pages/macros/macros.component.html","../../../projects/admin/src/lib/pages/macros/macros.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface MacroVm {\n id: string;\n title: string;\n category?: string;\n body: string;\n enabled: boolean;\n}\n\n// P7.5, SUP-03 — the canned-response library the support inbox draws\n// from. List + inline editor. ops CRUD is covered by\n// `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-macros',\n templateUrl: './macros.component.html',\n})\nexport class MacrosComponent extends BaseDirective {\n private readonly source = this.apiService.on('apps/commerce/support-macro');\n\n loading = true;\n macros: MacroVm[] = [];\n selected?: MacroVm;\n newTitle = '';\n\n override init = () => {\n this.load();\n };\n\n load(): void {\n this.loading = true;\n this.source\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.macros = (res?.data ?? []).sort((a: MacroVm, b: MacroVm) =>\n `${a.category}${a.title}`.localeCompare(`${b.category}${b.title}`),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.macros.find((m) => m.id === this.selected!.id);\n }\n }),\n );\n }\n\n async create(): Promise<void> {\n const title = this.newTitle.trim();\n if (!title) return;\n try {\n const res: any = await firstValueFrom(\n this.source.create({ title, body: '' } as any),\n );\n this.newTitle = '';\n this.load();\n if (res?.data?.id) setTimeout(() => (this.selected = { ...res.data }), 150);\n } catch {\n notify('Could not create the macro.', undefined, 'error');\n }\n }\n\n async save(): Promise<void> {\n if (!this.selected) return;\n const m = this.selected;\n try {\n await firstValueFrom(\n this.source.update(m.id, {\n title: m.title,\n category: m.category || undefined,\n body: m.body,\n enabled: m.enabled,\n } as any),\n );\n notify('Macro saved.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not save the macro.', undefined, 'error');\n }\n }\n\n async remove(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.source.remove(this.selected.id));\n this.selected = undefined;\n this.load();\n } catch {\n notify('Could not delete the macro.', undefined, 'error');\n }\n }\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">Canned responses</div>\n <div class=\"x-page-subtitle\">Reusable reply snippets for the support inbox.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-mc-layout\">\n <div class=\"x-mc-list\">\n <form class=\"x-mc-new\" (ngSubmit)=\"create()\">\n <input placeholder=\"New macro title\" [(ngModel)]=\"newTitle\" name=\"newTitle\" />\n <button type=\"submit\" [disabled]=\"!newTitle.trim()\">Add</button>\n </form>\n @for (m of macros; track m.id) {\n <button\n type=\"button\"\n class=\"x-mc-row\"\n [class.is-active]=\"selected?.id === m.id\"\n (click)=\"selected = m\"\n >\n <span class=\"x-mc-row-title\">{{ m.title }}</span>\n @if (m.category) { <span class=\"x-mc-row-cat\">{{ m.category }}</span> }\n @if (!m.enabled) { <span class=\"x-mc-row-off\">off</span> }\n </button>\n } @empty {\n <div class=\"x-mc-empty\">No macros yet.</div>\n }\n </div>\n\n <div class=\"x-mc-editor\">\n @if (!selected) {\n <div class=\"x-mc-empty\">Select a macro.</div>\n } @else {\n <label>Title <input [(ngModel)]=\"selected.title\" name=\"title\" /></label>\n <label>Category <input [(ngModel)]=\"selected.category\" name=\"category\" placeholder=\"e.g. delivery\" /></label>\n <label>Body\n <textarea rows=\"8\" [(ngModel)]=\"selected.body\" name=\"body\"></textarea>\n </label>\n <label class=\"x-mc-check\">\n <input type=\"checkbox\" [(ngModel)]=\"selected.enabled\" name=\"enabled\" /> Enabled\n </label>\n <div class=\"x-mc-actions\">\n <button type=\"button\" (click)=\"save()\">Save</button>\n <button type=\"button\" class=\"x-mc-del\" (click)=\"remove()\">Delete</button>\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { margin-bottom: 20px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mc-layout { display: grid; grid-template-columns: 280px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 760px) { .x-mc-layout { grid-template-columns: 1fr; } }\n .x-mc-new { display: flex; gap: 6px; margin-bottom: 10px; }\n .x-mc-new input { flex: 1; font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-new button, .x-mc-actions button { font: inherit; font-weight: 600; font-size: 12.5px; padding: 7px 12px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); cursor: pointer; }\n .x-mc-list { display: flex; flex-direction: column; gap: 4px; }\n .x-mc-row { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface, #fff); padding: 8px 10px; cursor: pointer; display: flex; gap: 6px; align-items: center; }\n .x-mc-row.is-active { border-color: var(--color-brand); }\n .x-mc-row-title { font-size: 13px; font-weight: 600; color: var(--color-text); }\n .x-mc-row-cat { font-size: 10.5px; color: var(--color-text-muted); text-transform: uppercase; }\n .x-mc-row-off { font-size: 10.5px; color: var(--color-danger, #c0392b); margin-left: auto; }\n .x-mc-editor { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }\n .x-mc-editor label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); }\n .x-mc-editor input:not([type=checkbox]), .x-mc-editor textarea { font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-check { flex-direction: row !important; align-items: center; gap: 6px; text-transform: none; }\n .x-mc-actions { display: flex; gap: 8px; }\n .x-mc-del { color: var(--color-danger, #c0392b); }\n .x-mc-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { MacrosComponent } from './macros.component';\n\n@NgModule({\n declarations: [MacrosComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: MacrosComponent }]),\n ],\n})\nexport class MacrosModule {}\n"],"names":["i2","i1"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs","sources":["../../../projects/admin/src/lib/pages/macros/macros.component.ts","../../../projects/admin/src/lib/pages/macros/macros.component.html","../../../projects/admin/src/lib/pages/macros/macros.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { firstValueFrom, takeUntil } from 'rxjs';\n\ninterface MacroVm {\n id: string;\n title: string;\n category?: string;\n body: string;\n enabled: boolean;\n}\n\n// P7.5, SUP-03 — the canned-response library the support inbox draws\n// from. List + inline editor. ops CRUD is covered by\n// `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-macros',\n templateUrl: './macros.component.html',\n})\nexport class MacrosComponent extends BaseDirective {\n private readonly source = this.apiService.on('apps/commerce/support-macro');\n\n loading = true;\n macros: MacroVm[] = [];\n selected?: MacroVm;\n newTitle = '';\n\n override init = () => {\n this.load();\n };\n\n load(): void {\n this.loading = true;\n this.source\n .getMany({ perPage: 200 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.macros = (res?.data ?? []).sort((a: MacroVm, b: MacroVm) =>\n `${a.category}${a.title}`.localeCompare(`${b.category}${b.title}`),\n );\n this.loading = false;\n if (this.selected) {\n this.selected = this.macros.find((m) => m.id === this.selected!.id);\n }\n }),\n );\n }\n\n async create(): Promise<void> {\n const title = this.newTitle.trim();\n if (!title) return;\n try {\n const res: any = await firstValueFrom(\n this.source.create({ title, body: '' } as any),\n );\n this.newTitle = '';\n this.load();\n if (res?.data?.id) setTimeout(() => (this.selected = { ...res.data }), 150);\n } catch {\n notify('Could not create the macro.', undefined, 'error');\n }\n }\n\n async save(): Promise<void> {\n if (!this.selected) return;\n const m = this.selected;\n try {\n await firstValueFrom(\n this.source.update(m.id, {\n title: m.title,\n category: m.category || undefined,\n body: m.body,\n enabled: m.enabled,\n } as any),\n );\n notify('Macro saved.', undefined, 'success');\n this.load();\n } catch {\n notify('Could not save the macro.', undefined, 'error');\n }\n }\n\n async remove(): Promise<void> {\n if (!this.selected) return;\n try {\n await firstValueFrom(this.source.remove(this.selected.id));\n this.selected = undefined;\n this.load();\n } catch {\n notify('Could not delete the macro.', undefined, 'error');\n }\n }\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">Canned responses</div>\n <div class=\"x-page-subtitle\">Reusable reply snippets for the support inbox.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else {\n <div class=\"x-mc-layout\">\n <div class=\"x-mc-list\">\n <form class=\"x-mc-new\" (ngSubmit)=\"create()\">\n <input placeholder=\"New macro title\" [(ngModel)]=\"newTitle\" name=\"newTitle\" />\n <button type=\"submit\" [disabled]=\"!newTitle.trim()\">Add</button>\n </form>\n @for (m of macros; track m.id) {\n <button\n type=\"button\"\n class=\"x-mc-row\"\n [class.is-active]=\"selected?.id === m.id\"\n (click)=\"selected = m\"\n >\n <span class=\"x-mc-row-title\">{{ m.title }}</span>\n @if (m.category) { <span class=\"x-mc-row-cat\">{{ m.category }}</span> }\n @if (!m.enabled) { <span class=\"x-mc-row-off\">off</span> }\n </button>\n } @empty {\n <div class=\"x-mc-empty\">No macros yet.</div>\n }\n </div>\n\n <div class=\"x-mc-editor\">\n @if (!selected) {\n <div class=\"x-mc-empty\">Select a macro.</div>\n } @else {\n <label>Title <input [(ngModel)]=\"selected.title\" name=\"title\" /></label>\n <label>Category <input [(ngModel)]=\"selected.category\" name=\"category\" placeholder=\"e.g. delivery\" /></label>\n <label>Body\n <textarea rows=\"8\" [(ngModel)]=\"selected.body\" name=\"body\"></textarea>\n </label>\n <label class=\"x-mc-check\">\n <input type=\"checkbox\" [(ngModel)]=\"selected.enabled\" name=\"enabled\" /> Enabled\n </label>\n <div class=\"x-mc-actions\">\n <button type=\"button\" (click)=\"save()\">Save</button>\n <button type=\"button\" class=\"x-mc-del\" (click)=\"remove()\">Delete</button>\n </div>\n }\n </div>\n </div>\n}\n\n<style>\n .x-page-head { margin-bottom: 20px; }\n .x-page-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-page-subtitle { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mc-layout { display: grid; grid-template-columns: 280px 1fr; gap: 16px; align-items: start; }\n @media (max-width: 760px) { .x-mc-layout { grid-template-columns: 1fr; } }\n .x-mc-new { display: flex; gap: 6px; margin-bottom: 10px; }\n .x-mc-new input { flex: 1; font: inherit; padding: 7px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-new button, .x-mc-actions button { font: inherit; font-weight: 600; font-size: 12.5px; padding: 7px 12px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); cursor: pointer; }\n .x-mc-list { display: flex; flex-direction: column; gap: 4px; }\n .x-mc-row { text-align: left; appearance: none; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface, #fff); padding: 8px 10px; cursor: pointer; display: flex; gap: 6px; align-items: center; }\n .x-mc-row.is-active { border-color: var(--color-brand); }\n .x-mc-row-title { font-size: 13px; font-weight: 600; color: var(--color-text); }\n .x-mc-row-cat { font-size: 10.5px; color: var(--color-text-muted); text-transform: uppercase; }\n .x-mc-row-off { font-size: 10.5px; color: var(--color-danger, #c0392b); margin-left: auto; }\n .x-mc-editor { border: 1px solid var(--color-border); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; }\n .x-mc-editor label { display: flex; flex-direction: column; gap: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); }\n .x-mc-editor input:not([type=checkbox]), .x-mc-editor textarea { font: inherit; padding: 8px 10px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface, #fff); color: var(--color-text); }\n .x-mc-check { flex-direction: row !important; align-items: center; gap: 6px; text-transform: none; }\n .x-mc-actions { display: flex; gap: 8px; }\n .x-mc-del { color: var(--color-danger, #c0392b); }\n .x-mc-empty { padding: 24px; text-align: center; font-size: 13px; color: var(--color-text-muted); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { MacrosComponent } from './macros.component';\n\n@NgModule({\n declarations: [MacrosComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: MacrosComponent }]),\n ],\n})\nexport class MacrosModule {}\n"],"names":["i1"],"mappings":";;;;;;;;;;AAYA;AACA;AACA;AAMM,MAAO,eAAgB,SAAQ,aAAa,CAAA;AALlD,IAAA,WAAA,GAAA;;QAMmB,IAAA,CAAA,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,6BAA6B,CAAC;QAE3E,IAAA,CAAA,OAAO,GAAG,IAAI;QACd,IAAA,CAAA,MAAM,GAAc,EAAE;QAEtB,IAAA,CAAA,QAAQ,GAAG,EAAE;QAEJ,IAAA,CAAA,IAAI,GAAG,MAAK;YACnB,IAAI,CAAC,IAAI,EAAE;AACb,QAAA,CAAC;AAgEF,IAAA;IA9DC,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AACnB,QAAA,IAAI,CAAC;AACF,aAAA,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,EAAS;AAC/B,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,aAAA,SAAS,CACR,KAAK,CAAC,CAAC,GAAQ,KAAI;AACjB,YAAA,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,CAAU,EAAE,CAAU,KAC1D,CAAA,EAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAA,CAAE,CAAC,aAAa,CAAC,CAAA,EAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAA,CAAE,CAAC,CACnE;AACD,YAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACpB,YAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,QAAS,CAAC,EAAE,CAAC;YACrE;QACF,CAAC,CAAC,CACH;IACL;AAEA,IAAA,MAAM,MAAM,GAAA;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;AAClC,QAAA,IAAI,CAAC,KAAK;YAAE;AACZ,QAAA,IAAI;YACF,MAAM,GAAG,GAAQ,MAAM,cAAc,CACnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAS,CAAC,CAC/C;AACD,YAAA,IAAI,CAAC,QAAQ,GAAG,EAAE;YAClB,IAAI,CAAC,IAAI,EAAE;AACX,YAAA,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE;AAAE,gBAAA,UAAU,CAAC,OAAO,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC;QAC7E;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,CAAC,6BAA6B,EAAE,SAAS,EAAE,OAAO,CAAC;QAC3D;IACF;AAEA,IAAA,MAAM,IAAI,GAAA;QACR,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;AACpB,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ;AACvB,QAAA,IAAI;YACF,MAAM,cAAc,CAClB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;gBACvB,KAAK,EAAE,CAAC,CAAC,KAAK;AACd,gBAAA,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,SAAS;gBACjC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;AACZ,aAAA,CAAC,CACV;AACD,YAAA,MAAM,CAAC,cAAc,EAAE,SAAS,EAAE,SAAS,CAAC;YAC5C,IAAI,CAAC,IAAI,EAAE;QACb;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,CAAC,2BAA2B,EAAE,SAAS,EAAE,OAAO,CAAC;QACzD;IACF;AAEA,IAAA,MAAM,MAAM,GAAA;QACV,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;AACpB,QAAA,IAAI;AACF,YAAA,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC1D,YAAA,IAAI,CAAC,QAAQ,GAAG,SAAS;YACzB,IAAI,CAAC,IAAI,EAAE;QACb;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,CAAC,6BAA6B,EAAE,SAAS,EAAE,OAAO,CAAC;QAC3D;IACF;+GAzEW,eAAe,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAf,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,eAAe,4FCpB5B,qzIA0EA,EAAA,MAAA,EAAA,CAAA,qiEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,yEAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FDtDa,eAAe,EAAA,UAAA,EAAA,CAAA;kBAL3B,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,UAAA,EAAA,KAAK,YACP,UAAU,EAAA,QAAA,EAAA,qzIAAA,EAAA;;;MEHT,YAAY,CAAA;+GAAZ,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;gHAAZ,YAAY,EAAA,YAAA,EAAA,CAPR,eAAe,CAAA,EAAA,OAAA,EAAA,CAE5B,YAAY;YACZ,cAAc,EAAAA,IAAA,CAAA,YAAA,CAAA,EAAA,CAAA,CAAA;AAIL,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,YAAY,YALrB,YAAY;YACZ,cAAc;AACd,YAAA,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC,CAAA,EAAA,CAAA,CAAA;;4FAGxD,YAAY,EAAA,UAAA,EAAA,CAAA;kBARxB,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,YAAY,EAAE,CAAC,eAAe,CAAC;AAC/B,oBAAA,OAAO,EAAE;wBACP,YAAY;wBACZ,cAAc;AACd,wBAAA,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;AAClE,qBAAA;AACF,iBAAA;;;;;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Component, NgModule } from '@angular/core';
|
|
3
|
-
import * as i1
|
|
3
|
+
import * as i1 from '@angular/router';
|
|
4
4
|
import { RouterModule } from '@angular/router';
|
|
5
5
|
import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
-
import * as
|
|
6
|
+
import * as i2 from '@thescaffold/ngx-ui';
|
|
7
7
|
import { ElementsModule } from '@thescaffold/ngx-ui';
|
|
8
8
|
import { forkJoin, catchError, of, takeUntil, firstValueFrom } from 'rxjs';
|
|
9
|
-
import * as
|
|
9
|
+
import * as i3 from '@angular/common';
|
|
10
10
|
|
|
11
11
|
// P5.11, UGC-04 — the UGC moderation queue. Everything `pending` across
|
|
12
12
|
// reviews, questions and answers, with publish / reject / hide.
|
|
@@ -85,7 +85,7 @@ class ModerationComponent extends BaseDirective {
|
|
|
85
85
|
return Number.isNaN(t) ? 0 : t;
|
|
86
86
|
}
|
|
87
87
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
88
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ModerationComponent, isStandalone: false, selector: "x-moderation", usesInheritance: true, ngImport: i0, template: "<div class=\"x-mod-head\">\n <div class=\"x-mod-title\">Moderation</div>\n <div class=\"x-mod-sub\">Reviews, questions and answers awaiting a decision.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!items.length) {\n <div class=\"x-mod-empty\">Nothing waiting. Nice.</div>\n} @else {\n <div class=\"x-mod-list\">\n @for (item of items; track item.id) {\n <div class=\"x-mod-item\">\n <div class=\"x-mod-meta\">\n <span class=\"x-mod-kind\">{{ item.kind }}</span>\n <span class=\"x-mod-secondary\">{{ item.secondary }}</span>\n <span class=\"x-mod-date\">{{ item.createdAt | date: 'short' }}</span>\n </div>\n <div class=\"x-mod-body\">{{ item.primary }}</div>\n <div class=\"x-mod-actions\">\n <button type=\"button\" class=\"x-mod-btn x-mod-ok\" (click)=\"moderate(item, 'published')\">\n Publish\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'rejected')\">\n Reject\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'hidden')\">\n Hide\n </button>\n </div>\n </div>\n }\n </div>\n}\n\n<style>\n .x-mod-head { margin-bottom: 20px; }\n .x-mod-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-mod-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mod-empty { font-size: 14px; color: var(--color-text-muted); }\n .x-mod-list { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }\n .x-mod-item {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: 16px;\n }\n .x-mod-meta {\n display: flex; gap: 10px; align-items: center;\n font-size: 11.5px; color: var(--color-text-muted); margin-bottom: 8px;\n }\n .x-mod-kind {\n font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px;\n color: var(--color-accent-hover);\n }\n .x-mod-body { font-size: 14px; color: var(--color-text); margin-bottom: 12px; }\n .x-mod-actions { display: flex; gap: 8px; }\n .x-mod-btn {\n border: 1px solid var(--color-border);\n background: transparent;\n border-radius: var(--radius-md);\n padding: 6px 14px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n color: var(--color-text-muted);\n }\n .x-mod-ok { border-color: var(--color-accent); color: var(--color-accent-hover); }\n</style>\n", styles: [".x-mod-head{margin-bottom:20px}.x-mod-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-mod-sub{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-mod-empty{font-size:14px;color:var(--color-text-muted)}.x-mod-list{display:flex;flex-direction:column;gap:12px;max-width:720px}.x-mod-item{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px}.x-mod-meta{display:flex;gap:10px;align-items:center;font-size:11.5px;color:var(--color-text-muted);margin-bottom:8px}.x-mod-kind{font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-accent-hover)}.x-mod-body{font-size:14px;color:var(--color-text);margin-bottom:12px}.x-mod-actions{display:flex;gap:8px}.x-mod-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-mod-ok{border-color:var(--color-accent);color:var(--color-accent-hover)}\n"], dependencies: [{ kind: "component", type:
|
|
88
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ModerationComponent, isStandalone: false, selector: "x-moderation", usesInheritance: true, ngImport: i0, template: "<div class=\"x-mod-head\">\n <div class=\"x-mod-title\">Moderation</div>\n <div class=\"x-mod-sub\">Reviews, questions and answers awaiting a decision.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!items.length) {\n <div class=\"x-mod-empty\">Nothing waiting. Nice.</div>\n} @else {\n <div class=\"x-mod-list\">\n @for (item of items; track item.id) {\n <div class=\"x-mod-item\">\n <div class=\"x-mod-meta\">\n <span class=\"x-mod-kind\">{{ item.kind }}</span>\n <span class=\"x-mod-secondary\">{{ item.secondary }}</span>\n <span class=\"x-mod-date\">{{ item.createdAt | date: 'short' }}</span>\n </div>\n <div class=\"x-mod-body\">{{ item.primary }}</div>\n <div class=\"x-mod-actions\">\n <button type=\"button\" class=\"x-mod-btn x-mod-ok\" (click)=\"moderate(item, 'published')\">\n Publish\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'rejected')\">\n Reject\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'hidden')\">\n Hide\n </button>\n </div>\n </div>\n }\n </div>\n}\n\n<style>\n .x-mod-head { margin-bottom: 20px; }\n .x-mod-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-mod-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mod-empty { font-size: 14px; color: var(--color-text-muted); }\n .x-mod-list { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }\n .x-mod-item {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: 16px;\n }\n .x-mod-meta {\n display: flex; gap: 10px; align-items: center;\n font-size: 11.5px; color: var(--color-text-muted); margin-bottom: 8px;\n }\n .x-mod-kind {\n font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px;\n color: var(--color-accent-hover);\n }\n .x-mod-body { font-size: 14px; color: var(--color-text); margin-bottom: 12px; }\n .x-mod-actions { display: flex; gap: 8px; }\n .x-mod-btn {\n border: 1px solid var(--color-border);\n background: transparent;\n border-radius: var(--radius-md);\n padding: 6px 14px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n color: var(--color-text-muted);\n }\n .x-mod-ok { border-color: var(--color-accent); color: var(--color-accent-hover); }\n</style>\n", styles: [".x-mod-head{margin-bottom:20px}.x-mod-title{font-size:24px;font-weight:800;color:var(--color-text)}.x-mod-sub{font-size:13.5px;color:var(--color-text-muted);margin-top:2px}.x-mod-empty{font-size:14px;color:var(--color-text-muted)}.x-mod-list{display:flex;flex-direction:column;gap:12px;max-width:720px}.x-mod-item{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px}.x-mod-meta{display:flex;gap:10px;align-items:center;font-size:11.5px;color:var(--color-text-muted);margin-bottom:8px}.x-mod-kind{font-weight:800;text-transform:uppercase;letter-spacing:.4px;color:var(--color-accent-hover)}.x-mod-body{font-size:14px;color:var(--color-text);margin-bottom:12px}.x-mod-actions{display:flex;gap:8px}.x-mod-btn{border:1px solid var(--color-border);background:transparent;border-radius:var(--radius-md);padding:6px 14px;font-size:12.5px;font-weight:700;cursor:pointer;color:var(--color-text-muted)}.x-mod-ok{border-color:var(--color-accent);color:var(--color-accent-hover)}\n"], dependencies: [{ kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "pipe", type: i3.DatePipe, name: "date" }] }); }
|
|
89
89
|
}
|
|
90
90
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationComponent, decorators: [{
|
|
91
91
|
type: Component,
|
|
@@ -95,7 +95,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
95
95
|
class ModerationModule {
|
|
96
96
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
97
97
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, declarations: [ModerationComponent], imports: [SharedModule,
|
|
98
|
-
ElementsModule, i1
|
|
98
|
+
ElementsModule, i1.RouterModule] }); }
|
|
99
99
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, imports: [SharedModule,
|
|
100
100
|
ElementsModule,
|
|
101
101
|
RouterModule.forChild([{ path: '', component: ModerationComponent }])] }); }
|
|
@@ -113,4 +113,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
|
|
|
113
113
|
}] });
|
|
114
114
|
|
|
115
115
|
export { ModerationModule };
|
|
116
|
-
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-moderation.module-
|
|
116
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs","sources":["../../../projects/admin/src/lib/pages/moderation/moderation.component.ts","../../../projects/admin/src/lib/pages/moderation/moderation.component.html","../../../projects/admin/src/lib/pages/moderation/moderation.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, forkJoin, of, takeUntil } from 'rxjs';\n\ninterface ModItem {\n kind: 'review' | 'question' | 'answer';\n id: string;\n primary: string;\n secondary: string;\n rating?: number;\n createdAt?: string;\n}\n\n// P5.11, UGC-04 — the UGC moderation queue. Everything `pending` across\n// reviews, questions and answers, with publish / reject / hide.\n@Component({\n standalone: false,\n selector: 'x-moderation',\n templateUrl: './moderation.component.html',\n})\nexport class ModerationComponent extends BaseDirective {\n loading = true;\n items: ModItem[] = [];\n\n override init = () => {\n this.load();\n };\n\n load(): void {\n this.loading = true;\n forkJoin({\n reviews: this.apiService\n .on('apps/commerce/review')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n questions: this.apiService\n .on('apps/commerce/question')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n answers: this.apiService\n .on('apps/commerce/answer')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const items: ModItem[] = [];\n for (const r of res?.reviews?.data ?? []) {\n items.push({\n kind: 'review',\n id: r.id,\n primary: r.title || r.body || `${r.rating}★ review`,\n secondary: `${r.rating}★ · ${r.isVerifiedPurchase ? 'verified' : 'unverified'}`,\n rating: r.rating,\n createdAt: r.createdAt,\n });\n }\n for (const q of res?.questions?.data ?? []) {\n items.push({\n kind: 'question',\n id: q.id,\n primary: q.body,\n secondary: 'question',\n createdAt: q.createdAt,\n });\n }\n for (const a of res?.answers?.data ?? []) {\n items.push({\n kind: 'answer',\n id: a.id,\n primary: a.body,\n secondary: a.isOfficial ? 'official answer' : 'answer',\n createdAt: a.createdAt,\n });\n }\n this.items = items.sort(\n (x, y) => this.ts(x.createdAt) - this.ts(y.createdAt),\n );\n this.loading = false;\n }),\n );\n }\n\n async moderate(item: ModItem, status: 'published' | 'rejected' | 'hidden'): Promise<void> {\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/${item.kind}/${item.id}/moderate`,\n { status },\n ),\n );\n this.items = this.items.filter((i) => i.id !== item.id);\n notify(`${item.kind} ${status}`, undefined, 'success');\n } catch {\n notify('Could not update that item.', undefined, 'error');\n }\n }\n\n private ts(v?: string): number {\n const t = v ? Date.parse(v) : NaN;\n return Number.isNaN(t) ? 0 : t;\n }\n}\n","<div class=\"x-mod-head\">\n <div class=\"x-mod-title\">Moderation</div>\n <div class=\"x-mod-sub\">Reviews, questions and answers awaiting a decision.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!items.length) {\n <div class=\"x-mod-empty\">Nothing waiting. Nice.</div>\n} @else {\n <div class=\"x-mod-list\">\n @for (item of items; track item.id) {\n <div class=\"x-mod-item\">\n <div class=\"x-mod-meta\">\n <span class=\"x-mod-kind\">{{ item.kind }}</span>\n <span class=\"x-mod-secondary\">{{ item.secondary }}</span>\n <span class=\"x-mod-date\">{{ item.createdAt | date: 'short' }}</span>\n </div>\n <div class=\"x-mod-body\">{{ item.primary }}</div>\n <div class=\"x-mod-actions\">\n <button type=\"button\" class=\"x-mod-btn x-mod-ok\" (click)=\"moderate(item, 'published')\">\n Publish\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'rejected')\">\n Reject\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'hidden')\">\n Hide\n </button>\n </div>\n </div>\n }\n </div>\n}\n\n<style>\n .x-mod-head { margin-bottom: 20px; }\n .x-mod-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-mod-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mod-empty { font-size: 14px; color: var(--color-text-muted); }\n .x-mod-list { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }\n .x-mod-item {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: 16px;\n }\n .x-mod-meta {\n display: flex; gap: 10px; align-items: center;\n font-size: 11.5px; color: var(--color-text-muted); margin-bottom: 8px;\n }\n .x-mod-kind {\n font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px;\n color: var(--color-accent-hover);\n }\n .x-mod-body { font-size: 14px; color: var(--color-text); margin-bottom: 12px; }\n .x-mod-actions { display: flex; gap: 8px; }\n .x-mod-btn {\n border: 1px solid var(--color-border);\n background: transparent;\n border-radius: var(--radius-md);\n padding: 6px 14px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n color: var(--color-text-muted);\n }\n .x-mod-ok { border-color: var(--color-accent); color: var(--color-accent-hover); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { ModerationComponent } from './moderation.component';\n\n@NgModule({\n declarations: [ModerationComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: ModerationComponent }]),\n ],\n})\nexport class ModerationModule {}\n"],"names":["i1"],"mappings":";;;;;;;;;;AAaA;AACA;AAMM,MAAO,mBAAoB,SAAQ,aAAa,CAAA;AALtD,IAAA,WAAA,GAAA;;QAME,IAAA,CAAA,OAAO,GAAG,IAAI;QACd,IAAA,CAAA,KAAK,GAAc,EAAE;QAEZ,IAAA,CAAA,IAAI,GAAG,MAAK;YACnB,IAAI,CAAC,IAAI,EAAE;AACb,QAAA,CAAC;AA6EF,IAAA;IA3EC,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AACnB,QAAA,QAAQ,CAAC;YACP,OAAO,EAAE,IAAI,CAAC;iBACX,EAAE,CAAC,sBAAsB;iBACzB,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAS;AAClD,iBAAA,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3C,SAAS,EAAE,IAAI,CAAC;iBACb,EAAE,CAAC,wBAAwB;iBAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAS;AAClD,iBAAA,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3C,OAAO,EAAE,IAAI,CAAC;iBACX,EAAE,CAAC,sBAAsB;iBACzB,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAS;AAClD,iBAAA,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;SAC5C;AACE,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACtB,aAAA,SAAS,CACR,KAAK,CAAC,CAAC,GAAQ,KAAI;YACjB,MAAM,KAAK,GAAc,EAAE;YAC3B,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE;gBACxC,KAAK,CAAC,IAAI,CAAC;AACT,oBAAA,IAAI,EAAE,QAAQ;oBACd,EAAE,EAAE,CAAC,CAAC,EAAE;AACR,oBAAA,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI,CAAA,EAAG,CAAC,CAAC,MAAM,CAAA,QAAA,CAAU;AACnD,oBAAA,SAAS,EAAE,CAAA,EAAG,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,kBAAkB,GAAG,UAAU,GAAG,YAAY,CAAA,CAAE;oBAC/E,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,SAAS,EAAE,CAAC,CAAC,SAAS;AACvB,iBAAA,CAAC;YACJ;YACA,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE;gBAC1C,KAAK,CAAC,IAAI,CAAC;AACT,oBAAA,IAAI,EAAE,UAAU;oBAChB,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,OAAO,EAAE,CAAC,CAAC,IAAI;AACf,oBAAA,SAAS,EAAE,UAAU;oBACrB,SAAS,EAAE,CAAC,CAAC,SAAS;AACvB,iBAAA,CAAC;YACJ;YACA,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE;gBACxC,KAAK,CAAC,IAAI,CAAC;AACT,oBAAA,IAAI,EAAE,QAAQ;oBACd,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,OAAO,EAAE,CAAC,CAAC,IAAI;oBACf,SAAS,EAAE,CAAC,CAAC,UAAU,GAAG,iBAAiB,GAAG,QAAQ;oBACtD,SAAS,EAAE,CAAC,CAAC,SAAS;AACvB,iBAAA,CAAC;YACJ;AACA,YAAA,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CACrB,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CACtD;AACD,YAAA,IAAI,CAAC,OAAO,GAAG,KAAK;QACtB,CAAC,CAAC,CACH;IACL;AAEA,IAAA,MAAM,QAAQ,CAAC,IAAa,EAAE,MAA2C,EAAA;AACvE,QAAA,IAAI;YACF,MAAM,cAAc,CAClB,IAAI,CAAC,UAAU,CAAC,IAAI,CAClB,CAAA,cAAA,EAAiB,IAAI,CAAC,IAAI,CAAA,CAAA,EAAI,IAAI,CAAC,EAAE,CAAA,SAAA,CAAW,EAChD,EAAE,MAAM,EAAE,CACX,CACF;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;AACvD,YAAA,MAAM,CAAC,CAAA,EAAG,IAAI,CAAC,IAAI,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE,EAAE,SAAS,EAAE,SAAS,CAAC;QACxD;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,CAAC,6BAA6B,EAAE,SAAS,EAAE,OAAO,CAAC;QAC3D;IACF;AAEQ,IAAA,EAAE,CAAC,CAAU,EAAA;AACnB,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG;AACjC,QAAA,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC;+GAlFW,mBAAmB,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mBAAmB,gGCpBhC,khFAqEA,EAAA,MAAA,EAAA,CAAA,wgCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FDjDa,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAL/B,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,UAAA,EAAA,KAAK,YACP,cAAc,EAAA,QAAA,EAAA,khFAAA,EAAA;;;MEHb,gBAAgB,CAAA;+GAAhB,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;gHAAhB,gBAAgB,EAAA,YAAA,EAAA,CAPZ,mBAAmB,CAAA,EAAA,OAAA,EAAA,CAEhC,YAAY;YACZ,cAAc,EAAAA,IAAA,CAAA,YAAA,CAAA,EAAA,CAAA,CAAA;AAIL,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,YALzB,YAAY;YACZ,cAAc;AACd,YAAA,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAA,EAAA,CAAA,CAAA;;4FAG5D,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAR5B,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,YAAY,EAAE,CAAC,mBAAmB,CAAC;AACnC,oBAAA,OAAO,EAAE;wBACP,YAAY;wBACZ,cAAc;AACd,wBAAA,YAAY,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;AACtE,qBAAA;AACF,iBAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs","sources":["../../../projects/admin/src/lib/pages/moderation/moderation.component.ts","../../../projects/admin/src/lib/pages/moderation/moderation.component.html","../../../projects/admin/src/lib/pages/moderation/moderation.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, using } from '@thescaffold/ngx-core';\nimport { catchError, firstValueFrom, forkJoin, of, takeUntil } from 'rxjs';\n\ninterface ModItem {\n kind: 'review' | 'question' | 'answer';\n id: string;\n primary: string;\n secondary: string;\n rating?: number;\n createdAt?: string;\n}\n\n// P5.11, UGC-04 — the UGC moderation queue. Everything `pending` across\n// reviews, questions and answers, with publish / reject / hide.\n@Component({\n standalone: false,\n selector: 'x-moderation',\n templateUrl: './moderation.component.html',\n})\nexport class ModerationComponent extends BaseDirective {\n loading = true;\n items: ModItem[] = [];\n\n override init = () => {\n this.load();\n };\n\n load(): void {\n this.loading = true;\n forkJoin({\n reviews: this.apiService\n .on('apps/commerce/review')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n questions: this.apiService\n .on('apps/commerce/question')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n answers: this.apiService\n .on('apps/commerce/answer')\n .getMany({ status: 'pending', perPage: 100 } as any)\n .pipe(catchError(() => of({ data: [] }))),\n })\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n const items: ModItem[] = [];\n for (const r of res?.reviews?.data ?? []) {\n items.push({\n kind: 'review',\n id: r.id,\n primary: r.title || r.body || `${r.rating}★ review`,\n secondary: `${r.rating}★ · ${r.isVerifiedPurchase ? 'verified' : 'unverified'}`,\n rating: r.rating,\n createdAt: r.createdAt,\n });\n }\n for (const q of res?.questions?.data ?? []) {\n items.push({\n kind: 'question',\n id: q.id,\n primary: q.body,\n secondary: 'question',\n createdAt: q.createdAt,\n });\n }\n for (const a of res?.answers?.data ?? []) {\n items.push({\n kind: 'answer',\n id: a.id,\n primary: a.body,\n secondary: a.isOfficial ? 'official answer' : 'answer',\n createdAt: a.createdAt,\n });\n }\n this.items = items.sort(\n (x, y) => this.ts(x.createdAt) - this.ts(y.createdAt),\n );\n this.loading = false;\n }),\n );\n }\n\n async moderate(item: ModItem, status: 'published' | 'rejected' | 'hidden'): Promise<void> {\n try {\n await firstValueFrom(\n this.apiService.post(\n `apps/commerce/${item.kind}/${item.id}/moderate`,\n { status },\n ),\n );\n this.items = this.items.filter((i) => i.id !== item.id);\n notify(`${item.kind} ${status}`, undefined, 'success');\n } catch {\n notify('Could not update that item.', undefined, 'error');\n }\n }\n\n private ts(v?: string): number {\n const t = v ? Date.parse(v) : NaN;\n return Number.isNaN(t) ? 0 : t;\n }\n}\n","<div class=\"x-mod-head\">\n <div class=\"x-mod-title\">Moderation</div>\n <div class=\"x-mod-sub\">Reviews, questions and answers awaiting a decision.</div>\n</div>\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!items.length) {\n <div class=\"x-mod-empty\">Nothing waiting. Nice.</div>\n} @else {\n <div class=\"x-mod-list\">\n @for (item of items; track item.id) {\n <div class=\"x-mod-item\">\n <div class=\"x-mod-meta\">\n <span class=\"x-mod-kind\">{{ item.kind }}</span>\n <span class=\"x-mod-secondary\">{{ item.secondary }}</span>\n <span class=\"x-mod-date\">{{ item.createdAt | date: 'short' }}</span>\n </div>\n <div class=\"x-mod-body\">{{ item.primary }}</div>\n <div class=\"x-mod-actions\">\n <button type=\"button\" class=\"x-mod-btn x-mod-ok\" (click)=\"moderate(item, 'published')\">\n Publish\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'rejected')\">\n Reject\n </button>\n <button type=\"button\" class=\"x-mod-btn\" (click)=\"moderate(item, 'hidden')\">\n Hide\n </button>\n </div>\n </div>\n }\n </div>\n}\n\n<style>\n .x-mod-head { margin-bottom: 20px; }\n .x-mod-title { font-size: 24px; font-weight: 800; color: var(--color-text); }\n .x-mod-sub { font-size: 13.5px; color: var(--color-text-muted); margin-top: 2px; }\n .x-mod-empty { font-size: 14px; color: var(--color-text-muted); }\n .x-mod-list { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }\n .x-mod-item {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: 16px;\n }\n .x-mod-meta {\n display: flex; gap: 10px; align-items: center;\n font-size: 11.5px; color: var(--color-text-muted); margin-bottom: 8px;\n }\n .x-mod-kind {\n font-weight: 800; text-transform: uppercase; letter-spacing: 0.4px;\n color: var(--color-accent-hover);\n }\n .x-mod-body { font-size: 14px; color: var(--color-text); margin-bottom: 12px; }\n .x-mod-actions { display: flex; gap: 8px; }\n .x-mod-btn {\n border: 1px solid var(--color-border);\n background: transparent;\n border-radius: var(--radius-md);\n padding: 6px 14px;\n font-size: 12.5px;\n font-weight: 700;\n cursor: pointer;\n color: var(--color-text-muted);\n }\n .x-mod-ok { border-color: var(--color-accent); color: var(--color-accent-hover); }\n</style>\n","import { NgModule } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { SharedModule } from '@thescaffold/ngx-core';\nimport { ElementsModule } from '@thescaffold/ngx-ui';\nimport { ModerationComponent } from './moderation.component';\n\n@NgModule({\n declarations: [ModerationComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: ModerationComponent }]),\n ],\n})\nexport class ModerationModule {}\n"],"names":["i1","i2"],"mappings":"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"}
|