Files
internetlab-test-task/frontend/app/components/ContactForm.vue
2026-06-22 09:31:44 +03:00

201 lines
5.4 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>
<section id="contact" class="py-24 px-4 bg-gray-950">
<div class="max-w-2xl mx-auto">
<div class="section-hidden" ref="sectionRef">
<h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
Связаться
</h2>
<div class="w-16 h-1 bg-indigo-500 mb-10 rounded-full" />
<UCard class="bg-gray-900 border-gray-800">
<div v-if="success" class="space-y-4">
<UAlert
color="success"
variant="soft"
icon="i-heroicons-check-circle"
title="Сообщение отправлено!"
description="Мы получили ваше обращение и свяжемся с вами в ближайшее время."
/>
<UAlert
v-if="aiReply"
color="primary"
variant="soft"
icon="i-heroicons-sparkles"
title="Автоответ от AI"
:description="aiReply"
/>
<UButton
color="neutral"
variant="ghost"
icon="i-heroicons-arrow-left"
@click="handleReset"
>
Отправить ещё
</UButton>
</div>
<form v-else @submit.prevent="handleSubmit" class="space-y-5">
<UAlert
v-if="error"
color="error"
variant="soft"
icon="i-heroicons-exclamation-triangle"
:title="error"
/>
<UFormField
label="Имя"
required
:error="validationErrors.name"
>
<UInput
v-model="form.name"
placeholder="Иван Иванов"
:disabled="loading"
size="lg"
class="w-full"
/>
</UFormField>
<UFormField
label="Телефон"
required
:error="validationErrors.phone"
>
<UInput
v-model="form.phone"
placeholder="+7 999 123-45-67"
type="tel"
:disabled="loading"
size="lg"
class="w-full"
/>
</UFormField>
<UFormField
label="Email"
required
:error="validationErrors.email"
>
<UInput
v-model="form.email"
placeholder="ivan@example.com"
type="email"
:disabled="loading"
size="lg"
class="w-full"
/>
</UFormField>
<UFormField label="Комментарий">
<UTextarea
v-model="form.comment"
placeholder="Расскажите о вашем проекте..."
:disabled="loading"
:rows="4"
class="w-full"
/>
</UFormField>
<UButton
type="submit"
color="primary"
size="lg"
:loading="loading"
:disabled="loading"
icon="i-heroicons-paper-airplane"
class="w-full justify-center"
>
{{ loading ? 'Отправляем...' : 'Отправить' }}
</UButton>
</form>
</UCard>
</div>
</div>
</section>
</template>
<script setup lang="ts">
const sectionRef = ref<HTMLElement | null>(null);
const { loading, error, success, aiReply, submit, reset } = useContact();
const form = reactive({
name: '',
phone: '',
email: '',
comment: '',
});
const validationErrors = reactive({
name: '',
phone: '',
email: '',
});
function validate(): boolean {
validationErrors.name = '';
validationErrors.phone = '';
validationErrors.email = '';
let valid = true;
if (!form.name.trim()) {
validationErrors.name = 'Введите имя';
valid = false;
}
if (!form.phone.trim()) {
validationErrors.phone = 'Введите телефон';
valid = false;
}
else if (!/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/.test(form.phone.replace(/\s/g, ''))) {
validationErrors.phone = 'Некорректный формат телефона';
valid = false;
}
if (!form.email.trim()) {
validationErrors.email = 'Введите email';
valid = false;
}
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) {
validationErrors.email = 'Некорректный email';
valid = false;
}
return valid;
}
async function handleSubmit() {
if (!validate()) return;
await submit({
name: form.name.trim(),
phone: form.phone.trim(),
email: form.email.trim(),
comment: form.comment.trim() || undefined,
});
}
function handleReset() {
reset();
form.name = '';
form.phone = '';
form.email = '';
form.comment = '';
}
onMounted(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.remove('section-hidden');
entry.target.classList.add('section-visible');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 },
);
if (sectionRef.value) observer.observe(sectionRef.value);
});
</script>