refactor: odeme feature'ı + son süpürme — geçiş tamamlandı (Faz 10)
Some checks failed
Deploy / deploy (push) Failing after 3m46s
Some checks failed
Deploy / deploy (push) Failing after 3m46s
- paket/actions.ts → odeme-actions.ts; satin-al-form + rapor-yok-cta features/odeme/components/ altına; odeme-queries.ts (siparisGetir) - Yeni async OdemeSonucKarti: verifySession + sahiplik kontrolü + self-healing odemeyiSonuclandir çağrısı akıştaki yerinde (artık Suspense altındaki feature bileşeninde, aynı render semantiği); başarı/hata kartları içeride - Yeni async PaketSatinAl: paket + top-up kartları, getCurrentUser okuması içeride; statik hero/dipnot sayfada kaldı - İki sayfa senkron searchParams.then(); paket hata uyarısı sayfada çözülmüş JSX (hata yokken hiçbir şey çizilmediği için fallback bilerek null); paket/loading.tsx + odeme/sonuc/loading.tsx silindi - Süpürme doğrulandı: app/ altında route-dışı bileşen dosyası kalmadı; eski yol grep'leri sıfır; 7 *-queries server-only, 3 *-actions 'use server'; async sayfa sıfır; /api/odeme/callback el değmedi - Davranış değişikliği yok Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
75
src/features/odeme/odeme-actions.ts
Normal file
75
src/features/odeme/odeme-actions.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
"use server";
|
||||
|
||||
import { eq } from "drizzle-orm";
|
||||
import { headers } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { verifySession } from "@/lib/session";
|
||||
import { appDb, schema } from "@/lib/appdb";
|
||||
import { URUNLER } from "@/lib/credits";
|
||||
import { initializeCheckoutForm } from "@/lib/iyzico";
|
||||
|
||||
export type OdemeBaslatDurum = { error?: string } | undefined;
|
||||
|
||||
export async function baslatOdeme(
|
||||
_prev: OdemeBaslatDurum,
|
||||
formData: FormData,
|
||||
): Promise<OdemeBaslatDurum> {
|
||||
const session = await verifySession("/paket");
|
||||
const product = formData.get("urun");
|
||||
if (product !== "paket" && product !== "topup") {
|
||||
return { error: "Geçersiz ürün." };
|
||||
}
|
||||
const urun = URUNLER[product];
|
||||
|
||||
const orderId = crypto.randomUUID();
|
||||
await appDb.insert(schema.orders).values({
|
||||
id: orderId,
|
||||
userId: session.user.id,
|
||||
product,
|
||||
amountKurus: urun.amountKurus,
|
||||
credits: urun.credits,
|
||||
status: "pending",
|
||||
createdAt: new Date(),
|
||||
});
|
||||
|
||||
const h = await headers();
|
||||
const buyerIp =
|
||||
h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "85.34.78.112";
|
||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
|
||||
|
||||
let init;
|
||||
try {
|
||||
init = await initializeCheckoutForm({
|
||||
orderId,
|
||||
fiyatKurus: urun.amountKurus,
|
||||
urunAdi: `KolayTercih — ${urun.label}`,
|
||||
email: session.user.email,
|
||||
userId: session.user.id,
|
||||
callbackUrl: `${appUrl}/api/odeme/callback`,
|
||||
buyerIp,
|
||||
});
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.message === "IYZICO_KEYS_MISSING") {
|
||||
// Yapılandırma detayı log'a; kullanıcıya altyapı sızdırmayan mesaj
|
||||
console.error("[odeme] iyzico anahtarları eksik — ödeme başlatılamadı");
|
||||
return {
|
||||
error:
|
||||
"Ödeme şu anda başlatılamıyor; kartından çekim yapılmadı. Birazdan tekrar dener misin?",
|
||||
};
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (init.status !== "success" || !init.paymentPageUrl || !init.token) {
|
||||
return {
|
||||
error: init.errorMessage ?? "Ödeme başlatılamadı. Tekrar dener misin?",
|
||||
};
|
||||
}
|
||||
|
||||
await appDb
|
||||
.update(schema.orders)
|
||||
.set({ iyzicoToken: init.token })
|
||||
.where(eq(schema.orders.id, orderId));
|
||||
|
||||
redirect(init.paymentPageUrl);
|
||||
}
|
||||
Reference in New Issue
Block a user