189 lines
4.2 KiB
Vue
189 lines
4.2 KiB
Vue
<template>
|
|
<div class="form-section">
|
|
<h3>Address Information</h3>
|
|
<div class="form-grid">
|
|
<div class="form-field full-width">
|
|
<label for="address-line1"> Address Line 1 <span class="required">*</span> </label>
|
|
<InputText
|
|
id="address-line1"
|
|
v-model="localFormData.addressLine1"
|
|
:disabled="isSubmitting"
|
|
placeholder="Street address"
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
<div class="form-field full-width">
|
|
<label for="address-line2">Address Line 2</label>
|
|
<InputText
|
|
id="address-line2"
|
|
v-model="localFormData.addressLine2"
|
|
:disabled="isSubmitting"
|
|
placeholder="Apt, suite, unit, etc."
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
<div class="form-field">
|
|
<label for="zipcode"> Zip Code <span class="required">*</span> </label>
|
|
<InputText
|
|
id="zipcode"
|
|
v-model="localFormData.pincode"
|
|
:disabled="isSubmitting"
|
|
@input="handleZipcodeInput"
|
|
maxlength="5"
|
|
placeholder="12345"
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
<div class="form-field">
|
|
<label for="city"> City <span class="required">*</span> </label>
|
|
<InputText
|
|
id="city"
|
|
v-model="localFormData.city"
|
|
:disabled="isSubmitting || zipcodeLookupDisabled"
|
|
placeholder="City"
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
<div class="form-field">
|
|
<label for="state"> State <span class="required">*</span> </label>
|
|
<InputText
|
|
id="state"
|
|
v-model="localFormData.state"
|
|
:disabled="isSubmitting || zipcodeLookupDisabled"
|
|
placeholder="State"
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from "vue";
|
|
import InputText from "primevue/inputtext";
|
|
import Api from "../../api";
|
|
import { useNotificationStore } from "../../stores/notifications-primevue";
|
|
|
|
const props = defineProps({
|
|
formData: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
isSubmitting: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
isEditMode: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(["update:formData"]);
|
|
|
|
const notificationStore = useNotificationStore();
|
|
|
|
const localFormData = computed({
|
|
get: () => props.formData,
|
|
set: (value) => emit("update:formData", value),
|
|
});
|
|
|
|
const zipcodeLookupDisabled = ref(true);
|
|
|
|
const handleZipcodeInput = async (event) => {
|
|
const input = event.target.value;
|
|
|
|
// Only allow digits
|
|
const digitsOnly = input.replace(/\D/g, "");
|
|
|
|
// Limit to 5 digits
|
|
if (digitsOnly.length > 5) {
|
|
return;
|
|
}
|
|
|
|
localFormData.value.pincode = digitsOnly;
|
|
|
|
// Reset city/state if zipcode is not complete
|
|
if (digitsOnly.length < 5 && zipcodeLookupDisabled.value) {
|
|
localFormData.value.city = "";
|
|
localFormData.value.state = "";
|
|
zipcodeLookupDisabled.value = false;
|
|
}
|
|
|
|
// Fetch city/state when 5 digits entered
|
|
if (digitsOnly.length === 5) {
|
|
try {
|
|
console.log("DEBUG: Looking up city/state for zip code:", digitsOnly);
|
|
const places = await Api.getCityStateByZip(digitsOnly);
|
|
console.log("DEBUG: Retrieved places:", places);
|
|
if (places && places.length > 0) {
|
|
// Auto-populate city and state
|
|
localFormData.value.city = places[0]["city"];
|
|
localFormData.value.state = places[0]["state"];
|
|
zipcodeLookupDisabled.value = true;
|
|
notificationStore.addSuccess(`Found: ${places[0]["city"]}, ${places[0]["state"]}`);
|
|
}
|
|
} catch (error) {
|
|
// Enable manual entry if lookup fails
|
|
zipcodeLookupDisabled.value = false;
|
|
notificationStore.addWarning(
|
|
"Could not find city/state for this zip code. Please enter manually.",
|
|
);
|
|
}
|
|
}
|
|
};
|
|
</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);
|
|
}
|
|
|
|
.form-section h3 {
|
|
margin: 0 0 1rem 0;
|
|
color: var(--text-color);
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.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);
|
|
}
|
|
|
|
.w-full {
|
|
width: 100% !important;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.form-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|