feat: enforce checklist/minibar completion before marking task done
- ApiError now carries errors[] array from 422 responses - updateStatus re-throws 422 so TaskCard can surface errors - TaskCard: minibarCheckedLocal state + 'Подтвердить проверку минибара' button - TaskCard: async handleComplete with completionErrors display - Backend validation errors shown inline in completion panel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,10 @@ const BASE = (import.meta.env.VITE_API_URL as string | undefined) ?? 'https://ap
|
||||
// ── Errors ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(public status: number, message: string) {
|
||||
errors?: string[]
|
||||
constructor(public status: number, message: string, errors?: string[]) {
|
||||
super(message)
|
||||
this.errors = errors
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +117,10 @@ async function req<T>(
|
||||
const data: unknown = await res.json()
|
||||
|
||||
if (!res.ok) {
|
||||
const msg = (data as Record<string, string>)?.error ?? 'Request failed'
|
||||
throw new ApiError(res.status, msg)
|
||||
const d = data as Record<string, unknown>
|
||||
const msg = (d?.error as string) ?? 'Request failed'
|
||||
const errors = Array.isArray(d?.errors) ? (d.errors as string[]) : undefined
|
||||
throw new ApiError(res.status, msg, errors)
|
||||
}
|
||||
|
||||
return transformKeys(data) as T
|
||||
@@ -652,12 +656,13 @@ export const api = {
|
||||
task_type: data.taskType ?? null,
|
||||
}),
|
||||
|
||||
updateTemplate: (slug: string, templateId: string, data: { name?: string; taskType?: string | null; isActive?: boolean; sortOrder?: number }) =>
|
||||
updateTemplate: (slug: string, templateId: string, data: { name?: string; taskType?: string | null; isActive?: boolean; sortOrder?: number; requireBeforeComplete?: boolean }) =>
|
||||
req<ChecklistTemplate>('PATCH', `/api/hotels/${slug}/checklist-templates/${templateId}`, {
|
||||
name: data.name,
|
||||
task_type: data.taskType,
|
||||
is_active: data.isActive,
|
||||
sort_order: data.sortOrder,
|
||||
require_before_complete: data.requireBeforeComplete,
|
||||
}),
|
||||
|
||||
deleteTemplate: (slug: string, templateId: string) =>
|
||||
@@ -686,6 +691,14 @@ export const api = {
|
||||
|
||||
uncompleteItem: (slug: string, taskId: string, itemId: string) =>
|
||||
req<void>('DELETE', `/api/hotels/${slug}/housekeeping/${taskId}/checklist/${itemId}/complete`),
|
||||
|
||||
getHousekeepingRules: (slug: string) =>
|
||||
req<{ requireMinibarCheck: boolean }>('GET', `/api/hotels/${slug}/housekeeping-rules`),
|
||||
|
||||
updateHousekeepingRules: (slug: string, data: { requireMinibarCheck: boolean }) =>
|
||||
req<{ requireMinibarCheck: boolean }>('PATCH', `/api/hotels/${slug}/housekeeping-rules`, {
|
||||
require_minibar_check: data.requireMinibarCheck,
|
||||
}),
|
||||
},
|
||||
|
||||
// ── Minibar ───────────────────────────────────────────────────────────────
|
||||
@@ -842,6 +855,7 @@ export interface HkPayload {
|
||||
status?: string; assignee_id?: string; notes?: string; due_date?: string
|
||||
category?: string; photos?: string[]
|
||||
resolution_notes?: string; resolution_photos?: string[]
|
||||
minibar_checked?: boolean
|
||||
}
|
||||
|
||||
export interface HkSettings {
|
||||
@@ -1280,6 +1294,7 @@ export interface ChecklistTemplate {
|
||||
name: string
|
||||
taskType: string | null
|
||||
isActive: boolean
|
||||
requireBeforeComplete: boolean
|
||||
sortOrder: number
|
||||
createdAt: string
|
||||
items: ChecklistItem[]
|
||||
|
||||
Reference in New Issue
Block a user