@isaiahiroko/tilmart-ngx-apps-admin 0.2.0 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs} +5 -5
  2. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-articles.module-OeLRnPwN.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-articles.module-Cpx9BZcg.mjs.map} +1 -1
  3. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs +239 -0
  4. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-attribute-templates.module-CwQnW1cH.mjs.map +1 -0
  5. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs} +6 -6
  6. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-audit.module-C9gvw8X2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-audit.module-D5YaCThD.mjs.map} +1 -1
  7. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs +76 -0
  8. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-banners.module-KSapnx6Y.mjs.map +1 -0
  9. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs +70 -0
  10. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-brands.module-7I0ni-tQ.mjs.map +1 -0
  11. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-bulk-upload.module-BGTbsYUP.mjs +370 -0
  12. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-bulk-upload.module-BGTbsYUP.mjs.map +1 -0
  13. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-BwjfFXDU.mjs +562 -0
  14. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-BwjfFXDU.mjs.map +1 -0
  15. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs +94 -0
  16. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-categories.module-OTUfenf0.mjs.map +1 -0
  17. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs +137 -0
  18. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Dk9mz7Wj.mjs.map +1 -0
  19. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs} +6 -6
  20. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-xN-JUWwp.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-compatibility-rules.module-JiFnNJj_.mjs.map} +1 -1
  21. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs} +5 -5
  22. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-content.module-DLdKAUqc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-content.module-Bx6Zj0WX.mjs.map} +1 -1
  23. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs +85 -0
  24. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CoRh6Hxq.mjs.map +1 -0
  25. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs +123 -0
  26. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-CslGiOdq.mjs.map +1 -0
  27. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs} +6 -6
  28. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-Bfgh3zE5.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-quality.module-CvFmMoJe.mjs.map} +1 -1
  29. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs} +6 -6
  30. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-C6tPNlup.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-data-requests.module-CuZwNVPO.mjs.map} +1 -1
  31. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs +83 -0
  32. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-flash-sales.module-BPRnC17l.mjs.map +1 -0
  33. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs} +5 -5
  34. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-homepage.module-BZ3UmxE3.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-homepage.module-vtAoIwSu.mjs.map} +1 -1
  35. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs} +6 -6
  36. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-inbox.module-BZDTa1L-.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-inbox.module-CRkfjWQT.mjs.map} +1 -1
  37. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs +66 -0
  38. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs.map +1 -0
  39. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs} +5 -5
  40. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-macros.module-BO4bdER2.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-macros.module-CElxL9W4.mjs.map} +1 -1
  41. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs} +6 -6
  42. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-moderation.module-CZOCrias.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-moderation.module-PGmFX7nk.mjs.map} +1 -1
  43. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs} +6 -6
  44. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-navigation.module-DoKzzRgn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-navigation.module-De1Cvqqa.mjs.map} +1 -1
  45. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs} +4 -4
  46. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-order-board.module-DIOjhptn.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-order-board.module-CmLNiEEP.mjs.map} +1 -1
  47. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-vldWwcAr.mjs +190 -0
  48. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-vldWwcAr.mjs.map +1 -0
  49. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs +114 -0
  50. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-DstLDYM7.mjs.map +1 -0
  51. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs +94 -0
  52. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG03OY1q.mjs.map +1 -0
  53. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs} +6 -6
  54. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-queues.module-K-zYYVFy.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-queues.module-D7iLwX0A.mjs.map} +1 -1
  55. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs +78 -0
  56. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs.map +1 -0
  57. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs → isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs} +9 -34
  58. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs.map +1 -0
  59. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs} +5 -5
  60. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs.map} +1 -1
  61. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs +163 -0
  62. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs.map +1 -0
  63. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs +81 -0
  64. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs.map +1 -0
  65. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs +318 -0
  66. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs.map +1 -0
  67. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs → isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs} +13 -32
  68. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs.map +1 -0
  69. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs +140 -0
  70. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs.map +1 -0
  71. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs +102 -0
  72. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-Bt9W1oGR.mjs.map +1 -0
  73. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs} +6 -6
  74. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-trace.module-Pwr-82Rc.mjs.map → isaiahiroko-tilmart-ngx-apps-admin-trace.module-9sRlGZCC.mjs.map} +1 -1
  75. package/fesm2022/{isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs → isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs} +9 -34
  76. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-C31RJJJ_.mjs.map +1 -0
  77. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs +104 -72
  78. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin.mjs.map +1 -1
  79. package/package.json +1 -1
  80. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs +0 -294
  81. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-baskets.module-_lHPl1dT.mjs.map +0 -1
  82. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs +0 -224
  83. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-catalog.module-Bvx2tVOi.mjs.map +0 -1
  84. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs +0 -106
  85. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-claims.module-Ccsd8Yx3.mjs.map +0 -1
  86. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs +0 -106
  87. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-coupons.module-CQNCSlsd.mjs.map +0 -1
  88. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs +0 -106
  89. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-customers.module-12XdV9zo.mjs.map +0 -1
  90. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs +0 -185
  91. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-orders.module-Ddw49QW0.mjs.map +0 -1
  92. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs +0 -106
  93. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-payments.module-BhqAtTZs.mjs.map +0 -1
  94. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs +0 -274
  95. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-procurement.module-qXW-g0pf.mjs.map +0 -1
  96. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs +0 -106
  97. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-promotions.module-DG9uTDqX.mjs.map +0 -1
  98. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs +0 -106
  99. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-redirects.module-Hm2dO_bC.mjs.map +0 -1
  100. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map +0 -1
  101. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs +0 -106
  102. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-returns.module-Bd2gdo6_.mjs.map +0 -1
  103. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs +0 -105
  104. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-routes.module-BkVY06ci.mjs.map +0 -1
  105. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs +0 -222
  106. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-settings.module-DKeZTldO.mjs.map +0 -1
  107. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map +0 -1
  108. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs +0 -107
  109. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-stock.module-DYiAkF7E.mjs.map +0 -1
  110. package/fesm2022/isaiahiroko-tilmart-ngx-apps-admin-users.module-Bx_7fI2g.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-redirects.module-oQw5Xo5T.mjs","sources":["../../../projects/admin/src/lib/pages/redirects/redirects.component.ts","../../../projects/admin/src/lib/pages/_shared/simple-crud.component.html","../../../projects/admin/src/lib/pages/redirects/redirects.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { CrudFieldSpec, SimpleCrudDirective } from '../_shared/simple-crud.base';\n\n// R1 production-readiness pass — CMS-06. Auto-minted on a slug change;\n// was list-only otherwise, with no way for ops to add one manually to\n// fix a stray 404.\n@Component({\n standalone: false,\n selector: 'x-redirects',\n templateUrl: '../_shared/simple-crud.component.html',\n styleUrl: '../_shared/simple-crud.component.scss',\n})\nexport class RedirectsComponent extends SimpleCrudDirective {\n protected pageTitle = 'Redirects';\n protected pageSubtitle = 'Stored 301/302 path redirects — auto-minted on slug changes (CMS-06), or add one by hand.';\n protected singularLabel = 'redirect';\n protected pluralName = 'redirects';\n protected dataSource = this.apiService.on('apps/commerce/redirect');\n\n protected columns = [\n { key: 'fromPath', value: 'From' },\n { key: 'toPath', value: 'To' },\n { key: 'statusCode', value: 'Code' },\n { key: 'hitCount', value: 'Hits' },\n ];\n\n protected fields: CrudFieldSpec[] = [\n { key: 'fromPath', label: 'From path', type: 'text', required: true, placeholder: '/p/old-slug' },\n { key: 'toPath', label: 'To path', type: 'text', required: true, placeholder: '/p/new-slug' },\n {\n key: 'statusCode',\n label: 'Status code',\n type: 'select',\n numericSelect: true,\n options: [\n { value: '301', label: '301 — Permanent' },\n { value: '302', label: '302 — Temporary' },\n ],\n },\n { key: 'reason', label: 'Reason', type: 'text' },\n { key: 'enabled', label: 'Enabled', type: 'boolean' },\n ];\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\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} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">— choose —</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\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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"}
