191 lines
9.8 KiB
TypeScript
191 lines
9.8 KiB
TypeScript
import LandlordLayout from "@/Layouts/LandlordLayout";
|
||
import { Link, router } from "@inertiajs/react";
|
||
import { Plus, Edit, Trash2, Globe } from "lucide-react";
|
||
import { useState } from "react";
|
||
import {
|
||
AlertDialog,
|
||
AlertDialogAction,
|
||
AlertDialogCancel,
|
||
AlertDialogContent,
|
||
AlertDialogDescription,
|
||
AlertDialogFooter,
|
||
AlertDialogHeader,
|
||
AlertDialogTitle,
|
||
} from "@/Components/ui/alert-dialog";
|
||
|
||
interface Tenant {
|
||
id: string;
|
||
name: string;
|
||
email: string | null;
|
||
is_active: boolean;
|
||
created_at: string;
|
||
domains: string[];
|
||
}
|
||
|
||
interface Props {
|
||
tenants: Tenant[];
|
||
}
|
||
|
||
export default function TenantIndex({ tenants }: Props) {
|
||
const [deleteTarget, setDeleteTarget] = useState<Tenant | null>(null);
|
||
|
||
const handleDelete = () => {
|
||
if (deleteTarget) {
|
||
router.delete(route("landlord.tenants.destroy", deleteTarget.id));
|
||
setDeleteTarget(null);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<LandlordLayout
|
||
title="客戶管理"
|
||
>
|
||
<div className="space-y-6">
|
||
{/* Header */}
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<h1 className="text-2xl font-bold text-slate-900">客戶管理</h1>
|
||
<p className="text-slate-500 mt-1">管理系統中的所有客戶</p>
|
||
</div>
|
||
<Link
|
||
href="/landlord/tenants/create"
|
||
className="bg-primary-main hover:bg-primary-dark text-white px-4 py-2 rounded-lg flex items-center gap-2 transition-colors"
|
||
>
|
||
<Plus className="w-4 h-4" />
|
||
新增客戶
|
||
</Link>
|
||
</div>
|
||
|
||
{/* Table */}
|
||
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||
<table className="w-full">
|
||
<thead className="bg-slate-50">
|
||
<tr>
|
||
<th className="px-6 py-3 text-left text-xs font-semibold text-slate-500 uppercase">
|
||
ID
|
||
</th>
|
||
<th className="px-6 py-3 text-left text-xs font-semibold text-slate-500 uppercase">
|
||
名稱
|
||
</th>
|
||
<th className="px-6 py-3 text-left text-xs font-semibold text-slate-500 uppercase">
|
||
域名
|
||
</th>
|
||
<th className="px-6 py-3 text-left text-xs font-semibold text-slate-500 uppercase">
|
||
狀態
|
||
</th>
|
||
<th className="px-6 py-3 text-left text-xs font-semibold text-slate-500 uppercase">
|
||
建立時間
|
||
</th>
|
||
<th className="px-6 py-3 text-right text-xs font-semibold text-slate-500 uppercase">
|
||
操作
|
||
</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody className="divide-y divide-slate-100">
|
||
{tenants.length === 0 ? (
|
||
<tr>
|
||
<td colSpan={6} className="px-6 py-12 text-center text-slate-500">
|
||
尚無客戶資料,請點擊「新增客戶」建立第一個客戶
|
||
</td>
|
||
</tr>
|
||
) : (
|
||
tenants.map((tenant) => (
|
||
<tr key={tenant.id} className="hover:bg-slate-50">
|
||
<td className="px-6 py-4 font-mono text-sm text-slate-600">
|
||
{tenant.id}
|
||
</td>
|
||
<td className="px-6 py-4">
|
||
<div>
|
||
<p className="font-medium text-slate-900">{tenant.name}</p>
|
||
{tenant.email && (
|
||
<p className="text-sm text-slate-500">{tenant.email}</p>
|
||
)}
|
||
</div>
|
||
</td>
|
||
<td className="px-6 py-4">
|
||
{tenant.domains.length > 0 ? (
|
||
<div className="flex items-center gap-1 flex-wrap">
|
||
{tenant.domains.map((domain) => (
|
||
<span
|
||
key={domain}
|
||
className="inline-flex items-center gap-1 px-2 py-1 bg-slate-100 rounded text-xs"
|
||
>
|
||
<Globe className="w-3 h-3" />
|
||
{domain}
|
||
</span>
|
||
))}
|
||
</div>
|
||
) : (
|
||
<span className="text-slate-400 text-sm">無</span>
|
||
)}
|
||
</td>
|
||
<td className="px-6 py-4">
|
||
<span
|
||
className={`px-2 py-1 rounded-full text-xs font-medium ${tenant.is_active
|
||
? "bg-green-100 text-green-700"
|
||
: "bg-slate-100 text-slate-600"
|
||
}`}
|
||
>
|
||
{tenant.is_active ? "啟用" : "停用"}
|
||
</span>
|
||
</td>
|
||
<td className="px-6 py-4 text-sm text-slate-500">
|
||
{tenant.created_at}
|
||
</td>
|
||
<td className="px-6 py-4 text-right">
|
||
<div className="flex items-center justify-end gap-2">
|
||
<Link
|
||
href={`/landlord/tenants/${tenant.id}`}
|
||
className="p-2 text-slate-400 hover:text-primary-main hover:bg-slate-100 rounded-lg transition-colors"
|
||
title="查看詳情"
|
||
>
|
||
<Globe className="w-4 h-4" />
|
||
</Link>
|
||
<Link
|
||
href={`/landlord/tenants/${tenant.id}/edit`}
|
||
className="p-2 text-slate-400 hover:text-blue-600 hover:bg-slate-100 rounded-lg transition-colors"
|
||
title="編輯"
|
||
>
|
||
<Edit className="w-4 h-4" />
|
||
</Link>
|
||
<button
|
||
onClick={() => setDeleteTarget(tenant)}
|
||
className="p-2 text-slate-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||
title="刪除"
|
||
>
|
||
<Trash2 className="w-4 h-4" />
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Delete Confirmation */}
|
||
<AlertDialog open={!!deleteTarget} onOpenChange={() => setDeleteTarget(null)}>
|
||
<AlertDialogContent>
|
||
<AlertDialogHeader>
|
||
<AlertDialogTitle>確定要刪除這個客戶嗎?</AlertDialogTitle>
|
||
<AlertDialogDescription>
|
||
刪除客戶將會同時刪除其資料庫和所有資料,此操作無法復原。
|
||
</AlertDialogDescription>
|
||
</AlertDialogHeader>
|
||
<AlertDialogFooter>
|
||
<AlertDialogCancel>取消</AlertDialogCancel>
|
||
<AlertDialogAction
|
||
onClick={handleDelete}
|
||
className="bg-red-600 hover:bg-red-700"
|
||
>
|
||
確定刪除
|
||
</AlertDialogAction>
|
||
</AlertDialogFooter>
|
||
</AlertDialogContent>
|
||
</AlertDialog>
|
||
</LandlordLayout>
|
||
);
|
||
}
|