Enhance subuser profile management with editable name and email fields
- Added support for subusers to update their name and email via modals in `UserProfile.vue`. - Updated `SubuserGrantSelector` styles with improved layout and accessibility for compact mode. - Refined `SessionUser` logic to conditionally render visible profile attributes and actions based on subuser status. - Adjusted navigation permissions to remove redundant `user_invoices` permission check.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import {defineProps, onMounted, ref} from 'vue';
|
||||
import {defineProps, onMounted, ref, watch} from 'vue';
|
||||
import {parseError, getError} from "@/components/request/HandleGlobalError.vue";
|
||||
|
||||
const props = defineProps({
|
||||
@@ -27,6 +27,11 @@ const isEditting = ref(false);
|
||||
|
||||
const v_model = ref(props.value);
|
||||
|
||||
// Watch for changes in the value prop and update v_model
|
||||
watch(() => props.value, (newValue) => {
|
||||
v_model.value = newValue;
|
||||
});
|
||||
|
||||
const errorId = ref(null);
|
||||
|
||||
const parseErrorOnSave = (error) => {
|
||||
|
||||
@@ -52,7 +52,7 @@ const menu_items = ref([
|
||||
icon: 'fas fa-file-invoice',
|
||||
children: [],
|
||||
permissions: [
|
||||
'user_invoices'
|
||||
'user'
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -72,7 +72,7 @@ const items = computed<NavigationItemProps[]>(() => [
|
||||
label: SessionUser.functions.ucFirst(SessionUser.objects.collectedOrderInvoices.meta.labels.multiple),
|
||||
to: `/user/invoices`,
|
||||
type: 'link',
|
||||
permissions: ['user', 'user_invoices'],
|
||||
permissions: ['user'],
|
||||
},
|
||||
{
|
||||
label: 'Chauffører',
|
||||
|
||||
@@ -59,7 +59,10 @@ const selectedGrantName = computed(() => {
|
||||
:class="{ 'is-active': grant.billing_customer_number === selectedCustomerNumber }"
|
||||
@click="selectGrant(grant.billing_customer_number)"
|
||||
>
|
||||
{{ grant.name || 'Kunde #' + grant.billing_customer_number }}
|
||||
<span class="dropdown-item-check">
|
||||
<i class="fas fa-check" v-if="grant.billing_customer_number === selectedCustomerNumber"></i>
|
||||
</span>
|
||||
<span class="dropdown-item-text">{{ grant.name || 'Kunde #' + grant.billing_customer_number }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,16 +113,62 @@ const selectedGrantName = computed(() => {
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-menu {
|
||||
min-width: 200px;
|
||||
min-width: 250px;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-content {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item {
|
||||
cursor: pointer;
|
||||
padding: 0.625rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
transition: background-color 0.15s ease, color 0.15s ease;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item.is-active {
|
||||
background-color: #3273dc;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item.is-active:hover {
|
||||
background-color: #2366d1;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item-check {
|
||||
width: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
color: #3273dc;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item.is-active .dropdown-item-check {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.grant-selector.is-compact .dropdown-item-text {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.label {
|
||||
|
||||
@@ -359,6 +359,125 @@ const onClickSavePhoneNumber = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
/** Subuser name change */
|
||||
const onClickSaveSubuserName = async () => {
|
||||
await Swal.fire({
|
||||
title: 'Indtast dit navn',
|
||||
input: 'text',
|
||||
inputLabel: 'Navn',
|
||||
inputPlaceholder: 'Dit navn',
|
||||
inputValue: SessionUser.subuser.name.value || '',
|
||||
showCancelButton: true,
|
||||
preConfirm: (value) => {
|
||||
if (!value) {
|
||||
Swal.showValidationMessage('Indtast venligst dit navn');
|
||||
return;
|
||||
}
|
||||
if (value.length < 2) {
|
||||
Swal.showValidationMessage('Navnet skal være mindst 2 tegn langt');
|
||||
return;
|
||||
}
|
||||
isLoading.value = true;
|
||||
Swal.showLoading();
|
||||
return value;
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading(),
|
||||
showLoaderOnConfirm: true,
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const name = result.value;
|
||||
SessionUser.request(
|
||||
'/subusers/me',
|
||||
'PUT',
|
||||
{ name: name }
|
||||
).then((response) => {
|
||||
if (response.status === 200) {
|
||||
Swal.fire({
|
||||
title: 'Navn gemt',
|
||||
text: 'Dit navn er blevet opdateret.',
|
||||
icon: 'success',
|
||||
});
|
||||
SessionUser.subuser.name.value = name;
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: 'Der opstod en fejl under gemme af navnet.',
|
||||
icon: 'error',
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: SessionUser.functions.parseErrorMessage(error),
|
||||
icon: 'error',
|
||||
});
|
||||
}).finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Subuser email change */
|
||||
const onClickSaveSubuserEmail = async () => {
|
||||
await Swal.fire({
|
||||
title: 'Indtast din e-mailadresse',
|
||||
input: 'text',
|
||||
inputLabel: 'E-mail',
|
||||
inputPlaceholder: 'Din e-mailadresse',
|
||||
inputValue: SessionUser.subuser.email.value || '',
|
||||
showCancelButton: true,
|
||||
preConfirm: (value) => {
|
||||
if (!value) {
|
||||
Swal.showValidationMessage('Indtast venligst din e-mailadresse');
|
||||
return;
|
||||
}
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(value)) {
|
||||
Swal.showValidationMessage('Indtast venligst en gyldig e-mailadresse');
|
||||
return;
|
||||
}
|
||||
isLoading.value = true;
|
||||
Swal.showLoading();
|
||||
return value;
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading(),
|
||||
showLoaderOnConfirm: true,
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const email = result.value;
|
||||
SessionUser.request(
|
||||
'/subusers/me',
|
||||
'PUT',
|
||||
{ email: email }
|
||||
).then((response) => {
|
||||
if (response.status === 200) {
|
||||
Swal.fire({
|
||||
title: 'E-mail gemt',
|
||||
text: 'Din e-mailadresse er blevet opdateret.',
|
||||
icon: 'success',
|
||||
});
|
||||
SessionUser.subuser.email.value = email;
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: 'Der opstod en fejl under gemme af e-mailadressen.',
|
||||
icon: 'error',
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
Swal.fire({
|
||||
title: 'Fejl',
|
||||
text: SessionUser.functions.parseErrorMessage(error),
|
||||
icon: 'error',
|
||||
});
|
||||
}).finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const onClickSaveWashCertificateEmail = async () => {
|
||||
// Show the wash certificate email input dialog
|
||||
await Swal.fire({
|
||||
@@ -416,6 +535,7 @@ const onClickSaveWashCertificateEmail = async () => {
|
||||
<UserDashboardPageWrapper title="Brugerprofil">
|
||||
<!-- Invoicing -->
|
||||
<ConfigurationCategory
|
||||
v-if="!SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Fakturaoplysninger"
|
||||
@@ -439,6 +559,7 @@ const onClickSaveWashCertificateEmail = async () => {
|
||||
</ConfigurationCategory>
|
||||
<!-- Security -->
|
||||
<ConfigurationCategory
|
||||
v-if="!SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Sikkerhed"
|
||||
@@ -505,13 +626,92 @@ const onClickSaveWashCertificateEmail = async () => {
|
||||
</button>
|
||||
</div>
|
||||
</ConfigurationCategory>
|
||||
<!-- Subuser - Profile Information -->
|
||||
<ConfigurationCategory
|
||||
v-if="SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Underbruger"
|
||||
subtitle="Profiloplysninger"
|
||||
description="Dine underbruger-oplysninger"
|
||||
icon="fas fa-user"
|
||||
>
|
||||
<!-- Username (read-only) -->
|
||||
<ConfigurationInput
|
||||
title="Brugernavn"
|
||||
description="Dit brugernavn kan ikke ændres."
|
||||
:value="SessionUser.subuser.username.value"
|
||||
:disabled="true"
|
||||
/>
|
||||
<!-- Name (editable) -->
|
||||
<ConfigurationInput
|
||||
title="Navn"
|
||||
description="Dit visningsnavn som underbruger."
|
||||
:value="SessionUser.subuser.name.value"
|
||||
:disabled="true"
|
||||
/>
|
||||
<button
|
||||
class="button is-link is-small mt-2"
|
||||
@click="onClickSaveSubuserName"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<span>
|
||||
<i class="fas fa-edit"></i>
|
||||
<span class="ml-2">Rediger navn</span>
|
||||
</span>
|
||||
</button>
|
||||
</ConfigurationCategory>
|
||||
<!-- Subuser - Contact Information -->
|
||||
<ConfigurationCategory
|
||||
v-if="SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Underbruger"
|
||||
subtitle="Kontaktoplysninger"
|
||||
description="Dine kontaktoplysninger som underbruger"
|
||||
icon="fas fa-address-card"
|
||||
>
|
||||
<!-- Email (editable) -->
|
||||
<ConfigurationInput
|
||||
title="E-mail"
|
||||
description="Din e-mailadresse som underbruger."
|
||||
:value="SessionUser.subuser.email.value"
|
||||
:disabled="true"
|
||||
/>
|
||||
<button
|
||||
class="button is-link is-small mt-2"
|
||||
@click="onClickSaveSubuserEmail"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<span>
|
||||
<i class="fas fa-edit"></i>
|
||||
<span class="ml-2">Rediger e-mail</span>
|
||||
</span>
|
||||
</button>
|
||||
<hr class="my-4"/>
|
||||
<!-- Phone number (read-only) -->
|
||||
<ConfigurationInput
|
||||
title="Telefonnummer"
|
||||
description="Dit telefonnummer som underbruger."
|
||||
:value="SessionUser.subuser.phone.number.value"
|
||||
:disabled="true"
|
||||
/>
|
||||
<!-- Country code (read-only) -->
|
||||
<ConfigurationInput
|
||||
title="Landekode"
|
||||
description="Din landekode for telefonnummeret."
|
||||
:value="SessionUser.subuser.phone.country_code.value"
|
||||
:disabled="true"
|
||||
/>
|
||||
</ConfigurationCategory>
|
||||
<!-- Subuser - Grant selection -->
|
||||
<ConfigurationCategory
|
||||
v-if="SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Underbruger"
|
||||
description="Du er logget ind som underbruger. Vælg hvilken kunde du vil handle på vegne af."
|
||||
subtitle="Kundevalg"
|
||||
description="Vælg hvilken kunde du vil handle på vegne af."
|
||||
icon="fas fa-users"
|
||||
>
|
||||
<SubuserGrantSelector :show-label="false" />
|
||||
@@ -521,6 +721,7 @@ const onClickSaveWashCertificateEmail = async () => {
|
||||
</ConfigurationCategory>
|
||||
<!-- Notifications - email notifications -->
|
||||
<ConfigurationCategory
|
||||
v-if="!SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Notifikationer"
|
||||
@@ -557,6 +758,7 @@ const onClickSaveWashCertificateEmail = async () => {
|
||||
</ConfigurationCategory>
|
||||
<!-- Notifications - SMS notifications -->
|
||||
<ConfigurationCategory
|
||||
v-if="!SessionUser.isSubuser.value"
|
||||
class="mt-2"
|
||||
:module="SessionUser.functions.device.isMobile() ? `` : `Brugerprofil`"
|
||||
title="Notifikationer"
|
||||
|
||||
Reference in New Issue
Block a user