Files
star-erp/resources/js/Pages/Landlord/Tenant/Index.tsx
sky121113 2e71a1cb29
All checks were successful
Koori-ERP-Deploy-System / deploy-demo (push) Has been skipped
Koori-ERP-Deploy-System / deploy-production (push) Successful in 49s
Feature: Tenant Short Name and Branding Implementation
- Added short_name to Tenant model and controller
- Updated Landlord/Tenant pages (Create, Edit, Show, Index)
- Implemented branding customization (Favicon, Login Copyright, Sidebar Title)
- Updated HandleInertiaRequests to share branding data
2026-01-29 16:28:34 +08:00

198 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
short_name: string | null;
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-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={7} 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 text-sm text-slate-700">
{tenant.short_name || '-'}
</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>
);
}