@burdenoff/microfe-timecampus 2026.626.2 → 2026.703.2
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 +996 -816
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js +28 -0
- package/dist/generated/wspace-types.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/timecampus/TimeCampusRoutes.js +16 -12
- package/dist/timecampus/TimeCampusRoutes.js.map +1 -1
- package/dist/timecampus/components/Modal.js +65 -0
- package/dist/timecampus/components/Modal.js.map +1 -0
- package/dist/timecampus/components/StatusBadge.js +28 -0
- package/dist/timecampus/components/StatusBadge.js.map +1 -0
- package/dist/timecampus/components/Toast.js +87 -0
- package/dist/timecampus/components/Toast.js.map +1 -0
- package/dist/timecampus/index.js +1 -1
- package/dist/timecampus/pages/HomePage.js +143 -135
- package/dist/timecampus/pages/HomePage.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +14 -19
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +49 -37
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +315 -87
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +340 -46
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +374 -92
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +70 -37
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +366 -60
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +461 -87
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +314 -55
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +30 -27
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +269 -74
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/ActionItemFormModal.js +127 -0
- package/dist/timecampus/pages/meetings/ActionItemFormModal.js.map +1 -0
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +62 -52
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +361 -74
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingFormModal.js +156 -0
- package/dist/timecampus/pages/meetings/MeetingFormModal.js.map +1 -0
- package/dist/timecampus/pages/meetings/MeetingsPage.js +175 -74
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/ParticipantFormModal.js +105 -0
- package/dist/timecampus/pages/meetings/ParticipantFormModal.js.map +1 -0
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +307 -67
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +51 -48
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +248 -51
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +354 -87
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +367 -65
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +674 -104
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +46 -34
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +93 -69
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +4 -3
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +72 -53
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +40 -35
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +484 -97
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +210 -99
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +229 -97
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +315 -110
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/timeline/TimelinePage.js +250 -0
- package/dist/timecampus/pages/timeline/TimelinePage.js.map +1 -0
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +158 -76
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +181 -52
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +212 -61
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/dist/timecampus/store/timecampusStore.js +13 -1
- package/dist/timecampus/store/timecampusStore.js.map +1 -1
- package/dist/timecampus/utils/helpers.js +20 -10
- package/dist/timecampus/utils/helpers.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","names":[],"sources":["../../../src/timecampus/components/Toast.tsx"],"sourcesContent":["import { useEffect, useCallback, useState, type FC } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { X, CheckCircle, AlertTriangle, Info, XCircle } from \"lucide-react\";\nimport { cn } from \"../utils/helpers\";\n\nexport type ToastVariant = \"success\" | \"error\" | \"warning\" | \"info\";\n\nexport interface ToastData {\n id: string;\n title: string;\n description?: string;\n variant: ToastVariant;\n duration?: number;\n}\n\ninterface ToastProps extends ToastData {\n onDismiss: (id: string) => void;\n}\n\nconst variantConfig: Record<\n ToastVariant,\n { icon: typeof CheckCircle; className: string }\n> = {\n success: {\n icon: CheckCircle,\n className:\n \"border-status-success-bg/40 bg-status-success-bg text-status-success-text\",\n },\n error: {\n icon: XCircle,\n className:\n \"border-status-error-bg/40 bg-status-error-bg text-status-error-text\",\n },\n warning: {\n icon: AlertTriangle,\n className:\n \"border-status-warning-bg/40 bg-status-warning-bg text-status-warning-text\",\n },\n info: {\n icon: Info,\n className:\n \"border-status-info-bg/40 bg-status-info-bg text-status-info-text\",\n },\n};\n\nexport const Toast: FC<ToastProps> = ({\n id,\n title,\n description,\n variant,\n duration = 4000,\n onDismiss,\n}) => {\n const { icon: Icon, className } = variantConfig[variant];\n\n useEffect(() => {\n if (duration > 0) {\n const timer = setTimeout(() => onDismiss(id), duration);\n return () => clearTimeout(timer);\n }\n }, [id, duration, onDismiss]);\n\n return (\n <div\n className={cn(\n \"flex items-start gap-3 rounded-lg border p-4 shadow-pop animate-in slide-in-from-right-full\",\n className,\n )}\n role=\"alert\"\n >\n <Icon className=\"mt-0.5 h-5 w-5 shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium\">{title}</p>\n {description && (\n <p className=\"mt-0.5 text-xs opacity-80\">{description}</p>\n )}\n </div>\n <button\n onClick={() => onDismiss(id)}\n className=\"shrink-0 opacity-60 hover:opacity-100\"\n aria-label=\"Dismiss\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n );\n};\n\ninterface ToastContainerProps {\n toasts: ToastData[];\n onDismiss: (id: string) => void;\n}\n\nexport const ToastContainer: FC<ToastContainerProps> = ({\n toasts,\n onDismiss,\n}) => {\n if (toasts.length === 0) return null;\n return createPortal(\n <div className=\"fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2\">\n {toasts.map((t) => (\n <Toast key={t.id} {...t} onDismiss={onDismiss} />\n ))}\n </div>,\n document.body,\n );\n};\n\n/** Hook for managing toast state */\nexport function useToast() {\n const [toasts, setToasts] = useState<ToastData[]>([]);\n\n const addToast = useCallback((toast: Omit<ToastData, \"id\">) => {\n const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n setToasts((prev) => [...prev, { ...toast, id }]);\n return id;\n }, []);\n\n const dismissToast = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const clearToasts = useCallback(() => {\n setToasts([]);\n }, []);\n\n return { toasts, addToast, dismissToast, clearToasts };\n}\n"],"mappings":";;;;;;AAmBA,IAAM,IAGF;CACF,SAAS;EACP,MAAM;EACN,WACE;EACH;CACD,OAAO;EACL,MAAM;EACN,WACE;EACH;CACD,SAAS;EACP,MAAM;EACN,WACE;EACH;CACD,MAAM;EACJ,MAAM;EACN,WACE;EACH;CACF,EAEY,KAAyB,EACpC,OACA,UACA,gBACA,YACA,cAAW,KACX,mBACI;CACJ,IAAM,EAAE,MAAM,GAAM,iBAAc,EAAc;AAShD,QAPA,QAAgB;AACd,MAAI,IAAW,GAAG;GAChB,IAAM,IAAQ,iBAAiB,EAAU,EAAG,EAAE,EAAS;AACvD,gBAAa,aAAa,EAAM;;IAEjC;EAAC;EAAI;EAAU;EAAU,CAAC,EAG3B,kBAAC,OAAD;EACE,WAAW,EACT,+FACA,EACD;EACD,MAAK;YALP;GAOE,kBAAC,GAAD,EAAM,WAAU,2BAA4B,CAAA;GAC5C,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAuB;KAAU,CAAA,EAC7C,KACC,kBAAC,KAAD;KAAG,WAAU;eAA6B;KAAgB,CAAA,CAExD;;GACN,kBAAC,UAAD;IACE,eAAe,EAAU,EAAG;IAC5B,WAAU;IACV,cAAW;cAEX,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;IAClB,CAAA;GACL;;GASG,KAA2C,EACtD,WACA,mBAEI,EAAO,WAAW,IAAU,OACzB,EACL,kBAAC,OAAD;CAAK,WAAU;WACZ,EAAO,KAAK,MACX,kBAAC,GAAD;EAAkB,GAAI;EAAc;EAAa,EAArC,EAAE,GAAmC,CACjD;CACE,CAAA,EACN,SAAS,KACV;AAIH,SAAgB,IAAW;CACzB,IAAM,CAAC,GAAQ,KAAa,EAAsB,EAAE,CAAC;AAgBrD,QAAO;EAAE;EAAQ,UAdA,GAAa,MAAiC;GAC7D,IAAM,IAAK,SAAS,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE;AAExE,UADA,GAAW,MAAS,CAAC,GAAG,GAAM;IAAE,GAAG;IAAO;IAAI,CAAC,CAAC,EACzC;KACN,EAAE,CAAC;EAUqB,cARN,GAAa,MAAe;AAC/C,MAAW,MAAS,EAAK,QAAQ,MAAM,EAAE,OAAO,EAAG,CAAC;KACnD,EAAE,CAAC;EAMmC,aAJrB,QAAkB;AACpC,KAAU,EAAE,CAAC;KACZ,EAAE,CAAC;EAEgD"}
|
package/dist/timecampus/index.js
CHANGED
|
@@ -1,248 +1,256 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useTimeCampusNavigate as e } from "../providers/TimeCampusProvider.js";
|
|
2
|
+
import { cn as t, formatHours as n } from "../utils/helpers.js";
|
|
2
3
|
import { StatCard as r } from "../components/StatCard.js";
|
|
3
4
|
import { LoadingSkeleton as i } from "../components/LoadingSkeleton.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { useI18n as w } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
|
+
import { useGetTimeEntryStatsQuery as a, useListTimeEntriesQuery as o } from "../../generated/wspace-operations.js";
|
|
6
|
+
import { ArrowRight as s, BarChart3 as c, CheckCircle as l, Clock as u, FolderOpen as d, Play as f, TrendingUp as p, Users as m } from "lucide-react";
|
|
7
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
8
|
+
import { AuroraBackground as _, CTAOverflowMenu as v, EmphasisPanel as y, GlassCard as b, GradientText as x } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
import { useI18n as S } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
10
|
//#region src/timecampus/pages/HomePage.tsx
|
|
11
|
-
var
|
|
12
|
-
let { t:
|
|
13
|
-
let n =
|
|
11
|
+
var C = () => {
|
|
12
|
+
let { t: C } = S(), w = (e, t) => {
|
|
13
|
+
let n = C(e);
|
|
14
14
|
return n === e ? t : n;
|
|
15
|
-
},
|
|
15
|
+
}, T = e(), { data: E, loading: D } = a(), { data: O, loading: k } = o({ variables: { limit: 4 } }), A = E?.timeEntryStats, j = O?.timeEntries?.items ?? [], M = /* @__PURE__ */ h(v, {
|
|
16
16
|
primary: {
|
|
17
|
-
label:
|
|
18
|
-
onSelect: () =>
|
|
19
|
-
icon:
|
|
17
|
+
label: w("timecampus.home.actions.startTimer", "Start Timer"),
|
|
18
|
+
onSelect: () => T("/time/timer"),
|
|
19
|
+
icon: /* @__PURE__ */ h(f, { className: "h-4 w-4" })
|
|
20
20
|
},
|
|
21
21
|
actions: [{
|
|
22
|
-
label:
|
|
23
|
-
onSelect: () =>
|
|
24
|
-
icon: /* @__PURE__ */
|
|
22
|
+
label: w("timecampus.home.quickActions.viewProjects.label", "View Projects"),
|
|
23
|
+
onSelect: () => T("/projects"),
|
|
24
|
+
icon: /* @__PURE__ */ h(d, { className: "h-4 w-4" })
|
|
25
25
|
}, {
|
|
26
|
-
label:
|
|
27
|
-
onSelect: () =>
|
|
28
|
-
icon: /* @__PURE__ */
|
|
26
|
+
label: w("timecampus.home.quickActions.reports.label", "Reports"),
|
|
27
|
+
onSelect: () => T("/reports"),
|
|
28
|
+
icon: /* @__PURE__ */ h(c, { className: "h-4 w-4" })
|
|
29
29
|
}]
|
|
30
|
-
}),
|
|
30
|
+
}), N = () => /* @__PURE__ */ g("div", {
|
|
31
31
|
className: "relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6",
|
|
32
|
-
children: [/* @__PURE__ */ _
|
|
32
|
+
children: [/* @__PURE__ */ h(_, { intensity: "subtle" }), /* @__PURE__ */ g("div", {
|
|
33
33
|
className: "relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
34
|
+
children: [/* @__PURE__ */ g("div", {
|
|
35
35
|
className: "min-w-0",
|
|
36
|
-
children: [/* @__PURE__ */
|
|
36
|
+
children: [/* @__PURE__ */ h("h1", {
|
|
37
37
|
className: "text-2xl font-bold text-text-primary",
|
|
38
|
-
children: /* @__PURE__ */
|
|
39
|
-
}), /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ h(x, { children: w("timecampus.home.title", "Dashboard") })
|
|
39
|
+
}), /* @__PURE__ */ h("p", {
|
|
40
40
|
className: "mt-1 text-sm text-text-secondary",
|
|
41
|
-
children:
|
|
41
|
+
children: w("timecampus.home.description", "Overview of your time tracking and productivity")
|
|
42
42
|
})]
|
|
43
|
-
}),
|
|
43
|
+
}), M]
|
|
44
44
|
})]
|
|
45
45
|
});
|
|
46
|
-
return
|
|
46
|
+
return D && k ? /* @__PURE__ */ g("div", {
|
|
47
47
|
className: "min-h-full space-y-6 p-4 sm:p-6",
|
|
48
|
-
children: [
|
|
48
|
+
children: [N(), /* @__PURE__ */ h(i, {
|
|
49
49
|
variant: "card",
|
|
50
50
|
count: 4
|
|
51
51
|
})]
|
|
52
|
-
}) : /* @__PURE__ */
|
|
52
|
+
}) : /* @__PURE__ */ g("div", {
|
|
53
53
|
className: "min-h-full space-y-6 p-4 sm:p-6",
|
|
54
54
|
children: [
|
|
55
|
-
|
|
56
|
-
/* @__PURE__ */
|
|
55
|
+
N(),
|
|
56
|
+
/* @__PURE__ */ g("div", {
|
|
57
57
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
58
58
|
children: [
|
|
59
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ h(r, {
|
|
60
60
|
featured: !0,
|
|
61
|
-
title:
|
|
62
|
-
value:
|
|
63
|
-
icon: /* @__PURE__ */
|
|
61
|
+
title: w("timecampus.home.stats.today", "Today"),
|
|
62
|
+
value: n(A?.totalHours ?? 0),
|
|
63
|
+
icon: /* @__PURE__ */ h(u, { className: "h-5 w-5" }),
|
|
64
64
|
trend: {
|
|
65
65
|
value: 12.5,
|
|
66
|
-
label:
|
|
66
|
+
label: w("timecampus.home.stats.vsYesterday", "vs yesterday")
|
|
67
67
|
}
|
|
68
68
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
70
|
-
title:
|
|
71
|
-
value:
|
|
72
|
-
icon: /* @__PURE__ */
|
|
73
|
-
description: `${
|
|
69
|
+
/* @__PURE__ */ h(r, {
|
|
70
|
+
title: w("timecampus.home.stats.billable", "Billable"),
|
|
71
|
+
value: n(A?.billableHours ?? 0),
|
|
72
|
+
icon: /* @__PURE__ */ h(p, { className: "h-5 w-5" }),
|
|
73
|
+
description: `${A?.totalEntries ?? 0} ${w("timecampus.home.stats.entries", "entries")}`
|
|
74
74
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
title:
|
|
77
|
-
value:
|
|
78
|
-
icon: /* @__PURE__ */
|
|
79
|
-
description:
|
|
75
|
+
/* @__PURE__ */ h(r, {
|
|
76
|
+
title: w("timecampus.home.stats.activeTimers", "Active Timers"),
|
|
77
|
+
value: A?.activeTimers ?? 0,
|
|
78
|
+
icon: /* @__PURE__ */ h(d, { className: "h-5 w-5" }),
|
|
79
|
+
description: w("timecampus.home.stats.currentlyRunning", "Currently running")
|
|
80
80
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
title:
|
|
83
|
-
value:
|
|
84
|
-
icon: /* @__PURE__ */
|
|
85
|
-
description:
|
|
81
|
+
/* @__PURE__ */ h(r, {
|
|
82
|
+
title: w("timecampus.home.stats.totalEntries", "Entries"),
|
|
83
|
+
value: A?.totalEntries ?? 0,
|
|
84
|
+
icon: /* @__PURE__ */ h(c, { className: "h-5 w-5" }),
|
|
85
|
+
description: w("timecampus.home.stats.totalEntriesDescription", "Total time entries")
|
|
86
86
|
})
|
|
87
87
|
]
|
|
88
88
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ g("div", {
|
|
90
90
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
91
|
-
children: [/* @__PURE__ */
|
|
91
|
+
children: [/* @__PURE__ */ g(b, {
|
|
92
92
|
treatment: "plain",
|
|
93
93
|
className: "border-border-seam p-6 lg:col-span-2",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ g("div", {
|
|
95
95
|
className: "mb-4 flex items-center justify-between",
|
|
96
|
-
children: [/* @__PURE__ */
|
|
96
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h3", {
|
|
97
97
|
className: "text-sm font-semibold text-text-primary",
|
|
98
|
-
children:
|
|
99
|
-
}), /* @__PURE__ */
|
|
98
|
+
children: w("timecampus.home.recentEntries.title", "Recent Time Entries")
|
|
99
|
+
}), /* @__PURE__ */ h("p", {
|
|
100
100
|
className: "text-xs text-text-secondary",
|
|
101
|
-
children:
|
|
102
|
-
})] }), /* @__PURE__ */
|
|
101
|
+
children: w("timecampus.home.recentEntries.description", "Your latest tracked activities")
|
|
102
|
+
})] }), /* @__PURE__ */ g("button", {
|
|
103
|
+
onClick: () => T("/time/entries"),
|
|
103
104
|
className: "inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border",
|
|
104
105
|
children: [
|
|
105
|
-
|
|
106
|
+
w("timecampus.home.recentEntries.viewAll", "View all"),
|
|
106
107
|
" ",
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ h(s, { className: "h-3 w-3" })
|
|
108
109
|
]
|
|
109
110
|
})]
|
|
110
|
-
}),
|
|
111
|
+
}), k ? /* @__PURE__ */ h(i, {
|
|
111
112
|
variant: "list",
|
|
112
113
|
count: 4
|
|
113
|
-
}) : /* @__PURE__ */
|
|
114
|
+
}) : /* @__PURE__ */ g("div", {
|
|
114
115
|
className: "flex flex-col gap-3",
|
|
115
|
-
children: [
|
|
116
|
+
children: [j.map((e) => /* @__PURE__ */ g("div", {
|
|
116
117
|
className: "flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ g("div", {
|
|
118
119
|
className: "min-w-0 flex-1",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
120
|
+
children: [/* @__PURE__ */ h("p", {
|
|
120
121
|
className: "text-sm font-medium text-text-primary",
|
|
121
|
-
children:
|
|
122
|
-
}), /* @__PURE__ */
|
|
122
|
+
children: e.project?.name ?? w("timecampus.home.recentEntries.noProject", "No Project")
|
|
123
|
+
}), /* @__PURE__ */ h("p", {
|
|
123
124
|
className: "text-xs text-text-secondary",
|
|
124
|
-
children:
|
|
125
|
+
children: e.description ?? w("timecampus.home.recentEntries.noDescription", "No description")
|
|
125
126
|
})]
|
|
126
|
-
}), /* @__PURE__ */
|
|
127
|
+
}), /* @__PURE__ */ g("div", {
|
|
127
128
|
className: "ml-4 text-right",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
129
|
+
children: [/* @__PURE__ */ h("p", {
|
|
129
130
|
className: "font-mono text-sm font-medium tabular-nums text-text-primary",
|
|
130
|
-
children:
|
|
131
|
-
}), /* @__PURE__ */
|
|
132
|
-
className:
|
|
133
|
-
children: [
|
|
131
|
+
children: n((e.duration ?? 0) / 3600)
|
|
132
|
+
}), /* @__PURE__ */ g("span", {
|
|
133
|
+
className: t("inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium", e.isRunning ? "bg-status-info-bg text-status-info-text" : "bg-status-success-bg text-status-success-text"),
|
|
134
|
+
children: [e.isRunning && /* @__PURE__ */ h("span", { className: "h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse" }), e.isRunning ? w("timecampus.home.recentEntries.status.running", "running") : w("timecampus.home.recentEntries.status.completed", "completed")]
|
|
134
135
|
})]
|
|
135
136
|
})]
|
|
136
|
-
},
|
|
137
|
+
}, e.id)), j.length === 0 && /* @__PURE__ */ h("p", {
|
|
137
138
|
className: "py-4 text-center text-sm text-text-secondary",
|
|
138
|
-
children:
|
|
139
|
+
children: w("timecampus.home.recentEntries.empty", "No time entries yet")
|
|
139
140
|
})]
|
|
140
141
|
})]
|
|
141
|
-
}), /* @__PURE__ */
|
|
142
|
+
}), /* @__PURE__ */ g(y, {
|
|
142
143
|
className: "p-6",
|
|
143
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ g("div", {
|
|
144
145
|
className: "mb-4",
|
|
145
|
-
children: [/* @__PURE__ */
|
|
146
|
+
children: [/* @__PURE__ */ h("h3", {
|
|
146
147
|
className: "text-sm font-semibold text-text-primary",
|
|
147
|
-
children:
|
|
148
|
-
}), /* @__PURE__ */
|
|
148
|
+
children: w("timecampus.home.summary.title", "Quick Summary")
|
|
149
|
+
}), /* @__PURE__ */ h("p", {
|
|
149
150
|
className: "text-xs text-text-secondary",
|
|
150
|
-
children:
|
|
151
|
+
children: w("timecampus.home.summary.description", "Time tracking overview")
|
|
151
152
|
})]
|
|
152
|
-
}), /* @__PURE__ */
|
|
153
|
+
}), /* @__PURE__ */ g("div", {
|
|
153
154
|
className: "flex flex-col gap-4",
|
|
154
155
|
children: [
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
+
/* @__PURE__ */ g("div", {
|
|
156
157
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
157
|
-
children: [/* @__PURE__ */
|
|
158
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
158
159
|
className: "text-xs font-medium text-text-secondary",
|
|
159
|
-
children:
|
|
160
|
-
}), /* @__PURE__ */
|
|
160
|
+
children: w("timecampus.home.summary.totalHours", "Total Hours")
|
|
161
|
+
}), /* @__PURE__ */ h("p", {
|
|
161
162
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
162
|
-
children:
|
|
163
|
-
})] }), /* @__PURE__ */
|
|
163
|
+
children: n(A?.totalHours ?? 0)
|
|
164
|
+
})] }), /* @__PURE__ */ h(u, { className: "h-5 w-5 text-text-secondary" })]
|
|
164
165
|
}),
|
|
165
|
-
/* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ g("div", {
|
|
166
167
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
168
169
|
className: "text-xs font-medium text-text-secondary",
|
|
169
|
-
children:
|
|
170
|
-
}), /* @__PURE__ */
|
|
170
|
+
children: w("timecampus.home.summary.billableHours", "Billable Hours")
|
|
171
|
+
}), /* @__PURE__ */ h("p", {
|
|
171
172
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
172
|
-
children:
|
|
173
|
-
})] }), /* @__PURE__ */
|
|
173
|
+
children: n(A?.billableHours ?? 0)
|
|
174
|
+
})] }), /* @__PURE__ */ h(p, { className: "h-5 w-5 text-text-secondary" })]
|
|
174
175
|
}),
|
|
175
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ g("div", {
|
|
176
177
|
className: "flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
178
179
|
className: "text-xs font-medium text-text-secondary",
|
|
179
|
-
children:
|
|
180
|
-
}), /* @__PURE__ */
|
|
180
|
+
children: w("timecampus.home.summary.activeTimers", "Active Timers")
|
|
181
|
+
}), /* @__PURE__ */ h("p", {
|
|
181
182
|
className: "mt-1 text-xl font-bold tabular-nums text-text-primary",
|
|
182
|
-
children:
|
|
183
|
-
})] }), /* @__PURE__ */
|
|
183
|
+
children: A?.activeTimers ?? 0
|
|
184
|
+
})] }), /* @__PURE__ */ h(m, { className: "h-5 w-5 text-text-secondary" })]
|
|
184
185
|
})
|
|
185
186
|
]
|
|
186
187
|
})]
|
|
187
188
|
})]
|
|
188
189
|
}),
|
|
189
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ g(b, {
|
|
190
191
|
treatment: "plain",
|
|
191
192
|
className: "border-border-seam p-6",
|
|
192
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ g("div", {
|
|
193
194
|
className: "mb-4",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
195
|
+
children: [/* @__PURE__ */ h("h3", {
|
|
195
196
|
className: "text-sm font-semibold text-text-primary",
|
|
196
|
-
children:
|
|
197
|
-
}), /* @__PURE__ */
|
|
197
|
+
children: w("timecampus.home.quickActions.title", "Quick Actions")
|
|
198
|
+
}), /* @__PURE__ */ h("p", {
|
|
198
199
|
className: "text-xs text-text-secondary",
|
|
199
|
-
children:
|
|
200
|
+
children: w("timecampus.home.quickActions.description", "Frequently used features")
|
|
200
201
|
})]
|
|
201
|
-
}), /* @__PURE__ */
|
|
202
|
+
}), /* @__PURE__ */ h("div", {
|
|
202
203
|
className: "grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6",
|
|
203
204
|
children: [
|
|
204
205
|
{
|
|
205
|
-
label:
|
|
206
|
-
icon: p,
|
|
207
|
-
description: E("timecampus.home.quickActions.startTimer.description", "Track your time")
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
label: E("timecampus.home.quickActions.viewProjects.label", "View Projects"),
|
|
206
|
+
label: w("timecampus.home.quickActions.startTimer.label", "Start Timer"),
|
|
211
207
|
icon: f,
|
|
212
|
-
|
|
208
|
+
route: "/time/timer",
|
|
209
|
+
description: w("timecampus.home.quickActions.startTimer.description", "Track your time")
|
|
213
210
|
},
|
|
214
211
|
{
|
|
215
|
-
label:
|
|
212
|
+
label: w("timecampus.home.quickActions.viewProjects.label", "View Projects"),
|
|
216
213
|
icon: d,
|
|
217
|
-
|
|
214
|
+
route: "/projects",
|
|
215
|
+
description: w("timecampus.home.quickActions.viewProjects.description", "Manage projects")
|
|
218
216
|
},
|
|
219
217
|
{
|
|
220
|
-
label:
|
|
221
|
-
icon:
|
|
222
|
-
|
|
218
|
+
label: w("timecampus.home.quickActions.timeEntries.label", "Time Entries"),
|
|
219
|
+
icon: u,
|
|
220
|
+
route: "/time/entries",
|
|
221
|
+
description: w("timecampus.home.quickActions.timeEntries.description", "View all entries")
|
|
223
222
|
},
|
|
224
223
|
{
|
|
225
|
-
label:
|
|
226
|
-
icon:
|
|
227
|
-
|
|
224
|
+
label: w("timecampus.home.quickActions.teamActivity.label", "Team Activity"),
|
|
225
|
+
icon: m,
|
|
226
|
+
route: "/team-activity",
|
|
227
|
+
description: w("timecampus.home.quickActions.teamActivity.description", "See team status")
|
|
228
228
|
},
|
|
229
229
|
{
|
|
230
|
-
label:
|
|
231
|
-
icon:
|
|
232
|
-
|
|
230
|
+
label: w("timecampus.home.quickActions.reports.label", "Reports"),
|
|
231
|
+
icon: c,
|
|
232
|
+
route: "/reports",
|
|
233
|
+
description: w("timecampus.home.quickActions.reports.description", "Generate reports")
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
label: w("timecampus.home.quickActions.approvals.label", "Approvals"),
|
|
237
|
+
icon: l,
|
|
238
|
+
route: "/time-approval",
|
|
239
|
+
description: w("timecampus.home.quickActions.approvals.description", "Review timesheets")
|
|
233
240
|
}
|
|
234
|
-
].map(({ label: e, icon: t, description: n }) => /* @__PURE__ */
|
|
241
|
+
].map(({ label: e, icon: t, description: n, route: r }) => /* @__PURE__ */ g("button", {
|
|
242
|
+
onClick: () => T(r),
|
|
235
243
|
className: "flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border",
|
|
236
244
|
children: [
|
|
237
|
-
/* @__PURE__ */
|
|
245
|
+
/* @__PURE__ */ h("div", {
|
|
238
246
|
className: "rounded-full bg-action-primary-bg/10 p-3",
|
|
239
|
-
children: /* @__PURE__ */
|
|
247
|
+
children: /* @__PURE__ */ h(t, { className: "h-5 w-5 text-primary" })
|
|
240
248
|
}),
|
|
241
|
-
/* @__PURE__ */
|
|
249
|
+
/* @__PURE__ */ h("span", {
|
|
242
250
|
className: "text-sm font-medium text-text-primary",
|
|
243
251
|
children: e
|
|
244
252
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
253
|
+
/* @__PURE__ */ h("span", {
|
|
246
254
|
className: "text-xs text-text-secondary",
|
|
247
255
|
children: n
|
|
248
256
|
})
|
|
@@ -254,6 +262,6 @@ var T = () => {
|
|
|
254
262
|
});
|
|
255
263
|
};
|
|
256
264
|
//#endregion
|
|
257
|
-
export {
|
|
265
|
+
export { C as HomePage };
|
|
258
266
|
|
|
259
267
|
//# sourceMappingURL=HomePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/timecampus/pages/HomePage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Clock,\n FolderOpen,\n Users,\n TrendingUp,\n Timer,\n CheckCircle,\n BarChart3,\n Play,\n ArrowRight,\n} from \"lucide-react\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n} from \"@burdenoff/fe-libs/ui\";\nimport { StatCard } from \"../components/StatCard\";\nimport { LoadingSkeleton } from \"../components/LoadingSkeleton\";\nimport { cn, formatHours, formatTimerDuration } from \"../utils/helpers\";\nimport { useTimeCampusStore } from \"../store/timecampusStore\";\nimport {\n useGetTimeEntryStatsQuery,\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\n\nexport const HomePage: FC = () => {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { activeTimer, startTimer, stopTimer } = useTimeCampusStore();\n\n const { data: statsData, loading: statsLoading } =\n useGetTimeEntryStatsQuery();\n const { data: entriesData, loading: entriesLoading } =\n useListTimeEntriesQuery({\n variables: { limit: 4 },\n });\n\n const stats = statsData?.timeEntryStats;\n const recentEntries = entriesData?.timeEntries?.items ?? [];\n\n const timerLabel = activeTimer\n ? `${formatTimerDuration(activeTimer.seconds)} - ${t(\"timecampus.home.actions.stop\", \"Stop\")}`\n : t(\"timecampus.home.actions.startTimer\", \"Start Timer\");\n\n const headerActions = (\n <CTAOverflowMenu\n primary={{\n label: timerLabel,\n onSelect: () => (activeTimer ? stopTimer() : startTimer()),\n icon: activeTimer ? (\n <Timer className=\"h-4 w-4\" />\n ) : (\n <Play className=\"h-4 w-4\" />\n ),\n }}\n actions={[\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n onSelect: () => {},\n icon: <FolderOpen className=\"h-4 w-4\" />,\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n onSelect: () => {},\n icon: <BarChart3 className=\"h-4 w-4\" />,\n },\n ]}\n />\n );\n\n const renderHeader = () => (\n <div className=\"relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>\n {t(\"timecampus.home.title\", \"Dashboard\")}\n </GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t(\n \"timecampus.home.description\",\n \"Overview of your time tracking and productivity\",\n )}\n </p>\n </div>\n {headerActions}\n </div>\n </div>\n );\n\n if (statsLoading && entriesLoading) {\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n <LoadingSkeleton variant=\"card\" count={4} />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n\n {/* Hero metric + supporting metrics */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n featured\n title={t(\"timecampus.home.stats.today\", \"Today\")}\n value={formatHours(stats?.totalHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n trend={{\n value: 12.5,\n label: t(\"timecampus.home.stats.vsYesterday\", \"vs yesterday\"),\n }}\n />\n <StatCard\n title={t(\"timecampus.home.stats.billable\", \"Billable\")}\n value={formatHours(stats?.billableHours ?? 0)}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n description={`${stats?.totalEntries ?? 0} ${t(\"timecampus.home.stats.entries\", \"entries\")}`}\n />\n <StatCard\n title={t(\"timecampus.home.stats.activeTimers\", \"Active Timers\")}\n value={stats?.activeTimers ?? 0}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.currentlyRunning\",\n \"Currently running\",\n )}\n />\n <StatCard\n title={t(\"timecampus.home.stats.totalEntries\", \"Entries\")}\n value={stats?.totalEntries ?? 0}\n icon={<BarChart3 className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.totalEntriesDescription\",\n \"Total time entries\",\n )}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Recent Time Entries */}\n <GlassCard\n treatment=\"plain\"\n className=\"border-border-seam p-6 lg:col-span-2\"\n >\n <div className=\"mb-4 flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\n \"timecampus.home.recentEntries.title\",\n \"Recent Time Entries\",\n )}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.description\",\n \"Your latest tracked activities\",\n )}\n </p>\n </div>\n <button className=\"inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\">\n {t(\"timecampus.home.recentEntries.viewAll\", \"View all\")}{\" \"}\n <ArrowRight className=\"h-3 w-3\" />\n </button>\n </div>\n {entriesLoading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {recentEntries.map((entry: TimeEntryFieldsFragment) => (\n <div\n key={entry.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {entry.project?.name ??\n t(\n \"timecampus.home.recentEntries.noProject\",\n \"No Project\",\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {entry.description ??\n t(\n \"timecampus.home.recentEntries.noDescription\",\n \"No description\",\n )}\n </p>\n </div>\n <div className=\"ml-4 text-right\">\n <p className=\"font-mono text-sm font-medium tabular-nums text-text-primary\">\n {formatHours((entry.duration ?? 0) / 3600)}\n </p>\n <span\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\",\n entry.isRunning\n ? \"bg-status-info-bg text-status-info-text\"\n : \"bg-status-success-bg text-status-success-text\",\n )}\n >\n {entry.isRunning && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse\" />\n )}\n {entry.isRunning\n ? t(\n \"timecampus.home.recentEntries.status.running\",\n \"running\",\n )\n : t(\n \"timecampus.home.recentEntries.status.completed\",\n \"completed\",\n )}\n </span>\n </div>\n </div>\n ))}\n {recentEntries.length === 0 && (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.empty\",\n \"No time entries yet\",\n )}\n </p>\n )}\n </div>\n )}\n </GlassCard>\n\n {/* Quick Summary — the one emphasis zone */}\n <EmphasisPanel className=\"p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.summary.title\", \"Quick Summary\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.summary.description\",\n \"Time tracking overview\",\n )}\n </p>\n </div>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.totalHours\", \"Total Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.totalHours ?? 0)}\n </p>\n </div>\n <Clock className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.billableHours\", \"Billable Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.billableHours ?? 0)}\n </p>\n </div>\n <TrendingUp className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.activeTimers\", \"Active Timers\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {stats?.activeTimers ?? 0}\n </p>\n </div>\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n </div>\n </EmphasisPanel>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.quickActions.title\", \"Quick Actions\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.quickActions.description\",\n \"Frequently used features\",\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\">\n {[\n {\n label: t(\n \"timecampus.home.quickActions.startTimer.label\",\n \"Start Timer\",\n ),\n icon: Play,\n description: t(\n \"timecampus.home.quickActions.startTimer.description\",\n \"Track your time\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n icon: FolderOpen,\n description: t(\n \"timecampus.home.quickActions.viewProjects.description\",\n \"Manage projects\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.timeEntries.label\",\n \"Time Entries\",\n ),\n icon: Clock,\n description: t(\n \"timecampus.home.quickActions.timeEntries.description\",\n \"View all entries\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.teamActivity.label\",\n \"Team Activity\",\n ),\n icon: Users,\n description: t(\n \"timecampus.home.quickActions.teamActivity.description\",\n \"See team status\",\n ),\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n icon: BarChart3,\n description: t(\n \"timecampus.home.quickActions.reports.description\",\n \"Generate reports\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.approvals.label\",\n \"Approvals\",\n ),\n icon: CheckCircle,\n description: t(\n \"timecampus.home.quickActions.approvals.description\",\n \"Review timesheets\",\n ),\n },\n ].map(({ label, icon: Icon, description }) => (\n <button\n key={label}\n className=\"flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n <div className=\"rounded-full bg-action-primary-bg/10 p-3\">\n <Icon className=\"h-5 w-5 text-primary\" />\n </div>\n <span className=\"text-sm font-medium text-text-primary\">\n {label}\n </span>\n <span className=\"text-xs text-text-secondary\">{description}</span>\n </button>\n ))}\n </div>\n </GlassCard>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/timecampus/pages/HomePage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport {\n Clock,\n FolderOpen,\n Users,\n TrendingUp,\n CheckCircle,\n BarChart3,\n Play,\n ArrowRight,\n} from \"lucide-react\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n} from \"@burdenoff/fe-libs/ui\";\nimport { StatCard } from \"../components/StatCard\";\nimport { LoadingSkeleton } from \"../components/LoadingSkeleton\";\nimport { cn, formatHours } from \"../utils/helpers\";\nimport { useTimeCampusNavigate } from \"../providers/TimeCampusProvider\";\nimport {\n useGetTimeEntryStatsQuery,\n useListTimeEntriesQuery,\n type TimeEntryFieldsFragment,\n} from \"@/generated/wspace-operations\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\n\nexport const HomePage: FC = () => {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const navigate = useTimeCampusNavigate();\n\n const { data: statsData, loading: statsLoading } =\n useGetTimeEntryStatsQuery();\n const { data: entriesData, loading: entriesLoading } =\n useListTimeEntriesQuery({\n variables: { limit: 4 },\n });\n\n const stats = statsData?.timeEntryStats;\n const recentEntries = entriesData?.timeEntries?.items ?? [];\n\n const headerActions = (\n <CTAOverflowMenu\n primary={{\n label: t(\"timecampus.home.actions.startTimer\", \"Start Timer\"),\n onSelect: () => navigate(\"/time/timer\"),\n icon: <Play className=\"h-4 w-4\" />,\n }}\n actions={[\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n onSelect: () => navigate(\"/projects\"),\n icon: <FolderOpen className=\"h-4 w-4\" />,\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n onSelect: () => navigate(\"/reports\"),\n icon: <BarChart3 className=\"h-4 w-4\" />,\n },\n ]}\n />\n );\n\n const renderHeader = () => (\n <div className=\"relative overflow-hidden rounded-2xl border border-border-seam bg-gloss-card p-5 sm:p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>\n {t(\"timecampus.home.title\", \"Dashboard\")}\n </GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t(\n \"timecampus.home.description\",\n \"Overview of your time tracking and productivity\",\n )}\n </p>\n </div>\n {headerActions}\n </div>\n </div>\n );\n\n if (statsLoading && entriesLoading) {\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n <LoadingSkeleton variant=\"card\" count={4} />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full space-y-6 p-4 sm:p-6\">\n {renderHeader()}\n\n {/* Hero metric + supporting metrics */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n featured\n title={t(\"timecampus.home.stats.today\", \"Today\")}\n value={formatHours(stats?.totalHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n trend={{\n value: 12.5,\n label: t(\"timecampus.home.stats.vsYesterday\", \"vs yesterday\"),\n }}\n />\n <StatCard\n title={t(\"timecampus.home.stats.billable\", \"Billable\")}\n value={formatHours(stats?.billableHours ?? 0)}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n description={`${stats?.totalEntries ?? 0} ${t(\"timecampus.home.stats.entries\", \"entries\")}`}\n />\n <StatCard\n title={t(\"timecampus.home.stats.activeTimers\", \"Active Timers\")}\n value={stats?.activeTimers ?? 0}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.currentlyRunning\",\n \"Currently running\",\n )}\n />\n <StatCard\n title={t(\"timecampus.home.stats.totalEntries\", \"Entries\")}\n value={stats?.totalEntries ?? 0}\n icon={<BarChart3 className=\"h-5 w-5\" />}\n description={t(\n \"timecampus.home.stats.totalEntriesDescription\",\n \"Total time entries\",\n )}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Recent Time Entries */}\n <GlassCard\n treatment=\"plain\"\n className=\"border-border-seam p-6 lg:col-span-2\"\n >\n <div className=\"mb-4 flex items-center justify-between\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\n \"timecampus.home.recentEntries.title\",\n \"Recent Time Entries\",\n )}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.description\",\n \"Your latest tracked activities\",\n )}\n </p>\n </div>\n <button\n onClick={() => navigate(\"/time/entries\")}\n className=\"inline-flex min-h-[2.75rem] items-center gap-1 rounded-md px-2 text-xs font-medium text-primary transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n {t(\"timecampus.home.recentEntries.viewAll\", \"View all\")}{\" \"}\n <ArrowRight className=\"h-3 w-3\" />\n </button>\n </div>\n {entriesLoading ? (\n <LoadingSkeleton variant=\"list\" count={4} />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {recentEntries.map((entry: TimeEntryFieldsFragment) => (\n <div\n key={entry.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {entry.project?.name ??\n t(\n \"timecampus.home.recentEntries.noProject\",\n \"No Project\",\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {entry.description ??\n t(\n \"timecampus.home.recentEntries.noDescription\",\n \"No description\",\n )}\n </p>\n </div>\n <div className=\"ml-4 text-right\">\n <p className=\"font-mono text-sm font-medium tabular-nums text-text-primary\">\n {formatHours((entry.duration ?? 0) / 3600)}\n </p>\n <span\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\",\n entry.isRunning\n ? \"bg-status-info-bg text-status-info-text\"\n : \"bg-status-success-bg text-status-success-text\",\n )}\n >\n {entry.isRunning && (\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-info-text motion-safe:animate-vc-glow-pulse\" />\n )}\n {entry.isRunning\n ? t(\n \"timecampus.home.recentEntries.status.running\",\n \"running\",\n )\n : t(\n \"timecampus.home.recentEntries.status.completed\",\n \"completed\",\n )}\n </span>\n </div>\n </div>\n ))}\n {recentEntries.length === 0 && (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n \"timecampus.home.recentEntries.empty\",\n \"No time entries yet\",\n )}\n </p>\n )}\n </div>\n )}\n </GlassCard>\n\n {/* Quick Summary — the one emphasis zone */}\n <EmphasisPanel className=\"p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.summary.title\", \"Quick Summary\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.summary.description\",\n \"Time tracking overview\",\n )}\n </p>\n </div>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.totalHours\", \"Total Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.totalHours ?? 0)}\n </p>\n </div>\n <Clock className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.billableHours\", \"Billable Hours\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {formatHours(stats?.billableHours ?? 0)}\n </p>\n </div>\n <TrendingUp className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex items-center justify-between rounded-lg border border-border-seam bg-bg-surface/40 p-3\">\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {t(\"timecampus.home.summary.activeTimers\", \"Active Timers\")}\n </p>\n <p className=\"mt-1 text-xl font-bold tabular-nums text-text-primary\">\n {stats?.activeTimers ?? 0}\n </p>\n </div>\n <Users className=\"h-5 w-5 text-text-secondary\" />\n </div>\n </div>\n </EmphasisPanel>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <div className=\"mb-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t(\"timecampus.home.quickActions.title\", \"Quick Actions\")}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {t(\n \"timecampus.home.quickActions.description\",\n \"Frequently used features\",\n )}\n </p>\n </div>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\">\n {[\n {\n label: t(\n \"timecampus.home.quickActions.startTimer.label\",\n \"Start Timer\",\n ),\n icon: Play,\n route: \"/time/timer\",\n description: t(\n \"timecampus.home.quickActions.startTimer.description\",\n \"Track your time\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.viewProjects.label\",\n \"View Projects\",\n ),\n icon: FolderOpen,\n route: \"/projects\",\n description: t(\n \"timecampus.home.quickActions.viewProjects.description\",\n \"Manage projects\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.timeEntries.label\",\n \"Time Entries\",\n ),\n icon: Clock,\n route: \"/time/entries\",\n description: t(\n \"timecampus.home.quickActions.timeEntries.description\",\n \"View all entries\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.teamActivity.label\",\n \"Team Activity\",\n ),\n icon: Users,\n route: \"/team-activity\",\n description: t(\n \"timecampus.home.quickActions.teamActivity.description\",\n \"See team status\",\n ),\n },\n {\n label: t(\"timecampus.home.quickActions.reports.label\", \"Reports\"),\n icon: BarChart3,\n route: \"/reports\",\n description: t(\n \"timecampus.home.quickActions.reports.description\",\n \"Generate reports\",\n ),\n },\n {\n label: t(\n \"timecampus.home.quickActions.approvals.label\",\n \"Approvals\",\n ),\n icon: CheckCircle,\n route: \"/time-approval\",\n description: t(\n \"timecampus.home.quickActions.approvals.description\",\n \"Review timesheets\",\n ),\n },\n ].map(({ label, icon: Icon, description, route }) => (\n <button\n key={label}\n onClick={() => navigate(route)}\n className=\"flex min-h-[2.75rem] flex-col items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-center transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-border\"\n >\n <div className=\"rounded-full bg-action-primary-bg/10 p-3\">\n <Icon className=\"h-5 w-5 text-primary\" />\n </div>\n <span className=\"text-sm font-medium text-text-primary\">\n {label}\n </span>\n <span className=\"text-xs text-text-secondary\">{description}</span>\n </button>\n ))}\n </div>\n </GlassCard>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AA6BA,IAAa,UAAqB;CAChC,IAAM,EAAE,GAAG,MAAc,GAAS,EAC5B,KAAK,GAAa,MAA6B;EACnD,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAE9B,IAAW,GAAuB,EAElC,EAAE,MAAM,GAAW,SAAS,MAChC,GAA2B,EACvB,EAAE,MAAM,GAAa,SAAS,MAClC,EAAwB,EACtB,WAAW,EAAE,OAAO,GAAG,EACxB,CAAC,EAEE,IAAQ,GAAW,gBACnB,IAAgB,GAAa,aAAa,SAAS,EAAE,EAErD,IACJ,kBAAC,GAAD;EACE,SAAS;GACP,OAAO,EAAE,sCAAsC,cAAc;GAC7D,gBAAgB,EAAS,cAAc;GACvC,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;GACnC;EACD,SAAS,CACP;GACE,OAAO,EACL,mDACA,gBACD;GACD,gBAAgB,EAAS,YAAY;GACrC,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;GACzC,EACD;GACE,OAAO,EAAE,8CAA8C,UAAU;GACjE,gBAAgB,EAAS,WAAW;GACpC,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;GACxC,CACF;EACD,CAAA,EAGE,UACJ,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA,EACvC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UACG,EAAE,yBAAyB,YAAY,EAC3B,CAAA;KACZ,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,+BACA,kDACD;KACC,CAAA,CACA;OACL,EACG;KACF;;AAYR,QATI,KAAgB,IAEhB,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,GAAc,EACf,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA,CACxC;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GACG,GAAc;GAGf,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,UAAA;MACA,OAAO,EAAE,+BAA+B,QAAQ;MAChD,OAAO,EAAY,GAAO,cAAc,EAAE;MAC1C,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,OAAO;OACL,OAAO;OACP,OAAO,EAAE,qCAAqC,eAAe;OAC9D;MACD,CAAA;KACF,kBAAC,GAAD;MACE,OAAO,EAAE,kCAAkC,WAAW;MACtD,OAAO,EAAY,GAAO,iBAAiB,EAAE;MAC7C,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,aAAa,GAAG,GAAO,gBAAgB,EAAE,GAAG,EAAE,iCAAiC,UAAU;MACzF,CAAA;KACF,kBAAC,GAAD;MACE,OAAO,EAAE,sCAAsC,gBAAgB;MAC/D,OAAO,GAAO,gBAAgB;MAC9B,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,aAAa,EACX,0CACA,oBACD;MACD,CAAA;KACF,kBAAC,GAAD;MACE,OAAO,EAAE,sCAAsC,UAAU;MACzD,OAAO,GAAO,gBAAgB;MAC9B,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MACvC,aAAa,EACX,iDACA,qBACD;MACD,CAAA;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,GAAD;KACE,WAAU;KACV,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EACC,uCACA,sBACD;OACE,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,6CACA,iCACD;OACC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;OACE,eAAe,EAAS,gBAAgB;OACxC,WAAU;iBAFZ;QAIG,EAAE,yCAAyC,WAAW;QAAE;QACzD,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;QAC3B;SACL;SACL,IACC,kBAAC,GAAD;MAAiB,SAAQ;MAAO,OAAO;MAAK,CAAA,GAE5C,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,EAAc,KAAK,MAClB,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAM,SAAS,QACd,EACE,2CACA,aACD;SACD,CAAA,EACJ,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAM,eACL,EACE,+CACA,iBACD;SACD,CAAA,CACA;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAa,EAAM,YAAY,KAAK,KAAK;SACxC,CAAA,EACJ,kBAAC,QAAD;SACE,WAAW,EACT,iFACA,EAAM,YACF,4CACA,gDACL;mBANH,CAQG,EAAM,aACL,kBAAC,QAAD,EAAM,WAAU,kFAAmF,CAAA,EAEpG,EAAM,YACH,EACE,gDACA,UACD,GACD,EACE,kDACA,YACD,CACA;WACH;UACF;SA7CC,EAAM,GA6CP,CACN,EACD,EAAc,WAAW,KACxB,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,uCACA,sBACD;OACC,CAAA,CAEF;QAEE;QAGZ,kBAAC,GAAD;KAAe,WAAU;eAAzB,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAE,iCAAiC,gBAAgB;OACjD,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,uCACA,yBACD;OACC,CAAA,CACA;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,sCAAsC,cAAc;SACrD,CAAA,EACJ,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAY,GAAO,cAAc,EAAE;SAClC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA,CAC7C;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,yCAAyC,iBAAiB;SAC3D,CAAA,EACJ,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAY,GAAO,iBAAiB,EAAE;SACrC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,GAAD,EAAY,WAAU,+BAAgC,CAAA,CAClD;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAE,wCAAwC,gBAAgB;SACzD,CAAA,EACJ,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAO,gBAAgB;SACtB,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA,CAC7C;;OACF;QACQ;OACZ;;GAGN,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cAAvC,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAE,sCAAsC,gBAAgB;MACtD,CAAA,EACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,4CACA,2BACD;MACC,CAAA,CACA;QACN,kBAAC,OAAD;KAAK,WAAU;eACZ;MACC;OACE,OAAO,EACL,iDACA,cACD;OACD,MAAM;OACN,OAAO;OACP,aAAa,EACX,uDACA,kBACD;OACF;MACD;OACE,OAAO,EACL,mDACA,gBACD;OACD,MAAM;OACN,OAAO;OACP,aAAa,EACX,yDACA,kBACD;OACF;MACD;OACE,OAAO,EACL,kDACA,eACD;OACD,MAAM;OACN,OAAO;OACP,aAAa,EACX,wDACA,mBACD;OACF;MACD;OACE,OAAO,EACL,mDACA,gBACD;OACD,MAAM;OACN,OAAO;OACP,aAAa,EACX,yDACA,kBACD;OACF;MACD;OACE,OAAO,EAAE,8CAA8C,UAAU;OACjE,MAAM;OACN,OAAO;OACP,aAAa,EACX,oDACA,mBACD;OACF;MACD;OACE,OAAO,EACL,gDACA,YACD;OACD,MAAM;OACN,OAAO;OACP,aAAa,EACX,sDACA,oBACD;OACF;MACF,CAAC,KAAK,EAAE,UAAO,MAAM,GAAM,gBAAa,eACvC,kBAAC,UAAD;MAEE,eAAe,EAAS,EAAM;MAC9B,WAAU;gBAHZ;OAKE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD,EAAM,WAAU,wBAAyB,CAAA;QACrC,CAAA;OACN,kBAAC,QAAD;QAAM,WAAU;kBACb;QACI,CAAA;OACP,kBAAC,QAAD;QAAM,WAAU;kBAA+B;QAAmB,CAAA;OAC3D;QAXF,EAWE,CACT;KACE,CAAA,CACI;;GACR"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useTimeCampusNavigate as e } from "../../providers/TimeCampusProvider.js";
|
|
2
2
|
import { LoadingSkeleton as t } from "../../components/LoadingSkeleton.js";
|
|
3
3
|
import { useListConfigurationsQuery as n } from "../../../generated/wspace-operations.js";
|
|
4
4
|
import { PageLayout as r } from "../../components/PageLayout.js";
|
|
5
5
|
import { EmptyState as i } from "../../components/EmptyState.js";
|
|
6
|
-
import {
|
|
6
|
+
import { TimeCampusConfigScope as a } from "../../../generated/wspace-types.js";
|
|
7
|
+
import { Puzzle as o, Store as s } from "lucide-react";
|
|
7
8
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
9
|
//#region src/timecampus/pages/applets/AppletStorePage.tsx
|
|
9
10
|
function u() {
|
|
10
|
-
let
|
|
11
|
+
let u = e(), { data: d, loading: f, error: p } = n({ variables: { scope: a.Workspace } }), m = (d?.configurations ?? []).filter((e) => e.key.startsWith("applet.store."));
|
|
11
12
|
return f ? /* @__PURE__ */ c(r, {
|
|
12
13
|
title: "Applet Store",
|
|
13
14
|
description: "Browse and install applets to extend TimeCampus",
|
|
@@ -33,11 +34,9 @@ function u() {
|
|
|
33
34
|
}) : /* @__PURE__ */ c("div", {
|
|
34
35
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
35
36
|
children: m.map((e) => {
|
|
36
|
-
let t = e.value, n = t.name ?? e.key.replace("applet.store.", ""), r = e.description ?? t.description ?? "";
|
|
37
|
-
t.category;
|
|
38
|
-
let i = t.rating ?? 0, u = t.downloads ?? 0;
|
|
37
|
+
let t = e.value, n = t.name ?? e.key.replace("applet.store.", ""), r = e.description ?? t.description ?? "", i = t.category ?? "general";
|
|
39
38
|
return /* @__PURE__ */ l("div", {
|
|
40
|
-
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-5 transition-colors hover:bg-bg-sunken/50
|
|
39
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-5 transition-colors hover:bg-bg-sunken/50",
|
|
41
40
|
children: [/* @__PURE__ */ l("div", {
|
|
42
41
|
className: "flex items-start gap-3",
|
|
43
42
|
children: [/* @__PURE__ */ c("div", {
|
|
@@ -55,18 +54,14 @@ function u() {
|
|
|
55
54
|
})]
|
|
56
55
|
}), /* @__PURE__ */ l("div", {
|
|
57
56
|
className: "mt-3 flex items-center justify-between",
|
|
58
|
-
children: [/* @__PURE__ */
|
|
59
|
-
className: "flex
|
|
60
|
-
children:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})]
|
|
67
|
-
}), /* @__PURE__ */ c("button", {
|
|
68
|
-
className: "rounded-md bg-action-primary-bg px-3 py-1 text-xs font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
69
|
-
children: "Install"
|
|
57
|
+
children: [/* @__PURE__ */ c("span", {
|
|
58
|
+
className: "inline-flex rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
59
|
+
children: i
|
|
60
|
+
}), /* @__PURE__ */ l("button", {
|
|
61
|
+
type: "button",
|
|
62
|
+
onClick: () => u("/store"),
|
|
63
|
+
className: "inline-flex items-center gap-1 rounded-md bg-action-primary-bg px-3 py-1 text-xs font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
64
|
+
children: [/* @__PURE__ */ c(s, { className: "h-3 w-3" }), "Get it"]
|
|
70
65
|
})]
|
|
71
66
|
})]
|
|
72
67
|
}, e.id);
|