"Add phone number edit functionality to UserProfile.vue; implement save dialog with validation and backend integration; filter Safety Seal addon in MyBookingsBook.vue."
This commit is contained in:
@@ -92,7 +92,7 @@ export const getSessionData = async () => {
|
||||
SessionUser.user.customer_number.value = response.data.data.customer_number;
|
||||
SessionUser.user.group_id.value = response.data.data.group_id;
|
||||
SessionUser.user.email.value = response.data.data.email;
|
||||
SessionUser.user.phone.phone.value = response.data.data.phone.phone;
|
||||
SessionUser.user.phone.number.value = response.data.data.phone.number;
|
||||
SessionUser.user.phone.country_code.value = response.data.data.phone.country_code;
|
||||
SessionUser.user.created_at.value = response.data.data.created_at;
|
||||
SessionUser.user.updated_at.value = response.data.data.updated_at;
|
||||
@@ -175,7 +175,7 @@ export const SessionUser = {
|
||||
group_id: ref(null),
|
||||
email: ref(null),
|
||||
phone: {
|
||||
phone: ref(null),
|
||||
number: ref(null),
|
||||
country_code: ref(null),
|
||||
},
|
||||
created_at: ref(null),
|
||||
@@ -344,7 +344,7 @@ export const SessionUser = {
|
||||
SessionUser.user.display_name.value = null;
|
||||
SessionUser.user.group_id.value = null;
|
||||
SessionUser.user.email.value = null;
|
||||
SessionUser.user.phone.phone.value = null;
|
||||
SessionUser.user.phone.number.value = null;
|
||||
SessionUser.user.phone.country_code.value = null;
|
||||
SessionUser.user.created_at.value = null;
|
||||
SessionUser.user.updated_at.value = null;
|
||||
|
||||
@@ -603,6 +603,13 @@ const getExteriorWash = (product: PosProduct) => {
|
||||
return { ...product, addons: [], quantity: 1 };
|
||||
}
|
||||
|
||||
// Detects the Safety Seal addon by name (case-insensitive). Prefer ID if available later.
|
||||
const isSafetySealAddon = (p: any): boolean => {
|
||||
const name = ((p && p.name) ? String(p.name) : '').toLowerCase();
|
||||
// Common variants: Danish "plombe"/"sikkerhedsplombe" and English "safety seal"
|
||||
return name.includes('plombe') || name.includes('safety seal') || name.includes('sikkerhedsplombe');
|
||||
}
|
||||
|
||||
const interiorAddon = computed(() => {
|
||||
if (!selectedProduct.value) return null;
|
||||
return getInteriorWashAddon(selectedProduct.value as PosProduct);
|
||||
@@ -623,9 +630,10 @@ const exteriorPriceLabel = computed(() => {
|
||||
});
|
||||
|
||||
// Filtered list of addons for the UI: hide the interior wash addon (has its own dedicated button)
|
||||
// and hide the Safety Seal addon (redundant now)
|
||||
const visibleAddons = computed(() => {
|
||||
const addons = (selectedProduct.value?.addons || []) as any[];
|
||||
return addons.filter(a => !a?.product?.name?.includes('Indvendig'));
|
||||
return addons.filter(a => !a?.product?.name?.includes('Indvendig') && !isSafetySealAddon(a?.product));
|
||||
});
|
||||
|
||||
const completeBasket = computed({
|
||||
@@ -638,7 +646,7 @@ const completeBasket = computed({
|
||||
// Selected addons with quantity > 0 (excluding interior wash which is controlled by its own toggle)
|
||||
const selectedAddons = (product.addons || [])
|
||||
.map((a: any) => a?.product)
|
||||
.filter((p: any) => p && (p.quantity || 0) > 0 && !(p?.name || '').includes('Indvendig')) as PosProduct[];
|
||||
.filter((p: any) => p && (p.quantity || 0) > 0 && !(p?.name || '').includes('Indvendig') && !isSafetySealAddon(p)) as PosProduct[];
|
||||
|
||||
// Exterior/base product (default selected)
|
||||
if (washExterior.value && exteriorWash) {
|
||||
|
||||
@@ -290,6 +290,73 @@ const onClickChangePassword = async () => {
|
||||
});
|
||||
}
|
||||
|
||||
const onClickSavePhoneNumber = async () => {
|
||||
// Show the phone number and country code input dialog
|
||||
await Swal.fire({
|
||||
title: 'Indtast telefonnummer',
|
||||
html:
|
||||
'<input id="swal-input1" class="swal2-input" type="number" placeholder="Telefonnummer">' +
|
||||
'<input id="swal-input2" class="swal2-input" type="number" placeholder="Landekode (f.eks. 45 for Danmark)">',
|
||||
focusConfirm: false,
|
||||
showCancelButton: true,
|
||||
preConfirm: () => {
|
||||
const phoneNumber = Swal.getPopup().querySelector('#swal-input1').value;
|
||||
const countryCode = Swal.getPopup().querySelector('#swal-input2').value;
|
||||
// Simple validation
|
||||
if (!phoneNumber) {
|
||||
Swal.showValidationMessage('Indtast venligst et telefonnummer');
|
||||
return;
|
||||
}
|
||||
if (!countryCode) {
|
||||
Swal.showValidationMessage('Indtast venligst en landekode');
|
||||
return;
|
||||
}
|
||||
isLoading.value = true;
|
||||
Swal.showLoading();
|
||||
return { phoneNumber, countryCode };
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading(),
|
||||
showLoaderOnConfirm: true,
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const { phoneNumber, countryCode } = result.value;
|
||||
// Send the change phone number request
|
||||
SessionUser.request(
|
||||
'/account/security/change-phone-number',
|
||||
'POST',
|
||||
{
|
||||
phone_number: parseInt(phoneNumber),
|
||||
country_code: parseInt(countryCode),
|
||||
}
|
||||
).then((response) => {
|
||||
if (response.status === 200) {
|
||||
Swal.fire({
|
||||
title: 'Telefonnummer gemt',
|
||||
text: 'Dit telefonnummer er blevet gemt.',
|
||||
icon: 'success',
|
||||
});
|
||||
SessionUser.getSessionData();
|
||||
} else {
|
||||
// Show validation errors
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: 'Der opstod en fejl under gemme af telefonnummeret.',
|
||||
icon: 'error',
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: SessionUser.functions.parseErrorMessage(error),
|
||||
icon: 'error',
|
||||
});
|
||||
}).finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@@ -331,7 +398,7 @@ const onClickChangePassword = async () => {
|
||||
<!-- E-mail -->
|
||||
<ConfigurationInput
|
||||
:title="SessionUser.objects.global.language.email"
|
||||
description="Vi bruger denne e-mail til at nulstille din adgangskode"
|
||||
description="Vi bruger denne e-mail til at nulstille din adgangskode, fremsende vaskecertifikater og andre vigtige oplysninger."
|
||||
v-bind:value="SessionUser.user.email"
|
||||
:disabled="true"
|
||||
/>
|
||||
@@ -349,20 +416,33 @@ const onClickChangePassword = async () => {
|
||||
<ConfigurationInput
|
||||
:title="SessionUser.objects.global.language.phone_number"
|
||||
description="Telefonnummer"
|
||||
v-bind:value="SessionUser.user.phone.phone"
|
||||
v-bind:value="SessionUser.user.phone.number"
|
||||
:disabled="true"
|
||||
/>
|
||||
<!-- Change password -->
|
||||
<button
|
||||
class="button is-link is-small mt-2"
|
||||
@click="onClickChangePassword"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<div class="buttons">
|
||||
<!-- Change phone number and country code -->
|
||||
<button
|
||||
class="button is-link is-small mt-2"
|
||||
@click="onClickSavePhoneNumber"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<span>
|
||||
<i class="fas fa-edit"></i>
|
||||
<span class="ml-2">Rediger telefonnummer</span>
|
||||
</span>
|
||||
</button>
|
||||
<!-- Change password -->
|
||||
<button
|
||||
class="button is-link is-small mt-2"
|
||||
@click="onClickChangePassword"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<span>
|
||||
<i class="fas fa-key"></i>
|
||||
<span class="ml-2">Skift adgangskode</span>
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</ConfigurationCategory>
|
||||
<!-- Microsoft -->
|
||||
<ConfigurationCategory
|
||||
|
||||
Reference in New Issue
Block a user