3b3efafcc8
- 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
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
"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>
|
||
);
|
||
}
|