@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.
- package/README.md +9 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs +154 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs +84 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +294 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +224 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs +261 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs +365 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs +286 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs +104 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs +73 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-disputes.module-DmUoAS0Z.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs +404 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs +290 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs +112 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs +116 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs +281 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs +115 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs +185 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs +70 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payouts.module-CoiscPIZ.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +274 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs +84 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs +104 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +106 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs +81 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +105 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +222 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs +150 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +107 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs +92 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs +111 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +1 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +475 -0
- package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -0
- package/package.json +34 -0
- package/types/isaiahiroko-tilmart-ngx-apps-admin.d.ts +32 -0
|
@@ -0,0 +1,106 @@
|
|
|
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, titleCase, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
|
|
11
|
+
// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list
|
|
12
|
+
// view on `x-webget-collection` over `apps/commerce/redirect`, matching the
|
|
13
|
+
// established admin pattern (users, routes, inbox). ops CRUD is covered
|
|
14
|
+
// by `admin:*:apps:commerce:*`.
|
|
15
|
+
class RedirectsComponent extends BaseDirective {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.pluralName = 'redirects';
|
|
19
|
+
this.dataSource = this.apiService.on('apps/commerce/redirect');
|
|
20
|
+
this.columns = [
|
|
21
|
+
{ key: 'fromPath', value: 'From' },
|
|
22
|
+
{ key: 'toPath', value: 'To' },
|
|
23
|
+
{ key: 'statusCode', value: 'Code' },
|
|
24
|
+
{ key: 'hitCount', value: 'Hits' },
|
|
25
|
+
];
|
|
26
|
+
this.page = 1;
|
|
27
|
+
this.perPage = 25;
|
|
28
|
+
this.list$ = new BehaviorSubject(null);
|
|
29
|
+
this.init = () => {
|
|
30
|
+
this.list();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
list(page = this.page, perPage = this.perPage) {
|
|
34
|
+
this.dataSource
|
|
35
|
+
.getMany({ page, perPage })
|
|
36
|
+
.pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
|
|
37
|
+
.subscribe(using((data) => this.list$.next(data)));
|
|
38
|
+
}
|
|
39
|
+
toCollection(response) {
|
|
40
|
+
return {
|
|
41
|
+
title: titleCase(this.pluralName),
|
|
42
|
+
columns: this.columns,
|
|
43
|
+
rows: response?.data,
|
|
44
|
+
hasHeaders: true,
|
|
45
|
+
hasTextFilter: true,
|
|
46
|
+
page: response?.meta?.current_page,
|
|
47
|
+
perPage: response?.meta?.per_page,
|
|
48
|
+
total: response?.meta?.total,
|
|
49
|
+
onPage: (page) => this.list(page),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RedirectsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
53
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: RedirectsComponent, isStandalone: false, selector: "x-redirects", usesInheritance: true, ngImport: i0, template: `
|
|
54
|
+
<div class="x-page-head">
|
|
55
|
+
<div class="x-page-title">Redirects</div>
|
|
56
|
+
<div class="x-page-subtitle">Stored 301/302 path redirects — auto-minted on slug changes (CMS-06).</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
@if (list$ | async; as list) {
|
|
60
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
61
|
+
} @else {
|
|
62
|
+
<x-element-loader></x-element-loader>
|
|
63
|
+
}
|
|
64
|
+
`, isInline: true, 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}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i1.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
|
|
65
|
+
}
|
|
66
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RedirectsComponent, decorators: [{
|
|
67
|
+
type: Component,
|
|
68
|
+
args: [{ standalone: false, selector: 'x-redirects', template: `
|
|
69
|
+
<div class="x-page-head">
|
|
70
|
+
<div class="x-page-title">Redirects</div>
|
|
71
|
+
<div class="x-page-subtitle">Stored 301/302 path redirects — auto-minted on slug changes (CMS-06).</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
@if (list$ | async; as list) {
|
|
75
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
76
|
+
} @else {
|
|
77
|
+
<x-element-loader></x-element-loader>
|
|
78
|
+
}
|
|
79
|
+
`, 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}\n"] }]
|
|
80
|
+
}] });
|
|
81
|
+
|
|
82
|
+
class RedirectsModule {
|
|
83
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RedirectsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
84
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: RedirectsModule, declarations: [RedirectsComponent], imports: [SharedModule,
|
|
85
|
+
ElementsModule,
|
|
86
|
+
WebgetsModule, i1$1.RouterModule] }); }
|
|
87
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RedirectsModule, imports: [SharedModule,
|
|
88
|
+
ElementsModule,
|
|
89
|
+
WebgetsModule,
|
|
90
|
+
RouterModule.forChild([{ path: '', component: RedirectsComponent }])] }); }
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RedirectsModule, decorators: [{
|
|
93
|
+
type: NgModule,
|
|
94
|
+
args: [{
|
|
95
|
+
declarations: [RedirectsComponent],
|
|
96
|
+
imports: [
|
|
97
|
+
SharedModule,
|
|
98
|
+
ElementsModule,
|
|
99
|
+
WebgetsModule,
|
|
100
|
+
RouterModule.forChild([{ path: '', component: RedirectsComponent }]),
|
|
101
|
+
],
|
|
102
|
+
}]
|
|
103
|
+
}] });
|
|
104
|
+
|
|
105
|
+
export { RedirectsModule };
|
|
106
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs","sources":["../../../projects/admin/src/lib/pages/redirects/redirects.component.ts","../../../projects/admin/src/lib/pages/redirects/redirects.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, map, takeUntil } from 'rxjs';\n\n// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list\n// view on `x-webget-collection` over `apps/commerce/redirect`, matching the\n// established admin pattern (users, routes, inbox). ops CRUD is covered\n// by `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-redirects',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Redirects</div>\n <div class=\"x-page-subtitle\">Stored 301/302 path redirects — auto-minted on slug changes (CMS-06).</div>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n `,\n ],\n})\nexport class RedirectsComponent extends BaseDirective {\n pluralName = 'redirects';\n dataSource = this.apiService.on('apps/commerce/redirect');\n\n columns = [\n { key: 'fromPath', value: 'From' },\n { key: 'toPath', value: 'To' },\n { key: 'statusCode', value: 'Code' },\n { key: 'hitCount', value: 'Hits' },\n ];\n\n page = 1;\n perPage = 25;\n\n list$ = new BehaviorSubject<any>(null);\n\n override init = () => {\n this.list();\n };\n\n list(page = this.page, perPage = this.perPage) {\n this.dataSource\n .getMany({ page, perPage })\n .pipe(\n takeUntil(this.$),\n map((response) => this.toCollection(response)),\n )\n .subscribe(using((data) => this.list$.next(data)));\n }\n\n private toCollection(response: any) {\n return {\n title: titleCase(this.pluralName),\n columns: this.columns,\n rows: response?.data,\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 };\n }\n}\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 { RedirectsComponent } from './redirects.component';\n\n@NgModule({\n declarations: [RedirectsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: RedirectsComponent }]),\n ],\n})\nexport class RedirectsModule {}\n"],"names":["i1"],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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, titleCase, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
|
|
11
|
+
// Referral/reward view (docs/TRD.md §7).
|
|
12
|
+
class ReferralsComponent extends BaseDirective {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.name = 'referral';
|
|
16
|
+
this.pluralName = 'referrals';
|
|
17
|
+
// P5.14 — the commerce Referral (ACC-11); the Salama grocery route is gone.
|
|
18
|
+
this.dataSource = this.apiService.on('apps/commerce/referral');
|
|
19
|
+
this.columns = [
|
|
20
|
+
{ key: 'code', value: 'Code' },
|
|
21
|
+
{ key: 'referredContactPhone', value: 'Referred contact' },
|
|
22
|
+
{ key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },
|
|
23
|
+
{ key: 'convertedAt', value: 'Converted', type: 'date' },
|
|
24
|
+
{ key: 'createdAt', value: 'Referred on', type: 'date' },
|
|
25
|
+
];
|
|
26
|
+
this.page = 1;
|
|
27
|
+
this.perPage = 25;
|
|
28
|
+
this.list$ = new BehaviorSubject(null);
|
|
29
|
+
this.init = () => {
|
|
30
|
+
this.list();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
list(page = this.page, perPage = this.perPage) {
|
|
34
|
+
this.dataSource
|
|
35
|
+
.getMany({ page, perPage })
|
|
36
|
+
.pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
|
|
37
|
+
.subscribe(using((data) => this.list$.next(data)));
|
|
38
|
+
}
|
|
39
|
+
toCollection(response) {
|
|
40
|
+
return {
|
|
41
|
+
title: titleCase(this.pluralName),
|
|
42
|
+
columns: this.columns,
|
|
43
|
+
rows: response?.data,
|
|
44
|
+
hasHeaders: true,
|
|
45
|
+
hasTextFilter: true,
|
|
46
|
+
page: response?.meta?.current_page,
|
|
47
|
+
perPage: response?.meta?.per_page,
|
|
48
|
+
total: response?.meta?.total,
|
|
49
|
+
onPage: (page) => this.list(page),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
53
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ReferralsComponent, isStandalone: false, selector: "x-referrals", usesInheritance: true, ngImport: i0, template: `
|
|
54
|
+
<div class="x-page-head">
|
|
55
|
+
<div class="x-page-title">Referrals</div>
|
|
56
|
+
<div class="x-page-subtitle">Who referred whom, and reward status.</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
@if (list$ | async; as list) {
|
|
60
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
61
|
+
} @else {
|
|
62
|
+
<x-element-loader></x-element-loader>
|
|
63
|
+
}
|
|
64
|
+
`, isInline: true, 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}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i1.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
|
|
65
|
+
}
|
|
66
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsComponent, decorators: [{
|
|
67
|
+
type: Component,
|
|
68
|
+
args: [{ standalone: false, selector: 'x-referrals', template: `
|
|
69
|
+
<div class="x-page-head">
|
|
70
|
+
<div class="x-page-title">Referrals</div>
|
|
71
|
+
<div class="x-page-subtitle">Who referred whom, and reward status.</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
@if (list$ | async; as list) {
|
|
75
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
76
|
+
} @else {
|
|
77
|
+
<x-element-loader></x-element-loader>
|
|
78
|
+
}
|
|
79
|
+
`, 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}\n"] }]
|
|
80
|
+
}] });
|
|
81
|
+
|
|
82
|
+
class ReferralsModule {
|
|
83
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
84
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, declarations: [ReferralsComponent], imports: [SharedModule,
|
|
85
|
+
ElementsModule,
|
|
86
|
+
WebgetsModule, i1$1.RouterModule] }); }
|
|
87
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, imports: [SharedModule,
|
|
88
|
+
ElementsModule,
|
|
89
|
+
WebgetsModule,
|
|
90
|
+
RouterModule.forChild([{ path: '', component: ReferralsComponent }])] }); }
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, decorators: [{
|
|
93
|
+
type: NgModule,
|
|
94
|
+
args: [{
|
|
95
|
+
declarations: [ReferralsComponent],
|
|
96
|
+
imports: [
|
|
97
|
+
SharedModule,
|
|
98
|
+
ElementsModule,
|
|
99
|
+
WebgetsModule,
|
|
100
|
+
RouterModule.forChild([{ path: '', component: ReferralsComponent }]),
|
|
101
|
+
],
|
|
102
|
+
}]
|
|
103
|
+
}] });
|
|
104
|
+
|
|
105
|
+
export { ReferralsModule };
|
|
106
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs","sources":["../../../projects/admin/src/lib/pages/referrals/referrals.component.ts","../../../projects/admin/src/lib/pages/referrals/referrals.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, takeUntil, map } from 'rxjs';\n\n// Referral/reward view (docs/TRD.md §7).\n@Component({\n standalone: false,\n selector: 'x-referrals',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Referrals</div>\n <div class=\"x-page-subtitle\">Who referred whom, and reward status.</div>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n `,\n ],\n})\nexport class ReferralsComponent extends BaseDirective {\n name = 'referral';\n pluralName = 'referrals';\n // P5.14 — the commerce Referral (ACC-11); the Salama grocery route is gone.\n dataSource = this.apiService.on('apps/commerce/referral');\n\n columns = [\n { key: 'code', value: 'Code' },\n { key: 'referredContactPhone', value: 'Referred contact' },\n { key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },\n { key: 'convertedAt', value: 'Converted', type: 'date' },\n { key: 'createdAt', value: 'Referred on', type: 'date' },\n ];\n\n page = 1;\n perPage = 25;\n\n list$ = new BehaviorSubject<any>(null);\n\n override init = () => {\n this.list();\n };\n\n list(page = this.page, perPage = this.perPage) {\n this.dataSource\n .getMany({ page, perPage })\n .pipe(\n takeUntil(this.$),\n map((response) => this.toCollection(response)),\n )\n .subscribe(using((data) => this.list$.next(data)));\n }\n\n private toCollection(response: any) {\n return {\n title: titleCase(this.pluralName),\n columns: this.columns,\n rows: response?.data,\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 };\n }\n}\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 { ReferralsComponent } from './referrals.component';\n\n@NgModule({\n declarations: [ReferralsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: ReferralsComponent }]),\n ],\n})\nexport class ReferralsModule {}\n"],"names":["i1"],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
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, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { takeUntil } from 'rxjs';
|
|
9
|
+
|
|
10
|
+
const TABS = [
|
|
11
|
+
{ key: 'commerce', label: 'Commerce', ana: 'ANA-01', hasRange: true },
|
|
12
|
+
{ key: 'funnel', label: 'Funnel', ana: 'ANA-02', hasRange: true },
|
|
13
|
+
{ key: 'search', label: 'Search', ana: 'ANA-03', hasRange: true },
|
|
14
|
+
{ key: 'tools', label: 'Tools', ana: 'ANA-04', hasRange: true },
|
|
15
|
+
{ key: 'inventory', label: 'Inventory', ana: 'ANA-05', hasRange: false },
|
|
16
|
+
{ key: 'operations', label: 'Operations', ana: 'ANA-09', hasRange: true },
|
|
17
|
+
];
|
|
18
|
+
// P7.4 — the ANA-* analytics dashboard. Each tab reads one
|
|
19
|
+
// `apps/admin/analytics/*` read model (raw SQL over the commerce tables,
|
|
20
|
+
// libs/admin). ANA-11 web analytics / campaign attribution lives in
|
|
21
|
+
// Countly, not here.
|
|
22
|
+
class ReportsComponent extends BaseDirective {
|
|
23
|
+
constructor() {
|
|
24
|
+
super(...arguments);
|
|
25
|
+
this.source = this.apiService.on('apps/admin/analytics');
|
|
26
|
+
this.tabs = TABS;
|
|
27
|
+
this.active = 'commerce';
|
|
28
|
+
this.days = 30;
|
|
29
|
+
this.loading = true;
|
|
30
|
+
this.data = null;
|
|
31
|
+
this.init = () => {
|
|
32
|
+
this.load();
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
get activeTab() {
|
|
36
|
+
return TABS.find((t) => t.key === this.active);
|
|
37
|
+
}
|
|
38
|
+
select(key) {
|
|
39
|
+
if (this.active === key)
|
|
40
|
+
return;
|
|
41
|
+
this.active = key;
|
|
42
|
+
this.load();
|
|
43
|
+
}
|
|
44
|
+
setDays(days) {
|
|
45
|
+
this.days = days;
|
|
46
|
+
this.load();
|
|
47
|
+
}
|
|
48
|
+
load() {
|
|
49
|
+
this.loading = true;
|
|
50
|
+
this.data = null;
|
|
51
|
+
const path = this.activeTab.hasRange
|
|
52
|
+
? `${this.active}?days=${this.days}`
|
|
53
|
+
: this.active;
|
|
54
|
+
this.source
|
|
55
|
+
.getOne(path)
|
|
56
|
+
.pipe(takeUntil(this.$))
|
|
57
|
+
.subscribe(using((res) => {
|
|
58
|
+
this.data = res?.data ?? null;
|
|
59
|
+
this.loading = false;
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
money(n) {
|
|
63
|
+
const v = Number(n) || 0;
|
|
64
|
+
return `₦${v.toLocaleString('en-NG', { maximumFractionDigits: 0 })}`;
|
|
65
|
+
}
|
|
66
|
+
num(n) {
|
|
67
|
+
return (Number(n) || 0).toLocaleString('en-NG');
|
|
68
|
+
}
|
|
69
|
+
keys(obj) {
|
|
70
|
+
return obj ? Object.keys(obj) : [];
|
|
71
|
+
}
|
|
72
|
+
humanize(key) {
|
|
73
|
+
return key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
74
|
+
}
|
|
75
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
76
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ReportsComponent, isStandalone: false, selector: "x-reports", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Reports</div>\n <div class=\"x-page-subtitle\">\n Analytics read models over the commerce tables. Web traffic, sessions and\n campaign attribution are in Countly (ANA-11).\n </div>\n</div>\n\n<nav class=\"x-rp-tabs\">\n @for (t of tabs; track t.key) {\n <button\n type=\"button\"\n class=\"x-rp-tab\"\n [class.is-active]=\"active === t.key\"\n (click)=\"select(t.key)\"\n >\n {{ t.label }} <span class=\"x-rp-ana\">{{ t.ana }}</span>\n </button>\n }\n</nav>\n\n@if (activeTab.hasRange) {\n <div class=\"x-rp-range\">\n @for (d of [7, 30, 90]; track d) {\n <button\n type=\"button\"\n class=\"x-rp-range-btn\"\n [class.is-active]=\"days === d\"\n (click)=\"setDays(d)\"\n >\n {{ d }}d\n </button>\n }\n </div>\n}\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!data) {\n <p class=\"x-rp-empty\">No data.</p>\n} @else {\n <!-- summary blocks: any object of scalars renders as cards -->\n @for (block of ['summary', 'fulfilment', 'returns', 'support', 'toolRevenue', 'compatibilityChecks']; track block) {\n @if (data[block] && keys(data[block]).length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-cards\">\n @for (k of keys(data[block]); track k) {\n <div class=\"x-rp-card\">\n <div class=\"x-rp-card-label\">{{ humanize(k) }}</div>\n <div class=\"x-rp-card-value\">\n @if (k.includes('revenue') || k.includes('value') || k.includes('aov') || k.includes('discount')) {\n {{ money(data[block][k]) }}\n } @else {\n {{ num(data[block][k]) }}\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- funnel -->\n @if (data.stages) {\n <div class=\"x-rp-section-label\">Checkout funnel</div>\n @if (data.note) { <p class=\"x-rp-note\">{{ data.note }}</p> }\n <table class=\"x-rp-table\">\n <thead><tr><th>Stage</th><th>Count</th><th>% of top</th><th>Drop from previous</th></tr></thead>\n <tbody>\n @for (s of data.stages; track s.key) {\n <tr>\n <td>{{ s.label }}</td>\n <td>{{ num(s.value) }}</td>\n <td>{{ s.conversionFromTop }}%</td>\n <td [class.x-rp-drop]=\"s.dropFromPrev > 0\">{{ s.dropFromPrev }}%</td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- generic array tables -->\n @for (block of ['byDay', 'byChannel', 'byPaymentMethod', 'byCategory', 'byType', 'byMethod', 'topQueries', 'zeroResult', 'blockFrequency', 'worstStockouts']; track block) {\n @if (data[block] && data[block].length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-table-wrap\">\n <table class=\"x-rp-table\">\n <thead>\n <tr>\n @for (col of keys(data[block][0]); track col) {\n <th>{{ humanize(col) }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data[block]; track $index) {\n <tr>\n @for (col of keys(row); track col) {\n <td>\n @if (col.includes('revenue') || col.includes('amount')) {\n {{ money(row[col]) }}\n } @else {\n {{ row[col] }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n}\n\n<style>\n .x-page-head { 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; max-width: 640px; }\n\n .x-rp-tabs { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: 14px; }\n .x-rp-tab { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 8px 12px; font-size: 13.5px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-tab.is-active { color: var(--color-text); border-bottom-color: var(--color-brand); }\n .x-rp-ana { font-size: 10px; opacity: 0.6; font-weight: 500; }\n\n .x-rp-range { display: flex; gap: 6px; margin-bottom: 18px; }\n .x-rp-range-btn { appearance: none; background: transparent; border: 1px solid var(--color-border); border-radius: 999px; padding: 3px 12px; font-size: 12px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-range-btn.is-active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }\n\n .x-rp-section-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; color: var(--color-text-muted); margin: 24px 0 10px; }\n .x-rp-note { font-size: 12.5px; color: var(--color-text-muted); margin: -4px 0 10px; }\n .x-rp-empty { font-size: 13px; color: var(--color-text-muted); }\n\n .x-rp-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px; }\n .x-rp-card { border: 1px solid var(--color-border); border-radius: 10px; padding: 10px 14px; }\n .x-rp-card-label { font-size: 11.5px; color: var(--color-text-muted); }\n .x-rp-card-value { font-size: 19px; font-weight: 800; color: var(--color-text); margin-top: 3px; }\n\n .x-rp-table-wrap { overflow-x: auto; }\n .x-rp-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n .x-rp-table th, .x-rp-table td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--color-border); white-space: nowrap; }\n .x-rp-table th { color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; }\n .x-rp-drop { color: var(--color-danger, #c0392b); font-weight: 600; }\n</style>\n", styles: [".x-page-head{margin-bottom:16px}.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;max-width:640px}.x-rp-tabs{display:flex;flex-wrap:wrap;gap:4px;border-bottom:1px solid var(--color-border);margin-bottom:14px}.x-rp-tab{appearance:none;background:transparent;border:0;border-bottom:2px solid transparent;padding:8px 12px;font-size:13.5px;font-weight:600;color:var(--color-text-muted);cursor:pointer}.x-rp-tab.is-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-rp-ana{font-size:10px;opacity:.6;font-weight:500}.x-rp-range{display:flex;gap:6px;margin-bottom:18px}.x-rp-range-btn{appearance:none;background:transparent;border:1px solid var(--color-border);border-radius:999px;padding:3px 12px;font-size:12px;font-weight:600;color:var(--color-text-muted);cursor:pointer}.x-rp-range-btn.is-active{background:var(--color-brand);color:#fff;border-color:var(--color-brand)}.x-rp-section-label{font-size:11.5px;text-transform:uppercase;letter-spacing:.04em;font-weight:700;color:var(--color-text-muted);margin:24px 0 10px}.x-rp-note{font-size:12.5px;color:var(--color-text-muted);margin:-4px 0 10px}.x-rp-empty{font-size:13px;color:var(--color-text-muted)}.x-rp-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:10px}.x-rp-card{border:1px solid var(--color-border);border-radius:10px;padding:10px 14px}.x-rp-card-label{font-size:11.5px;color:var(--color-text-muted)}.x-rp-card-value{font-size:19px;font-weight:800;color:var(--color-text);margin-top:3px}.x-rp-table-wrap{overflow-x:auto}.x-rp-table{width:100%;border-collapse:collapse;font-size:13px}.x-rp-table th,.x-rp-table td{text-align:left;padding:7px 10px;border-bottom:1px solid var(--color-border);white-space:nowrap}.x-rp-table th{color:var(--color-text-muted);font-size:11px;text-transform:uppercase;letter-spacing:.03em}.x-rp-drop{color:var(--color-danger, #c0392b);font-weight:600}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }] }); }
|
|
77
|
+
}
|
|
78
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsComponent, decorators: [{
|
|
79
|
+
type: Component,
|
|
80
|
+
args: [{ standalone: false, selector: 'x-reports', template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Reports</div>\n <div class=\"x-page-subtitle\">\n Analytics read models over the commerce tables. Web traffic, sessions and\n campaign attribution are in Countly (ANA-11).\n </div>\n</div>\n\n<nav class=\"x-rp-tabs\">\n @for (t of tabs; track t.key) {\n <button\n type=\"button\"\n class=\"x-rp-tab\"\n [class.is-active]=\"active === t.key\"\n (click)=\"select(t.key)\"\n >\n {{ t.label }} <span class=\"x-rp-ana\">{{ t.ana }}</span>\n </button>\n }\n</nav>\n\n@if (activeTab.hasRange) {\n <div class=\"x-rp-range\">\n @for (d of [7, 30, 90]; track d) {\n <button\n type=\"button\"\n class=\"x-rp-range-btn\"\n [class.is-active]=\"days === d\"\n (click)=\"setDays(d)\"\n >\n {{ d }}d\n </button>\n }\n </div>\n}\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!data) {\n <p class=\"x-rp-empty\">No data.</p>\n} @else {\n <!-- summary blocks: any object of scalars renders as cards -->\n @for (block of ['summary', 'fulfilment', 'returns', 'support', 'toolRevenue', 'compatibilityChecks']; track block) {\n @if (data[block] && keys(data[block]).length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-cards\">\n @for (k of keys(data[block]); track k) {\n <div class=\"x-rp-card\">\n <div class=\"x-rp-card-label\">{{ humanize(k) }}</div>\n <div class=\"x-rp-card-value\">\n @if (k.includes('revenue') || k.includes('value') || k.includes('aov') || k.includes('discount')) {\n {{ money(data[block][k]) }}\n } @else {\n {{ num(data[block][k]) }}\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- funnel -->\n @if (data.stages) {\n <div class=\"x-rp-section-label\">Checkout funnel</div>\n @if (data.note) { <p class=\"x-rp-note\">{{ data.note }}</p> }\n <table class=\"x-rp-table\">\n <thead><tr><th>Stage</th><th>Count</th><th>% of top</th><th>Drop from previous</th></tr></thead>\n <tbody>\n @for (s of data.stages; track s.key) {\n <tr>\n <td>{{ s.label }}</td>\n <td>{{ num(s.value) }}</td>\n <td>{{ s.conversionFromTop }}%</td>\n <td [class.x-rp-drop]=\"s.dropFromPrev > 0\">{{ s.dropFromPrev }}%</td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- generic array tables -->\n @for (block of ['byDay', 'byChannel', 'byPaymentMethod', 'byCategory', 'byType', 'byMethod', 'topQueries', 'zeroResult', 'blockFrequency', 'worstStockouts']; track block) {\n @if (data[block] && data[block].length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-table-wrap\">\n <table class=\"x-rp-table\">\n <thead>\n <tr>\n @for (col of keys(data[block][0]); track col) {\n <th>{{ humanize(col) }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data[block]; track $index) {\n <tr>\n @for (col of keys(row); track col) {\n <td>\n @if (col.includes('revenue') || col.includes('amount')) {\n {{ money(row[col]) }}\n } @else {\n {{ row[col] }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n}\n\n<style>\n .x-page-head { 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; max-width: 640px; }\n\n .x-rp-tabs { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: 14px; }\n .x-rp-tab { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 8px 12px; font-size: 13.5px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-tab.is-active { color: var(--color-text); border-bottom-color: var(--color-brand); }\n .x-rp-ana { font-size: 10px; opacity: 0.6; font-weight: 500; }\n\n .x-rp-range { display: flex; gap: 6px; margin-bottom: 18px; }\n .x-rp-range-btn { appearance: none; background: transparent; border: 1px solid var(--color-border); border-radius: 999px; padding: 3px 12px; font-size: 12px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-range-btn.is-active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }\n\n .x-rp-section-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; color: var(--color-text-muted); margin: 24px 0 10px; }\n .x-rp-note { font-size: 12.5px; color: var(--color-text-muted); margin: -4px 0 10px; }\n .x-rp-empty { font-size: 13px; color: var(--color-text-muted); }\n\n .x-rp-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px; }\n .x-rp-card { border: 1px solid var(--color-border); border-radius: 10px; padding: 10px 14px; }\n .x-rp-card-label { font-size: 11.5px; color: var(--color-text-muted); }\n .x-rp-card-value { font-size: 19px; font-weight: 800; color: var(--color-text); margin-top: 3px; }\n\n .x-rp-table-wrap { overflow-x: auto; }\n .x-rp-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n .x-rp-table th, .x-rp-table td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--color-border); white-space: nowrap; }\n .x-rp-table th { color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; }\n .x-rp-drop { color: var(--color-danger, #c0392b); font-weight: 600; }\n</style>\n" }]
|
|
81
|
+
}] });
|
|
82
|
+
|
|
83
|
+
class ReportsModule {
|
|
84
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
85
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, declarations: [ReportsComponent], imports: [SharedModule,
|
|
86
|
+
ElementsModule, i1$1.RouterModule] }); }
|
|
87
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, imports: [SharedModule,
|
|
88
|
+
ElementsModule,
|
|
89
|
+
RouterModule.forChild([{ path: '', component: ReportsComponent }])] }); }
|
|
90
|
+
}
|
|
91
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, decorators: [{
|
|
92
|
+
type: NgModule,
|
|
93
|
+
args: [{
|
|
94
|
+
declarations: [ReportsComponent],
|
|
95
|
+
imports: [
|
|
96
|
+
SharedModule,
|
|
97
|
+
ElementsModule,
|
|
98
|
+
RouterModule.forChild([{ path: '', component: ReportsComponent }]),
|
|
99
|
+
],
|
|
100
|
+
}]
|
|
101
|
+
}] });
|
|
102
|
+
|
|
103
|
+
export { ReportsModule };
|
|
104
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs","sources":["../../../projects/admin/src/lib/pages/reports/reports.component.ts","../../../projects/admin/src/lib/pages/reports/reports.component.html","../../../projects/admin/src/lib/pages/reports/reports.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, using } from '@thescaffold/ngx-core';\nimport { takeUntil } from 'rxjs';\n\ntype TabKey =\n | 'commerce'\n | 'funnel'\n | 'search'\n | 'tools'\n | 'inventory'\n | 'operations';\n\ninterface Tab {\n key: TabKey;\n label: string;\n ana: string;\n hasRange: boolean;\n}\n\nconst TABS: Tab[] = [\n { key: 'commerce', label: 'Commerce', ana: 'ANA-01', hasRange: true },\n { key: 'funnel', label: 'Funnel', ana: 'ANA-02', hasRange: true },\n { key: 'search', label: 'Search', ana: 'ANA-03', hasRange: true },\n { key: 'tools', label: 'Tools', ana: 'ANA-04', hasRange: true },\n { key: 'inventory', label: 'Inventory', ana: 'ANA-05', hasRange: false },\n { key: 'operations', label: 'Operations', ana: 'ANA-09', hasRange: true },\n];\n\n// P7.4 — the ANA-* analytics dashboard. Each tab reads one\n// `apps/admin/analytics/*` read model (raw SQL over the commerce tables,\n// libs/admin). ANA-11 web analytics / campaign attribution lives in\n// Countly, not here.\n@Component({\n standalone: false,\n selector: 'x-reports',\n templateUrl: './reports.component.html',\n})\nexport class ReportsComponent extends BaseDirective {\n private readonly source = this.apiService.on('apps/admin/analytics');\n\n readonly tabs = TABS;\n active: TabKey = 'commerce';\n days = 30;\n loading = true;\n data: any = null;\n\n override init = () => {\n this.load();\n };\n\n get activeTab(): Tab {\n return TABS.find((t) => t.key === this.active)!;\n }\n\n select(key: TabKey): void {\n if (this.active === key) return;\n this.active = key;\n this.load();\n }\n\n setDays(days: number): void {\n this.days = days;\n this.load();\n }\n\n load(): void {\n this.loading = true;\n this.data = null;\n const path = this.activeTab.hasRange\n ? `${this.active}?days=${this.days}`\n : this.active;\n this.source\n .getOne(path)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n this.data = res?.data ?? null;\n this.loading = false;\n }),\n );\n }\n\n money(n: any): string {\n const v = Number(n) || 0;\n return `₦${v.toLocaleString('en-NG', { maximumFractionDigits: 0 })}`;\n }\n\n num(n: any): string {\n return (Number(n) || 0).toLocaleString('en-NG');\n }\n\n keys(obj: any): string[] {\n return obj ? Object.keys(obj) : [];\n }\n\n humanize(key: string): string {\n return key.replace(/_/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n }\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">Reports</div>\n <div class=\"x-page-subtitle\">\n Analytics read models over the commerce tables. Web traffic, sessions and\n campaign attribution are in Countly (ANA-11).\n </div>\n</div>\n\n<nav class=\"x-rp-tabs\">\n @for (t of tabs; track t.key) {\n <button\n type=\"button\"\n class=\"x-rp-tab\"\n [class.is-active]=\"active === t.key\"\n (click)=\"select(t.key)\"\n >\n {{ t.label }} <span class=\"x-rp-ana\">{{ t.ana }}</span>\n </button>\n }\n</nav>\n\n@if (activeTab.hasRange) {\n <div class=\"x-rp-range\">\n @for (d of [7, 30, 90]; track d) {\n <button\n type=\"button\"\n class=\"x-rp-range-btn\"\n [class.is-active]=\"days === d\"\n (click)=\"setDays(d)\"\n >\n {{ d }}d\n </button>\n }\n </div>\n}\n\n@if (loading) {\n <x-element-loader></x-element-loader>\n} @else if (!data) {\n <p class=\"x-rp-empty\">No data.</p>\n} @else {\n <!-- summary blocks: any object of scalars renders as cards -->\n @for (block of ['summary', 'fulfilment', 'returns', 'support', 'toolRevenue', 'compatibilityChecks']; track block) {\n @if (data[block] && keys(data[block]).length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-cards\">\n @for (k of keys(data[block]); track k) {\n <div class=\"x-rp-card\">\n <div class=\"x-rp-card-label\">{{ humanize(k) }}</div>\n <div class=\"x-rp-card-value\">\n @if (k.includes('revenue') || k.includes('value') || k.includes('aov') || k.includes('discount')) {\n {{ money(data[block][k]) }}\n } @else {\n {{ num(data[block][k]) }}\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- funnel -->\n @if (data.stages) {\n <div class=\"x-rp-section-label\">Checkout funnel</div>\n @if (data.note) { <p class=\"x-rp-note\">{{ data.note }}</p> }\n <table class=\"x-rp-table\">\n <thead><tr><th>Stage</th><th>Count</th><th>% of top</th><th>Drop from previous</th></tr></thead>\n <tbody>\n @for (s of data.stages; track s.key) {\n <tr>\n <td>{{ s.label }}</td>\n <td>{{ num(s.value) }}</td>\n <td>{{ s.conversionFromTop }}%</td>\n <td [class.x-rp-drop]=\"s.dropFromPrev > 0\">{{ s.dropFromPrev }}%</td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n <!-- generic array tables -->\n @for (block of ['byDay', 'byChannel', 'byPaymentMethod', 'byCategory', 'byType', 'byMethod', 'topQueries', 'zeroResult', 'blockFrequency', 'worstStockouts']; track block) {\n @if (data[block] && data[block].length) {\n <div class=\"x-rp-section-label\">{{ humanize(block) }}</div>\n <div class=\"x-rp-table-wrap\">\n <table class=\"x-rp-table\">\n <thead>\n <tr>\n @for (col of keys(data[block][0]); track col) {\n <th>{{ humanize(col) }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data[block]; track $index) {\n <tr>\n @for (col of keys(row); track col) {\n <td>\n @if (col.includes('revenue') || col.includes('amount')) {\n {{ money(row[col]) }}\n } @else {\n {{ row[col] }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n}\n\n<style>\n .x-page-head { 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; max-width: 640px; }\n\n .x-rp-tabs { display: flex; flex-wrap: wrap; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: 14px; }\n .x-rp-tab { appearance: none; background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 8px 12px; font-size: 13.5px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-tab.is-active { color: var(--color-text); border-bottom-color: var(--color-brand); }\n .x-rp-ana { font-size: 10px; opacity: 0.6; font-weight: 500; }\n\n .x-rp-range { display: flex; gap: 6px; margin-bottom: 18px; }\n .x-rp-range-btn { appearance: none; background: transparent; border: 1px solid var(--color-border); border-radius: 999px; padding: 3px 12px; font-size: 12px; font-weight: 600; color: var(--color-text-muted); cursor: pointer; }\n .x-rp-range-btn.is-active { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }\n\n .x-rp-section-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; color: var(--color-text-muted); margin: 24px 0 10px; }\n .x-rp-note { font-size: 12.5px; color: var(--color-text-muted); margin: -4px 0 10px; }\n .x-rp-empty { font-size: 13px; color: var(--color-text-muted); }\n\n .x-rp-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 10px; }\n .x-rp-card { border: 1px solid var(--color-border); border-radius: 10px; padding: 10px 14px; }\n .x-rp-card-label { font-size: 11.5px; color: var(--color-text-muted); }\n .x-rp-card-value { font-size: 19px; font-weight: 800; color: var(--color-text); margin-top: 3px; }\n\n .x-rp-table-wrap { overflow-x: auto; }\n .x-rp-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n .x-rp-table th, .x-rp-table td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--color-border); white-space: nowrap; }\n .x-rp-table th { color: var(--color-text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; }\n .x-rp-drop { color: var(--color-danger, #c0392b); font-weight: 600; }\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 { ReportsComponent } from './reports.component';\n\n@NgModule({\n declarations: [ReportsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n RouterModule.forChild([{ path: '', component: ReportsComponent }]),\n ],\n})\nexport class ReportsModule {}\n"],"names":["i1"],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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, titleCase, SharedModule } from '@thescaffold/ngx-core';
|
|
6
|
+
import * as i1 from '@thescaffold/ngx-ui';
|
|
7
|
+
import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
|
|
8
|
+
import { BehaviorSubject, takeUntil, map } from 'rxjs';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
|
|
11
|
+
// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list
|
|
12
|
+
// view on `x-webget-collection` over `apps/commerce/return-request`, matching the
|
|
13
|
+
// established admin pattern (users, routes, inbox). ops CRUD is covered
|
|
14
|
+
// by `admin:*:apps:commerce:*`.
|
|
15
|
+
class ReturnsComponent extends BaseDirective {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.pluralName = 'returns';
|
|
19
|
+
this.dataSource = this.apiService.on('apps/commerce/return-request');
|
|
20
|
+
this.columns = [
|
|
21
|
+
{ key: 'rmaNumber', value: 'RMA' },
|
|
22
|
+
{ key: 'orderId', value: 'Order' },
|
|
23
|
+
{ key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },
|
|
24
|
+
{ key: 'createdAt', value: 'Opened', type: 'date' },
|
|
25
|
+
];
|
|
26
|
+
this.page = 1;
|
|
27
|
+
this.perPage = 25;
|
|
28
|
+
this.list$ = new BehaviorSubject(null);
|
|
29
|
+
this.init = () => {
|
|
30
|
+
this.list();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
list(page = this.page, perPage = this.perPage) {
|
|
34
|
+
this.dataSource
|
|
35
|
+
.getMany({ page, perPage })
|
|
36
|
+
.pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
|
|
37
|
+
.subscribe(using((data) => this.list$.next(data)));
|
|
38
|
+
}
|
|
39
|
+
toCollection(response) {
|
|
40
|
+
return {
|
|
41
|
+
title: titleCase(this.pluralName),
|
|
42
|
+
columns: this.columns,
|
|
43
|
+
rows: response?.data,
|
|
44
|
+
hasHeaders: true,
|
|
45
|
+
hasTextFilter: true,
|
|
46
|
+
page: response?.meta?.current_page,
|
|
47
|
+
perPage: response?.meta?.per_page,
|
|
48
|
+
total: response?.meta?.total,
|
|
49
|
+
onPage: (page) => this.list(page),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
53
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ReturnsComponent, isStandalone: false, selector: "x-returns", usesInheritance: true, ngImport: i0, template: `
|
|
54
|
+
<div class="x-page-head">
|
|
55
|
+
<div class="x-page-title">Returns</div>
|
|
56
|
+
<div class="x-page-subtitle">RMA requests against delivered orders — triage, method and resolution.</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
@if (list$ | async; as list) {
|
|
60
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
61
|
+
} @else {
|
|
62
|
+
<x-element-loader></x-element-loader>
|
|
63
|
+
}
|
|
64
|
+
`, isInline: true, 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}\n"], dependencies: [{ kind: "component", type: i1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i1.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
|
|
65
|
+
}
|
|
66
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsComponent, decorators: [{
|
|
67
|
+
type: Component,
|
|
68
|
+
args: [{ standalone: false, selector: 'x-returns', template: `
|
|
69
|
+
<div class="x-page-head">
|
|
70
|
+
<div class="x-page-title">Returns</div>
|
|
71
|
+
<div class="x-page-subtitle">RMA requests against delivered orders — triage, method and resolution.</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
@if (list$ | async; as list) {
|
|
75
|
+
<x-webget-collection [data]="list"></x-webget-collection>
|
|
76
|
+
} @else {
|
|
77
|
+
<x-element-loader></x-element-loader>
|
|
78
|
+
}
|
|
79
|
+
`, 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}\n"] }]
|
|
80
|
+
}] });
|
|
81
|
+
|
|
82
|
+
class ReturnsModule {
|
|
83
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
84
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, declarations: [ReturnsComponent], imports: [SharedModule,
|
|
85
|
+
ElementsModule,
|
|
86
|
+
WebgetsModule, i1$1.RouterModule] }); }
|
|
87
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, imports: [SharedModule,
|
|
88
|
+
ElementsModule,
|
|
89
|
+
WebgetsModule,
|
|
90
|
+
RouterModule.forChild([{ path: '', component: ReturnsComponent }])] }); }
|
|
91
|
+
}
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, decorators: [{
|
|
93
|
+
type: NgModule,
|
|
94
|
+
args: [{
|
|
95
|
+
declarations: [ReturnsComponent],
|
|
96
|
+
imports: [
|
|
97
|
+
SharedModule,
|
|
98
|
+
ElementsModule,
|
|
99
|
+
WebgetsModule,
|
|
100
|
+
RouterModule.forChild([{ path: '', component: ReturnsComponent }]),
|
|
101
|
+
],
|
|
102
|
+
}]
|
|
103
|
+
}] });
|
|
104
|
+
|
|
105
|
+
export { ReturnsModule };
|
|
106
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs","sources":["../../../projects/admin/src/lib/pages/returns/returns.component.ts","../../../projects/admin/src/lib/pages/returns/returns.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, map, takeUntil } from 'rxjs';\n\n// P7.1 — ops console section pass (PRD 6.2, TRD 9.2). A standard list\n// view on `x-webget-collection` over `apps/commerce/return-request`, matching the\n// established admin pattern (users, routes, inbox). ops CRUD is covered\n// by `admin:*:apps:commerce:*`.\n@Component({\n standalone: false,\n selector: 'x-returns',\n template: `\n <div class=\"x-page-head\">\n <div class=\"x-page-title\">Returns</div>\n <div class=\"x-page-subtitle\">RMA requests against delivered orders — triage, method and resolution.</div>\n </div>\n\n @if (list$ | async; as list) {\n <x-webget-collection [data]=\"list\"></x-webget-collection>\n } @else {\n <x-element-loader></x-element-loader>\n }\n `,\n styles: [\n `\n .x-page-head {\n margin-bottom: 20px;\n }\n .x-page-title {\n font-size: 24px;\n font-weight: 800;\n color: var(--color-text);\n }\n .x-page-subtitle {\n font-size: 13.5px;\n color: var(--color-text-muted);\n margin-top: 2px;\n }\n `,\n ],\n})\nexport class ReturnsComponent extends BaseDirective {\n pluralName = 'returns';\n dataSource = this.apiService.on('apps/commerce/return-request');\n\n columns = [\n { key: 'rmaNumber', value: 'RMA' },\n { key: 'orderId', value: 'Order' },\n { key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },\n { key: 'createdAt', value: 'Opened', type: 'date' },\n ];\n\n page = 1;\n perPage = 25;\n\n list$ = new BehaviorSubject<any>(null);\n\n override init = () => {\n this.list();\n };\n\n list(page = this.page, perPage = this.perPage) {\n this.dataSource\n .getMany({ page, perPage })\n .pipe(\n takeUntil(this.$),\n map((response) => this.toCollection(response)),\n )\n .subscribe(using((data) => this.list$.next(data)));\n }\n\n private toCollection(response: any) {\n return {\n title: titleCase(this.pluralName),\n columns: this.columns,\n rows: response?.data,\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 };\n }\n}\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 { ReturnsComponent } from './returns.component';\n\n@NgModule({\n declarations: [ReturnsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: ReturnsComponent }]),\n ],\n})\nexport class ReturnsModule {}\n"],"names":["i1"],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, Output, Input, Component, NgModule } from '@angular/core';
|
|
3
|
+
import '@thescaffold/editor-core/define';
|
|
4
|
+
|
|
5
|
+
// P6.10 — a thin Angular host for `@thescaffold/editor-core`'s
|
|
6
|
+
// `<x-editor>` custom element. `@thescaffold/editor-angular` ships
|
|
7
|
+
// source-only (no build) so it can't be consumed as a package; this is
|
|
8
|
+
// the same handful of lines its `EditorComponent` uses. `content` is
|
|
9
|
+
// HTML in, HTML out via `contentChange`.
|
|
10
|
+
class RichEditorComponent {
|
|
11
|
+
constructor(host, zone) {
|
|
12
|
+
this.host = host;
|
|
13
|
+
this.zone = zone;
|
|
14
|
+
this.content = '';
|
|
15
|
+
this.contentChange = new EventEmitter();
|
|
16
|
+
this.el = null;
|
|
17
|
+
this.ctx = null;
|
|
18
|
+
}
|
|
19
|
+
ngAfterViewInit() {
|
|
20
|
+
this.zone.runOutsideAngular(() => {
|
|
21
|
+
const editor = document.createElement('x-editor');
|
|
22
|
+
editor.style.height = '100%';
|
|
23
|
+
this.host.nativeElement.appendChild(editor);
|
|
24
|
+
this.el = editor;
|
|
25
|
+
editor.addEventListener('xe:ready', (event) => {
|
|
26
|
+
this.ctx = event.detail?.editor ?? null;
|
|
27
|
+
if (this.content)
|
|
28
|
+
this.ctx?.setContent(this.content, 'html');
|
|
29
|
+
});
|
|
30
|
+
editor.addEventListener('xe:change', (event) => {
|
|
31
|
+
const next = event.detail?.content ?? '';
|
|
32
|
+
this.zone.run(() => this.contentChange.emit(next));
|
|
33
|
+
});
|
|
34
|
+
editor.config = {
|
|
35
|
+
mode: 'doc',
|
|
36
|
+
content: this.content,
|
|
37
|
+
editable: true,
|
|
38
|
+
theme: 'auto',
|
|
39
|
+
addons: [],
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
ngOnChanges(changes) {
|
|
44
|
+
if (changes['content'] && !changes['content'].firstChange && this.ctx) {
|
|
45
|
+
this.ctx.setContent(this.content ?? '', 'html');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
ngOnDestroy() {
|
|
49
|
+
this.el?.remove();
|
|
50
|
+
this.el = null;
|
|
51
|
+
this.ctx = null;
|
|
52
|
+
}
|
|
53
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RichEditorComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
54
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.16", type: RichEditorComponent, isStandalone: false, selector: "x-rich-editor", inputs: { content: "content" }, outputs: { contentChange: "contentChange" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, styles: [":host{display:block;min-height:160px}\n"] }); }
|
|
55
|
+
}
|
|
56
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RichEditorComponent, decorators: [{
|
|
57
|
+
type: Component,
|
|
58
|
+
args: [{ standalone: false, selector: 'x-rich-editor', template: '', styles: [":host{display:block;min-height:160px}\n"] }]
|
|
59
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { content: [{
|
|
60
|
+
type: Input
|
|
61
|
+
}], contentChange: [{
|
|
62
|
+
type: Output
|
|
63
|
+
}] } });
|
|
64
|
+
|
|
65
|
+
// P6.10 — shared WYSIWYG host, used by the CMS page builder (`content`)
|
|
66
|
+
// and the Learn-hub article editor (`articles`).
|
|
67
|
+
class RichEditorModule {
|
|
68
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RichEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
69
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: RichEditorModule, declarations: [RichEditorComponent], exports: [RichEditorComponent] }); }
|
|
70
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RichEditorModule }); }
|
|
71
|
+
}
|
|
72
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RichEditorModule, decorators: [{
|
|
73
|
+
type: NgModule,
|
|
74
|
+
args: [{
|
|
75
|
+
declarations: [RichEditorComponent],
|
|
76
|
+
exports: [RichEditorComponent],
|
|
77
|
+
}]
|
|
78
|
+
}] });
|
|
79
|
+
|
|
80
|
+
export { RichEditorComponent as R, RichEditorModule as a };
|
|
81
|
+
//# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-rich-editor.module-DW9Gy_QQ.mjs.map
|