From f0bfa08df103471a0d9a62bb769a8671845d2e26 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Tue, 3 Mar 2026 08:31:27 -0500 Subject: [PATCH] feat: redesign dashboard layout with calendar, open sessions, and glass-card panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New layout: greeting → calendar+actions → sessions+stats → activity Replaces old QuickStats and SessionsPanel with new dashboard components Co-Authored-By: Claude Opus 4.6 --- frontend/src/pages/QuickStartPage.tsx | 597 ++++++++++++++------------ 1 file changed, 319 insertions(+), 278 deletions(-) diff --git a/frontend/src/pages/QuickStartPage.tsx b/frontend/src/pages/QuickStartPage.tsx index 69c48b26..deb86fee 100644 --- a/frontend/src/pages/QuickStartPage.tsx +++ b/frontend/src/pages/QuickStartPage.tsx @@ -12,8 +12,7 @@ import { usePinnedFlowsStore } from '@/store/pinnedFlowsStore' import { useUserPreferencesStore } from '@/store/userPreferencesStore' import { usePaginationParams } from '@/hooks/usePaginationParams' import { useCachedQuota } from '@/hooks/useCachedQuota' -import { QuickStats } from '@/components/dashboard/QuickStats' -import { SessionsPanel } from '@/components/dashboard/SessionsPanel' +// QuickStats and SessionsPanel replaced by new dashboard panels import { TreeGridView } from '@/components/library/TreeGridView' import { TreeListView } from '@/components/library/TreeListView' import { TreeTableView } from '@/components/library/TreeTableView' @@ -22,6 +21,10 @@ import { AIFlowBuilderModal } from '@/components/ai-builder/AIFlowBuilderModal' import { CreateFlowDropdown } from '@/components/common/CreateFlowDropdown' import { cn } from '@/lib/utils' 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 { const now = Date.now() @@ -215,15 +218,21 @@ export function QuickStartPage() { const now = new Date() return d.toDateString() === now.toDateString() }).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 => ({ - id: s.id, - treeName: s.tree_snapshot?.name || 'Unknown', - status: (s.completed_at ? 'completed' : 'in_progress') as 'completed' | 'in_progress', - ticketNumber: s.ticket_number || undefined, - timeAgo: timeAgo(s.started_at), - })) + // 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, + treeName: s.tree_snapshot?.name || 'Unknown', + treeId: s.tree_id, + treeType: (s.tree_snapshot as unknown as Record)?.tree_type as string | undefined, + timeAgo: timeAgo(s.started_at), + })) + + // recentSessionItems removed — replaced by RecentActivity component // Favorites display const MAX_VISIBLE_FAVORITES = 8 @@ -270,297 +279,329 @@ export function QuickStartPage() { return (
- {/* Page Header */} -
-
-

- Dashboard -

-

- Welcome back. Here's what's happening with your flows. -

+ {/* Greeting */} +
+

+ Good {new Date().getHours() < 12 ? 'morning' : new Date().getHours() < 18 ? 'afternoon' : 'evening'}, {user?.name?.split(' ')[0] || 'there'} +

+

+ {new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })} +

+
+ + {/* Row 1: Calendar + Quick Actions */} +
+
+ +
+
+
- {/* Quick Stats */} - - - {/* Search */} -
- - setQuery(e.target.value)} - onFocus={() => query.length >= 2 && setShowResults(true)} - placeholder="Search flows, sessions, tags…" - className="w-full rounded-lg border border-border bg-card py-2.5 pl-9 pr-4 text-sm text-foreground placeholder:text-muted-foreground focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/20" - /> - {showResults && ( -
- {isSearching ? ( -
- + {/* Row 2: Open Sessions + Stats 2x2 */} +
+
+ +
+
+
+ {[ + { 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 }, + ].map((stat, i) => ( +
+

+ {stat.label} +

+

+ {stat.value} +

- ) : searchResults.length === 0 ? ( -
No results found
- ) : ( -
    - {searchResults.map((tree) => ( -
  • - -
  • - ))} -
- )} + ))}
- )} +
- {/* Recent Sessions */} - + {/* Row 3: Recent Activity */} + - {/* Favorites Section */} -
-
-

