get create client working

This commit is contained in:
Casey 2025-11-25 06:22:44 -06:00
parent 4a3576168a
commit cb33d0c3b3
11 changed files with 1179 additions and 336 deletions

View file

@ -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>