Task #739: تحويل تبويب القاعات من بطاقات إلى جدول
- protocol.tsx (tab === "rooms"): replaced the 2-column card grid with a
Table styled like the bookings table (bg-slate-100/80 header, centered
headers/cells) with columns: # | القاعات | الحالة | الإجراء.
- # = sequential index; name via nameOf with capacity line beneath.
- Status badge keeps emerald-100 / slate-200 colors.
- Actions column (edit/delete, same setRoomDialog/setDeleteTarget
handlers) rendered only when canManageRooms.
- EmptyState (rooms.empty), "قاعة جديدة" button, and dialogs unchanged.
- i18n: added protocol.rooms.status ("الحالة"/"Status") and
protocol.rooms.actions ("الإجراء"/"Action") to ar.json and en.json.
- Verified: pnpm --filter @workspace/tx-os exec tsc --noEmit clean;
architect review passed with no blocking issues.
This commit is contained in:
@@ -1893,6 +1893,8 @@
|
||||
"location": "الموقع",
|
||||
"active": "مفعّلة",
|
||||
"isActive": "مفعّلة",
|
||||
"status": "الحالة",
|
||||
"actions": "الإجراء",
|
||||
"empty": "لا توجد قاعات."
|
||||
},
|
||||
"issues": {
|
||||
|
||||
@@ -1738,6 +1738,8 @@
|
||||
"location": "Location",
|
||||
"active": "Active",
|
||||
"isActive": "Active",
|
||||
"status": "Status",
|
||||
"actions": "Action",
|
||||
"empty": "No rooms."
|
||||
},
|
||||
"issues": {
|
||||
|
||||
@@ -1780,26 +1780,47 @@ export default function ProtocolPage() {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
{(rooms.data ?? []).map((r) => (
|
||||
<div
|
||||
key={r.id}
|
||||
className="bg-white rounded-xl border border-slate-200 p-3"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
{rooms.data?.length === 0 ? (
|
||||
<EmptyState text={t("protocol.rooms.empty")} />
|
||||
) : (
|
||||
<div className="rounded-xl border border-slate-200 bg-white overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="bg-slate-100/80 hover:bg-slate-100/80">
|
||||
<TableHead className="w-10 text-center">#</TableHead>
|
||||
<TableHead className="text-center whitespace-nowrap">
|
||||
{t("protocol.rooms.title")}
|
||||
</TableHead>
|
||||
<TableHead className="text-center whitespace-nowrap">
|
||||
{t("protocol.rooms.status")}
|
||||
</TableHead>
|
||||
{c?.canManageRooms && (
|
||||
<TableHead className="text-center whitespace-nowrap">
|
||||
{t("protocol.rooms.actions")}
|
||||
</TableHead>
|
||||
)}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{(rooms.data ?? []).map((r, i) => (
|
||||
<TableRow key={r.id}>
|
||||
<TableCell className="text-center text-slate-500">
|
||||
{i + 1}
|
||||
</TableCell>
|
||||
<TableCell className="text-center">
|
||||
<div className="font-medium text-slate-800">
|
||||
{nameOf(r.nameAr, r.nameEn)}
|
||||
</div>
|
||||
{r.capacity ? (
|
||||
<div className="text-xs text-slate-500">
|
||||
{r.capacity
|
||||
? `${t("protocol.rooms.capacity")}: ${r.capacity}`
|
||||
: ""}
|
||||
</div>
|
||||
{`${t("protocol.rooms.capacity")}: ${r.capacity}`}
|
||||
</div>
|
||||
) : null}
|
||||
</TableCell>
|
||||
<TableCell className="text-center">
|
||||
<span
|
||||
className={cn(
|
||||
"text-xs px-2 py-0.5 rounded-full shrink-0",
|
||||
"text-xs px-2 py-0.5 rounded-full",
|
||||
r.isActive
|
||||
? "bg-emerald-100 text-emerald-700"
|
||||
: "bg-slate-200 text-slate-500",
|
||||
@@ -1809,31 +1830,37 @@ export default function ProtocolPage() {
|
||||
? t("protocol.rooms.active")
|
||||
: t("protocol.rooms.inactive")}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
{c?.canManageRooms && (
|
||||
<div className="flex gap-1.5 mt-2">
|
||||
<TableCell className="text-center">
|
||||
<div className="flex justify-center gap-1.5">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setRoomDialog({ open: true, edit: r })}
|
||||
onClick={() =>
|
||||
setRoomDialog({ open: true, edit: r })
|
||||
}
|
||||
>
|
||||
<Pencil size={14} />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setDeleteTarget({ kind: "room", id: r.id })}
|
||||
onClick={() =>
|
||||
setDeleteTarget({ kind: "room", id: r.id })
|
||||
}
|
||||
>
|
||||
<Trash2 size={14} className="text-rose-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
)}
|
||||
</div>
|
||||
</TableRow>
|
||||
))}
|
||||
{rooms.data?.length === 0 && (
|
||||
<EmptyState text={t("protocol.rooms.empty")} />
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user