Some checks failed
Deploy / deploy (push) Failing after 38m47s
- Introduced a mechanism to save partially generated responses in case of errors, ensuring users do not lose their input. - Updated the RevizyonKutusu component to utilize a persistent request ID for retrying failed requests without double charging credits. - Improved the Sayfalama component to support client-side pagination without changing the URL, enhancing user navigation. - Added a timeout for AI generation requests to ensure credits are refunded in case of prolonged processing. - Refactored various components for better clarity and responsiveness, including updates to the BolumProgramListesi and ListePaneli components.
127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
import type { Metadata } from "next";
|
||
import { eq } from "drizzle-orm";
|
||
import {
|
||
PUAN_TURLERI,
|
||
rankWindowFacets,
|
||
searchByRank,
|
||
type PuanTuruKey,
|
||
} from "@/lib/db";
|
||
import { getSession, getCurrentUser } from "@/lib/session";
|
||
import { appDb, schema } from "@/lib/appdb";
|
||
import type { RaporSonuc } from "@/lib/ai/rapor";
|
||
import type { RaporParams } from "@/lib/rapor-havuzu";
|
||
import { raporMaskele } from "@/lib/rapor-maske";
|
||
import { SihirbazBolumu } from "./sihirbaz-cagri-karti";
|
||
import type { MevcutRapor } from "./liste-paneli";
|
||
import { ProgramTablosu } from "@/components/program-tablosu";
|
||
import { ManuelHarita } from "@/components/manuel-liste/manuel-harita";
|
||
import { SiteFooter } from "@/components/site-footer";
|
||
import { SiraGerekli } from "./sira-gerekli";
|
||
|
||
// listeOlustur aksiyonu 2 AI denemesi yapabiliyor (deneme başına 50 sn abort
|
||
// sınırı, bkz. lib/ai/cagri.ts); platform limiti AI zaman aşımından SONRA
|
||
// dolmalı ki kredi iadesi her zaman çalışabilsin.
|
||
export const maxDuration = 120;
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Tercih Listeni Kur",
|
||
// Param uzayı sonsuz + içerik sıralamaya göre kişisel: indexlenmez ama
|
||
// link değeri follow ile geri akar. robots.txt'te ENGELLEME — noindex'in
|
||
// görülebilmesi için sayfa taranabilir kalmalı.
|
||
robots: { index: false, follow: true },
|
||
};
|
||
|
||
export default async function SonucPage({
|
||
searchParams,
|
||
}: {
|
||
searchParams: Promise<{
|
||
sira?: string;
|
||
tur?: string;
|
||
sihirbaz?: string;
|
||
acildi?: string;
|
||
hazir?: string;
|
||
}>;
|
||
}) {
|
||
const params = await searchParams;
|
||
const sira = Number.parseInt(params.sira ?? "", 10);
|
||
const turKey: PuanTuruKey =
|
||
params.tur && params.tur in PUAN_TURLERI
|
||
? (params.tur as PuanTuruKey)
|
||
: "say";
|
||
|
||
if (!Number.isFinite(sira) || sira < 1 || sira > 4_000_000) {
|
||
return (
|
||
<>
|
||
<SiraGerekli />
|
||
<SiteFooter />
|
||
</>
|
||
);
|
||
}
|
||
|
||
// Sihirbaz için: kullanıcı durumu, kayıtlı rapor ve dinamik facet'ler.
|
||
// Rapor sorgusu yalnızca session.user.id'ye bağlı — getCurrentUser'ı
|
||
// beklemeden paralel çalışır (seri DB zinciri kurma).
|
||
const session = await getSession();
|
||
const [user, raporSatiri] = session
|
||
? await Promise.all([
|
||
getCurrentUser(),
|
||
appDb.query.reports.findFirst({
|
||
where: eq(schema.reports.userId, session.user.id),
|
||
}),
|
||
])
|
||
: [null, null];
|
||
|
||
const facetler = rankWindowFacets(sira, turKey);
|
||
// Yapay Zeka'sız ham liste: yalnızca sıralamayla ulaşılabilen programlar (dilimli)
|
||
const hamSonuclar = searchByRank(sira, turKey, { limitPerBucket: 20 });
|
||
// Paketsize giden rapor sunucuda maskelenir: blur yalnızca CSS olduğundan
|
||
// kilitli satırların gerçek içeriği client'a hiç inmez.
|
||
const hasPaket = Boolean(user?.hasPaket);
|
||
const mevcutRapor: MevcutRapor | null = raporSatiri?.result
|
||
? {
|
||
rapor: hasPaket
|
||
? (raporSatiri.result as RaporSonuc)
|
||
: raporMaskele(raporSatiri.result as RaporSonuc),
|
||
params: raporSatiri.params as RaporParams,
|
||
revisionCount: raporSatiri.revisionCount,
|
||
}
|
||
: null;
|
||
|
||
return (
|
||
<div className="min-h-screen bg-slate-50 text-slate-900">
|
||
<main className="mx-auto max-w-4xl px-4 py-12">
|
||
{/* Sayfa hiyerarşisi: önce Türkiye haritası, sonra liste. Manuel
|
||
liste store'una abone olduğundan tablodan "+" ile eklenenler
|
||
buraya canlı yansır. */}
|
||
<ManuelHarita />
|
||
|
||
{/* Yapay Zeka'dan bağımsız ham tablo — haritanın hemen altında, sayfanın ana
|
||
gövdesi; puan türü navbar'daki sıralama rozetinden değiştirilir */}
|
||
<ProgramTablosu sonuclar={hamSonuclar} adaySira={sira} tur={turKey} />
|
||
|
||
{/* Sihirbaz akışı (CTA + modal + Yapay Zeka listesi) — blurlu Yapay Zeka paneli
|
||
sayfanın en altında yaşar */}
|
||
<SihirbazBolumu
|
||
sira={sira}
|
||
tur={turKey}
|
||
facetler={facetler}
|
||
girisliMi={Boolean(session)}
|
||
hasPaket={hasPaket}
|
||
kredi={user?.creditBalance ?? 0}
|
||
mevcutRapor={mevcutRapor}
|
||
otomatikAc={params.sihirbaz === "1"}
|
||
acilis={params.acildi === "1"}
|
||
secimlerHazir={params.hazir === "1"}
|
||
/>
|
||
|
||
<p className="mt-10 text-center text-xs leading-relaxed text-slate-500">
|
||
Veriler resmî YÖK Atlas kaynağından derlenmiştir. KolayTercih bir karar
|
||
destek aracıdır; yerleşme garantisi vermez, tercih sorumluluğu adaya
|
||
aittir.
|
||
</p>
|
||
</main>
|
||
<SiteFooter />
|
||
</div>
|
||
);
|
||
}
|