- Favorites - {pinnedItems.length > 0 && ( - ({pinnedItems.length}) - )} -

- {hasMoreFavorites && ( - + {/* ── Existing content below ── */} +
+ + {/* Search */} +
+ + setQuery(e.target.value)} + onFocus={() => query.length >= 2 && setShowResults(true)} + placeholder="Search flows, sessions, tags…" + className="w-full rounded-lg border border-border bg-card py-2.5 pl-9 pr-4 text-sm text-foreground placeholder:text-muted-foreground focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/20" + /> + {showResults && ( +
+ {isSearching ? ( +
+ +
+ ) : searchResults.length === 0 ? ( +
No results found
+ ) : ( +
    + {searchResults.map((tree) => ( +
  • + +
  • + ))} +
+ )} +
)}
- {pinnedIsLoading ? ( -
- {Array.from({ length: 4 }).map((_, i) => ( -
- ))} -
- ) : pinnedItems.length === 0 ? ( -

- Star a flow to pin it here for quick access. -

- ) : ( -
- {visibleFavorites.map((flow) => ( - - - ))} -
- )} -
- {/* My Flows Section — tabbed */} -
-
- {tabs.map((tab) => ( - - ))} -
- {activeTab === 'mine' && canCreateTrees && ( - setShowAIBuilder(true)} - /> + + {hasMoreFavorites && ( + )} -
+ {pinnedIsLoading ? ( +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ ))} +
+ ) : pinnedItems.length === 0 ? ( +

+ Star a flow to pin it here for quick access. +

+ ) : ( +
+ {visibleFavorites.map((flow) => ( + + + ))} +
+ )}
- {isLoadingFlows ? ( -
- {Array.from({ length: 6 }).map((_, i) => ( -
+ {/* My Flows Section — tabbed */} +
+
+ {tabs.map((tab) => ( + ))} +
+ {activeTab === 'mine' && canCreateTrees && ( + setShowAIBuilder(true)} + /> + )} + +
- ) : myFlows.length === 0 ? ( -
-

- {activeTab === 'mine' - ? "You haven't created any flows yet." - : activeTab === 'team' - ? 'No team flows found.' - : activeTab === 'public' - ? 'No public flows found.' - : 'No flows found.'} -

- {activeTab === 'mine' && canCreateTrees && ( - setShowAIBuilder(true)} - label="Create your first flow" - /> - )} -
- ) : ( - <> - {allFlowsCeiling && ( -

- Showing first 500 flows. Use search or filters to find specific flows. + + {isLoadingFlows ? ( +

+ {Array.from({ length: 6 }).map((_, i) => ( +
+ ))} +
+ ) : myFlows.length === 0 ? ( +
+

+ {activeTab === 'mine' + ? "You haven't created any flows yet." + : activeTab === 'team' + ? 'No team flows found.' + : activeTab === 'public' + ? 'No public flows found.' + : 'No flows found.'}

- )} + {activeTab === 'mine' && canCreateTrees && ( + setShowAIBuilder(true)} + label="Create your first flow" + /> + )} +
+ ) : ( + <> + {allFlowsCeiling && ( +

+ Showing first 500 flows. Use search or filters to find specific flows. +

+ )} - {dashboardMyFlowsView === 'grid' && ( - - )} - {dashboardMyFlowsView === 'list' && ( - - )} - {dashboardMyFlowsView === 'table' && ( - - )} + {dashboardMyFlowsView === 'grid' && ( + + )} + {dashboardMyFlowsView === 'list' && ( + + )} + {dashboardMyFlowsView === 'table' && ( + + )} - {/* Pagination controls */} - {pageSize !== 'all' && ( -
-
- - Page {page} - + {/* Pagination controls */} + {pageSize !== 'all' && ( +
+
+ + Page {page} + +
+
+ Show: + +
-
- Show: - + )} + {pageSize === 'all' && ( +
+
+ Show: + +
-
- )} - {pageSize === 'all' && ( -
-
- Show: - -
-
- )} - - )} + )} + + )} +
{/* Fork Modal */}