Update contact form
All checks were successful
Build and deploy updated apps / Build & deploy (push) Successful in 1m49s

This commit is contained in:
Dominik Milacher 2025-10-15 10:04:43 +02:00
parent cbfab733b7
commit f6e88469b3
4 changed files with 84 additions and 47 deletions

View File

@ -22,6 +22,7 @@ const matrix: ContentMatrix = {
} }
const business: BusinessInfo = { const business: BusinessInfo = {
uid: 'panoramablick-saalbach.at',
name: { name: {
de: 'Landhaus Panoramablick', de: 'Landhaus Panoramablick',
en: 'Guesthouse Panoramablick' en: 'Guesthouse Panoramablick'
@ -485,7 +486,6 @@ export default defineAppConfig({
contact: { contact: {
title: { title: {
de: 'Kontakt aufnehmen', de: 'Kontakt aufnehmen',
'de@winter': 'Winterkontakt',
en: 'Contact us' en: 'Contact us'
}, },
description: { description: {
@ -508,24 +508,68 @@ export default defineAppConfig({
}, },
form: { form: {
name: { name: {
de: 'Ihr Name', prompt: {
en: 'Your name' de: 'Ihr Name',
en: 'Your name'
},
invalid: {
de: 'Name zu kurz',
en: 'Name too short'
}
}, },
email: { email: {
de: 'Ihre E-Mail', prompt: {
en: 'Your email address' de: 'Ihre E-Mail',
en: 'Your email address'
},
invalid: {
de: 'E-Mail Adresse nicht gültig',
en: 'Email address not valid'
}
}, },
subject: { subject: {
de: 'Betreff', prompt: {
en: 'Subject' de: 'Betreff',
en: 'Subject'
},
invalid: {
de: 'Betreff zu kurz',
en: 'Subject too short'
}
}, },
message: { message: {
de: 'Ihre Anfrage', prompt: {
en: 'Your inquiry' de: 'Ihre Anfrage',
en: 'Your inquiry'
},
invalid: {
de: 'Nachricht zu kurz',
en: 'Message too short'
}
}, },
send: { send: {
de: 'Senden', de: 'Senden',
en: 'Send' en: 'Send'
},
sent: {
title: {
de: 'Nachricht gesendet',
en: 'Message sent'
},
description: {
de: 'Vielen Dank - wir melden uns bald.',
en: 'Thank you - we\'ll be in touch soon.'
}
},
error: {
title: {
de: 'Fehler',
en: 'Error'
},
description: {
de: 'Die Nachricht konnte nicht versendet werden - bitte versuchen Sie es erneut.',
en: 'The message could not be sent - please try again.'
}
} }
}, },
heroes: { heroes: {
@ -545,7 +589,7 @@ export default defineAppConfig({
}, },
image: '/family/sabrina-daniel.webp' image: '/family/sabrina-daniel.webp'
} }
} },
}, },
apartments: { apartments: {
'highlight': { 'highlight': {

View File

@ -10,7 +10,6 @@ const { add } = useToast()
const shown = useCookie('cookie-toast-shown', { maxAge: 60 * 60 * 24 * 7 }) const shown = useCookie('cookie-toast-shown', { maxAge: 60 * 60 * 24 * 7 })
onMounted(() => { onMounted(() => {
console.log("MIAU", c.value)
if (!shown.value) { if (!shown.value) {
add({ add({
title: c.value.cookies.title, title: c.value.cookies.title,

View File

@ -45,23 +45,23 @@
</p> </p>
<!-- Form --> <!-- Form -->
<UForm :state="state" class="space-y-4" @submit="onSubmit"> <UForm :state="state" :schema="schema" class="space-y-4" @submit="onSubmit">
<UFormField name="name" label="Name" :ui="{ label: 'sr-only' }"> <UFormField name="name" label="Name" :ui="{ label: 'sr-only' }">
<UInput v-model="state.name" class="w-full" :placeholder="c.contact.form.name"/> <UInput v-model="state.name" class="w-full" :placeholder="c.contact.form.name.prompt"/>
</UFormField> </UFormField>
<UFormField name="email" label="E-Mail" :ui="{ label: 'sr-only' }"> <UFormField name="email" label="E-Mail" :ui="{ label: 'sr-only' }">
<UInput v-model="state.email" type="email" class="w-full" <UInput v-model="state.email" type="email" class="w-full"
:placeholder="c.contact.form.email"/> :placeholder="c.contact.form.email.prompt"/>
</UFormField> </UFormField>
<UFormField name="subject" label="Betreff" :ui="{ label: 'sr-only' }"> <UFormField name="subject" label="Betreff" :ui="{ label: 'sr-only' }">
<UInput v-model="state.subject" class="w-full" :placeholder="c.contact.form.subject"/> <UInput v-model="state.subject" class="w-full" :placeholder="c.contact.form.subject.prompt"/>
</UFormField> </UFormField>
<UFormField name="message" label="Nachricht" :ui="{ label: 'sr-only' }"> <UFormField name="message" label="Nachricht" :ui="{ label: 'sr-only' }">
<UTextarea v-model="state.message" :rows="6" class="w-full" <UTextarea v-model="state.message" :rows="6" class="w-full"
:placeholder="c.contact.form.message"/> :placeholder="c.contact.form.message.prompt"/>
</UFormField> </UFormField>
<UButton type="submit" color="primary" size="lg" class="w-full sm:w-auto" trailing-icon="i-heroicons-paper-airplane"> <UButton type="submit" color="primary" size="lg" class="w-full sm:w-auto" trailing-icon="i-heroicons-paper-airplane">
@ -103,16 +103,16 @@ import * as v from 'valibot'
import type {FormSubmitEvent} from '@nuxt/ui' import type {FormSubmitEvent} from '@nuxt/ui'
/* ───── validation schema ───── */ /* ───── validation schema ───── */
const schema = v.object({ const schema = computed(() => v.object({
name: v.pipe(v.string(), v.minLength(2, 'Bitte Namen eingeben')), name: v.pipe(v.string(), v.minLength(2, c.value.contact.form.name.invalid)),
email: v.pipe(v.string(), v.email('Ungültige E-Mail')), email: v.pipe(v.string(), v.email(c.value.contact.form.email.invalid)),
subject: v.pipe(v.string(), v.minLength(3, 'Betreff fehlt')), subject: v.pipe(v.string(), v.minLength(3, c.value.contact.form.subject.invalid)),
message: v.pipe(v.string(), v.minLength(10, 'Nachricht ist zu kurz')) message: v.pipe(v.string(), v.minLength(10, c.value.contact.form.message.invalid))
}) }))
type Schema = v.InferOutput<typeof schema> //type Schema = v.InferOutput<typeof schema>
/* ───── reactive form state ───── */ /* ───── reactive form state ───── */
const state = reactive<Schema>({ const state = reactive({
name: '', email: '', subject: '', message: '' name: '', email: '', subject: '', message: ''
}) })
@ -120,17 +120,8 @@ const toast = useToast()
/* ───── submit handler ───── */ /* ───── submit handler ───── */
async function onSubmit(event: FormSubmitEvent<Schema>) { async function onSubmit(event: FormSubmitEvent<Schema>) {
const config = useRuntimeConfig() const config = useAppConfig()
const hotelId = config.public.hotelId const hotelId = config.content.business.uid ?? ''
if (!hotelId) {
toast.add({
title: 'Fehler',
description: 'Hotel-ID ist nicht konfiguriert!',
color: 'primary'
})
throw new Error('Hotel ID not configured')
}
try { try {
await $fetch('https://api.dominikmilacher.com/contact', { await $fetch('https://api.dominikmilacher.com/contact', {
@ -143,17 +134,19 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
}) })
toast.add({ toast.add({
title: 'Nachricht gesendet', title: c.value.contact.form.sent.title,
description: 'Vielen Dank wir melden uns bald.', description: c.value.contact.form.sent.description,
color: 'primary' color: 'primary'
}) })
/* reset fields */ /* reset fields */
Object.assign(state, {name: '', email: '', subject: '', message: ''}) Object.assign(state, {name: '', email: '', subject: '', message: ''})
} catch (err: any) { } catch (err: any) {
//console.log(err?.data?.detail)
//console.log(err?.message)
toast.add({ toast.add({
title: 'Fehler', title: c.value.contact.form.error.title,
description: err?.data?.detail ?? err?.message ?? 'Nachricht konnte nicht gesendet werden.', description: c.value.contact.form.error.description,
color: 'primary' color: 'primary'
}) })
} }

View File

@ -30,13 +30,14 @@ export interface ContentMatrix {
} }
export interface BusinessInfo { export interface BusinessInfo {
name: Translations, uid: string
operator: Translations, name: Translations
address: Translations, operator: Translations
phone: Translations, address: Translations
email: Translations, phone: Translations
vat: Translations, email: Translations
authority: Translations, vat: Translations
membership: Translations, authority: Translations
membership: Translations
regulation: Translations regulation: Translations
} }