"use client"
import { useState, useRef, useEffect } from 'react'
interface TableRow {
id: string
name: string
email: string
status: string
joinDate: string
details: {
phone: string
address: string
company: string
department: string
}
}
interface TableExpandableProps {
data?: TableRow[]
}
const defaultData: TableRow[] = [
{
id: '1',
name: 'Sarah Johnson',
email: 'sarah.johnson@example.com',
status: 'Active',
joinDate: '2023-01-15',
details: {
phone: '+1 (555) 123-4567',
address: '123 Oak Street, San Francisco, CA 94102',
company: 'TechCorp Inc',
department: 'Engineering'
}
},
{
id: '2',
name: 'Michael Chen',
email: 'michael.chen@example.com',
status: 'Active',
joinDate: '2023-03-22',
details: {
phone: '+1 (555) 234-5678',
address: '456 Maple Avenue, New York, NY 10001',
company: 'InnovateLabs',
department: 'Product'
}
},
{
id: '3',
name: 'Emma Williams',
email: 'emma.williams@example.com',
status: 'Inactive',
joinDate: '2022-11-08',
details: {
phone: '+1 (555) 345-6789',
address: '789 Pine Road, Austin, TX 78701',
company: 'DataSystems LLC',
department: 'Analytics'
}
},
{
id: '4',
name: 'David Rodriguez',
email: 'david.rodriguez@example.com',
status: 'Active',
joinDate: '2023-05-10',
details: {
phone: '+1 (555) 456-7890',
address: '321 Elm Street, Seattle, WA 98101',
company: 'CloudNine',
department: 'Infrastructure'
}
},
{
id: '5',
name: 'Lisa Anderson',
email: 'lisa.anderson@example.com',
status: 'Active',
joinDate: '2023-02-28',
details: {
phone: '+1 (555) 567-8901',
address: '654 Birch Lane, Boston, MA 02101',
company: 'DesignStudio',
department: 'Design'
}
}
]
export default function TableExpandable({ data = defaultData }: TableExpandableProps) {
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set())
const [expandedHeights, setExpandedHeights] = useState<Record<string, number>>({})
const contentRefs = useRef<Record<string, HTMLDivElement>>({})
useEffect(() => {
const newHeights: Record<string, number> = {}
expandedRows.forEach((rowId) => {
const ref = contentRefs.current[rowId]
if (ref) {
newHeights[rowId] = ref.scrollHeight
}
})
setExpandedHeights(newHeights)
}, [expandedRows])
const toggleRow = (rowId: string) => {
const newExpandedRows = new Set(expandedRows)
if (newExpandedRows.has(rowId)) {
newExpandedRows.delete(rowId)
} else {
newExpandedRows.add(rowId)
}
setExpandedRows(newExpandedRows)
}
const expandAll = () => {
setExpandedRows(new Set(data.map(row => row.id)))
}
const collapseAll = () => {
setExpandedRows(new Set())
}
const isAllExpanded = expandedRows.size === data.length && data.length > 0
const isSomeExpanded = expandedRows.size > 0 && expandedRows.size < data.length
return (
<div className="w-full h-screen bg-[#0A0A0A] p-8 overflow-auto">
<div className="max-w-6xl mx-auto">
<div className="mb-6 flex items-center justify-between">
<h1 className="text-3xl font-bold text-[#F5F5F0]">Users Directory</h1>
<div className="flex gap-3">
<button
onClick={expandAll}
className="px-4 py-2 bg-[#C9A84C] text-[#0A0A0A] font-semibold rounded-lg hover:bg-[#D9B85C] transition-colors duration-200"
>
Expand All
</button>
<button
onClick={collapseAll}
className="px-4 py-2 border border-[#C9A84C] text-[#C9A84C] font-semibold rounded-lg hover:bg-[#C9A84C] hover:text-[#0A0A0A] transition-colors duration-200"
>
Collapse All
</button>
</div>
</div>
<div className="border border-[#333333] rounded-lg overflow-hidden">
<table className="w-full">
<thead>
<tr className="bg-[#1A1A1A] border-b border-[#333333]">
<th className="w-12 px-6 py-4 text-left"></th>
<th className="px-6 py-4 text-left text-[#F5F5F0] font-semibold">Name</th>
<th className="px-6 py-4 text-left text-[#F5F5F0] font-semibold">Email</th>
<th className="px-6 py-4 text-left text-[#F5F5F0] font-semibold">Status</th>
<th className="px-6 py-4 text-left text-[#F5F5F0] font-semibold">Join Date</th>
</tr>
</thead>
<tbody>
{data.map((row, index) => {
const isExpanded = expandedRows.has(row.id)
const height = expandedHeights[row.id] || 0
return (
<tbody key={row.id}>
<tr
className={`border-b border-[#333333] hover:bg-[#1A1A1A] transition-colors duration-200 ${
index === data.length - 1 ? '' : ''
}`}
>
<td className="px-6 py-4">
<button
onClick={() => toggleRow(row.id)}
className="w-8 h-8 flex items-center justify-center rounded hover:bg-[#333333] transition-colors duration-200"
>
<svg
className={`w-5 h-5 text-[#C9A84C] transition-transform duration-300 ${
isExpanded ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 14l-7 7m0 0l-7-7m7 7V3"
/>
</svg>
</button>
</td>
<td className="px-6 py-4 text-[#F5F5F0]">{row.name}</td>
<td className="px-6 py-4 text-[#A9A9A0]">{row.email}</td>
<td className="px-6 py-4">
<span
className={`inline-flex px-3 py-1 rounded-full text-sm font-medium ${
row.status === 'Active'
? 'bg-green-900 text-green-200'
: 'bg-gray-700 text-gray-300'
}`}
>
{row.status}
</span>
</td>
<td className="px-6 py-4 text-[#A9A9A0]">{row.joinDate}</td>
</tr>
<tr
className="bg-[#1A1A1A] border-b border-[#333333]"
style={{
maxHeight: isExpanded ? `${height + 32}px` : '0px',
overflow: 'hidden',
transition: 'max-height 0.3s ease-in-out'
}}
>
<td colSpan={5} className="p-0">
<div
ref={(el) => {
if (el) contentRefs.current[row.id] = el
}}
className="px-6 py-4"
>
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
<div>
<h4 className="text-[#C9A84C] font-semibold text-sm mb-1">Phone</h4>
<p className="text-[#F5F5F0]">{row.details.phone}</p>
</div>
<div>
<h4 className="text-[#C9A84C] font-semibold text-sm mb-1">Company</h4>
<p className="text-[#F5F5F0]">{row.details.company}</p>
</div>
<div>
<h4 className="text-[#C9A84C] font-semibold text-sm mb-1">Department</h4>
<p className="text-[#F5F5F0]">{row.details.department}</p>
</div>
<div>
<h4 className="text-[#C9A84C] font-semibold text-sm mb-1">Address</h4>
<p className="text-[#F5F5F0]">{row.details.address}</p>
</div>
</div>
</div>
</td>
</tr>
</tbody>
)
})}
</tbody>
</table>
</div>
<div className="mt-6 text-[#A9A9A0] text-sm">
{expandedRows.size > 0 && (
<p>
{expandedRows.size} row{expandedRows.size !== 1 ? 's' : ''} expanded
</p>
)}
</div>
</div>
</div>
)
}