"use client";
/**
* ClientTable — Enhanced version
*
* Changes from original:
* 1. Clicking a row now opens an inline ClientDetailPanel (slide-down) showing full client info.
* 2. "Addresses" link inside the detail panel navigates to /dashboard/clients/[clientId]/addresses.
* 3. The row-level onClick still calls onManageAddresses (kept for backwards-compatibility),
* but the primary UX is now the expandable detail panel.
* 4. Active row is highlighted with a brand-tinted left border.
*/
import { useState } from "react";
import { Spinner } from "../UI";
import type { Client } from "@/src/types/client";
// ── Address count badge ────────────────────────────────────────────────────
function AddressBadge({ count, onClick }: { count: number; onClick: () => void }) {
const hasAddr = count > 0;
return (
);
}
// ── Status badge ───────────────────────────────────────────────────────────
function StatusBadge({ active }: { active?: boolean }) {
const isActive = active !== false;
return (
{isActive ? "نشط" : "غير نشط"}
);
}
// ── Icon button ────────────────────────────────────────────────────────────
function IconBtn({
onClick,
title,
color,
bg,
borderColor,
children,
}: {
onClick: () => void;
title: string;
color: string;
bg: string;
borderColor: string;
children: React.ReactNode;
}) {
return (
);
}
// ── Client detail panel (inline expandable) ────────────────────────────────
/**
* ClientDetailPanel — shown below the clicked row.
* Displays all client fields (name, email, phone, taxId, notes, createdAt)
* and provides a direct link to the addresses sub-page.
*
* @param client The client whose details are rendered.
* @param onGoAddresses Callback that navigates to /dashboard/clients/[id]/addresses.
* @param onEdit Opens the edit modal for this client.
*/
function ClientDetailPanel({
client,
onGoAddresses,
onEdit,
}: {
client: Client;
onGoAddresses: () => void;
onEdit: () => void;
}) {
const infoItem = (label: string, value: React.ReactNode) => (
{label}
{value || —}
);
return (
{/* ── Top row: name + quick actions ── */}
{client.name}
{client.taxId && (
{client.taxId}
)}
{/* Action buttons */}
{/* Edit client */}
{/*
* "Addresses" button — KEY FEATURE:
* Navigates to /dashboard/clients/[clientId]/addresses
*/}
{/* ── Info grid ── */}
{infoItem(
"البريد الإلكتروني",
e.stopPropagation()}
style={{ color: "#2563EB", textDecoration: "none" }}
>
{client.email}
,
)}
{infoItem("الهاتف", client.phone)}
{infoItem(
"تاريخ الإضافة",
new Date(client.createdAt).toLocaleDateString("ar-SA", {
year: "numeric",
month: "long",
day: "numeric",
}),
)}
{infoItem(
"آخر تحديث",
new Date(client.updatedAt).toLocaleDateString("ar-SA", {
year: "numeric",
month: "long",
day: "numeric",
}),
)}
{client.notes && infoItem("ملاحظات", client.notes)}
{/* Keyframe animation injected via a style tag (scoped) */}
);
}
// ── Shared card & header styles ────────────────────────────────────────────
const cardStyle: React.CSSProperties = {
borderRadius: "var(--radius-xl)",
border: "1px solid var(--color-border)",
background: "var(--color-surface)",
overflow: "hidden",
boxShadow: "var(--shadow-card)",
};
const thStyle: React.CSSProperties = {
padding: "0.75rem 1.5rem",
fontSize: 11,
fontWeight: 700,
textTransform: "uppercase",
letterSpacing: "0.2em",
color: "var(--color-text-muted)",
background: "var(--color-surface-muted)",
borderBottom: "1px solid var(--color-border)",
};
// ── Props ──────────────────────────────────────────────────────────────────
interface ClientTableProps {
clients: Client[];
loading: boolean;
search: string;
page: number;
pages: number;
onEdit: (client: Client) => void;
onDelete: (client: Client) => void;
onAddFirst: () => void;
onPageChange: (p: number) => void;
/** Navigate to address management for a client */
onManageAddresses: (client: Client) => void;
}
// ── Main table ─────────────────────────────────────────────────────────────
export function ClientTable({
clients,
loading,
search,
page,
pages,
onEdit,
onDelete,
onAddFirst,
onPageChange,
onManageAddresses,
}: ClientTableProps) {
/**
* expandedId — tracks which client row is currently expanded.
* Clicking the same row again collapses it (toggle behaviour).
*/
const [expandedId, setExpandedId] = useState(null);
const handleRowClick = (client: Client) => {
// Toggle: collapse if already open, expand otherwise
setExpandedId((prev) => (prev === client.id ? null : client.id));
};
return (
{/* Column headers */}
العميل
البريد الإلكتروني
الهاتف
العناوين
تاريخ الإضافة
إجراءات
{/* Loading */}
{loading ? (
جارٍ التحميل…
) : clients.length === 0 ? (
/* Empty state */
{search
? `لا توجد نتائج لـ "${search}"`
: "لا يوجد عملاء لعرضهم."}
{!search && (
)}
) : (
/* Data rows */
{clients.map((c, i) => {
const isExpanded = expandedId === c.id;
return (
-
{/* ── Main row ── */}
{
if (e.key === "Enter" || e.key === " ") handleRowClick(c);
}}
onClick={() => handleRowClick(c)}
style={{
display: "grid",
gridTemplateColumns: "2fr 1.5fr 1.5fr 1fr 1fr 80px",
alignItems: "center",
gap: "0.5rem",
padding: "0.875rem 1.5rem",
borderBottom: isExpanded
? "none"
: "1px solid var(--color-border)",
/* Highlight the expanded row with a brand-tinted background */
background: isExpanded
? "#EFF6FF"
: i % 2 !== 0
? "var(--color-surface-muted)"
: "transparent",
/* Left accent border when expanded (RTL: border-right in visual) */
borderRight: isExpanded
? "3px solid var(--color-brand-600)"
: "3px solid transparent",
fontSize: 13,
cursor: "pointer",
transition: "background 120ms, border-color 120ms",
outline: "none",
}}
>
{/* Name */}
{c.name}
{/* Chevron indicator — rotates when expanded */}
{c.taxId && (
{c.taxId}
)}
{/* Email */}
{c.email}
{/* Phone */}
{c.phone}
{/*
* Address count badge — clicking it navigates directly to
* /dashboard/clients/[clientId]/addresses (bypasses the detail panel).
*/}
onManageAddresses(c)}
/>
{/* Created at */}
{new Date(c.createdAt).toLocaleDateString("ar-SA", {
year: "numeric",
month: "short",
day: "numeric",
})}
{/* Row action buttons */}
e.stopPropagation()}
>
onEdit(c)}
>
onDelete(c)}
>
{/*
* ── Expandable detail panel ──
* Rendered inline below the row when isExpanded is true.
* Contains full client metadata + "العناوين" navigation button.
*
* TEST: Click any row → panel slides in with client details.
* Click "العناوين" → router.push to /dashboard/clients/[id]/addresses.
* Click same row again → panel collapses.
*/}
{isExpanded && (
onManageAddresses(c)}
onEdit={() => onEdit(c)}
/>
)}
);
})}
)}
{/* Pagination */}
{pages > 1 && (
صفحة{" "}
{page}{" "}
من{" "}
{pages}
{[
{
label: "السابق",
action: () => onPageChange(Math.max(1, page - 1)),
disabled: page === 1,
},
{
label: "التالي",
action: () => onPageChange(Math.min(pages, page + 1)),
disabled: page === pages,
},
].map((btn) => (
))}
)}
);
}