@exxatdesignux/ui 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/init.mjs +29 -0
- package/package.json +7 -2
- package/template/.nvmrc +1 -0
- package/template/.prettierignore +7 -0
- package/template/.prettierrc +11 -0
- package/template/AGENTS.md +485 -0
- package/template/Logo/Exxat_Prism.svg +39 -0
- package/template/Logo/Exxat_one.svg +36 -0
- package/template/README.md +58 -0
- package/template/app/(app)/compliance/page.tsx +10 -0
- package/template/app/(app)/dashboard/loading.tsx +18 -0
- package/template/app/(app)/dashboard/page.tsx +36 -0
- package/template/app/(app)/data-list/[id]/page.tsx +28 -0
- package/template/app/(app)/data-list/new/page.tsx +31 -0
- package/template/app/(app)/data-list/page.tsx +10 -0
- package/template/app/(app)/error.tsx +43 -0
- package/template/app/(app)/help/page.tsx +34 -0
- package/template/app/(app)/layout.tsx +54 -0
- package/template/app/(app)/loading.tsx +18 -0
- package/template/app/(app)/question-bank/page.tsx +10 -0
- package/template/app/(app)/rotations/page.tsx +15 -0
- package/template/app/(app)/settings/page.tsx +17 -0
- package/template/app/(app)/sites/all/page.tsx +13 -0
- package/template/app/(app)/team/page.tsx +10 -0
- package/template/app/favicon.ico +0 -0
- package/template/app/globals.css +1811 -0
- package/template/app/layout.tsx +95 -0
- package/template/app/page.tsx +9 -0
- package/template/components/.gitkeep +0 -0
- package/template/components/app-sidebar-dynamic.tsx +15 -0
- package/template/components/app-sidebar.tsx +901 -0
- package/template/components/ask-leo-composer.tsx +216 -0
- package/template/components/ask-leo-sidebar.tsx +509 -0
- package/template/components/chart-area-interactive.tsx +293 -0
- package/template/components/charts-overview.tsx +2321 -0
- package/template/components/command-menu-01.tsx +133 -0
- package/template/components/command-menu-02.tsx +386 -0
- package/template/components/command-menu.tsx +182 -0
- package/template/components/compliance-board-view.tsx +134 -0
- package/template/components/compliance-client.tsx +92 -0
- package/template/components/compliance-list-view.tsx +59 -0
- package/template/components/compliance-page-header.tsx +89 -0
- package/template/components/compliance-table.tsx +525 -0
- package/template/components/dashboard-onboarding-gallery.tsx +13 -0
- package/template/components/dashboard-onboarding.tsx +21 -0
- package/template/components/dashboard-promo-banner.tsx +67 -0
- package/template/components/dashboard-quota-progress-card.tsx +369 -0
- package/template/components/dashboard-report-charts.tsx +69 -0
- package/template/components/dashboard-section-heading.tsx +68 -0
- package/template/components/dashboard-tabs.tsx +598 -0
- package/template/components/data-list-client.tsx +239 -0
- package/template/components/data-list-table-cells.test.tsx +22 -0
- package/template/components/data-list-table-cells.tsx +173 -0
- package/template/components/data-list-table.tsx +879 -0
- package/template/components/data-table/filter-date-calendar.tsx +38 -0
- package/template/components/data-table/filter-text-value-input.tsx +77 -0
- package/template/components/data-table/index.tsx +1612 -0
- package/template/components/data-table/pagination.tsx +256 -0
- package/template/components/data-table/types.ts +91 -0
- package/template/components/data-table/use-table-state.ts +566 -0
- package/template/components/data-view-dashboard-charts-compliance.tsx +960 -0
- package/template/components/data-view-dashboard-charts-team.tsx +968 -0
- package/template/components/data-view-dashboard-charts.tsx +1668 -0
- package/template/components/data-views/board-card-primitives.tsx +93 -0
- package/template/components/data-views/index.ts +41 -0
- package/template/components/data-views/list-page-board-card.tsx +192 -0
- package/template/components/data-views/list-page-board-template.tsx +122 -0
- package/template/components/data-views/placement-board-card.tsx +262 -0
- package/template/components/export-drawer.tsx +375 -0
- package/template/components/exxat-product-logo.tsx +453 -0
- package/template/components/form-layout-01.tsx +131 -0
- package/template/components/getting-started.tsx +625 -0
- package/template/components/key-metrics.tsx +920 -0
- package/template/components/leo-insight-indicator.tsx +364 -0
- package/template/components/leo-typing-dots.tsx +121 -0
- package/template/components/list-hub-status-badge.tsx +51 -0
- package/template/components/list-page-dashboard-charts.tsx +18 -0
- package/template/components/nav-documents.tsx +89 -0
- package/template/components/nav-main.tsx +58 -0
- package/template/components/nav-secondary.tsx +64 -0
- package/template/components/nav-user.tsx +190 -0
- package/template/components/new-placement-back-btn.tsx +28 -0
- package/template/components/new-placement-form.tsx +1066 -0
- package/template/components/onboarding/index.ts +4 -0
- package/template/components/onboarding/onboarding-01.tsx +7 -0
- package/template/components/onboarding/onboarding-02.tsx +7 -0
- package/template/components/onboarding/onboarding-03.tsx +7 -0
- package/template/components/onboarding/onboarding-04.tsx +7 -0
- package/template/components/page-header.tsx +57 -0
- package/template/components/placement-detail.tsx +438 -0
- package/template/components/placements-board-view.tsx +404 -0
- package/template/components/placements-list-view.tsx +285 -0
- package/template/components/placements-page-header.tsx +160 -0
- package/template/components/placements-table-columns.tsx +639 -0
- package/template/components/product-switcher.tsx +116 -0
- package/template/components/question-bank-board-view.tsx +205 -0
- package/template/components/question-bank-client.tsx +77 -0
- package/template/components/question-bank-list-view.tsx +59 -0
- package/template/components/question-bank-page-header.tsx +89 -0
- package/template/components/question-bank-table.tsx +586 -0
- package/template/components/rotations-empty-state.tsx +47 -0
- package/template/components/rotations-panel-activator.tsx +8 -0
- package/template/components/secondary-nav.tsx +394 -0
- package/template/components/secondary-panel.tsx +239 -0
- package/template/components/section-cards.tsx +106 -0
- package/template/components/settings-appearance-card.tsx +424 -0
- package/template/components/settings-client.tsx +537 -0
- package/template/components/settings-form-row.tsx +42 -0
- package/template/components/sidebar-auto-collapse.tsx +23 -0
- package/template/components/sidebar-auto-open.tsx +18 -0
- package/template/components/sidebar-shell.tsx +37 -0
- package/template/components/site-header.tsx +93 -0
- package/template/components/sites-all-client.tsx +154 -0
- package/template/components/sites-board-view.tsx +67 -0
- package/template/components/sites-list-view.tsx +47 -0
- package/template/components/sites-table.tsx +312 -0
- package/template/components/system-banner-slot.tsx +66 -0
- package/template/components/table-properties/column-row.tsx +90 -0
- package/template/components/table-properties/draggable-list.ts +49 -0
- package/template/components/table-properties/drawer-button.tsx +231 -0
- package/template/components/table-properties/drawer.tsx +1102 -0
- package/template/components/table-properties/filter-card.tsx +251 -0
- package/template/components/table-properties/index.ts +22 -0
- package/template/components/table-properties/sort-card.tsx +59 -0
- package/template/components/table-properties/types.ts +124 -0
- package/template/components/task-list-panel.tsx +98 -0
- package/template/components/task-priority-badge.tsx +28 -0
- package/template/components/team-board-view.tsx +114 -0
- package/template/components/team-client.tsx +93 -0
- package/template/components/team-list-view.tsx +62 -0
- package/template/components/team-page-header.tsx +92 -0
- package/template/components/team-table.tsx +525 -0
- package/template/components/templates/list-page.tsx +576 -0
- package/template/components/templates/primary-page-template.tsx +56 -0
- package/template/components/theme-color-sync.tsx +32 -0
- package/template/components/theme-provider.tsx +71 -0
- package/template/components/tinted-icon-disc.tsx +53 -0
- package/template/components/ui/ai-thinking-surface.tsx +121 -0
- package/template/components/ui/avatar.tsx +1 -0
- package/template/components/ui/badge.tsx +1 -0
- package/template/components/ui/banner.tsx +1 -0
- package/template/components/ui/breadcrumb.tsx +1 -0
- package/template/components/ui/button.tsx +1 -0
- package/template/components/ui/calendar.tsx +1 -0
- package/template/components/ui/card.tsx +1 -0
- package/template/components/ui/chart.tsx +1 -0
- package/template/components/ui/checkbox.tsx +1 -0
- package/template/components/ui/coach-mark.tsx +1 -0
- package/template/components/ui/collapsible.tsx +1 -0
- package/template/components/ui/command.tsx +1 -0
- package/template/components/ui/date-picker-field.tsx +1 -0
- package/template/components/ui/dialog.tsx +1 -0
- package/template/components/ui/dot-pattern.tsx +159 -0
- package/template/components/ui/drag-handle-grip.tsx +1 -0
- package/template/components/ui/drawer.tsx +1 -0
- package/template/components/ui/dropdown-menu.tsx +1 -0
- package/template/components/ui/field.tsx +1 -0
- package/template/components/ui/form.tsx +1 -0
- package/template/components/ui/input-group.tsx +1 -0
- package/template/components/ui/input-mask.tsx +1 -0
- package/template/components/ui/input.tsx +1 -0
- package/template/components/ui/kbd.tsx +1 -0
- package/template/components/ui/label.tsx +1 -0
- package/template/components/ui/leo-icon.tsx +726 -0
- package/template/components/ui/payment-card-fields.tsx +1 -0
- package/template/components/ui/popover.tsx +1 -0
- package/template/components/ui/radio-group.tsx +1 -0
- package/template/components/ui/select.tsx +1 -0
- package/template/components/ui/selection-tile-grid.tsx +1 -0
- package/template/components/ui/separator.tsx +1 -0
- package/template/components/ui/sheet.tsx +1 -0
- package/template/components/ui/sidebar.tsx +1 -0
- package/template/components/ui/skeleton.tsx +1 -0
- package/template/components/ui/sonner.tsx +1 -0
- package/template/components/ui/status-badge.tsx +1 -0
- package/template/components/ui/table.tsx +1 -0
- package/template/components/ui/tabs.tsx +1 -0
- package/template/components/ui/textarea.tsx +1 -0
- package/template/components/ui/tip.tsx +1 -0
- package/template/components/ui/toggle-group.tsx +1 -0
- package/template/components/ui/toggle-switch.tsx +1 -0
- package/template/components/ui/toggle.tsx +1 -0
- package/template/components/ui/tooltip.tsx +1 -0
- package/template/components/ui/view-segmented-control.tsx +1 -0
- package/template/components.json +27 -0
- package/template/contexts/chart-variant-context.tsx +35 -0
- package/template/contexts/command-menu-context.tsx +28 -0
- package/template/contexts/dashboard-view-context.tsx +35 -0
- package/template/contexts/product-context.tsx +38 -0
- package/template/contexts/system-banner-context.tsx +127 -0
- package/template/docs/command-menu-pattern.md +45 -0
- package/template/docs/data-views-pattern.md +160 -0
- package/template/ecosystem.config.cjs +20 -0
- package/template/eslint.config.mjs +18 -0
- package/template/fontawesome-subset.manifest.json +190 -0
- package/template/hooks/.gitkeep +0 -0
- package/template/hooks/use-app-theme.ts +1 -0
- package/template/hooks/use-coach-mark.ts +1 -0
- package/template/hooks/use-mobile.ts +1 -0
- package/template/hooks/use-mod-key-label.ts +1 -0
- package/template/lib/.gitkeep +0 -0
- package/template/lib/ask-leo-route-context.ts +133 -0
- package/template/lib/chart-keyboard-selection.test.ts +20 -0
- package/template/lib/chart-keyboard-selection.ts +17 -0
- package/template/lib/chart-line-dash.ts +16 -0
- package/template/lib/coach-mark-registry.ts +68 -0
- package/template/lib/command-menu-config.ts +127 -0
- package/template/lib/command-menu-search-data.ts +44 -0
- package/template/lib/conditional-rule-match.ts +32 -0
- package/template/lib/dashboard-customize-coach-mark.ts +18 -0
- package/template/lib/dashboard-layout-merge.ts +63 -0
- package/template/lib/data-list-display-options.ts +35 -0
- package/template/lib/data-list-persistence.ts +280 -0
- package/template/lib/data-list-view-surface.ts +58 -0
- package/template/lib/data-list-view.ts +29 -0
- package/template/lib/data-view-dashboard-storage.ts +101 -0
- package/template/lib/date-filter.ts +8 -0
- package/template/lib/dev-log.test.ts +28 -0
- package/template/lib/dev-log.ts +8 -0
- package/template/lib/editable-target.ts +10 -0
- package/template/lib/floating-sheet-panel.ts +72 -0
- package/template/lib/initials-from-name.ts +7 -0
- package/template/lib/list-page-table-properties.ts +52 -0
- package/template/lib/list-status-badges.ts +168 -0
- package/template/lib/logo-dev.ts +12 -0
- package/template/lib/mock/compliance-kpi.ts +61 -0
- package/template/lib/mock/compliance.ts +146 -0
- package/template/lib/mock/dashboard.ts +105 -0
- package/template/lib/mock/navigation.tsx +231 -0
- package/template/lib/mock/placements-kpi.ts +134 -0
- package/template/lib/mock/placements.ts +183 -0
- package/template/lib/mock/question-bank-kpi.ts +61 -0
- package/template/lib/mock/question-bank.ts +142 -0
- package/template/lib/mock/sites-directory.ts +16 -0
- package/template/lib/mock/sites-kpi.ts +25 -0
- package/template/lib/mock/team-kpi.ts +60 -0
- package/template/lib/mock/team.ts +118 -0
- package/template/lib/motion-ui.ts +17 -0
- package/template/lib/placement-board-card-layout.ts +79 -0
- package/template/lib/placement-lifecycle.ts +5 -0
- package/template/lib/row-height.ts +10 -0
- package/template/lib/stock-portrait.ts +11 -0
- package/template/lib/utils.test.ts +13 -0
- package/template/lib/utils.ts +1 -0
- package/template/next.config.mjs +15 -0
- package/template/package.json +83 -0
- package/template/postcss.config.mjs +8 -0
- package/template/public/.gitkeep +0 -0
- package/template/public/Illustration/Rotation.svg +74 -0
- package/template/public/avatars/user.svg +11 -0
- package/template/public/favicon/favicon.ico +0 -0
- package/template/public/favicon.ico +0 -0
- package/template/public/logos/exxat-one.svg +36 -0
- package/template/public/logos/exxat-prism.svg +39 -0
- package/template/public/mock-schools/emory.svg +4 -0
- package/template/public/mock-schools/rush.svg +4 -0
- package/template/scripts/fontawesome-subset-audit.mjs +190 -0
- package/template/scripts/pm2-startup-macos.sh +13 -0
- package/template/skills-lock.json +10 -0
- package/template/stores/app-store.ts +33 -0
- package/template/tests/setup.ts +1 -0
- package/template/tsconfig.json +35 -0
- package/template/types/react-payment-inputs.d.ts +19 -0
- package/template/vitest.config.ts +18 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DashboardTabs — three-view dashboard switcher
|
|
5
|
+
*
|
|
6
|
+
* Report — full KPI + charts view (current dashboard)
|
|
7
|
+
* Simple — Promo · Greeting · Onboarding gallery · Tasks · Insights · Recent · Learn
|
|
8
|
+
* Mix — compact metrics + key chart + tasks & activity side-by-side
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as React from "react"
|
|
12
|
+
import { Card, CardContent, CardHeader, CardDescription } from "@/components/ui/card"
|
|
13
|
+
import { TintedIconDisc, type TintedIconDiscTone } from "@/components/tinted-icon-disc"
|
|
14
|
+
import { Separator } from "@/components/ui/separator"
|
|
15
|
+
import { KeyMetrics, type MetricItem, type MetricInsight } from "@/components/key-metrics"
|
|
16
|
+
import type { ChartCardVariant } from "@/components/charts-overview"
|
|
17
|
+
import { DashboardReportCharts } from "@/components/dashboard-report-charts"
|
|
18
|
+
import { GettingStarted, GettingStartedProgressCard } from "@/components/getting-started"
|
|
19
|
+
import { TaskListPanel, type TaskListItem } from "@/components/task-list-panel"
|
|
20
|
+
import { PageHeader } from "@/components/page-header"
|
|
21
|
+
import { useDashboardView } from "@/contexts/dashboard-view-context"
|
|
22
|
+
import { useChartVariant } from "@/contexts/chart-variant-context"
|
|
23
|
+
import { useAskLeo, useAskLeoPageContext } from "@/components/ask-leo-sidebar"
|
|
24
|
+
import { cn } from "@/lib/utils"
|
|
25
|
+
import {
|
|
26
|
+
DashboardSectionTitle,
|
|
27
|
+
dashboardSectionDescriptionClassName,
|
|
28
|
+
} from "@/components/dashboard-section-heading"
|
|
29
|
+
import { DashboardPromoBanner } from "@/components/dashboard-promo-banner"
|
|
30
|
+
import { CoachMark } from "@/components/ui/coach-mark"
|
|
31
|
+
import { useCoachMark } from "@/hooks/use-coach-mark"
|
|
32
|
+
|
|
33
|
+
/* ── Types passed from the page ─────────────────────────────────────────── */
|
|
34
|
+
interface DashboardTabsProps {
|
|
35
|
+
metrics: MetricItem[]
|
|
36
|
+
insight: MetricInsight
|
|
37
|
+
title?: string
|
|
38
|
+
subtitle?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
42
|
+
SIMPLE TAB — widgets
|
|
43
|
+
════════════════════════════════════════════════════════════════════════════ */
|
|
44
|
+
|
|
45
|
+
/* ── Greeting ─────────────────────────────────────────────────────────────── */
|
|
46
|
+
function GreetingWidget({ compact = false }: { compact?: boolean }) {
|
|
47
|
+
const [now, setNow] = React.useState<Date | null>(null)
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
setNow(new Date())
|
|
50
|
+
}, [])
|
|
51
|
+
|
|
52
|
+
const hour = now?.getHours() ?? 9
|
|
53
|
+
const greeting =
|
|
54
|
+
hour < 12 ? "Good morning" : hour < 17 ? "Good afternoon" : "Good evening"
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="flex flex-col gap-3">
|
|
58
|
+
<div className="flex items-start justify-between gap-4">
|
|
59
|
+
<div>
|
|
60
|
+
{!compact ? (
|
|
61
|
+
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider" suppressHydrationWarning>
|
|
62
|
+
{now?.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric" }) ?? ""}
|
|
63
|
+
</p>
|
|
64
|
+
) : null}
|
|
65
|
+
{compact ? (
|
|
66
|
+
<p
|
|
67
|
+
className="text-2xl font-semibold tracking-tight leading-tight text-foreground"
|
|
68
|
+
style={{ fontFamily: "var(--font-heading)" }}
|
|
69
|
+
>
|
|
70
|
+
{greeting}, Himanshu 👋
|
|
71
|
+
</p>
|
|
72
|
+
) : (
|
|
73
|
+
<h2
|
|
74
|
+
className="text-2xl font-semibold tracking-tight leading-tight text-foreground"
|
|
75
|
+
style={{ fontFamily: "var(--font-heading)" }}
|
|
76
|
+
>
|
|
77
|
+
{greeting}, Himanshu 👋
|
|
78
|
+
</h2>
|
|
79
|
+
)}
|
|
80
|
+
{!compact ? (
|
|
81
|
+
<p className="mt-1 text-sm text-muted-foreground max-w-sm">
|
|
82
|
+
You have <span className="font-medium text-foreground">8 reviews</span> pending and{" "}
|
|
83
|
+
<span className="font-medium text-foreground">23 requests</span> waiting today.
|
|
84
|
+
</p>
|
|
85
|
+
) : null}
|
|
86
|
+
</div>
|
|
87
|
+
<TintedIconDisc icon="fa-sun-bright" tone="brand" size="lg" />
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* ── Tasks ────────────────────────────────────────────────────────────────── */
|
|
94
|
+
const TASK_ITEMS: TaskListItem[] = [
|
|
95
|
+
{ id: 1, label: "Review pending evaluations", due: "Today", priority: "high", done: false },
|
|
96
|
+
{ id: 2, label: "Approve site contract — City Med", due: "Today", priority: "high", done: false },
|
|
97
|
+
{ id: 3, label: "Send onboarding docs to PT cohort", due: "Tomorrow", priority: "medium", done: false },
|
|
98
|
+
{ id: 4, label: "Update compliance checklist", due: "Mar 25", priority: "medium", done: false },
|
|
99
|
+
{ id: 5, label: "Schedule supervisor training", due: "Mar 28", priority: "low", done: true },
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
/* ── Insights ─────────────────────────────────────────────────────────────── */
|
|
103
|
+
const INSIGHTS: {
|
|
104
|
+
id: number
|
|
105
|
+
icon: string
|
|
106
|
+
tone: TintedIconDiscTone
|
|
107
|
+
title: string
|
|
108
|
+
body: string
|
|
109
|
+
}[] = [
|
|
110
|
+
{
|
|
111
|
+
id: 1,
|
|
112
|
+
icon: "fa-arrow-trend-up",
|
|
113
|
+
tone: "chart-2",
|
|
114
|
+
title: "Placement rate up 12%",
|
|
115
|
+
body: "Nursing placements increased compared to last quarter. Site capacity utilisation at 94%.",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 2,
|
|
119
|
+
icon: "fa-triangle-exclamation",
|
|
120
|
+
tone: "chart-4",
|
|
121
|
+
title: "Review backlog growing",
|
|
122
|
+
body: "8 evaluations have been pending for more than 48 hrs. Clear them to unblock new requests.",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 3,
|
|
126
|
+
icon: "fa-certificate",
|
|
127
|
+
tone: "brand",
|
|
128
|
+
title: "Compliance milestone",
|
|
129
|
+
body: "Nursing program reached 98% compliance — highest in 12 months.",
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
function InsightsWidget({ plain = false }: { plain?: boolean }) {
|
|
134
|
+
/* Glow applied — AI surface (rule 1). See GLOW GUIDELINE in key-metrics.tsx */
|
|
135
|
+
const glowStyle = {
|
|
136
|
+
background:
|
|
137
|
+
"radial-gradient(ellipse 120% 80% at 50% 100%, oklch(from var(--brand-color) l c h / 0.14) 0%, transparent 65%)",
|
|
138
|
+
} as const
|
|
139
|
+
|
|
140
|
+
const items = INSIGHTS.map((ins, idx) => (
|
|
141
|
+
<React.Fragment key={ins.id}>
|
|
142
|
+
<div className="flex gap-3 items-start py-2">
|
|
143
|
+
<TintedIconDisc
|
|
144
|
+
className="mt-0.5"
|
|
145
|
+
icon={ins.icon}
|
|
146
|
+
tone={ins.tone}
|
|
147
|
+
size="md"
|
|
148
|
+
/>
|
|
149
|
+
<div className="flex-1 min-w-0">
|
|
150
|
+
<p className="text-xs font-semibold text-foreground leading-snug">{ins.title}</p>
|
|
151
|
+
<p className="text-xs text-muted-foreground mt-0.5 leading-snug">{ins.body}</p>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
{plain && idx < INSIGHTS.length - 1 ? (
|
|
155
|
+
<Separator className="opacity-50" aria-hidden="true" />
|
|
156
|
+
) : null}
|
|
157
|
+
</React.Fragment>
|
|
158
|
+
))
|
|
159
|
+
|
|
160
|
+
if (plain) {
|
|
161
|
+
return (
|
|
162
|
+
<section aria-labelledby="dashboard-insights-heading" className="flex flex-col gap-3">
|
|
163
|
+
<div className="flex flex-col gap-0.5">
|
|
164
|
+
<DashboardSectionTitle as="h1" id="dashboard-insights-heading">
|
|
165
|
+
Insights
|
|
166
|
+
</DashboardSectionTitle>
|
|
167
|
+
<p className={cn(dashboardSectionDescriptionClassName, "mt-0.5")}>
|
|
168
|
+
AI-generated · Updated now
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
<div className="flex flex-col">{items}</div>
|
|
172
|
+
</section>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<Card size="sm" className="overflow-hidden" style={glowStyle}>
|
|
178
|
+
<CardHeader>
|
|
179
|
+
<DashboardSectionTitle as="h2">Insights</DashboardSectionTitle>
|
|
180
|
+
<CardDescription>AI-generated · Updated now</CardDescription>
|
|
181
|
+
</CardHeader>
|
|
182
|
+
<CardContent className="flex flex-col gap-3">
|
|
183
|
+
{INSIGHTS.map((ins) => (
|
|
184
|
+
<div key={ins.id} className="flex gap-3 items-start">
|
|
185
|
+
<TintedIconDisc
|
|
186
|
+
className="mt-0.5"
|
|
187
|
+
icon={ins.icon}
|
|
188
|
+
tone={ins.tone}
|
|
189
|
+
size="md"
|
|
190
|
+
/>
|
|
191
|
+
<div className="flex-1 min-w-0">
|
|
192
|
+
<p className="text-xs font-semibold text-foreground leading-snug">{ins.title}</p>
|
|
193
|
+
<p className="text-xs text-muted-foreground mt-0.5 leading-snug">{ins.body}</p>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
))}
|
|
197
|
+
</CardContent>
|
|
198
|
+
</Card>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ── Recent Activity ──────────────────────────────────────────────────────── */
|
|
203
|
+
const ACTIVITY: {
|
|
204
|
+
id: number
|
|
205
|
+
icon: string
|
|
206
|
+
tone: TintedIconDiscTone
|
|
207
|
+
actor: string
|
|
208
|
+
action: string
|
|
209
|
+
subject: string
|
|
210
|
+
time: string
|
|
211
|
+
}[] = [
|
|
212
|
+
{ id: 1, icon: "fa-user-check", tone: "chart-2", actor: "Dr. Patel", action: "approved", subject: "City Med placement", time: "2m ago" },
|
|
213
|
+
{ id: 2, icon: "fa-file-signature", tone: "brand", actor: "Sarah Kim", action: "submitted", subject: "OT evaluation form", time: "18m ago" },
|
|
214
|
+
{ id: 3, icon: "fa-circle-xmark", tone: "destructive", actor: "North Clinic", action: "rejected", subject: "2 pending requests", time: "1h ago" },
|
|
215
|
+
{ id: 4, icon: "fa-envelope-open", tone: "chart-4", actor: "System", action: "sent reminder", subject: "to 5 supervisors", time: "3h ago" },
|
|
216
|
+
{ id: 5, icon: "fa-arrow-up-right", tone: "brand", actor: "You", action: "exported", subject: "Q1 compliance report", time: "5h ago" },
|
|
217
|
+
{ id: 6, icon: "fa-user-plus", tone: "chart-2", actor: "Admissions", action: "added", subject: "14 new nursing students", time: "Yesterday"},
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
function RecentActivityWidget({ plain = false }: { plain?: boolean }) {
|
|
221
|
+
const rows = ACTIVITY.map((ev, idx) => (
|
|
222
|
+
<React.Fragment key={ev.id}>
|
|
223
|
+
<div className="flex items-start gap-3 py-2">
|
|
224
|
+
<TintedIconDisc
|
|
225
|
+
className="mt-0.5"
|
|
226
|
+
icon={ev.icon}
|
|
227
|
+
tone={ev.tone}
|
|
228
|
+
size="sm"
|
|
229
|
+
/>
|
|
230
|
+
<div className="flex-1 min-w-0">
|
|
231
|
+
<p className="text-xs leading-snug text-foreground">
|
|
232
|
+
<span className="font-medium">{ev.actor}</span>{" "}
|
|
233
|
+
<span className="text-muted-foreground">{ev.action}</span>{" "}
|
|
234
|
+
<span className="font-medium">{ev.subject}</span>
|
|
235
|
+
</p>
|
|
236
|
+
<p className="text-xs text-muted-foreground mt-0.5">{ev.time}</p>
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
{idx < ACTIVITY.length - 1 && (
|
|
240
|
+
<Separator className="opacity-50" aria-hidden="true" />
|
|
241
|
+
)}
|
|
242
|
+
</React.Fragment>
|
|
243
|
+
))
|
|
244
|
+
|
|
245
|
+
if (plain) {
|
|
246
|
+
return (
|
|
247
|
+
<section aria-labelledby="dashboard-activity-heading" className="flex flex-col gap-3">
|
|
248
|
+
<DashboardSectionTitle as="h1" id="dashboard-activity-heading">
|
|
249
|
+
Recent Activity
|
|
250
|
+
</DashboardSectionTitle>
|
|
251
|
+
<div className="flex flex-col overflow-auto">{rows}</div>
|
|
252
|
+
</section>
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<Card size="sm">
|
|
258
|
+
<CardHeader>
|
|
259
|
+
<DashboardSectionTitle as="h2">Recent Activity</DashboardSectionTitle>
|
|
260
|
+
</CardHeader>
|
|
261
|
+
<CardContent className="flex flex-col overflow-auto">{rows}</CardContent>
|
|
262
|
+
</Card>
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* ── Learn / Guide ────────────────────────────────────────────────────────── */
|
|
267
|
+
const STEPS = [
|
|
268
|
+
{ id: 1, label: "Create your organisation profile", done: true },
|
|
269
|
+
{ id: 2, label: "Add your first placement site", done: true },
|
|
270
|
+
{ id: 3, label: "Import student roster", done: true },
|
|
271
|
+
{ id: 4, label: "Configure compliance requirements", done: false },
|
|
272
|
+
{ id: 5, label: "Invite supervisors", done: false },
|
|
273
|
+
{ id: 6, label: "Launch first placement cycle", done: false },
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
const GUIDE_ARTICLES = [
|
|
277
|
+
{
|
|
278
|
+
id: "workflow",
|
|
279
|
+
icon: "fa-sitemap",
|
|
280
|
+
title: "How does a placement actually work?",
|
|
281
|
+
meta: "5m read",
|
|
282
|
+
gradientClass: "bg-gradient-to-br from-chart-3 to-chart-1",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "site",
|
|
286
|
+
icon: "fa-circle-play",
|
|
287
|
+
title: "Watch: Setting up your first clinical site",
|
|
288
|
+
meta: "3m watch",
|
|
289
|
+
gradientClass: "bg-gradient-to-br from-chart-1 to-chart-5",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: "compliance",
|
|
293
|
+
icon: "fa-shield-check",
|
|
294
|
+
title: "Make compliance less of a headache",
|
|
295
|
+
meta: "8m read",
|
|
296
|
+
gradientClass: "bg-gradient-to-br from-chart-2 to-chart-4",
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: "reports",
|
|
300
|
+
icon: "fa-file-chart-column",
|
|
301
|
+
title: "Turn your data into a report in 2 minutes",
|
|
302
|
+
meta: "4m read",
|
|
303
|
+
gradientClass: "bg-gradient-to-br from-chart-4 to-chart-5",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: "support",
|
|
307
|
+
icon: "fa-headset",
|
|
308
|
+
title: "Stuck? Our team is one message away",
|
|
309
|
+
meta: "Get help",
|
|
310
|
+
gradientClass: "bg-gradient-to-br from-chart-3 to-muted",
|
|
311
|
+
},
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
function LearnSection({ layout = "scroll", plain = false }: { layout?: "scroll" | "stack"; plain?: boolean }) {
|
|
315
|
+
const done = STEPS.filter((s) => s.done).length
|
|
316
|
+
const total = STEPS.length
|
|
317
|
+
const pct = Math.round((done / total) * 100)
|
|
318
|
+
const nextStep = STEPS.find((s) => !s.done)
|
|
319
|
+
const stacked = layout === "stack"
|
|
320
|
+
const tileClass = cn(
|
|
321
|
+
"flex flex-col rounded-lg overflow-hidden border border-border bg-card hover:bg-interactive-hover-soft transition-colors focus-visible:outline-2 focus-visible:outline-ring",
|
|
322
|
+
stacked ? "w-full" : "shrink-0 w-[13rem]",
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const tiles = (
|
|
326
|
+
<>
|
|
327
|
+
<a
|
|
328
|
+
href="#"
|
|
329
|
+
className={tileClass}
|
|
330
|
+
aria-label={`Continue setup — ${done} of ${total} steps done`}
|
|
331
|
+
>
|
|
332
|
+
<div
|
|
333
|
+
className="h-[6.5rem] relative flex items-center justify-center overflow-hidden bg-gradient-to-br from-chart-1 to-chart-3"
|
|
334
|
+
>
|
|
335
|
+
<i className="fa-light fa-rocket-launch text-[3rem] text-background/25" aria-hidden="true" />
|
|
336
|
+
<div className="absolute inset-x-0 bottom-0 px-3 pb-2.5">
|
|
337
|
+
<div className="h-[3px] rounded-full overflow-hidden bg-background/20">
|
|
338
|
+
<div
|
|
339
|
+
className="h-full rounded-full bg-background/80"
|
|
340
|
+
style={{ width: `${pct}%`, transition: "width 0.5s ease" }}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
<div className="flex flex-1 flex-col gap-1 p-3">
|
|
346
|
+
<p className="text-sm font-medium leading-snug text-foreground">
|
|
347
|
+
Pick up where you left off
|
|
348
|
+
</p>
|
|
349
|
+
{nextStep && (
|
|
350
|
+
<p className="text-xs text-muted-foreground leading-snug">Next: {nextStep.label}</p>
|
|
351
|
+
)}
|
|
352
|
+
<div className="mt-auto pt-1.5">
|
|
353
|
+
<span className="inline-block text-xs font-medium px-1.5 py-0.5 rounded-full bg-muted text-muted-foreground">
|
|
354
|
+
{done}/{total} steps
|
|
355
|
+
</span>
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
</a>
|
|
359
|
+
|
|
360
|
+
{GUIDE_ARTICLES.map((g) => (
|
|
361
|
+
<a
|
|
362
|
+
key={g.id}
|
|
363
|
+
href="#"
|
|
364
|
+
className={tileClass}
|
|
365
|
+
aria-label={g.title}
|
|
366
|
+
>
|
|
367
|
+
<div
|
|
368
|
+
className={cn("h-[6.5rem] flex items-center justify-center overflow-hidden", g.gradientClass)}
|
|
369
|
+
>
|
|
370
|
+
<i className={`fa-light ${g.icon} text-[3rem] text-background/25`} aria-hidden="true" />
|
|
371
|
+
</div>
|
|
372
|
+
<div className="flex flex-1 flex-col gap-1 p-3">
|
|
373
|
+
<h3 className="text-sm font-medium leading-snug text-foreground">{g.title}</h3>
|
|
374
|
+
<div className="flex items-center gap-1.5 mt-auto pt-1.5 text-muted-foreground">
|
|
375
|
+
<i className="fa-light fa-book-open text-xs" aria-hidden="true" />
|
|
376
|
+
<span className="text-xs">{g.meta}</span>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</a>
|
|
380
|
+
))}
|
|
381
|
+
</>
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
const rail = (
|
|
385
|
+
<div
|
|
386
|
+
className={cn("flex gap-3", stacked ? "flex-col" : "overflow-x-auto")}
|
|
387
|
+
style={stacked ? undefined : { scrollbarWidth: "none" }}
|
|
388
|
+
>
|
|
389
|
+
{tiles}
|
|
390
|
+
</div>
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
if (plain) {
|
|
394
|
+
return (
|
|
395
|
+
<section aria-labelledby="dashboard-learn-heading" className="flex flex-col gap-3">
|
|
396
|
+
<div className="flex flex-col gap-0.5">
|
|
397
|
+
<DashboardSectionTitle as="h1" id="dashboard-learn-heading">
|
|
398
|
+
Learn
|
|
399
|
+
</DashboardSectionTitle>
|
|
400
|
+
<p className={cn(dashboardSectionDescriptionClassName, "mt-0.5")}>
|
|
401
|
+
Guides, videos & resources
|
|
402
|
+
</p>
|
|
403
|
+
</div>
|
|
404
|
+
{rail}
|
|
405
|
+
</section>
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return (
|
|
410
|
+
<Card size="sm" className="overflow-hidden">
|
|
411
|
+
<CardHeader>
|
|
412
|
+
<DashboardSectionTitle as="h2">Learn</DashboardSectionTitle>
|
|
413
|
+
<CardDescription>Guides, videos & resources</CardDescription>
|
|
414
|
+
</CardHeader>
|
|
415
|
+
<CardContent>{rail}</CardContent>
|
|
416
|
+
</Card>
|
|
417
|
+
)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
421
|
+
TAB VIEWS
|
|
422
|
+
════════════════════════════════════════════════════════════════════════════ */
|
|
423
|
+
|
|
424
|
+
function ReportView({ metrics, insight, chartVariant }: DashboardTabsProps & { chartVariant: ChartCardVariant }) {
|
|
425
|
+
return (
|
|
426
|
+
<DashboardReportCharts
|
|
427
|
+
metrics={metrics}
|
|
428
|
+
insight={insight}
|
|
429
|
+
chartVariant={chartVariant}
|
|
430
|
+
/>
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function SimpleView() {
|
|
435
|
+
return (
|
|
436
|
+
<div className="mx-auto flex w-full max-w-4xl flex-col gap-10 px-4 py-2 pb-8 sm:gap-11 sm:px-6 sm:pb-9 lg:gap-12 lg:px-8 lg:pb-10">
|
|
437
|
+
<DashboardPromoBanner />
|
|
438
|
+
<GreetingWidget compact />
|
|
439
|
+
<GettingStarted inset={false} titleAs="h1" />
|
|
440
|
+
<TaskListPanel
|
|
441
|
+
title="Tasks"
|
|
442
|
+
headingId="dashboard-tasks-heading"
|
|
443
|
+
headingLevel="h1"
|
|
444
|
+
plain
|
|
445
|
+
defaultTasks={TASK_ITEMS}
|
|
446
|
+
/>
|
|
447
|
+
<InsightsWidget plain />
|
|
448
|
+
<RecentActivityWidget plain />
|
|
449
|
+
<LearnSection layout="scroll" plain />
|
|
450
|
+
</div>
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function MixView({ metrics, insight }: DashboardTabsProps) {
|
|
455
|
+
return (
|
|
456
|
+
<div className="flex flex-col gap-4 pb-6">
|
|
457
|
+
<div className="px-4 lg:px-6">
|
|
458
|
+
<DashboardPromoBanner />
|
|
459
|
+
</div>
|
|
460
|
+
{/* Key metrics flat band */}
|
|
461
|
+
<KeyMetrics variant="flat" metrics={metrics} insight={insight} />
|
|
462
|
+
|
|
463
|
+
<div className="px-4 lg:px-6 flex flex-col gap-4">
|
|
464
|
+
{/* Row: Greeting + Onboarding */}
|
|
465
|
+
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3 items-stretch">
|
|
466
|
+
<div className="lg:col-span-2">
|
|
467
|
+
<GreetingWidget />
|
|
468
|
+
</div>
|
|
469
|
+
<GettingStartedProgressCard steps={STEPS} title="Guided onboarding" />
|
|
470
|
+
</div>
|
|
471
|
+
|
|
472
|
+
{/* Row: Tasks + Recent Activity */}
|
|
473
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 items-stretch">
|
|
474
|
+
<TaskListPanel title="Tasks" defaultTasks={TASK_ITEMS} />
|
|
475
|
+
<RecentActivityWidget />
|
|
476
|
+
</div>
|
|
477
|
+
|
|
478
|
+
{/* Row: Insights */}
|
|
479
|
+
<InsightsWidget />
|
|
480
|
+
|
|
481
|
+
<GettingStarted />
|
|
482
|
+
|
|
483
|
+
{/* Learn panel — full width */}
|
|
484
|
+
<LearnSection />
|
|
485
|
+
</div>
|
|
486
|
+
</div>
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
491
|
+
COACH MARK FLOW — dashboard onboarding tour
|
|
492
|
+
════════════════════════════════════════════════════════════════════════════ */
|
|
493
|
+
|
|
494
|
+
const DASHBOARD_TOUR_STEPS = [
|
|
495
|
+
{
|
|
496
|
+
id: "tour-welcome",
|
|
497
|
+
target: "h1",
|
|
498
|
+
side: "bottom" as const,
|
|
499
|
+
align: "start" as const,
|
|
500
|
+
title: "Welcome to your Dashboard",
|
|
501
|
+
description:
|
|
502
|
+
"This is your command centre. See key metrics, charts, tasks and AI insights — all in one place.",
|
|
503
|
+
image: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=640&h=320&fit=crop&q=80",
|
|
504
|
+
imageAlt: "Dashboard analytics overview",
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
id: "tour-metrics",
|
|
508
|
+
target: "[aria-label='Key Metrics']",
|
|
509
|
+
side: "bottom" as const,
|
|
510
|
+
align: "start" as const,
|
|
511
|
+
title: "Key Metrics at a Glance",
|
|
512
|
+
description:
|
|
513
|
+
"Track pending requests, confirmed placements, compliance rate and more. Trends show how numbers changed since last period.",
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
id: "tour-insights",
|
|
517
|
+
target: "[aria-label='Insight']",
|
|
518
|
+
side: "left" as const,
|
|
519
|
+
align: "start" as const,
|
|
520
|
+
title: "AI-Powered Insights",
|
|
521
|
+
description:
|
|
522
|
+
"Leo analyses your data and surfaces actionable insights automatically — no need to dig through reports.",
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
id: "tour-askleo",
|
|
526
|
+
target: "[aria-label='Ask Leo']",
|
|
527
|
+
side: "bottom" as const,
|
|
528
|
+
align: "end" as const,
|
|
529
|
+
title: "Ask Leo Anything",
|
|
530
|
+
description:
|
|
531
|
+
"Click here or press ⌘⌥K to open Leo, your AI assistant. Ask questions about your data, get recommendations, or automate tasks.",
|
|
532
|
+
},
|
|
533
|
+
]
|
|
534
|
+
|
|
535
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
536
|
+
Main export
|
|
537
|
+
════════════════════════════════════════════════════════════════════════════ */
|
|
538
|
+
|
|
539
|
+
export function DashboardTabs({
|
|
540
|
+
metrics,
|
|
541
|
+
insight: insightProp,
|
|
542
|
+
title = "Dashboard",
|
|
543
|
+
subtitle,
|
|
544
|
+
}: DashboardTabsProps) {
|
|
545
|
+
const { chartVariant } = useChartVariant()
|
|
546
|
+
const { activeView } = useDashboardView()
|
|
547
|
+
const { openWithPrompt } = useAskLeo()
|
|
548
|
+
|
|
549
|
+
const insight = React.useMemo<MetricInsight>(() => {
|
|
550
|
+
if (insightProp.onAction) return insightProp
|
|
551
|
+
return {
|
|
552
|
+
...insightProp,
|
|
553
|
+
onAction: () =>
|
|
554
|
+
openWithPrompt(
|
|
555
|
+
insightProp.description ?? insightProp.statement ?? insightProp.title,
|
|
556
|
+
),
|
|
557
|
+
}
|
|
558
|
+
}, [insightProp, openWithPrompt])
|
|
559
|
+
|
|
560
|
+
const tour = useCoachMark({
|
|
561
|
+
flowId: "dashboard-tour",
|
|
562
|
+
steps: DASHBOARD_TOUR_STEPS,
|
|
563
|
+
delay: 800,
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
const viewLabel =
|
|
567
|
+
activeView === "report" ? "Report" : activeView === "simple" ? "Simple" : "Mix"
|
|
568
|
+
|
|
569
|
+
useAskLeoPageContext(
|
|
570
|
+
React.useMemo(
|
|
571
|
+
() => ({
|
|
572
|
+
title: "Dashboard",
|
|
573
|
+
description: `${viewLabel} layout · ${metrics.length} KPI tiles on the strip.`,
|
|
574
|
+
suggestions: [
|
|
575
|
+
"What changed in my key metrics this week?",
|
|
576
|
+
"Summarize the insight card for my stand-up",
|
|
577
|
+
"Which metric should I watch for placement risk?",
|
|
578
|
+
],
|
|
579
|
+
}),
|
|
580
|
+
[viewLabel, metrics.length],
|
|
581
|
+
),
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
return (
|
|
585
|
+
<div className="flex flex-col">
|
|
586
|
+
{/* Coach mark tour — targets elements by CSS selector, no wrapping needed */}
|
|
587
|
+
<CoachMark state={tour} />
|
|
588
|
+
|
|
589
|
+
{/* Simple view: greeting IS the page header — no separate PageHeader */}
|
|
590
|
+
{activeView !== "simple" && (
|
|
591
|
+
<PageHeader title={title} subtitle={subtitle} className="pt-4 md:pt-6" />
|
|
592
|
+
)}
|
|
593
|
+
{activeView === "report" && <ReportView metrics={metrics} insight={insight} chartVariant={chartVariant} />}
|
|
594
|
+
{activeView === "simple" && <SimpleView />}
|
|
595
|
+
{activeView === "mix" && <MixView metrics={metrics} insight={insight} />}
|
|
596
|
+
</div>
|
|
597
|
+
)
|
|
598
|
+
}
|