--- import DashboardLayout from '../../layouts/DashboardLayout.astro'; import { Icon } from 'astro-icon/components'; import { db } from '../../db'; import { organizations, members, timeEntries, clients, categories } from '../../db/schema'; import { eq, desc, and, isNull, gte, sql } from 'drizzle-orm'; import { formatDuration } from '../../lib/formatTime'; const user = Astro.locals.user; if (!user) return Astro.redirect('/login'); // Get current team from cookie or first membership const currentTeamId = Astro.cookies.get('currentTeamId')?.value; const userOrgs = await db.select({ id: organizations.id, name: organizations.name, role: members.role, organizationId: members.organizationId, }) .from(members) .innerJoin(organizations, eq(members.organizationId, organizations.id)) .where(eq(members.userId, user.id)) .all(); // Use current team or fallback to first const currentOrg = currentTeamId ? userOrgs.find(o => o.organizationId === currentTeamId) || userOrgs[0] : userOrgs[0]; let stats = { totalTimeThisWeek: 0, totalTimeThisMonth: 0, activeTimers: 0, totalClients: 0, recentEntries: [] as any[], }; if (currentOrg) { const now = new Date(); const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); const weekStats = await db.select({ totalDuration: sql`sum(${timeEntries.endTime} - ${timeEntries.startTime})` }) .from(timeEntries) .where(and( eq(timeEntries.organizationId, currentOrg.organizationId), gte(timeEntries.startTime, weekAgo), sql`${timeEntries.endTime} IS NOT NULL` )) .get(); stats.totalTimeThisWeek = weekStats?.totalDuration || 0; const monthStats = await db.select({ totalDuration: sql`sum(${timeEntries.endTime} - ${timeEntries.startTime})` }) .from(timeEntries) .where(and( eq(timeEntries.organizationId, currentOrg.organizationId), gte(timeEntries.startTime, monthAgo), sql`${timeEntries.endTime} IS NOT NULL` )) .get(); stats.totalTimeThisMonth = monthStats?.totalDuration || 0; const activeCount = await db.select({ count: sql`count(*)` }) .from(timeEntries) .where(and( eq(timeEntries.organizationId, currentOrg.organizationId), isNull(timeEntries.endTime) )) .get(); stats.activeTimers = activeCount?.count || 0; const clientCount = await db.select({ count: sql`count(*)` }) .from(clients) .where(eq(clients.organizationId, currentOrg.organizationId)) .get(); stats.totalClients = clientCount?.count || 0; stats.recentEntries = await db.select({ entry: timeEntries, client: clients, category: categories, }) .from(timeEntries) .innerJoin(clients, eq(timeEntries.clientId, clients.id)) .innerJoin(categories, eq(timeEntries.categoryId, categories.id)) .where(eq(timeEntries.organizationId, currentOrg.organizationId)) .orderBy(desc(timeEntries.startTime)) .limit(5) .all(); } const hasMembership = userOrgs.length > 0; ---

Dashboard

Welcome back, {user.name}!

New Team
{!hasMembership && (

Welcome to Chronus!

You're not part of any team yet. Create one or wait for an invitation.
New Team
)} {hasMembership && ( <>
This Week
{formatDuration(stats.totalTimeThisWeek)}
Total tracked time
This Month
{formatDuration(stats.totalTimeThisMonth)}
Total tracked time
Active Timers
{stats.activeTimers}
Currently running
Clients
{stats.totalClients}
Total active

Recent Activity

{stats.recentEntries.length > 0 ? (
    {stats.recentEntries.map(({ entry, client, category }) => (
  • {client.name}
    {category.name} • {entry.endTime ? formatDuration(entry.endTime.getTime() - entry.startTime.getTime()) : 'Running...'}
  • ))}
) : (

No recent time entries

)}
)}