Add vehicle type selection component to MyWashStart workflow
- Introduced `MyWashStartVehicleTypeSelection.vue` for vehicle type selection with enhanced UI and dynamic fetching. - Replaced deprecated "Type of vehicle" field with the new selection component. - Updated logic to handle vehicle type fetching, selection, and state updates in `MyWashStart.vue`.
This commit is contained in:
@@ -23,6 +23,9 @@ import {getDepartmentsGuest} from "@/components/pagination/departmentTabs.vue";
|
||||
import {computed, onMounted, onUnmounted, ref, watch} from "vue";
|
||||
import ScrollableSteps from "@/components/displays/steps/ScrollableSteps.vue";
|
||||
import { setShowFooterInContent } from "@/components/viewport/conditions/ViewPortFooterOptions.vue";
|
||||
import MyWashStartVehicleTypeSelection
|
||||
from "@/views/dashboards/userDashboard/wash/displays/MyWashStartVehicleTypeSelection.vue";
|
||||
import type { PosProduct } from '@/components/displays/department/pos/steps/mobile/objects/PosProduct.vue';
|
||||
|
||||
const guestDepartments = ref([]);
|
||||
|
||||
@@ -618,6 +621,20 @@ const previousGuidedWashStep = () => {
|
||||
currentGuidedWashStep.value -= 1;
|
||||
}
|
||||
}
|
||||
// Define the vehicle template object
|
||||
type VehicleTypeTemplate = {
|
||||
id: number;
|
||||
name: string;
|
||||
price: number;
|
||||
product?: PosProduct;
|
||||
selected?: boolean; // Optional selected state
|
||||
loading?: boolean; // Optional loading state
|
||||
};
|
||||
|
||||
const onSelectVehicleType = (selection: VehicleTypeTemplate) => {
|
||||
console.warn('Vehicle type selected:', selection);
|
||||
vehicleTypeSelect.value = selection.id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Watch for changes in the steps and update the localStorage accordingly.
|
||||
@@ -695,8 +712,12 @@ watch(() => currentStep.value, () => {
|
||||
<template #empty>Ingen køretøjer fundet</template>
|
||||
</b-autocomplete>
|
||||
</b-field>
|
||||
<!-- Select your vehicle -->
|
||||
<b-field label="Vælg dit køretøj">
|
||||
<MyWashStartVehicleTypeSelection @selected="onSelectVehicleType($event)" :selectedVehicleTypeId="vehicleTypeSelect"/>
|
||||
</b-field>
|
||||
<!-- Type of vehicle -->
|
||||
<b-field label="Type af køretøj">
|
||||
<b-field label="Type af køretøj" v-show="false"> <!-- TODO: Deprecate this field for "Select your vehicle" -->
|
||||
<b-select v-model="vehicleTypeSelect" placeholder="Vælg type af køretøj" expanded style="max-height: 200px; overflow-y: auto;" :loading="vehicleTypes.length === 0">
|
||||
<template v-if="vehicleTypes.length === 0">
|
||||
<option disabled>Indlæser typer...</option>
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref, defineEmits, defineProps, watch} from 'vue';
|
||||
import { SessionUser } from '@/components/session/token/SessionUser.vue';
|
||||
import type { PosProduct } from '@/components/displays/department/pos/steps/mobile/objects/PosProduct.vue';
|
||||
import WhiteBoxCard from "@/components/displays/boxes/WhiteBoxCard.vue";
|
||||
import { getPicture } from "@/components/displays/department/pos/displays/Piktogrammer.vue";
|
||||
import {BSkeleton} from "buefy";
|
||||
// Define props (selected id can be passed if needed)
|
||||
const props = defineProps<{
|
||||
selectedVehicleTypeId?: number;
|
||||
}>();
|
||||
// Define emits
|
||||
const emits = defineEmits<{
|
||||
(e: 'selected', vehicleType: VehicleTypeTemplate): void;
|
||||
}>();
|
||||
|
||||
// Define the vehicle template object
|
||||
type VehicleTypeTemplate = {
|
||||
id: number;
|
||||
name: string;
|
||||
price: number;
|
||||
product?: PosProduct;
|
||||
selected?: boolean; // Optional selected state
|
||||
loading?: boolean; // Optional loading state
|
||||
};
|
||||
|
||||
const getLoadingVehicleTypes = (count: number): VehicleTypeTemplate[] => {
|
||||
const loadingTypes: VehicleTypeTemplate[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
loadingTypes.push({ id: i, name: 'Indlæser...', price: 0, loading: true });
|
||||
}
|
||||
return loadingTypes;
|
||||
};
|
||||
|
||||
const loadingVehicleTypes = ref<VehicleTypeTemplate[]>([
|
||||
...getLoadingVehicleTypes(6)
|
||||
]);
|
||||
|
||||
// Define the reactive objects
|
||||
const vehicleTypes = ref<VehicleTypeTemplate[]>(
|
||||
loadingVehicleTypes.value
|
||||
);
|
||||
// Fetch vehicle types from SessionUser or an API
|
||||
const fetchVehicleTypes = async () => {
|
||||
try {
|
||||
const response = await SessionUser.objects.vehicles.columns.type.options(true, {isWash: true, addDefaultOption: true, restrictToCategory4: null, includeProductRaw: true});
|
||||
vehicleTypes.value = response.map((type: any) => ({
|
||||
id: type.id,
|
||||
name: type.name,
|
||||
price: type.price,
|
||||
product: type.product as PosProduct,
|
||||
selected: props.selectedVehicleTypeId === type.id,
|
||||
}));
|
||||
// Load missing images or other data if necessary
|
||||
console.warn(response);
|
||||
} catch (error) {
|
||||
console.error('Error fetching vehicle types:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Select a vehicle type
|
||||
const select = (vehicleType: VehicleTypeTemplate) => {
|
||||
if (vehicleType.loading) {
|
||||
return; // Prevent selection if still loading
|
||||
}
|
||||
// Update the selected state
|
||||
vehicleTypes.value.forEach((type) => {
|
||||
if (type.loading) {
|
||||
return; // Skip loading types
|
||||
}
|
||||
type.selected = type.id === vehicleType.id;
|
||||
});
|
||||
// Emit the selected vehicle type
|
||||
emits('selected', vehicleType);
|
||||
};
|
||||
|
||||
// Fetch vehicle types on component mount
|
||||
onMounted(() => {
|
||||
fetchVehicleTypes();
|
||||
});
|
||||
|
||||
// Watch for changes in selectedVehicleTypeId prop
|
||||
watch(() => props.selectedVehicleTypeId, (newId) => {
|
||||
vehicleTypes.value.forEach((type) => {
|
||||
if (type.loading) {
|
||||
return; // Skip loading types
|
||||
}
|
||||
type.selected = type.id === newId;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="columns is-multiline is-mobile is-gapless">
|
||||
<!-- Vehicle Type Template -->
|
||||
<template v-for="vehicleType in vehicleTypes" :key="vehicleType.id">
|
||||
<div class="column is-one-third">
|
||||
<div class="vehicle-type-content">
|
||||
<WhiteBoxCard :toggleable="false" :hideHeader="true" :hasHoverEffect="true" :hasSelectedStyle="vehicleType?.selected" :hasSelectionStyle="!vehicleType?.selected" @click="select(vehicleType)">
|
||||
<template v-slot:default>
|
||||
<div class="is-align-content-center">
|
||||
<!-- Image -->
|
||||
<div style="height: 60px; width: 60px; margin: 0 auto;" class="centered-image-container">
|
||||
<img v-if="!vehicleType.loading" :src="getPicture(vehicleType.product.piktogram)" :alt="vehicleType.name" class="image" />
|
||||
<b-skeleton v-else height="60px" width="60px" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</WhiteBoxCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Selection description -->
|
||||
<div class="column is-full mt-3">
|
||||
<div class="vehicle-type-description">
|
||||
<p class="has-text-centered p-2">
|
||||
<template v-if="vehicleTypes.some(type => type.selected)">
|
||||
Du har valgt: <strong>{{ vehicleTypes.find(type => type.selected)?.name }}</strong>
|
||||
<template v-if="vehicleTypes.find(type => type.selected)?.product.description && vehicleTypes.find(type => type.selected)?.product.description.length > 0">
|
||||
<br />{{ vehicleTypes.find(type => type.selected)?.product.description }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
Vælg venligst din køretøjstype ved at klikke på ikonet ovenfor.
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Image styling */
|
||||
.centered-image-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
/* Vehicle type content styling */
|
||||
.vehicle-type-content {
|
||||
padding: 5px;
|
||||
}
|
||||
/* Prevent padding on the left, and right-most columns */
|
||||
.vehicle-type-content:nth-child(3n + 1) {
|
||||
padding-left: 0;
|
||||
}
|
||||
.vehicle-type-content:nth-child(3n) {
|
||||
padding-right: 0;
|
||||
}
|
||||
/* Description styling */
|
||||
.vehicle-type-description {
|
||||
background-color: rgba(0, 0, 0, 0.08);
|
||||
border-radius: 5px;
|
||||
min-height: 64px;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user