@burdenoff/microfe-timecampus 2026.830.2 → 2026.904.1
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/dist/timecampus/components/index.js +4 -4
- package/dist/timecampus/pages/HomePage.d.ts.map +1 -1
- package/dist/timecampus/pages/HomePage.js +149 -133
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +7 -7
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +7 -7
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +13 -13
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +7 -7
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +7 -7
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +13 -13
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +135 -135
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/invoicing/InvoicingPage.js +7 -7
- package/dist/timecampus/pages/invoicing/InvoicingPage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/DeadTimeRadarPage.js +8 -8
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js +4 -4
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js +104 -104
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js +7 -7
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js +33 -33
- package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/RecommendationsPage.js +80 -80
- package/dist/timecampus/pages/lifetime/RecommendationsPage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/TimeWellSpentPage.js +16 -16
- package/dist/timecampus/pages/lifetime/ValuesGoalsPage.js +11 -11
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +11 -11
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +14 -14
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +12 -12
- package/dist/timecampus/pages/projects/ProjectsPage.js +5 -5
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +8 -8
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +8 -8
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +8 -8
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +13 -13
- package/dist/timecampus/pages/time/TimeEntriesPage.js +5 -5
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +138 -138
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +14 -14
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +26 -26
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +8 -8
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +79 -79
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkPatternsPage.js","names":[],"sources":["../../../../src/timecampus/pages/work-patterns/WorkPatternsPage.tsx"],"sourcesContent":["import {\n TrendingUp,\n Clock,\n Zap,\n Brain,\n AlertTriangle,\n ShieldCheck,\n Lightbulb,\n ArrowRight,\n} from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport {\n PageLayout,\n StatCard,\n ChartCard,\n Heatmap,\n TrendChart,\n StatusBadge,\n EmptyState,\n LoadingSkeleton,\n type HeatmapValue,\n} from \"../../components\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListWorkPatternsQuery,\n useGetWorkPatternSummaryQuery,\n type WorkPatternFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport {\n WorkPatternInsightType,\n type WorkPatternInsight,\n} from \"@/generated/wspace-types\";\n\nconst DAY_LABELS = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"] as const;\n\n/** JS `getDay()` is 0=Sun..6=Sat; remap so Monday is index 0. */\nfunction dayOfWeekIndex(d: Date): number {\n return (d.getDay() + 6) % 7;\n}\n\n/** Monday (local midnight) of the week containing `d`. */\nfunction weekStart(d: Date): Date {\n const s = new Date(d);\n s.setDate(d.getDate() - dayOfWeekIndex(d));\n s.setHours(0, 0, 0, 0);\n return s;\n}\n\nfunction shortDate(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"\";\n return d.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\" });\n}\n\n// Self-reported ordinals mapped onto a shared 1 (worst) – 5 (best) scale so\n// energy and mood can be trended together. Only real, fetched enum values map;\n// anything else stays null (a gap in the line, never a fabricated point).\nconst ENERGY_SCORE: Record<string, number> = {\n VERY_LOW: 1,\n LOW: 2,\n MEDIUM: 3,\n HIGH: 4,\n VERY_HIGH: 5,\n};\nconst MOOD_SCORE: Record<string, number> = {\n VERY_NEGATIVE: 1,\n NEGATIVE: 2,\n NEUTRAL: 3,\n POSITIVE: 4,\n VERY_POSITIVE: 5,\n};\n\nconst HIGH_STRESS = new Set([\"HIGH\", \"VERY_HIGH\"]);\nconst LOW_ENERGY = new Set([\"LOW\", \"VERY_LOW\"]);\n\nconst formatHoursValue = (v: number) => `${v.toFixed(1)}h`;\n\ntype BurnoutTone = \"danger\" | \"warning\" | \"success\";\n\nconst INSIGHT_VARIANT: Record<\n WorkPatternInsightType,\n \"success\" | \"error\" | \"warning\" | \"info\" | \"muted\"\n> = {\n [WorkPatternInsightType.Positive]: \"success\",\n [WorkPatternInsightType.Negative]: \"error\",\n [WorkPatternInsightType.Warning]: \"warning\",\n [WorkPatternInsightType.Recommendation]: \"info\",\n [WorkPatternInsightType.Neutral]: \"muted\",\n};\n\nconst INSIGHT_LABEL: Record<WorkPatternInsightType, string> = {\n [WorkPatternInsightType.Positive]: \"Positive\",\n [WorkPatternInsightType.Negative]: \"Negative\",\n [WorkPatternInsightType.Warning]: \"Warning\",\n [WorkPatternInsightType.Recommendation]: \"Tip\",\n [WorkPatternInsightType.Neutral]: \"Neutral\",\n};\n\nexport function WorkPatternsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const {\n data: patternsData,\n loading: patternsLoading,\n error: patternsError,\n } = useListWorkPatternsQuery({\n variables: { pagination: { limit: 30 } },\n skip: !workspaceId,\n });\n\n const {\n data: summaryData,\n loading: summaryLoading,\n error: summaryError,\n } = useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const loading = patternsLoading || summaryLoading;\n const error = patternsError || summaryError;\n const summary = summaryData?.workPatternSummary;\n const patterns = patternsData?.workPatterns ?? [];\n const insights = summary?.insights ?? [];\n\n // Chronological order for time-based visuals; the list itself is newest-first.\n const chronological = [...patterns].sort((a, b) => {\n const ta = new Date(a.date).getTime();\n const tb = new Date(b.date).getTime();\n return (Number.isNaN(ta) ? 0 : ta) - (Number.isNaN(tb) ? 0 : tb);\n });\n\n // Derive stats from the latest pattern entry\n const latestPattern = patterns[0];\n const productivityScore =\n summary?.averageProductivity != null\n ? `${Math.round(summary.averageProductivity)}%`\n : \"--\";\n const focusHours =\n latestPattern?.focusHours != null\n ? `${latestPattern.focusHours.toFixed(1)}h`\n : \"--\";\n const totalHours = latestPattern\n ? (\n latestPattern.focusHours +\n latestPattern.meetingHours +\n latestPattern.breakHours\n ).toFixed(0)\n : \"8\";\n const deepWorkSessions =\n latestPattern?.deepWorkSessions != null\n ? String(latestPattern.deepWorkSessions)\n : \"--\";\n const mostProductiveDay = summary?.mostProductiveDay ?? \"--\";\n\n // ---- Heatmap: focus (productive) hours by weekday × week -----------------\n const weekKeys: number[] = [];\n for (const p of chronological) {\n const d = new Date(p.date);\n if (Number.isNaN(d.getTime())) continue;\n const key = weekStart(d).getTime();\n if (!weekKeys.includes(key)) weekKeys.push(key);\n }\n const selectedWeeks = weekKeys.slice(-6); // most recent 6 weeks\n const columnLabels = selectedWeeks.map((ts) =>\n shortDate(new Date(ts).toISOString()),\n );\n const heatmapData: HeatmapValue[][] = DAY_LABELS.map(() =>\n selectedWeeks.map<HeatmapValue>(() => null),\n );\n for (const p of chronological) {\n const d = new Date(p.date);\n if (Number.isNaN(d.getTime())) continue;\n const weekIdx = selectedWeeks.indexOf(weekStart(d).getTime());\n if (weekIdx < 0) continue;\n heatmapData[dayOfWeekIndex(d)][weekIdx] = p.focusHours;\n }\n\n // ---- Energy & mood trend --------------------------------------------------\n const trendData = chronological.map((p) => ({\n date: shortDate(p.date),\n energy:\n p.energyLevel != null ? (ENERGY_SCORE[p.energyLevel] ?? null) : null,\n mood: p.mood != null ? (MOOD_SCORE[p.mood] ?? null) : null,\n }));\n const hasEnergyMood = trendData.some(\n (d) => d.energy != null || d.mood != null,\n );\n\n // ---- Burnout signal (derived from real stress/energy + backend insights) --\n const recent = patterns.slice(0, 7); // most recent logged days\n const windowSize = recent.length;\n const highStressDays = recent.filter(\n (p: WorkPatternFieldsFragment) =>\n p.stressLevel != null && HIGH_STRESS.has(p.stressLevel),\n ).length;\n const lowEnergyDays = recent.filter(\n (p: WorkPatternFieldsFragment) =>\n p.energyLevel != null && LOW_ENERGY.has(p.energyLevel),\n ).length;\n const warningInsight = insights.find(\n (i: WorkPatternInsight) =>\n i.type === WorkPatternInsightType.Warning ||\n i.type === WorkPatternInsightType.Negative,\n );\n const half = Math.ceil(Math.max(windowSize, 1) / 2);\n\n let burnoutTone: BurnoutTone = \"success\";\n if (windowSize > 0 && highStressDays >= half) burnoutTone = \"danger\";\n else if (highStressDays > 0 || lowEnergyDays >= half || warningInsight)\n burnoutTone = \"warning\";\n if (warningInsight?.type === WorkPatternInsightType.Negative)\n burnoutTone = \"danger\";\n\n const stressEvidence: string[] = [];\n if (highStressDays > 0)\n stressEvidence.push(\n `${highStressDays} of your last ${windowSize} logged day${windowSize === 1 ? \"\" : \"s\"} showed high stress`,\n );\n if (lowEnergyDays > 0)\n stressEvidence.push(`${lowEnergyDays} showed low energy`);\n\n const burnoutHeading =\n warningInsight?.title ??\n (burnoutTone === \"danger\"\n ? \"Sustained overload detected\"\n : burnoutTone === \"warning\"\n ? \"Watch your workload\"\n : \"Balanced workload\");\n const burnoutBody =\n warningInsight?.description ??\n (burnoutTone === \"success\"\n ? \"Your recent stress and energy levels look healthy — keep protecting your focus blocks.\"\n : stressEvidence.length > 0\n ? `${stressEvidence.join(\" and \")}. Protect your deep-work time before it erodes.`\n : \"Recent signals suggest an uneven balance — schedule focus time to stay ahead of overload.\");\n const burnoutRecommendation = warningInsight?.recommendation ?? null;\n\n const burnoutAccent =\n burnoutTone === \"danger\"\n ? \"bg-status-error-bg text-status-error-text\"\n : burnoutTone === \"warning\"\n ? \"bg-status-warning-bg text-status-warning-text\"\n : \"bg-status-success-bg text-status-success-text\";\n\n if (loading) {\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n >\n <div className=\"rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n Failed to load work patterns. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n purpose=\"Learn how you actually work across a typical week — when you focus best, where meetings pile up, and which day is your peak — so you can schedule deep work for the hours you're sharpest.\"\n >\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Productivity Score\"\n value={productivityScore}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n trend={\n summary?.averageProductivity != null\n ? { value: 5, label: \"vs last week\" }\n : undefined\n }\n />\n <StatCard\n title=\"Focus Hours\"\n value={focusHours}\n icon={<Brain className=\"h-5 w-5\" />}\n description={`Out of ${totalHours}h total`}\n />\n <StatCard\n title=\"Peak Day\"\n value={mostProductiveDay}\n icon={<Zap className=\"h-5 w-5\" />}\n description=\"Most productive day\"\n />\n <StatCard\n title=\"Deep Work\"\n value={`${deepWorkSessions} sessions`}\n icon={<Clock className=\"h-5 w-5\" />}\n description=\"90+ min uninterrupted\"\n />\n </div>\n\n {/* Burnout signal — honest, derived from recent stress/energy + insights */}\n <GlassCard\n treatment=\"glass\"\n glow={burnoutTone !== \"success\"}\n className=\"p-5 sm:p-6\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start\">\n <div\n className={`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl ${burnoutAccent}`}\n >\n {burnoutTone === \"success\" ? (\n <ShieldCheck className=\"h-5 w-5\" />\n ) : (\n <AlertTriangle className=\"h-5 w-5\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Burnout Signal\n </h3>\n <StatusBadge\n variant={\n burnoutTone === \"danger\"\n ? \"error\"\n : burnoutTone === \"warning\"\n ? \"warning\"\n : \"success\"\n }\n label={burnoutHeading}\n />\n </div>\n <p className=\"mt-1.5 text-sm text-text-secondary\">\n {burnoutBody}\n </p>\n {burnoutRecommendation && (\n <p className=\"mt-2 flex items-start gap-1.5 text-sm text-text-primary\">\n <Lightbulb className=\"mt-0.5 h-4 w-4 shrink-0 text-primary\" />\n <span>{burnoutRecommendation}</span>\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <ChartCard\n title=\"Weekly Productive Hours\"\n description=\"Focused hours logged by weekday across recent weeks\"\n >\n <Heatmap\n data={heatmapData}\n rowLabels={[...DAY_LABELS]}\n columnLabels={columnLabels}\n rowsLabel=\"Day\"\n valueFormat={formatHoursValue}\n legendLabels={[\"Fewer\", \"More\"]}\n height={240}\n emptyLabel=\"No work-pattern days logged yet.\"\n ariaLabel=\"Focused hours by weekday and week\"\n />\n </ChartCard>\n\n <ChartCard\n title=\"Energy & Mood Trends\"\n description=\"Self-reported energy and mood, each on a 1 (low) – 5 (high) scale\"\n >\n {hasEnergyMood ? (\n <TrendChart\n data={trendData}\n xKey=\"date\"\n series={[\n { key: \"energy\", label: \"Energy\" },\n { key: \"mood\", label: \"Mood\" },\n ]}\n type=\"area\"\n height={240}\n emptyLabel=\"No energy or mood check-ins yet.\"\n ariaLabel=\"Energy and mood over time\"\n />\n ) : (\n <EmptyState\n title=\"No energy or mood data yet\"\n description=\"Log how you feel on your work-pattern entries to see the trend here.\"\n />\n )}\n </ChartCard>\n </div>\n\n {insights.length > 0 && (\n <GlassCard treatment=\"glass\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Lightbulb className=\"h-4 w-4 text-primary\" />\n Insights\n </h3>\n <div className=\"space-y-3\">\n {insights.map((insight: WorkPatternInsight, idx: number) => (\n <div\n key={`${insight.type}-${idx}`}\n className=\"rounded-lg border border-border-subtle bg-bg-surface/40 p-4\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge\n variant={INSIGHT_VARIANT[insight.type]}\n label={INSIGHT_LABEL[insight.type]}\n />\n <p className=\"text-sm font-medium text-text-primary\">\n {insight.title}\n </p>\n </div>\n <p className=\"mt-1.5 text-sm text-text-secondary\">\n {insight.description}\n </p>\n {insight.recommendation && (\n <p className=\"mt-2 flex items-start gap-1.5 text-xs text-text-primary\">\n <ArrowRight className=\"mt-0.5 h-3.5 w-3.5 shrink-0 text-primary\" />\n <span>{insight.recommendation}</span>\n </p>\n )}\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkPatternsPage.js","names":[],"sources":["../../../../src/timecampus/pages/work-patterns/WorkPatternsPage.tsx"],"sourcesContent":["import {\n TrendingUp,\n Clock,\n Zap,\n Brain,\n AlertTriangle,\n ShieldCheck,\n Lightbulb,\n ArrowRight,\n} from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport {\n PageLayout,\n StatCard,\n ChartCard,\n Heatmap,\n TrendChart,\n StatusBadge,\n EmptyState,\n LoadingSkeleton,\n type HeatmapValue,\n} from \"../../components\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useListWorkPatternsQuery,\n useGetWorkPatternSummaryQuery,\n type WorkPatternFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport {\n WorkPatternInsightType,\n type WorkPatternInsight,\n} from \"@/generated/wspace-types\";\n\nconst DAY_LABELS = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"] as const;\n\n/** JS `getDay()` is 0=Sun..6=Sat; remap so Monday is index 0. */\nfunction dayOfWeekIndex(d: Date): number {\n return (d.getDay() + 6) % 7;\n}\n\n/** Monday (local midnight) of the week containing `d`. */\nfunction weekStart(d: Date): Date {\n const s = new Date(d);\n s.setDate(d.getDate() - dayOfWeekIndex(d));\n s.setHours(0, 0, 0, 0);\n return s;\n}\n\nfunction shortDate(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"\";\n return d.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\" });\n}\n\n// Self-reported ordinals mapped onto a shared 1 (worst) – 5 (best) scale so\n// energy and mood can be trended together. Only real, fetched enum values map;\n// anything else stays null (a gap in the line, never a fabricated point).\nconst ENERGY_SCORE: Record<string, number> = {\n VERY_LOW: 1,\n LOW: 2,\n MEDIUM: 3,\n HIGH: 4,\n VERY_HIGH: 5,\n};\nconst MOOD_SCORE: Record<string, number> = {\n VERY_NEGATIVE: 1,\n NEGATIVE: 2,\n NEUTRAL: 3,\n POSITIVE: 4,\n VERY_POSITIVE: 5,\n};\n\nconst HIGH_STRESS = new Set([\"HIGH\", \"VERY_HIGH\"]);\nconst LOW_ENERGY = new Set([\"LOW\", \"VERY_LOW\"]);\n\nconst formatHoursValue = (v: number) => `${v.toFixed(1)}h`;\n\ntype BurnoutTone = \"danger\" | \"warning\" | \"success\";\n\nconst INSIGHT_VARIANT: Record<\n WorkPatternInsightType,\n \"success\" | \"error\" | \"warning\" | \"info\" | \"muted\"\n> = {\n [WorkPatternInsightType.Positive]: \"success\",\n [WorkPatternInsightType.Negative]: \"error\",\n [WorkPatternInsightType.Warning]: \"warning\",\n [WorkPatternInsightType.Recommendation]: \"info\",\n [WorkPatternInsightType.Neutral]: \"muted\",\n};\n\nconst INSIGHT_LABEL: Record<WorkPatternInsightType, string> = {\n [WorkPatternInsightType.Positive]: \"Positive\",\n [WorkPatternInsightType.Negative]: \"Negative\",\n [WorkPatternInsightType.Warning]: \"Warning\",\n [WorkPatternInsightType.Recommendation]: \"Tip\",\n [WorkPatternInsightType.Neutral]: \"Neutral\",\n};\n\nexport function WorkPatternsPage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const {\n data: patternsData,\n loading: patternsLoading,\n error: patternsError,\n } = useListWorkPatternsQuery({\n variables: { pagination: { limit: 30 } },\n skip: !workspaceId,\n });\n\n const {\n data: summaryData,\n loading: summaryLoading,\n error: summaryError,\n } = useGetWorkPatternSummaryQuery({\n skip: !workspaceId,\n });\n\n const loading = patternsLoading || summaryLoading;\n const error = patternsError || summaryError;\n const summary = summaryData?.workPatternSummary;\n const patterns = patternsData?.workPatterns ?? [];\n const insights = summary?.insights ?? [];\n\n // Chronological order for time-based visuals; the list itself is newest-first.\n const chronological = [...patterns].sort((a, b) => {\n const ta = new Date(a.date).getTime();\n const tb = new Date(b.date).getTime();\n return (Number.isNaN(ta) ? 0 : ta) - (Number.isNaN(tb) ? 0 : tb);\n });\n\n // Derive stats from the latest pattern entry\n const latestPattern = patterns[0];\n const productivityScore =\n summary?.averageProductivity != null\n ? `${Math.round(summary.averageProductivity)}%`\n : \"--\";\n const focusHours =\n latestPattern?.focusHours != null\n ? `${latestPattern.focusHours.toFixed(1)}h`\n : \"--\";\n const totalHours = latestPattern\n ? (\n latestPattern.focusHours +\n latestPattern.meetingHours +\n latestPattern.breakHours\n ).toFixed(0)\n : \"8\";\n const deepWorkSessions =\n latestPattern?.deepWorkSessions != null\n ? String(latestPattern.deepWorkSessions)\n : \"--\";\n const mostProductiveDay = summary?.mostProductiveDay ?? \"--\";\n\n // ---- Heatmap: focus (productive) hours by weekday × week -----------------\n const weekKeys: number[] = [];\n for (const p of chronological) {\n const d = new Date(p.date);\n if (Number.isNaN(d.getTime())) continue;\n const key = weekStart(d).getTime();\n if (!weekKeys.includes(key)) weekKeys.push(key);\n }\n const selectedWeeks = weekKeys.slice(-6); // most recent 6 weeks\n const columnLabels = selectedWeeks.map((ts) =>\n shortDate(new Date(ts).toISOString()),\n );\n const heatmapData: HeatmapValue[][] = DAY_LABELS.map(() =>\n selectedWeeks.map<HeatmapValue>(() => null),\n );\n for (const p of chronological) {\n const d = new Date(p.date);\n if (Number.isNaN(d.getTime())) continue;\n const weekIdx = selectedWeeks.indexOf(weekStart(d).getTime());\n if (weekIdx < 0) continue;\n heatmapData[dayOfWeekIndex(d)][weekIdx] = p.focusHours;\n }\n\n // ---- Energy & mood trend --------------------------------------------------\n const trendData = chronological.map((p) => ({\n date: shortDate(p.date),\n energy:\n p.energyLevel != null ? (ENERGY_SCORE[p.energyLevel] ?? null) : null,\n mood: p.mood != null ? (MOOD_SCORE[p.mood] ?? null) : null,\n }));\n const hasEnergyMood = trendData.some(\n (d) => d.energy != null || d.mood != null,\n );\n\n // ---- Burnout signal (derived from real stress/energy + backend insights) --\n const recent = patterns.slice(0, 7); // most recent logged days\n const windowSize = recent.length;\n const highStressDays = recent.filter(\n (p: WorkPatternFieldsFragment) =>\n p.stressLevel != null && HIGH_STRESS.has(p.stressLevel),\n ).length;\n const lowEnergyDays = recent.filter(\n (p: WorkPatternFieldsFragment) =>\n p.energyLevel != null && LOW_ENERGY.has(p.energyLevel),\n ).length;\n const warningInsight = insights.find(\n (i: WorkPatternInsight) =>\n i.type === WorkPatternInsightType.Warning ||\n i.type === WorkPatternInsightType.Negative,\n );\n const half = Math.ceil(Math.max(windowSize, 1) / 2);\n\n let burnoutTone: BurnoutTone = \"success\";\n if (windowSize > 0 && highStressDays >= half) burnoutTone = \"danger\";\n else if (highStressDays > 0 || lowEnergyDays >= half || warningInsight)\n burnoutTone = \"warning\";\n if (warningInsight?.type === WorkPatternInsightType.Negative)\n burnoutTone = \"danger\";\n\n const stressEvidence: string[] = [];\n if (highStressDays > 0)\n stressEvidence.push(\n `${highStressDays} of your last ${windowSize} logged day${windowSize === 1 ? \"\" : \"s\"} showed high stress`,\n );\n if (lowEnergyDays > 0)\n stressEvidence.push(`${lowEnergyDays} showed low energy`);\n\n const burnoutHeading =\n warningInsight?.title ??\n (burnoutTone === \"danger\"\n ? \"Sustained overload detected\"\n : burnoutTone === \"warning\"\n ? \"Watch your workload\"\n : \"Balanced workload\");\n const burnoutBody =\n warningInsight?.description ??\n (burnoutTone === \"success\"\n ? \"Your recent stress and energy levels look healthy — keep protecting your focus blocks.\"\n : stressEvidence.length > 0\n ? `${stressEvidence.join(\" and \")}. Protect your deep-work time before it erodes.`\n : \"Recent signals suggest an uneven balance — schedule focus time to stay ahead of overload.\");\n const burnoutRecommendation = warningInsight?.recommendation ?? null;\n\n const burnoutAccent =\n burnoutTone === \"danger\"\n ? \"bg-status-error-bg text-status-error-text\"\n : burnoutTone === \"warning\"\n ? \"bg-status-warning-bg text-status-warning-text\"\n : \"bg-status-success-bg text-status-success-text\";\n\n if (loading) {\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n >\n <LoadingSkeleton variant=\"card\" count={4} />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n >\n <div className=\"rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n Failed to load work patterns. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Work Patterns\"\n description=\"Analyze your work habits and productivity patterns\"\n purpose=\"Learn how you actually work across a typical week — when you focus best, where meetings pile up, and which day is your peak — so you can schedule deep work for the hours you're sharpest.\"\n >\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Productivity Score\"\n value={productivityScore}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n trend={\n summary?.averageProductivity != null\n ? { value: 5, label: \"vs last week\" }\n : undefined\n }\n />\n <StatCard\n title=\"Focus Hours\"\n value={focusHours}\n icon={<Brain className=\"h-5 w-5\" />}\n description={`Out of ${totalHours}h total`}\n />\n <StatCard\n title=\"Peak Day\"\n value={mostProductiveDay}\n icon={<Zap className=\"h-5 w-5\" />}\n description=\"Most productive day\"\n />\n <StatCard\n title=\"Deep Work\"\n value={`${deepWorkSessions} sessions`}\n icon={<Clock className=\"h-5 w-5\" />}\n description=\"90+ min uninterrupted\"\n />\n </div>\n\n {/* Burnout signal — honest, derived from recent stress/energy + insights */}\n <GlassCard\n treatment=\"glass\"\n glow={burnoutTone !== \"success\"}\n className=\"p-5 sm:p-6\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start\">\n <div\n className={`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl ${burnoutAccent}`}\n >\n {burnoutTone === \"success\" ? (\n <ShieldCheck className=\"h-5 w-5\" />\n ) : (\n <AlertTriangle className=\"h-5 w-5\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Burnout Signal\n </h3>\n <StatusBadge\n variant={\n burnoutTone === \"danger\"\n ? \"error\"\n : burnoutTone === \"warning\"\n ? \"warning\"\n : \"success\"\n }\n label={burnoutHeading}\n />\n </div>\n <p className=\"mt-1.5 text-sm text-text-secondary\">\n {burnoutBody}\n </p>\n {burnoutRecommendation && (\n <p className=\"mt-2 flex items-start gap-1.5 text-sm text-text-primary\">\n <Lightbulb className=\"mt-0.5 h-4 w-4 shrink-0 text-primary\" />\n <span>{burnoutRecommendation}</span>\n </p>\n )}\n </div>\n </div>\n </GlassCard>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <ChartCard\n title=\"Weekly Productive Hours\"\n description=\"Focused hours logged by weekday across recent weeks\"\n >\n <Heatmap\n data={heatmapData}\n rowLabels={[...DAY_LABELS]}\n columnLabels={columnLabels}\n rowsLabel=\"Day\"\n valueFormat={formatHoursValue}\n legendLabels={[\"Fewer\", \"More\"]}\n height={240}\n emptyLabel=\"No work-pattern days logged yet.\"\n ariaLabel=\"Focused hours by weekday and week\"\n />\n </ChartCard>\n\n <ChartCard\n title=\"Energy & Mood Trends\"\n description=\"Self-reported energy and mood, each on a 1 (low) – 5 (high) scale\"\n >\n {hasEnergyMood ? (\n <TrendChart\n data={trendData}\n xKey=\"date\"\n series={[\n { key: \"energy\", label: \"Energy\" },\n { key: \"mood\", label: \"Mood\" },\n ]}\n type=\"area\"\n height={240}\n emptyLabel=\"No energy or mood check-ins yet.\"\n ariaLabel=\"Energy and mood over time\"\n />\n ) : (\n <EmptyState\n title=\"No energy or mood data yet\"\n description=\"Log how you feel on your work-pattern entries to see the trend here.\"\n />\n )}\n </ChartCard>\n </div>\n\n {insights.length > 0 && (\n <GlassCard treatment=\"glass\" className=\"p-5 sm:p-6\">\n <h3 className=\"mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Lightbulb className=\"h-4 w-4 text-primary\" />\n Insights\n </h3>\n <div className=\"space-y-3\">\n {insights.map((insight: WorkPatternInsight, idx: number) => (\n <div\n key={`${insight.type}-${idx}`}\n className=\"rounded-lg border border-border-subtle bg-bg-surface/40 p-4\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge\n variant={INSIGHT_VARIANT[insight.type]}\n label={INSIGHT_LABEL[insight.type]}\n />\n <p className=\"text-sm font-medium text-text-primary\">\n {insight.title}\n </p>\n </div>\n <p className=\"mt-1.5 text-sm text-text-secondary\">\n {insight.description}\n </p>\n {insight.recommendation && (\n <p className=\"mt-2 flex items-start gap-1.5 text-xs text-text-primary\">\n <ArrowRight className=\"mt-0.5 h-3.5 w-3.5 shrink-0 text-primary\" />\n <span>{insight.recommendation}</span>\n </p>\n )}\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED