@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-routes.module-CGBBHwId.mjs","sources":["../../../projects/admin/src/lib/pages/routes/routes.component.ts","../../../projects/admin/src/lib/pages/_shared/simple-crud.component.html","../../../projects/admin/src/lib/pages/routes/routes.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { CrudFieldSpec, SimpleCrudDirective } from '../_shared/simple-crud.base';\n\n// R1 production-readiness pass. Route/cluster/day board (docs/TRD.md\n// §7): a simple list, not a routing-optimization engine — matches the\n// PRD's density model (which street/day, not turn-by-turn routing). Was\n// list-only; ops had no way to define a new route.\n@Component({\n standalone: false,\n selector: 'x-routes',\n templateUrl: '../_shared/simple-crud.component.html',\n styleUrl: '../_shared/simple-crud.component.scss',\n})\nexport class RoutesComponent extends SimpleCrudDirective {\n protected pageTitle = 'Routes';\n protected pageSubtitle = 'Street/estate clusters, by delivery day.';\n protected singularLabel = 'route';\n protected pluralName = 'routes';\n protected dataSource = this.apiService.on('apps/commerce/route');\n\n protected columns = [\n { key: 'name', value: 'Name' },\n { key: 'dayOfWeek', value: 'Day', type: 'class', class: 'badge text-bg-light border' },\n { key: 'vanCapacityKg', value: 'Van capacity (kg)' },\n ];\n\n protected fields: CrudFieldSpec[] = [\n { key: 'name', label: 'Name', type: 'text', required: true },\n {\n key: 'dayOfWeek',\n label: 'Day of week',\n type: 'select',\n required: true,\n options: [\n { value: 'monday', label: 'Monday' },\n { value: 'tuesday', label: 'Tuesday' },\n { value: 'wednesday', label: 'Wednesday' },\n { value: 'thursday', label: 'Thursday' },\n { value: 'friday', label: 'Friday' },\n { value: 'saturday', label: 'Saturday' },\n { value: 'sunday', label: 'Sunday' },\n ],\n },\n { key: 'vanCapacityKg', label: 'Van capacity (kg)', type: 'number' },\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 { RoutesComponent } from './routes.component';\n\n@NgModule({\n declarations: [RoutesComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: RoutesComponent }]),\n ],\n})\nexport class RoutesModule {}\n"],"names":["i1"],"mappings":"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"}
@@ -0,0 +1,318 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/router';
4
+ import { RouterModule } from '@angular/router';
5
+ import { BaseDirective, titleCase, using, notify, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
+ import { ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
+ import { BehaviorSubject, takeUntil, map, firstValueFrom } from 'rxjs';
9
+ import * as i1 from '@angular/forms';
10
+ import * as i3 from '@angular/common';
11
+
12
+ // R1 production-readiness pass — ADM-12 / ORD-05. P7.1's original
13
+ // version stacked these four config resources as read-only lists; ops
14
+ // had no way to add a channel, shipping zone, shipping method or return
15
+ // policy "without a deploy" (ADM-12's own words). Same field-by-field
16
+ // form idea as `SimpleCrudDirective`, adapted for four resources sharing
17
+ // one tabbed page rather than one resource per route.
18
+ class SettingsComponent extends BaseDirective {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.sections = [
22
+ {
23
+ key: 'channels',
24
+ title: 'Channels',
25
+ singularLabel: 'channel',
26
+ mount: 'apps/commerce/channel',
27
+ columns: [
28
+ { key: 'name', value: 'Name' },
29
+ { key: 'code', value: 'Code' },
30
+ { key: 'currency', value: 'Currency' },
31
+ ],
32
+ fields: [
33
+ { key: 'name', label: 'Name', type: 'text', required: true },
34
+ { key: 'code', label: 'Code', type: 'text', required: true, placeholder: 'e.g. web-ng' },
35
+ { key: 'currency', label: 'Currency', type: 'text', placeholder: 'NGN' },
36
+ {
37
+ key: 'taxMode',
38
+ label: 'Tax mode',
39
+ type: 'select',
40
+ options: [
41
+ { value: 'inclusive', label: 'Inclusive' },
42
+ { value: 'exclusive', label: 'Exclusive' },
43
+ ],
44
+ },
45
+ ],
46
+ data$: new BehaviorSubject(null),
47
+ page: 1,
48
+ },
49
+ {
50
+ key: 'zones',
51
+ title: 'Shipping zones',
52
+ singularLabel: 'shipping zone',
53
+ mount: 'apps/commerce/delivery-zone',
54
+ columns: [
55
+ { key: 'name', value: 'Name' },
56
+ { key: 'state', value: 'State' },
57
+ { key: 'lga', value: 'LGA' },
58
+ ],
59
+ fields: [
60
+ { key: 'name', label: 'Name', type: 'text', required: true },
61
+ { key: 'state', label: 'State', type: 'text', required: true },
62
+ { key: 'lga', label: 'LGA', type: 'text' },
63
+ ],
64
+ data$: new BehaviorSubject(null),
65
+ page: 1,
66
+ },
67
+ {
68
+ key: 'methods',
69
+ title: 'Shipping methods',
70
+ singularLabel: 'shipping method',
71
+ mount: 'apps/commerce/delivery-method',
72
+ columns: [
73
+ { key: 'name', value: 'Name' },
74
+ { key: 'flatFee', value: 'Flat fee' },
75
+ { key: 'perKg', value: 'Per kg' },
76
+ {
77
+ key: 'enabled',
78
+ value: 'Enabled',
79
+ type: 'class',
80
+ class: 'badge text-bg-light border',
81
+ },
82
+ ],
83
+ fields: [
84
+ { key: 'name', label: 'Name', type: 'text', required: true },
85
+ {
86
+ key: 'type',
87
+ label: 'Type',
88
+ type: 'select',
89
+ options: [
90
+ { value: 'door', label: 'Door delivery' },
91
+ { value: 'express', label: 'Express' },
92
+ { value: 'pickup', label: 'Pickup' },
93
+ { value: 'scheduled', label: 'Scheduled' },
94
+ { value: 'freight', label: 'Freight' },
95
+ ],
96
+ },
97
+ { key: 'estimateDaysMin', label: 'Estimate — min days', type: 'number' },
98
+ { key: 'estimateDaysMax', label: 'Estimate — max days', type: 'number' },
99
+ { key: 'enabled', label: 'Enabled', type: 'boolean' },
100
+ {
101
+ key: 'rateRules',
102
+ label: 'Rate rules (JSON array)',
103
+ type: 'json',
104
+ placeholder: '[{"zoneId": null, "flatFee": 2000, "perKg": 150}]',
105
+ },
106
+ ],
107
+ data$: new BehaviorSubject(null),
108
+ page: 1,
109
+ },
110
+ {
111
+ key: 'returns',
112
+ title: 'Return policies',
113
+ singularLabel: 'return policy',
114
+ mount: 'apps/commerce/return-policy',
115
+ columns: [
116
+ { key: 'windowDays', value: 'Window (days)' },
117
+ { key: 'restockingFeePct', value: 'Restock fee %' },
118
+ { key: 'whoPaysReturn', value: 'Who pays' },
119
+ {
120
+ key: 'enabled',
121
+ value: 'Enabled',
122
+ type: 'class',
123
+ class: 'badge text-bg-light border',
124
+ },
125
+ ],
126
+ fields: [
127
+ { key: 'windowDays', label: 'Return window (days)', type: 'number', required: true },
128
+ {
129
+ key: 'reasonCode',
130
+ label: 'Reason code (blank = default policy)',
131
+ type: 'select',
132
+ options: [
133
+ { value: 'damaged_in_transit', label: 'Damaged in transit' },
134
+ { value: 'wrong_item', label: 'Wrong item' },
135
+ { value: 'not_as_described', label: 'Not as described' },
136
+ { value: 'faulty_on_arrival', label: 'Faulty on arrival' },
137
+ { value: 'changed_mind', label: 'Changed mind' },
138
+ { value: 'missing_parts', label: 'Missing parts' },
139
+ ],
140
+ },
141
+ { key: 'restockingFeePct', label: 'Restocking fee %', type: 'number' },
142
+ {
143
+ key: 'whoPaysReturn',
144
+ label: 'Who pays for return shipping',
145
+ type: 'select',
146
+ options: [
147
+ { value: 'customer', label: 'Customer' },
148
+ { value: 'tilmart', label: 'Tilmart' },
149
+ { value: 'seller', label: 'Seller' },
150
+ ],
151
+ },
152
+ { key: 'allowChangeOfMind', label: 'Allow change-of-mind returns', type: 'boolean' },
153
+ { key: 'enabled', label: 'Enabled', type: 'boolean' },
154
+ ],
155
+ data$: new BehaviorSubject(null),
156
+ page: 1,
157
+ },
158
+ ];
159
+ this.active = this.sections[0].key;
160
+ this.editing = false;
161
+ this.saving = false;
162
+ this.draft = null;
163
+ this.init = () => {
164
+ for (const section of this.sections)
165
+ this.load(section);
166
+ };
167
+ }
168
+ get activeSection() {
169
+ return this.sections.find((s) => s.key === this.active);
170
+ }
171
+ load(section, page = section.page, query = section.query) {
172
+ section.page = page;
173
+ section.query = query;
174
+ const params = { page, perPage: 100 };
175
+ if (query)
176
+ params.query = query;
177
+ this.apiService
178
+ .on(section.mount)
179
+ .getMany(params)
180
+ .pipe(takeUntil(this.$), map((response) => ({
181
+ title: titleCase(section.title),
182
+ columns: section.columns,
183
+ rows: response?.data,
184
+ hasHeaders: true,
185
+ hasTextFilter: true,
186
+ page: response?.meta?.current_page,
187
+ perPage: response?.meta?.per_page,
188
+ total: response?.meta?.total,
189
+ onPage: (p) => this.load(section, p, query),
190
+ onSearch: (q) => this.load(section, 1, q),
191
+ onRefresh: () => this.load(section, page, query),
192
+ links: {
193
+ secondary: [{ title: 'Edit', fn: (_l, item) => this.edit(item) }],
194
+ },
195
+ })))
196
+ .subscribe(using((data) => section.data$.next(data)));
197
+ }
198
+ selectTab(key) {
199
+ this.active = key;
200
+ this.editing = false;
201
+ this.draft = null;
202
+ }
203
+ startCreate() {
204
+ this.editing = true;
205
+ const draft = {};
206
+ for (const field of this.activeSection.fields) {
207
+ draft[field.key] = field.type === 'boolean' ? false : '';
208
+ }
209
+ this.draft = draft;
210
+ }
211
+ edit(item) {
212
+ this.editing = true;
213
+ const draft = { ...item };
214
+ for (const field of this.activeSection.fields) {
215
+ if (field.type === 'json' && draft[field.key] != null && typeof draft[field.key] !== 'string') {
216
+ draft[field.key] = JSON.stringify(draft[field.key], null, 2);
217
+ }
218
+ }
219
+ this.draft = draft;
220
+ }
221
+ cancelEdit() {
222
+ this.editing = false;
223
+ this.draft = null;
224
+ }
225
+ async save() {
226
+ if (!this.draft)
227
+ return;
228
+ const section = this.activeSection;
229
+ this.saving = true;
230
+ try {
231
+ const payload = {};
232
+ for (const field of section.fields) {
233
+ const raw = this.draft[field.key];
234
+ if (field.type === 'number') {
235
+ payload[field.key] = raw !== null && raw !== undefined && `${raw}` !== '' ? Number(raw) : undefined;
236
+ }
237
+ else if (field.type === 'boolean') {
238
+ payload[field.key] = !!raw;
239
+ }
240
+ else if (field.type === 'json') {
241
+ try {
242
+ payload[field.key] = raw && `${raw}`.trim() ? JSON.parse(raw) : undefined;
243
+ }
244
+ catch {
245
+ payload[field.key] = undefined;
246
+ }
247
+ }
248
+ else {
249
+ payload[field.key] = raw || undefined;
250
+ }
251
+ }
252
+ const source = this.apiService.on(section.mount);
253
+ if (this.draft['id']) {
254
+ await firstValueFrom(source.update(this.draft['id'], payload));
255
+ }
256
+ else {
257
+ await firstValueFrom(source.create(payload));
258
+ }
259
+ notify(`${titleCase(section.singularLabel)} saved.`, undefined, 'success');
260
+ this.editing = false;
261
+ this.draft = null;
262
+ this.load(section, section.page, section.query);
263
+ }
264
+ catch {
265
+ notify('Could not save (check required fields).', undefined, 'error');
266
+ }
267
+ finally {
268
+ this.saving = false;
269
+ }
270
+ }
271
+ async remove() {
272
+ if (!this.draft?.['id'])
273
+ return;
274
+ const section = this.activeSection;
275
+ try {
276
+ await firstValueFrom(this.apiService.on(section.mount).remove(this.draft['id']));
277
+ notify(`${titleCase(section.singularLabel)} deleted.`, undefined, 'success');
278
+ this.editing = false;
279
+ this.draft = null;
280
+ this.load(section, section.page, section.query);
281
+ }
282
+ catch {
283
+ notify('Could not delete — it may still be referenced elsewhere.', undefined, 'error');
284
+ }
285
+ }
286
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SettingsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
287
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: SettingsComponent, isStandalone: false, selector: "x-settings", usesInheritance: true, ngImport: i0, template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Settings</div>\n <div class=\"x-page-subtitle\">\n Channels, shipping and returns configuration.\n </div>\n</div>\n\n<nav class=\"x-settings-tabs\">\n @for (s of sections; track s.key) {\n <button\n type=\"button\"\n class=\"x-settings-tab\"\n [class.is-active]=\"active === s.key\"\n (click)=\"selectTab(s.key)\"\n >\n {{ s.title }}\n </button>\n }\n</nav>\n\n@for (s of sections; track s.key) {\n @if (active === s.key) {\n @if (!editing) {\n <div class=\"x-settings-toolbar\">\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" (click)=\"startCreate()\">\n + New {{ s.singularLabel }}\n </button>\n </div>\n @if (s.data$ | 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-settings-editor\">\n <div class=\"x-settings-editor-head\">\n <div class=\"x-settings-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ s.singularLabel }}</div>\n <div class=\"x-settings-editor-actions\">\n @if (draft['id']) {\n <button type=\"button\" class=\"x-settings-btn x-settings-danger\" (click)=\"remove()\">Delete</button>\n }\n <button type=\"button\" class=\"x-settings-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-settings-grid\">\n @for (f of s.fields; track f.key) {\n <label class=\"x-settings-f\" [class.x-settings-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-settings-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.options; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-settings-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 @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n }\n }\n}\n\n<div class=\"x-settings-more\">\n <p>\n <strong>Users &amp; roles</strong> \u2014\n <a routerLink=\"/admin/users\">manage accounts</a>.\n </p>\n <p>\n <strong>Notifications</strong> \u2014 transactional and marketing templates\n are seeded per environment (NotificationTemplates); per-customer\n preferences are on the customer record.\n </p>\n <p class=\"x-settings-audit\">\n <strong>Audit log</strong> \u2014 every privileged action is recorded\n (ntx-apps-audit); <a routerLink=\"/admin/audit\">open the viewer</a>.\n </p>\n</div>\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}.x-settings-tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;border-bottom:1px solid var(--color-border)}.x-settings-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-settings-tab.is-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-settings-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-settings-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-settings-btn:disabled{opacity:.5;cursor:default}.x-settings-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-settings-danger{color:var(--color-danger, #c0362c)}.x-settings-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-settings-editor-head{display:flex;align-items:center;justify-content:space-between}.x-settings-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-settings-editor-actions{display:flex;gap:8px}.x-settings-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-settings-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-settings-f-wide{grid-column:1/-1}.x-settings-f input,.x-settings-f select,.x-settings-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-settings-f input[type=checkbox]{width:18px;height:18px}.x-settings-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-settings-required{color:var(--color-danger, #c0362c)}.x-settings-more{margin-top:28px;padding-top:18px;border-top:1px solid var(--color-border);font-size:13px;line-height:1.6;color:var(--color-text-muted)}.x-settings-more a{color:var(--color-brand)}.x-settings-audit{margin-bottom:0}\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: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i2.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i2.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SettingsComponent, decorators: [{
290
+ type: Component,
291
+ args: [{ standalone: false, selector: 'x-settings', template: "<div class=\"x-page-head\">\n <div class=\"x-page-title\">Settings</div>\n <div class=\"x-page-subtitle\">\n Channels, shipping and returns configuration.\n </div>\n</div>\n\n<nav class=\"x-settings-tabs\">\n @for (s of sections; track s.key) {\n <button\n type=\"button\"\n class=\"x-settings-tab\"\n [class.is-active]=\"active === s.key\"\n (click)=\"selectTab(s.key)\"\n >\n {{ s.title }}\n </button>\n }\n</nav>\n\n@for (s of sections; track s.key) {\n @if (active === s.key) {\n @if (!editing) {\n <div class=\"x-settings-toolbar\">\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" (click)=\"startCreate()\">\n + New {{ s.singularLabel }}\n </button>\n </div>\n @if (s.data$ | 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-settings-editor\">\n <div class=\"x-settings-editor-head\">\n <div class=\"x-settings-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ s.singularLabel }}</div>\n <div class=\"x-settings-editor-actions\">\n @if (draft['id']) {\n <button type=\"button\" class=\"x-settings-btn x-settings-danger\" (click)=\"remove()\">Delete</button>\n }\n <button type=\"button\" class=\"x-settings-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving\u2026' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-settings-grid\">\n @for (f of s.fields; track f.key) {\n <label class=\"x-settings-f\" [class.x-settings-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-settings-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.options; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-settings-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 @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n }\n }\n}\n\n<div class=\"x-settings-more\">\n <p>\n <strong>Users &amp; roles</strong> \u2014\n <a routerLink=\"/admin/users\">manage accounts</a>.\n </p>\n <p>\n <strong>Notifications</strong> \u2014 transactional and marketing templates\n are seeded per environment (NotificationTemplates); per-customer\n preferences are on the customer record.\n </p>\n <p class=\"x-settings-audit\">\n <strong>Audit log</strong> \u2014 every privileged action is recorded\n (ntx-apps-audit); <a routerLink=\"/admin/audit\">open the viewer</a>.\n </p>\n</div>\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}.x-settings-tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;border-bottom:1px solid var(--color-border)}.x-settings-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-settings-tab.is-active{color:var(--color-text);border-bottom-color:var(--color-brand)}.x-settings-toolbar{display:flex;justify-content:flex-end;margin-bottom:14px}.x-settings-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-settings-btn:disabled{opacity:.5;cursor:default}.x-settings-btn-primary{border-color:var(--color-accent);color:var(--color-accent-hover)}.x-settings-danger{color:var(--color-danger, #c0362c)}.x-settings-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-settings-editor-head{display:flex;align-items:center;justify-content:space-between}.x-settings-editor-title{font-size:16px;font-weight:800;color:var(--color-text)}.x-settings-editor-actions{display:flex;gap:8px}.x-settings-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.x-settings-f{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--color-text-muted);font-weight:700}.x-settings-f-wide{grid-column:1/-1}.x-settings-f input,.x-settings-f select,.x-settings-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-settings-f input[type=checkbox]{width:18px;height:18px}.x-settings-json{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.x-settings-required{color:var(--color-danger, #c0362c)}.x-settings-more{margin-top:28px;padding-top:18px;border-top:1px solid var(--color-border);font-size:13px;line-height:1.6;color:var(--color-text-muted)}.x-settings-more a{color:var(--color-brand)}.x-settings-audit{margin-bottom:0}\n"] }]
292
+ }] });
293
+
294
+ class SettingsModule {
295
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SettingsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
296
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: SettingsModule, declarations: [SettingsComponent], imports: [SharedModule,
297
+ ElementsModule,
298
+ WebgetsModule, i1$1.RouterModule] }); }
299
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SettingsModule, imports: [SharedModule,
300
+ ElementsModule,
301
+ WebgetsModule,
302
+ RouterModule.forChild([{ path: '', component: SettingsComponent }])] }); }
303
+ }
304
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: SettingsModule, decorators: [{
305
+ type: NgModule,
306
+ args: [{
307
+ declarations: [SettingsComponent],
308
+ imports: [
309
+ SharedModule,
310
+ ElementsModule,
311
+ WebgetsModule,
312
+ RouterModule.forChild([{ path: '', component: SettingsComponent }]),
313
+ ],
314
+ }]
315
+ }] });
316
+
317
+ export { SettingsModule };
318
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-settings.module-Cz6xPNwB.mjs","sources":["../../../projects/admin/src/lib/pages/settings/settings.component.ts","../../../projects/admin/src/lib/pages/settings/settings.component.html","../../../projects/admin/src/lib/pages/settings/settings.module.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { BaseDirective, notify, titleCase, using } from '@thescaffold/ngx-core';\nimport { BehaviorSubject, firstValueFrom, map, takeUntil } from 'rxjs';\nimport { CrudFieldSpec } from '../_shared/simple-crud.base';\n\ninterface Section {\n key: string;\n title: string;\n singularLabel: string;\n mount: string;\n columns: { key: string; value: string; type?: string; class?: string }[];\n fields: CrudFieldSpec[];\n data$: BehaviorSubject<any>;\n page: number;\n query?: string;\n}\n\n// R1 production-readiness pass — ADM-12 / ORD-05. P7.1's original\n// version stacked these four config resources as read-only lists; ops\n// had no way to add a channel, shipping zone, shipping method or return\n// policy \"without a deploy\" (ADM-12's own words). Same field-by-field\n// form idea as `SimpleCrudDirective`, adapted for four resources sharing\n// one tabbed page rather than one resource per route.\n@Component({\n standalone: false,\n selector: 'x-settings',\n templateUrl: './settings.component.html',\n styleUrl: './settings.component.scss',\n})\nexport class SettingsComponent extends BaseDirective {\n readonly sections: Section[] = [\n {\n key: 'channels',\n title: 'Channels',\n singularLabel: 'channel',\n mount: 'apps/commerce/channel',\n columns: [\n { key: 'name', value: 'Name' },\n { key: 'code', value: 'Code' },\n { key: 'currency', value: 'Currency' },\n ],\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true },\n { key: 'code', label: 'Code', type: 'text', required: true, placeholder: 'e.g. web-ng' },\n { key: 'currency', label: 'Currency', type: 'text', placeholder: 'NGN' },\n {\n key: 'taxMode',\n label: 'Tax mode',\n type: 'select',\n options: [\n { value: 'inclusive', label: 'Inclusive' },\n { value: 'exclusive', label: 'Exclusive' },\n ],\n },\n ],\n data$: new BehaviorSubject<any>(null),\n page: 1,\n },\n {\n key: 'zones',\n title: 'Shipping zones',\n singularLabel: 'shipping zone',\n mount: 'apps/commerce/delivery-zone',\n columns: [\n { key: 'name', value: 'Name' },\n { key: 'state', value: 'State' },\n { key: 'lga', value: 'LGA' },\n ],\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true },\n { key: 'state', label: 'State', type: 'text', required: true },\n { key: 'lga', label: 'LGA', type: 'text' },\n ],\n data$: new BehaviorSubject<any>(null),\n page: 1,\n },\n {\n key: 'methods',\n title: 'Shipping methods',\n singularLabel: 'shipping method',\n mount: 'apps/commerce/delivery-method',\n columns: [\n { key: 'name', value: 'Name' },\n { key: 'flatFee', value: 'Flat fee' },\n { key: 'perKg', value: 'Per kg' },\n {\n key: 'enabled',\n value: 'Enabled',\n type: 'class',\n class: 'badge text-bg-light border',\n },\n ],\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true },\n {\n key: 'type',\n label: 'Type',\n type: 'select',\n options: [\n { value: 'door', label: 'Door delivery' },\n { value: 'express', label: 'Express' },\n { value: 'pickup', label: 'Pickup' },\n { value: 'scheduled', label: 'Scheduled' },\n { value: 'freight', label: 'Freight' },\n ],\n },\n { key: 'estimateDaysMin', label: 'Estimate — min days', type: 'number' },\n { key: 'estimateDaysMax', label: 'Estimate — max days', type: 'number' },\n { key: 'enabled', label: 'Enabled', type: 'boolean' },\n {\n key: 'rateRules',\n label: 'Rate rules (JSON array)',\n type: 'json',\n placeholder: '[{\"zoneId\": null, \"flatFee\": 2000, \"perKg\": 150}]',\n },\n ],\n data$: new BehaviorSubject<any>(null),\n page: 1,\n },\n {\n key: 'returns',\n title: 'Return policies',\n singularLabel: 'return policy',\n mount: 'apps/commerce/return-policy',\n columns: [\n { key: 'windowDays', value: 'Window (days)' },\n { key: 'restockingFeePct', value: 'Restock fee %' },\n { key: 'whoPaysReturn', value: 'Who pays' },\n {\n key: 'enabled',\n value: 'Enabled',\n type: 'class',\n class: 'badge text-bg-light border',\n },\n ],\n fields: [\n { key: 'windowDays', label: 'Return window (days)', type: 'number', required: true },\n {\n key: 'reasonCode',\n label: 'Reason code (blank = default policy)',\n type: 'select',\n options: [\n { value: 'damaged_in_transit', label: 'Damaged in transit' },\n { value: 'wrong_item', label: 'Wrong item' },\n { value: 'not_as_described', label: 'Not as described' },\n { value: 'faulty_on_arrival', label: 'Faulty on arrival' },\n { value: 'changed_mind', label: 'Changed mind' },\n { value: 'missing_parts', label: 'Missing parts' },\n ],\n },\n { key: 'restockingFeePct', label: 'Restocking fee %', type: 'number' },\n {\n key: 'whoPaysReturn',\n label: 'Who pays for return shipping',\n type: 'select',\n options: [\n { value: 'customer', label: 'Customer' },\n { value: 'tilmart', label: 'Tilmart' },\n { value: 'seller', label: 'Seller' },\n ],\n },\n { key: 'allowChangeOfMind', label: 'Allow change-of-mind returns', type: 'boolean' },\n { key: 'enabled', label: 'Enabled', type: 'boolean' },\n ],\n data$: new BehaviorSubject<any>(null),\n page: 1,\n },\n ];\n\n active = this.sections[0].key;\n editing = false;\n saving = false;\n draft: Record<string, any> | null = null;\n\n get activeSection(): Section {\n return this.sections.find((s) => s.key === this.active)!;\n }\n\n override init = () => {\n for (const section of this.sections) this.load(section);\n };\n\n private load(section: Section, page = section.page, query = section.query): void {\n section.page = page;\n section.query = query;\n const params: any = { page, perPage: 100 };\n if (query) params.query = query;\n this.apiService\n .on(section.mount)\n .getMany(params)\n .pipe(\n takeUntil(this.$),\n map((response: any) => ({\n title: titleCase(section.title),\n columns: section.columns,\n rows: response?.data,\n hasHeaders: true,\n hasTextFilter: true,\n page: response?.meta?.current_page,\n perPage: response?.meta?.per_page,\n total: response?.meta?.total,\n onPage: (p: number) => this.load(section, p, query),\n onSearch: (q: string) => this.load(section, 1, q),\n onRefresh: () => this.load(section, page, query),\n links: {\n secondary: [{ title: 'Edit', fn: (_l: any, item: any) => this.edit(item) }],\n },\n })),\n )\n .subscribe(using((data) => section.data$.next(data)));\n }\n\n selectTab(key: string): void {\n this.active = key;\n this.editing = false;\n this.draft = null;\n }\n\n startCreate(): void {\n this.editing = true;\n const draft: Record<string, any> = {};\n for (const field of this.activeSection.fields) {\n draft[field.key] = field.type === 'boolean' ? false : '';\n }\n this.draft = draft;\n }\n\n edit(item: any): void {\n this.editing = true;\n const draft = { ...item };\n for (const field of this.activeSection.fields) {\n if (field.type === 'json' && draft[field.key] != null && typeof draft[field.key] !== 'string') {\n draft[field.key] = JSON.stringify(draft[field.key], null, 2);\n }\n }\n this.draft = draft;\n }\n\n cancelEdit(): void {\n this.editing = false;\n this.draft = null;\n }\n\n async save(): Promise<void> {\n if (!this.draft) return;\n const section = this.activeSection;\n this.saving = true;\n try {\n const payload: Record<string, any> = {};\n for (const field of section.fields) {\n const raw = this.draft[field.key];\n if (field.type === 'number') {\n payload[field.key] = raw !== null && raw !== undefined && `${raw}` !== '' ? Number(raw) : undefined;\n } else if (field.type === 'boolean') {\n payload[field.key] = !!raw;\n } else if (field.type === 'json') {\n try {\n payload[field.key] = raw && `${raw}`.trim() ? JSON.parse(raw) : undefined;\n } catch {\n payload[field.key] = undefined;\n }\n } else {\n payload[field.key] = raw || undefined;\n }\n }\n\n const source = this.apiService.on(section.mount);\n if (this.draft['id']) {\n await firstValueFrom(source.update(this.draft['id'], payload));\n } else {\n await firstValueFrom(source.create(payload));\n }\n notify(`${titleCase(section.singularLabel)} saved.`, undefined, 'success');\n this.editing = false;\n this.draft = null;\n this.load(section, section.page, section.query);\n } catch {\n notify('Could not save (check required fields).', undefined, 'error');\n } finally {\n this.saving = false;\n }\n }\n\n async remove(): Promise<void> {\n if (!this.draft?.['id']) return;\n const section = this.activeSection;\n try {\n await firstValueFrom(this.apiService.on(section.mount).remove(this.draft['id']));\n notify(`${titleCase(section.singularLabel)} deleted.`, undefined, 'success');\n this.editing = false;\n this.draft = null;\n this.load(section, section.page, section.query);\n } catch {\n notify('Could not delete — it may still be referenced elsewhere.', undefined, 'error');\n }\n }\n}\n","<div class=\"x-page-head\">\n <div class=\"x-page-title\">Settings</div>\n <div class=\"x-page-subtitle\">\n Channels, shipping and returns configuration.\n </div>\n</div>\n\n<nav class=\"x-settings-tabs\">\n @for (s of sections; track s.key) {\n <button\n type=\"button\"\n class=\"x-settings-tab\"\n [class.is-active]=\"active === s.key\"\n (click)=\"selectTab(s.key)\"\n >\n {{ s.title }}\n </button>\n }\n</nav>\n\n@for (s of sections; track s.key) {\n @if (active === s.key) {\n @if (!editing) {\n <div class=\"x-settings-toolbar\">\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" (click)=\"startCreate()\">\n + New {{ s.singularLabel }}\n </button>\n </div>\n @if (s.data$ | 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-settings-editor\">\n <div class=\"x-settings-editor-head\">\n <div class=\"x-settings-editor-title\">{{ draft['id'] ? 'Edit' : 'New' }} {{ s.singularLabel }}</div>\n <div class=\"x-settings-editor-actions\">\n @if (draft['id']) {\n <button type=\"button\" class=\"x-settings-btn x-settings-danger\" (click)=\"remove()\">Delete</button>\n }\n <button type=\"button\" class=\"x-settings-btn\" (click)=\"cancelEdit()\">Close</button>\n <button type=\"button\" class=\"x-settings-btn x-settings-btn-primary\" [disabled]=\"saving\" (click)=\"save()\">\n {{ saving ? 'Saving…' : 'Save' }}\n </button>\n </div>\n </div>\n\n <div class=\"x-settings-grid\">\n @for (f of s.fields; track f.key) {\n <label class=\"x-settings-f\" [class.x-settings-f-wide]=\"f.type === 'textarea' || f.type === 'json'\">\n {{ f.label }}\n @if (f.required) {\n <span class=\"x-settings-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.options; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n @case ('json') {\n <textarea rows=\"4\" class=\"x-settings-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 @default {\n <input type=\"text\" [(ngModel)]=\"draft[f.key]\" [placeholder]=\"f.placeholder || ''\" />\n }\n }\n </label>\n }\n </div>\n </div>\n }\n }\n}\n\n<div class=\"x-settings-more\">\n <p>\n <strong>Users &amp; roles</strong> —\n <a routerLink=\"/admin/users\">manage accounts</a>.\n </p>\n <p>\n <strong>Notifications</strong> — transactional and marketing templates\n are seeded per environment (NotificationTemplates); per-customer\n preferences are on the customer record.\n </p>\n <p class=\"x-settings-audit\">\n <strong>Audit log</strong> — every privileged action is recorded\n (ntx-apps-audit); <a routerLink=\"/admin/audit\">open the viewer</a>.\n </p>\n</div>\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 { SettingsComponent } from './settings.component';\n\n@NgModule({\n declarations: [SettingsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: SettingsComponent }]),\n ],\n})\nexport class SettingsModule {}\n"],"names":["i2","i3","i4","i1"],"mappings":"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"}
@@ -1,13 +1,14 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, TemplateRef, ViewChild, Component, NgModule } from '@angular/core';
3
- import * as i1$2 from '@angular/router';
3
+ import * as i1$1 from '@angular/router';
4
4
  import { RouterModule } from '@angular/router';
