import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Clock, Database, Users, FileText, Plus, Loader2, FolderPlus, UserPlus, Activity } from 'lucide-react'; import { Button, Card, CardHeader, CardContent } from '@/components'; import { useDrawingStore, useAuthStore } from '@/stores'; import { api } from '@/services'; import styles from './Dashboard.module.scss'; const ACTIVITY_LIMIT = 5; const StatChart: React.FC<{ value: number; max: number }> = ({ value, max }) => { const pct = max > 0 ? Math.min((value / max) * 100, 100) : 0; return (
); }; export const Dashboard: React.FC = () => { const { t } = useTranslation(); const navigate = useNavigate(); const { recentDrawings, setRecentDrawings, activity, setActivity } = useDrawingStore(); const { user } = useAuthStore(); const [isCreating, setIsCreating] = useState(false); const [statsData, setStatsData] = useState({ teams: 0, members: 0, projects: 0, folders: 0, drawings: 0, templates: 0, revisions: 0, assets: 0, storage_bytes: 0, }); useEffect(() => { const loadData = async () => { try { const [drawings, stats, activityData] = await Promise.all([ api.drawings.list(), api.stats.get(), api.activity.list(), ]); setRecentDrawings(drawings); setStatsData(stats); setActivity(activityData); } catch (err) { console.error('Failed to load dashboard data:', err); } }; loadData(); }, [setRecentDrawings, setActivity]); const handleCreateDrawing = async () => { setIsCreating(true); try { const newDrawing = await api.drawings.create({ title: 'Untitled Drawing', visibility: 'team', }); setRecentDrawings([newDrawing, ...recentDrawings]); navigate(`/drawing/${newDrawing.id}`); } catch (err) { console.error('Failed to create drawing:', err); } finally { setIsCreating(false); } }; const formatBytes = (bytes: number) => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`; }; const maxStat = Math.max(statsData.drawings, statsData.projects + statsData.folders, statsData.teams, statsData.revisions, 1); const storageMax = Math.max(Number(statsData.storage_bytes), 1024 * 1024); const stats = [ { label: t('dashboard.stats.drawings'), value: statsData.drawings, chartValue: statsData.drawings, max: maxStat, icon: FileText }, { label: t('dashboard.stats.projects'), value: statsData.projects + statsData.folders, chartValue: statsData.projects + statsData.folders, max: maxStat, icon: FolderPlus }, { label: t('dashboard.stats.teams'), value: statsData.teams, chartValue: statsData.teams, max: maxStat, icon: Users }, { label: t('dashboard.stats.revisions'), value: statsData.revisions, chartValue: statsData.revisions, max: maxStat, icon: Clock }, { label: t('dashboard.stats.storage'), value: formatBytes(Number(statsData.storage_bytes)), chartValue: Number(statsData.storage_bytes), max: storageMax, icon: Database }, ]; const visibleActivity = activity .filter((event) => event.event_type !== 'revision_created') .slice(0, ACTIVITY_LIMIT); return ({t('dashboard.subtitle')}
{t('dashboard.noDrawings')}
{t('dashboard.noDrawingsSub')}
{drawing.title}
Edited {new Date(drawing.updated_at).toLocaleDateString()}
No recent activity
{event.actor?.name || 'Unknown'}{' '} {event.event_type.replace(/_/g, ' ')}{' '} {event.resource_type}
{new Date(event.created_at).toLocaleString()}