@@ -1,15 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, NgModule } from '@angular/core';
3
- import * as i1$1 from '@angular/router';
3
+ import * as i1 from '@angular/router';
4
4
  import { RouterModule } from '@angular/router';
5
- import { BaseDirective, using, titleCase, SharedModule } from '@thescaffold/ngx-core';
6
- import * as i1 from '@thescaffold/ngx-ui';
5
+ import { SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
7
  import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
- import { BehaviorSubject, takeUntil, map } from 'rxjs';
9
- import * as i2 from '@angular/common';
8
+ import { L as ListPageDirective } from './isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs';
9
+ import * as i3 from '@angular/common';
10
10
 
11
11
  // Referral/reward view (docs/TRD.md §7).
12
- class ReferralsComponent extends BaseDirective {
12
+ class ReferralsComponent extends ListPageDirective {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.name = 'referral';
@@ -23,31 +23,6 @@ class ReferralsComponent extends BaseDirective {
23
23
  { key: 'convertedAt', value: 'Converted', type: 'date' },
24
24
  { key: 'createdAt', value: 'Referred on', type: 'date' },
25
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
26
  }
52
27
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
53
28
  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: `
@@ -61,7 +36,7 @@ class ReferralsComponent extends BaseDirective {
61
36
  } @else {
62
37
  <x-element-loader></x-element-loader>
63
38
  }
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" }] }); }
39
+ `, 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: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i2.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
65
40
  }
66
41
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsComponent, decorators: [{
67
42
  type: Component,
@@ -83,7 +58,7 @@ class ReferralsModule {
83
58
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
84
59
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, declarations: [ReferralsComponent], imports: [SharedModule,
85
60
  ElementsModule,
86
- WebgetsModule, i1$1.RouterModule] }); }
61
+ WebgetsModule, i1.RouterModule] }); }
87
62
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReferralsModule, imports: [SharedModule,
88
63
  ElementsModule,
89
64
  WebgetsModule,
@@ -103,4 +78,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
103
78
  }] });
