@burdenoff/microfe-timecampus 2026.703.7 → 2026.707.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/generated/wspace-operations.js +1023 -1514
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js +12 -18
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/timecampus/TimeCampusRoot.js +82 -150
- package/dist/timecampus/TimeCampusRoot.js.map +1 -1
- package/dist/timecampus/TimeCampusRoutes.js +96 -164
- package/dist/timecampus/TimeCampusRoutes.js.map +1 -1
- package/dist/timecampus/components/index.js +2 -2
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +7 -7
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +6 -6
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +8 -8
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +6 -6
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js +91 -91
- package/dist/timecampus/pages/lifetime/FiniteLifePage.js.map +1 -1
- package/dist/timecampus/pages/lifetime/LifeBalancePage.js +18 -18
- package/dist/timecampus/pages/lifetime/LifeTimelinePage.js +7 -7
- package/dist/timecampus/pages/lifetime/ValuesGoalsPage.js +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +6 -6
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +7 -7
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +212 -212
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +4 -4
- package/dist/timecampus/pages/time/TimeTrackingPage.js +143 -143
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +87 -93
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/package.json +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +0 -167
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +0 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +0 -162
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +0 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +0 -133
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +0 -418
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +0 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +0 -142
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +0 -119
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +0 -110
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +0 -83
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +0 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +0 -198
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +0 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +0 -124
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +0 -88
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +0 -135
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +0 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +0 -191
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +0 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +0 -196
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +0 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +0 -297
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +0 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +0 -133
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +0 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +0 -311
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +0 -1
|
@@ -6,9 +6,9 @@ import { useApproveExpenseMutation as a, useCreateExpenseMutation as ee, useDele
|
|
|
6
6
|
import { PageLayout as o } from "../../components/PageLayout.js";
|
|
7
7
|
import { StatusBadge as se } from "../../components/StatusBadge.js";
|
|
8
8
|
import { EmptyState as ce } from "../../components/EmptyState.js";
|
|
9
|
-
import {
|
|
9
|
+
import { Modal as s } from "../../components/Modal.js";
|
|
10
|
+
import { ChartCard as c } from "../../components/ChartCard.js";
|
|
10
11
|
import { ToastContainer as le, useToast as ue } from "../../components/Toast.js";
|
|
11
|
-
import { Modal as c } from "../../components/Modal.js";
|
|
12
12
|
import { DonutChart as de } from "../../components/charts/DonutChart.js";
|
|
13
13
|
import { RadialGauge as fe } from "../../components/charts/RadialGauge.js";
|
|
14
14
|
import "../../components/index.js";
|
|
@@ -310,7 +310,7 @@ function C() {
|
|
|
310
310
|
}) : /* @__PURE__ */ h(p, { children: [
|
|
311
311
|
/* @__PURE__ */ h("div", {
|
|
312
312
|
className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
|
|
313
|
-
children: [/* @__PURE__ */ m(
|
|
313
|
+
children: [/* @__PURE__ */ m(c, {
|
|
314
314
|
title: "Spend by category",
|
|
315
315
|
description: "Total tracked spend grouped by category",
|
|
316
316
|
className: "lg:col-span-2",
|
|
@@ -323,7 +323,7 @@ function C() {
|
|
|
323
323
|
emptyLabel: "No categorised spend yet.",
|
|
324
324
|
ariaLabel: "Spend by category"
|
|
325
325
|
})
|
|
326
|
-
}), /* @__PURE__ */ m(
|
|
326
|
+
}), /* @__PURE__ */ m(c, {
|
|
327
327
|
title: "Approval progress",
|
|
328
328
|
description: "Approved vs. awaiting review",
|
|
329
329
|
children: /* @__PURE__ */ m(fe, {
|
|
@@ -441,7 +441,7 @@ function C() {
|
|
|
441
441
|
})
|
|
442
442
|
})
|
|
443
443
|
] }),
|
|
444
|
-
/* @__PURE__ */ m(
|
|
444
|
+
/* @__PURE__ */ m(s, {
|
|
445
445
|
open: qe,
|
|
446
446
|
onClose: Q,
|
|
447
447
|
title: I ? "Edit Expense" : "Add Expense",
|
|
@@ -570,7 +570,7 @@ function C() {
|
|
|
570
570
|
]
|
|
571
571
|
})
|
|
572
572
|
}),
|
|
573
|
-
/* @__PURE__ */ m(
|
|
573
|
+
/* @__PURE__ */ m(s, {
|
|
574
574
|
open: W !== null,
|
|
575
575
|
onClose: () => G(null),
|
|
576
576
|
title: "Delete expense?",
|
|
@@ -591,7 +591,7 @@ function C() {
|
|
|
591
591
|
children: "This permanently removes the expense. This action cannot be undone."
|
|
592
592
|
})
|
|
593
593
|
}),
|
|
594
|
-
/* @__PURE__ */ h(
|
|
594
|
+
/* @__PURE__ */ h(s, {
|
|
595
595
|
open: K !== null,
|
|
596
596
|
onClose: () => q(null),
|
|
597
597
|
title: "Reject expense",
|
|
@@ -618,7 +618,7 @@ function C() {
|
|
|
618
618
|
className: b
|
|
619
619
|
})]
|
|
620
620
|
}),
|
|
621
|
-
/* @__PURE__ */ m(
|
|
621
|
+
/* @__PURE__ */ m(s, {
|
|
622
622
|
open: H !== null,
|
|
623
623
|
onClose: () => U(null),
|
|
624
624
|
title: "Expense review",
|
|
@@ -4,8 +4,8 @@ import { LoadingSkeleton as r } from "../../components/LoadingSkeleton.js";
|
|
|
4
4
|
import { useCreateGeofenceMutation as i, useDeleteGeofenceMutation as a, useListGeofencesQuery as o, useToggleGeofenceMutation as s, useUpdateGeofenceMutation as c } from "../../../generated/wspace-operations.js";
|
|
5
5
|
import { PageLayout as l } from "../../components/PageLayout.js";
|
|
6
6
|
import { EmptyState as u } from "../../components/EmptyState.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { Modal as d } from "../../components/Modal.js";
|
|
8
|
+
import { ChartCard as f } from "../../components/ChartCard.js";
|
|
9
9
|
import { BarsChart as ee } from "../../components/charts/BarsChart.js";
|
|
10
10
|
import { DonutChart as p } from "../../components/charts/DonutChart.js";
|
|
11
11
|
import "../../components/index.js";
|
|
@@ -175,7 +175,7 @@ function k() {
|
|
|
175
175
|
}),
|
|
176
176
|
/* @__PURE__ */ C("div", {
|
|
177
177
|
className: "mt-6 grid grid-cols-1 gap-4 lg:grid-cols-2",
|
|
178
|
-
children: [/* @__PURE__ */ S(
|
|
178
|
+
children: [/* @__PURE__ */ S(f, {
|
|
179
179
|
title: "Trigger configuration",
|
|
180
180
|
description: "How your zones fire",
|
|
181
181
|
children: /* @__PURE__ */ S(p, {
|
|
@@ -185,7 +185,7 @@ function k() {
|
|
|
185
185
|
ariaLabel: "Geofence trigger configuration mix",
|
|
186
186
|
emptyLabel: "No zones to summarize yet"
|
|
187
187
|
})
|
|
188
|
-
}), /* @__PURE__ */ S(
|
|
188
|
+
}), /* @__PURE__ */ S(f, {
|
|
189
189
|
title: "Activity by zone",
|
|
190
190
|
description: "Recorded enter/exit events per zone",
|
|
191
191
|
children: /* @__PURE__ */ S(ee, {
|
|
@@ -351,7 +351,7 @@ function k() {
|
|
|
351
351
|
})
|
|
352
352
|
})
|
|
353
353
|
] }),
|
|
354
|
-
/* @__PURE__ */ C(
|
|
354
|
+
/* @__PURE__ */ C(d, {
|
|
355
355
|
open: R,
|
|
356
356
|
onClose: () => z(!1),
|
|
357
357
|
title: B ? "Edit Geofence" : "Create Geofence",
|
|
@@ -487,7 +487,7 @@ function k() {
|
|
|
487
487
|
]
|
|
488
488
|
})]
|
|
489
489
|
}),
|
|
490
|
-
/* @__PURE__ */ S(
|
|
490
|
+
/* @__PURE__ */ S(d, {
|
|
491
491
|
open: W !== null,
|
|
492
492
|
onClose: () => G(null),
|
|
493
493
|
title: "Delete Geofence",
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
|
-
import { useMyLifeInWeeksQuery as
|
|
4
|
-
import { PageLayout as
|
|
5
|
-
import { EmptyState as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { DonutChart as
|
|
10
|
-
import { WeeksGrid as
|
|
3
|
+
import { useMyLifeInWeeksQuery as n, useMyLifeProfileQuery as ee, useUpdateMyLifeProfileMutation as r } from "../../../generated/wspace-operations.js";
|
|
4
|
+
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
5
|
+
import { EmptyState as te } from "../../components/EmptyState.js";
|
|
6
|
+
import { Modal as ne } from "../../components/Modal.js";
|
|
7
|
+
import { ChartCard as a } from "../../components/ChartCard.js";
|
|
8
|
+
import { ToastContainer as re, useToast as ie } from "../../components/Toast.js";
|
|
9
|
+
import { DonutChart as ae } from "../../components/charts/DonutChart.js";
|
|
10
|
+
import { WeeksGrid as o } from "../../components/charts/WeeksGrid.js";
|
|
11
11
|
import "../../components/index.js";
|
|
12
|
-
import { formatSecondsHuman as
|
|
13
|
-
import { useMemo as
|
|
14
|
-
import { ArrowRight as
|
|
15
|
-
import { Fragment as
|
|
16
|
-
import { GlassCard as
|
|
12
|
+
import { formatSecondsHuman as s, lifeDomainLabel as c } from "./domains.js";
|
|
13
|
+
import { useMemo as l, useState as u } from "react";
|
|
14
|
+
import { ArrowRight as d, CalendarDays as oe, Hourglass as f, Lock as p, SlidersHorizontal as m, Sparkles as h } from "lucide-react";
|
|
15
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
16
|
+
import { GlassCard as se } from "@burdenoff/fe-libs/ui";
|
|
17
17
|
//#region src/timecampus/pages/lifetime/FiniteLifePage.tsx
|
|
18
|
-
function
|
|
18
|
+
function y(e) {
|
|
19
19
|
return Math.max(0, Math.round(e)).toLocaleString();
|
|
20
20
|
}
|
|
21
|
-
function
|
|
21
|
+
function b(e) {
|
|
22
22
|
return (Math.round(e / 52 * 10) / 10).toFixed(1);
|
|
23
23
|
}
|
|
24
|
-
function
|
|
24
|
+
function ce(e) {
|
|
25
25
|
return e ? e.slice(0, 10) : "";
|
|
26
26
|
}
|
|
27
27
|
var x = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
28
28
|
function S() {
|
|
29
|
-
let { workspaceId: S = "" } = e(), { toasts: le, addToast: C, dismissToast: w } =
|
|
30
|
-
B(
|
|
29
|
+
let { workspaceId: S = "" } = e(), { toasts: le, addToast: C, dismissToast: w } = ie(), { data: T, loading: E, error: D, refetch: O } = n({ skip: !S }), { data: k, loading: A, error: j, refetch: M } = ee({ skip: !S }), [N, { loading: P }] = r(), F = T?.myLifeInWeeks, I = k?.myLifeProfile, [L, R] = u(!1), [z, B] = u(""), [V, H] = u(""), [U, W] = u(!1), [G, K] = u(null), q = () => {
|
|
30
|
+
B(ce(I?.birthDate ?? F?.birthDate)), H(I?.lifeExpectancyYears == null ? F?.lifeExpectancyYears == null ? "" : String(F.lifeExpectancyYears) : String(I.lifeExpectancyYears)), W(I?.hideRemainingWeeks ?? F?.hideRemainingWeeks ?? !1), K(null), R(!0);
|
|
31
31
|
}, ue = async (e) => {
|
|
32
32
|
if (e?.preventDefault(), K(null), !z) {
|
|
33
33
|
K("Please add your birth date to continue.");
|
|
@@ -64,88 +64,88 @@ function S() {
|
|
|
64
64
|
description: "Please try again in a moment."
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
|
-
}, J = !!F?.birthDate, Y = F?.hideRemainingWeeks ?? I?.hideRemainingWeeks ?? !1, X = F?.weeksLived ?? null, Z = F?.lifeExpectancyYears ?? null, de = Y ? null : F?.expectedTotalWeeks ?? null, Q = Y || F?.weeksRemaining == null ? null : F.weeksRemaining, $ =
|
|
68
|
-
name:
|
|
67
|
+
}, J = !!F?.birthDate, Y = F?.hideRemainingWeeks ?? I?.hideRemainingWeeks ?? !1, X = F?.weeksLived ?? null, Z = F?.lifeExpectancyYears ?? null, de = Y ? null : F?.expectedTotalWeeks ?? null, Q = Y || F?.weeksRemaining == null ? null : F.weeksRemaining, $ = l(() => (F?.domainRollups ?? []).filter((e) => e.totalSeconds > 0).map((e) => ({
|
|
68
|
+
name: c(e.domain),
|
|
69
69
|
value: e.totalSeconds
|
|
70
70
|
})), [F?.domainRollups]), fe = $.reduce((e, t) => e + t.value, 0);
|
|
71
|
-
return (E || A) && !F && !I ? /* @__PURE__ */
|
|
71
|
+
return (E || A) && !F && !I ? /* @__PURE__ */ _(i, {
|
|
72
72
|
title: "Your Life in Weeks",
|
|
73
73
|
description: "A calm, private view of the weeks you've lived — and the ones still ahead.",
|
|
74
|
-
children: /* @__PURE__ */
|
|
75
|
-
}) : /* @__PURE__ */
|
|
74
|
+
children: /* @__PURE__ */ _(t, { variant: "detail" })
|
|
75
|
+
}) : /* @__PURE__ */ v(i, {
|
|
76
76
|
title: "Your Life in Weeks",
|
|
77
77
|
description: "A calm, private view of the weeks you've lived — and the ones still ahead.",
|
|
78
78
|
purpose: "Each square is a single week of your life. It's a gentle memento — not a countdown — meant only for you, to help this week feel a little more intentional.",
|
|
79
|
-
actions: /* @__PURE__ */
|
|
79
|
+
actions: /* @__PURE__ */ v("button", {
|
|
80
80
|
type: "button",
|
|
81
81
|
onClick: q,
|
|
82
82
|
className: "inline-flex items-center gap-1.5 rounded-md border border-border-subtle bg-bg-surface px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
|
|
83
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ _(m, { className: "h-4 w-4" }), "Life settings"]
|
|
84
84
|
}),
|
|
85
85
|
children: [
|
|
86
|
-
(D || j) && !F && !I ? /* @__PURE__ */
|
|
86
|
+
(D || j) && !F && !I ? /* @__PURE__ */ _("div", {
|
|
87
87
|
className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
|
|
88
88
|
children: "We couldn't load your life view right now. Please try again in a moment."
|
|
89
|
-
}) : /* @__PURE__ */
|
|
89
|
+
}) : /* @__PURE__ */ v("div", {
|
|
90
90
|
className: "space-y-6",
|
|
91
91
|
children: [
|
|
92
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ v("div", {
|
|
93
93
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ _("div", {
|
|
95
95
|
className: "lg:col-span-2",
|
|
96
|
-
children: /* @__PURE__ */
|
|
96
|
+
children: /* @__PURE__ */ v(a, {
|
|
97
97
|
title: "Your life in weeks",
|
|
98
98
|
description: J ? "Each row is a year; each square, a week you have lived or have yet to live." : "Add your birth date to fill in the weeks you've already lived.",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ _(o, {
|
|
100
100
|
weeksLived: X,
|
|
101
101
|
totalWeeks: de,
|
|
102
|
-
ariaLabel: J ? `Your life in weeks: ${
|
|
103
|
-
}), /* @__PURE__ */
|
|
102
|
+
ariaLabel: J ? `Your life in weeks: ${y(X ?? 0)} weeks lived so far` : "Your life in weeks — birth date not set yet"
|
|
103
|
+
}), /* @__PURE__ */ v("div", {
|
|
104
104
|
className: "mt-4 flex flex-wrap items-center gap-x-5 gap-y-2 text-xs text-text-secondary",
|
|
105
105
|
children: [
|
|
106
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ v("span", {
|
|
107
107
|
className: "flex items-center gap-1.5",
|
|
108
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ _("span", { className: "h-3 w-3 rounded-[3px] bg-action-primary-bg" }), "Weeks lived"]
|
|
109
109
|
}),
|
|
110
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ v("span", {
|
|
111
111
|
className: "flex items-center gap-1.5",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: [/* @__PURE__ */ _("span", { className: "h-3 w-3 rounded-[3px] border-2 border-action-primary-bg bg-bg-surface" }), "This week"]
|
|
113
113
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ v("span", {
|
|
115
115
|
className: "flex items-center gap-1.5",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
116
|
+
children: [/* @__PURE__ */ _("span", { className: "h-3 w-3 rounded-[3px] border border-border-seam" }), "Ahead"]
|
|
117
117
|
})
|
|
118
118
|
]
|
|
119
119
|
})]
|
|
120
120
|
})
|
|
121
|
-
}), /* @__PURE__ */
|
|
121
|
+
}), /* @__PURE__ */ v(se, {
|
|
122
122
|
treatment: "glass",
|
|
123
123
|
glow: !0,
|
|
124
124
|
className: "flex flex-col p-5 sm:p-6",
|
|
125
125
|
children: [
|
|
126
|
-
/* @__PURE__ */
|
|
126
|
+
/* @__PURE__ */ _("div", {
|
|
127
127
|
className: "flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/10 text-primary",
|
|
128
|
-
children: /* @__PURE__ */
|
|
128
|
+
children: /* @__PURE__ */ _(f, { className: "h-5 w-5" })
|
|
129
129
|
}),
|
|
130
|
-
J ? /* @__PURE__ */
|
|
130
|
+
J ? /* @__PURE__ */ v("div", {
|
|
131
131
|
className: "mt-4 space-y-5",
|
|
132
132
|
children: [
|
|
133
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
134
134
|
className: "text-sm text-text-secondary",
|
|
135
135
|
children: "You have lived"
|
|
136
|
-
}), /* @__PURE__ */
|
|
136
|
+
}), /* @__PURE__ */ v("p", {
|
|
137
137
|
className: "mt-0.5 text-3xl font-bold tabular-nums text-text-primary",
|
|
138
138
|
children: [
|
|
139
|
-
|
|
139
|
+
y(X ?? 0),
|
|
140
140
|
" ",
|
|
141
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ _("span", {
|
|
142
142
|
className: "text-xl font-semibold text-text-secondary",
|
|
143
143
|
children: "weeks"
|
|
144
144
|
})
|
|
145
145
|
]
|
|
146
146
|
})] }),
|
|
147
|
-
Z != null && Q != null ? /* @__PURE__ */
|
|
148
|
-
/* @__PURE__ */
|
|
147
|
+
Z != null && Q != null ? /* @__PURE__ */ v("div", { children: [
|
|
148
|
+
/* @__PURE__ */ v("p", {
|
|
149
149
|
className: "text-sm text-text-secondary",
|
|
150
150
|
children: [
|
|
151
151
|
"If you live to ",
|
|
@@ -153,108 +153,108 @@ function S() {
|
|
|
153
153
|
", about"
|
|
154
154
|
]
|
|
155
155
|
}),
|
|
156
|
-
/* @__PURE__ */
|
|
156
|
+
/* @__PURE__ */ v("p", {
|
|
157
157
|
className: "mt-0.5 text-2xl font-bold tabular-nums text-text-primary",
|
|
158
158
|
children: [
|
|
159
|
-
|
|
159
|
+
y(Q),
|
|
160
160
|
" ",
|
|
161
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ _("span", {
|
|
162
162
|
className: "text-lg font-semibold text-text-secondary",
|
|
163
163
|
children: "remain"
|
|
164
164
|
})
|
|
165
165
|
]
|
|
166
166
|
}),
|
|
167
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ v("p", {
|
|
168
168
|
className: "mt-1 text-xs text-text-secondary",
|
|
169
169
|
children: [
|
|
170
|
-
|
|
170
|
+
b(X ?? 0),
|
|
171
171
|
" years lived ·",
|
|
172
172
|
" ",
|
|
173
|
-
|
|
173
|
+
b(Q),
|
|
174
174
|
" years ahead"
|
|
175
175
|
]
|
|
176
176
|
})
|
|
177
|
-
] }) : /* @__PURE__ */
|
|
177
|
+
] }) : /* @__PURE__ */ _("p", {
|
|
178
178
|
className: "text-xs text-text-secondary",
|
|
179
179
|
children: Y ? "You've chosen to see only the weeks you've lived." : "Add a life expectancy in settings to gently sketch the weeks ahead."
|
|
180
180
|
}),
|
|
181
|
-
/* @__PURE__ */
|
|
181
|
+
/* @__PURE__ */ _("div", {
|
|
182
182
|
className: "rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
183
|
-
children: /* @__PURE__ */
|
|
183
|
+
children: /* @__PURE__ */ v("p", {
|
|
184
184
|
className: "flex items-start gap-2 text-sm text-text-primary",
|
|
185
|
-
children: [/* @__PURE__ */ h
|
|
185
|
+
children: [/* @__PURE__ */ _(h, { className: "mt-0.5 h-4 w-4 shrink-0 text-primary" }), /* @__PURE__ */ _("span", { children: "What if today was your last? Make this week count." })]
|
|
186
186
|
})
|
|
187
187
|
})
|
|
188
188
|
]
|
|
189
|
-
}) : /* @__PURE__ */
|
|
189
|
+
}) : /* @__PURE__ */ v("div", {
|
|
190
190
|
className: "mt-4 space-y-4",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
191
|
+
children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h3", {
|
|
192
192
|
className: "text-base font-semibold text-text-primary",
|
|
193
193
|
children: "See your life in weeks"
|
|
194
|
-
}), /* @__PURE__ */
|
|
194
|
+
}), /* @__PURE__ */ _("p", {
|
|
195
195
|
className: "mt-1 text-sm text-text-secondary",
|
|
196
196
|
children: "Add your birth date and we'll gently fill in the weeks you've lived so far — a quiet reminder that time is finite, and this week is yours to spend."
|
|
197
|
-
})] }), /* @__PURE__ */
|
|
197
|
+
})] }), /* @__PURE__ */ v("button", {
|
|
198
198
|
type: "button",
|
|
199
199
|
onClick: q,
|
|
200
200
|
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
201
|
-
children: ["Add your birth date", /* @__PURE__ */
|
|
201
|
+
children: ["Add your birth date", /* @__PURE__ */ _(d, { className: "h-4 w-4" })]
|
|
202
202
|
})]
|
|
203
203
|
}),
|
|
204
|
-
/* @__PURE__ */
|
|
204
|
+
/* @__PURE__ */ v("p", {
|
|
205
205
|
className: "mt-6 flex items-start gap-1.5 text-xs text-text-secondary",
|
|
206
|
-
children: [/* @__PURE__ */
|
|
206
|
+
children: [/* @__PURE__ */ _(p, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ _("span", { children: "Only you can see this. Your birth date is never shared, and you can turn this off anytime." })]
|
|
207
207
|
})
|
|
208
208
|
]
|
|
209
209
|
})]
|
|
210
210
|
}),
|
|
211
|
-
$.length > 0 && /* @__PURE__ */
|
|
211
|
+
$.length > 0 && /* @__PURE__ */ _(a, {
|
|
212
212
|
title: "Where your recent weeks went",
|
|
213
213
|
description: "How your logged time settled across life's domains lately — a mirror, not a scorecard.",
|
|
214
|
-
children: /* @__PURE__ */
|
|
214
|
+
children: /* @__PURE__ */ _(ae, {
|
|
215
215
|
data: $,
|
|
216
216
|
centerLabel: "logged lately",
|
|
217
|
-
centerValue:
|
|
218
|
-
valueFormat: (e) =>
|
|
217
|
+
centerValue: s(fe),
|
|
218
|
+
valueFormat: (e) => s(e),
|
|
219
219
|
emptyLabel: "Nothing logged in this window yet.",
|
|
220
220
|
ariaLabel: "Recent time by life domain"
|
|
221
221
|
})
|
|
222
222
|
}),
|
|
223
|
-
J && $.length === 0 && /* @__PURE__ */
|
|
223
|
+
J && $.length === 0 && /* @__PURE__ */ _(te, {
|
|
224
224
|
title: "Your weeks are yours to shape",
|
|
225
225
|
description: "As you capture how you spend your time, a quiet reflection of your recent weeks will appear here — only for you."
|
|
226
226
|
})
|
|
227
227
|
]
|
|
228
228
|
}),
|
|
229
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ _(ne, {
|
|
230
230
|
open: L,
|
|
231
231
|
onClose: () => R(!1),
|
|
232
232
|
title: "Your life in weeks",
|
|
233
233
|
description: "This is private and entirely optional. Add only what feels comfortable.",
|
|
234
|
-
footer: /* @__PURE__ */ g
|
|
234
|
+
footer: /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("button", {
|
|
235
235
|
type: "button",
|
|
236
236
|
onClick: () => R(!1),
|
|
237
237
|
className: "rounded-md border border-border-subtle px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken hover:text-text-primary",
|
|
238
238
|
children: "Cancel"
|
|
239
|
-
}), /* @__PURE__ */
|
|
239
|
+
}), /* @__PURE__ */ _("button", {
|
|
240
240
|
type: "submit",
|
|
241
241
|
form: "finite-life-setup",
|
|
242
242
|
disabled: P,
|
|
243
243
|
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
|
|
244
244
|
children: P ? "Saving…" : "Save"
|
|
245
245
|
})] }),
|
|
246
|
-
children: /* @__PURE__ */
|
|
246
|
+
children: /* @__PURE__ */ v("form", {
|
|
247
247
|
id: "finite-life-setup",
|
|
248
248
|
onSubmit: ue,
|
|
249
249
|
className: "space-y-5",
|
|
250
250
|
children: [
|
|
251
|
-
/* @__PURE__ */
|
|
252
|
-
/* @__PURE__ */
|
|
251
|
+
/* @__PURE__ */ v("div", { children: [
|
|
252
|
+
/* @__PURE__ */ v("label", {
|
|
253
253
|
htmlFor: "finite-life-birthdate",
|
|
254
254
|
className: "flex items-center gap-1.5 text-sm font-medium text-text-primary",
|
|
255
|
-
children: [/* @__PURE__ */
|
|
255
|
+
children: [/* @__PURE__ */ _(oe, { className: "h-4 w-4 text-text-secondary" }), "Your birth date"]
|
|
256
256
|
}),
|
|
257
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ _("input", {
|
|
258
258
|
id: "finite-life-birthdate",
|
|
259
259
|
type: "date",
|
|
260
260
|
value: z,
|
|
@@ -262,25 +262,25 @@ function S() {
|
|
|
262
262
|
onChange: (e) => B(e.target.value),
|
|
263
263
|
className: "mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary"
|
|
264
264
|
}),
|
|
265
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ _("p", {
|
|
266
266
|
className: "mt-1.5 text-xs text-text-secondary",
|
|
267
267
|
children: "Used only to count the weeks you've lived. It stays with you."
|
|
268
268
|
})
|
|
269
269
|
] }),
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ v("div", { children: [
|
|
271
|
+
/* @__PURE__ */ v("label", {
|
|
272
272
|
htmlFor: "finite-life-expectancy",
|
|
273
273
|
className: "text-sm font-medium text-text-primary",
|
|
274
274
|
children: [
|
|
275
275
|
"Life expectancy",
|
|
276
276
|
" ",
|
|
277
|
-
/* @__PURE__ */
|
|
277
|
+
/* @__PURE__ */ _("span", {
|
|
278
278
|
className: "font-normal text-text-secondary",
|
|
279
279
|
children: "(optional)"
|
|
280
280
|
})
|
|
281
281
|
]
|
|
282
282
|
}),
|
|
283
|
-
/* @__PURE__ */
|
|
283
|
+
/* @__PURE__ */ _("input", {
|
|
284
284
|
id: "finite-life-expectancy",
|
|
285
285
|
type: "number",
|
|
286
286
|
inputMode: "numeric",
|
|
@@ -292,34 +292,34 @@ function S() {
|
|
|
292
292
|
onChange: (e) => H(e.target.value),
|
|
293
293
|
className: "mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary"
|
|
294
294
|
}),
|
|
295
|
-
/* @__PURE__ */
|
|
295
|
+
/* @__PURE__ */ _("p", {
|
|
296
296
|
className: "mt-1.5 text-xs text-text-secondary",
|
|
297
297
|
children: "A gentle horizon for the weeks ahead — never a deadline. Leave it blank to simply see the weeks you've lived."
|
|
298
298
|
})
|
|
299
299
|
] }),
|
|
300
|
-
/* @__PURE__ */
|
|
300
|
+
/* @__PURE__ */ v("label", {
|
|
301
301
|
className: "flex items-start gap-2.5 rounded-lg border border-border-subtle bg-bg-surface/40 p-3",
|
|
302
|
-
children: [/* @__PURE__ */
|
|
302
|
+
children: [/* @__PURE__ */ _("input", {
|
|
303
303
|
type: "checkbox",
|
|
304
304
|
checked: U,
|
|
305
305
|
onChange: (e) => W(e.target.checked),
|
|
306
306
|
className: "mt-0.5 h-4 w-4 shrink-0 rounded border-border-subtle"
|
|
307
|
-
}), /* @__PURE__ */
|
|
307
|
+
}), /* @__PURE__ */ v("span", {
|
|
308
308
|
className: "text-sm text-text-primary",
|
|
309
|
-
children: ["Hide the weeks ahead", /* @__PURE__ */
|
|
309
|
+
children: ["Hide the weeks ahead", /* @__PURE__ */ _("span", {
|
|
310
310
|
className: "mt-0.5 block text-xs text-text-secondary",
|
|
311
311
|
children: "Show only the weeks you've lived — no horizon, no countdown."
|
|
312
312
|
})]
|
|
313
313
|
})]
|
|
314
314
|
}),
|
|
315
|
-
G && /* @__PURE__ */
|
|
315
|
+
G && /* @__PURE__ */ _("p", {
|
|
316
316
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text",
|
|
317
317
|
children: G
|
|
318
318
|
})
|
|
319
319
|
]
|
|
320
320
|
})
|
|
321
321
|
}),
|
|
322
|
-
/* @__PURE__ */
|
|
322
|
+
/* @__PURE__ */ _(re, {
|
|
323
323
|
toasts: le,
|
|
324
324
|
onDismiss: w
|
|
325
325
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FiniteLifePage.js","names":[],"sources":["../../../../src/timecampus/pages/lifetime/FiniteLifePage.tsx"],"sourcesContent":["import { useMemo, useState, type FormEvent } from \"react\";\nimport {\n Hourglass,\n Sparkles,\n SlidersHorizontal,\n CalendarDays,\n Lock,\n ArrowRight,\n} from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport {\n PageLayout,\n ChartCard,\n EmptyState,\n Modal,\n DonutChart,\n WeeksGrid,\n LoadingSkeleton,\n ToastContainer,\n useToast,\n type DonutSlice,\n} from \"../../components\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useMyLifeInWeeksQuery,\n useMyLifeProfileQuery,\n useUpdateMyLifeProfileMutation,\n type MyLifeInWeeksQuery,\n} from \"@/generated/wspace-operations\";\nimport { lifeDomainLabel, formatSecondsHuman } from \"./domains\";\n\n/** One life-domain roll-up row, typed from the generated query result. */\ntype LifeDomainRollup =\n MyLifeInWeeksQuery[\"myLifeInWeeks\"][\"domainRollups\"][number];\n\n/** Grouped integer (e.g. 1,742). */\nfunction nf(n: number): string {\n return Math.max(0, Math.round(n)).toLocaleString();\n}\n\n/** Whole-week count → years with one decimal (e.g. 33.5). */\nfunction weeksToYears(weeks: number): string {\n return (Math.round((weeks / 52) * 10) / 10).toFixed(1);\n}\n\n/** ISO datetime → the `YYYY-MM-DD` a native date input expects. */\nfunction isoToDateInput(iso: string | null | undefined): string {\n if (!iso) return \"\";\n return iso.slice(0, 10);\n}\n\nconst TODAY_DATE_INPUT = new Date().toISOString().slice(0, 10);\n\n/**\n * FiniteLifePage — the finite-life \"your life in weeks\" memento.\n *\n * A calm, opt-in, entirely private reflection: each cell is one week of a life,\n * anchored to the gentle north star \"What if today was your last?\". Everything\n * it draws comes from the viewer's own (optional) birth date and life\n * expectancy — never a guessed age or an invented mortality date. It is\n * self-scoped (identity travels in the gateway headers, so the queries take no\n * user argument) and honest by construction: with no birth date it still\n * renders an open horizon and simply invites you to add one. It respects the\n * `hideRemainingWeeks` choice so no one is forced to stare down a countdown.\n */\nexport function FiniteLifePage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { toasts, addToast, dismissToast } = useToast();\n\n const {\n data: weeksData,\n loading: weeksLoading,\n error: weeksError,\n refetch: refetchWeeks,\n } = useMyLifeInWeeksQuery({ skip: !workspaceId });\n\n const {\n data: profileData,\n loading: profileLoading,\n error: profileError,\n refetch: refetchProfile,\n } = useMyLifeProfileQuery({ skip: !workspaceId });\n\n const [updateProfile, { loading: saving }] = useUpdateMyLifeProfileMutation();\n\n const weeks = weeksData?.myLifeInWeeks;\n const profile = profileData?.myLifeProfile;\n\n // ---- Setup modal (opt-in, dismissible) -----------------------------------\n const [setupOpen, setSetupOpen] = useState(false);\n const [birthDateInput, setBirthDateInput] = useState(\"\");\n const [expectancyInput, setExpectancyInput] = useState(\"\");\n const [hideRemainingInput, setHideRemainingInput] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n\n const openSetup = () => {\n setBirthDateInput(isoToDateInput(profile?.birthDate ?? weeks?.birthDate));\n setExpectancyInput(\n profile?.lifeExpectancyYears != null\n ? String(profile.lifeExpectancyYears)\n : weeks?.lifeExpectancyYears != null\n ? String(weeks.lifeExpectancyYears)\n : \"\",\n );\n setHideRemainingInput(\n profile?.hideRemainingWeeks ?? weeks?.hideRemainingWeeks ?? false,\n );\n setFormError(null);\n setSetupOpen(true);\n };\n\n const handleSave = async (e?: FormEvent) => {\n e?.preventDefault();\n setFormError(null);\n\n if (!birthDateInput) {\n setFormError(\"Please add your birth date to continue.\");\n return;\n }\n if (birthDateInput > TODAY_DATE_INPUT) {\n setFormError(\"Your birth date can't be in the future.\");\n return;\n }\n\n let expectancy: number | null = null;\n if (expectancyInput.trim() !== \"\") {\n const parsed = Number(expectancyInput);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 130) {\n setFormError(\n \"Life expectancy should be a whole number of years (1–130).\",\n );\n return;\n }\n expectancy = parsed;\n }\n\n try {\n await updateProfile({\n variables: {\n input: {\n birthDate: new Date(\n `${birthDateInput}T00:00:00.000Z`,\n ).toISOString(),\n lifeExpectancyYears: expectancy,\n hideRemainingWeeks: hideRemainingInput,\n finiteLifeOptIn: true,\n },\n },\n });\n await Promise.all([refetchWeeks(), refetchProfile()]);\n setSetupOpen(false);\n addToast({\n variant: \"success\",\n title: \"Saved — this is just for you\",\n description: \"You can change or turn this off anytime.\",\n });\n } catch {\n addToast({\n variant: \"error\",\n title: \"Couldn't save your settings\",\n description: \"Please try again in a moment.\",\n });\n }\n };\n\n // ---- Derived, honest values ----------------------------------------------\n const hasBirthDate = !!weeks?.birthDate;\n const hideRemaining =\n weeks?.hideRemainingWeeks ?? profile?.hideRemainingWeeks ?? false;\n\n const weeksLived = weeks?.weeksLived ?? null;\n const expectancyYears = weeks?.lifeExpectancyYears ?? null;\n // Only reveal the full mortal horizon when the user hasn't asked to hide it.\n const gridTotalWeeks = hideRemaining\n ? null\n : (weeks?.expectedTotalWeeks ?? null);\n const weeksRemaining =\n hideRemaining || weeks?.weeksRemaining == null\n ? null\n : weeks.weeksRemaining;\n\n // Reflection: where the recent (backend-defined) window actually went.\n const domainSlices: DonutSlice[] = useMemo(() => {\n const rollups: LifeDomainRollup[] = weeks?.domainRollups ?? [];\n return rollups\n .filter((r) => r.totalSeconds > 0)\n .map((r) => ({\n name: lifeDomainLabel(r.domain),\n value: r.totalSeconds,\n }));\n }, [weeks?.domainRollups]);\n const rollupTotalSeconds = domainSlices.reduce((sum, s) => sum + s.value, 0);\n\n const loading = weeksLoading || profileLoading;\n const hardError = (weeksError || profileError) && !weeks && !profile;\n\n const setupAction = (\n <button\n type=\"button\"\n onClick={openSetup}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle bg-bg-surface px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n Life settings\n </button>\n );\n\n if (loading && !weeks && !profile) {\n return (\n <PageLayout\n title=\"Your Life in Weeks\"\n description=\"A calm, private view of the weeks you've lived — and the ones still ahead.\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Your Life in Weeks\"\n description=\"A calm, private view of the weeks you've lived — and the ones still ahead.\"\n purpose=\"Each square is a single week of your life. It's a gentle memento — not a countdown — meant only for you, to help this week feel a little more intentional.\"\n actions={setupAction}\n >\n {hardError ? (\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 We couldn't load your life view right now. Please try again in a\n moment.\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* The grid — the memento itself */}\n <div className=\"lg:col-span-2\">\n <ChartCard\n title=\"Your life in weeks\"\n description={\n hasBirthDate\n ? \"Each row is a year; each square, a week you have lived or have yet to live.\"\n : \"Add your birth date to fill in the weeks you've already lived.\"\n }\n >\n <WeeksGrid\n weeksLived={weeksLived}\n totalWeeks={gridTotalWeeks}\n ariaLabel={\n hasBirthDate\n ? `Your life in weeks: ${nf(weeksLived ?? 0)} weeks lived so far`\n : \"Your life in weeks — birth date not set yet\"\n }\n />\n <div className=\"mt-4 flex flex-wrap items-center gap-x-5 gap-y-2 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] bg-action-primary-bg\" />\n Weeks lived\n </span>\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] border-2 border-action-primary-bg bg-bg-surface\" />\n This week\n </span>\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] border border-border-seam\" />\n Ahead\n </span>\n </div>\n </ChartCard>\n </div>\n\n {/* The calm side card */}\n <GlassCard\n treatment=\"glass\"\n glow\n className=\"flex flex-col p-5 sm:p-6\"\n >\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/10 text-primary\">\n <Hourglass className=\"h-5 w-5\" />\n </div>\n\n {hasBirthDate ? (\n <div className=\"mt-4 space-y-5\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n You have lived\n </p>\n <p className=\"mt-0.5 text-3xl font-bold tabular-nums text-text-primary\">\n {nf(weeksLived ?? 0)}{\" \"}\n <span className=\"text-xl font-semibold text-text-secondary\">\n weeks\n </span>\n </p>\n </div>\n\n {expectancyYears != null && weeksRemaining != null ? (\n <div>\n <p className=\"text-sm text-text-secondary\">\n If you live to {expectancyYears}, about\n </p>\n <p className=\"mt-0.5 text-2xl font-bold tabular-nums text-text-primary\">\n {nf(weeksRemaining)}{\" \"}\n <span className=\"text-lg font-semibold text-text-secondary\">\n remain\n </span>\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {weeksToYears(weeksLived ?? 0)} years lived ·{\" \"}\n {weeksToYears(weeksRemaining)} years ahead\n </p>\n </div>\n ) : (\n <p className=\"text-xs text-text-secondary\">\n {hideRemaining\n ? \"You've chosen to see only the weeks you've lived.\"\n : \"Add a life expectancy in settings to gently sketch the weeks ahead.\"}\n </p>\n )}\n\n <div className=\"rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <p className=\"flex items-start gap-2 text-sm text-text-primary\">\n <Sparkles className=\"mt-0.5 h-4 w-4 shrink-0 text-primary\" />\n <span>\n What if today was your last? Make this week count.\n </span>\n </p>\n </div>\n </div>\n ) : (\n <div className=\"mt-4 space-y-4\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n See your life in weeks\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Add your birth date and we'll gently fill in the weeks\n you've lived so far — a quiet reminder that time is\n finite, and this week is yours to spend.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={openSetup}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n Add your birth date\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n\n <p className=\"mt-6 flex items-start gap-1.5 text-xs text-text-secondary\">\n <Lock className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>\n Only you can see this. Your birth date is never shared, and\n you can turn this off anytime.\n </span>\n </p>\n </GlassCard>\n </div>\n\n {/* Gentle reflection — only when there's real recent data to show */}\n {domainSlices.length > 0 && (\n <ChartCard\n title=\"Where your recent weeks went\"\n description=\"How your logged time settled across life's domains lately — a mirror, not a scorecard.\"\n >\n <DonutChart\n data={domainSlices}\n centerLabel=\"logged lately\"\n centerValue={formatSecondsHuman(rollupTotalSeconds)}\n valueFormat={(v) => formatSecondsHuman(v)}\n emptyLabel=\"Nothing logged in this window yet.\"\n ariaLabel=\"Recent time by life domain\"\n />\n </ChartCard>\n )}\n\n {/* Honest first-run nudge when nothing has been logged either */}\n {hasBirthDate && domainSlices.length === 0 && (\n <EmptyState\n title=\"Your weeks are yours to shape\"\n description=\"As you capture how you spend your time, a quiet reflection of your recent weeks will appear here — only for you.\"\n />\n )}\n </div>\n )}\n\n {/* Opt-in setup */}\n <Modal\n open={setupOpen}\n onClose={() => setSetupOpen(false)}\n title=\"Your life in weeks\"\n description=\"This is private and entirely optional. Add only what feels comfortable.\"\n footer={\n <>\n <button\n type=\"button\"\n onClick={() => setSetupOpen(false)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n form=\"finite-life-setup\"\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {saving ? \"Saving…\" : \"Save\"}\n </button>\n </>\n }\n >\n <form\n id=\"finite-life-setup\"\n onSubmit={handleSave}\n className=\"space-y-5\"\n >\n <div>\n <label\n htmlFor=\"finite-life-birthdate\"\n className=\"flex items-center gap-1.5 text-sm font-medium text-text-primary\"\n >\n <CalendarDays className=\"h-4 w-4 text-text-secondary\" />\n Your birth date\n </label>\n <input\n id=\"finite-life-birthdate\"\n type=\"date\"\n value={birthDateInput}\n max={TODAY_DATE_INPUT}\n onChange={(e) => setBirthDateInput(e.target.value)}\n className=\"mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary\"\n />\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n Used only to count the weeks you've lived. It stays with you.\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"finite-life-expectancy\"\n className=\"text-sm font-medium text-text-primary\"\n >\n Life expectancy{\" \"}\n <span className=\"font-normal text-text-secondary\">\n (optional)\n </span>\n </label>\n <input\n id=\"finite-life-expectancy\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={130}\n step={1}\n placeholder=\"e.g. 90\"\n value={expectancyInput}\n onChange={(e) => setExpectancyInput(e.target.value)}\n className=\"mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary\"\n />\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n A gentle horizon for the weeks ahead — never a deadline. Leave it\n blank to simply see the weeks you've lived.\n </p>\n </div>\n\n <label className=\"flex items-start gap-2.5 rounded-lg border border-border-subtle bg-bg-surface/40 p-3\">\n <input\n type=\"checkbox\"\n checked={hideRemainingInput}\n onChange={(e) => setHideRemainingInput(e.target.checked)}\n className=\"mt-0.5 h-4 w-4 shrink-0 rounded border-border-subtle\"\n />\n <span className=\"text-sm text-text-primary\">\n Hide the weeks ahead\n <span className=\"mt-0.5 block text-xs text-text-secondary\">\n Show only the weeks you've lived — no horizon, no countdown.\n </span>\n </span>\n </label>\n\n {formError && (\n <p className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text\">\n {formError}\n </p>\n )}\n </form>\n </Modal>\n\n <ToastContainer toasts={toasts} onDismiss={dismissToast} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FiniteLifePage.js","names":[],"sources":["../../../../src/timecampus/pages/lifetime/FiniteLifePage.tsx"],"sourcesContent":["import { useMemo, useState, type FormEvent } from \"react\";\nimport {\n Hourglass,\n Sparkles,\n SlidersHorizontal,\n CalendarDays,\n Lock,\n ArrowRight,\n} from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport {\n PageLayout,\n ChartCard,\n EmptyState,\n Modal,\n DonutChart,\n WeeksGrid,\n LoadingSkeleton,\n ToastContainer,\n useToast,\n type DonutSlice,\n} from \"../../components\";\nimport { useTimeCampus } from \"../../providers/TimeCampusProvider\";\nimport {\n useMyLifeInWeeksQuery,\n useMyLifeProfileQuery,\n useUpdateMyLifeProfileMutation,\n type MyLifeInWeeksQuery,\n} from \"@/generated/wspace-operations\";\nimport { lifeDomainLabel, formatSecondsHuman } from \"./domains\";\n\n/** One life-domain roll-up row, typed from the generated query result. */\ntype LifeDomainRollup =\n MyLifeInWeeksQuery[\"myLifeInWeeks\"][\"domainRollups\"][number];\n\n/** Grouped integer (e.g. 1,742). */\nfunction nf(n: number): string {\n return Math.max(0, Math.round(n)).toLocaleString();\n}\n\n/** Whole-week count → years with one decimal (e.g. 33.5). */\nfunction weeksToYears(weeks: number): string {\n return (Math.round((weeks / 52) * 10) / 10).toFixed(1);\n}\n\n/** ISO datetime → the `YYYY-MM-DD` a native date input expects. */\nfunction isoToDateInput(iso: string | null | undefined): string {\n if (!iso) return \"\";\n return iso.slice(0, 10);\n}\n\nconst TODAY_DATE_INPUT = new Date().toISOString().slice(0, 10);\n\n/**\n * FiniteLifePage — the finite-life \"your life in weeks\" memento.\n *\n * A calm, opt-in, entirely private reflection: each cell is one week of a life,\n * anchored to the gentle north star \"What if today was your last?\". Everything\n * it draws comes from the viewer's own (optional) birth date and life\n * expectancy — never a guessed age or an invented mortality date. It is\n * self-scoped (identity travels in the gateway headers, so the queries take no\n * user argument) and honest by construction: with no birth date it still\n * renders an open horizon and simply invites you to add one. It respects the\n * `hideRemainingWeeks` choice so no one is forced to stare down a countdown.\n */\nexport function FiniteLifePage() {\n const { workspaceId = \"\" } = useTimeCampus();\n const { toasts, addToast, dismissToast } = useToast();\n\n const {\n data: weeksData,\n loading: weeksLoading,\n error: weeksError,\n refetch: refetchWeeks,\n } = useMyLifeInWeeksQuery({ skip: !workspaceId });\n\n const {\n data: profileData,\n loading: profileLoading,\n error: profileError,\n refetch: refetchProfile,\n } = useMyLifeProfileQuery({ skip: !workspaceId });\n\n const [updateProfile, { loading: saving }] = useUpdateMyLifeProfileMutation();\n\n const weeks = weeksData?.myLifeInWeeks;\n const profile = profileData?.myLifeProfile;\n\n // ---- Setup modal (opt-in, dismissible) -----------------------------------\n const [setupOpen, setSetupOpen] = useState(false);\n const [birthDateInput, setBirthDateInput] = useState(\"\");\n const [expectancyInput, setExpectancyInput] = useState(\"\");\n const [hideRemainingInput, setHideRemainingInput] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n\n const openSetup = () => {\n setBirthDateInput(isoToDateInput(profile?.birthDate ?? weeks?.birthDate));\n setExpectancyInput(\n profile?.lifeExpectancyYears != null\n ? String(profile.lifeExpectancyYears)\n : weeks?.lifeExpectancyYears != null\n ? String(weeks.lifeExpectancyYears)\n : \"\",\n );\n setHideRemainingInput(\n profile?.hideRemainingWeeks ?? weeks?.hideRemainingWeeks ?? false,\n );\n setFormError(null);\n setSetupOpen(true);\n };\n\n const handleSave = async (e?: FormEvent) => {\n e?.preventDefault();\n setFormError(null);\n\n if (!birthDateInput) {\n setFormError(\"Please add your birth date to continue.\");\n return;\n }\n if (birthDateInput > TODAY_DATE_INPUT) {\n setFormError(\"Your birth date can't be in the future.\");\n return;\n }\n\n let expectancy: number | null = null;\n if (expectancyInput.trim() !== \"\") {\n const parsed = Number(expectancyInput);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 130) {\n setFormError(\n \"Life expectancy should be a whole number of years (1–130).\",\n );\n return;\n }\n expectancy = parsed;\n }\n\n try {\n await updateProfile({\n variables: {\n input: {\n birthDate: new Date(\n `${birthDateInput}T00:00:00.000Z`,\n ).toISOString(),\n lifeExpectancyYears: expectancy,\n hideRemainingWeeks: hideRemainingInput,\n finiteLifeOptIn: true,\n },\n },\n });\n await Promise.all([refetchWeeks(), refetchProfile()]);\n setSetupOpen(false);\n addToast({\n variant: \"success\",\n title: \"Saved — this is just for you\",\n description: \"You can change or turn this off anytime.\",\n });\n } catch {\n addToast({\n variant: \"error\",\n title: \"Couldn't save your settings\",\n description: \"Please try again in a moment.\",\n });\n }\n };\n\n // ---- Derived, honest values ----------------------------------------------\n const hasBirthDate = !!weeks?.birthDate;\n const hideRemaining =\n weeks?.hideRemainingWeeks ?? profile?.hideRemainingWeeks ?? false;\n\n const weeksLived = weeks?.weeksLived ?? null;\n const expectancyYears = weeks?.lifeExpectancyYears ?? null;\n // Only reveal the full mortal horizon when the user hasn't asked to hide it.\n const gridTotalWeeks = hideRemaining\n ? null\n : (weeks?.expectedTotalWeeks ?? null);\n const weeksRemaining =\n hideRemaining || weeks?.weeksRemaining == null\n ? null\n : weeks.weeksRemaining;\n\n // Reflection: where the recent (backend-defined) window actually went.\n const domainSlices: DonutSlice[] = useMemo(() => {\n const rollups: LifeDomainRollup[] = weeks?.domainRollups ?? [];\n return rollups\n .filter((r) => r.totalSeconds > 0)\n .map((r) => ({\n name: lifeDomainLabel(r.domain),\n value: r.totalSeconds,\n }));\n }, [weeks?.domainRollups]);\n const rollupTotalSeconds = domainSlices.reduce((sum, s) => sum + s.value, 0);\n\n const loading = weeksLoading || profileLoading;\n const hardError = (weeksError || profileError) && !weeks && !profile;\n\n const setupAction = (\n <button\n type=\"button\"\n onClick={openSetup}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle bg-bg-surface px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n Life settings\n </button>\n );\n\n if (loading && !weeks && !profile) {\n return (\n <PageLayout\n title=\"Your Life in Weeks\"\n description=\"A calm, private view of the weeks you've lived — and the ones still ahead.\"\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Your Life in Weeks\"\n description=\"A calm, private view of the weeks you've lived — and the ones still ahead.\"\n purpose=\"Each square is a single week of your life. It's a gentle memento — not a countdown — meant only for you, to help this week feel a little more intentional.\"\n actions={setupAction}\n >\n {hardError ? (\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 We couldn't load your life view right now. Please try again in a\n moment.\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* The grid — the memento itself */}\n <div className=\"lg:col-span-2\">\n <ChartCard\n title=\"Your life in weeks\"\n description={\n hasBirthDate\n ? \"Each row is a year; each square, a week you have lived or have yet to live.\"\n : \"Add your birth date to fill in the weeks you've already lived.\"\n }\n >\n <WeeksGrid\n weeksLived={weeksLived}\n totalWeeks={gridTotalWeeks}\n ariaLabel={\n hasBirthDate\n ? `Your life in weeks: ${nf(weeksLived ?? 0)} weeks lived so far`\n : \"Your life in weeks — birth date not set yet\"\n }\n />\n <div className=\"mt-4 flex flex-wrap items-center gap-x-5 gap-y-2 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] bg-action-primary-bg\" />\n Weeks lived\n </span>\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] border-2 border-action-primary-bg bg-bg-surface\" />\n This week\n </span>\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-3 w-3 rounded-[3px] border border-border-seam\" />\n Ahead\n </span>\n </div>\n </ChartCard>\n </div>\n\n {/* The calm side card */}\n <GlassCard\n treatment=\"glass\"\n glow\n className=\"flex flex-col p-5 sm:p-6\"\n >\n <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-action-primary-bg/10 text-primary\">\n <Hourglass className=\"h-5 w-5\" />\n </div>\n\n {hasBirthDate ? (\n <div className=\"mt-4 space-y-5\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n You have lived\n </p>\n <p className=\"mt-0.5 text-3xl font-bold tabular-nums text-text-primary\">\n {nf(weeksLived ?? 0)}{\" \"}\n <span className=\"text-xl font-semibold text-text-secondary\">\n weeks\n </span>\n </p>\n </div>\n\n {expectancyYears != null && weeksRemaining != null ? (\n <div>\n <p className=\"text-sm text-text-secondary\">\n If you live to {expectancyYears}, about\n </p>\n <p className=\"mt-0.5 text-2xl font-bold tabular-nums text-text-primary\">\n {nf(weeksRemaining)}{\" \"}\n <span className=\"text-lg font-semibold text-text-secondary\">\n remain\n </span>\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {weeksToYears(weeksLived ?? 0)} years lived ·{\" \"}\n {weeksToYears(weeksRemaining)} years ahead\n </p>\n </div>\n ) : (\n <p className=\"text-xs text-text-secondary\">\n {hideRemaining\n ? \"You've chosen to see only the weeks you've lived.\"\n : \"Add a life expectancy in settings to gently sketch the weeks ahead.\"}\n </p>\n )}\n\n <div className=\"rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <p className=\"flex items-start gap-2 text-sm text-text-primary\">\n <Sparkles className=\"mt-0.5 h-4 w-4 shrink-0 text-primary\" />\n <span>\n What if today was your last? Make this week count.\n </span>\n </p>\n </div>\n </div>\n ) : (\n <div className=\"mt-4 space-y-4\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n See your life in weeks\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Add your birth date and we'll gently fill in the weeks\n you've lived so far — a quiet reminder that time is\n finite, and this week is yours to spend.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={openSetup}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n Add your birth date\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n\n <p className=\"mt-6 flex items-start gap-1.5 text-xs text-text-secondary\">\n <Lock className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>\n Only you can see this. Your birth date is never shared, and\n you can turn this off anytime.\n </span>\n </p>\n </GlassCard>\n </div>\n\n {/* Gentle reflection — only when there's real recent data to show */}\n {domainSlices.length > 0 && (\n <ChartCard\n title=\"Where your recent weeks went\"\n description=\"How your logged time settled across life's domains lately — a mirror, not a scorecard.\"\n >\n <DonutChart\n data={domainSlices}\n centerLabel=\"logged lately\"\n centerValue={formatSecondsHuman(rollupTotalSeconds)}\n valueFormat={(v) => formatSecondsHuman(v)}\n emptyLabel=\"Nothing logged in this window yet.\"\n ariaLabel=\"Recent time by life domain\"\n />\n </ChartCard>\n )}\n\n {/* Honest first-run nudge when nothing has been logged either */}\n {hasBirthDate && domainSlices.length === 0 && (\n <EmptyState\n title=\"Your weeks are yours to shape\"\n description=\"As you capture how you spend your time, a quiet reflection of your recent weeks will appear here — only for you.\"\n />\n )}\n </div>\n )}\n\n {/* Opt-in setup */}\n <Modal\n open={setupOpen}\n onClose={() => setSetupOpen(false)}\n title=\"Your life in weeks\"\n description=\"This is private and entirely optional. Add only what feels comfortable.\"\n footer={\n <>\n <button\n type=\"button\"\n onClick={() => setSetupOpen(false)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n form=\"finite-life-setup\"\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {saving ? \"Saving…\" : \"Save\"}\n </button>\n </>\n }\n >\n <form\n id=\"finite-life-setup\"\n onSubmit={handleSave}\n className=\"space-y-5\"\n >\n <div>\n <label\n htmlFor=\"finite-life-birthdate\"\n className=\"flex items-center gap-1.5 text-sm font-medium text-text-primary\"\n >\n <CalendarDays className=\"h-4 w-4 text-text-secondary\" />\n Your birth date\n </label>\n <input\n id=\"finite-life-birthdate\"\n type=\"date\"\n value={birthDateInput}\n max={TODAY_DATE_INPUT}\n onChange={(e) => setBirthDateInput(e.target.value)}\n className=\"mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary\"\n />\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n Used only to count the weeks you've lived. It stays with you.\n </p>\n </div>\n\n <div>\n <label\n htmlFor=\"finite-life-expectancy\"\n className=\"text-sm font-medium text-text-primary\"\n >\n Life expectancy{\" \"}\n <span className=\"font-normal text-text-secondary\">\n (optional)\n </span>\n </label>\n <input\n id=\"finite-life-expectancy\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={130}\n step={1}\n placeholder=\"e.g. 90\"\n value={expectancyInput}\n onChange={(e) => setExpectancyInput(e.target.value)}\n className=\"mt-2 w-full rounded-lg border border-border-subtle bg-bg-sunken px-3 py-2 text-sm text-text-primary\"\n />\n <p className=\"mt-1.5 text-xs text-text-secondary\">\n A gentle horizon for the weeks ahead — never a deadline. Leave it\n blank to simply see the weeks you've lived.\n </p>\n </div>\n\n <label className=\"flex items-start gap-2.5 rounded-lg border border-border-subtle bg-bg-surface/40 p-3\">\n <input\n type=\"checkbox\"\n checked={hideRemainingInput}\n onChange={(e) => setHideRemainingInput(e.target.checked)}\n className=\"mt-0.5 h-4 w-4 shrink-0 rounded border-border-subtle\"\n />\n <span className=\"text-sm text-text-primary\">\n Hide the weeks ahead\n <span className=\"mt-0.5 block text-xs text-text-secondary\">\n Show only the weeks you've lived — no horizon, no countdown.\n </span>\n </span>\n </label>\n\n {formError && (\n <p className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text\">\n {formError}\n </p>\n )}\n </form>\n </Modal>\n\n <ToastContainer toasts={toasts} onDismiss={dismissToast} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|