Files
kolaytercih/src/features/rapor/components/revizyon-kutusu.tsx
bilalgursen fbd184e2be 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>
2026-08-08 01:39:33 +03:00

101 lines
3.5 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.
"use client";
// Paketlinin geri bildirime dayalı liste revizyonu (/listem üzerinde).
// listeRevize sunucu aksiyonunu çağırır; başarıda sayfayı yeniler ki
// sunucuda güncellenen rapor ve kredi bakiyesi ekrana yansısın.
import { useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { RefreshCcw } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { listeRevize } from "@/features/rapor/rapor-actions";
import { olay } from "@/lib/analitik";
export function RevizyonKutusu({ kalanHak }: { kalanHak: number }) {
const [feedback, setFeedback] = useState("");
const [pending, setPending] = useState(false);
const router = useRouter();
// Aynı deneme için sabit requestId: cevap kaybolan network hatasında retry
// çifte harcamaz. Sunucudan cevap gelince sıfırlanır (harcama ya tamamlandı
// ya iade edildi; sonraki deneme taze id ile başlamalı — bkz. sonuc/actions.ts).
const requestIdRef = useRef<string | null>(null);
if (kalanHak <= 0) {
return (
<section
id="revizyon"
className="scroll-mt-24 rounded-2xl border border-slate-200 bg-white p-5"
>
<p className="text-sm text-slate-500">
Revizyon hakların doldu. Danışman sohbetinden listen hakkında soru
sormaya devam edebilirsin.
</p>
</section>
);
}
async function revizeEt() {
setPending(true);
try {
if (!requestIdRef.current) requestIdRef.current = crypto.randomUUID();
const sonuc = await listeRevize({
feedback: feedback.trim(),
requestId: requestIdRef.current,
});
requestIdRef.current = null;
if (sonuc.ok) {
olay("liste_revize", { sayfa: "listem" });
toast.success("Listen yeniden kuruldu.");
setFeedback("");
router.refresh();
} else {
toast.error(sonuc.error);
}
} catch {
toast.error("Beklenmeyen bir hata oluştu, tekrar dener misin?");
} finally {
setPending(false);
}
}
return (
<section
id="revizyon"
className="scroll-mt-24 rounded-2xl border border-slate-200 bg-white p-5"
>
<h2 className="font-heading text-base font-bold">
Listede değişiklik mi istiyorsun?
</h2>
<p className="mb-3 mt-1 text-sm text-slate-600">
Ne değişsin istediğini yaz; liste aynı gerçek veriyle yeniden kurulsun
(3 kredi).
</p>
<textarea
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
rows={2}
maxLength={1000}
placeholder="ör. İlk 5 tercihte daha fazla İstanbul olsun, garanti dilimini genişlet…"
disabled={pending}
className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
/>
<div className="mt-3 flex items-center gap-3">
<Button
type="button"
variant="outline"
disabled={pending || feedback.trim().length < 5}
onClick={revizeEt}
className="cursor-pointer"
>
<RefreshCcw className="size-4" aria-hidden />
{pending ? "Yeniden kuruluyor…" : "Revize et (3 kredi)"}
</Button>
<span className="text-xs text-slate-500">
Kalan hak: <span className="font-semibold">{kalanHak}</span>
</span>
</div>
</section>
);
}