104
79
 
105
80
  export { ReferralsModule };
106
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-referrals.module-QLNhuh7q.mjs.map
81
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-referrals.module-BIAY4L_u.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 { ListPageDirective } from '../_shared/list-page.base';\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 ListPageDirective {\n name = 'referral';\n protected pluralName = 'referrals';\n // P5.14 — the commerce Referral (ACC-11); the Salama grocery route is gone.\n protected dataSource = this.apiService.on('apps/commerce/referral');\n\n protected 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}\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","i2"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, NgModule } from '@angular/core';
3
- import * as i1$1 from '@angular/router';
3
+ import * as i1 from '@angular/router';
4
4
  import { RouterModule } from '@angular/router';
5
5
  import { BaseDirective, using, SharedModule } from '@thescaffold/ngx-core';
6
- import * as i1 from '@thescaffold/ngx-ui';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
7
  import { ElementsModule } from '@thescaffold/ngx-ui';
8
8
  import { takeUntil } from 'rxjs';
9
9
 
@@ -73,7 +73,7 @@ class ReportsComponent extends BaseDirective {
73
73
  return key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
74
74
  }
75
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"] }] }); }
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: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }] }); }
77
77
  }
78
78
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsComponent, decorators: [{
79
79
  type: Component,
@@ -83,7 +83,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
83
83
  class ReportsModule {
84
84
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
85
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] }); }
86
+ ElementsModule, i1.RouterModule] }); }
87
87
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReportsModule, imports: [SharedModule,
88
88
  ElementsModule,
89
89
  RouterModule.forChild([{ path: '', component: ReportsComponent }])] }); }
@@ -101,4 +101,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
101
101
  }] });
102
102
 
103
103
  export { ReportsModule };
