- tercihFarki eski 'İş garantisi' parametresini yeni ada eşleyerek kıyaslar; ad değişikliği 3 kredilik güncelleme çağrısı üretmesin - çekmece kartı yalnız profil yokken sıra ister, butonu sıra kapısını açar (profilsiz ziyaretçi /listem giriş duvarına gönderilmiyordu → çıkmaz) - sunucuylaBirlestir risksiz gelen kayıtların riskini doldurur - /paket'teki fiyat kıyasına kaynak satırı Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
118 lines
3.9 KiB
TypeScript
118 lines
3.9 KiB
TypeScript
// Kayıtlı listenin üretildiği tercihler (rapor params) ile kullanıcının şu
|
||
// anki tercih profilini karşılaştırır. /listem başlığındaki "Tercihlerin
|
||
// değişmiş" butonu ve açtığı güncelleme modalı bu farktan doğar.
|
||
//
|
||
// İzomorfik: yalnızca tip ve etiket sabitlerine bağlı — hem client bileşeni
|
||
// hem sunucu tarafı tüketebilir.
|
||
//
|
||
// Eski akışla üretilmiş raporlarda sihirbaz alanları (kategoriler/iller/
|
||
// universiteTipi/oncelikler) hiç yok. Olmayan alan "değişmiş" sayılmaz:
|
||
// kıyaslanacak bir değer yokken kullanıcıyı 3 kredilik güncellemeye
|
||
// çağırmak dürüst olmaz. Sıralama ve puan türü her raporda dolu olduğundan
|
||
// onlar her zaman kıyaslanır.
|
||
|
||
import {
|
||
PUAN_TURU_ETIKET,
|
||
UNIVERSITE_TIPI_ETIKET,
|
||
oncelikNormalize,
|
||
type TercihProfili,
|
||
} from "@/features/sihirbaz/sihirbaz-sabitler";
|
||
import type { RaporParams } from "./types/rapor";
|
||
|
||
export type FarkAlani =
|
||
| "sira"
|
||
| "tur"
|
||
| "kategoriler"
|
||
| "iller"
|
||
| "universiteTipi"
|
||
| "oncelikler";
|
||
|
||
export const FARK_ETIKET: Record<FarkAlani, string> = {
|
||
sira: "başarı sıralaman",
|
||
tur: "puan türün",
|
||
kategoriler: "ilgi alanların",
|
||
iller: "şehir tercihlerin",
|
||
universiteTipi: "devlet/vakıf tercihin",
|
||
oncelikler: "önceliklerin",
|
||
};
|
||
|
||
// Sıra bağımsız küme kıyası: sihirbaz seçimleri tekrarsız olarak doğrulanır
|
||
// (bkz. sihirbazDogrula), aynı seçimlerin farklı sırayla kaydedilmesi
|
||
// "değişiklik" değildir.
|
||
function kumeFarkli(
|
||
eski: readonly string[] | undefined,
|
||
yeni: readonly string[],
|
||
): boolean {
|
||
if (!eski) return false;
|
||
if (eski.length !== yeni.length) return true;
|
||
const kume = new Set(eski);
|
||
return yeni.some((x) => !kume.has(x));
|
||
}
|
||
|
||
function liste(degerler: readonly string[] | undefined): string {
|
||
return degerler && degerler.length > 0 ? degerler.join(", ") : "—";
|
||
}
|
||
|
||
export function tercihFarki(
|
||
params: RaporParams,
|
||
profil: TercihProfili,
|
||
): FarkAlani[] {
|
||
const farklar: FarkAlani[] = [];
|
||
const s = profil.secimler;
|
||
|
||
if (Math.round(params.sira) !== Math.round(profil.sira)) farklar.push("sira");
|
||
if (params.tur !== profil.tur) farklar.push("tur");
|
||
if (kumeFarkli(params.kategoriler, s.kategoriler)) farklar.push("kategoriler");
|
||
if (kumeFarkli(params.iller, s.iller)) farklar.push("iller");
|
||
if (
|
||
params.universiteTipi !== undefined &&
|
||
params.universiteTipi !== s.universiteTipi
|
||
) {
|
||
farklar.push("universiteTipi");
|
||
}
|
||
if (kumeFarkli(params.oncelikler?.map(oncelikNormalize), s.oncelikler)) {
|
||
farklar.push("oncelikler");
|
||
}
|
||
|
||
return farklar;
|
||
}
|
||
|
||
export type FarkSatiri = { alan: FarkAlani; etiket: string; eski: string; yeni: string };
|
||
|
||
/** Değişen her alanın eski → yeni değeri; uyarıda tek tek gösterilir. */
|
||
export function farkSatirlari(
|
||
params: RaporParams,
|
||
profil: TercihProfili,
|
||
farklar: FarkAlani[],
|
||
): FarkSatiri[] {
|
||
const s = profil.secimler;
|
||
const sayi = (n: number) => Math.round(n).toLocaleString("tr-TR");
|
||
|
||
return farklar.map((alan) => {
|
||
const ortak = { alan, etiket: FARK_ETIKET[alan] };
|
||
switch (alan) {
|
||
case "sira":
|
||
return { ...ortak, eski: `${sayi(params.sira)}.`, yeni: `${sayi(profil.sira)}.` };
|
||
case "tur":
|
||
return {
|
||
...ortak,
|
||
eski: PUAN_TURU_ETIKET[params.tur] ?? params.tur,
|
||
yeni: PUAN_TURU_ETIKET[profil.tur] ?? profil.tur,
|
||
};
|
||
case "kategoriler":
|
||
return { ...ortak, eski: liste(params.kategoriler), yeni: liste(s.kategoriler) };
|
||
case "iller":
|
||
return { ...ortak, eski: liste(params.iller), yeni: liste(s.iller) };
|
||
case "universiteTipi":
|
||
return {
|
||
...ortak,
|
||
eski: UNIVERSITE_TIPI_ETIKET[params.universiteTipi ?? "farketmez"],
|
||
yeni: UNIVERSITE_TIPI_ETIKET[s.universiteTipi],
|
||
};
|
||
case "oncelikler":
|
||
return { ...ortak, eski: liste(params.oncelikler?.map(oncelikNormalize)),
|
||
yeni: liste(s.oncelikler), };
|
||
}
|
||
});
|
||
}
|