Files
kovakyazilim/app/(site)/sektor/[slug]/page.tsx
T
Ege Can Komur cf46e30a7e feat: TR rakip analizi → satış blokerleri düzeltildi
Rakip analizi (kocaelidijital.com, promedyanet.com, lf.com.tr) sonrası
satış blokerleri tespit edildi ve aşağıdaki bölümler eklendi:

1. ANASAYFADA SSS (8 hazır soru, admin'den düzenlenebilir)
   - Fiyat, süre, ödeme, garanti, hosting, SEO, mevcut site yenileme,
     sadece tasarım hizmeti gibi en sık sorulan sorular
   - HomepageFaq component (sticky sol + accordion sağ)
   - site_settings.homepage_faq[] (JSON {q,a})

2. RISK REVERSAL bölümü (Guarantee component)
   - 'İlk taslak ücretsiz, memnun değilseniz devam etmiyoruz'
   - 4 garanti maddesi checklist
   - site_settings.guarantee_title/description/items

3. PROJE METRİKLERİ (vaka çalışması güçlendirme)
   - projects.metrics[] (JSON {value,label})
   - Detay sayfada büyük metric kartları
   - Admin formda 'değer | etiket' satır formatı

4. HERO COPY GÜNCELLEMESİ (admin'den düzenlenebilir)
   - 'Kocaeli'de 2-3 hafta içinde yayında olan, satan kurumsal web siteleri'
   - 'İlk tasarım taslakı ücretsiz' vurgusu
   - Trust band: 30 dk yanıt + ücretsiz taslak + 4.9 memnuniyet

5. /SITE-ANALIZI LEAD MAGNET SAYFASI
   - URL + ad + email + telefon formu
   - 6 analiz başlığı (CWV, mobil, SEO, güvenlik, içerik, rakip)
   - contact_messages'a source=quick-site-audit ile yazılır
   - 'subject' alanı ile inbox'ta ayırt edilebilir

6. EKİP BÖLÜMÜ (Hakkımızda sayfasında)
   - Yeni team_members tablosu (name, role, bio, photo, linkedin)
   - /admin/ekip CRUD sayfası
   - TeamGrid component

7. SEKTÖR LANDING SAYFALARI (/sektor/[slug])
   - Yeni industries tablosu (slug, title, content, features, faq, SEO)
   - /admin/sektorler CRUD sayfası
   - SEO + ad-targeted landing template
   - Hero + trust + features + content + garanti + projeler + hizmetler + FAQ + JSON-LD

Admin /admin/site formuna yeni bölümler:
- 'Risk reversal / Garanti' (title + description + items)
- 'Anasayfa SSS' (---' bloklarla)

App sidebar'a 'Sektörler' ve 'Ekip' linkleri eklendi.
Footer'a 'Ücretsiz Site Analizi' linki eklendi.

36 route üretiliyor (önceki 31'den +5: /site-analizi, /sektor/[slug],
/admin/ekip + alt, /admin/sektorler + alt).
2026-05-20 04:03:21 +03:00

211 lines
7.2 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.
import Image from "next/image";
import Link from "next/link";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { ArrowRight, ArrowLeft, CheckCircle2 } from "lucide-react";
import { marked } from "marked";
import {
getIndustryBySlug,
listProjects,
listServices,
getSiteSettings,
} from "@/lib/data";
import { buildMetadata } from "@/lib/seo";
import { ProjectsGrid } from "@/components/projects-grid";
import { ServicesGrid } from "@/components/services-grid";
import { TrustBand } from "@/components/trust-band";
import { Guarantee } from "@/components/guarantee";
import { QuickLeadForm } from "@/components/quick-lead-form";
import { FaqList } from "@/components/faq-list";
import { FaqLd } from "@/components/json-ld";
import { SectionTitle } from "@/components/section-title";
import type { FaqItem } from "@/lib/types";
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const industry = await getIndustryBySlug(slug);
if (!industry) return { title: "Sektör bulunamadı" };
return buildMetadata(`/sektor/${slug}`, {
title: industry.seo_title || industry.title,
description: industry.seo_description || industry.subtitle || undefined,
});
}
function parseFaq(items?: string[] | null): FaqItem[] {
if (!items) return [];
const out: FaqItem[] = [];
for (const raw of items) {
try {
const obj = JSON.parse(raw) as Partial<FaqItem>;
if (obj.q && obj.a) out.push({ q: obj.q, a: obj.a });
} catch {
/* ignore */
}
}
return out;
}
export default async function IndustryPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const industry = await getIndustryBySlug(slug);
if (!industry) notFound();
const [services, projects, settings] = await Promise.all([
listServices(),
listProjects({ limit: 6 }),
getSiteSettings(),
]);
const faqItems = parseFaq(industry.faq);
const html = industry.content
? (marked.parse(industry.content, { async: false }) as string)
: "";
return (
<>
<FaqLd items={faqItems} />
<section className="relative overflow-hidden border-b border-[var(--border)]">
<div className="absolute inset-0 hero-grid opacity-50" aria-hidden />
<div className="relative mx-auto max-w-7xl px-6 py-20">
<Link
href="/"
className="inline-flex items-center gap-1 text-sm text-[var(--muted)] hover:text-[var(--navy)]"
>
<ArrowLeft className="size-3.5" /> Anasayfa
</Link>
<div className="mt-6 grid items-center gap-12 lg:grid-cols-[1.2fr_1fr]">
<div>
<span className="inline-flex items-center gap-2 rounded-full border border-[var(--sky)]/30 bg-[var(--sky-50)] px-3 py-1 text-xs font-medium text-[var(--sky-600)]">
Sektöre özel çözüm
</span>
<h1 className="mt-5 text-4xl font-bold leading-tight tracking-tight text-[var(--navy)] sm:text-5xl">
{industry.title}
</h1>
{industry.subtitle && (
<p className="mt-5 max-w-xl text-lg leading-relaxed text-[var(--muted)]">
{industry.subtitle}
</p>
)}
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<Link
href="/iletisim"
className="inline-flex items-center justify-center gap-2 rounded-full bg-[var(--navy)] px-6 py-3 text-sm font-semibold text-white transition hover:bg-[var(--navy-700)]"
>
Ücretsiz keşif görüşmesi
<ArrowRight className="size-4" />
</Link>
<Link
href="/site-analizi"
className="inline-flex items-center justify-center gap-2 rounded-full border border-[var(--border)] bg-white px-6 py-3 text-sm font-medium text-[var(--navy)] transition hover:border-[var(--navy)]"
>
Ücretsiz site analizi
</Link>
</div>
</div>
<div className="lg:pl-6">
<QuickLeadForm
title="Sektörünüze özel teklif"
description="Adınızı ve telefonunuzu bırakın, sektör uzmanımız 30 dakika içinde sizi arasın."
buttonLabel="Beni hemen arayın"
/>
</div>
</div>
</div>
</section>
<TrustBand settings={settings} />
{industry.features && industry.features.length > 0 && (
<section className="border-b border-[var(--border)] py-20">
<div className="mx-auto max-w-7xl px-6">
<SectionTitle
eyebrow="Neler dahil?"
title="Sektörünüze uygun, hazır çözümler"
description={`${industry.title} alanında deneyimimizle geliştirdiğimiz fonksiyonlar.`}
/>
<ul className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{industry.features.map((f) => (
<li
key={f}
className="flex items-start gap-2 rounded-2xl border border-[var(--border)] bg-white p-5"
>
<CheckCircle2 className="mt-0.5 size-5 shrink-0 text-[var(--sky-600)]" />
<span className="text-sm text-[var(--foreground)]">{f}</span>
</li>
))}
</ul>
</div>
</section>
)}
{html && (
<section className="py-16">
<div className="mx-auto max-w-3xl px-6">
<article
className="prose prose-lg max-w-none text-[var(--foreground)]"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
</section>
)}
<Guarantee settings={settings} />
{projects.length > 0 && (
<section className="border-y border-[var(--border)] py-20">
<div className="mx-auto max-w-7xl px-6">
<SectionTitle
eyebrow="Referanslar"
title="Benzer projelerimiz"
description="Sektörünüz veya benzer alanlarda tamamladığımız işler."
/>
<div className="mt-12">
<ProjectsGrid projects={projects} />
</div>
</div>
</section>
)}
{services.length > 0 && (
<section className="py-20">
<div className="mx-auto max-w-7xl px-6">
<SectionTitle
eyebrow="Hizmetler"
title="Sunduğumuz çözümler"
description="Sektörünüze uygun hizmet paketlerimiz."
/>
<div className="mt-12">
<ServicesGrid services={services} />
</div>
</div>
</section>
)}
{faqItems.length > 0 && (
<section className="border-t border-[var(--border)] py-20">
<div className="mx-auto grid max-w-6xl gap-12 px-6 lg:grid-cols-[1fr_2fr]">
<SectionTitle
align="left"
eyebrow="SSS"
title={`${industry.title} sektörü soruları`}
/>
<FaqList items={faqItems} />
</div>
</section>
)}
</>
);
}