Files
online-energieausweis/src/components/PlzSuche.svelte
2025-02-21 12:25:28 +11:00

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>