104
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-reports.module-DBZov0We.mjs.map
104
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.mjs.map
@@ -1 +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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"}
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-reports.module-DORiIVLQ.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,163 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, TemplateRef, ViewChild, Component, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { notify, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
+ import { FlyoutService, ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
+ import { firstValueFrom } from 'rxjs';
9
+ import { L as ListPageDirective } from './isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs';
10
+ import * as i1 from '@angular/forms';
11
+ import * as i3 from '@angular/common';
12
+
13
+ // R1 production-readiness pass — RET-03/RET-04. The backend workflow
14
+ // (`ReturnsWorkflow.inspect`/`.resolve`, `return-request.controller.ts`)
15
+ // was already complete; this was the single biggest "list with zero
16
+ // actions" gap the audit found — ops could see an RMA existed but had no
17
+ // way to record an inspection outcome or close it out. Same
18
+ // detail-flyout + action pattern as Orders/Shipments.
19
+ class ReturnsComponent extends ListPageDirective {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.flyoutService = inject(FlyoutService);
23
+ this.pluralName = 'returns';
24
+ this.dataSource = this.apiService.on('apps/commerce/return-request');
25
+ this.lineSource = this.apiService.on('apps/commerce/return-line');
26
+ this.orderLineSource = this.apiService.on('apps/commerce/order-line');
27
+ this.columns = [
28
+ { key: 'rmaNumber', value: 'RMA' },
29
+ { key: 'orderId', value: 'Order' },
30
+ { key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },
31
+ { key: 'createdAt', value: 'Opened', type: 'date' },
32
+ ];
33
+ this.detail = null;
34
+ this.lines = [];
35
+ this.saving = false;
36
+ this.resolution = 'refund';
37
+ this.refundAmount = null;
38
+ this.resolveNote = '';
39
+ this.outcomes = ['pending', 'accept', 'reject', 'partial'];
40
+ this.dispositions = ['restock', 'quarantine', 'scrap', 'return_to_seller'];
41
+ this.resolutions = ['refund', 'replacement', 'exchange', 'reject'];
42
+ }
43
+ extraCollectionFields() {
44
+ return {
45
+ links: {
46
+ secondary: [{ title: 'View', fn: (_link, item) => this.view(item) }],
47
+ },
48
+ };
49
+ }
50
+ async view(item) {
51
+ this.detail = null;
52
+ this.lines = [];
53
+ this.resolution = 'refund';
54
+ this.refundAmount = null;
55
+ this.resolveNote = '';
56
+ this.flyoutService.open(this.detailFlyout);
57
+ const detailRes = await firstValueFrom(this.dataSource.getOne(item.id));
58
+ this.detail = detailRes?.data ?? item;
59
+ const [linesRes, orderLinesRes] = await Promise.all([
60
+ firstValueFrom(this.lineSource.getMany({ returnRequestId: item.id, page: 1, perPage: 100 })),
61
+ firstValueFrom(this.orderLineSource.getMany({ orderId: this.detail.orderId, page: 1, perPage: 200 })),
62
+ ]);
63
+ const nameByOrderLineId = new Map((orderLinesRes?.data ?? []).map((ol) => [ol.id, ol.nameSnapshot || ol.variantId]));
64
+ this.lines = (linesRes?.data ?? []).map((l) => ({
65
+ id: l.id,
66
+ orderLineId: l.orderLineId,
67
+ itemName: nameByOrderLineId.get(l.orderLineId) || l.orderLineId,
68
+ quantity: l.quantity,
69
+ inspectionOutcome: l.inspectionOutcome || 'pending',
70
+ acceptedQuantity: l.acceptedQuantity,
71
+ disposition: l.disposition || '',
72
+ note: l.note || '',
73
+ }));
74
+ }
75
+ async saveInspection() {
76
+ if (!this.detail)
77
+ return;
78
+ this.saving = true;
79
+ try {
80
+ const res = await firstValueFrom(this.apiService.post(`apps/commerce/return-request/${this.detail.id}/inspect`, {
81
+ lines: this.lines.map((l) => ({
82
+ returnLineId: l.id,
83
+ outcome: l.inspectionOutcome,
84
+ acceptedQuantity: l.acceptedQuantity != null ? Number(l.acceptedQuantity) : undefined,
85
+ disposition: l.disposition || undefined,
86
+ note: l.note || undefined,
87
+ })),
88
+ }));
89
+ if (res?.status === 'error') {
90
+ notify(res.message || 'Could not save the inspection.', undefined, 'error');
91
+ return;
92
+ }
93
+ notify('Inspection saved.', undefined, 'success');
94
+ this.list(this.page, this.perPage);
95
+ }
96
+ catch {
97
+ notify('Could not save the inspection.', undefined, 'error');
98
+ }
99
+ finally {
100
+ this.saving = false;
101
+ }
102
+ }
103
+ async resolveReturn() {
104
+ if (!this.detail)
105
+ return;
106
+ this.saving = true;
107
+ try {
108
+ const res = await firstValueFrom(this.apiService.post(`apps/commerce/return-request/${this.detail.id}/resolve`, {
109
+ resolution: this.resolution,
110
+ refundAmount: this.refundAmount != null ? Number(this.refundAmount) : undefined,
111
+ note: this.resolveNote || undefined,
112
+ }));
113
+ if (res?.status === 'error') {
114
+ notify(res.message || 'Could not resolve the return.', undefined, 'error');
115
+ return;
116
+ }
117
+ notify('Return resolved.', undefined, 'success');
118
+ this.flyoutService.dismiss();
119
+ this.list(this.page, this.perPage);
120
+ }
121
+ catch {
122
+ notify('Could not resolve the return.', undefined, 'error');
123
+ }
124
+ finally {
125
+ this.saving = false;
126
+ }
127
+ }
128
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
129
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ReturnsComponent, isStandalone: false, selector: "x-returns", viewQueries: [{ propertyName: "detailFlyout", first: true, predicate: ["detailFlyout"], descendants: true, read: TemplateRef, static: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Returns</div>\n <div class=\"x-page-subtitle\">RMA requests against delivered orders \u2014 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<ng-template #detailFlyout>\n <x-webget-flyout [data]=\"{ title: 'Return detail' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <div class=\"fw-bold font-monospace\">{{ detail.rmaNumber }}</div>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.status }}</span>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.reasonCode }}</span>\n </div>\n\n <div>\n <div class=\"fw-bold small mb-1\">Lines</div>\n @for (line of lines; track line.id) {\n <div class=\"border rounded p-2 mb-2 small\">\n <div class=\"fw-bold\">{{ line.itemName }} \u00B7 qty {{ line.quantity }}</div>\n <div class=\"d-flex flex-wrap gap-2 mt-1\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.inspectionOutcome\">\n @for (o of outcomes; track o) { <option [value]=\"o\">{{ o }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:110px\"\n placeholder=\"accepted qty\"\n [(ngModel)]=\"line.acceptedQuantity\"\n />\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.disposition\">\n <option value=\"\">\u2014 disposition \u2014</option>\n @for (d of dispositions; track d) { <option [value]=\"d\">{{ d }}</option> }\n </select>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"line.note\"\n />\n </div>\n </div>\n } @empty {\n <div class=\"text-secondary small\">No lines.</div>\n }\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" [disabled]=\"saving\" (click)=\"saveInspection()\">\n Save inspection\n </button>\n </div>\n\n <hr class=\"my-1\" />\n\n <div>\n <div class=\"fw-bold small mb-1\">Resolve</div>\n <div class=\"d-flex flex-wrap gap-2\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"resolution\">\n @for (r of resolutions; track r) { <option [value]=\"r\">{{ r }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:140px\"\n placeholder=\"refund amount (\u20A6)\"\n [(ngModel)]=\"refundAmount\"\n />\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"resolveNote\"\n />\n </div>\n <button type=\"button\" class=\"btn btn-sm btn-dark mt-2\" [disabled]=\"saving\" (click)=\"resolveReturn()\">\n Resolve return\n </button>\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n </div>\n </x-webget-flyout>\n</ng-template>\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}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i2.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "component", type: i2.FlyoutComponent, selector: "x-webget-flyout", inputs: ["data"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
130
+ }
131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsComponent, decorators: [{
132
+ type: Component,
133
+ args: [{ standalone: false, selector: 'x-returns', template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Returns</div>\n <div class=\"x-page-subtitle\">RMA requests against delivered orders \u2014 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<ng-template #detailFlyout>\n <x-webget-flyout [data]=\"{ title: 'Return detail' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <div class=\"fw-bold font-monospace\">{{ detail.rmaNumber }}</div>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.status }}</span>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.reasonCode }}</span>\n </div>\n\n <div>\n <div class=\"fw-bold small mb-1\">Lines</div>\n @for (line of lines; track line.id) {\n <div class=\"border rounded p-2 mb-2 small\">\n <div class=\"fw-bold\">{{ line.itemName }} \u00B7 qty {{ line.quantity }}</div>\n <div class=\"d-flex flex-wrap gap-2 mt-1\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.inspectionOutcome\">\n @for (o of outcomes; track o) { <option [value]=\"o\">{{ o }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:110px\"\n placeholder=\"accepted qty\"\n [(ngModel)]=\"line.acceptedQuantity\"\n />\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.disposition\">\n <option value=\"\">\u2014 disposition \u2014</option>\n @for (d of dispositions; track d) { <option [value]=\"d\">{{ d }}</option> }\n </select>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"line.note\"\n />\n </div>\n </div>\n } @empty {\n <div class=\"text-secondary small\">No lines.</div>\n }\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" [disabled]=\"saving\" (click)=\"saveInspection()\">\n Save inspection\n </button>\n </div>\n\n <hr class=\"my-1\" />\n\n <div>\n <div class=\"fw-bold small mb-1\">Resolve</div>\n <div class=\"d-flex flex-wrap gap-2\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"resolution\">\n @for (r of resolutions; track r) { <option [value]=\"r\">{{ r }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:140px\"\n placeholder=\"refund amount (\u20A6)\"\n [(ngModel)]=\"refundAmount\"\n />\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"resolveNote\"\n />\n </div>\n <button type=\"button\" class=\"btn btn-sm btn-dark mt-2\" [disabled]=\"saving\" (click)=\"resolveReturn()\">\n Resolve return\n </button>\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n </div>\n </x-webget-flyout>\n</ng-template>\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}\n"] }]
134
+ }], propDecorators: { detailFlyout: [{
135
+ type: ViewChild,
136
+ args: ['detailFlyout', { read: TemplateRef, static: true }]
137
+ }] } });
138
+
139
+ class ReturnsModule {
140
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
141
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, declarations: [ReturnsComponent], imports: [SharedModule,
142
+ ElementsModule,
143
+ WebgetsModule, i1$1.RouterModule] }); }
144
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, imports: [SharedModule,
145
+ ElementsModule,
146
+ WebgetsModule,
147
+ RouterModule.forChild([{ path: '', component: ReturnsComponent }])] }); }
148
+ }
149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ReturnsModule, decorators: [{
150
+ type: NgModule,
151
+ args: [{
152
+ declarations: [ReturnsComponent],
153
+ imports: [
154
+ SharedModule,
155
+ ElementsModule,
156
+ WebgetsModule,
157
+ RouterModule.forChild([{ path: '', component: ReturnsComponent }]),
158
+ ],
159
+ }]
160
+ }] });
161
+
162
+ export { ReturnsModule };
163
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-returns.module-C9Iu9CX6.mjs","sources":["../../../projects/admin/src/lib/pages/returns/returns.component.ts","../../../projects/admin/src/lib/pages/returns/returns.component.html","../../../projects/admin/src/lib/pages/returns/returns.module.ts"],"sourcesContent":["import { Component, TemplateRef, ViewChild, inject } from '@angular/core';\nimport { notify } from '@thescaffold/ngx-core';\nimport { FlyoutService } from '@thescaffold/ngx-ui';\nimport { firstValueFrom } from 'rxjs';\nimport { ListPageDirective } from '../_shared/list-page.base';\n\ninterface LineVm {\n id: string;\n orderLineId: string;\n itemName: string;\n quantity: number;\n inspectionOutcome: string;\n acceptedQuantity?: number;\n disposition?: string;\n note?: string;\n}\n\n// R1 production-readiness pass — RET-03/RET-04. The backend workflow\n// (`ReturnsWorkflow.inspect`/`.resolve`, `return-request.controller.ts`)\n// was already complete; this was the single biggest \"list with zero\n// actions\" gap the audit found — ops could see an RMA existed but had no\n// way to record an inspection outcome or close it out. Same\n// detail-flyout + action pattern as Orders/Shipments.\n@Component({\n standalone: false,\n selector: 'x-returns',\n templateUrl: './returns.component.html',\n styleUrl: './returns.component.scss',\n})\nexport class ReturnsComponent extends ListPageDirective {\n private readonly flyoutService = inject(FlyoutService);\n\n protected pluralName = 'returns';\n protected dataSource = this.apiService.on('apps/commerce/return-request');\n private readonly lineSource = this.apiService.on('apps/commerce/return-line');\n private readonly orderLineSource = this.apiService.on('apps/commerce/order-line');\n\n protected 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 detail: any = null;\n lines: LineVm[] = [];\n saving = false;\n resolution = 'refund';\n refundAmount: number | null = null;\n resolveNote = '';\n\n readonly outcomes = ['pending', 'accept', 'reject', 'partial'];\n readonly dispositions = ['restock', 'quarantine', 'scrap', 'return_to_seller'];\n readonly resolutions = ['refund', 'replacement', 'exchange', 'reject'];\n\n @ViewChild('detailFlyout', { read: TemplateRef, static: true })\n detailFlyout!: TemplateRef<any>;\n\n protected override extraCollectionFields() {\n return {\n links: {\n secondary: [{ title: 'View', fn: (_link: any, item: any) => this.view(item) }],\n },\n };\n }\n\n async view(item: any): Promise<void> {\n this.detail = null;\n this.lines = [];\n this.resolution = 'refund';\n this.refundAmount = null;\n this.resolveNote = '';\n this.flyoutService.open(this.detailFlyout);\n\n const detailRes: any = await firstValueFrom(this.dataSource.getOne(item.id));\n this.detail = detailRes?.data ?? item;\n\n const [linesRes, orderLinesRes]: any = await Promise.all([\n firstValueFrom(this.lineSource.getMany({ returnRequestId: item.id, page: 1, perPage: 100 } as any)),\n firstValueFrom(this.orderLineSource.getMany({ orderId: this.detail.orderId, page: 1, perPage: 200 } as any)),\n ]);\n\n const nameByOrderLineId = new Map<string, string>(\n (orderLinesRes?.data ?? []).map((ol: any) => [ol.id, ol.nameSnapshot || ol.variantId]),\n );\n\n this.lines = (linesRes?.data ?? []).map((l: any) => ({\n id: l.id,\n orderLineId: l.orderLineId,\n itemName: nameByOrderLineId.get(l.orderLineId) || l.orderLineId,\n quantity: l.quantity,\n inspectionOutcome: l.inspectionOutcome || 'pending',\n acceptedQuantity: l.acceptedQuantity,\n disposition: l.disposition || '',\n note: l.note || '',\n }));\n }\n\n async saveInspection(): Promise<void> {\n if (!this.detail) return;\n this.saving = true;\n try {\n const res: any = await firstValueFrom(\n this.apiService.post(`apps/commerce/return-request/${this.detail.id}/inspect`, {\n lines: this.lines.map((l) => ({\n returnLineId: l.id,\n outcome: l.inspectionOutcome,\n acceptedQuantity: l.acceptedQuantity != null ? Number(l.acceptedQuantity) : undefined,\n disposition: l.disposition || undefined,\n note: l.note || undefined,\n })),\n }),\n );\n if (res?.status === 'error') {\n notify(res.message || 'Could not save the inspection.', undefined, 'error');\n return;\n }\n notify('Inspection saved.', undefined, 'success');\n this.list(this.page, this.perPage);\n } catch {\n notify('Could not save the inspection.', undefined, 'error');\n } finally {\n this.saving = false;\n }\n }\n\n async resolveReturn(): Promise<void> {\n if (!this.detail) return;\n this.saving = true;\n try {\n const res: any = await firstValueFrom(\n this.apiService.post(`apps/commerce/return-request/${this.detail.id}/resolve`, {\n resolution: this.resolution,\n refundAmount: this.refundAmount != null ? Number(this.refundAmount) : undefined,\n note: this.resolveNote || undefined,\n }),\n );\n if (res?.status === 'error') {\n notify(res.message || 'Could not resolve the return.', undefined, 'error');\n return;\n }\n notify('Return resolved.', undefined, 'success');\n this.flyoutService.dismiss();\n this.list(this.page, this.perPage);\n } catch {\n notify('Could not resolve the return.', undefined, 'error');\n } finally {\n this.saving = false;\n }\n }\n}\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<ng-template #detailFlyout>\n <x-webget-flyout [data]=\"{ title: 'Return detail' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <div class=\"fw-bold font-monospace\">{{ detail.rmaNumber }}</div>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.status }}</span>\n <span class=\"badge text-bg-light border mt-1\">{{ detail.reasonCode }}</span>\n </div>\n\n <div>\n <div class=\"fw-bold small mb-1\">Lines</div>\n @for (line of lines; track line.id) {\n <div class=\"border rounded p-2 mb-2 small\">\n <div class=\"fw-bold\">{{ line.itemName }} · qty {{ line.quantity }}</div>\n <div class=\"d-flex flex-wrap gap-2 mt-1\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.inspectionOutcome\">\n @for (o of outcomes; track o) { <option [value]=\"o\">{{ o }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:110px\"\n placeholder=\"accepted qty\"\n [(ngModel)]=\"line.acceptedQuantity\"\n />\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"line.disposition\">\n <option value=\"\">— disposition —</option>\n @for (d of dispositions; track d) { <option [value]=\"d\">{{ d }}</option> }\n </select>\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"line.note\"\n />\n </div>\n </div>\n } @empty {\n <div class=\"text-secondary small\">No lines.</div>\n }\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" [disabled]=\"saving\" (click)=\"saveInspection()\">\n Save inspection\n </button>\n </div>\n\n <hr class=\"my-1\" />\n\n <div>\n <div class=\"fw-bold small mb-1\">Resolve</div>\n <div class=\"d-flex flex-wrap gap-2\">\n <select class=\"form-select form-select-sm\" style=\"width:auto\" [(ngModel)]=\"resolution\">\n @for (r of resolutions; track r) { <option [value]=\"r\">{{ r }}</option> }\n </select>\n <input\n type=\"number\"\n class=\"form-control form-control-sm\"\n style=\"width:140px\"\n placeholder=\"refund amount (₦)\"\n [(ngModel)]=\"refundAmount\"\n />\n <input\n type=\"text\"\n class=\"form-control form-control-sm\"\n placeholder=\"note\"\n [(ngModel)]=\"resolveNote\"\n />\n </div>\n <button type=\"button\" class=\"btn btn-sm btn-dark mt-2\" [disabled]=\"saving\" (click)=\"resolveReturn()\">\n Resolve return\n </button>\n </div>\n } @else {\n <x-element-loader></x-element-loader>\n }\n </div>\n </x-webget-flyout>\n</ng-template>\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 { Component, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
+ import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
+ import { S as SimpleCrudDirective } from './isaiahiroko-tilmart-ngx-apps-admin-simple-crud.base-C8SPw14H.mjs';
9
+ import * as i1 from '@angular/forms';
10
+ import * as i3 from '@angular/common';
11
+
12
+ // R1 production-readiness pass. Route/cluster/day board (docs/TRD.md
13
+ // §7): a simple list, not a routing-optimization engine — matches the
14
+ // PRD's density model (which street/day, not turn-by-turn routing). Was
15
+ // list-only; ops had no way to define a new route.
16
+ class RoutesComponent extends SimpleCrudDirective {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.pageTitle = 'Routes';
20
+ this.pageSubtitle = 'Street/estate clusters, by delivery day.';
21
+ this.singularLabel = 'route';
22
+ this.pluralName = 'routes';
23
+ this.dataSource = this.apiService.on('apps/commerce/route');
24
+ this.columns = [
25
+ { key: 'name', value: 'Name' },
26
+ { key: 'dayOfWeek', value: 'Day', type: 'class', class: 'badge text-bg-light border' },
27
+ { key: 'vanCapacityKg', value: 'Van capacity (kg)' },
28
+ ];
29
+ this.fields = [
30
+ { key: 'name', label: 'Name', type: 'text', required: true },
31
+ {
32
+ key: 'dayOfWeek',
33
+ label: 'Day of week',
34
+ type: 'select',
35
+ required: true,
36
+ options: [
37
+ { value: 'monday', label: 'Monday' },
38
+ { value: 'tuesday', label: 'Tuesday' },
39
+ { value: 'wednesday', label: 'Wednesday' },
40
+ { value: 'thursday', label: 'Thursday' },
41
+ { value: 'friday', label: 'Friday' },
42
+ { value: 'saturday', label: 'Saturday' },
43
+ { value: 'sunday', label: 'Sunday' },
44
+ ],
45
+ },
46
+ { key: 'vanCapacityKg', label: 'Van capacity (kg)', type: 'number' },
47
+ ];
48
+ }
49
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RoutesComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
50
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: RoutesComponent, isStandalone: false, selector: "x-routes", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\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} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">\u2014 choose \u2014</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n}\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-scrud-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-scrud-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-scrud-btn:disabled{opacity:.5;cursor:default}.x-scrud-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-scrud-danger{color:var(--color-danger, #c0362c)}.x-scrud-editor{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:14px}.x-scrud-editor-head{display:flex;align-items:center;justify-content:space-between}.x-scrud-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-scrud-editor-actions{display:flex;gap:8px}.x-scrud-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-scrud-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-scrud-f-wide{grid-column:1/-1}.x-scrud-f input,.x-scrud-f select,.x-scrud-f textarea{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text);font-weight:400}.x-scrud-f input[type=checkbox]{width:18px;height:18px}.x-scrud-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-scrud-required{color:var(--color-danger, #c0362c)}\n"], dependencies: [{ kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i2.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
51
+ }
52
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RoutesComponent, decorators: [{
53
+ type: Component,
54
+ args: [{ standalone: false, selector: 'x-routes', template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">{{ pageTitle }}</div>\n <div class=\"x-page-subtitle\">{{ pageSubtitle }}</div>\n</div>\n\n@if (!editing) {\n <div class=\"x-scrud-toolbar\">\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" (click)=\"startCreate()\">+ New {{ singularLabel }}</button>\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} @else if (draft) {\n <div class=\"x-scrud-editor\">\n <div class=\"x-scrud-editor-head\">\n <div class=\"x-scrud-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ singularLabel }}</div>\n <div class=\"x-scrud-editor-actions\">\n @if (draft['id'] && !hideDelete) {\n <button type=\"button\" class=\"x-scrud-btn x-scrud-danger\" (click)=\"remove(draft); cancelEdit()\">Delete</button>\n }\n <button type=\"button\" class=\"x-scrud-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-scrud-btn x-scrud-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-scrud-grid\">\n @for (f of fields; track f.key) {\n <label class=\"x-scrud-f\" [class.x-scrud-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-scrud-required\">*</span>\n }\n @switch (f.type) {\n @case ('boolean') {\n <input type=\"checkbox\" [(ngModel)]=\"draft[f.key]\" />\n }\n @case ('select') {\n <select [(ngModel)]=\"draft[f.key]\">\n <option value=\"\">\u2014 choose \u2014</option>\n @for (opt of (f.optionsKey ? dynamicOptions[f.optionsKey] : f.options); track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('textarea') {\n <textarea rows=\"3\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\"></textarea>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-scrud-json\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || '{}'\"></textarea>\n }\n @case ('number') {\n <input type=\"number\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n @case ('date') {\n <input type=\"datetime-local\" [(ngModel)]=\"draft[f.key]\" />\n }\n @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n}\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-scrud-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-scrud-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-scrud-btn:disabled{opacity:.5;cursor:default}.x-scrud-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-scrud-danger{color:var(--color-danger, #c0362c)}.x-scrud-editor{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:16px;display:flex;flex-direction:column;gap:14px}.x-scrud-editor-head{display:flex;align-items:center;justify-content:space-between}.x-scrud-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-scrud-editor-actions{display:flex;gap:8px}.x-scrud-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-scrud-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-scrud-f-wide{grid-column:1/-1}.x-scrud-f input,.x-scrud-f select,.x-scrud-f textarea{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-size:13px;background:var(--color-surface);color:var(--color-text);font-weight:400}.x-scrud-f input[type=checkbox]{width:18px;height:18px}.x-scrud-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-scrud-required{color:var(--color-danger, #c0362c)}\n"] }]
55
+ }] });
56
+
57
+ class RoutesModule {
58
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RoutesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
59
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: RoutesModule, declarations: [RoutesComponent], imports: [SharedModule,
60
+ ElementsModule,
61
+ WebgetsModule, i1$1.RouterModule] }); }
62
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RoutesModule, imports: [SharedModule,
63
+ ElementsModule,
64
+ WebgetsModule,
65
+ RouterModule.forChild([{ path: '', component: RoutesComponent }])] }); }
66
+ }
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: RoutesModule, decorators: [{
68
+ type: NgModule,
69
+ args: [{
70
+ declarations: [RoutesComponent],
71
+ imports: [
72
+ SharedModule,
73
+ ElementsModule,
74
+ WebgetsModule,
75
+ RouterModule.forChild([{ path: '', component: RoutesComponent }]),
76
+ ],
77
+ }]
78
+ }] });
79
+
80
+ export { RoutesModule };
81
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-routes.module-CGBBHwId.mjs.map