Dominik Milacher f6e88469b3
All checks were successful
Build and deploy updated apps / Build & deploy (push) Successful in 1m49s
Update contact form
2025-10-15 10:04:43 +02:00

155 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<!-- Contactcentric layout -->
<AppFlatSection>
<!-- Grid: form (fixed maxwidth) | host snapshots -->
<div class="flex flex-col md:flex-row gap-8 items-center">
<!-- Contact form -->
<div class="w-full md:w-auto max-w-xl mx-auto lg:mx-0">
<h1 class="text-3xl sm:text-4xl font-bold mb-4">{{ c.contact.title }}</h1>
<!-- Extended intro -->
<p class="text-neutral-600 mb-4 max-w-prose">
{{ c.contact.description }}
</p>
<!-- Contact shortcuts -->
<div class="mb-8 space-y-1 text-sm">
<!-- Phone (phone + WhatsApp icons) -->
<div class="flex items-center gap-2">
<!-- Heroicons phone -->
<UIcon name="i-heroicons-phone" class="w-4 h-4 text-neutral-600"/>
<!-- WhatsApp icon (any Iconify set you use) -->
<UIcon name="i-uil-whatsapp" class="w-4 h-4 text-neutral-600"/>
<a :href="`tel:${c.contact.phone.replace(/\s+/g, '')}`" class="hover:underline text-neutral-600">
{{ c.contact.phone }}
</a>
</div>
<!-- E-mail -->
<div class="flex items-center gap-2">
<UIcon name="i-heroicons-envelope" class="w-4 h-4 text-neutral-600"/>
<a :href="`mailto:${c.contact.email}`" class="hover:underline text-neutral-600">
{{ c.contact.email }}
</a>
</div>
</div>
<p class="text-neutral-600 mb-4 max-w-prose">
{{ c.contact.online1 }}
<UButton :to="p('book')" variant="outline" trailing-icon="i-heroicons-calendar-days">{{
c.contact.online2
}}
</UButton>
{{ c.contact.online3 }}
</p>
<!-- Form -->
<UForm :state="state" :schema="schema" class="space-y-4" @submit="onSubmit">
<UFormField name="name" label="Name" :ui="{ label: 'sr-only' }">
<UInput v-model="state.name" class="w-full" :placeholder="c.contact.form.name.prompt"/>
</UFormField>
<UFormField name="email" label="E-Mail" :ui="{ label: 'sr-only' }">
<UInput v-model="state.email" type="email" class="w-full"
:placeholder="c.contact.form.email.prompt"/>
</UFormField>
<UFormField name="subject" label="Betreff" :ui="{ label: 'sr-only' }">
<UInput v-model="state.subject" class="w-full" :placeholder="c.contact.form.subject.prompt"/>
</UFormField>
<UFormField name="message" label="Nachricht" :ui="{ label: 'sr-only' }">
<UTextarea v-model="state.message" :rows="6" class="w-full"
:placeholder="c.contact.form.message.prompt"/>
</UFormField>
<UButton type="submit" color="primary" size="lg" class="w-full sm:w-auto" trailing-icon="i-heroicons-paper-airplane">
{{ c.contact.form.send }}
</UButton>
</UForm>
</div>
<!-- Decorative host snapshots -->
<div id="hosts" class="flex flex-col gap-10 lg:self-center w-full md:w-auto">
<AppHero
:src="c.contact.heroes.parents.image"
:alt="c.contact.heroes.parents.title"
image-side="left"
:size="50"
:title="c.contact.heroes.parents.title"
:description="c.contact.heroes.parents.description"
/>
<AppHero
:src="c.contact.heroes.children.image"
:alt="c.contact.heroes.children.title"
image-side="right"
:size="50"
:title="c.contact.heroes.children.title"
:description="c.contact.heroes.children.description"
/>
</div>
</div>
</AppFlatSection>
</div>
</template>
<script setup lang="ts">
/*TODO form should contain link to privacy statement?*/
const {p, c} = useContent()
import * as v from 'valibot'
import type {FormSubmitEvent} from '@nuxt/ui'
/* ───── validation schema ───── */
const schema = computed(() => v.object({
name: v.pipe(v.string(), v.minLength(2, c.value.contact.form.name.invalid)),
email: v.pipe(v.string(), v.email(c.value.contact.form.email.invalid)),
subject: v.pipe(v.string(), v.minLength(3, c.value.contact.form.subject.invalid)),
message: v.pipe(v.string(), v.minLength(10, c.value.contact.form.message.invalid))
}))
//type Schema = v.InferOutput<typeof schema>
/* ───── reactive form state ───── */
const state = reactive({
name: '', email: '', subject: '', message: ''
})
const toast = useToast()
/* ───── submit handler ───── */
async function onSubmit(event: FormSubmitEvent<Schema>) {
const config = useAppConfig()
const hotelId = config.content.business.uid ?? ''
try {
await $fetch('https://api.dominikmilacher.com/contact', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: {
...event.data,
hotel: hotelId
}
})
toast.add({
title: c.value.contact.form.sent.title,
description: c.value.contact.form.sent.description,
color: 'primary'
})
/* reset fields */
Object.assign(state, {name: '', email: '', subject: '', message: ''})
} catch (err: any) {
//console.log(err?.data?.detail)
//console.log(err?.message)
toast.add({
title: c.value.contact.form.error.title,
description: c.value.contact.form.error.description,
color: 'primary'
})
}
}
</script>