Files
device-management/resources/js/pages/administration/tenants/edit.tsx
T
Wian Drs 60946ddf37
tests / ci (push) Has been cancelled
update lisensi prosess
2026-08-25 13:43:55 +07:00

275 lines
12 KiB
TypeScript

import { Form, Head, Link, usePage } from '@inertiajs/react';
import InputError from '@/components/input-error';
import { TenantAdminNav } from '@/components/tenant-admin-nav';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
type Tenant = {
id: number;
uuid: string;
name: string;
slug: string;
is_active: boolean;
};
type User = {
uuid: string;
name: string;
email: string;
is_active: boolean;
created_at: string;
};
type Installation = {
deployment_type: 'managed_cloud' | 'self_hosted';
domain?: string;
status: string;
last_seen_at?: string;
};
type License = {
plan: string;
status: string;
max_devices: number;
max_users: number;
expires_at: string;
};
export default function TenantEdit({
tenant,
users,
installation,
license,
plans,
}: {
tenant: Tenant;
users: User[];
installation: Installation | null;
license: License | null;
plans: Record<
string,
{ name: string; price: number; max_devices: number; max_users: number }
>;
}) {
const { flash } = usePage().props as unknown as {
flash: { success?: string };
};
return (
<>
<Head title={`Kelola ${tenant.name}`} />
<div className="mx-auto flex w-full max-w-5xl flex-1 flex-col gap-6 p-4 md:p-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-semibold">
{tenant.name}
</h1>
<p className="text-sm text-muted-foreground">
UUID: {tenant.uuid}
</p>
</div>
<Badge variant={tenant.is_active ? 'default' : 'secondary'}>
{tenant.is_active ? 'Aktif' : 'Nonaktif'}
</Badge>
</div>
<TenantAdminNav tenantId={tenant.id} />
{flash.success && (
<div className="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
{flash.success}
</div>
)}
<Form
action={`/administration/tenants/${tenant.id}`}
method="put"
className="space-y-6"
>
{({ processing, errors }) => (
<Card>
<CardHeader>
<CardTitle>Pengaturan Tenant</CardTitle>
<CardDescription>
Menonaktifkan tenant mempertahankan seluruh
data.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-5 md:grid-cols-2">
<div className="grid gap-2">
<Label htmlFor="name">Nama Tenant</Label>
<Input
id="name"
name="name"
defaultValue={tenant.name}
required
/>
<InputError message={errors.name} />
</div>
<div className="grid gap-2">
<Label htmlFor="slug">Slug</Label>
<Input
id="slug"
name="slug"
defaultValue={tenant.slug}
required
/>
<InputError message={errors.slug} />
</div>
<div className="flex items-center gap-3 md:col-span-2">
<input
type="hidden"
name="is_active"
value="0"
/>
<input
id="is_active"
name="is_active"
type="checkbox"
value="1"
defaultChecked={tenant.is_active}
className="size-4 rounded border"
/>
<Label htmlFor="is_active">
Tenant aktif
</Label>
</div>
<div className="grid gap-2">
<Label>Lokasi Instalasi</Label>
<select
name="deployment_type"
defaultValue={
installation?.deployment_type ??
'managed_cloud'
}
className="h-10 rounded-md border bg-background px-3"
>
<option value="managed_cloud">
RADIQ NDM Cloud
</option>
<option value="self_hosted">
Server/VPS/Komputer Tenant
</option>
</select>
</div>
<div className="grid gap-2">
<Label>Domain / Alamat Instalasi</Label>
<Input
name="deployment_domain"
defaultValue={
installation?.domain ?? ''
}
/>
</div>
<div className="grid gap-2 md:col-span-2">
<Label>Paket Lisensi Aktif</Label>
<select
name="plan_code"
defaultValue={
license?.plan ?? 'cloud_free'
}
className="h-10 rounded-md border bg-background px-3"
>
{Object.entries(plans).map(
([code, plan]) => (
<option key={code} value={code}>
{plan.name} ·{' '}
{plan.price === 0
? 'Gratis'
: `Rp${plan.price.toLocaleString('id-ID')}/bulan`}{' '}
· {plan.max_devices}{' '}
perangkat · {plan.max_users}{' '}
user
</option>
),
)}
</select>
<p className="text-xs text-muted-foreground">
Status: {license?.status ?? 'belum ada'}
{license?.expires_at
? ` · sampai ${new Date(license.expires_at).toLocaleDateString('id-ID')}`
: ''}
</p>
<InputError message={errors.plan_code} />
</div>
<div className="flex gap-3 md:col-span-2">
<Button disabled={processing}>
Simpan Perubahan
</Button>
<Button variant="outline" asChild>
<Link href="/administration/tenants">
Kembali
</Link>
</Button>
</div>
</CardContent>
</Card>
)}
</Form>
<Card>
<CardHeader>
<CardTitle>User Tenant</CardTitle>
<CardDescription>
Daftar awal; manajemen user lengkap tersedia pada
increment berikutnya.
</CardDescription>
</CardHeader>
<CardContent className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b text-left text-muted-foreground">
<th className="py-3">Nama</th>
<th>Email</th>
<th>Status</th>
<th>Dibuat</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr
key={user.uuid}
className="border-b last:border-0"
>
<td className="py-3 font-medium">
{user.name}
</td>
<td>{user.email}</td>
<td>
<Badge
variant={
user.is_active
? 'default'
: 'secondary'
}
>
{user.is_active
? 'Aktif'
: 'Nonaktif'}
</Badge>
</td>
<td>
{new Date(
user.created_at,
).toLocaleDateString('id-ID')}
</td>
</tr>
))}
</tbody>
</table>
</CardContent>
</Card>
</div>
</>
);
}
TenantEdit.layout = {
breadcrumbs: [
{ title: 'Tenants', href: '/administration/tenants' },
{ title: 'Kelola', href: '#' },
],
};