diff --git a/src/components/admin/CollectionTable.tsx b/src/components/admin/CollectionTable.tsx new file mode 100644 index 0000000..b5de3a5 --- /dev/null +++ b/src/components/admin/CollectionTable.tsx @@ -0,0 +1,141 @@ +import { useState, useEffect } from 'react'; + +interface CollectionTableProps { + endpoint: string; + columns: string[]; + title?: string; +} + +export default function CollectionTable({ endpoint, columns, title }: CollectionTableProps) { + const [data, setData] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [page, setPage] = useState(0); + const [total, setTotal] = useState(0); + const limit = 50; + + const fetchData = async () => { + setLoading(true); + try { + const token = localStorage.getItem('godToken') || ''; + const response = await fetch(`${endpoint}?limit=${limit}&offset=${page * limit}`, { + headers: { + 'X-God-Token': token + } + }); + + if (!response.ok) { + throw new Error('Failed to fetch data'); + } + + const result = await response.json(); + setData(result.data || []); + setTotal(result.meta?.total || 0); + } catch (err: any) { + setError(err.message); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, [endpoint, page]); + + if (loading) { + return ( +
+
Loading...
+
+ ); + } + + if (error) { + return ( +
+
Error
+
{error}
+
+ ); + } + + return ( +
+ {/* Header */} +
+

{title || 'Collection'}

+
+ {total} total items +
+
+ + {/* Table */} +
+ + + + {columns.map(col => ( + + ))} + + + + + {data.length === 0 ? ( + + + + ) : ( + data.map((item, idx) => ( + + {columns.map(col => ( + + ))} + + + )) + )} + +
+ {col.replace(/_/g, ' ')} + + Actions +
+ No items found +
+ {typeof item[col] === 'object' + ? JSON.stringify(item[col]).substring(0, 50) + '...' + : item[col] || '-' + } + + +
+
+ + {/* Pagination */} + {total > limit && ( +
+ +
+ Page {page + 1} of {Math.ceil(total / limit)} +
+ +
+ )} +
+ ); +}