Add XLVask integration for user management and vehicles

Introduces XLVask functionality, including user account linking, fetching vehicles, and conditional UI updates for user accounts. Adds new routes, components, and localization strings to support the integration.
This commit is contained in:
Jepp9350
2025-05-12 09:36:25 +02:00
parent 2b27e95d95
commit f6e5cfd784
9 changed files with 215 additions and 4 deletions
@@ -28,7 +28,11 @@ const props = defineProps({
invoice_collection_id: {
type: Number,
default: null
}
},
reg_1: {
type: String,
default: null
},
});
const customerModalVisible = ref(false);
@@ -185,6 +189,20 @@ const redirectDepartmentOrderPage = async (orderId) => {
:click-action="() => redirectSuperUserInvoiceCollectionPage(props.invoice_collection_id)"
/>
</template>
<!-- If there is a reg_1, show the reg_1 actions -->
<template v-if="props.reg_1">
<!-- Label -->
<action-settings-wheel-item-label
:label="SessionUser.objects.vehicles.meta.labels.single"
/>
<!-- Show the vehicle, in a new tab -->
<action-settings-wheel-item
label="Vis køretøj i ny fane"
icon="fas fa-car"
v-if="SessionUser.canAccessSuperUser()"
:click-action="() => SessionUser.functions.redirectTo.superUser('/vehicles/' + props.reg_1, true)"
/>
</template>
</template>
<!-- If no actions are defined, then show that no actions are defined -->
<template v-else>
@@ -1,5 +1,6 @@
<script setup>
import { defineProps } from 'vue';
import { SessionUser } from "@/components/session/token/SessionUser.vue";
const props = defineProps({
icon: {
@@ -117,7 +118,7 @@ const hasIcon = () => {
</span>
<span class="ml-1"
:class="getLabelColor()"
>{{ getLabel() }}</span>
>{{ SessionUser.functions.ucFirst(getLabel()) }}</span>
</a>
</template>
@@ -234,6 +234,7 @@ const isVehicleAddonApplied = (addon) => {
<ActionSettingsWheelButton
v-if="!props.compact"
:user_id="object.user_id"
:reg_1="object.reg"
>
<template #actions>
<!-- Delete -->
@@ -25,6 +25,7 @@ export const ObjectsGlobal = {
succeeded: "Fuldførte",
customers: "Kunder",
selected: "Valgt",
found: "Fundet",
waiting: "Afventer",
selected_multiple: "Valgte",
queue: "Kø",
@@ -125,6 +126,7 @@ export const ObjectsGlobal = {
payment_intent: 'Betalingsintention',
receipt: 'Kvittering',
receipt_url: 'Kvitterings URL',
discount: 'Rabat',
},
invoice: 'Faktura',
},
+14
View File
@@ -88,6 +88,8 @@ import UserProfile from "@/views/dashboards/userDashboard/profile/UserProfile.vu
import DepartmentNotifications
from "@/views/dashboards/departmentDashboard/modules/notifications/DepartmentNotifications.vue";
import Vehicles from "@/views/dashboards/superUserDashboard/Vehicles.vue";
import ConfigurationXLVask from "@/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue";
import UserXLVask from "@/views/dashboards/superUserDashboard/user/UserXLVask.vue";
// Export the router as router
export const router = createRouter({
@@ -304,6 +306,12 @@ export const router = createRouter({
component: UserWashSubscriptions,
meta: { middleware: superUserMiddleware }
},
{
name: 'userxlvask',
path: '/superuser/users/:userId/xlvask',
component: UserXLVask,
meta: { middleware: superUserMiddleware }
},
{
name: 'products',
path: '/superuser/products',
@@ -418,6 +426,12 @@ export const router = createRouter({
component: ConfigurationGatewayAPI,
meta: { middleware: superUserMiddleware }
},
{
name: 'configurationXLVask',
path: '/superuser/configuration/xlvask',
component: ConfigurationXLVask,
meta: { middleware: superUserMiddleware }
},
{
name: 'customers',
path: '/superuser/customers',
@@ -14,6 +14,7 @@ const tabs = [
{ name: 'Pricing', path: '/superuser/users/' + userId.value + '/pricing' },
{ name: 'Other', path: '/superuser/users/' + userId.value + '/other' },
{ name: 'Vehicles', path: '/superuser/users/' + userId.value + '/vehicles' },
{ name: SessionUser.superUser.modules.xlvask.meta.title, path: '/superuser/users/' + userId.value + '/xlvask' },
];
// Get the current path
@@ -1,6 +1,6 @@
<script>
import {ref} from "vue";
import {ref, watch} from "vue";
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
// Get the user from the route
export const userId = ref(0);
@@ -11,6 +11,14 @@ export const setUser = (id) => {
getUserData();
}
export const onUserChange = (callback) => {
watch(userId, (newValue) => {
if (newValue) {
callback(newValue);
}
});
}
@@ -2,7 +2,10 @@
import SuperUserDashboardUserNavigation from "@/views/dashboards/superUserDashboard/user/SuperUserDashboardUserNavigation.vue";
import SuperUserDashboardNavigation from "@/views/dashboards/superUserDashboard/SuperUserDashboardNavigation.vue";
import {user, getUserData, userId, setUser, getUserCustomerNumber} from "@/views/dashboards/superUserDashboard/user/SuperUserSelectedUserObject.vue";
import {useRouter} from "vue-router";
const router = useRouter()
setUser(router.currentRoute.value.params.userId);
</script>
@@ -0,0 +1,163 @@
<script setup>
import UserSubPageWrapper from "@/views/dashboards/superUserDashboard/user/UserSubPageWrapper.vue";
import PageTitle from "@/components/global/PageTitle.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import {user, getUserData, userId, setUser, getUserCustomerNumber, onUserChange} from "@/views/dashboards/superUserDashboard/user/SuperUserSelectedUserObject.vue";
import {ref, watch} from "vue";
/** XLVask User vehicles */
const xlvaskUserVehicles = ref([]);
const getXlvaskUserVehicles = async () => {
// Get the vehicles from XLVask
await SessionUser.superUser.modules.xlvask.functions.getVehicles(
xlvaskUserObject.value.customerId,
).then((response) => {
let matchingVehicles = response.data.data;
if (matchingVehicles.length !== 0) {
xlvaskUserVehicles.value = matchingVehicles;
}
}
).catch((error => {}));
}
/** XLVask User */
const xlvaskDefaultUserFunctions = {
hasXLVaskAccount: () => {
return xlvaskUserObject.value.customerId !== null
},
getThis: () => {
return xlvaskUserObject
},
}
const xlvaskDefaultUserObject = {
customerId: null,
name: null,
vendorId: null,
customerTypeId: null,
discount: null, // Int
phone: null,
email: null,
address: null,
address2: null,
zip: null,
city: null,
userId: null,
vatnumber: null,
excludeFromAutoInvoice: null,
country: null,
createDate: null,
externId: null,
active: null,
language: null,
note: null,
updated: null,
...xlvaskDefaultUserFunctions,
}
const generateXlVaskUserObject = async () => {
let tmp_xlvaskUserObject = {
...xlvaskDefaultUserObject
}
// If the customer number is set, then we can contact XLVask
if (user.customer_number.value) {
//console.log("XLVask customer number set", user.customer_number.value);
// Get all the matching customers from XLVask
await SessionUser.superUser.modules.xlvask.functions.getCustomers(
null,
null,
user.customer_number.value,
).then((response) => {
//console.log("XLVask response", response.data.data);
let matchingCustomers = response.data.data;
if (matchingCustomers.length === 0) {
//console.log("XLVask customer not found");
} else {
//console.log("XLVask customer found", matchingCustomers);
// Get the first customer
let customer = matchingCustomers[0];
//console.log("XLVask customer", customer);
// Set the customer data
tmp_xlvaskUserObject = {
...tmp_xlvaskUserObject,
...customer,
externId: parseInt(customer.externId),
}
}
}
).catch((error => {
//console.error("XLVask error", error);
})).finally(() => {
//console.log("XLVask finally");
xlvaskUserObject.value = tmp_xlvaskUserObject;
});
} else {
//console.log("XLVask customer number not set");
}
}
const xlvaskUserObject = ref(xlvaskDefaultUserObject);
const initXlvaskUserObject = async (userId = null) => {
// Reset the xlvask user object
xlvaskUserObject.value = {...xlvaskDefaultUserObject};
if (userId) {
await generateXlVaskUserObject();
}
}
onUserChange(newUserId => {
// Get the user data
initXlvaskUserObject(newUserId);
})
initXlvaskUserObject(user.id);
watch(user.customer_number, (newValue) => {
initXlvaskUserObject(user.id);
});
watch(xlvaskUserObject, (newValue) => {
// Check if the user has an XLVask account
if (xlvaskUserObject.value.hasXLVaskAccount()) {
// Get the vehicles from XLVask
getXlvaskUserVehicles();
} else {
// If the user does not have an XLVask account, reset the vehicles
xlvaskUserVehicles.value = [];
}
}, { immediate: true });
</script>
<template>
<UserSubPageWrapper>
<template #title>
<PageTitle title="User" :subtitle="SessionUser.superUser.modules.xlvask.meta.title"/>
</template>
<div v-if="xlvaskUserObject">
{{ userId }} (Customer number: {{ user.customer_number }})
<template v-if="xlvaskUserObject.hasXLVaskAccount()">
<!-- The user has an XLVask account -->
<div class="message is-success">
<div class="message-body">
<strong>{{ SessionUser.superUser.modules.xlvask.meta.title }} {{ SessionUser.objects.global.language.customer.toLowerCase() }} {{ SessionUser.objects.global.language.found.toLowerCase()}}</strong>
<p>Navn: {{ xlvaskUserObject.name }}</p>
<p>Telefon: {{ xlvaskUserObject.phone }}</p>
<p>Email: {{ xlvaskUserObject.email }}</p>
<p>Adresse: {{ xlvaskUserObject.address }} {{ xlvaskUserObject.address2 }}</p>
<p>Postnummer: {{ xlvaskUserObject.zip }}</p>
<p>By: {{ xlvaskUserObject.city }}</p>
<p>Land: {{ xlvaskUserObject.country }}</p>
<!-- If the customer has a discount, show it -->
<p v-if="xlvaskUserObject.discount !== null">{{ SessionUser.objects.global.language.payment.discount }}: <strong>{{ xlvaskUserObject.discount }}%</strong></p>
<p>XLVask ID: <strong>{{ xlvaskUserObject.customerId }}</strong></p>
</div>
</div>
<!-- Vehicles connected to the user -->
<!--{{ xlvaskUserVehicles }} -->
</template>
<template v-else>
<!-- The user does not have an XLVask account -->
XLVask ID: <strong>Ingen</strong>
</template>
</div>
</UserSubPageWrapper>
</template>
<style scoped>
</style>