Dominik Milacher 73083ded58
Some checks failed
Build and deploy updated apps / Build & deploy (push) Failing after 1m7s
Overhaul content management
2025-10-22 19:31:38 +02:00

161 lines
5.5 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">{{ l.title }}</h1>
<!-- Extended intro -->
<p class="text-neutral-600 mb-4 max-w-prose">
{{ l.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:${g.business.phone.replace(/\s+/g, '')}`" class="hover:underline text-neutral-600">
{{ g.business.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:${g.business.email}`" class="hover:underline text-neutral-600">
{{ g.business.email }}
</a>
</div>
</div>
<p class="text-neutral-600 mb-4 max-w-prose">
{{ l.online1 }}
<UButton :to="p('book')" variant="outline" trailing-icon="i-heroicons-calendar-days">{{
l.online2
}}
</UButton>
{{ l.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="l.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="l.form.email.prompt"/>
</UFormField>
<UFormField name="subject" label="Betreff" :ui="{ label: 'sr-only' }">
<UInput v-model="state.subject" class="w-full" :placeholder="l.form.subject.prompt"/>
</UFormField>
<UFormField name="message" label="Nachricht" :ui="{ label: 'sr-only' }">
<UTextarea v-model="state.message" :rows="6" class="w-full"
:placeholder="l.form.message.prompt"/>
</UFormField>
<UButton type="submit" color="primary" size="lg" class="w-full sm:w-auto" trailing-icon="i-heroicons-paper-airplane">
{{ l.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="l.heroes.parents.image"
:alt="l.heroes.parents.title"
image-side="left"
:size="50"
:title="l.heroes.parents.title"
:description="l.heroes.parents.description"
/>
<AppHero
:src="l.heroes.children.image"
:alt="l.heroes.children.title"
image-side="right"
:size="50"
:title="l.heroes.children.title"
:description="l.heroes.children.description"
/>
</div>
</div>
</AppFlatSection>
</div>
</template>
<script setup lang="ts">
useSeoLinking()
const {g, l, p} = useContentInjected()
useSeoMeta({
title: () => l.value.meta.title,
description: () => l.value.meta.description,
})
/*TODO form should contain link to privacy statement?*/
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, l.value.form.name.invalid)),
email: v.pipe(v.string(), v.email(l.value.form.email.invalid)),
subject: v.pipe(v.string(), v.minLength(3, l.value.form.subject.invalid)),
message: v.pipe(v.string(), v.minLength(10, l.value.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 hotelId = g.value.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: l.value.form.sent.title,
description: l.value.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: l.value.form.error.title,
description: l.value.form.error.description,
color: 'primary'
})
}
}
</script>