diff --git a/src/app/features/admin/orders/pages/admin-order-detail-page.component.html b/src/app/features/admin/orders/pages/admin-order-detail-page.component.html index 1d71d18..6afaa2e 100644 --- a/src/app/features/admin/orders/pages/admin-order-detail-page.component.html +++ b/src/app/features/admin/orders/pages/admin-order-detail-page.component.html @@ -46,14 +46,17 @@

{{ 'adminOrders.changeStatus' | translate }}

- + @for (status of selectableStatuses; track status) { } + @if (isTerminal()) { + + }
- {{ 'adminOrders.requestRefund' | translate }} - {{ 'adminOrders.cancelOrder' | translate }} + {{ 'adminOrders.requestRefund' | translate }} + {{ 'adminOrders.cancelOrder' | translate }}
diff --git a/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts b/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts index 7435150..27d78b7 100644 --- a/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts +++ b/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts @@ -30,6 +30,8 @@ export class AdminOrderDetailPageComponent { private readonly translate = inject(TranslateService); readonly statuses: AdminOrderStatus[] = ['pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded']; + /** Terminal statuses are only reachable via the confirm-gated cancel()/requestRefund(), never the raw dropdown. */ + readonly selectableStatuses: AdminOrderStatus[] = this.statuses.filter(status => !TERMINAL_STATUSES.includes(status)); readonly workflowSteps = WORKFLOW_STEPS; readonly noteDraft = signal(''); readonly internalNoteDraft = signal(''); @@ -74,6 +76,11 @@ export class AdminOrderDetailPageComponent { } setStatus(id: string, status: AdminOrderStatus): void { + if (TERMINAL_STATUSES.includes(status)) { + // Unreachable from the dropdown (options are filtered), but guard anyway + // since terminal transitions must always go through the confirm dialog. + return; + } this.facade.setStatus(id, status); } diff --git a/src/app/features/admin/orders/pages/admin-orders-list-page.component.html b/src/app/features/admin/orders/pages/admin-orders-list-page.component.html index fce1a75..321d71d 100644 --- a/src/app/features/admin/orders/pages/admin-orders-list-page.component.html +++ b/src/app/features/admin/orders/pages/admin-orders-list-page.component.html @@ -37,8 +37,8 @@
{{ facade.selectedIds().length }} {{ 'adminProducts.selectedCount' | translate }} {{ 'adminOrders.applyStatus' | translate }} diff --git a/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts b/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts index 9c1d430..a8e36f8 100644 --- a/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts +++ b/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts @@ -30,6 +30,8 @@ export class AdminOrdersListPageComponent { private readonly languageService = inject(LanguageService); readonly statuses = ['all', 'pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'] as const; + /** Bulk status change excludes terminal statuses - cancel/refund must go through the confirm-gated single-order flow. */ + readonly bulkSelectableStatuses: AdminOrderStatus[] = ['pending', 'processing', 'shipped', 'delivered']; readonly allColumns = ALL_ORDER_COLUMNS; protected readonly columnsPanelOpen = signal(false); protected readonly bulkStatusValue = signal('pending');