"Add 'Add Customer' functionality: integrate new popup component and action flow for customer creation in PosDepartmentStepMobile. Update popup handling logic, adjust button actions, and introduce dynamic form autofill for seamless user experience."
This commit is contained in:
@@ -31,7 +31,10 @@ import PosDepartmentStepMobileAttachments
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobileAttachments.vue";
|
||||
import PosDepartmentStep1MobileTransactionHistory
|
||||
from "@/components/displays/department/pos/steps/mobile/views/PosDepartmentStep1MobileTransactionHistory.vue";
|
||||
import {attachments} from "@/components/displays/department/pos/steps/mobile/objects/PosDepartmentStepMobileFlow.vue";
|
||||
import {
|
||||
attachments,
|
||||
popups
|
||||
} from "@/components/displays/department/pos/steps/mobile/objects/PosDepartmentStepMobileFlow.vue";
|
||||
// Debug mode flag
|
||||
const debug_mode = ref(false);
|
||||
// Debug array to store request results
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineEmits, watch, ref } from "vue";
|
||||
import { PosSearchResult } from "../objects/PosSearchResult.vue";
|
||||
import CustomerSearchField from "@/components/search/economic/customerSearchField.vue";
|
||||
import { searchCustomerResults, isSearching } from "@/components/search/economic/customerSearch.vue";
|
||||
import ControlFieldInputSearchResults
|
||||
from "@/components/viewport/elements/controls/fields/search/ControlFieldInputSearchResults.vue";
|
||||
import { searchAndSelectCustomer } from "@/components/shop/POSDepartmentProcess.vue";
|
||||
import { metadata, vehicles } from "../objects/PosDepartmentStepMobileFlow.vue";
|
||||
import VehicleCustomerSuggestionsPos from "@/components/forms/department/pos/input/vehicleCustomerSuggestionsPos.vue";
|
||||
import {
|
||||
actionButtons,
|
||||
popups
|
||||
} from "@/components/displays/department/pos/steps/mobile/objects/PosDepartmentStepMobileFlow.vue";
|
||||
import SessionUser from "@/components/session/token/SessionUser.vue";
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void;
|
||||
}>();
|
||||
|
||||
/**
|
||||
* Variables
|
||||
*/
|
||||
const searchQuery = ref("");
|
||||
const searchResult = ref(/**{
|
||||
"vat": 41004355,
|
||||
"status": "Normal",
|
||||
"name": "Truckwash ApS",
|
||||
"address": "Letland Alle 2",
|
||||
"zipcode": 2630,
|
||||
"city": "Taastrup",
|
||||
"protected": true,
|
||||
"phone": "21754690",
|
||||
"website": null,
|
||||
"email": "mikkel@truckwash.dk",
|
||||
"fax": null,
|
||||
"startdate": "2019-12-11",
|
||||
"enddate": null,
|
||||
"employees": 14,
|
||||
"industrycode": 953190,
|
||||
"industrydesc": "Reparation og vedligeholdelse af motorkøretøjer i.a.n.",
|
||||
"companytype": "APS",
|
||||
"companydesc": "Anpartsselskab",
|
||||
"owners": [
|
||||
"DELOITTE STATSAUTORISERET REVISIONSPARTNERSELSKAB",
|
||||
"MBL Revision I/S",
|
||||
"WASH GROUP A/S"
|
||||
]
|
||||
}*/null);
|
||||
const lastSearchResult = ref(null); // This is used to change the autofilled fields, when the search result changes
|
||||
const searching = ref(false);
|
||||
const error = ref(popups.get().props.error); // Used to display an error message if the customer creation fails
|
||||
const search = (query: string) => {
|
||||
return SessionUser.request("/cvr/search", "GET", {
|
||||
query: query,
|
||||
}).then((response) => {
|
||||
console.warn(response, 'response');
|
||||
searchResult.value = response.data.data;
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
searchResult.value = null;
|
||||
}).finally(() => {
|
||||
searching.value = false;
|
||||
changeAutofilledFields();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Form fields
|
||||
*/
|
||||
const cvr = ref("");
|
||||
const companyPhone = ref("");
|
||||
const invoiceEmail = ref("");
|
||||
const contactEmail = ref("");
|
||||
const contactPhone = ref("");
|
||||
/**
|
||||
* Autofill fields, when search result changes
|
||||
* If the operator has changed the values in the fields, we want to keep them, so we can autofill them again when the search result changes
|
||||
*/
|
||||
const changeAutofilledFields = () => {
|
||||
if (lastSearchResult.value !== null) {
|
||||
cvr.value = "";
|
||||
if (lastSearchResult.value.phone === companyPhone.value) {
|
||||
companyPhone.value = "";
|
||||
}
|
||||
if (lastSearchResult.value.phone === contactPhone.value) {
|
||||
contactPhone.value = "";
|
||||
}
|
||||
if (lastSearchResult.value.email === contactEmail.value) {
|
||||
contactEmail.value = "";
|
||||
}
|
||||
if (lastSearchResult.value.email === invoiceEmail.value) {
|
||||
invoiceEmail.value = "";
|
||||
}
|
||||
}
|
||||
// Fill the fields with the new search result
|
||||
if (searchResult.value !== null) {
|
||||
if (cvr.value === "") {
|
||||
cvr.value = searchResult.value.vat.toString();
|
||||
}
|
||||
if (companyPhone.value === "") {
|
||||
companyPhone.value = searchResult.value.phone;
|
||||
}
|
||||
if (contactPhone.value === "") {
|
||||
contactPhone.value = searchResult.value.phone;
|
||||
}
|
||||
if (contactEmail.value === "") {
|
||||
contactEmail.value = searchResult.value.email;
|
||||
}
|
||||
if (invoiceEmail.value === "") {
|
||||
invoiceEmail.value = searchResult.value.email;
|
||||
}
|
||||
}
|
||||
lastSearchResult.value = searchResult.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch the validity of the fields and emit an event to the parent component
|
||||
* If the fields are valid, we can enable the "Add Customer" button
|
||||
*/
|
||||
watch([cvr, companyPhone, invoiceEmail, contactEmail, contactPhone], (newValues) => {
|
||||
// Remove the "Add Customer" button if it exists
|
||||
const index = popups.get().actionButtons.findIndex((button) => button.label === "Tilføj kunde");
|
||||
if (index !== -1) {
|
||||
popups.get().actionButtons.splice(index, 1);
|
||||
}
|
||||
// Add the "Add Customer" button if all fields are filled
|
||||
if (newValues.every((value) => value !== "")) {
|
||||
popups.get().actionButtons.push({
|
||||
label: "Tilføj kunde",
|
||||
onClick: () => {
|
||||
popups.get().actionButtons = []; // Remove all action buttons to prevent multiple clicks
|
||||
try {
|
||||
SessionUser.request("/auth/register/cvr", "POST", {
|
||||
cvr: cvr.value,
|
||||
companyPhone: parseInt(companyPhone.value),
|
||||
invoiceEmail: invoiceEmail.value,
|
||||
contactEmail: contactEmail.value,
|
||||
contactPhone: parseInt(contactPhone.value),
|
||||
searchResult: searchResult.value,
|
||||
}).then((response) => {
|
||||
console.warn(response, 'response register cvr');
|
||||
searchAndSelectCustomer(companyPhone.value);
|
||||
metadata.setCustomerId(parseInt(companyPhone.value));
|
||||
emit('close');
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
const errorResponse = SessionUser.functions.parseErrorMessage(error);
|
||||
if (errorResponse !== null) {
|
||||
popups.get().props.error = `Der opstod en fejl under oprettelsen af kunden: ${errorResponse}`;
|
||||
// Reset the buttons
|
||||
popups.get().actionButtons = popups.get().actionButtons = [{...actionButtons.default.value.cancel}];
|
||||
return;
|
||||
}
|
||||
popups.get().props.error = "Der opstod en fejl under oprettelsen af kunden. Prøv igen.";
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
popups.get().props.error = "Der opstod en fejl under oprettelsen af kunden. Prøv igen.";
|
||||
}
|
||||
},
|
||||
color: "primary",
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="overflow-y: auto; overflow-x: hidden; height: 100%; padding-bottom: 10px;">
|
||||
<div class="mx-3">
|
||||
<div class="field">
|
||||
<label class="label"><small>CVR</small></label>
|
||||
<div class="control has-icons-right" :class="{'is-loading': searching}">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
@input="searching = true; search(searchQuery);"
|
||||
class="input is-searched"
|
||||
:class="{'is-danger': searchResult === null, 'is-success': searchResult !== null && searchResult.name !== 'Ikke fundet'}"
|
||||
type="text"
|
||||
placeholder="Søg CVR nummer..."
|
||||
/>
|
||||
<span class="icon is-right" :class="{'has-text-danger': (searchResult === null || searchResult.name === 'Ikke fundet') && !searching, 'has-text-success': (searchResult !== null && searchResult.name !== 'Ikke fundet') && !searching}">
|
||||
<i class="fas fa-check" v-if="(searchResult !== null && searchResult.name !== 'Ikke fundet') && !searching"></i>
|
||||
<i class="fas fa-exclamation-triangle" v-else-if="(searchResult === null || searchResult.name === 'Ikke fundet') && !searching"></i>
|
||||
<i class="fas fa-search" v-else-if="!searching"></i>
|
||||
</span>
|
||||
</div>
|
||||
<p class="help" v-if="searchResult !== null && searchResult.name !== 'Ikke fundet'">{{ searchResult.name }}</p>
|
||||
</div>
|
||||
<!-- Company phone -->
|
||||
<div class="field">
|
||||
<label class="label"><small>Firma telefon</small></label>
|
||||
<div class="control">
|
||||
<input v-model="companyPhone" class="input" type="text" placeholder="Firma telefon" :disabled="searchResult === null" :class="{'is-danger': searchResult !== null && companyPhone === ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Invoice email -->
|
||||
<div class="field">
|
||||
<label class="label"><small>Faktura email</small></label>
|
||||
<div class="control">
|
||||
<input v-model="invoiceEmail" class="input" type="text" placeholder="Faktura email" :disabled="searchResult === null" :class="{'is-danger': searchResult !== null && invoiceEmail === ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Contact email -->
|
||||
<div class="field">
|
||||
<label class="label"><small>Kontakt email</small></label>
|
||||
<div class="control">
|
||||
<input v-model="contactEmail" class="input" type="text" placeholder="Kontakt email" :disabled="searchResult === null" :class="{'is-danger': searchResult !== null && contactEmail === ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Contact phone -->
|
||||
<div class="field">
|
||||
<label class="label"><small>Kontakt telefon</small></label>
|
||||
<div class="control">
|
||||
<input v-model="contactPhone" class="input" type="text" placeholder="Kontakt telefon" :disabled="searchResult === null" :class="{'is-danger': searchResult !== null && contactPhone === ''}"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Error message -->
|
||||
<div class="notification is-danger" v-if="popups.get().props.error !== null">
|
||||
{{ popups.get().props.error}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Search results -->
|
||||
<!--{{ searchResult }}-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
+23
-1
@@ -157,6 +157,16 @@ const defaultActionButtons = ref<{ [key: string]: PosActionButton }>({
|
||||
},
|
||||
color: 'primary'
|
||||
},
|
||||
addCustomer: {
|
||||
label: 'Tilføj kunde',
|
||||
description: 'Tilføj en ny kunde til systemet',
|
||||
onClick: () => {
|
||||
console.warn('Add Customer button clicked');
|
||||
// Open the add customer popup
|
||||
popups.select('add_customer', { props: { error: null, canCreate: true } });
|
||||
},
|
||||
color: 'primary',
|
||||
},
|
||||
editReference: {
|
||||
label: 'Redigér reference',
|
||||
description: 'Redigér reference for denne transaktion',
|
||||
@@ -229,7 +239,7 @@ const addDefaultPopups = () => {
|
||||
message: 'Bekræft venligst valget af kunde til denne transaktion',
|
||||
component: 'select_customer',
|
||||
style: {height: '50vh'},
|
||||
actionButtons: [{...defaultActionButtons.value.cancel}],
|
||||
actionButtons: [{...defaultActionButtons.value.cancel}, {...defaultActionButtons.value.addCustomer, label: 'Ny kunde'}],
|
||||
});
|
||||
// Completed
|
||||
addPopup({
|
||||
@@ -315,6 +325,18 @@ const addDefaultPopups = () => {
|
||||
],
|
||||
props: {base64String: null, filename: null}
|
||||
});
|
||||
// Add customer
|
||||
addPopup({
|
||||
id: 'add_customer',
|
||||
title: 'Tilføj kunde',
|
||||
message: 'Indtast venligst oplysninger for den nye kunde',
|
||||
component: 'add_customer',
|
||||
style: {maxHeight: '60vh'},
|
||||
actionButtons: [
|
||||
{...defaultActionButtons.value.cancel}
|
||||
],
|
||||
props: {cvr: null, contactEmail: null, contactPhone: null, companyPhone: null, invoiceEmail: null, searchResult: null, canCreate: false, error: null}
|
||||
});
|
||||
}
|
||||
// Function to check if a popup is defined in the list
|
||||
const isPopupDefined = (id: string): boolean => {
|
||||
|
||||
@@ -20,8 +20,10 @@ import PosDepartmentStepMobilePopupCustomerNotes
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobilePopupCustomerNotes.vue";
|
||||
import PosDepartmentStepMobilePopupImage
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobilePopupImage.vue";
|
||||
import PosDepartmentStepMobilePopupAddCustomer
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobilePopupAddCustomer.vue";
|
||||
|
||||
export type PopupComponentKey = 'select_customer' | 'completed_transaction' | 'complete_booking' | 'error' | 'add_product_note' | 'select_vehicle' | 'change_reference' | 'customer_notes' | 'image_viewer';
|
||||
export type PopupComponentKey = 'select_customer' | 'completed_transaction' | 'complete_booking' | 'error' | 'add_product_note' | 'select_vehicle' | 'change_reference' | 'customer_notes' | 'image_viewer' | 'add_customer';
|
||||
|
||||
export const PopupComponents = {
|
||||
select_customer: PosDepartmentStepMobilePopupSelectCustomer,
|
||||
@@ -33,6 +35,7 @@ export const PopupComponents = {
|
||||
change_reference: PosDepartmentStepMobilePopupSetReference,
|
||||
customer_notes: PosDepartmentStepMobilePopupCustomerNotes,
|
||||
image_viewer: PosDepartmentStepMobilePopupImage,
|
||||
add_customer: PosDepartmentStepMobilePopupAddCustomer
|
||||
} as const;
|
||||
|
||||
export const popupComponentKeyToComponent = (key: PopupComponentKey) => PopupComponents[key];
|
||||
@@ -64,6 +67,7 @@ export default defineComponent({
|
||||
PosDepartmentStepMobilePopupSetReference,
|
||||
PosDepartmentStepMobilePopupCustomerNotes,
|
||||
PosDepartmentStepMobilePopupImage,
|
||||
PosDepartmentStepMobilePopupAddCustomer
|
||||
},
|
||||
props: {
|
||||
popup: {
|
||||
|
||||
Reference in New Issue
Block a user