83 lines
1.8 KiB
Svelte
83 lines
1.8 KiB
Svelte
<script lang="ts">
|
|
import { API, api, inferOutput } from "astro-typesafe-api/client";
|
|
|
|
export let name: string;
|
|
export let readonly: boolean = false;
|
|
export let city: string | null | undefined;
|
|
export let zip: string | null = "";
|
|
|
|
|
|
let hideZipDropdown: boolean = true;
|
|
let zipCodes: inferOutput<API["postleitzahlen"]["GET"]> = [];
|
|
|
|
async function fetchZipCodeInformation() {
|
|
if (!zip || (zip.length < 2)) {
|
|
return
|
|
}
|
|
|
|
try {
|
|
const result = await api.postleitzahlen.GET.fetch({ plz: zip, limit: 10 });
|
|
|
|
if (result.length > 0) {
|
|
zipCodes = result;
|
|
hideZipDropdown = false;
|
|
}
|
|
} catch(e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
function clickOutside(element: HTMLElement, callbackFunction: () => any) {
|
|
function onClick(event: MouseEvent) {
|
|
if (!element.contains(event.target as HTMLElement)) {
|
|
callbackFunction();
|
|
}
|
|
}
|
|
|
|
document.body.addEventListener('click', onClick);
|
|
|
|
return {
|
|
destroy() {
|
|
document.body.removeEventListener('click', onClick);
|
|
}
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<div use:clickOutside={() => {
|
|
hideZipDropdown = true;
|
|
}}>
|
|
|
|
<input
|
|
name={name}
|
|
id={name}
|
|
type="text"
|
|
required
|
|
readonly={readonly}
|
|
bind:value={zip}
|
|
on:input={fetchZipCodeInformation}
|
|
on:focus={() => {
|
|
if (zipCodes.length > 0) {
|
|
hideZipDropdown = false
|
|
}
|
|
}}
|
|
maxlength="5"
|
|
/>
|
|
|
|
<div data-test="plz-container" class="absolute top-[calc(100%+4px)] flex flex-col left-0 bg-white py-1 shadow-md rounded-lg z-10" class:hidden={hideZipDropdown}>
|
|
{#each zipCodes as zipCode}
|
|
<button class="hover:bg-gray-100 cursor-pointer px-2 py-1 text-nowrap" type="button" tabindex="-1" on:click={() => {
|
|
zip = zipCode.plz;
|
|
city = zipCode.stadt;
|
|
hideZipDropdown = true;
|
|
}}>{zipCode.plz}, {zipCode.stadt}</button>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
button:not(:last-of-type) {
|
|
@apply border-b border-b-gray-200;
|
|
}
|
|
</style> |