refactor: rapor feature'ı — listem, yazdır, sohbet ve actions taşındı (Faz 8)
- app/sonuc/actions.ts → features/rapor/rapor-actions.ts birebir taşındı (kredi harcama/iade idempotency yolları bayt bayt aynı, yalnızca import yolları değişti); liste-uretici/revizyon-kutusu action'ı doğrudan import ediyor - lib/rapor-kaydi.ts rapor-queries.ts'e emildi: kullanicininRaporu aynı tek okuma kapısı; listem sayfasındaki inline drizzle sorgusu sohbetGecmisiGetir oldu; tadimlikSec re-export'u eklendi - listem-govde, sohbet-client, revizyon-kutusu, liste-uretici, listem-bos-cta, rapor-listesi, tadimlik-satiri, yazdir-butonu features/rapor/components/'a - Yeni async ListemIcerik (verifySession + maskeleme + bosDurum dalı içeride; çift await searchParams kalktı) ve RaporYazdir (3 redirect + yazdırılabilir belge); skeleton'lar eski loading.tsx geometrileriyle aynı dosyada - /listem ve /rapor/yazdir senkron: searchParams.then() + sayfada Suspense; maxDuration=300 ve metadata sayfada kaldı; iki loading.tsx silindi - Davranış değişikliği yok; /api/soru el değmedi Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
// /rapor/yazdir rapor sorgusunu bekler — belge düzeninde iskelet.
|
||||
export default function Loading() {
|
||||
return (
|
||||
<main
|
||||
aria-live="polite"
|
||||
className="mx-auto w-full max-w-3xl bg-white p-8"
|
||||
>
|
||||
<div className="border-b-2 border-slate-200 pb-4">
|
||||
<Skeleton className="h-8 w-64" />
|
||||
<Skeleton className="mt-2 h-4 w-40" />
|
||||
</div>
|
||||
<div className="mt-6 space-y-3">
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-14 w-full rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,142 +1,19 @@
|
||||
import { Suspense } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import Image from "next/image";
|
||||
import { redirect } from "next/navigation";
|
||||
import { verifySession, getCurrentUser } from "@/lib/session";
|
||||
import { kullanicininRaporu } from "@/lib/rapor-kaydi";
|
||||
import { PUAN_TURLERI } from "@/types/yokatlas";
|
||||
import type { RaporSonuc } from "@/features/rapor/types/rapor";
|
||||
import type { RaporParams } from "@/features/rapor/types/rapor";
|
||||
import { YazdirButonu } from "./yazdir-butonu";
|
||||
import {
|
||||
RaporYazdir,
|
||||
RaporYazdirSkeleton,
|
||||
} from "@/features/rapor/components/rapor-yazdir";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Tercih Raporu (Yazdır)",
|
||||
robots: { index: false, follow: false },
|
||||
};
|
||||
|
||||
const DILIM_LABEL: Record<string, string> = {
|
||||
hayal: "Hayal (Riskli)",
|
||||
dengeli: "Dengeli (Az riskli)",
|
||||
garanti: "Garanti (Güvenli)",
|
||||
};
|
||||
|
||||
export default async function YazdirPage() {
|
||||
const session = await verifySession("/rapor/yazdir");
|
||||
// Kullanıcı satırı ile rapor sorgusu bağımsız — paralel çöz
|
||||
const [user, satir] = await Promise.all([
|
||||
getCurrentUser(),
|
||||
kullanicininRaporu(session.user.id),
|
||||
]);
|
||||
if (!user) redirect("/giris");
|
||||
if (!user.hasPaket) redirect("/paket");
|
||||
if (!satir?.result) redirect("/sonuc");
|
||||
|
||||
const rapor = satir.result as RaporSonuc;
|
||||
const params = satir.params as RaporParams;
|
||||
const tarih = new Date(satir.updatedAt).toLocaleDateString("tr-TR", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
export default function YazdirPage() {
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl bg-white p-8 text-slate-900 print:p-[10mm]">
|
||||
<YazdirButonu />
|
||||
|
||||
<header className="border-b-2 border-slate-900 pb-4">
|
||||
<h1 className="font-heading text-2xl font-bold">
|
||||
{rapor.tercihler.length} Tercihlik Kişisel Liste ve Risk Raporu
|
||||
</h1>
|
||||
<p className="mt-1 text-sm text-slate-600">
|
||||
Başarı sıralaması: {params.sira.toLocaleString("tr-TR")} · Puan
|
||||
türü: {PUAN_TURLERI[params.tur]}
|
||||
{params.il ? ` · İl: ${params.il}` : ""} · {tarih}
|
||||
</p>
|
||||
{rapor.kapsam?.uyarlandi ? (
|
||||
<p className="mt-1 text-sm text-slate-600">
|
||||
Not: Tercihlerine göre {rapor.kapsam.toplam} uygun program bulundu;
|
||||
liste {rapor.kapsam.dagilim.hayal} hayal ·{" "}
|
||||
{rapor.kapsam.dagilim.dengeli} dengeli ·{" "}
|
||||
{rapor.kapsam.dagilim.garanti} garanti olarak kuruldu.
|
||||
</p>
|
||||
) : null}
|
||||
</header>
|
||||
|
||||
<section className="mt-5">
|
||||
<h2 className="font-heading text-base font-bold">
|
||||
Genel değerlendirme
|
||||
</h2>
|
||||
<p className="mt-1 whitespace-pre-line text-sm leading-relaxed">
|
||||
{rapor.genelDegerlendirme}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<table className="mt-5 w-full border-collapse text-xs">
|
||||
<thead>
|
||||
<tr className="border-b-2 border-slate-900 text-left">
|
||||
<th className="py-2 pr-2">#</th>
|
||||
<th className="py-2 pr-2">Program / Üniversite</th>
|
||||
<th className="py-2 pr-2">Dilim</th>
|
||||
<th className="py-2 pr-2">Gerekçe</th>
|
||||
<th className="py-2 pr-2">Risk notu</th>
|
||||
<th className="py-2">Trend</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rapor.tercihler.map((t) => {
|
||||
const p = rapor.programlar[t.programId];
|
||||
return (
|
||||
<tr
|
||||
key={t.sira}
|
||||
className="break-inside-avoid border-b border-slate-200 align-top"
|
||||
>
|
||||
<td className="py-2 pr-2 font-bold">{t.sira}</td>
|
||||
<td className="py-2 pr-2">
|
||||
<span className="font-semibold">{p?.isim}</span>
|
||||
<br />
|
||||
<span className="text-slate-600">
|
||||
{p?.universite} · {p?.il ?? "—"}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-2 pr-2">{DILIM_LABEL[t.dilim]}</td>
|
||||
<td className="py-2 pr-2">{t.gerekce}</td>
|
||||
<td className="py-2 pr-2">{t.riskNotu}</td>
|
||||
<td className="py-2">{t.trendOzeti}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<footer className="mt-6 border-t border-slate-300 pt-3 text-[10px] leading-relaxed text-slate-500">
|
||||
<p>
|
||||
Bu rapor KolayTercih tarafından resmî YÖK Atlas verisi (2021–2025
|
||||
taban sıralamaları, kontenjan ve yerleşme istatistikleri) kullanılarak
|
||||
üretilmiştir. Taban sıralamaları her yıl değişir; bu rapor yerleşme
|
||||
garantisi vermez. Tercih listesinin ÖSYM sistemine girilmesi ve nihai
|
||||
sorumluluğu adaya aittir.
|
||||
</p>
|
||||
<div className="mt-4 flex break-inside-avoid items-center justify-between">
|
||||
<div className="flex items-center font-bricolage text-slate-900">
|
||||
<Image
|
||||
src="/kolay-tercih-mark.svg"
|
||||
alt=""
|
||||
width={44}
|
||||
height={44}
|
||||
aria-hidden="true"
|
||||
className="size-11 shrink-0"
|
||||
/>
|
||||
<span>
|
||||
<span className="font-light text-3xl tracking-tighter">Kolay</span>
|
||||
<span className="font-semibold text-3xl tracking-tighter">
|
||||
Tercih
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span className="font-bricolage text-sm font-medium text-slate-900">
|
||||
kolaytercih.com
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<Suspense fallback={<RaporYazdirSkeleton />}>
|
||||
<RaporYazdir />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Printer } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export function YazdirButonu() {
|
||||
return (
|
||||
<div className="mb-6 flex items-center justify-between rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 print:hidden">
|
||||
<p className="text-sm text-slate-600">
|
||||
"PDF olarak kaydet" seçeneğiyle raporu indirebilir veya
|
||||
yazdırabilirsin.
|
||||
</p>
|
||||
<Button
|
||||
onClick={() => window.print()}
|
||||
className="cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
||||
>
|
||||
<Printer className="size-4" aria-hidden />
|
||||
Yazdır / PDF kaydet
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user