feat: redesign dashboard layout with calendar, open sessions, and glass-card panels

New layout: greeting → calendar+actions → sessions+stats → activity
Replaces old QuickStats and SessionsPanel with new dashboard components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-03 08:31:27 -05:00
parent 396453c18a
commit f0bfa08df1

View File

@@ -12,8 +12,7 @@ import { usePinnedFlowsStore } from '@/store/pinnedFlowsStore'
import { useUserPreferencesStore } from '@/store/userPreferencesStore' import { useUserPreferencesStore } from '@/store/userPreferencesStore'
import { usePaginationParams } from '@/hooks/usePaginationParams' import { usePaginationParams } from '@/hooks/usePaginationParams'
import { useCachedQuota } from '@/hooks/useCachedQuota' import { useCachedQuota } from '@/hooks/useCachedQuota'
import { QuickStats } from '@/components/dashboard/QuickStats' // QuickStats and SessionsPanel replaced by new dashboard panels
import { SessionsPanel } from '@/components/dashboard/SessionsPanel'
import { TreeGridView } from '@/components/library/TreeGridView' import { TreeGridView } from '@/components/library/TreeGridView'
import { TreeListView } from '@/components/library/TreeListView' import { TreeListView } from '@/components/library/TreeListView'
import { TreeTableView } from '@/components/library/TreeTableView' import { TreeTableView } from '@/components/library/TreeTableView'
@@ -22,6 +21,10 @@ import { AIFlowBuilderModal } from '@/components/ai-builder/AIFlowBuilderModal'
import { CreateFlowDropdown } from '@/components/common/CreateFlowDropdown' import { CreateFlowDropdown } from '@/components/common/CreateFlowDropdown'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { toast } from '@/lib/toast' import { toast } from '@/lib/toast'
import { WeeklyCalendar } from '@/components/dashboard/WeeklyCalendar'
import { QuickActions } from '@/components/dashboard/QuickActions'
import { OpenSessions } from '@/components/dashboard/OpenSessions'
import { RecentActivity } from '@/components/dashboard/RecentActivity'
function timeAgo(dateStr: string): string { function timeAgo(dateStr: string): string {
const now = Date.now() const now = Date.now()
@@ -215,16 +218,22 @@ export function QuickStartPage() {
const now = new Date() const now = new Date()
return d.toDateString() === now.toDateString() return d.toDateString() === now.toDateString()
}).length }).length
const completedSessions = allSessions.filter(s => s.completed_at).length // completedSessions removed — no longer displayed in new layout
const recentSessionItems = allSessions.slice(0, 5).map(s => ({ // Open sessions for the new panel (3 oldest)
const openSessionItems = activeSessions
.sort((a, b) => new Date(a.started_at).getTime() - new Date(b.started_at).getTime())
.slice(0, 3)
.map(s => ({
id: s.id, id: s.id,
treeName: s.tree_snapshot?.name || 'Unknown', treeName: s.tree_snapshot?.name || 'Unknown',
status: (s.completed_at ? 'completed' : 'in_progress') as 'completed' | 'in_progress', treeId: s.tree_id,
ticketNumber: s.ticket_number || undefined, treeType: (s.tree_snapshot as unknown as Record<string, unknown>)?.tree_type as string | undefined,
timeAgo: timeAgo(s.started_at), timeAgo: timeAgo(s.started_at),
})) }))
// recentSessionItems removed — replaced by RecentActivity component
// Favorites display // Favorites display
const MAX_VISIBLE_FAVORITES = 8 const MAX_VISIBLE_FAVORITES = 8
const visibleFavorites = showAllFavorites ? pinnedItems : pinnedItems.slice(0, MAX_VISIBLE_FAVORITES) const visibleFavorites = showAllFavorites ? pinnedItems : pinnedItems.slice(0, MAX_VISIBLE_FAVORITES)
@@ -270,27 +279,61 @@ export function QuickStartPage() {
return ( return (
<div className="p-6 space-y-6"> <div className="p-6 space-y-6">
{/* Page Header */} {/* Greeting */}
<div className="flex items-start justify-between"> <div className="fade-in" style={{ animationDelay: '100ms' }}>
<div> <h1 className="font-heading text-4xl font-extrabold tracking-tight text-foreground">
<h1 className="font-heading text-[1.375rem] font-bold tracking-tight text-foreground"> Good {new Date().getHours() < 12 ? 'morning' : new Date().getHours() < 18 ? 'afternoon' : 'evening'}, {user?.name?.split(' ')[0] || 'there'}
Dashboard
</h1> </h1>
<p className="mt-1 text-sm text-muted-foreground"> <p className="mt-1 text-sm text-muted-foreground">
Welcome back. Here&apos;s what&apos;s happening with your flows. {new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}
</p> </p>
</div> </div>
{/* Row 1: Calendar + Quick Actions */}
<div className="flex gap-4" style={{ alignItems: 'stretch' }}>
<div className="flex-1 min-w-0">
<WeeklyCalendar />
</div>
<div className="w-72 shrink-0">
<QuickActions />
</div>
</div> </div>
{/* Quick Stats */} {/* Row 2: Open Sessions + Stats 2x2 */}
<QuickStats <div className="flex gap-4" style={{ alignItems: 'stretch' }}>
stats={[ <div className="flex-1 min-w-0">
{ label: 'My Flows', value: myFlows.length, gradient: true }, <OpenSessions sessions={openSessionItems} />
{ label: 'Sessions Today', value: todaySessions, color: '#f59e0b' }, </div>
{ label: 'Open Sessions', value: openSessions, meta: `${completedSessions} completed` }, <div className="w-72 shrink-0">
<div className="grid grid-cols-2 gap-3 h-full">
{[
{ label: 'Active Flows', value: myFlows.length, gradient: true, glow: true },
{ label: 'This Week', value: todaySessions },
{ label: 'Open Sessions', value: openSessions },
{ label: 'Favorites', value: pinnedItems.length }, { label: 'Favorites', value: pinnedItems.length },
]} ].map((stat, i) => (
/> <div
key={stat.label}
className={cn('glass-card p-4 flex flex-col justify-between fade-in', stat.glow && 'active-glow')}
style={{ animationDelay: `${500 + i * 70}ms` }}
>
<p className="font-label text-[0.625rem] font-medium uppercase tracking-[0.1em] text-muted-foreground">
{stat.label}
</p>
<p className={cn('font-heading text-2xl font-extrabold tracking-tight', stat.gradient && 'text-gradient-brand')}>
{stat.value}
</p>
</div>
))}
</div>
</div>
</div>
{/* Row 3: Recent Activity */}
<RecentActivity />
{/* ── Existing content below ── */}
<div style={{ borderTop: '1px solid var(--glass-border)' }} className="pt-6 space-y-6">
{/* Search */} {/* Search */}
<div ref={searchRef} className="relative"> <div ref={searchRef} className="relative">
@@ -332,9 +375,6 @@ export function QuickStartPage() {
)} )}
</div> </div>
{/* Recent Sessions */}
<SessionsPanel sessions={recentSessionItems} delay={150} />
{/* Favorites Section */} {/* Favorites Section */}
<div> <div>
<div className="mb-3 flex items-center justify-between"> <div className="mb-3 flex items-center justify-between">
@@ -562,6 +602,7 @@ export function QuickStartPage() {
</> </>
)} )}
</div> </div>
</div>
{/* Fork Modal */} {/* Fork Modal */}
{forkTarget && ( {forkTarget && (