5
- import { BaseDirective, using, notify, titleCase, SharedModule } from '@thescaffold/ngx-core';
6
- import * as i1$1 from '@thescaffold/ngx-ui';
5
+ import { using, notify, SharedModule } from '@thescaffold/ngx-core';
6
+ import * as i2 from '@thescaffold/ngx-ui';
7
7
  import { FlyoutService, ElementsModule, WebgetsModule } from '@thescaffold/ngx-ui';
8
- import { BehaviorSubject, takeUntil, map } from 'rxjs';
8
+ import { takeUntil } from 'rxjs';
9
+ import { L as ListPageDirective } from './isaiahiroko-tilmart-ngx-apps-admin-list-page.base-Cl7JZ-Tp.mjs';
9
10
  import * as i1 from '@angular/forms';
10
- import * as i2 from '@angular/common';
11
+ import * as i3 from '@angular/common';
11
12
 
12
13
  const EXCEPTION_REASONS = [
13
14
  'recipient_unavailable',
@@ -23,11 +24,12 @@ const EXCEPTION_REASONS = [
23
24
  // ORD-08 / ORD-12 — the fulfilment queue. List every shipment; drill in
24
25
  // to dispatch, mark delivered, or record a delivery exception (each
25
26
  // calls `FulfilmentWorkflow` via the shipment controller).
26
- class ShipmentsComponent extends BaseDirective {
27
+ class ShipmentsComponent extends ListPageDirective {
27
28
  constructor() {
28
29
  super(...arguments);
29
30
  this.flyoutService = inject(FlyoutService);
30
- this.shipmentSource = this.apiService.on('apps/commerce/shipment');
31
+ this.pluralName = 'shipments';
32
+ this.dataSource = this.apiService.on('apps/commerce/shipment');
31
33
  this.lineSource = this.apiService.on('apps/commerce/shipment-line');
32
34
  this.exceptionSource = this.apiService.on('apps/commerce/delivery-exception');
33
35
  this.reasons = EXCEPTION_REASONS;
@@ -38,21 +40,9 @@ class ShipmentsComponent extends BaseDirective {
38
40
  { key: 'trackingRef', value: 'Tracking' },
39
41
  { key: 'createdAt', value: 'Created', type: 'date' },
40
42
  ];
41
- this.page = 1;
42
- this.perPage = 25;
43
- this.list$ = new BehaviorSubject(null);
44
43
  this.detail = null;
45
44
  this.exceptionReason = 'recipient_unavailable';
46
45
  this.exceptionNote = '';
47
- this.init = () => {
48
- this.list();
49
- };
50
- }
51
- list(page = this.page, perPage = this.perPage) {
52
- this.shipmentSource
53
- .getMany({ page, perPage })
54
- .pipe(takeUntil(this.$), map((response) => this.toCollection(response)))
55
- .subscribe(using((data) => this.list$.next(data)));
56
46
  }
57
47
  view(item) {
58
48
  this.detail = null;
@@ -96,24 +86,15 @@ class ShipmentsComponent extends BaseDirective {
96
86
  recordException() {
97
87
  this.act('exception', { reasonCode: this.exceptionReason, notes: this.exceptionNote || undefined }, 'Delivery exception recorded.');
98
88
  }
99
- toCollection(response) {
89
+ extraCollectionFields() {
100
90
  return {
101
- title: titleCase('shipments'),
102
- columns: this.columns,
103
- rows: response?.data ?? [],
104
- hasHeaders: true,
105
- hasTextFilter: true,
106
- page: response?.meta?.current_page,
107
- perPage: response?.meta?.per_page,
108
- total: response?.meta?.total,
109
- onPage: (page) => this.list(page),
110
91
  links: {
111
92
  secondary: [{ title: 'View', fn: (_link, item) => this.view(item) }],
112
93
  },
113
94
  };
114
95
  }
115
96
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ShipmentsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
116
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ShipmentsComponent, isStandalone: false, selector: "x-shipments", 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\">Shipments</div>\n <div class=\"x-page-subtitle\">Dispatch, deliver, and record delivery exceptions (ORD-08).</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: 'Shipment' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <span class=\"badge text-bg-light border\">{{ detail.status }}</span>\n @if (detail.trackingRef) {\n <div class=\"small text-secondary mt-1\">{{ detail.carrier }} \u00B7 {{ detail.trackingRef }}</div>\n }\n @if (detail.dispatchedAt) {\n <div class=\"small text-secondary\">Dispatched {{ detail.dispatchedAt | date: 'MMM d, h:mm a' }}</div>\n }\n @if (detail.deliveredAt) {\n <div class=\"small text-secondary\">Delivered {{ detail.deliveredAt | date: 'MMM d, h:mm a' }}</div>\n }\n </div>\n\n <div class=\"d-flex flex-wrap gap-2\">\n @if (detail.status === 'preparing' || detail.status === 'ready_for_dispatch') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" (click)=\"dispatch()\">Dispatch</button>\n }\n @if (detail.status === 'dispatched' || detail.status === 'out_for_delivery' || detail.status === 'failed_delivery') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-success\" (click)=\"deliver()\">Mark delivered</button>\n }\n </div>\n\n <table class=\"table table-sm\">\n <thead><tr><th>Order line</th><th>Qty</th><th>Serials</th></tr></thead>\n <tbody>\n @for (line of detail.lines; track line.id) {\n <tr>\n <td class=\"font-monospace small\">{{ line.orderLineId }}</td>\n <td>{{ line.quantity }}</td>\n <td class=\"small\">{{ line.serialNumbers?.join(', ') || '\u2014' }}</td>\n </tr>\n } @empty {\n <tr><td colspan=\"3\" class=\"text-secondary\">No lines.</td></tr>\n }\n </tbody>\n </table>\n\n <div>\n <div class=\"fw-bold small mb-1\">Delivery exceptions</div>\n @for (ex of detail.exceptions; track ex.id) {\n <div class=\"small text-secondary\">\n Attempt {{ ex.attemptNumber }} \u00B7 {{ ex.reasonCode }}\n @if (ex.notes) { \u2014 {{ ex.notes }} }\n </div>\n } @empty {\n <div class=\"small text-secondary\">None.</div>\n }\n </div>\n\n <hr class=\"my-1\" />\n <div class=\"d-flex flex-column gap-2\">\n <div class=\"fw-bold small\">Record an exception</div>\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"exceptionReason\">\n @for (reason of reasons; track reason) {\n <option [value]=\"reason\">{{ reason }}</option>\n }\n </select>\n <input class=\"form-control form-control-sm\" placeholder=\"Note (optional)\" [(ngModel)]=\"exceptionNote\" />\n <button type=\"button\" class=\"btn btn-sm btn-outline-warning align-self-start\" (click)=\"recordException()\">\n Record exception\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.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: i1$1.LoaderComponent, selector: "x-element-loader", inputs: ["data"] }, { kind: "component", type: i1$1.CollectionComponent, selector: "x-webget-collection", inputs: ["data"], outputs: ["search", "filter", "refresh", "select", "page", "show"] }, { kind: "component", type: i1$1.FlyoutComponent, selector: "x-webget-flyout", inputs: ["data"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); }
97
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: ShipmentsComponent, isStandalone: false, selector: "x-shipments", 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\">Shipments</div>\n <div class=\"x-page-subtitle\">Dispatch, deliver, and record delivery exceptions (ORD-08).</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: 'Shipment' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <span class=\"badge text-bg-light border\">{{ detail.status }}</span>\n @if (detail.trackingRef) {\n <div class=\"small text-secondary mt-1\">{{ detail.carrier }} \u00B7 {{ detail.trackingRef }}</div>\n }\n @if (detail.dispatchedAt) {\n <div class=\"small text-secondary\">Dispatched {{ detail.dispatchedAt | date: 'MMM d, h:mm a' }}</div>\n }\n @if (detail.deliveredAt) {\n <div class=\"small text-secondary\">Delivered {{ detail.deliveredAt | date: 'MMM d, h:mm a' }}</div>\n }\n </div>\n\n <div class=\"d-flex flex-wrap gap-2\">\n @if (detail.status === 'preparing' || detail.status === 'ready_for_dispatch') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" (click)=\"dispatch()\">Dispatch</button>\n }\n @if (detail.status === 'dispatched' || detail.status === 'out_for_delivery' || detail.status === 'failed_delivery') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-success\" (click)=\"deliver()\">Mark delivered</button>\n }\n </div>\n\n <table class=\"table table-sm\">\n <thead><tr><th>Order line</th><th>Qty</th><th>Serials</th></tr></thead>\n <tbody>\n @for (line of detail.lines; track line.id) {\n <tr>\n <td class=\"font-monospace small\">{{ line.orderLineId }}</td>\n <td>{{ line.quantity }}</td>\n <td class=\"small\">{{ line.serialNumbers?.join(', ') || '\u2014' }}</td>\n </tr>\n } @empty {\n <tr><td colspan=\"3\" class=\"text-secondary\">No lines.</td></tr>\n }\n </tbody>\n </table>\n\n <div>\n <div class=\"fw-bold small mb-1\">Delivery exceptions</div>\n @for (ex of detail.exceptions; track ex.id) {\n <div class=\"small text-secondary\">\n Attempt {{ ex.attemptNumber }} \u00B7 {{ ex.reasonCode }}\n @if (ex.notes) { \u2014 {{ ex.notes }} }\n </div>\n } @empty {\n <div class=\"small text-secondary\">None.</div>\n }\n </div>\n\n <hr class=\"my-1\" />\n <div class=\"d-flex flex-column gap-2\">\n <div class=\"fw-bold small\">Record an exception</div>\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"exceptionReason\">\n @for (reason of reasons; track reason) {\n <option [value]=\"reason\">{{ reason }}</option>\n }\n </select>\n <input class=\"form-control form-control-sm\" placeholder=\"Note (optional)\" [(ngModel)]=\"exceptionNote\" />\n <button type=\"button\" class=\"btn btn-sm btn-outline-warning align-self-start\" (click)=\"recordException()\">\n Record exception\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.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" }, { kind: "pipe", type: i3.DatePipe, name: "date" }] }); }
117
98
  }
118
99
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ShipmentsComponent, decorators: [{
119
100
  type: Component,
@@ -127,7 +108,7 @@ class ShipmentsModule {
127
108
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ShipmentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
128
109
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.16", ngImport: i0, type: ShipmentsModule, declarations: [ShipmentsComponent], imports: [SharedModule,
129
110
  ElementsModule,
130
- WebgetsModule, i1$2.RouterModule] }); }
111
+ WebgetsModule, i1$1.RouterModule] }); }
131
112
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: ShipmentsModule, imports: [SharedModule,
132
113
  ElementsModule,
133
114
  WebgetsModule,
@@ -147,4 +128,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
147
128
  }] });
