get create client working
This commit is contained in:
parent
4a3576168a
commit
cb33d0c3b3
11 changed files with 1179 additions and 336 deletions
|
|
@ -0,0 +1,361 @@
|
|||
<template>
|
||||
<div class="form-section">
|
||||
<div class="section-header">
|
||||
<h3>Contact Information</h3>
|
||||
<div class="toggle-container" v-if="!isEditMode">
|
||||
<label for="new-contact-toggle" class="toggle-label">New Contact</label>
|
||||
<ToggleSwitch
|
||||
v-model="isNewContact"
|
||||
inputId="new-contact-toggle"
|
||||
:disabled="isNewClientLocked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<!-- Select existing contact mode -->
|
||||
<template v-if="!isNewContact">
|
||||
<div class="form-field full-width">
|
||||
<label for="contact-select"> Contact <span class="required">*</span> </label>
|
||||
<Select
|
||||
id="contact-select"
|
||||
v-model="selectedContact"
|
||||
:options="contactOptions"
|
||||
optionLabel="label"
|
||||
:disabled="isSubmitting || contactOptions.length === 0"
|
||||
placeholder="Select a contact"
|
||||
class="w-full"
|
||||
@change="handleContactSelect"
|
||||
/>
|
||||
<small v-if="contactOptions.length === 0" class="helper-text">
|
||||
No contacts available. Toggle "New Contact" to add one.
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="contact-phone">Phone</label>
|
||||
<InputText
|
||||
id="contact-phone"
|
||||
v-model="localFormData.phoneNumber"
|
||||
disabled
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="contact-email">Email</label>
|
||||
<InputText
|
||||
id="contact-email"
|
||||
v-model="localFormData.email"
|
||||
disabled
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- New contact mode -->
|
||||
<template v-else>
|
||||
<div class="form-field full-width">
|
||||
<div class="checkbox-container">
|
||||
<Checkbox
|
||||
v-model="sameAsClientName"
|
||||
inputId="same-as-client"
|
||||
:binary="true"
|
||||
:disabled="isSubmitting || isEditMode || !isNewClientLocked"
|
||||
/>
|
||||
<label for="same-as-client" class="checkbox-label">
|
||||
Same as Client Name
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="first-name"> First Name <span class="required">*</span> </label>
|
||||
<InputText
|
||||
id="first-name"
|
||||
v-model="localFormData.firstName"
|
||||
:disabled="isSubmitting || sameAsClientName"
|
||||
placeholder="Enter first name"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="last-name"> Last Name <span class="required">*</span> </label>
|
||||
<InputText
|
||||
id="last-name"
|
||||
v-model="localFormData.lastName"
|
||||
:disabled="isSubmitting || sameAsClientName"
|
||||
placeholder="Enter last name"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="phone-number">Phone</label>
|
||||
<InputText
|
||||
id="phone-number"
|
||||
v-model="localFormData.phoneNumber"
|
||||
:disabled="isSubmitting"
|
||||
placeholder="(555) 123-4567"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="email">Email</label>
|
||||
<InputText
|
||||
id="email"
|
||||
v-model="localFormData.email"
|
||||
:disabled="isSubmitting"
|
||||
type="email"
|
||||
placeholder="email@example.com"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed, onMounted } from "vue";
|
||||
import InputText from "primevue/inputtext";
|
||||
import Select from "primevue/select";
|
||||
import ToggleSwitch from "primevue/toggleswitch";
|
||||
import Checkbox from "primevue/checkbox";
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isSubmitting: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isEditMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isNewClientLocked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
availableContacts: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:formData", "newContactToggle"]);
|
||||
|
||||
const localFormData = computed({
|
||||
get: () => props.formData,
|
||||
set: (value) => emit("update:formData", value),
|
||||
});
|
||||
|
||||
const isNewContact = ref(false);
|
||||
const selectedContact = ref(null);
|
||||
const sameAsClientName = ref(false);
|
||||
|
||||
// Compute contact options from available contacts
|
||||
const contactOptions = computed(() => {
|
||||
if (!props.availableContacts || props.availableContacts.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return props.availableContacts.map((contact) => ({
|
||||
label: `${contact.firstName} ${contact.lastName}`,
|
||||
value: contact,
|
||||
}));
|
||||
});
|
||||
|
||||
// Ensure New Contact is ON and locked when New Client is ON
|
||||
watch(
|
||||
() => props.isNewClientLocked,
|
||||
(locked) => {
|
||||
if (locked) {
|
||||
isNewContact.value = true;
|
||||
} else {
|
||||
isNewContact.value = false;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// On mount, set isNewContact to true if isNewClientLocked is true
|
||||
onMounted(() => {
|
||||
if (props.isNewClientLocked) {
|
||||
isNewContact.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-check "Same as Client Name" when customer type is Individual
|
||||
watch(
|
||||
() => props.formData.customerType,
|
||||
(customerType) => {
|
||||
if (customerType === "Individual" && props.isNewClientLocked && !props.isEditMode) {
|
||||
sameAsClientName.value = true;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// Reset "Same as Client Name" when editing or using existing customer
|
||||
watch([() => props.isEditMode, () => props.isNewClientLocked], ([editMode, newClientLocked]) => {
|
||||
if (editMode || !newClientLocked) {
|
||||
sameAsClientName.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-fill name fields when "Same as Client Name" is checked
|
||||
watch(sameAsClientName, (checked) => {
|
||||
if (checked && props.formData.customerName) {
|
||||
const nameParts = props.formData.customerName.trim().split(" ");
|
||||
if (nameParts.length === 1) {
|
||||
localFormData.value.firstName = nameParts[0];
|
||||
localFormData.value.lastName = "";
|
||||
} else if (nameParts.length >= 2) {
|
||||
localFormData.value.firstName = nameParts[0];
|
||||
localFormData.value.lastName = nameParts.slice(1).join(" ");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for customer name changes when "Same as Client Name" is checked
|
||||
watch(
|
||||
() => props.formData.customerName,
|
||||
(newName) => {
|
||||
if (sameAsClientName.value && newName) {
|
||||
const nameParts = newName.trim().split(" ");
|
||||
if (nameParts.length === 1) {
|
||||
localFormData.value.firstName = nameParts[0];
|
||||
localFormData.value.lastName = "";
|
||||
} else if (nameParts.length >= 2) {
|
||||
localFormData.value.firstName = nameParts[0];
|
||||
localFormData.value.lastName = nameParts.slice(1).join(" ");
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Watch for toggle changes
|
||||
watch(isNewContact, (newValue) => {
|
||||
if (newValue) {
|
||||
// Clear contact selection when switching to new contact mode
|
||||
selectedContact.value = null;
|
||||
localFormData.value.firstName = "";
|
||||
localFormData.value.lastName = "";
|
||||
localFormData.value.phoneNumber = "";
|
||||
localFormData.value.email = "";
|
||||
}
|
||||
emit("newContactToggle", newValue);
|
||||
});
|
||||
|
||||
const handleContactSelect = () => {
|
||||
if (selectedContact.value && selectedContact.value.value) {
|
||||
const contact = selectedContact.value.value;
|
||||
localFormData.value.firstName = contact.firstName;
|
||||
localFormData.value.lastName = contact.lastName;
|
||||
localFormData.value.phoneNumber = contact.phone || "";
|
||||
localFormData.value.email = contact.email || "";
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
isNewContact,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-section {
|
||||
background: var(--surface-card);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid var(--surface-border);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.toggle-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.toggle-label {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-color-secondary);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-field.full-width {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
font-weight: 500;
|
||||
color: var(--text-color-secondary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--red-500);
|
||||
}
|
||||
|
||||
.helper-text {
|
||||
color: var(--text-color-secondary);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-color-secondary);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue