Files
service-finder/frontend_admin/components/SharedAddressForm.vue
2026-07-02 11:52:22 +00:00

230 lines
7.8 KiB
Vue

<template>
<div>
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6 mb-6">
<h2 class="text-lg font-semibold text-white mb-4">Cím adatok</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Smart Location Input (zip + city autocomplete) -->
<div class="md:col-span-2">
<SmartLocationInput
:model-value="selectedLocation"
@update:model-value="onLocationSelected"
label="Irányítószám / Város"
placeholder="Kezdj el gépelni (pl. 1011 vagy Budapest)..."
/>
</div>
<!-- Street name -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Utca neve</label>
<input
:value="modelValue.street_name"
@input="updateField('street_name', ($event.target as HTMLInputElement).value)"
placeholder="pl. Egressy"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
<!-- Street type -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Közterület jellege</label>
<select
:value="modelValue.street_type"
@change="updateField('street_type', ($event.target as HTMLSelectElement).value)"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
>
<option value="">Válassz...</option>
<option value="utca">utca</option>
<option value="út">út</option>
<option value="tér">tér</option>
<option value="körút">körút</option>
<option value="sugárút">sugárút</option>
<option value="köz">köz</option>
<option value="sétány">sétány</option>
<option value="lakópark">lakópark</option>
<option value="liget">liget</option>
<option value="erdő">erdő</option>
<option value="dűlő">dűlő</option>
<option value="major">major</option>
<option value="puszta">puszta</option>
<option value="sziget">sziget</option>
<option value="telep">telep</option>
</select>
</div>
<!-- House number -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Házszám</label>
<input
:value="modelValue.house_number"
@input="updateField('house_number', ($event.target as HTMLInputElement).value)"
placeholder="pl. 4/b"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
<!-- Stairwell -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Lépcsőház</label>
<input
:value="modelValue.stairwell"
@input="updateField('stairwell', ($event.target as HTMLInputElement).value)"
placeholder="pl. 1"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
<!-- Floor -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Emelet</label>
<input
:value="modelValue.floor"
@input="updateField('floor', ($event.target as HTMLInputElement).value)"
placeholder="pl. 3"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
<!-- Door -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Ajtó</label>
<input
:value="modelValue.door"
@input="updateField('door', ($event.target as HTMLInputElement).value)"
placeholder="pl. A"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
<!-- Parcel ID (hrsz) -->
<div>
<label class="block text-sm font-medium text-slate-300 mb-1">Helyrajzi szám (hrsz)</label>
<input
:value="modelValue.parcel_id"
@input="updateField('parcel_id', ($event.target as HTMLInputElement).value)"
placeholder="pl. 12345/6"
class="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500 text-sm"
/>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
/**
* SharedAddressForm.vue
* ======================
*
* Reusable address form component that uses SmartLocationInput for
* zip/city autocomplete and provides all other address fields.
*
* Usage:
* <SharedAddressForm v-model="form.address" />
*
* The v-model expects an object matching the AddressIn schema:
* {
* zip?: string
* city?: string
* street_name?: string
* street_type?: string
* house_number?: string
* stairwell?: string
* floor?: string
* door?: string
* parcel_id?: string
* full_address_text?: string
* latitude?: number
* longitude?: number
* }
*/
import { ref, computed } from 'vue'
interface AddressForm {
zip?: string | null
city?: string | null
street_name?: string | null
street_type?: string | null
house_number?: string | null
stairwell?: string | null
floor?: string | null
door?: string | null
parcel_id?: string | null
full_address_text?: string | null
latitude?: number | null
longitude?: number | null
}
interface LocationItem {
id: number
zip_code: string
city: string
country_code: string
}
const props = withDefaults(defineProps<{
modelValue?: AddressForm
}>(), {
modelValue: () => ({
zip: null,
city: null,
street_name: null,
street_type: null,
house_number: null,
stairwell: null,
floor: null,
door: null,
parcel_id: null,
full_address_text: null,
latitude: null,
longitude: null,
}),
})
const emit = defineEmits<{
'update:modelValue': [value: AddressForm]
}>()
/**
* Computed property for the SmartLocationInput selected value.
* Converts the address zip/city to a LocationItem if both are present.
*/
const selectedLocation = computed<LocationItem | null>(() => {
if (props.modelValue?.zip && props.modelValue?.city) {
return {
id: 0, // We don't have the DB id here, but SmartLocationInput handles this
zip_code: props.modelValue.zip,
city: props.modelValue.city,
country_code: 'HU',
}
}
return null
})
/**
* Handle location selection from SmartLocationInput.
* Updates the zip and city fields in the address model.
*/
function onLocationSelected(location: LocationItem | null) {
const updated = { ...props.modelValue }
if (location) {
updated.zip = location.zip_code
updated.city = location.city
} else {
updated.zip = null
updated.city = null
}
emit('update:modelValue', updated)
}
/**
* Update a single field in the address model.
*/
function updateField(field: keyof AddressForm, value: string) {
const updated = { ...props.modelValue }
;(updated as any)[field] = value || null
emit('update:modelValue', updated)
}
</script>