diff --git a/src/components/displays/selfServe/SelfServeTasksStep.vue b/src/components/displays/selfServe/SelfServeTasksStep.vue index c6b36181..2046fc1f 100644 --- a/src/components/displays/selfServe/SelfServeTasksStep.vue +++ b/src/components/displays/selfServe/SelfServeTasksStep.vue @@ -1,6 +1,6 @@ @@ -58,26 +66,28 @@ const onDynamicImageError = () => { {{ $t("self_wash.loading_data") }} + +
- Machine status @@ -107,19 +117,20 @@ const onDynamicImageError = () => { overflow: hidden; } +.self-serve-dynamic-image-preload { + position: absolute; + width: 0; + height: 0; + opacity: 0; + pointer-events: none; +} + @media screen and (min-width: 769px) { .self-serve-dynamic-image-frame { max-width: 640px; } } -.self-serve-dynamic-image-skeleton { - position: absolute; - inset: 0; - overflow: hidden; - border-radius: 4px; -} - .self-serve-dynamic-image { width: 100%; height: 100%; @@ -128,8 +139,4 @@ const onDynamicImageError = () => { object-fit: contain; transition: opacity 120ms ease; } - -.self-serve-dynamic-image.is-loading { - opacity: 0; -} diff --git a/src/composables/useSelfServeLogic.js b/src/composables/useSelfServeLogic.js index a9c47327..e6f7930c 100644 --- a/src/composables/useSelfServeLogic.js +++ b/src/composables/useSelfServeLogic.js @@ -271,6 +271,55 @@ const mergeByNumericId = (existingItems, incomingItems) => { return merged; }; +const taskStableKey = (task) => + String(task?.task ?? "") + .trim() + .toLowerCase(); + +const mergeTaskSets = (existingTasks, incomingTasks) => { + if (!Array.isArray(existingTasks) || existingTasks.length === 0) { + return Array.isArray(incomingTasks) ? [...incomingTasks] : []; + } + + if (!Array.isArray(incomingTasks) || incomingTasks.length === 0) { + return [...existingTasks]; + } + + const usedExistingIndexes = new Set(); + + return incomingTasks.map((incomingTask) => { + const incomingId = extractTaskId(incomingTask); + let existingIndex = -1; + + if (incomingId) { + existingIndex = existingTasks.findIndex((task) => extractTaskId(task) === incomingId); + } else { + const incomingKey = taskStableKey(incomingTask); + existingIndex = existingTasks.findIndex( + (task, index) => !usedExistingIndexes.has(index) && taskStableKey(task) === incomingKey + ); + } + + if (existingIndex === -1) { + return incomingTask; + } + + usedExistingIndexes.add(existingIndex); + const existingTask = existingTasks[existingIndex]; + + return { + ...existingTask, + ...incomingTask, + id: incomingTask.id || existingTask.id, + task_id: incomingTask.task_id || existingTask.task_id, + attachments: Array.isArray(incomingTask.attachments) && incomingTask.attachments.length > 0 + ? incomingTask.attachments + : existingTask.attachments, + _attachmentsLoaded: incomingTask._attachmentsLoaded || existingTask._attachmentsLoaded, + }; + }); +}; + export function useSelfServeLogic() { const loading = ref(false); const requestError = ref(null); @@ -537,8 +586,9 @@ export function useSelfServeLogic() { const normalizedTasks = summaryData.tasks .map(normalizeTask) .sort((a, b) => a.order_priority - b.order_priority); + const mergedTasks = mergeTaskSets(tasks.value, normalizedTasks); - const hydratedTasks = await hydrateTaskAttachments(normalizedTasks); + const hydratedTasks = await hydrateTaskAttachments(mergedTasks); if (!isFetchRequestActive(requestId)) { return false; } diff --git a/src/composables/useWashFlowState.js b/src/composables/useWashFlowState.js index 330f4442..16583cb2 100644 --- a/src/composables/useWashFlowState.js +++ b/src/composables/useWashFlowState.js @@ -19,7 +19,6 @@ export function useWashFlowState(options) { customerNumberInput, licensePlateInput, vehicleTypeSelect, - availableProductIds, isCustomerNumberRequired, radioLaneOption, nearestDepartment, @@ -58,10 +57,7 @@ export function useWashFlowState(options) { } const selectedVehicleTypeId = vehicleTypeSelect.value; - const allowedProductIds = new Set((availableProductIds.value || []).map((productId) => String(productId))); const hasSelectedVehicleType = selectedVehicleTypeId !== null && selectedVehicleTypeId !== undefined; - const hasAllowedVehicleType = hasSelectedVehicleType - && (allowedProductIds.size === 0 || allowedProductIds.has(String(selectedVehicleTypeId))); const customerNumberValue = customerNumberInput.value; const requiresCustomerNumber = isCustomerNumberRequired?.value ?? false; const customerNumberValid = !requiresCustomerNumber @@ -69,7 +65,7 @@ export function useWashFlowState(options) { || customerNumberValue === undefined || String(customerNumberValue).trim() !== ""; const licensePlateValid = !!(licensePlateInput.value && licensePlateInput.value.trim() !== ""); - if (!hasAllowedVehicleType) { + if (!hasSelectedVehicleType) { return false; } diff --git a/src/views/dashboards/userDashboard/wash/MyWashStart.vue b/src/views/dashboards/userDashboard/wash/MyWashStart.vue index 21f1dc36..b90f7b00 100644 --- a/src/views/dashboards/userDashboard/wash/MyWashStart.vue +++ b/src/views/dashboards/userDashboard/wash/MyWashStart.vue @@ -1860,6 +1860,7 @@ watch(