// Enhanced DataTable Component with hierarchical headers and column fixing
// const DataTable = ({ data, columns, onCellClick, title, searchable = true, groupedColumns = null, fixedColumns = [] }) => {
// const [searchTerm, setSearchTerm] = useState('');
// const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' });
// const [columnSettings, setColumnSettings] = useState(false);
// const [fixedCols, setFixedCols] = useState(fixedColumns);
// if (!data || data.length === 0) {
// return (
// <div className="bg-white/90 backdrop-blur-xl rounded-3xl shadow-2xl border border-white/20 p-16 text-center relative overflow-hidden">
// <div className="absolute inset-0 bg-gradient-to-br from-blue-50/60 to-purple-50/60"></div>
// <div className="relative z-10">
// <div className="w-24 h-24 bg-gradient-to-br from-slate-200 to-slate-300 rounded-full flex items-center justify-center mx-auto mb-8 shadow-xl">
// <Database className="h-12 w-12 text-slate-500" />
// </div>
// <h3 className="text-2xl font-bold text-slate-800 mb-3">No Data Available</h3>
// <p className="text-slate-500 text-lg">Check back later or adjust your filters</p>
// </div>
// </div>
// );
// }
// const filteredData = searchable ? data?.filter(row =>
// Object.values(row).some(value =>
// String(value).toLowerCase().includes(searchTerm.toLowerCase())
// )
// ) : data;
// const sortedData = sortConfig.key
// ? [...filteredData].sort((a, b) => {
// if (a[sortConfig.key] < b[sortConfig.key]) {
// return sortConfig.direction === 'asc' ? -1 : 1;
// }
// if (a[sortConfig.key] > b[sortConfig.key]) {
// return sortConfig.direction === 'asc' ? 1 : -1;
// }
// return 0;
// })
// : filteredData;
// const handleSort = (key) => {
// setSortConfig({
// key,
// direction: sortConfig.key === key && sortConfig.direction === 'asc' ? 'desc' : 'asc'
// });
// };
// const toggleColumnFixed = (columnKey) => {
// setFixedCols(prev =>
// prev.includes(columnKey)
// ? prev.filter(key => key !== columnKey)
// : [...prev, columnKey]
// );
// };
// const isColumnFixed = (columnKey) => fixedCols.includes(columnKey);
// // Calculate fixed columns width
// const getFixedColumnsWidth = () => {
// const allColumns = groupedColumns ? groupedColumns.flatMap(g => g.columns) : columns;
// return fixedCols.reduce((width, colKey) => {
// const col = allColumns.find(c => c.key === colKey);
// return width + (col?.width || 150); // default width
// }, 0);
// };
// // Column Settings Panel
// const ColumnSettingsPanel = () => {
// const allColumns = groupedColumns ? groupedColumns.flatMap(g => g.columns) : columns;
// return (
// <div className={`fixed top-full right-0 mt-2 bg-white/95 backdrop-blur-xl rounded-2xl shadow-2xl border border-white/30 p-6 w-80 z-50 transform transition-all duration-300 ${columnSettings ? 'scale-100 opacity-100' : 'scale-95 opacity-0 pointer-events-none'}`}>
// <div className="flex items-center justify-between mb-4">
// <h4 className="text-lg font-bold text-slate-800">Column Settings</h4>
// <button
// onClick={() => setColumnSettings(false)}
// className="p-2 hover:bg-slate-100 rounded-xl transition-colors"
// >
// <XCircle className="h-5 w-5 text-slate-500" />
// </button>
// </div>
// <div className="space-y-3 max-h-96 overflow-y-auto">
// {allColumns.map(col => (
// <div key={col.key} className="flex items-center justify-between p-3 bg-slate-50/50 rounded-xl hover:bg-slate-100/50 transition-colors">
// <div className="flex-1">
// <div className="font-medium text-slate-700">{col.title}</div>
// <div className="text-sm text-slate-500">{col.key}</div>
// </div>
// <button
// onClick={() => toggleColumnFixed(col.key)}
// className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
// isColumnFixed(col.key)
// ? 'bg-blue-500 text-white shadow-lg'
// : 'bg-white border border-slate-200 text-slate-600 hover:bg-blue-50 hover:border-blue-200'
// }`}
// >
// {isColumnFixed(col.key) ? (
// <>
// <CheckCircle className="h-4 w-4" />
// Fixed
// </>
// ) : (
// <>
// <Database className="h-4 w-4" />
// Fix
// </>
// )}
// </button>
// </div>
// ))}
// </div>
// </div>
// );
// };
// // Render regular table headers
// const renderRegularHeaders = () => (
// <tr className="bg-gradient-to-r from-slate-100/95 to-slate-200/95 backdrop-blur-sm">
// {columns.map(col => (
// <th
// key={col.key}
// className={`px-6 py-5 text-left text-sm font-bold text-slate-700 uppercase tracking-wider border-r border-white/50 last:border-r-0 transition-all duration-200 ${
// isColumnFixed(col.key)
// ? 'sticky left-0 bg-gradient-to-r from-blue-100/95 to-indigo-100/95 z-20 shadow-lg'
// : ''
// } ${
// col.sortable ? 'cursor-pointer hover:bg-slate-200/70 group' : ''
// }`}
// onClick={() => col.sortable && handleSort(col.key)}
// style={isColumnFixed(col.key) ? { left: `${getFixedColumnsWidth() - (col.width || 150)}px` } : {}}
// >
// <div className="flex items-center gap-3">
// <span className="group-hover:text-blue-600 transition-colors">{col.title}</span>
// {isColumnFixed(col.key) && (
// <div className="w-2 h-2 bg-blue-500 rounded-full animate-pulse"></div>
// )}
// {col.sortable && (
// <ChevronRight
// className={`h-4 w-4 transition-all duration-300 ${
// sortConfig.key === col.key
// ? sortConfig.direction === 'desc' ? 'rotate-90 text-blue-600' : '-rotate-90 text-blue-600'
// : 'opacity-0 group-hover:opacity-70'
// }`}
// />
// )}
// </div>
// </th>
// ))}
// </tr>
// );
// // Render grouped headers for warehouse table
// const renderGroupedHeaders = () => {
// return (
// <>
// {/* Main group headers */}
// <tr className="bg-gradient-to-r from-blue-700 to-purple-700 text-white">
// {groupedColumns.map((group, idx) => (
// <th
// key={idx}
// colSpan={group.columns.length}
// className="px-6 py-6 text-center text-sm font-bold uppercase tracking-wider border-r border-white/30 last:border-r-0 relative overflow-hidden"
// >
// <div className="absolute inset-0 bg-gradient-to-br from-white/10 to-transparent"></div>
// <div className="relative flex items-center justify-center gap-3">
// {group.icon && (
// <div className="p-2 bg-white/20 rounded-xl">
// <group.icon className="h-5 w-5" />
// </div>
// )}
// <span className="text-lg font-extrabold">{group.title}</span>
// </div>
// </th>
// ))}
// </tr>
// {/* Sub headers */}
// <tr className="bg-gradient-to-r from-slate-50/98 to-slate-100/98 backdrop-blur-sm border-b-2 border-slate-200">
// {groupedColumns.map(group =>
// group.columns.map(col => {
// const fixedLeft = isColumnFixed(col.key) ?
// fixedCols.slice(0, fixedCols.indexOf(col.key))
// .reduce((acc, key) => acc + 150, 0) : 0;
// return (
// <th
// key={col.key}
// className={`px-4 py-4 text-left text-xs font-bold text-slate-700 uppercase tracking-wider border-r border-slate-200/50 last:border-r-0 transition-all duration-200 ${
// isColumnFixed(col.key)
// ? 'sticky left-0 bg-gradient-to-r from-blue-50/98 to-indigo-50/98 z-20 shadow-lg border-r-2 border-blue-200'
// : ''
// } ${
// col.sortable ? 'cursor-pointer hover:bg-slate-200/60 group' : ''
// }`}
// onClick={() => col.sortable && handleSort(col.key)}
// style={isColumnFixed(col.key) ? { left: `${fixedLeft}px` } : {}}
// >
// <div className="flex items-center gap-2">
// <span className={`group-hover:text-blue-600 transition-colors font-semibold ${col.clickable ? 'text-blue-600' : ''}`}>
// {col.title}
// </span>
// {isColumnFixed(col.key) && (
// <div className="w-1.5 h-1.5 bg-blue-500 rounded-full animate-pulse"></div>
// )}
// {col.sortable && (
// <ChevronRight
// className={`h-3 w-3 transition-all duration-300 ${
// sortConfig.key === col.key
// ? sortConfig.direction === 'desc' ? 'rotate-90 text-blue-600' : '-rotate-90 text-blue-600'
// : 'opacity-0 group-hover:opacity-70'
// }`}
// />
// )}
// </div>
// </th>
// );
// })
// )}
// </tr>
// </>
// );
// };
// return (
// <div className="bg-white/95 backdrop-blur-2xl rounded-3xl shadow-2xl border border-white/40 overflow-hidden relative">
// {/* Enhanced gradient overlay */}
// <div className="absolute inset-0 bg-gradient-to-br from-blue-50/40 via-transparent to-purple-50/40 pointer-events-none"></div>
// {/* Enhanced Header */}
// <div className="relative z-10 p-8 bg-gradient-to-r from-slate-50/90 to-slate-100/90 backdrop-blur-sm border-b-2 border-white/30">
// <div className="flex items-center justify-between">
// <div className="flex items-center gap-6">
// <div className="p-4 bg-gradient-to-br from-blue-600 to-purple-600 rounded-2xl shadow-xl">
// <BarChart3 className="h-8 w-8 text-white" />
// </div>
// <div>
// <h3 className="text-2xl font-bold bg-gradient-to-r from-slate-900 to-slate-700 bg-clip-text text-transparent">
// {title}
// </h3>
// <p className="text-slate-500 mt-1 text-lg">Advanced interactive data analysis</p>
// </div>
// </div>
// <div className="flex items-center gap-4">
// {/* Column Settings Button */}
// <div className="relative">
// <button
// onClick={() => setColumnSettings(!columnSettings)}
// className="flex items-center gap-2 px-4 py-3 bg-white/80 backdrop-blur border border-slate-200 rounded-xl hover:bg-blue-50 hover:border-blue-300 transition-all duration-300 shadow-lg hover:shadow-xl group"
// >
// <Database className="h-5 w-5 text-slate-600 group-hover:text-blue-600 transition-colors" />
// <span className="text-sm font-medium text-slate-700 group-hover:text-blue-700">Column Settings</span>
// </button>
// <ColumnSettingsPanel />
// </div>
// {/* Enhanced Search */}
// {searchable && (
// <div className="relative group">
// <Search className="h-5 w-5 absolute left-4 top-1/2 transform -translate-y-1/2 text-slate-400 group-focus-within:text-blue-600 transition-colors" />
// <input
// type="text"
// placeholder="Search across all data..."
// value={searchTerm}
// onChange={(e) => setSearchTerm(e.target.value)}
// className="pl-12 pr-6 py-3 w-96 bg-white/90 backdrop-blur-sm border border-slate-200 rounded-xl focus:ring-4 focus:ring-blue-500/20 focus:border-blue-400 transition-all duration-300 shadow-lg hover:shadow-xl text-slate-700 placeholder-slate-400"
// />
// <div className="absolute inset-0 bg-gradient-to-r from-blue-500/5 to-purple-500/5 rounded-xl opacity-0 group-focus-within:opacity-100 transition-opacity duration-300 pointer-events-none"></div>
// </div>
// )}
// </div>
// </div>
// {/* Fixed columns indicator */}
// {fixedCols.length > 0 && (
// <div className="mt-4 flex items-center gap-2">
// <div className="flex items-center gap-2 px-3 py-2 bg-blue-100/80 rounded-xl">
// <CheckCircle className="h-4 w-4 text-blue-600" />
// <span className="text-sm font-medium text-blue-800">{fixedCols.length} Fixed Column{fixedCols.length > 1 ? 's' : ''}</span>
// </div>
// </div>
// )}
// </div>
// {/* Enhanced Table */}
// <div className="relative z-10 overflow-x-auto">
// <table className="w-full">
// <thead>
// {groupedColumns ? renderGroupedHeaders() : renderRegularHeaders()}
// </thead>
// <tbody className="divide-y divide-slate-100/80">
// {sortedData.map((row, idx) => (
// <tr key={idx} className="hover:bg-gradient-to-r hover:from-blue-50/60 hover:to-purple-50/60 transition-all duration-300 group relative">
// {(groupedColumns ? groupedColumns.flatMap(g => g.columns) : columns).map(col => {
// const fixedLeft = isColumnFixed(col.key) ?
// fixedCols.slice(0, fixedCols.indexOf(col.key))
// .reduce((acc, key) => acc + 150, 0) : 0;
// return (
// <td
// key={col.key}
// className={`px-4 py-5 whitespace-nowrap text-sm border-r border-slate-100/60 last:border-r-0 relative transition-all duration-200 ${
// isColumnFixed(col.key)
// ? 'sticky left-0 bg-gradient-to-r from-blue-50/90 to-indigo-50/90 z-10 shadow-lg border-r-2 border-blue-200'
// : ''
// } ${
// col.clickable
// ? 'text-blue-600 hover:text-blue-800 cursor-pointer font-semibold hover:bg-blue-50/40 transition-all duration-300'
// : col.fixed
// ? 'text-slate-900 font-bold bg-slate-50/60'
// : 'text-slate-700'
// }`}
// onClick={() => col.clickable && onCellClick && onCellClick(row, col)}
// style={isColumnFixed(col.key) ? { left: `${fixedLeft}px` } : {}}
// >
// {col.clickable && (
// <div className="absolute inset-0 bg-gradient-to-r from-blue-100/0 via-blue-100/40 to-blue-100/0 transform scale-x-0 group-hover:scale-x-100 transition-transform duration-300 origin-left"></div>
// )}
// <span className="relative z-10 font-medium">
// {col.render ? col.render(row[col.key], row) : (row[col.key] || 0)}
// </span>
// {col.clickable && (
// <div className="absolute right-3 top-1/2 transform -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
// <ChevronRight className="h-3 w-3 text-blue-500" />
// </div>
// )}
// </td>
// );
// })}
// </tr>
// ))}
// </tbody>
// </table>
// </div>
// {/* Enhanced Footer */}
// <div className="relative z-10 px-8 py-6 bg-gradient-to-r from-slate-50/90 to-slate-100/90 backdrop-blur-sm border-t-2 border-white/30">
// <div className="flex items-center justify-between">
// <div className="flex items-center gap-6">
// <div className="text-sm text-slate-600">
// Showing <span className="font-bold text-slate-900 text-lg">{sortedData.length}</span> of <span className="font-bold text-slate-900 text-lg">{data.length}</span> records
// </div>
// {searchTerm && (
// <div className="flex items-center gap-2 px-3 py-1 bg-blue-100/60 rounded-full">
// <Search className="h-3 w-3 text-blue-600" />
// <span className="text-xs font-medium text-blue-700">Filtered results</span>
// </div>
// )}
// </div>
// <div className="flex items-center gap-4">
// <div className="flex items-center gap-2 text-sm text-slate-500">
// <div className="w-2 h-2 bg-emerald-400 rounded-full animate-pulse shadow-lg"></div>
// <span className="font-medium">Real-time data</span>
// </div>
// <div className="text-xs text-slate-400">
// Last updated: {new Date().toLocaleTimeString()}
// </div>
// </div>
// </div>
// </div>
// </div>
// );
// };
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)