1+ "use client"
2+ import TableGrid from "@/components/ui/table-grid/table-grid"
3+ import dummyData from "@/data/dummy.json"
4+ import type { Column } from "@/components/ui/table-grid/table-grid"
5+ import { useTableGrid } from "@/hooks/use-table-grid"
6+ import { useState , useEffect } from "react"
7+ import { PiCaretDownFill , PiCaretUpFill , PiMagnifyingGlass } from "react-icons/pi"
8+ import { FiAlertCircle } from "react-icons/fi"
9+
10+ interface DataItem extends Record < string , unknown > {
11+ id : number
12+ name : string
13+ age : number
14+ email : string
15+ department : string
16+ role : string
17+ status : string
18+ }
19+
20+ const columns : Column < DataItem > [ ] = [
21+ {
22+ id : "name" ,
23+ header : "Name" ,
24+ accessorKey : "name" ,
25+ sortable : true ,
26+ } ,
27+ {
28+ id : "department" ,
29+ header : "Department" ,
30+ accessorKey : "department" ,
31+ sortable : true ,
32+ } ,
33+ {
34+ id : "role" ,
35+ header : "Role" ,
36+ accessorKey : "role" ,
37+ sortable : true ,
38+ } ,
39+ {
40+ id : "status" ,
41+ header : "Status" ,
42+ accessorKey : "status" ,
43+ sortable : true ,
44+ } ,
45+ {
46+ id : "email" ,
47+ header : "Email" ,
48+ accessorKey : "email" ,
49+ sortable : true ,
50+ } ,
51+ ]
52+
53+ // Custom Components
54+ const CustomHeader = ( {
55+ column,
56+ sortIcon,
57+ onSort
58+ } : {
59+ column : Column < DataItem >
60+ sortIcon ?: React . ReactNode
61+ onSort ?: ( ) => void
62+ } ) => {
63+ const sortDirection = sortIcon ?. toString ( ) . includes ( "PiCaretUpFill" ) ? "asc" : "desc"
64+
65+ return (
66+ < div className = "flex items-center justify-between px-4 py-3" >
67+ < span className = "font-medium text-gray-700 dark:text-gray-200" >
68+ { typeof column . header === 'function' ? column . header ( ) : column . header }
69+ </ span >
70+ { column . sortable && (
71+ < button
72+ onClick = { onSort }
73+ className = "ml-2 p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors"
74+ type = "button"
75+ >
76+ { sortIcon ? (
77+ < div className = "text-blue-500 dark:text-blue-400" >
78+ { sortDirection === "asc" ? (
79+ < PiCaretUpFill size = { 16 } />
80+ ) : (
81+ < PiCaretDownFill size = { 16 } />
82+ ) }
83+ </ div >
84+ ) : (
85+ < PiCaretDownFill size = { 16 } className = "text-gray-400" />
86+ ) }
87+ </ button >
88+ ) }
89+ </ div >
90+ )
91+ }
92+
93+ const CustomCell = ( { value, column } : { value : unknown ; column : Column < DataItem > } ) => {
94+ if ( column . accessorKey === 'status' ) {
95+ const statusColors : Record < string , string > = {
96+ active : 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' ,
97+ inactive : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' ,
98+ pending : 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200' ,
99+ }
100+
101+ const status = String ( value ) . toLowerCase ( )
102+ const colorClass = statusColors [ status ] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200'
103+
104+ return (
105+ < span className = { `px-3 py-1 rounded-full text-sm font-medium ${ colorClass } ` } >
106+ { String ( value ) }
107+ </ span >
108+ )
109+ }
110+
111+ return (
112+ < div className = "px-4 py-3 text-gray-700 dark:text-gray-200" >
113+ { String ( value ) }
114+ </ div >
115+ )
116+ }
117+
118+ const CustomEmptyState = ( ) => (
119+ < div className = "flex flex-col items-center justify-center p-8 bg-white dark:bg-gray-800 rounded-lg shadow-sm" >
120+ < FiAlertCircle className = "w-12 h-12 text-gray-400 mb-4" />
121+ < h3 className = "text-lg font-medium text-gray-900 dark:text-white" > No Results Found</ h3 >
122+ < p className = "text-gray-500 dark:text-gray-400 text-center mt-2 max-w-sm" >
123+ We couldn't find any items matching your criteria. Try adjusting your search or filters.
124+ </ p >
125+ </ div >
126+ )
127+
128+ const CustomLoadingState = ( ) => (
129+ < div className = "flex flex-col items-center justify-center p-8" >
130+ < div className = "relative" >
131+ < div className = "w-12 h-12 rounded-full border-4 border-gray-200 dark:border-gray-700 animate-pulse" />
132+ < div className = "absolute top-0 left-0 w-12 h-12 rounded-full border-4 border-blue-500 dark:border-blue-400 animate-spin border-t-transparent" />
133+ </ div >
134+ < span className = "mt-4 text-sm text-gray-500 dark:text-gray-400" > Loading data...</ span >
135+ </ div >
136+ )
137+
138+ const CustomSearchInput = ( {
139+ value,
140+ onChange,
141+ placeholder
142+ } : {
143+ value : string
144+ onChange : ( value : string ) => void
145+ placeholder ?: string
146+ } ) => (
147+ < div className = "relative max-w-md w-full" >
148+ < div className = "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none" >
149+ < PiMagnifyingGlass className = "h-5 w-5 text-gray-400" />
150+ </ div >
151+ < input
152+ type = "text"
153+ value = { value }
154+ onChange = { ( e ) => onChange ( e . target . value ) }
155+ placeholder = { placeholder }
156+ className = "block w-full pl-10 pr-4 py-2 border border-gray-200 dark:border-gray-700 rounded-lg
157+ bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
158+ focus:ring-2 focus:ring-blue-500 focus:border-transparent
159+ placeholder-gray-500 dark:placeholder-gray-400
160+ transition-colors duration-200"
161+ />
162+ </ div >
163+ )
164+
165+ const CustomizedTable = ( ) => {
166+ const [ isLoading , setIsLoading ] = useState ( true )
167+ const [ showEmpty , setShowEmpty ] = useState ( false )
168+
169+ const {
170+ filteredData,
171+ handleSort,
172+ sortColumn,
173+ sortDirection,
174+ setFilterValue,
175+ filterValue,
176+ } = useTableGrid < DataItem > ( {
177+ data : showEmpty ? [ ] : dummyData ,
178+ columns,
179+ enableFuzzySearch : true ,
180+ } )
181+
182+ useEffect ( ( ) => {
183+ const timer = setTimeout ( ( ) => {
184+ setIsLoading ( false )
185+ } , 2000 )
186+ return ( ) => clearTimeout ( timer )
187+ } , [ ] )
188+
189+ return (
190+ < div className = "p-6 space-y-6" >
191+ < div className = "flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4" >
192+ < div >
193+ < h2 className = "text-2xl font-semibold text-gray-900 dark:text-white" >
194+ Team Members
195+ </ h2 >
196+ < p className = "mt-1 text-sm text-gray-500 dark:text-gray-400" >
197+ Manage your team members and their account permissions here.
198+ </ p >
199+ </ div >
200+ < div className = "flex gap-3" >
201+ < button
202+ onClick = { ( ) => setIsLoading ( ( prev ) => ! prev ) }
203+ className = "inline-flex items-center px-4 py-2 border border-transparent
204+ text-sm font-medium rounded-lg shadow-sm text-white
205+ bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2
206+ focus:ring-offset-2 focus:ring-blue-500 transition-colors"
207+ >
208+ Toggle Loading
209+ </ button >
210+ < button
211+ onClick = { ( ) => setShowEmpty ( ( prev ) => ! prev ) }
212+ className = "inline-flex items-center px-4 py-2 border border-gray-300
213+ dark:border-gray-600 text-sm font-medium rounded-lg shadow-sm
214+ text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800
215+ hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none
216+ focus:ring-2 focus:ring-offset-2 focus:ring-blue-500
217+ transition-colors"
218+ >
219+ Toggle Empty
220+ </ button >
221+ </ div >
222+ </ div >
223+
224+ < TableGrid < DataItem >
225+ columns = { columns }
226+ data = { filteredData }
227+ gridTemplateColumns = "repeat(5, 1fr)"
228+ maxHeight = "600px"
229+ variant = "modern"
230+ onSort = { handleSort }
231+ sortColumn = { sortColumn }
232+ sortDirection = { sortDirection }
233+ enableFuzzySearch = { true }
234+ filterValue = { filterValue }
235+ onFilterChange = { setFilterValue }
236+ isLoading = { isLoading }
237+ components = { {
238+ Header : CustomHeader ,
239+ Cell : CustomCell ,
240+ EmptyState : CustomEmptyState ,
241+ LoadingState : CustomLoadingState ,
242+ SearchInput : CustomSearchInput ,
243+ } }
244+ styleConfig = { {
245+ container : {
246+ className : "border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800 shadow-sm" ,
247+ } ,
248+ headerCell : {
249+ className : "border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800" ,
250+ } ,
251+ row : {
252+ className : "border-b border-gray-100 dark:border-gray-700/50 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors" ,
253+ } ,
254+ searchContainer : {
255+ className : "mb-4" ,
256+ } ,
257+ } }
258+ />
259+ </ div >
260+ )
261+ }
262+
263+ export default CustomizedTable
0 commit comments