Files
pleno-vue/src/composables/useWashSessionActions.js
T

358 lines
9.9 KiB
JavaScript

import { computed, ref, watch } from "vue";
import {
buildSelfServeDynamicImageUrl,
getSelfServeCompletedDynamicImageStep,
getSelfServeDynamicImageButtonsToPress,
getSelfServeDynamicImageThumbPosition,
getSelfServeTaskDynamicImageButtons,
} from "@/services/selfServeDynamicImage.js";
export function useWashSessionActions(options) {
const {
request,
alertFn = (message) => window.alert(message),
nearestDepartment,
vehicleTypeSelect,
washLaneId,
washInProgress,
washStartTime,
completedDurationMs,
now,
currentStep,
steps,
radioWashType,
activeTasks,
completedTasks,
saveProgress,
clearProgress,
startElapsedTimer,
stopElapsedTimer,
updateLaneAllowedServices,
fetchWashSummary,
enableMachineRelay,
isServiceAllowed,
} = options;
const machineStartCurrentStep = ref(0);
const openingPropertyAccessGate = ref(false);
const openingPropertyExitGate = ref(false);
const isStartingWash = ref(false);
const lastCommandErrorMessage = ref(null);
const extractCommandErrorMessage = (
source,
fallback = "Der opstod en fejl ved udførelse af kommandoen. Prøv igen senere."
) => {
const candidates = [
source?.response?.data?.data?.message,
source?.response?.data?.message,
source?.response?.data?.error,
source?.data?.data?.message,
source?.data?.message,
source?.data?.error,
source?.message,
];
const message = candidates.find((candidate) => typeof candidate === "string" && candidate.trim() !== "");
return message || fallback;
};
const getTaskButtons = (task) => getSelfServeTaskDynamicImageButtons(task);
const getButtonsToPress = () => getSelfServeDynamicImageButtonsToPress(activeTasks.value);
const getCompletedButtons = () => {
const totalButtonsCompleted = getSelfServeCompletedDynamicImageStep(activeTasks.value, completedTasks.value);
machineStartCurrentStep.value = totalButtonsCompleted;
return totalButtonsCompleted;
};
const isAlreadyStoppedStopError = (message) => {
const normalized = String(message || "").toLowerCase();
return normalized.includes("cannot stop lane") && normalized.includes("not occupied");
};
const clearActiveWashState = () => {
completedDurationMs.value = washStartTime.value ? now.value - washStartTime.value : 0;
washInProgress.value = false;
washLaneId.value = null;
stopElapsedTimer();
clearProgress();
};
const dynamicImageUrl = computed(() => {
const departmentId = nearestDepartment.value?.id;
const laneId = washLaneId.value;
const lane = nearestDepartment.value?.lanes?.find((entry) => entry.id === laneId);
if (!departmentId || !laneId || !lane) {
return null;
}
return buildSelfServeDynamicImageUrl({
departmentId,
laneId,
buttons: getButtonsToPress(),
currentStep: getCompletedButtons(),
vehicleTypeId: vehicleTypeSelect.value,
thumbPosition: getSelfServeDynamicImageThumbPosition(activeTasks.value),
});
});
const executeSelfServeCommand = async (
laneId,
command,
args = {
customer_number: null,
license_plate: null,
},
options = {}
) => {
if (!nearestDepartment.value) {
alertFn("Ingen afdeling valgt.");
return null;
}
const { suppressAlert = false } = options;
lastCommandErrorMessage.value = null;
try {
const response = await request("/modules/self-serve/lane/command", "post", {
lane_id: laneId,
command,
...args,
});
const successValue = response?.data?.success ?? response?.success;
if (successValue === false) {
const message = extractCommandErrorMessage(response);
lastCommandErrorMessage.value = message;
if (!suppressAlert) {
alertFn(message);
}
return null;
}
return response;
} catch (error) {
console.error(`Error executing command ${command} on lane ${laneId}:`, error);
const message = extractCommandErrorMessage(error);
lastCommandErrorMessage.value = message;
if (!suppressAlert) {
alertFn(message);
}
return null;
}
};
const resolveLaneId = (laneId = null, options = {}) => {
const { suppressAlert = false } = options;
const normalizedLaneId = Number.parseInt(String(laneId ?? washLaneId.value ?? ""), 10);
if (!Number.isInteger(normalizedLaneId) || normalizedLaneId <= 0) {
if (!suppressAlert) {
alertFn("Ingen vaskebane valgt.");
}
return null;
}
return normalizedLaneId;
};
const executePropertyGateCommand = async (command, laneId, loadingRef, options = {}) => {
if (loadingRef.value) {
return null;
}
loadingRef.value = true;
try {
const resolvedLaneId = resolveLaneId(laneId, options);
if (!resolvedLaneId) {
return null;
}
return await executeSelfServeCommand(
resolvedLaneId,
command,
{
customer_number: null,
license_plate: null,
},
options
);
} finally {
loadingRef.value = false;
}
};
const openPropertyAccessGate = async (laneId = null, options = {}) =>
executePropertyGateCommand("OPEN_PROPERTY_ACCESS_GATE", laneId, openingPropertyAccessGate, options);
const openPropertyExitGate = async (laneId = null, options = {}) =>
executePropertyGateCommand("OPEN_PROPERTY_EXIT_GATE", laneId, openingPropertyExitGate, options);
const rollbackStartedWash = async (laneId) => {
const stopResponse = await executeSelfServeCommand(
laneId,
"STOP",
{
customer_number: null,
license_plate: null,
},
{ suppressAlert: true }
);
if (!stopResponse) {
console.error(`Failed to roll back started wash on lane ${laneId}:`, lastCommandErrorMessage.value);
}
return stopResponse;
};
const onStartWash = async (laneId, licensePlate, customerNumber, targetStep = steps.WASH_IN_PROGRESS) => {
if (isStartingWash.value) {
return false;
}
if (washInProgress.value && currentStep.value === targetStep) {
return true;
}
if (washInProgress.value) {
currentStep.value = targetStep;
return true;
}
if (!nearestDepartment.value) {
alertFn("Ingen afdeling valgt.");
return false;
}
if (!licensePlate || licensePlate.trim() === "") {
alertFn("Indtast venligst et registreringsnummer.");
return false;
}
if (!parseInt(customerNumber)) {
alertFn("Indtast venligst et kundenummer.");
return false;
}
isStartingWash.value = true;
try {
try {
await updateLaneAllowedServices(laneId);
} catch (error) {
console.error("Error updating allowed services before start:", error);
alertFn(extractCommandErrorMessage(error, "Der opstod en fejl ved klargøring af vasken. Prøv igen senere."));
return false;
}
const startResponse = await executeSelfServeCommand(laneId, "START", {
customer_number: parseInt(customerNumber),
license_plate: licensePlate.trim().toUpperCase(),
defer_relay_side_effects: false,
});
if (!startResponse) {
return false;
}
if (radioWashType.value === "Machine" && isServiceAllowed("MACHINE")) {
let machineRelayResponse = null;
try {
machineRelayResponse = await enableMachineRelay(laneId);
} catch (error) {
console.error("Error enabling machine relay after wash start:", error);
await rollbackStartedWash(laneId);
alertFn(extractCommandErrorMessage(error, "Kunne ikke starte maskinen. Prøv igen."));
return false;
}
const machineRelaySuccessValue = machineRelayResponse?.data?.success ?? machineRelayResponse?.success;
if (machineRelaySuccessValue === false) {
await rollbackStartedWash(laneId);
alertFn(extractCommandErrorMessage(machineRelayResponse, "Kunne ikke starte maskinen. Prøv igen."));
return false;
}
}
washLaneId.value = laneId;
washStartTime.value = Date.now();
completedDurationMs.value = null;
washInProgress.value = true;
startElapsedTimer();
currentStep.value = targetStep;
saveProgress("onStartWash");
await fetchWashSummary({
lane_id: laneId,
reg: licensePlate.trim().toUpperCase(),
});
return true;
} catch (error) {
console.error("Error starting self-serve wash:", error);
alertFn(extractCommandErrorMessage(error, "Der opstod en fejl ved start af vasken. Prøv igen senere."));
return false;
} finally {
isStartingWash.value = false;
}
};
const onStopWash = async (laneId) => {
if (!nearestDepartment.value) {
alertFn("Ingen afdeling valgt.");
return false;
}
if (!washInProgress.value) {
alertFn("Ingen vask er i gang.");
return false;
}
const stopResponse = await executeSelfServeCommand(
laneId,
"STOP",
{
customer_number: null,
license_plate: null,
},
{ suppressAlert: true }
);
if (!stopResponse) {
if (isAlreadyStoppedStopError(lastCommandErrorMessage.value)) {
clearActiveWashState();
return true;
}
alertFn(lastCommandErrorMessage.value || "Der opstod en fejl ved udførelse af kommandoen. Prøv igen senere.");
return false;
}
clearActiveWashState();
return true;
};
watch(
[completedTasks, activeTasks],
() => {
getCompletedButtons();
},
{ deep: true }
);
return {
machineStartCurrentStep,
dynamicImageUrl,
getButtonsToPress,
getCompletedButtons,
executeSelfServeCommand,
onStartWash,
onStopWash,
openPropertyAccessGate,
openPropertyExitGate,
openingPropertyAccessGate,
openingPropertyExitGate,
isStartingWash,
};
}