Add vehicle type management and summary display in time booking process

This commit is contained in:
Jepp9350
2025-05-27 11:23:09 +02:00
parent 8c33f12ff2
commit f12149cce5
8 changed files with 198 additions and 23 deletions
@@ -59,7 +59,7 @@ const uniqueId = Math.random().toString(36).substring(7);
</div>
<!-- Optional price display -->
<div class="level-item" v-if="price !== null">
<span class="tag is-success">{{ SessionUser.functions.currency.toLocal(price) }}</span>
<span class="tag is-rounded is-light" v-bind:class="{ 'is-success': props.value }">{{ SessionUser.functions.currency.toLocal(price) }}</span>
</div>
</div>
</nav>
@@ -34,6 +34,7 @@ export const ObjectsGlobal = {
import: "Importer",
phone_country_code: "Landekode",
succeeded: "Fuldførte",
summary: "Oversigt",
opening_hours: "Åbningstider",
customers: "Kunder",
selected: "Valgt",
@@ -3,21 +3,14 @@ import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrap
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import TimeBookingsCalendar from "@/components/timebookings/TimeBookingsCalendar.vue";
import TimeBookingsTypesPagination
from "@/components/displays/pagination/models/DepartmentPos/TimeBookingsTypesPagination.vue";
import TimeBookingsNewStep1
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/steps/TimeBookingsNewStep1.vue";
import {timeBookingsNewProcess}
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/TimeBookingsNewProcess.vue";
import ButtonsBox from "@/components/displays/boxes/ButtonsBox.vue";
import {timeBookingsNewProcess} from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/TimeBookingsNewProcess.vue";
import TimeBookingsNewControls
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/displays/TimeBookingsNewControls.vue";
import ShowErrorField from "@/components/global/ShowErrorField.vue";
import TimeBookingsNewStepDivider
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/displays/TimeBookingsNewStepDivider.vue";
import TimeBookingsNewSummaryView
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/displays/TimeBookingsNewSummaryView.vue";
</script>
<template>
@@ -29,12 +22,14 @@ import TimeBookingsNewStepDivider
<TimeBookingsNewStepDivider>
<!-- If no component is available, show a fallback -->
<NotFoundFallBackPageWrapper :exists="timeBookingsNewProcess.getCurrentComponentView() !== null" error="Der er ingen trin tilgængelige for denne tidsbooking.">
<!-- Steps for creating a new time booking -->
<component :is="timeBookingsNewProcess.getCurrentComponentView()" v-bind="timeBookingsNewProcess" v-if="timeBookingsNewProcess.getCurrentComponentView()" v-bind:timeBookingsNewProcess="timeBookingsNewProcess"/>
{{ timeBookingsNewProcess.phone_country_code}}
{{ timeBookingsNewProcess.phone }}
{{ timeBookingsNewProcess.reg_1}}
{{timeBookingsNewProcess.vehicleType}}
<TimeBookingsNewSummaryView>
<template #content-left>
<!-- Steps for creating a new time booking -->
<component :is="timeBookingsNewProcess.getCurrentComponentView()" v-bind="timeBookingsNewProcess" v-if="timeBookingsNewProcess.getCurrentComponentView()" v-bind:timeBookingsNewProcess="timeBookingsNewProcess"/>
</template>
<template #content-bottom>
</template>
</TimeBookingsNewSummaryView>
<!-- If the step is not found, show an error message -->
<template #error>
<ShowErrorField :message="`Trin ${timeBookingsNewProcess.step.value}'s komponent blev ikke fundet. Dette er en fejl i systemet, og formodentligvis en fejl i udviklingen. Kontakt venligst support, hvis du ser denne fejl.`"/>
@@ -16,6 +16,7 @@ const isBookingForCustomer = ref(false); // Flag to indicate if the booking is f
const persistentCookiesEnabled = ref(false); // Flag to indicate if persistent cookies are enabled
const cookie_expires = '365d'; // Cookie expiration time
const addons = ref([]); // Placeholder for addons, if any
const vehicleTypeObject = ref(null); // Placeholder for the vehicle type object
// Persistent cookies for storing user data
const cookies = useCookies().cookies;
const getCookieName = (name) => {
@@ -202,12 +203,36 @@ const getAddons = () => {
return addons.value;
};
const toggleAddon = (addon) => {
const addonObjects = ref([]); // Addon objects to be used in the booking process
const getAddonObject = (addon) => {
// Function to get the addon object by its ID
return addonObjects.value.find(obj => obj.id === addon) || null;
};
const addAddonObject = (addon) => {
// Function to add an addon object to the list
if (!addonObjects.value.some(obj => obj.id === addon.id)) {
addonObjects.value.push(addon);
}
};
const removeAddonObject = (addon) => {
// Function to remove an addon object from the list
const index = addonObjects.value.findIndex(obj => obj.id === addon.id);
if (index > -1) {
addonObjects.value.splice(index, 1);
}
};
const toggleAddon = (addon, addon_object) => {
// Function to toggle an addon
if (hasAddon(addon)) {
removeAddon(addon);
removeAddonObject(addon_object);
} else {
addAddon(addon);
addAddonObject(addon_object);
}
};
@@ -246,6 +271,14 @@ watch([reg_1], ([newReg1]) => {
if (newReg1) reg_1.value = formatRegistrationNumber(newReg1);
});
// Watch for changes in the vehicle type, remove the addon objects if the vehicle type is changed
watch(vehicleType, (newVehicleType) => {
if (newVehicleType !== null) {
// If a new vehicle type is selected, clear the addons
addonObjects.value = [];
addons.value = [];
}
});
// Expose the nextStep and previousStep methods
export const timeBookingsNewProcess = {
@@ -272,5 +305,10 @@ export const timeBookingsNewProcess = {
hasAddon,
getAddons,
toggleAddon,
getAddonObject,
addonObjects,
addAddonObject,
removeAddonObject,
vehicleTypeObject
};
</script>
@@ -0,0 +1,44 @@
<script setup lang="ts">
import { SessionUser } from '@/components/session/token/SessionUser.vue';
import TimeBookingsNewSummaryLine
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/displays/TimeBookingsNewSummaryLine.vue";
import { timeBookingsNewProcess } from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/TimeBookingsNewProcess.vue";
import {ref, computed} from "vue";
</script>
<template>
<div>
<label class="label">{{ SessionUser.objects.global.language.summary }}</label>
<!-- Phone number summary line -->
<TimeBookingsNewSummaryLine label="Telefonnummer" :value="`${timeBookingsNewProcess.phone_country_code.value} ${timeBookingsNewProcess.phone.value}`"/>
<!-- Registration number summary line -->
<TimeBookingsNewSummaryLine label="Registreringsnummer" :value="timeBookingsNewProcess.reg_1.value"/>
<!-- Primary vehicle type summary line -->
<TimeBookingsNewSummaryLine
v-if="timeBookingsNewProcess.vehicleTypeObject.value"
label="Primær køretøjstype"
v-bind:value="timeBookingsNewProcess.vehicleTypeObject.value ? timeBookingsNewProcess.vehicleTypeObject.value.label : 'Ikke valgt'"
/>
<!-- Price summary line -->
<TimeBookingsNewSummaryLine
v-if="timeBookingsNewProcess.vehicleTypeObject.value"
v-bind:label="timeBookingsNewProcess.vehicleTypeObject.value ? timeBookingsNewProcess.vehicleTypeObject.value.label : 'Ikke valgt'"
v-bind:value="timeBookingsNewProcess.vehicleTypeObject.value ? SessionUser.functions.currency.toLocal(timeBookingsNewProcess.vehicleTypeObject.value.price) : 'Ikke valgt'"
color="is-success"
/>
<!-- Addons summary line -->
<template v-for="addon in timeBookingsNewProcess.addonObjects.value" :key="addon.id">
<TimeBookingsNewSummaryLine
:label="addon.name"
v-bind:value="SessionUser.functions.currency.toLocal(addon.product.price)"
icon="fas fa-plus"
color="is-info"
/>
</template>
</div>
</template>
<style scoped>
</style>
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { defineProps, ref, computed } from 'vue';
const props = defineProps({
label: {
type: String,
required: true,
},
value: {
type: [String, Number],
default: '',
},
icon: {
type: String,
default: '',
},
color: {
type: String,
default: 'is-primary',
},
});
</script>
<template>
<!-- Level summary line -->
<nav class="level is-mobile" style="width: 100%;">
<div class="level-left">
<!-- Left side with icon and label -->
<div class="level-item">
<span class="icon" v-if="icon">
<i :class="icon"></i>
</span>
<span>{{ label }}</span>
</div>
</div>
<div class="level-right">
<!-- Right side with value -->
<div class="level-item">
<span style="font-weight: bold;">
{{ value }}
</span>
</div>
</div>
</nav>
</template>
<style scoped>
</style>
@@ -0,0 +1,28 @@
<script setup lang="ts">
import TimeBookingsNewSummary
from "@/views/dashboards/departmentDashboard/modules/time-bookings/book/displays/TimeBookingsNewSummary.vue";
</script>
<template>
<div class="columns is-multiline">
<!-- Left column -->
<div class="column is-half">
<slot name="content-left"></slot>
</div>
<!-- Summary of the new time booking -->
<div class="column is-half">
<TimeBookingsNewSummary />
<!-- Additional slot -->
<slot name="content-right"></slot>
</div>
<!-- Bottom column -->
<div class="column is-full">
<slot name="content-bottom"></slot>
</div>
</div>
</template>
<style scoped>
</style>
@@ -1,7 +1,7 @@
<script setup>
import ConfigurationSelect from "@/components/displays/superuser/configuration/ConfigurationSelect.vue";
import {SessionUser} from "@/components/session/token/SessionUser.vue";
import {defineEmits, defineProps, ref} from "vue";
import {defineEmits, defineProps, ref, watch} from "vue";
import ConfigurationSwitch from "@/components/displays/superuser/configuration/ConfigurationSwitch.vue";
const props = defineProps({
@@ -13,7 +13,7 @@ const props = defineProps({
const emits = defineEmits(['update:selected']);
const countryCodes = ref(null);
const onSelect = (value) => {
const onSelect = (value, automated = false) => {
// Attempt to set the selected vehicle type
props.timeBookingsNewProcess.vehicleType.value = value;
emits('update:selected', value);
@@ -42,6 +42,27 @@ const getVehicleType = (id) => {
return vehicleTypes.value.filter(vehicle => vehicle.value === parseInt(id))[0];
};
watch(() => props.timeBookingsNewProcess.vehicleType.value, (newValue) => {
if (newValue !== null) {
props.timeBookingsNewProcess.vehicleTypeObject.value = getVehicleType(newValue);
} else {
props.timeBookingsNewProcess.vehicleTypeObject.value = null;
}
});
// Watch for changes in the vehicleTypes array to update the vehicle type object
watch(vehicleTypes, (newVehicleTypes) => {
if (props.timeBookingsNewProcess.vehicleType.value !== null) {
props.timeBookingsNewProcess.vehicleTypeObject.value = getVehicleType(props.timeBookingsNewProcess.vehicleType.value);
}
});
// Initialize the vehicle type object based on the current value
if (props.timeBookingsNewProcess.vehicleType.value !== null) {
onSelect(props.timeBookingsNewProcess.vehicleType.value, true);
} else {
props.timeBookingsNewProcess.vehicleTypeObject.value = null;
}
</script>
<template>
@@ -63,13 +84,12 @@ const getVehicleType = (id) => {
<ConfigurationSwitch
v-bind:is-compact="true"
v-bind:value="props.timeBookingsNewProcess.hasAddon(addon.option_id)"
v-bind:on-switch="() => props.timeBookingsNewProcess.toggleAddon(addon.option_id)"
v-bind:on-switch="() => props.timeBookingsNewProcess.toggleAddon(addon.option_id, addon)"
v-bind:title="addon.name"
v-bind:description="addon.description"
v-bind:price="addon.price"
v-bind:price="addon.product.price"
/>
</template>
{{ props.timeBookingsNewProcess.getAddons()}}
</div>
</template>