Kritik (K1-K6) sonrası kalan tüm maddeler: - Değer önce: girişsiz kullanıcı sihirbaz bitince /giris yerine /sonuc'taki ücretsiz tabloya gider (?hazir=1); AI CTA'sı "5 deneme kredinle listeni kur — giriş yap" paneli + sabit alt karttan verilir, girişte otomatik üretim - Ö1-Ö10: paywall kopyası, aranabilir il seçimi, "Seçtiklerim" adlandırması, gizlilik/koşullar/iletişim sayfaları, danışman özeti + uyarılar, revizyon kutusu, dilim özeti + tek şehir uyarısı, eksik veri rozetleri, magic link yeniden gönder, mobil sohbet kısayolu - G1-G5: binlik ayraçlı input + inline hata, adım göstergesi, route-level loading/error/not-found, dürüst konumlandırma kartı, dürüst buton etiketleri - Seçtiklerim butonu liste boşken gizli; ilk eklemede belirir - Dev süperadmin paneli (yalnızca development): hızlı giriş, kredi/paket/rapor senaryoları, sahte ödeme dönüşü Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
128 lines
3.9 KiB
TypeScript
128 lines
3.9 KiB
TypeScript
"use server";
|
||
|
||
// Dev süperadmin aksiyonları: yalnızca geliştirme ortamında çalışır.
|
||
// Panelden (src/components/dev/dev-panel.tsx) çağrılır; kullanıcı durumunu
|
||
// (kredi, paket, rapor) kurcalayıp tüm sayfaları gerçek akışta gezmeyi sağlar.
|
||
|
||
import { eq } from "drizzle-orm";
|
||
import { headers } from "next/headers";
|
||
import { appDb, schema } from "@/lib/appdb";
|
||
import { auth } from "@/lib/auth";
|
||
import { getCurrentUser } from "@/lib/session";
|
||
import { URUNLER } from "@/lib/credits";
|
||
|
||
function devKontrol() {
|
||
if (process.env.NODE_ENV === "production") {
|
||
throw new Error("Dev paneli yalnızca geliştirme ortamında çalışır.");
|
||
}
|
||
}
|
||
|
||
export type DevDurum =
|
||
| { girisli: false }
|
||
| {
|
||
girisli: true;
|
||
email: string;
|
||
kredi: number;
|
||
hasPaket: boolean;
|
||
raporVar: boolean;
|
||
sira: number | null;
|
||
tur: string | null;
|
||
};
|
||
|
||
export async function devDurum(): Promise<DevDurum> {
|
||
devKontrol();
|
||
const user = await getCurrentUser();
|
||
if (!user) return { girisli: false };
|
||
const rapor = await appDb.query.reports.findFirst({
|
||
where: eq(schema.reports.userId, user.id),
|
||
columns: { params: true },
|
||
});
|
||
const params = rapor?.params as { sira?: number; tur?: string } | undefined;
|
||
return {
|
||
girisli: true,
|
||
email: user.email,
|
||
kredi: user.creditBalance,
|
||
hasPaket: user.hasPaket,
|
||
raporVar: Boolean(rapor),
|
||
sira: params?.sira ?? null,
|
||
tur: params?.tur ?? null,
|
||
};
|
||
}
|
||
|
||
/** Magic link üretir ve (dev'de auth.ts'in yakaladığı) URL'i döner —
|
||
* panel bu URL'e giderek anında oturum açar; yeni e-posta = yeni kullanıcı. */
|
||
export async function devAnindaGiris(
|
||
email: string,
|
||
): Promise<{ ok: true; url: string } | { ok: false; error: string }> {
|
||
devKontrol();
|
||
const temiz = email.trim().toLowerCase();
|
||
if (!/^\S+@\S+\.\S+$/.test(temiz)) {
|
||
return { ok: false, error: "Geçerli bir e-posta gir." };
|
||
}
|
||
const g = globalThis as { __sonMagicLink?: string };
|
||
g.__sonMagicLink = undefined;
|
||
await auth.api.signInMagicLink({
|
||
body: { email: temiz, callbackURL: "/" },
|
||
headers: await headers(),
|
||
});
|
||
if (!g.__sonMagicLink) {
|
||
return { ok: false, error: "Magic link üretilemedi (auth.ts yakalayamadı)." };
|
||
}
|
||
return { ok: true, url: g.__sonMagicLink };
|
||
}
|
||
|
||
export async function devAyarla(ayar: {
|
||
kredi?: number;
|
||
hasPaket?: boolean;
|
||
}): Promise<{ ok: boolean; error?: string }> {
|
||
devKontrol();
|
||
const user = await getCurrentUser();
|
||
if (!user) return { ok: false, error: "Önce giriş yap." };
|
||
await appDb
|
||
.update(schema.user)
|
||
.set({
|
||
...(typeof ayar.kredi === "number"
|
||
? { creditBalance: Math.max(0, Math.round(ayar.kredi)) }
|
||
: {}),
|
||
...(typeof ayar.hasPaket === "boolean"
|
||
? { hasPaket: ayar.hasPaket }
|
||
: {}),
|
||
})
|
||
.where(eq(schema.user.id, user.id));
|
||
return { ok: true };
|
||
}
|
||
|
||
/** Raporu ve sohbet geçmişini siler — boş durumları test etmek için. */
|
||
export async function devRaporSil(): Promise<{ ok: boolean; error?: string }> {
|
||
devKontrol();
|
||
const user = await getCurrentUser();
|
||
if (!user) return { ok: false, error: "Önce giriş yap." };
|
||
await appDb
|
||
.delete(schema.reports)
|
||
.where(eq(schema.reports.userId, user.id));
|
||
await appDb
|
||
.delete(schema.chatMessages)
|
||
.where(eq(schema.chatMessages.userId, user.id));
|
||
return { ok: true };
|
||
}
|
||
|
||
/** Ödenmiş sahte sipariş oluşturur — /odeme/sonuc başarı ekranı için. */
|
||
export async function devSahteOdeme(): Promise<
|
||
{ ok: true; siparis: string } | { ok: false; error: string }
|
||
> {
|
||
devKontrol();
|
||
const user = await getCurrentUser();
|
||
if (!user) return { ok: false, error: "Önce giriş yap." };
|
||
const id = `dev-${crypto.randomUUID()}`;
|
||
await appDb.insert(schema.orders).values({
|
||
id,
|
||
userId: user.id,
|
||
product: "paket",
|
||
amountKurus: URUNLER.paket.amountKurus,
|
||
credits: URUNLER.paket.credits,
|
||
status: "paid",
|
||
createdAt: new Date(),
|
||
});
|
||
return { ok: true, siparis: id };
|
||
}
|