148
129
 
149
130
  export { ShipmentsModule };
150
- //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-shipments.module-XuaOKr8v.mjs.map
131
+ //# sourceMappingURL=isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isaiahiroko-tilmart-ngx-apps-admin-shipments.module-Cs5CLamm.mjs","sources":["../../../projects/admin/src/lib/pages/shipments/shipments.component.ts","../../../projects/admin/src/lib/pages/shipments/shipments.component.html","../../../projects/admin/src/lib/pages/shipments/shipments.module.ts"],"sourcesContent":["import { Component, TemplateRef, ViewChild, inject } from '@angular/core';\nimport { notify, using } from '@thescaffold/ngx-core';\nimport { FlyoutService } from '@thescaffold/ngx-ui';\nimport { takeUntil } from 'rxjs';\nimport { ListPageDirective } from '../_shared/list-page.base';\n\nconst EXCEPTION_REASONS = [\n 'recipient_unavailable',\n 'address_not_found',\n 'recipient_refused',\n 'damaged_in_transit',\n 'access_blocked',\n 'weather',\n 'vehicle_issue',\n 'security',\n 'other',\n];\n\n// ORD-08 / ORD-12 — the fulfilment queue. List every shipment; drill in\n// to dispatch, mark delivered, or record a delivery exception (each\n// calls `FulfilmentWorkflow` via the shipment controller).\n@Component({\n standalone: false,\n selector: 'x-shipments',\n templateUrl: './shipments.component.html',\n styleUrl: './shipments.component.scss',\n})\nexport class ShipmentsComponent extends ListPageDirective {\n private readonly flyoutService = inject(FlyoutService);\n\n protected pluralName = 'shipments';\n protected dataSource = this.apiService.on('apps/commerce/shipment');\n private readonly lineSource = this.apiService.on('apps/commerce/shipment-line');\n private readonly exceptionSource = this.apiService.on('apps/commerce/delivery-exception');\n\n readonly reasons = EXCEPTION_REASONS;\n\n protected columns = [\n { key: 'status', value: 'Status', type: 'class', class: 'badge text-bg-light border' },\n { key: 'orderId', value: 'Order' },\n { key: 'carrier', value: 'Carrier' },\n { key: 'trackingRef', value: 'Tracking' },\n { key: 'createdAt', value: 'Created', type: 'date' },\n ];\n\n detail: any = null;\n exceptionReason = 'recipient_unavailable';\n exceptionNote = '';\n\n @ViewChild('detailFlyout', { read: TemplateRef, static: true })\n detailFlyout!: TemplateRef<any>;\n\n view(item: any) {\n this.detail = null;\n this.exceptionReason = 'recipient_unavailable';\n this.exceptionNote = '';\n this.flyoutService.open(this.detailFlyout);\n\n this.lineSource\n .getMany({ shipmentId: item.id, page: 1, perPage: 100 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(\n using(({ data: lines }: { data: any[] }) => {\n this.detail = { ...item, lines: lines ?? [], exceptions: [] };\n this.exceptionSource\n .getMany({ shipmentId: item.id, page: 1, perPage: 50 } as any)\n .pipe(takeUntil(this.$))\n .subscribe(using(({ data }: { data: any[] }) => {\n if (this.detail) this.detail.exceptions = data ?? [];\n }));\n }),\n );\n }\n\n private act(path: string, body: Record<string, unknown>, okMsg: string) {\n this.apiService\n .post(`apps/commerce/shipment/${this.detail.id}/${path}`, body)\n .pipe(takeUntil(this.$))\n .subscribe(\n using((res: any) => {\n if (res?.status === 'error') {\n notify(res.message || 'That action failed.', undefined, 'error');\n return;\n }\n notify(okMsg, undefined, 'success');\n this.flyoutService.dismiss();\n this.list();\n }),\n );\n }\n\n dispatch() {\n this.act('dispatch', {}, 'Shipment dispatched.');\n }\n\n deliver() {\n this.act('deliver', {}, 'Shipment marked delivered.');\n }\n\n recordException() {\n this.act(\n 'exception',\n { reasonCode: this.exceptionReason, notes: this.exceptionNote || undefined },\n 'Delivery exception recorded.',\n );\n }\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","<div class=\"x-page-head\">\n <div class=\"x-page-title\">Shipments</div>\n <div class=\"x-page-subtitle\">Dispatch, deliver, and record delivery exceptions (ORD-08).</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: 'Shipment' }\">\n <div class=\"p-4 d-flex flex-column gap-3\">\n @if (detail) {\n <div>\n <span class=\"badge text-bg-light border\">{{ detail.status }}</span>\n @if (detail.trackingRef) {\n <div class=\"small text-secondary mt-1\">{{ detail.carrier }} · {{ detail.trackingRef }}</div>\n }\n @if (detail.dispatchedAt) {\n <div class=\"small text-secondary\">Dispatched {{ detail.dispatchedAt | date: 'MMM d, h:mm a' }}</div>\n }\n @if (detail.deliveredAt) {\n <div class=\"small text-secondary\">Delivered {{ detail.deliveredAt | date: 'MMM d, h:mm a' }}</div>\n }\n </div>\n\n <div class=\"d-flex flex-wrap gap-2\">\n @if (detail.status === 'preparing' || detail.status === 'ready_for_dispatch') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-dark\" (click)=\"dispatch()\">Dispatch</button>\n }\n @if (detail.status === 'dispatched' || detail.status === 'out_for_delivery' || detail.status === 'failed_delivery') {\n <button type=\"button\" class=\"btn btn-sm btn-outline-success\" (click)=\"deliver()\">Mark delivered</button>\n }\n </div>\n\n <table class=\"table table-sm\">\n <thead><tr><th>Order line</th><th>Qty</th><th>Serials</th></tr></thead>\n <tbody>\n @for (line of detail.lines; track line.id) {\n <tr>\n <td class=\"font-monospace small\">{{ line.orderLineId }}</td>\n <td>{{ line.quantity }}</td>\n <td class=\"small\">{{ line.serialNumbers?.join(', ') || '—' }}</td>\n </tr>\n } @empty {\n <tr><td colspan=\"3\" class=\"text-secondary\">No lines.</td></tr>\n }\n </tbody>\n </table>\n\n <div>\n <div class=\"fw-bold small mb-1\">Delivery exceptions</div>\n @for (ex of detail.exceptions; track ex.id) {\n <div class=\"small text-secondary\">\n Attempt {{ ex.attemptNumber }} · {{ ex.reasonCode }}\n @if (ex.notes) { — {{ ex.notes }} }\n </div>\n } @empty {\n <div class=\"small text-secondary\">None.</div>\n }\n </div>\n\n <hr class=\"my-1\" />\n <div class=\"d-flex flex-column gap-2\">\n <div class=\"fw-bold small\">Record an exception</div>\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"exceptionReason\">\n @for (reason of reasons; track reason) {\n <option [value]=\"reason\">{{ reason }}</option>\n }\n </select>\n <input class=\"form-control form-control-sm\" placeholder=\"Note (optional)\" [(ngModel)]=\"exceptionNote\" />\n <button type=\"button\" class=\"btn btn-sm btn-outline-warning align-self-start\" (click)=\"recordException()\">\n Record exception\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 { ShipmentsComponent } from './shipments.component';\n\n@NgModule({\n declarations: [ShipmentsComponent],\n imports: [\n SharedModule,\n ElementsModule,\n WebgetsModule,\n RouterModule.forChild([{ path: '', component: ShipmentsComponent }]),\n ],\n})\nexport class ShipmentsModule {}\n"],"names":["i1"],"mappings":"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"}