Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
88 lines
3.8 KiB
TypeScript
88 lines
3.8 KiB
TypeScript
import { ShellPage } from "@/components/page-templates";
|
|
import { Button, SectionCard } from "@/components/ui";
|
|
import { createTenant } from "@/lib/admin-crud";
|
|
import { getSession } from "@/lib/auth";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { redirect } from "next/navigation";
|
|
|
|
export default async function NewTenantPage({
|
|
searchParams
|
|
}: {
|
|
searchParams?: Promise<{ error?: string }>;
|
|
}) {
|
|
const session = await getSession();
|
|
if (!session || session.role !== "super_admin") {
|
|
redirect("/unauthorized");
|
|
}
|
|
|
|
const params = await (searchParams ?? Promise.resolve({ error: undefined }));
|
|
let plans: Array<{
|
|
id: string;
|
|
name: string;
|
|
code: string;
|
|
priceMonthly: number;
|
|
}> = [];
|
|
|
|
try {
|
|
plans = await prisma.subscriptionPlan.findMany({ orderBy: { priceMonthly: "asc" } });
|
|
} catch (error) {
|
|
console.error("[tenant/new] load plans failed", {
|
|
actorUserId: session.userId,
|
|
error: error instanceof Error ? error.message : String(error)
|
|
});
|
|
}
|
|
|
|
const error = params.error;
|
|
const errorMessage =
|
|
error === "missing_fields"
|
|
? "Nama perusahaan, slug, timezone, dan plan wajib diisi."
|
|
: error === "invalid_plan"
|
|
? "Plan tidak valid."
|
|
: error === "slug_exists"
|
|
? "Slug tenant sudah dipakai."
|
|
: error === "admin_email_exists"
|
|
? "Email admin awal sudah terpakai."
|
|
: error === "tenant_creation_failed"
|
|
? "Tidak bisa membuat tenant, silakan cek log server untuk detail error."
|
|
: error === "plans_fetch_failed"
|
|
? "Tidak dapat memuat daftar plan. Cek log server/DB koneksi."
|
|
: null;
|
|
|
|
return (
|
|
<ShellPage shell="super-admin" title="Create Tenant" description="Setup tenant baru beserta plan dan admin awal.">
|
|
<SectionCard title="Tenant form">
|
|
<form action={createTenant} className="grid gap-4 md:max-w-3xl md:grid-cols-2">
|
|
{errorMessage ? <p className="col-span-2 rounded-xl border border-warning/30 bg-warning/10 p-3 text-sm text-warning">{errorMessage}</p> : null}
|
|
{plans.length === 0 ? (
|
|
<p className="col-span-2 rounded-xl border border-warning/30 bg-warning/10 p-3 text-sm text-warning">
|
|
Belum ada data plan. Isi dulu plan pada <a href="/super-admin/billing/plans" className="underline">Catalog Plan</a> sebelum membuat tenant.
|
|
</p>
|
|
) : null}
|
|
<input name="name" className="rounded-xl border border-line px-4 py-3" placeholder="Company name" required />
|
|
<input name="slug" className="rounded-xl border border-line px-4 py-3" placeholder="Tenant slug" required />
|
|
<input name="timezone" className="rounded-xl border border-line px-4 py-3" placeholder="Timezone" required />
|
|
<select name="planId" required className="rounded-xl border border-line px-4 py-3" defaultValue="">
|
|
<option value="">Pilih plan</option>
|
|
{plans.map((plan) => (
|
|
<option key={plan.id} value={plan.id}>
|
|
{plan.name} ({plan.code}) - Rp {plan.priceMonthly.toLocaleString("id-ID")}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<input name="adminFullName" className="rounded-xl border border-line px-4 py-3" placeholder="Nama admin awal" />
|
|
<input name="adminEmail" type="email" className="rounded-xl border border-line px-4 py-3" placeholder="Initial admin email" />
|
|
<input
|
|
name="adminPassword"
|
|
type="password"
|
|
className="rounded-xl border border-line px-4 py-3 md:col-span-2"
|
|
placeholder="Password awal admin (kosong: kirim undangan)"
|
|
/>
|
|
<div className="md:col-span-2">
|
|
<Button type="submit">Create tenant</Button>
|
|
</div>
|
|
</form>
|
|
</SectionCard>
|
|
</ShellPage>
|
|
);
|
|
}
|