@isaiahiroko/tilmart-ngx-apps-admin 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +9 -0
  2. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs +154 -0
  3. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map +1 -0
  4. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs +84 -0
  5. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map +1 -0
  6. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +294 -0
  7. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +1 -0
  8. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +224 -0
  9. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +1 -0
  10. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +106 -0
  11. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +1 -0
  12. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs +261 -0
  13. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map +1 -0
  14. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs +365 -0
  15. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map +1 -0
  16. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +106 -0
  17. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +1 -0
  18. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +106 -0
  19. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +1 -0
  20. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs +286 -0
  21. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map +1 -0
  22. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs +104 -0
  23. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map +1 -0
  24. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs +73 -0
  25. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs.map +1 -0
  26. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs +404 -0
  27. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map +1 -0
  28. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs +290 -0
  29. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map +1 -0
  30. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs +112 -0
  31. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map +1 -0
  32. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs +116 -0
  33. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map +1 -0
  34. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs +281 -0
  35. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map +1 -0
  36. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs +115 -0
  37. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map +1 -0
  38. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs +185 -0
  39. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +1 -0
  40. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +106 -0
  41. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +1 -0
  42. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs +70 -0
  43. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs.map +1 -0
  44. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +274 -0
  45. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +1 -0
  46. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +106 -0
  47. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +1 -0
  48. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs +84 -0
  49. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map +1 -0
  50. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +106 -0
  51. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +1 -0
  52. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs +106 -0
  53. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +1 -0
  54. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs +104 -0
  55. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map +1 -0
  56. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +106 -0
  57. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +1 -0
  58. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs +81 -0
  59. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs.map +1 -0
  60. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +105 -0
  61. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +1 -0
  62. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +222 -0
  63. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +1 -0
  64. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs +150 -0
  65. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +1 -0
  66. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +107 -0
  67. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +1 -0
  68. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs +92 -0
  69. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map +1 -0
  70. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs +111 -0
  71. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +1 -0
  72. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +475 -0
  73. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -0
  74. package/package.json +34 -0
  75. package/types/isaiahiroko-tilmart-ngx-apps-admin.d.ts +32 -0
