refactor: remove TercihDegistiUyarisi component
Deleted the TercihDegistiUyarisi component from the project. This component was responsible for notifying users about changes in their preferences and suggesting a list update. The removal is part of a broader effort to streamline the codebase and improve maintainability.
This commit is contained in:
@@ -1,302 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
// /listem'deki "tercihlerin değişti" uyarısı: kayıtlı liste hangi tercihlerle
|
|
||||||
// kurulduysa (rapor params) kullanıcının güncel profili ondan ayrıldığında
|
|
||||||
// belirir ve listeyi yeni tercihlere göre yeniden kurmayı önerir.
|
|
||||||
//
|
|
||||||
// Yeniden kurulum normal üretimle AYNI kapıdan geçer (listeOlustur): 3 kredi,
|
|
||||||
// aynı requestId idempotency'si, aynı kredi-yetersiz/iade davranışı. Ayrı bir
|
|
||||||
// "güncelleme" ürünü ya da indirimli yol yok — kullanıcı yeni bir liste alıyor,
|
|
||||||
// bedeli de yeni liste bedeli.
|
|
||||||
//
|
|
||||||
// Uyarı kapatılabilir: kapatma kararı o anki profil imzasına yazılır, tercih
|
|
||||||
// yeniden değişirse uyarı geri gelir (bkz. profilImzasi).
|
|
||||||
|
|
||||||
import { useMemo, useRef, useState } from "react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { ArrowRight, Check, RefreshCcw, SlidersHorizontal, X } from "lucide-react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { olay, siraKovasi } from "@/lib/analitik";
|
|
||||||
import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili";
|
|
||||||
import { listeOlustur } from "@/features/rapor/rapor-actions";
|
|
||||||
import type { RaporParams } from "@/features/rapor/types/rapor";
|
|
||||||
import {
|
|
||||||
farkCumlesi,
|
|
||||||
farkSatirlari,
|
|
||||||
profilImzasi,
|
|
||||||
tercihFarki,
|
|
||||||
} from "@/features/rapor/tercih-farki";
|
|
||||||
import { useUretimMesaji } from "./uretim-mesaji";
|
|
||||||
|
|
||||||
const GIZLE_ANAHTARI = "kolaytercih.listem-fark-gizle";
|
|
||||||
|
|
||||||
function gizlenenImzayiOku(): string | null {
|
|
||||||
if (typeof window === "undefined") return null;
|
|
||||||
try {
|
|
||||||
return localStorage.getItem(GIZLE_ANAHTARI);
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Durum =
|
|
||||||
| { ad: "bekliyor" }
|
|
||||||
| { ad: "uretiliyor" }
|
|
||||||
| { ad: "tamamlandi" }
|
|
||||||
| { ad: "kredi-yetersiz" }
|
|
||||||
| { ad: "hata"; mesaj: string };
|
|
||||||
|
|
||||||
export function TercihDegistiUyarisi({
|
|
||||||
params,
|
|
||||||
kredi,
|
|
||||||
raporKredi,
|
|
||||||
hasPaket,
|
|
||||||
}: {
|
|
||||||
/** Kayıtlı listenin üretildiği tercihler */
|
|
||||||
params: RaporParams;
|
|
||||||
kredi: number;
|
|
||||||
raporKredi: number;
|
|
||||||
hasPaket: boolean;
|
|
||||||
}) {
|
|
||||||
const router = useRouter();
|
|
||||||
const profil = useTercihProfili();
|
|
||||||
const [durum, setDurum] = useState<Durum>({ ad: "bekliyor" });
|
|
||||||
// Profil client'ta çözüldüğü için bu bileşen SSR'da zaten hiçbir şey
|
|
||||||
// render etmiyor; gizleme kaydı ilk render'da güvenle okunabilir.
|
|
||||||
const [gizlenenImza, setGizlenenImza] = useState<string | null>(
|
|
||||||
gizlenenImzayiOku,
|
|
||||||
);
|
|
||||||
// Aynı deneme için sabit requestId: cevabı kaybolan istekte retry çifte
|
|
||||||
// harcamaz (bkz. liste-uretici.tsx ve spendCredits idempotency'si).
|
|
||||||
const requestIdRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
const farklar = useMemo(
|
|
||||||
() => (profil ? tercihFarki(params, profil) : []),
|
|
||||||
[params, profil],
|
|
||||||
);
|
|
||||||
const satirlar = useMemo(
|
|
||||||
() => (profil ? farkSatirlari(params, profil, farklar) : []),
|
|
||||||
[params, profil, farklar],
|
|
||||||
);
|
|
||||||
|
|
||||||
async function guncelle() {
|
|
||||||
if (!profil) return;
|
|
||||||
if (!requestIdRef.current) requestIdRef.current = crypto.randomUUID();
|
|
||||||
setDurum({ ad: "uretiliyor" });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const sonuc = await listeOlustur({
|
|
||||||
sira: profil.sira,
|
|
||||||
tur: profil.tur,
|
|
||||||
secimler: profil.secimler,
|
|
||||||
requestId: requestIdRef.current,
|
|
||||||
});
|
|
||||||
requestIdRef.current = null;
|
|
||||||
if (sonuc.ok) {
|
|
||||||
olay("liste_guncellendi", {
|
|
||||||
tur: profil.tur,
|
|
||||||
sira_kovasi: siraKovasi(profil.sira),
|
|
||||||
degisen_alan: farklar.length,
|
|
||||||
});
|
|
||||||
toast.success("Listen yeni tercihlerine göre yeniden kuruldu.");
|
|
||||||
// Sunucu params'ı tazelenince fark kalmaz ve uyarı kendiliğinden
|
|
||||||
// kaybolur; refresh dönene kadar "güncellendi" hâli görünür.
|
|
||||||
setDurum({ ad: "tamamlandi" });
|
|
||||||
router.refresh();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sonuc.code === "KREDI" || sonuc.code === "PAKET") {
|
|
||||||
olay("kredi_bitti");
|
|
||||||
setDurum({ ad: "kredi-yetersiz" });
|
|
||||||
} else if (sonuc.code === "AUTH") {
|
|
||||||
router.push(`/giris?callback=${encodeURIComponent("/listem")}`);
|
|
||||||
} else {
|
|
||||||
setDurum({ ad: "hata", mesaj: sonuc.error });
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setDurum({
|
|
||||||
ad: "hata",
|
|
||||||
mesaj: "Beklenmeyen bir hata oluştu, tekrar dener misin?",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function gizle() {
|
|
||||||
if (!profil) return;
|
|
||||||
const imza = profilImzasi(profil);
|
|
||||||
try {
|
|
||||||
localStorage.setItem(GIZLE_ANAHTARI, imza);
|
|
||||||
} catch {}
|
|
||||||
setGizlenenImza(imza);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!profil || farklar.length === 0) return null;
|
|
||||||
if (durum.ad === "tamamlandi") {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
role="status"
|
|
||||||
className="mb-6 flex items-center gap-3 rounded-2xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm font-medium text-emerald-800"
|
|
||||||
>
|
|
||||||
<Check className="size-4 shrink-0" aria-hidden />
|
|
||||||
Listen yeni tercihlerine göre güncellendi.
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Kapatılmış değişiklik: kullanıcı aynı tercihlerle bir daha rahatsız
|
|
||||||
// edilmez. Üretim/hata hâlleri kapatmadan bağımsız görünür kalır.
|
|
||||||
if (durum.ad === "bekliyor" && gizlenenImza === profilImzasi(profil)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const krediYeter = kredi >= raporKredi;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
aria-live="polite"
|
|
||||||
className="mb-6 rounded-2xl border border-amber-200 bg-amber-50 p-4 sm:p-5"
|
|
||||||
>
|
|
||||||
<div className="flex items-start gap-3">
|
|
||||||
<span className="flex size-9 shrink-0 items-center justify-center rounded-full bg-amber-100 text-amber-700">
|
|
||||||
<SlidersHorizontal className="size-4" aria-hidden />
|
|
||||||
</span>
|
|
||||||
<div className="min-w-0 flex-1">
|
|
||||||
<h2 className="font-heading font-bold text-amber-900">
|
|
||||||
Tercihlerin değişti
|
|
||||||
</h2>
|
|
||||||
<p className="mt-1 text-sm text-amber-900/80">
|
|
||||||
Aşağıdaki liste eski tercihlerinle kuruldu; {farkCumlesi(farklar)}{" "}
|
|
||||||
o zamandan beri değişti. Yeni tercihlerine göre yeniden kurabilirsin
|
|
||||||
— yeni liste bunun yerine geçer ve {raporKredi} kredi düşer.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<dl className="mt-3 flex flex-col gap-1.5 text-sm">
|
|
||||||
{satirlar.map((satir) => (
|
|
||||||
<div
|
|
||||||
key={satir.alan}
|
|
||||||
className="flex flex-col gap-0.5 sm:flex-row sm:items-baseline sm:gap-2"
|
|
||||||
>
|
|
||||||
<dt className="shrink-0 text-xs font-medium uppercase tracking-wide text-amber-700">
|
|
||||||
{satir.etiket}
|
|
||||||
</dt>
|
|
||||||
<dd className="min-w-0 text-amber-900">
|
|
||||||
<span className="text-amber-900/60">{satir.eski}</span>
|
|
||||||
<span className="px-1.5 text-amber-700" aria-label="yerine">
|
|
||||||
→
|
|
||||||
</span>
|
|
||||||
<span className="font-semibold">{satir.yeni}</span>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
{durum.ad === "uretiliyor" ? (
|
|
||||||
<UretimSatiri />
|
|
||||||
) : durum.ad === "kredi-yetersiz" ? (
|
|
||||||
<KrediYetersiz hasPaket={hasPaket} raporKredi={raporKredi} />
|
|
||||||
) : (
|
|
||||||
<div className="mt-4 flex flex-wrap items-center gap-3">
|
|
||||||
{durum.ad === "hata" ? (
|
|
||||||
<>
|
|
||||||
<p className="w-full text-sm text-red-700">{durum.mesaj}</p>
|
|
||||||
<Button
|
|
||||||
onClick={() => void guncelle()}
|
|
||||||
className="cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
|
||||||
>
|
|
||||||
<RefreshCcw className="size-4" aria-hidden />
|
|
||||||
Tekrar dene
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : krediYeter ? (
|
|
||||||
<Button
|
|
||||||
onClick={() => void guncelle()}
|
|
||||||
className="cursor-pointer bg-orange-500 text-white transition-[background-color,transform] duration-200 active:scale-[0.97] hover:bg-orange-600"
|
|
||||||
>
|
|
||||||
Listemi güncelle — {raporKredi} kredi
|
|
||||||
<ArrowRight className="size-4" aria-hidden />
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
asChild
|
|
||||||
className="cursor-pointer bg-orange-500 text-white transition-[background-color,transform] duration-200 active:scale-[0.97] hover:bg-orange-600"
|
|
||||||
>
|
|
||||||
<Link href="/paket">
|
|
||||||
{hasPaket ? "Kredi yükle ve güncelle" : "Paketi aktive et"}
|
|
||||||
<ArrowRight className="size-4" aria-hidden />
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={gizle}
|
|
||||||
className="cursor-pointer text-sm font-medium text-amber-800 underline underline-offset-2 transition-colors hover:text-amber-900"
|
|
||||||
>
|
|
||||||
Şimdilik kalsın
|
|
||||||
</button>
|
|
||||||
{!krediYeter && durum.ad !== "hata" ? (
|
|
||||||
<p className="w-full text-xs text-amber-900/70">
|
|
||||||
Güncelleme {raporKredi} kredi; bakiyen {kredi} kredi.
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{durum.ad === "bekliyor" ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={gizle}
|
|
||||||
className="flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full border border-amber-200 text-amber-800 transition-colors duration-200 active:scale-[0.96] hover:bg-amber-100"
|
|
||||||
>
|
|
||||||
<X className="size-4" aria-hidden />
|
|
||||||
<span className="sr-only">Uyarıyı kapat</span>
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function UretimSatiri() {
|
|
||||||
const mesaj = useUretimMesaji();
|
|
||||||
return (
|
|
||||||
<div className="mt-4 flex flex-col gap-1">
|
|
||||||
<p className="flex items-center gap-2 text-sm font-medium text-amber-900">
|
|
||||||
<RefreshCcw className="size-4 animate-spin" aria-hidden />
|
|
||||||
Listen yeni tercihlerine göre kuruluyor…
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-amber-900/70">{mesaj}</p>
|
|
||||||
<p className="text-xs text-amber-900/60">
|
|
||||||
Bu işlem yarım dakika kadar sürebilir, sayfayı kapatma.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function KrediYetersiz({
|
|
||||||
hasPaket,
|
|
||||||
raporKredi,
|
|
||||||
}: {
|
|
||||||
hasPaket: boolean;
|
|
||||||
raporKredi: number;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="mt-4 flex flex-wrap items-center gap-3">
|
|
||||||
<p className="w-full text-sm text-amber-900">
|
|
||||||
{hasPaket
|
|
||||||
? `Güncelleme ${raporKredi} kredi ve bakiyen yetmedi. Kredi yüklediğinde listen ve sohbet geçmişin duruyor, kaldığın yerden devam edersin.`
|
|
||||||
: `Güncelleme ${raporKredi} kredi ve bakiyen yetmedi. Tercih Dönemi Paketi'yle kredilerin, tam liste, PDF ve revizyon hakları birlikte gelir.`}
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
asChild
|
|
||||||
className="cursor-pointer bg-orange-500 text-white transition-colors duration-200 hover:bg-orange-600"
|
|
||||||
>
|
|
||||||
<Link href="/paket">
|
|
||||||
{hasPaket ? "Kredi yükle" : "Paketi aktive et"}
|
|
||||||
<ArrowRight className="size-4" aria-hidden />
|
|
||||||
</Link>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user