Spaces:
Running
Running
James McCool
Add comprehensive BUILD_GUIDE.md for building a MongoDB Data Viewer React app, detailing setup, CSS architecture, component design, and deployment to Hugging Face. Update DataTable component sort indicator from 'βοΈ' to 'β΅' for improved clarity.
1bcf29b
import React, { useState, useEffect } from 'react'; | |
import { Table, TableHeader, TableBody, TableHead, TableRow, TableCell, TableCaption } from './ui/table'; | |
import { Button } from './ui/button'; | |
const DataTable = () => { | |
const [data, setData] = useState([]); | |
const [loading, setLoading] = useState(true); | |
const [error, setError] = useState(null); | |
const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); | |
// Mock data for demonstration - replace with actual MongoDB data | |
const mockData = [ | |
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Developer' }, | |
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'Designer' }, | |
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Manager' }, | |
{ id: 4, name: 'Alice Brown', email: 'alice@example.com', role: 'Developer' }, | |
{ id: 5, name: 'Charlie Wilson', email: 'charlie@example.com', role: 'Designer' }, | |
]; | |
useEffect(() => { | |
// Simulate loading data | |
setTimeout(() => { | |
setData(mockData); | |
setLoading(false); | |
}, 1000); | |
}, []); | |
// Sorting function | |
const sortData = (key) => { | |
let direction = 'asc'; | |
// Three-state sorting: asc β desc β none | |
if (sortConfig.key === key) { | |
if (sortConfig.direction === 'asc') { | |
direction = 'desc'; | |
} else if (sortConfig.direction === 'desc') { | |
// Reset to no sorting | |
setSortConfig({ key: null, direction: 'none' }); | |
return; | |
} | |
} | |
setSortConfig({ key, direction }); | |
}; | |
// Get sorted data | |
const getSortedData = () => { | |
if (!sortConfig.key || sortConfig.direction === 'none') return data; | |
return [...data].sort((a, b) => { | |
let aValue = a[sortConfig.key]; | |
let bValue = b[sortConfig.key]; | |
// Handle string comparison (case-insensitive) | |
if (typeof aValue === 'string') { | |
aValue = aValue.toLowerCase(); | |
bValue = bValue.toLowerCase(); | |
} | |
if (aValue < bValue) { | |
return sortConfig.direction === 'asc' ? -1 : 1; | |
} | |
if (aValue > bValue) { | |
return sortConfig.direction === 'asc' ? 1 : -1; | |
} | |
return 0; | |
}); | |
}; | |
// Get sort indicator for column headers | |
const getSortIndicator = (key) => { | |
if (sortConfig.key !== key) return 'β΅'; | |
if (sortConfig.direction === 'asc') return 'β'; | |
if (sortConfig.direction === 'desc') return 'β'; | |
return 'β΅'; | |
}; | |
const fetchFromMongoDB = async () => { | |
try { | |
setLoading(true); | |
// Replace this with your actual MongoDB connection logic | |
// const response = await fetch('/api/data'); | |
// const result = await response.json(); | |
// setData(result); | |
// For now, using mock data | |
setData(mockData); | |
} catch (err) { | |
setError('Failed to fetch data'); | |
} finally { | |
setLoading(false); | |
} | |
}; | |
if (loading) { | |
return ( | |
<div className="flex items-center justify-center p-8"> | |
<div className="text-lg text-muted-foreground">Loading...</div> | |
</div> | |
); | |
} | |
if (error) { | |
return ( | |
<div className="flex items-center justify-center p-8"> | |
<div className="text-red-500">{error}</div> | |
</div> | |
); | |
} | |
const sortedData = getSortedData(); | |
return ( | |
<div className="w-full mx-auto p-6"> | |
<div className="flex justify-between items-center mb-6"> | |
<h2 className="text-2xl font-bold text-foreground">Interesting Mock Data</h2> | |
<Button onClick={fetchFromMongoDB}> | |
Refresh Data | |
</Button> | |
</div> | |
<div className="border rounded-lg bg-card"> | |
<Table> | |
<TableCaption>A list of users from the database.</TableCaption> | |
<TableHeader> | |
<TableRow> | |
<TableHead | |
className="cursor-pointer hover:bg-muted/50 transition-colors" | |
onClick={() => sortData('id')} | |
> | |
ID {getSortIndicator('id')} | |
</TableHead> | |
<TableHead | |
className="cursor-pointer hover:bg-muted/50 transition-colors" | |
onClick={() => sortData('name')} | |
> | |
Name {getSortIndicator('name')} | |
</TableHead> | |
<TableHead | |
className="cursor-pointer hover:bg-muted/50 transition-colors" | |
onClick={() => sortData('email')} | |
> | |
Email {getSortIndicator('email')} | |
</TableHead> | |
<TableHead | |
className="cursor-pointer hover:bg-muted/50 transition-colors" | |
onClick={() => sortData('role')} | |
> | |
Role {getSortIndicator('role')} | |
</TableHead> | |
</TableRow> | |
</TableHeader> | |
<TableBody> | |
{sortedData.map((user) => ( | |
<TableRow key={user.id}> | |
<TableCell className="font-medium">{user.id}</TableCell> | |
<TableCell>{user.name}</TableCell> | |
<TableCell>{user.email}</TableCell> | |
<TableCell>{user.role}</TableCell> | |
</TableRow> | |
))} | |
</TableBody> | |
</Table> | |
</div> | |
</div> | |
); | |
}; | |
export default DataTable; | |