diff --git a/zmscitizenview/src/components/Appointment/AppointmentSummary.vue b/zmscitizenview/src/components/Appointment/AppointmentSummary.vue index 8ebfe5ad1..b014b910e 100644 --- a/zmscitizenview/src/components/Appointment/AppointmentSummary.vue +++ b/zmscitizenview/src/components/Appointment/AppointmentSummary.vue @@ -278,6 +278,7 @@ const formatTime = (time: any) => { }; const clickPrivacyPolicy = () => (privacyPolicy.value = !privacyPolicy.value); + const clickElectronicCommunication = () => (electronicCommunication.value = !electronicCommunication.value); @@ -291,6 +292,10 @@ const cancelAppointment = () => emit("cancelAppointment"); const cancelReschedule = () => emit("cancelReschedule"); const rescheduleAppointment = () => emit("rescheduleAppointment"); +/** + * This function determines the expected duration of the appointment. + * The provider is queried for the service and each subservice because the slots for the respective service are stored in this provider. + */ const estimatedDuration = () => { let time = 0; const serviceProvider = selectedService.value?.providers?.find( @@ -298,8 +303,9 @@ const estimatedDuration = () => { ); if ( serviceProvider && - selectedService.value?.count && - serviceProvider?.slots + serviceProvider.slots && + selectedService.value && + selectedService.value.count ) { time = selectedService.value.count * @@ -308,7 +314,7 @@ const estimatedDuration = () => { } if (selectedService.value?.subServices) { - selectedService.value?.subServices?.forEach((subservice) => { + selectedService.value.subServices.forEach((subservice) => { const subserviceProvider = subservice.providers?.find( (provider) => provider.id == selectedProvider.value?.id ); diff --git a/zmscitizenview/src/components/Appointment/AppointmentView.vue b/zmscitizenview/src/components/Appointment/AppointmentView.vue index 523a6e100..f6ff8dc78 100644 --- a/zmscitizenview/src/components/Appointment/AppointmentView.vue +++ b/zmscitizenview/src/components/Appointment/AppointmentView.vue @@ -301,12 +301,18 @@ const increaseCurrentView = () => currentView.value++; const decreaseCurrentView = () => currentView.value--; +/** + * Adjusts the current view to the active step in the stepper + */ const changeStep = (step: string) => { if (parseInt(step) < parseInt(activeStep.value)) { currentView.value = parseInt(step); } }; +/** + * Creation of a map that prepares the services and their counts for the backend call. + */ const setServices = () => { selectedServiceMap.value = new Map(); if (selectedService.value) { @@ -461,6 +467,9 @@ const nextCancelReschedule = () => { rebookOrCanelDialog.value = true; }; +/** + * Adjusts the active step in the stepper to the current view + */ watch(currentView, (newCurrentView) => { activeStep.value = newCurrentView.toString(); }); diff --git a/zmscitizenview/src/components/Appointment/CalendarView.vue b/zmscitizenview/src/components/Appointment/CalendarView.vue index 6a53ae1d4..a76198557 100644 --- a/zmscitizenview/src/components/Appointment/CalendarView.vue +++ b/zmscitizenview/src/components/Appointment/CalendarView.vue @@ -108,7 +108,7 @@ />
@@ -118,7 +118,7 @@ {{ formatDay(selectedDay) }}
@@ -238,7 +238,7 @@ import { MucSlider, MucSliderItem, } from "@muenchen/muc-patternlab-vue"; -import { inject, onMounted, ref, watch } from "vue"; +import { computed, inject, onMounted, ref, watch } from "vue"; import { AvailableDaysDTO } from "@/api/models/AvailableDaysDTO"; import { AvailableTimeSlotsDTO } from "@/api/models/AvailableTimeSlotsDTO"; @@ -273,13 +273,17 @@ const { selectedProvider, selectedTimeslot } = inject( const selectableProviders = ref(); const availableDays = ref(); -const appointmentTimestamps = ref(); +const appointmentTimestamps = ref([]); const selectedDay = ref(); const error = ref(false); const minDate = ref(); const maxDate = ref(); +/** + * Reference to the appointment summary. + * After selecting a time slot, the focus is placed on the appointment summary. + */ const summary = ref(null); const TODAY = new Date(); @@ -323,9 +327,9 @@ const formatTime = (time: any) => { return formatterTime.format(date); }; -const timeSlotsInHours = () => { +const timeSlotsInHours = computed(() => { const timesByHours = new Map(); - appointmentTimestamps.value?.forEach((time) => { + appointmentTimestamps.value.forEach((time) => { const berlinDate = new Date(time * 1000); const hour = parseInt(berlinHourFormatter.format(berlinDate)); if (!timesByHours.has(hour)) { @@ -334,7 +338,7 @@ const timeSlotsInHours = () => { timesByHours.get(hour)?.push(time); }); return timesByHours; -}; +}); const showSelectionForProvider = (provider: OfficeImpl) => { selectedProvider.value = provider; @@ -363,6 +367,7 @@ const showSelectionForProvider = (provider: OfficeImpl) => { }; const getAppointmentsOfDay = (date: string) => { + appointmentTimestamps.value = []; fetchAvailableTimeSlots( date, selectedProvider.value, @@ -374,7 +379,6 @@ const getAppointmentsOfDay = (date: string) => { appointmentTimestamps.value = ( data as AvailableTimeSlotsDTO ).appointmentTimestamps; - timeSlotsInHours(); } else { error.value = true; } @@ -417,6 +421,10 @@ const handleTimeSlotSelection = (timeSlot: number) => { if (summary.value) summary.value.focus(); }; +/** + * This function determines the expected duration of the appointment. + * The provider is queried for the service and each subservice because the slots for the respective service are stored in this provider. + */ const estimatedDuration = () => { let time = 0; const serviceProvider = selectedService.value?.providers?.find( @@ -424,8 +432,9 @@ const estimatedDuration = () => { ); if ( serviceProvider && - selectedService.value?.count && - serviceProvider?.slots + serviceProvider.slots && + selectedService.value && + selectedService.value.count ) { time = selectedService.value.count * @@ -434,7 +443,7 @@ const estimatedDuration = () => { } if (selectedService.value?.subServices) { - selectedService.value?.subServices?.forEach((subservice) => { + selectedService.value.subServices.forEach((subservice) => { const subserviceProvider = subservice.providers?.find( (provider) => provider.id == selectedProvider.value?.id ); @@ -454,6 +463,7 @@ const previousStep = () => emit("back"); onMounted(() => { if (selectedService.value && selectedService.value.providers) { + // Checks whether a provider is already selected so that it is displayed first in the slider. let offices = selectedService.value.providers.filter((office) => { if (props.preselectedOfficeId) { return office.id == props.preselectedOfficeId; @@ -462,6 +472,7 @@ onMounted(() => { } }); + // Checks whether there are restrictions on the providers due to the subservices. if (selectedService.value.subServices) { const choosenSubservices = selectedService.value.subServices.filter( (subservice) => subservice.count > 0 @@ -479,6 +490,7 @@ onMounted(() => { selectableProviders.value = selectedService.value.providers; } + // If alternative locations are allowed to be selected, they will be added to the slider. if ( !props.exclusiveLocation && ((offices.length > 0 && offices[0].showAlternativeLocations) || diff --git a/zmscitizenview/src/components/Appointment/CustomerInfo.vue b/zmscitizenview/src/components/Appointment/CustomerInfo.vue index 2d84771d8..1de121d7b 100644 --- a/zmscitizenview/src/components/Appointment/CustomerInfo.vue +++ b/zmscitizenview/src/components/Appointment/CustomerInfo.vue @@ -3,7 +3,7 @@ class="m-component-form__title" tabindex="0" > - Kontaktdaten + {{ t("contactDetails") }}
(selectedService.value); const maxSlotsPerAppointment = ref(25); const currentSlots = ref(0); + +/** + * Count of the selected service + */ const countOfService = ref(1); +/** + * Reference to the duration info. + * If a screen reader user wants to skip the subservices, the focus is placed on the duration info. + */ const durationInfo = ref(null); watch(service, (newService) => { @@ -152,6 +160,9 @@ watch(service, (newService) => { updateSelectedService(newService); }); +/** + * Calculation of the currently required slots by changing the count of the selected service. + */ watch(countOfService, (newCountOfService) => { if (service.value.count < newCountOfService) { currentSlots.value += getMinSlotOfProvider(service.value.providers); @@ -228,6 +239,9 @@ const getProviders = (serviceId: string, providers: string[] | null) => { return officesAtService; }; +/** + * Calculation of the currently required slots by changing the count of a subservice. + */ const changeAppointmentCountOfSubservice = (id: string, count: number) => { const subservice = service.value.subServices?.find( (subService) => subService.id == id @@ -249,6 +263,9 @@ const estimatedDuration = computed(() => { : 0; }); +/** + * Calculates whether the count of selected service may be increased, depending on the maxQuantity of the service and the maxSlotsPerAppointment. + */ const maxValueOfService = computed(() => { return checkPlusEndabled.value ? service.value.maxQuantity @@ -295,6 +312,7 @@ const skipSubservices = () => { }; onMounted(() => { + //If a selected service already exists, the variables required for the calculation are calculated and initialized with the existing values. if (service.value) { let slots = 0; countOfService.value = service.value.count diff --git a/zmscitizenview/src/utils/de-DE.json b/zmscitizenview/src/utils/de-DE.json index 3991dfa8a..54a16c35d 100644 --- a/zmscitizenview/src/utils/de-DE.json +++ b/zmscitizenview/src/utils/de-DE.json @@ -28,6 +28,7 @@ "errorMessageTelephoneNumberRequired": "Bitte geben Sie Ihre Telefonnummer an.", "errorMessageTelephoneNumberValidation": "Ihre Telefonnummer entspricht nicht dem vorgegebenen Format. Bitte geben Sie nur ein +-Zeichen, Zahlen und Leerzeichen ein.", "contact": "Kontakt", + "contactDetails": "Kontaktdaten", "estimatedDuration": "Voraussichtliche Termindauer:", "firstName": "Vorname", "hint": "Hinweis", diff --git a/zmscitizenview/src/utils/en-US.json b/zmscitizenview/src/utils/en-US.json index 6b2c54f30..ed8b84411 100644 --- a/zmscitizenview/src/utils/en-US.json +++ b/zmscitizenview/src/utils/en-US.json @@ -17,6 +17,7 @@ "clock": "Clock", "combinableServices": "Combinable services", "contact": "Contact us", + "contactDetails": "Contact details", "communicationCheckboxLabel": "Electronic communication", "communicationCheckboxText": "I have taken note of the information on electronic communication and agree to be notified of my appointment by e-mail.", "confirmAppointmentHeader": "Confirm your appointment.",