@@ -0,0 +1,112 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, NgModule } from '@angular/core';
3
+ import * as i1$2 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i1$1 from '@thescaffold/ngx-ui';
7
+ import { ElementsModule } from '@thescaffold/ngx-ui';
8
+ import { takeUntil, firstValueFrom } from 'rxjs';
9
+ import * as i1 from '@angular/forms';
10
+
11
+ // P7.5, SUP-03 — the canned-response library the support inbox draws
12
+ // from. List + inline editor. ops CRUD is covered by
13
+ // `admin:*:apps:commerce:*`.
14
+ class MacrosComponent extends BaseDirective {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.source = this.apiService.on('apps/commerce/support-macro');
18
+ this.loading = true;
19
+ this.macros = [];
20
+ this.newTitle = '';
21
+ this.init = () => {
22
+ this.load();
23
+ };
24
+ }
25
+ load() {
26
+ this.loading = true;
27
+ this.source
28
+ .getMany({ perPage: 200 })
29
+ .pipe(takeUntil(this.$))
30
+ .subscribe(using((res) => {
31
+ this.macros = (res?.data ?? []).sort((a, b) => `${a.category}${a.title}`.localeCompare(`${b.category}${b.title}`));
32
+ this.loading = false;
33
+ if (this.selected) {
34
+ this.selected = this.macros.find((m) => m.id === this.selected.id);
35
+ }
36
+ }));
37
+ }
38
+ async create() {
39
+ const title = this.newTitle.trim();
40
+ if (!title)
41
+ return;
42
+ try {
43
+ const res = await firstValueFrom(this.source.create({ title, body: '' }));
44
+ this.newTitle = '';
45
+ this.load();
46
+ if (res?.data?.id)
47
+ setTimeout(() => (this.selected = { ...res.data }), 150);
48
+ }
49
+ catch {
50
+ notify('Could not create the macro.', undefined, 'error');
51
+ }
52
+ }
53
+ async save() {
54
+ if (!this.selected)
55
+ return;
56
+ const m = this.selected;
57
+ try {
58
+ await firstValueFrom(this.source.update(m.id, {
59
+ title: m.title,
60
+ category: m.category || undefined,
61
+ body: m.body,
62
+ enabled: m.enabled,
63
+ }));
64
+ notify('Macro saved.', undefined, 'success');
65
+ this.load();
66
+ }
67
+ catch {
68
+ notify('Could not save the macro.', undefined, 'error');
69
+ }
70
+ }
71
+ async remove() {
72
+ if (!this.selected)
73
+ return;
74
+ try {
75
+ await firstValueFrom(this.source.remove(this.selected.id));
76
+ this.selected = undefined;
77
+ this.load();
78
+ }
79
+ catch {
80
+ notify('Could not delete the macro.', undefined, 'error');
81
+ }
82
+ }
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: i1$1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }] }); }
85
+ }
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosComponent, decorators: [{
87
+ type: Component,
88
+ args: [{ standalone: false, selector: 'x-macros', 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" }]
89
+ }] });
90
+
91
+ class MacrosModule {
92
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
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$2.RouterModule] }); }
95
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, imports: [SharedModule,
96
+ ElementsModule,
97
+ RouterModule.forChild([{ path: '', component: MacrosComponent }])] }); }
98
+ }
99
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: MacrosModule, decorators: [{
100
+ type: NgModule,
101
+ args: [{
102
+ declarations: [MacrosComponent],
103
+ imports: [
104
+ SharedModule,
105
+ ElementsModule,
106
+ RouterModule.forChild([{ path: '', component: MacrosComponent }]),
107
+ ],
108
+ }]
109
+ }] });
110
+
111
+ export { MacrosModule };
112
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,116 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { BaseDirective, using, notify, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i1 from '@thescaffold/ngx-ui';
7
+ import { ElementsModule } from '@thescaffold/ngx-ui';
8
+ import { forkJoin, catchError, of, takeUntil, firstValueFrom } from 'rxjs';
9
+ import * as i2 from '@angular/common';
10
+
11
+ // P5.11, UGC-04 — the UGC moderation queue. Everything `pending` across
12
+ // reviews, questions and answers, with publish / reject / hide.
13
+ class ModerationComponent extends BaseDirective {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.loading = true;
17
+ this.items = [];
18
+ this.init = () => {
19
+ this.load();
20
+ };
21
+ }
22
+ load() {
23
+ this.loading = true;
24
+ forkJoin({
25
+ reviews: this.apiService
26
+ .on('apps/commerce/review')
27
+ .getMany({ status: 'pending', perPage: 100 })
28
+ .pipe(catchError(() => of({ data: [] }))),
29
+ questions: this.apiService
30
+ .on('apps/commerce/question')
31
+ .getMany({ status: 'pending', perPage: 100 })
32
+ .pipe(catchError(() => of({ data: [] }))),
33
+ answers: this.apiService
34
+ .on('apps/commerce/answer')
35
+ .getMany({ status: 'pending', perPage: 100 })
36
+ .pipe(catchError(() => of({ data: [] }))),
37
+ })
38
+ .pipe(takeUntil(this.$))
39
+ .subscribe(using((res) => {
40
+ const items = [];
41
+ for (const r of res?.reviews?.data ?? []) {
42
+ items.push({
43
+ kind: 'review',
44
+ id: r.id,
45
+ primary: r.title || r.body || `${r.rating}★ review`,
46
+ secondary: `${r.rating}★ · ${r.isVerifiedPurchase ? 'verified' : 'unverified'}`,
47
+ rating: r.rating,
48
+ createdAt: r.createdAt,
49
+ });
50
+ }
51
+ for (const q of res?.questions?.data ?? []) {
52
+ items.push({
53
+ kind: 'question',
54
+ id: q.id,
55
+ primary: q.body,
56
+ secondary: 'question',
57
+ createdAt: q.createdAt,
58
+ });
59
+ }
60
+ for (const a of res?.answers?.data ?? []) {
61
+ items.push({
62
+ kind: 'answer',
63
+ id: a.id,
64
+ primary: a.body,
65
+ secondary: a.isOfficial ? 'official answer' : 'answer',
66
+ createdAt: a.createdAt,
67
+ });
68
+ }
69
+ this.items = items.sort((x, y) => this.ts(x.createdAt) - this.ts(y.createdAt));
70
+ this.loading = false;
71
+ }));
72
+ }
73
+ async moderate(item, status) {
74
+ try {
75
+ await firstValueFrom(this.apiService.post(`apps/commerce/${item.kind}/${item.id}/moderate`, { status }));
76
+ this.items = this.items.filter((i) => i.id !== item.id);
77
+ notify(`${item.kind} ${status}`, undefined, 'success');
78
+ }
79
+ catch {
80
+ notify('Could not update that item.', undefined, 'error');
81
+ }
82
+ }
83
+ ts(v) {
84
+ const t = v ? Date.parse(v) : NaN;
85
+ return Number.isNaN(t) ? 0 : t;
86
+ }
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: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); }
89
+ }
90
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationComponent, decorators: [{
91
+ type: Component,
92
+ args: [{ standalone: false, selector: 'x-moderation', 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" }]
93
+ }] });
94
+
95
+ class ModerationModule {
96
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
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$1.RouterModule] }); }
99
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, imports: [SharedModule,
100
+ ElementsModule,
101
+ RouterModule.forChild([{ path: '', component: ModerationComponent }])] }); }
102
+ }
103
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ModerationModule, decorators: [{
104
+ type: NgModule,
105
+ args: [{
106
+ declarations: [ModerationComponent],
107
+ imports: [
108
+ SharedModule,
109
+ ElementsModule,
110
+ RouterModule.forChild([{ path: '', component: ModerationComponent }]),
111
+ ],
112
+ }]
113
+ }] });
114
+
115
+ export { ModerationModule };
116
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map
@@ -0,0 +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":"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"}