Task #69: Delete past orders from My Orders

- Add DELETE /api/orders/:id endpoint: owner can delete completed/cancelled
  orders; admin can delete any. 401/403/404/204 responses. Emits
  order_deleted to owner and assignee for live invalidation.
- Update OpenAPI spec with deleteServiceOrder operation; regenerate
  api-client-react + api-zod.
- Frontend: per-order trash button on completed/cancelled cards with
  confirm dialog; bulk "Clear finished (N)" button at top of list with
  confirm dialog and toast summary (handles partial failures).
- Add ar/en locale keys under myOrders for delete + clear flows
  (singular/plural variants).
- Backend tests cover all paths: pending owner=403, stranger=403,
  owner-cancelled=204, owner-completed=204, admin-pending=204, 404, 401.

All 25 service-order tests pass; the 1 failing test (admin-app-opens-
pagination) is unrelated/pre-existing.

Follow-ups proposed: #70 undo for deleted orders, #71 audit
self-notification on receiver-cancel-own-order.
This commit is contained in:
riyadhafraa
2026-04-22 06:37:01 +00:00
parent 7574357c2f
commit 58553d3d36
9 changed files with 454 additions and 16 deletions
+88
View File
@@ -4379,6 +4379,94 @@ export const useDeleteUser = <
return useMutation(getDeleteUserMutationOptions(options));
};
/**
* Permanently deletes the order. Allowed when the caller owns the order
AND it is in a terminal status (completed/cancelled), OR the caller is
an admin (any status).
* @summary Delete a service order
*/
export const getDeleteServiceOrderUrl = (id: number) => {
return `/api/orders/${id}`;
};
export const deleteServiceOrder = async (
id: number,
options?: RequestInit,
): Promise<void> => {
return customFetch<void>(getDeleteServiceOrderUrl(id), {
...options,
method: "DELETE",
});
};
export const getDeleteServiceOrderMutationOptions = <
TError = ErrorType<ErrorResponse>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteServiceOrder>>,
TError,
{ id: number },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteServiceOrder>>,
TError,
{ id: number },
TContext
> => {
const mutationKey = ["deleteServiceOrder"];
const { mutation: mutationOptions, request: requestOptions } = options
? options.mutation &&
"mutationKey" in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey }, request: undefined };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteServiceOrder>>,
{ id: number }
> = (props) => {
const { id } = props ?? {};
return deleteServiceOrder(id, requestOptions);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteServiceOrderMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteServiceOrder>>
>;
export type DeleteServiceOrderMutationError = ErrorType<ErrorResponse>;
/**
* @summary Delete a service order
*/
export const useDeleteServiceOrder = <
TError = ErrorType<ErrorResponse>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteServiceOrder>>,
TError,
{ id: number },
TContext
>;
request?: SecondParameter<typeof customFetch>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteServiceOrder>>,
TError,
{ id: number },
TContext
> => {
return useMutation(getDeleteServiceOrderMutationOptions(options));
};
/**
* @summary Idempotently add a role to a user (admin)
*/