admin roadmap trips ops and payment ops

This commit is contained in:
2026-05-18 19:25:32 +07:00
parent e1966b69f1
commit 4bcb93e283
22 changed files with 1586 additions and 188 deletions
+50 -1
View File
@@ -206,7 +206,10 @@ export async function cancelTripAction(tripId: string) {
}
try {
const result = await tripService.closeTrip(tripId, session.user.id);
const result = await tripService.closeTrip(tripId, {
type: "ORGANIZER",
userId: session.user.id,
});
revalidatePath(`/trips/${tripId}`);
revalidatePath("/trips");
revalidatePath("/");
@@ -222,3 +225,49 @@ export async function cancelTripAction(tripId: string) {
return { error: (err as Error).message };
}
}
/**
* Admin force-cancel trip dari panel admin (intervensi saat organizer
* unreachable / safety issue / dispute). Pakai actor ADMIN — bypass cek
* organizer match, record `cancelledByAdminId` + `cancelledReason`.
*/
export async function adminCancelTripAction(tripId: string, reason: string) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return { error: "Kamu harus login terlebih dahulu" };
}
const { isAdminEmail } = await import("@/lib/admin");
if (!isAdminEmail(session.user.email)) {
return { error: "Hanya admin yang bisa melakukan aksi ini" };
}
const trimmedReason = reason.trim();
if (trimmedReason.length < 10) {
return {
error: "Alasan cancel wajib diisi (minimal 10 karakter untuk audit)",
};
}
if (trimmedReason.length > 500) {
return { error: "Alasan cancel maksimal 500 karakter" };
}
try {
const result = await tripService.closeTrip(tripId, {
type: "ADMIN",
adminId: session.user.id,
reason: trimmedReason,
});
revalidatePath(`/trips/${tripId}`);
revalidatePath(`/admin/trips/${tripId}`);
revalidatePath("/admin/trips");
revalidatePath("/admin/refunds");
revalidatePath("/trips");
return {
success: true as const,
refundCount: result.refundsCreated.length,
cancelledCount: result.cancelledBookings.length,
skippedCount: result.skippedBookings.length,
};
} catch (err) {
return { error: (err as Error).message };
}
}