refactor: katalog feature'ı — sayfalar senkron kompozisyona geçti (Faz 2)
- 8 katalog bileşeni src/features/katalog/components/ altına taşındı; katalog-queries.ts (server-only) lib/katalog'un feature kapısı oldu - /bolumler ve /universiteler'in sayfa içi fetch+inline bileşenleri BolumKatalogu/UniversiteKatalogu feature bileşenlerine çıkarıldı - 6 sayfa async'ten senkron'a: params.then() + sayfada Suspense, skeleton'lar feature bileşeninin yanında (BolumIcerikSkeleton vb.) - generateStaticParams artık *-queries yerine bileşen dosyasının helper'larını kullanıyor (bolumStaticSlugs, uniSayfaStaticParams) - Davranış değişikliği yok; route durumları aynı (◐), 1917 statik sayfa Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
135
src/features/katalog/components/universite-program-tablosu.tsx
Normal file
135
src/features/katalog/components/universite-program-tablosu.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import type { Program } from "@/types/yokatlas";
|
||||
import {
|
||||
ProgramSiraGecmisi,
|
||||
ProgramTabanTrendi,
|
||||
programEtkinSira,
|
||||
} from "@/components/program-liste-verileri";
|
||||
import { ProgramEkleButonu } from "@/components/manuel-liste/program-ekle-butonu";
|
||||
import { ProgramNetleriButonu } from "./program-netleri";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
const sayi = (n: number) => n.toLocaleString("tr-TR");
|
||||
|
||||
const TUR_ETIKET: Record<string, string> = {
|
||||
SAYISAL: "SAY",
|
||||
"EŞİT AĞIRLIK": "EA",
|
||||
SÖZEL: "SÖZ",
|
||||
DİL: "DİL",
|
||||
TYT: "TYT",
|
||||
};
|
||||
|
||||
export type UniProgramSatiri = Program & { bolumSlug: string | null };
|
||||
|
||||
export function UniversiteProgramTablosu({
|
||||
gruplar,
|
||||
}: {
|
||||
gruplar: { fakulte: string; programlar: UniProgramSatiri[] }[];
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{gruplar.map(({ fakulte, programlar }, i) => (
|
||||
<section key={`${fakulte}-${i}`} className="mt-6">
|
||||
<h2 className="mb-3 font-heading text-xl font-bold text-slate-900">
|
||||
{fakulte}
|
||||
</h2>
|
||||
<div className="overflow-hidden rounded-2xl border border-slate-200 bg-white">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Program</TableHead>
|
||||
<TableHead className="hidden text-right md:table-cell">
|
||||
Son 5 yıl
|
||||
</TableHead>
|
||||
<TableHead className="hidden text-right lg:table-cell">
|
||||
2025 puan
|
||||
</TableHead>
|
||||
<TableHead className="hidden text-right sm:table-cell">
|
||||
Kontenjan
|
||||
</TableHead>
|
||||
<TableHead className="text-right">Taban sıra</TableHead>
|
||||
<TableHead className="w-24 text-right">
|
||||
<span className="sr-only">Netler ve listeye ekle</span>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{programlar.map((p) => {
|
||||
const taban = programEtkinSira(p);
|
||||
return (
|
||||
<TableRow key={p.id}>
|
||||
<TableCell className="max-w-0 w-full">
|
||||
{p.bolumSlug ? (
|
||||
<Link
|
||||
href={`/bolum/${p.bolumSlug}`}
|
||||
className="block truncate text-sm font-semibold text-slate-900 hover:text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
>
|
||||
{p.isim.trim()}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="block truncate text-sm font-semibold">
|
||||
{p.isim.trim()}
|
||||
</span>
|
||||
)}
|
||||
<span className="mt-0.5 flex items-center gap-1.5 text-xs text-slate-500">
|
||||
<span className="shrink-0 rounded bg-slate-100 px-1 py-px text-[10px] font-medium leading-4 text-slate-600">
|
||||
{TUR_ETIKET[p.tur] ?? p.tur}
|
||||
</span>
|
||||
{p.sure ? (
|
||||
<span className="shrink-0">{p.sure} yıl</span>
|
||||
) : null}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="hidden text-right text-xs md:table-cell">
|
||||
<ProgramSiraGecmisi program={p} />
|
||||
</TableCell>
|
||||
<TableCell className="hidden text-right text-xs tabular-nums text-slate-500 lg:table-cell">
|
||||
{p.puan2025 != null
|
||||
? p.puan2025.toFixed(2).replace(".", ",")
|
||||
: "—"}
|
||||
</TableCell>
|
||||
<TableCell className="hidden text-right text-xs tabular-nums text-slate-500 sm:table-cell">
|
||||
{p.kontenjan2025 != null
|
||||
? `${sayi(p.kontenjan2025)} kişi`
|
||||
: "—"}
|
||||
</TableCell>
|
||||
<TableCell className="text-right text-xs tabular-nums text-slate-500">
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<ProgramTabanTrendi program={p} />
|
||||
{taban != null ? `~${sayi(taban)}.` : "—"}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="pr-3 text-right">
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<ProgramNetleriButonu
|
||||
programId={p.id}
|
||||
isim={p.isim.trim()}
|
||||
className="size-8 min-h-8 min-w-8"
|
||||
/>
|
||||
<ProgramEkleButonu
|
||||
program={p}
|
||||
kaynak="universite"
|
||||
className="size-8 min-h-8 min-w-8"
|
||||
/>
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user