Files
kovakyazilim/components/contact-form.tsx
T
Ege Can Komur 3b3efafcc8 Kovak Yazılım kurumsal site — Next.js 16 + Appwrite
- Anasayfa, Hizmetler, Projeler, Hakkımızda, İletişim sayfaları
- Header/Footer, Hero, ServicesGrid, ProjectsGrid, ContactForm bileşenleri
- Appwrite TablesDB entegrasyonu (services, projects, contact_messages)
- Server Action ile iletişim formu (submitContact)
- Brand palette: navy #0F2C5C + sky #4DA3C7
- kovakyazilim.com'dan alınan logo public/logo.png
2026-05-20 01:52:27 +03:00

120 lines
3.5 KiB
TypeScript
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.
"use client";
import { useActionState } from "react";
import { submitContact, type ContactFormState } from "@/app/actions";
import { Send, CheckCircle2, AlertCircle } from "lucide-react";
const initial: ContactFormState = { ok: false, message: "" };
export function ContactForm() {
const [state, formAction, pending] = useActionState(submitContact, initial);
return (
<form action={formAction} className="space-y-5">
<div className="grid gap-5 sm:grid-cols-2">
<Field
label="Ad Soyad"
name="name"
placeholder="Adınız Soyadınız"
error={state.errors?.name}
required
/>
<Field
label="E-posta"
name="email"
type="email"
placeholder="ornek@firma.com"
error={state.errors?.email}
required
/>
<Field
label="Telefon"
name="phone"
placeholder="+90 5xx xxx xx xx"
/>
<Field
label="Konu"
name="subject"
placeholder="Proje türü"
/>
</div>
<div>
<label className="text-sm font-medium text-[var(--navy)]">
Mesajınız <span className="text-red-500">*</span>
</label>
<textarea
name="message"
required
minLength={10}
rows={5}
placeholder="Proje hakkında kısa bir özet paylaşın…"
className="mt-1.5 w-full rounded-xl border border-[var(--border)] bg-white px-4 py-3 text-sm text-[var(--foreground)] outline-none transition placeholder:text-[var(--muted)]/60 focus:border-[var(--sky)] focus:ring-2 focus:ring-[var(--sky)]/20"
/>
{state.errors?.message && (
<p className="mt-1 text-xs text-red-500">{state.errors.message}</p>
)}
</div>
<button
type="submit"
disabled={pending}
className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-[var(--navy)] px-6 py-3 text-sm font-medium text-white transition hover:bg-[var(--navy-700)] disabled:opacity-60 sm:w-auto"
>
{pending ? "Gönderiliyor…" : "Mesaj Gönder"}
<Send className="size-4" />
</button>
{state.message && (
<div
className={`flex items-start gap-3 rounded-xl border p-4 text-sm ${
state.ok
? "border-green-200 bg-green-50 text-green-800"
: "border-red-200 bg-red-50 text-red-800"
}`}
>
{state.ok ? (
<CheckCircle2 className="mt-0.5 size-5 shrink-0" />
) : (
<AlertCircle className="mt-0.5 size-5 shrink-0" />
)}
<span>{state.message}</span>
</div>
)}
</form>
);
}
function Field({
label,
name,
type = "text",
placeholder,
error,
required,
}: {
label: string;
name: string;
type?: string;
placeholder?: string;
error?: string;
required?: boolean;
}) {
return (
<div>
<label className="text-sm font-medium text-[var(--navy)]">
{label}
{required && <span className="text-red-500"> *</span>}
</label>
<input
name={name}
type={type}
required={required}
placeholder={placeholder}
className="mt-1.5 w-full rounded-xl border border-[var(--border)] bg-white px-4 py-3 text-sm text-[var(--foreground)] outline-none transition placeholder:text-[var(--muted)]/60 focus:border-[var(--sky)] focus:ring-2 focus:ring-[var(--sky)]/20"
/>
{error && <p className="mt-1 text-xs text-red-500">{error}</p>}
</div>
);
}