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
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user