@burdenoff/microfe-timecampus 2026.625.1 → 2026.626.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/timecampus/components/EmptyState.js +14 -0
- package/dist/timecampus/components/EmptyState.js.map +1 -0
- package/dist/timecampus/components/PageLayout.js +23 -15
- package/dist/timecampus/components/PageLayout.js.map +1 -1
- package/dist/timecampus/pages/applets/AppletStorePage.js +33 -30
- package/dist/timecampus/pages/applets/AppletStorePage.js.map +1 -1
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js +37 -31
- package/dist/timecampus/pages/applets/InstalledAppletsPage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +48 -44
- package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js +35 -31
- package/dist/timecampus/pages/application-usage/ApplicationUsageSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/channels/ChannelsPage.js +27 -24
- package/dist/timecampus/pages/channels/ChannelsPage.js.map +1 -1
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js +46 -38
- package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js +66 -39
- package/dist/timecampus/pages/dashboard/AnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/dashboard/ReportsPage.js +42 -36
- package/dist/timecampus/pages/dashboard/ReportsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/email-tracking/EmailAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js +35 -31
- package/dist/timecampus/pages/email-tracking/EmailSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +31 -25
- package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +43 -35
- package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScorePage.js +55 -51
- package/dist/timecampus/pages/focus-score/FocusScorePage.js.map +1 -1
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js +32 -28
- package/dist/timecampus/pages/focus-score/FocusScoreSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingPage.js +32 -25
- package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js +29 -25
- package/dist/timecampus/pages/geofencing/GeofencingSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js +32 -29
- package/dist/timecampus/pages/industry-solutions/IndustrySolutionsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js +29 -25
- package/dist/timecampus/pages/location-tracking/LocationPrivacySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +39 -35
- package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/meetings/MeetingAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js +33 -29
- package/dist/timecampus/pages/meetings/MeetingCreatePage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js +122 -104
- package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
- package/dist/timecampus/pages/meetings/MeetingsPage.js +42 -32
- package/dist/timecampus/pages/meetings/MeetingsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js +2 -0
- package/dist/timecampus/pages/pomodoro/PomodoroAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js +145 -114
- package/dist/timecampus/pages/pomodoro/PomodoroPage.js.map +1 -1
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js +49 -45
- package/dist/timecampus/pages/pomodoro/PomodoroSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectCreatePage.js +28 -24
- package/dist/timecampus/pages/projects/ProjectCreatePage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectDetailPage.js +109 -78
- package/dist/timecampus/pages/projects/ProjectDetailPage.js.map +1 -1
- package/dist/timecampus/pages/projects/ProjectsPage.js +11 -7
- package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
- package/dist/timecampus/pages/projects/TasksPage.js +40 -30
- package/dist/timecampus/pages/projects/TasksPage.js.map +1 -1
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +50 -46
- package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js +18 -14
- package/dist/timecampus/pages/team/TeamAnalyticsPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamMembersPage.js +41 -35
- package/dist/timecampus/pages/team/TeamMembersPage.js.map +1 -1
- package/dist/timecampus/pages/team/TeamPage.js +91 -61
- package/dist/timecampus/pages/team/TeamPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js +40 -36
- package/dist/timecampus/pages/team-activity/TeamActivityPage.js.map +1 -1
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js +33 -29
- package/dist/timecampus/pages/team-activity/TeamActivitySettingsPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js +17 -13
- package/dist/timecampus/pages/templates/TemplateApplicationPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplateDetailPage.js +67 -49
- package/dist/timecampus/pages/templates/TemplateDetailPage.js.map +1 -1
- package/dist/timecampus/pages/templates/TemplatesPage.js +34 -31
- package/dist/timecampus/pages/templates/TemplatesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeEntriesPage.js +48 -39
- package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimeTrackingPage.js +65 -64
- package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
- package/dist/timecampus/pages/time/TimerPage.js +103 -69
- package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +53 -49
- package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js +65 -47
- package/dist/timecampus/pages/widgets/WidgetDetailPage.js.map +1 -1
- package/dist/timecampus/pages/widgets/WidgetsPage.js +38 -31
- package/dist/timecampus/pages/widgets/WidgetsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +2 -0
- package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js +35 -31
- package/dist/timecampus/pages/work-patterns/WorkPatternsSettingsPage.js.map +1 -1
- package/dist/timecampus/pages/workflows/WorkflowsPage.js +43 -33
- package/dist/timecampus/pages/workflows/WorkflowsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -3,19 +3,23 @@ import { PageLayout as t } from "../../components/PageLayout.js";
|
|
|
3
3
|
import { useState as n } from "react";
|
|
4
4
|
import { ArrowLeft as r } from "lucide-react";
|
|
5
5
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
+
import { GlassCard as o } from "@burdenoff/fe-libs/ui";
|
|
6
7
|
//#region src/timecampus/pages/projects/ProjectCreatePage.tsx
|
|
7
|
-
function
|
|
8
|
-
let [
|
|
8
|
+
function s() {
|
|
9
|
+
let [s, c] = n(""), [l, u] = n(""), [d, f] = n(""), [p, m] = n(""), [h, g] = n(""), [_, { loading: v, error: y }] = e();
|
|
9
10
|
return /* @__PURE__ */ i(t, {
|
|
10
11
|
title: "Create Project",
|
|
11
12
|
description: "Set up a new project for time tracking",
|
|
13
|
+
purpose: "Define a new project — its client, estimate and rate — so the time your team logs against it rolls up into accurate progress and billing from day one.",
|
|
12
14
|
actions: /* @__PURE__ */ a("button", {
|
|
13
15
|
className: "inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50",
|
|
14
16
|
children: [/* @__PURE__ */ i(r, { className: "h-4 w-4" }), "Back to Projects"]
|
|
15
17
|
}),
|
|
16
|
-
children: /* @__PURE__ */ a(
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
children: /* @__PURE__ */ a(o, {
|
|
19
|
+
treatment: "glass",
|
|
20
|
+
glow: !0,
|
|
21
|
+
className: "mx-auto max-w-2xl p-6",
|
|
22
|
+
children: [y && /* @__PURE__ */ i("div", {
|
|
19
23
|
className: "mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text",
|
|
20
24
|
children: "Failed to create project. Please try again."
|
|
21
25
|
}), /* @__PURE__ */ a("div", {
|
|
@@ -27,8 +31,8 @@ function o() {
|
|
|
27
31
|
}), /* @__PURE__ */ i("input", {
|
|
28
32
|
type: "text",
|
|
29
33
|
placeholder: "Enter project name",
|
|
30
|
-
value:
|
|
31
|
-
onChange: (e) =>
|
|
34
|
+
value: s,
|
|
35
|
+
onChange: (e) => c(e.target.value),
|
|
32
36
|
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary"
|
|
33
37
|
})] }),
|
|
34
38
|
/* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("label", {
|
|
@@ -37,8 +41,8 @@ function o() {
|
|
|
37
41
|
}), /* @__PURE__ */ i("input", {
|
|
38
42
|
type: "text",
|
|
39
43
|
placeholder: "Client name",
|
|
40
|
-
value:
|
|
41
|
-
onChange: (e) =>
|
|
44
|
+
value: l,
|
|
45
|
+
onChange: (e) => u(e.target.value),
|
|
42
46
|
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary"
|
|
43
47
|
})] }),
|
|
44
48
|
/* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("label", {
|
|
@@ -47,8 +51,8 @@ function o() {
|
|
|
47
51
|
}), /* @__PURE__ */ i("textarea", {
|
|
48
52
|
placeholder: "Project description",
|
|
49
53
|
rows: 3,
|
|
50
|
-
value:
|
|
51
|
-
onChange: (e) =>
|
|
54
|
+
value: d,
|
|
55
|
+
onChange: (e) => f(e.target.value),
|
|
52
56
|
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary"
|
|
53
57
|
})] }),
|
|
54
58
|
/* @__PURE__ */ a("div", {
|
|
@@ -59,8 +63,8 @@ function o() {
|
|
|
59
63
|
}), /* @__PURE__ */ i("input", {
|
|
60
64
|
type: "number",
|
|
61
65
|
placeholder: "0",
|
|
62
|
-
value:
|
|
63
|
-
onChange: (e) =>
|
|
66
|
+
value: p,
|
|
67
|
+
onChange: (e) => m(e.target.value),
|
|
64
68
|
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
65
69
|
})] }), /* @__PURE__ */ a("div", { children: [/* @__PURE__ */ i("label", {
|
|
66
70
|
className: "block text-sm font-medium text-text-primary",
|
|
@@ -68,8 +72,8 @@ function o() {
|
|
|
68
72
|
}), /* @__PURE__ */ i("input", {
|
|
69
73
|
type: "number",
|
|
70
74
|
placeholder: "0.00",
|
|
71
|
-
value:
|
|
72
|
-
onChange: (e) =>
|
|
75
|
+
value: h,
|
|
76
|
+
onChange: (e) => g(e.target.value),
|
|
73
77
|
className: "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
|
|
74
78
|
})] })]
|
|
75
79
|
}),
|
|
@@ -80,17 +84,17 @@ function o() {
|
|
|
80
84
|
children: "Cancel"
|
|
81
85
|
}), /* @__PURE__ */ i("button", {
|
|
82
86
|
onClick: async () => {
|
|
83
|
-
|
|
84
|
-
name:
|
|
85
|
-
description:
|
|
86
|
-
clientId:
|
|
87
|
-
estimatedHours:
|
|
88
|
-
hourlyRate:
|
|
87
|
+
s.trim() && await _({ variables: { input: {
|
|
88
|
+
name: s.trim(),
|
|
89
|
+
description: d.trim() || void 0,
|
|
90
|
+
clientId: l.trim() || void 0,
|
|
91
|
+
estimatedHours: p ? Number(p) : void 0,
|
|
92
|
+
hourlyRate: h ? Number(h) : void 0
|
|
89
93
|
} } });
|
|
90
94
|
},
|
|
91
|
-
disabled:
|
|
95
|
+
disabled: v || !s.trim(),
|
|
92
96
|
className: "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",
|
|
93
|
-
children:
|
|
97
|
+
children: v ? "Creating..." : "Create Project"
|
|
94
98
|
})]
|
|
95
99
|
})
|
|
96
100
|
]
|
|
@@ -99,6 +103,6 @@ function o() {
|
|
|
99
103
|
});
|
|
100
104
|
}
|
|
101
105
|
//#endregion
|
|
102
|
-
export {
|
|
106
|
+
export { s as ProjectCreatePage };
|
|
103
107
|
|
|
104
108
|
//# sourceMappingURL=ProjectCreatePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectCreatePage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectCreatePage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { useCreateProjectMutation } from \"@/generated/wspace-operations\";\n\nexport function ProjectCreatePage() {\n const [name, setName] = useState(\"\");\n const [clientId, setClientId] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [estimatedHours, setEstimatedHours] = useState(\"\");\n const [hourlyRate, setHourlyRate] = useState(\"\");\n\n const [createProject, { loading: creating, error }] =\n useCreateProjectMutation();\n\n const handleSubmit = async () => {\n if (!name.trim()) return;\n await createProject({\n variables: {\n input: {\n name: name.trim(),\n description: description.trim() || undefined,\n clientId: clientId.trim() || undefined,\n estimatedHours: estimatedHours ? Number(estimatedHours) : undefined,\n hourlyRate: hourlyRate ? Number(hourlyRate) : undefined,\n },\n },\n });\n };\n\n return (\n <PageLayout\n title=\"Create Project\"\n description=\"Set up a new project for time tracking\"\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\">\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Projects\n </button>\n }\n >\n <
|
|
1
|
+
{"version":3,"file":"ProjectCreatePage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectCreatePage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { useCreateProjectMutation } from \"@/generated/wspace-operations\";\n\nexport function ProjectCreatePage() {\n const [name, setName] = useState(\"\");\n const [clientId, setClientId] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [estimatedHours, setEstimatedHours] = useState(\"\");\n const [hourlyRate, setHourlyRate] = useState(\"\");\n\n const [createProject, { loading: creating, error }] =\n useCreateProjectMutation();\n\n const handleSubmit = async () => {\n if (!name.trim()) return;\n await createProject({\n variables: {\n input: {\n name: name.trim(),\n description: description.trim() || undefined,\n clientId: clientId.trim() || undefined,\n estimatedHours: estimatedHours ? Number(estimatedHours) : undefined,\n hourlyRate: hourlyRate ? Number(hourlyRate) : undefined,\n },\n },\n });\n };\n\n return (\n <PageLayout\n title=\"Create Project\"\n description=\"Set up a new project for time tracking\"\n purpose=\"Define a new project — its client, estimate and rate — so the time your team logs against it rolls up into accurate progress and billing from day one.\"\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\">\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Projects\n </button>\n }\n >\n <GlassCard treatment=\"glass\" glow className=\"mx-auto max-w-2xl p-6\">\n {error && (\n <div className=\"mb-4 rounded-lg border border-status-error-bg/40 bg-status-error-bg p-3 text-sm text-status-error-text\">\n Failed to create project. Please try again.\n </div>\n )}\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Project Name\n </label>\n <input\n type=\"text\"\n placeholder=\"Enter project name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Client\n </label>\n <input\n type=\"text\"\n placeholder=\"Client name\"\n value={clientId}\n onChange={(e) => setClientId(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Description\n </label>\n <textarea\n placeholder=\"Project description\"\n rows={3}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Estimated Hours\n </label>\n <input\n type=\"number\"\n placeholder=\"0\"\n value={estimatedHours}\n onChange={(e) => setEstimatedHours(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary\">\n Hourly Rate\n </label>\n <input\n type=\"number\"\n placeholder=\"0.00\"\n value={hourlyRate}\n onChange={(e) => setHourlyRate(e.target.value)}\n className=\"mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n </div>\n <div className=\"flex justify-end gap-2 pt-4\">\n <button className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\">\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={creating || !name.trim()}\n className=\"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 {creating ? \"Creating...\" : \"Create Project\"}\n </button>\n </div>\n </div>\n </GlassCard>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,IAAoB;CAClC,IAAM,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAgB,KAAqB,EAAS,GAAG,EAClD,CAAC,GAAY,KAAiB,EAAS,GAAG,EAE1C,CAAC,GAAe,EAAE,SAAS,GAAU,cACzC,GAA0B;AAiB5B,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SAAQ;EACR,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,mBAE1B;;YAGX,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAA5C,CACG,KACC,kBAAC,OAAD;IAAK,WAAU;cAAyG;IAElH,CAAA,EAER,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAA8C;MAEvD,CAAA,EACR,kBAAC,SAAD;MACE,MAAK;MACL,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;MACxC,WAAU;MACV,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAA8C;MAEvD,CAAA,EACR,kBAAC,SAAD;MACE,MAAK;MACL,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;MAC5C,WAAU;MACV,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAA8C;MAEvD,CAAA,EACR,kBAAC,YAAD;MACE,aAAY;MACZ,MAAM;MACN,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,WAAU;MACV,CAAA,CACE,EAAA,CAAA;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAA8C;OAEvD,CAAA,EACR,kBAAC,SAAD;OACE,MAAK;OACL,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAkB,EAAE,OAAO,MAAM;OAClD,WAAU;OACV,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBAA8C;OAEvD,CAAA,EACR,kBAAC,SAAD;OACE,MAAK;OACL,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;OAC9C,WAAU;OACV,CAAA,CACE,EAAA,CAAA,CACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OAAQ,WAAU;iBAA+G;OAExH,CAAA,EACT,kBAAC,UAAD;OACE,SArGS,YAAY;AAC1B,UAAK,MAAM,IAChB,MAAM,EAAc,EAClB,WAAW,EACT,OAAO;SACL,MAAM,EAAK,MAAM;SACjB,aAAa,EAAY,MAAM,IAAI,KAAA;SACnC,UAAU,EAAS,MAAM,IAAI,KAAA;SAC7B,gBAAgB,IAAiB,OAAO,EAAe,GAAG,KAAA;SAC1D,YAAY,IAAa,OAAO,EAAW,GAAG,KAAA;SAC/C,EACF,EACF,CAAC;;OA0FQ,UAAU,KAAY,CAAC,EAAK,MAAM;OAClC,WAAU;iBAET,IAAW,gBAAgB;OACrB,CAAA,CACL;;KACF;MACI;;EACD,CAAA"}
|
|
@@ -1,91 +1,122 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { useTimeCampusNavigate as e } from "../../providers/TimeCampusProvider.js";
|
|
2
|
+
import { formatCurrency as t, formatHours as n } from "../../utils/helpers.js";
|
|
3
|
+
import { StatCard as r } from "../../components/StatCard.js";
|
|
4
|
+
import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
|
|
5
|
+
import { useGetProjectQuery as a, useGetProjectStatsQuery as o } from "../../../generated/wspace-operations.js";
|
|
6
|
+
import { PageLayout as s } from "../../components/PageLayout.js";
|
|
7
|
+
import { Clock as c, FolderOpen as l, TrendingUp as u, Users as d } from "lucide-react";
|
|
8
|
+
import { useParams as f } from "react-router-dom";
|
|
9
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
10
|
+
import { NextSteps as h } from "@burdenoff/fe-libs/ui";
|
|
9
11
|
//#region src/timecampus/pages/projects/ProjectDetailPage.tsx
|
|
10
|
-
function
|
|
11
|
-
let { projectId:
|
|
12
|
-
variables: { id:
|
|
13
|
-
skip: !
|
|
14
|
-
}), { data:
|
|
15
|
-
variables: { id:
|
|
16
|
-
skip: !
|
|
17
|
-
}),
|
|
18
|
-
return
|
|
12
|
+
function g() {
|
|
13
|
+
let { projectId: g } = f(), _ = e(), { data: v, loading: y, error: b } = a({
|
|
14
|
+
variables: { id: g },
|
|
15
|
+
skip: !g
|
|
16
|
+
}), { data: x, loading: S } = o({
|
|
17
|
+
variables: { id: g },
|
|
18
|
+
skip: !g
|
|
19
|
+
}), C = v?.project, w = x?.projectStats;
|
|
20
|
+
return b ? /* @__PURE__ */ p(s, {
|
|
19
21
|
title: "Project Details",
|
|
20
|
-
description: `Project ID: ${
|
|
21
|
-
children: /* @__PURE__ */
|
|
22
|
+
description: `Project ID: ${g}`,
|
|
23
|
+
children: /* @__PURE__ */ p("div", {
|
|
22
24
|
className: "rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text",
|
|
23
25
|
children: "Failed to load project details. Please try again later."
|
|
24
26
|
})
|
|
25
|
-
}) :
|
|
27
|
+
}) : y || S ? /* @__PURE__ */ p(s, {
|
|
26
28
|
title: "Project Details",
|
|
27
|
-
description: `Project ID: ${
|
|
28
|
-
children: /* @__PURE__ */
|
|
29
|
-
}) : /* @__PURE__ */
|
|
30
|
-
title:
|
|
31
|
-
description:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
29
|
+
description: `Project ID: ${g}`,
|
|
30
|
+
children: /* @__PURE__ */ p(i, { variant: "detail" })
|
|
31
|
+
}) : /* @__PURE__ */ m(s, {
|
|
32
|
+
title: C?.name ?? "Project Details",
|
|
33
|
+
description: C?.description ?? `Project ID: ${g}`,
|
|
34
|
+
purpose: "See everything happening on this project in one place — logged hours, task progress and budget burn — so you know whether it's on track and where the time is going before it overruns.",
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ p(h, {
|
|
37
|
+
storageKey: "timecampus-project-detail",
|
|
38
|
+
className: "mb-6",
|
|
39
|
+
steps: [
|
|
40
|
+
{
|
|
41
|
+
id: "log-time",
|
|
42
|
+
label: "Log time to this project",
|
|
43
|
+
description: "Start the timer or add a manual entry for this work.",
|
|
44
|
+
onClick: () => _("/time/timer")
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "view-tasks",
|
|
48
|
+
label: "Review tasks",
|
|
49
|
+
description: "Break the project into trackable tasks.",
|
|
50
|
+
onClick: () => _(`/projects/${g ?? ""}/tasks`)
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "open-reports",
|
|
54
|
+
label: "Open reports",
|
|
55
|
+
description: "Analyse this project's time and budget over time.",
|
|
56
|
+
onClick: () => _("/reports")
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}),
|
|
60
|
+
/* @__PURE__ */ m("div", {
|
|
61
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ p(r, {
|
|
64
|
+
featured: !0,
|
|
65
|
+
title: "Tracked Hours",
|
|
66
|
+
value: n(w?.totalHours ?? C?.trackedHours ?? 0),
|
|
67
|
+
icon: /* @__PURE__ */ p(c, { className: "h-5 w-5" })
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ p(r, {
|
|
70
|
+
title: "Tasks",
|
|
71
|
+
value: `${w?.completedTasks ?? 0} / ${w?.totalTasks ?? 0}`,
|
|
72
|
+
icon: /* @__PURE__ */ p(d, { className: "h-5 w-5" }),
|
|
73
|
+
description: "completed / total"
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ p(r, {
|
|
76
|
+
title: "Progress",
|
|
77
|
+
value: w?.totalTasks ? `${Math.round((w?.completedTasks ?? 0) / w.totalTasks * 100)}%` : "0%",
|
|
78
|
+
icon: /* @__PURE__ */ p(u, { className: "h-5 w-5" })
|
|
79
|
+
}),
|
|
80
|
+
/* @__PURE__ */ p(r, {
|
|
81
|
+
title: "Budget Used",
|
|
82
|
+
value: t(w?.budgetUsed ?? 0, C?.currency ?? "USD"),
|
|
83
|
+
icon: /* @__PURE__ */ p(l, { className: "h-5 w-5" }),
|
|
84
|
+
description: w?.budgetRemaining == null ? void 0 : `${t(w.budgetRemaining, C?.currency ?? "USD")} remaining`
|
|
70
85
|
})
|
|
86
|
+
]
|
|
87
|
+
}),
|
|
88
|
+
/* @__PURE__ */ m("div", {
|
|
89
|
+
className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
|
|
90
|
+
children: [/* @__PURE__ */ m("div", {
|
|
91
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
92
|
+
children: [/* @__PURE__ */ p("h3", {
|
|
93
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
94
|
+
children: "Recent Activity"
|
|
95
|
+
}), /* @__PURE__ */ p("div", {
|
|
96
|
+
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
97
|
+
children: /* @__PURE__ */ p("p", {
|
|
98
|
+
className: "text-sm text-text-secondary",
|
|
99
|
+
children: "Activity timeline will render here"
|
|
100
|
+
})
|
|
101
|
+
})]
|
|
102
|
+
}), /* @__PURE__ */ m("div", {
|
|
103
|
+
className: "rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6",
|
|
104
|
+
children: [/* @__PURE__ */ p("h3", {
|
|
105
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
106
|
+
children: "Time Distribution"
|
|
107
|
+
}), /* @__PURE__ */ p("div", {
|
|
108
|
+
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
109
|
+
children: /* @__PURE__ */ p("p", {
|
|
110
|
+
className: "text-sm text-text-secondary",
|
|
111
|
+
children: "Chart will render here"
|
|
112
|
+
})
|
|
113
|
+
})]
|
|
71
114
|
})]
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
children: [/* @__PURE__ */ f("h3", {
|
|
75
|
-
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
76
|
-
children: "Time Distribution"
|
|
77
|
-
}), /* @__PURE__ */ f("div", {
|
|
78
|
-
className: "flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle",
|
|
79
|
-
children: /* @__PURE__ */ f("p", {
|
|
80
|
-
className: "text-sm text-text-secondary",
|
|
81
|
-
children: "Chart will render here"
|
|
82
|
-
})
|
|
83
|
-
})]
|
|
84
|
-
})]
|
|
85
|
-
})]
|
|
115
|
+
})
|
|
116
|
+
]
|
|
86
117
|
});
|
|
87
118
|
}
|
|
88
119
|
//#endregion
|
|
89
|
-
export {
|
|
120
|
+
export { g as ProjectDetailPage };
|
|
90
121
|
|
|
91
122
|
//# sourceMappingURL=ProjectDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectDetailPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { FolderOpen, Clock, Users, TrendingUp } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { formatHours, formatCurrency } from \"../../utils/helpers\";\nimport {\n useGetProjectQuery,\n useGetProjectStatsQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function ProjectDetailPage() {\n const { projectId } = useParams<{ projectId: string }>();\n\n const {\n data: projectData,\n loading: projectLoading,\n error: projectError,\n } = useGetProjectQuery({\n variables: { id: projectId! },\n skip: !projectId,\n });\n\n const { data: statsData, loading: statsLoading } = useGetProjectStatsQuery({\n variables: { id: projectId! },\n skip: !projectId,\n });\n\n const project = projectData?.project;\n const stats = statsData?.projectStats;\n\n if (projectError) {\n return (\n <PageLayout\n title=\"Project Details\"\n description={`Project ID: ${projectId}`}\n >\n <div className=\"rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text\">\n Failed to load project details. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n if (projectLoading || statsLoading) {\n return (\n <PageLayout\n title=\"Project Details\"\n description={`Project ID: ${projectId}`}\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={project?.name ?? \"Project Details\"}\n description={project?.description ?? `Project ID: ${projectId}`}\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n title=\"Tracked Hours\"\n value={formatHours(stats?.totalHours ?? project?.trackedHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Tasks\"\n value={`${stats?.completedTasks ?? 0} / ${stats?.totalTasks ?? 0}`}\n icon={<Users className=\"h-5 w-5\" />}\n description=\"completed / total\"\n />\n <StatCard\n title=\"Progress\"\n value={\n stats?.totalTasks\n ? `${Math.round(((stats?.completedTasks ?? 0) / stats.totalTasks) * 100)}%`\n : \"0%\"\n }\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Budget Used\"\n value={formatCurrency(\n stats?.budgetUsed ?? 0,\n project?.currency ?? \"USD\",\n )}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={\n stats?.budgetRemaining != null\n ? `${formatCurrency(stats.budgetRemaining, project?.currency ?? \"USD\")} remaining`\n : undefined\n }\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Recent Activity\n </h3>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n Activity timeline will render here\n </p>\n </div>\n </div>\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Time Distribution\n </h3>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n Chart will render here\n </p>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectDetailPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectDetailPage.tsx"],"sourcesContent":["import { useParams } from \"react-router-dom\";\nimport { FolderOpen, Clock, Users, TrendingUp } from \"lucide-react\";\nimport { NextSteps } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { useTimeCampusNavigate } from \"../../providers/TimeCampusProvider\";\nimport { formatHours, formatCurrency } from \"../../utils/helpers\";\nimport {\n useGetProjectQuery,\n useGetProjectStatsQuery,\n} from \"@/generated/wspace-operations\";\n\nexport function ProjectDetailPage() {\n const { projectId } = useParams<{ projectId: string }>();\n const navigate = useTimeCampusNavigate();\n\n const {\n data: projectData,\n loading: projectLoading,\n error: projectError,\n } = useGetProjectQuery({\n variables: { id: projectId! },\n skip: !projectId,\n });\n\n const { data: statsData, loading: statsLoading } = useGetProjectStatsQuery({\n variables: { id: projectId! },\n skip: !projectId,\n });\n\n const project = projectData?.project;\n const stats = statsData?.projectStats;\n\n if (projectError) {\n return (\n <PageLayout\n title=\"Project Details\"\n description={`Project ID: ${projectId}`}\n >\n <div className=\"rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text\">\n Failed to load project details. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n if (projectLoading || statsLoading) {\n return (\n <PageLayout\n title=\"Project Details\"\n description={`Project ID: ${projectId}`}\n >\n <LoadingSkeleton variant=\"detail\" />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={project?.name ?? \"Project Details\"}\n description={project?.description ?? `Project ID: ${projectId}`}\n purpose=\"See everything happening on this project in one place — logged hours, task progress and budget burn — so you know whether it's on track and where the time is going before it overruns.\"\n >\n <NextSteps\n storageKey=\"timecampus-project-detail\"\n className=\"mb-6\"\n steps={[\n {\n id: \"log-time\",\n label: \"Log time to this project\",\n description: \"Start the timer or add a manual entry for this work.\",\n onClick: () => navigate(\"/time/timer\"),\n },\n {\n id: \"view-tasks\",\n label: \"Review tasks\",\n description: \"Break the project into trackable tasks.\",\n onClick: () => navigate(`/projects/${projectId ?? \"\"}/tasks`),\n },\n {\n id: \"open-reports\",\n label: \"Open reports\",\n description: \"Analyse this project's time and budget over time.\",\n onClick: () => navigate(\"/reports\"),\n },\n ]}\n />\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Tracked Hours\"\n value={formatHours(stats?.totalHours ?? project?.trackedHours ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Tasks\"\n value={`${stats?.completedTasks ?? 0} / ${stats?.totalTasks ?? 0}`}\n icon={<Users className=\"h-5 w-5\" />}\n description=\"completed / total\"\n />\n <StatCard\n title=\"Progress\"\n value={\n stats?.totalTasks\n ? `${Math.round(((stats?.completedTasks ?? 0) / stats.totalTasks) * 100)}%`\n : \"0%\"\n }\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n title=\"Budget Used\"\n value={formatCurrency(\n stats?.budgetUsed ?? 0,\n project?.currency ?? \"USD\",\n )}\n icon={<FolderOpen className=\"h-5 w-5\" />}\n description={\n stats?.budgetRemaining != null\n ? `${formatCurrency(stats.budgetRemaining, project?.currency ?? \"USD\")} remaining`\n : undefined\n }\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Recent Activity\n </h3>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n Activity timeline will render here\n </p>\n </div>\n </div>\n <div className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-6\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">\n Time Distribution\n </h3>\n <div className=\"flex h-48 items-center justify-center rounded-lg border border-dashed border-border-subtle\">\n <p className=\"text-sm text-text-secondary\">\n Chart will render here\n </p>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,IAAoB;CAClC,IAAM,EAAE,iBAAc,GAAkC,EAClD,IAAW,GAAuB,EAElC,EACJ,MAAM,GACN,SAAS,GACT,OAAO,MACL,EAAmB;EACrB,WAAW,EAAE,IAAI,GAAY;EAC7B,MAAM,CAAC;EACR,CAAC,EAEI,EAAE,MAAM,GAAW,SAAS,MAAiB,EAAwB;EACzE,WAAW,EAAE,IAAI,GAAY;EAC7B,MAAM,CAAC;EACR,CAAC,EAEI,IAAU,GAAa,SACvB,IAAQ,GAAW;AA0BzB,QAxBI,IAEA,kBAAC,GAAD;EACE,OAAM;EACN,aAAa,eAAe;YAE5B,kBAAC,OAAD;GAAK,WAAU;aAAoG;GAE7G,CAAA;EACK,CAAA,GAIb,KAAkB,IAElB,kBAAC,GAAD;EACE,OAAM;EACN,aAAa,eAAe;YAE5B,kBAAC,GAAD,EAAiB,SAAQ,UAAW,CAAA;EACzB,CAAA,GAKf,kBAAC,GAAD;EACE,OAAO,GAAS,QAAQ;EACxB,aAAa,GAAS,eAAe,eAAe;EACpD,SAAQ;YAHV;GAKE,kBAAC,GAAD;IACE,YAAW;IACX,WAAU;IACV,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,cAAc;MACvC;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,aAAa,KAAa,GAAG,QAAQ;MAC9D;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,WAAW;MACpC;KACF;IACD,CAAA;GACF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,UAAA;MACA,OAAM;MACN,OAAO,EAAY,GAAO,cAAc,GAAS,gBAAgB,EAAE;MACnE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,GAAG,GAAO,kBAAkB,EAAE,KAAK,GAAO,cAAc;MAC/D,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,aAAY;MACZ,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OACE,GAAO,aACH,GAAG,KAAK,OAAQ,GAAO,kBAAkB,KAAK,EAAM,aAAc,IAAI,CAAC,KACvE;MAEN,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EACL,GAAO,cAAc,GACrB,GAAS,YAAY,MACtB;MACD,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,aACE,GAAO,mBAAmB,OAEtB,KAAA,IADA,GAAG,EAAe,EAAM,iBAAiB,GAAS,YAAY,MAAM,CAAC;MAG3E,CAAA;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAExD,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAEvC,CAAA;MACA,CAAA,CACF;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAExD,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAEvC,CAAA;MACA,CAAA,CACF;OACF;;GACK"}
|
|
@@ -2,7 +2,8 @@ import { formatHours as e, getStatusColor as t } from "../../utils/helpers.js";
|
|
|
2
2
|
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
3
3
|
import { useListProjectsQuery as r } from "../../../generated/wspace-operations.js";
|
|
4
4
|
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
5
|
-
import {
|
|
5
|
+
import { EmptyState as a } from "../../components/EmptyState.js";
|
|
6
|
+
import { Plus as o } from "lucide-react";
|
|
6
7
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
7
8
|
import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
9
|
//#region src/timecampus/pages/projects/ProjectsPage.tsx
|
|
@@ -21,6 +22,7 @@ function u() {
|
|
|
21
22
|
}) : /* @__PURE__ */ s(i, {
|
|
22
23
|
title: d("timecampus.projects.title", "Projects"),
|
|
23
24
|
description: d("timecampus.projects.description", "Manage and track project time"),
|
|
25
|
+
purpose: d("timecampus.projects.purpose", "Group your work into projects so every hour you track rolls up to the right client and budget — use it to estimate effort, watch progress against the plan, and bill accurately."),
|
|
24
26
|
actions: /* @__PURE__ */ c("button", {
|
|
25
27
|
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
26
28
|
children: [/* @__PURE__ */ s(o, { className: "h-4 w-4" }), d("timecampus.projects.actions.newProject", "New Project")]
|
|
@@ -28,12 +30,14 @@ function u() {
|
|
|
28
30
|
children: p ? /* @__PURE__ */ s(n, {
|
|
29
31
|
variant: "card",
|
|
30
32
|
count: 4
|
|
31
|
-
}) : h.length === 0 ? /* @__PURE__ */
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
}) : h.length === 0 ? /* @__PURE__ */ s(a, {
|
|
34
|
+
illustration: "empty-generic",
|
|
35
|
+
title: d("timecampus.projects.empty.title", "No projects yet"),
|
|
36
|
+
description: d("timecampus.projects.empty", "No projects yet. Create your first project to get started."),
|
|
37
|
+
action: /* @__PURE__ */ c("button", {
|
|
38
|
+
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
39
|
+
children: [/* @__PURE__ */ s(o, { className: "h-4 w-4" }), d("timecampus.projects.actions.newProject", "New Project")]
|
|
40
|
+
})
|
|
37
41
|
}) : /* @__PURE__ */ s("div", {
|
|
38
42
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
39
43
|
children: h.map((n) => /* @__PURE__ */ c("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectsPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectsPage.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"ProjectsPage.js","names":[],"sources":["../../../../src/timecampus/pages/projects/ProjectsPage.tsx"],"sourcesContent":["import { Plus } from \"lucide-react\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { getStatusColor, formatHours } from \"../../utils/helpers\";\nimport {\n useListProjectsQuery,\n type ListProjectsQuery,\n} from \"@/generated/wspace-operations\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\n\ntype ProjectItem = NonNullable<ListProjectsQuery[\"projects\"]>[\"items\"][number];\n\nexport function ProjectsPage() {\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 { data, loading, error } = useListProjectsQuery({\n variables: { limit: 50 },\n });\n\n const projects = data?.projects?.items ?? [];\n\n if (error) {\n return (\n <PageLayout\n title={t(\"timecampus.projects.title\", \"Projects\")}\n description={t(\n \"timecampus.projects.description\",\n \"Manage and track project time\",\n )}\n >\n <div className=\"rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text\">\n {t(\n \"timecampus.projects.error.loadFailed\",\n \"Failed to load projects. Please try again later.\",\n )}\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={t(\"timecampus.projects.title\", \"Projects\")}\n description={t(\n \"timecampus.projects.description\",\n \"Manage and track project time\",\n )}\n purpose={t(\n \"timecampus.projects.purpose\",\n \"Group your work into projects so every hour you track rolls up to the right client and budget — use it to estimate effort, watch progress against the plan, and bill accurately.\",\n )}\n actions={\n <button className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\">\n <Plus className=\"h-4 w-4\" />\n {t(\"timecampus.projects.actions.newProject\", \"New Project\")}\n </button>\n }\n >\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={4} />\n ) : projects.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title={t(\"timecampus.projects.empty.title\", \"No projects yet\")}\n description={t(\n \"timecampus.projects.empty\",\n \"No projects yet. Create your first project to get started.\",\n )}\n action={\n <button className=\"inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\">\n <Plus className=\"h-4 w-4\" />\n {t(\"timecampus.projects.actions.newProject\", \"New Project\")}\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {projects.map((project: ProjectItem) => (\n <div\n key={project.id}\n className=\"rounded-xl border border-border-seam bg-gloss-card shadow-pop p-5 transition-colors hover:bg-bg-sunken/50 cursor-pointer\"\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div\n className=\"h-3 w-3 rounded-full\"\n style={{\n backgroundColor:\n project.color ?? \"var(--color-accent-blue)\",\n }}\n />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {project.name}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {project.clientId ??\n t(\"timecampus.projects.card.noClient\", \"No client\")}\n </p>\n </div>\n </div>\n <span\n className={`inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${getStatusColor(project.status)}`}\n >\n {project.status}\n </span>\n </div>\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>\n {t(\"timecampus.projects.card.progress\", \"Progress\")}\n </span>\n <span>\n {project.estimatedHours\n ? Math.round(\n (project.trackedHours / project.estimatedHours) * 100,\n )\n : 0}\n %\n </span>\n </div>\n <div className=\"mt-1 h-2 rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-action-primary-bg\"\n style={{\n width: `${project.estimatedHours ? Math.min(Math.round((project.trackedHours / project.estimatedHours) * 100), 100) : 0}%`,\n }}\n />\n </div>\n </div>\n <div className=\"mt-3 flex items-center justify-between text-xs text-text-secondary\">\n <span>\n {formatHours(project.trackedHours)} /{\" \"}\n {formatHours(project.estimatedHours ?? 0)}\n </span>\n <span>\n {project.tasks?.length ?? 0}{\" \"}\n {t(\"timecampus.projects.card.tasks\", \"tasks\")}\n </span>\n </div>\n </div>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,IAAe;CAC7B,IAAM,EAAE,GAAG,MAAc,GAAS,EAC5B,KAAK,GAAa,MAA6B;EACnD,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAE9B,EAAE,SAAM,YAAS,aAAU,EAAqB,EACpD,WAAW,EAAE,OAAO,IAAI,EACzB,CAAC,EAEI,IAAW,GAAM,UAAU,SAAS,EAAE;AAqB5C,QAnBI,IAEA,kBAAC,GAAD;EACE,OAAO,EAAE,6BAA6B,WAAW;EACjD,aAAa,EACX,mCACA,gCACD;YAED,kBAAC,OAAD;GAAK,WAAU;aACZ,EACC,wCACA,mDACD;GACG,CAAA;EACK,CAAA,GAKf,kBAAC,GAAD;EACE,OAAO,EAAE,6BAA6B,WAAW;EACjD,aAAa,EACX,mCACA,gCACD;EACD,SAAS,EACP,+BACA,mLACD;EACD,SACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAE,0CAA0C,cAAc,CACpD;;YAGV,IACC,kBAAC,GAAD;GAAiB,SAAQ;GAAO,OAAO;GAAK,CAAA,GAC1C,EAAS,WAAW,IACtB,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAE,mCAAmC,kBAAkB;GAC9D,aAAa,EACX,6BACA,6DACD;GACD,QACE,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAE,0CAA0C,cAAc,CACpD;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAS,KAAK,MACb,kBAAC,OAAD;IAEE,WAAU;cAFZ;KAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QACE,WAAU;QACV,OAAO,EACL,iBACE,EAAQ,SAAS,4BACpB;QACD,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ;QACP,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ,YACP,EAAE,qCAAqC,YAAY;QACnD,CAAA,CACA,EAAA,CAAA,CACF;UACN,kBAAC,QAAD;OACE,WAAW,4DAA4D,EAAe,EAAQ,OAAO;iBAEpG,EAAQ;OACJ,CAAA,CACH;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD,EAAA,UACG,EAAE,qCAAqC,WAAW,EAC9C,CAAA,EACP,kBAAC,QAAD,EAAA,UAAA,CACG,EAAQ,iBACL,KAAK,MACF,EAAQ,eAAe,EAAQ,iBAAkB,IACnD,GACD,GAAE,IAED,EAAA,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QACE,WAAU;QACV,OAAO,EACL,OAAO,GAAG,EAAQ,iBAAiB,KAAK,IAAI,KAAK,MAAO,EAAQ,eAAe,EAAQ,iBAAkB,IAAI,EAAE,IAAI,GAAG,EAAE,IACzH;QACD,CAAA;OACE,CAAA,CACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAA;OACG,EAAY,EAAQ,aAAa;OAAC;OAAG;OACrC,EAAY,EAAQ,kBAAkB,EAAE;OACpC,EAAA,CAAA,EACP,kBAAC,QAAD,EAAA,UAAA;OACG,EAAQ,OAAO,UAAU;OAAG;OAC5B,EAAE,kCAAkC,QAAQ;OACxC,EAAA,CAAA,CACH;;KACF;MA7DC,EAAQ,GA6DT,CACN;GACE,CAAA;EAEG,CAAA"}
|
|
@@ -2,44 +2,57 @@ import { getPriorityColor as e, getStatusColor as t } from "../../utils/helpers.
|
|
|
2
2
|
import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
|
|
3
3
|
import { useListTasksQuery as r } from "../../../generated/wspace-operations.js";
|
|
4
4
|
import { PageLayout as i } from "../../components/PageLayout.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { EmptyState as a } from "../../components/EmptyState.js";
|
|
6
|
+
import { CheckSquare as o, Plus as s } from "lucide-react";
|
|
7
|
+
import { useParams as c } from "react-router-dom";
|
|
8
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
9
|
+
import { GlassCard as d } from "@burdenoff/fe-libs/ui";
|
|
8
10
|
//#region src/timecampus/pages/projects/TasksPage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { projectId:
|
|
11
|
-
variables: { projectId:
|
|
12
|
-
skip: !
|
|
13
|
-
}),
|
|
14
|
-
return
|
|
11
|
+
function f() {
|
|
12
|
+
let { projectId: f } = c(), { data: p, loading: m, error: h } = r({
|
|
13
|
+
variables: { projectId: f },
|
|
14
|
+
skip: !f
|
|
15
|
+
}), g = p?.tasks?.items ?? [];
|
|
16
|
+
return h ? /* @__PURE__ */ l(i, {
|
|
15
17
|
title: "Tasks",
|
|
16
|
-
description: `Tasks for project ${
|
|
17
|
-
children: /* @__PURE__ */
|
|
18
|
+
description: `Tasks for project ${f}`,
|
|
19
|
+
children: /* @__PURE__ */ l("div", {
|
|
18
20
|
className: "rounded-xl border border-status-error-bg/40 bg-status-error-bg p-6 text-sm text-status-error-text",
|
|
19
21
|
children: "Failed to load tasks. Please try again later."
|
|
20
22
|
})
|
|
21
|
-
}) : /* @__PURE__ */
|
|
23
|
+
}) : /* @__PURE__ */ l(i, {
|
|
22
24
|
title: "Tasks",
|
|
23
|
-
description: `Tasks for project ${
|
|
24
|
-
|
|
25
|
+
description: `Tasks for project ${f}`,
|
|
26
|
+
purpose: "Break a project down into the concrete pieces of work that need doing, then track hours against each one — so you can see what's done, what's blocking, and where effort is actually being spent.",
|
|
27
|
+
actions: /* @__PURE__ */ u("button", {
|
|
25
28
|
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
26
|
-
children: [/* @__PURE__ */
|
|
29
|
+
children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Add Task"]
|
|
27
30
|
}),
|
|
28
|
-
children:
|
|
31
|
+
children: m ? /* @__PURE__ */ l(n, {
|
|
29
32
|
variant: "list",
|
|
30
33
|
count: 5
|
|
31
|
-
}) : /* @__PURE__ */
|
|
32
|
-
|
|
34
|
+
}) : g.length === 0 ? /* @__PURE__ */ l(a, {
|
|
35
|
+
illustration: "empty-generic",
|
|
36
|
+
title: "No tasks yet",
|
|
37
|
+
description: "Add a task to break this project into trackable work.",
|
|
38
|
+
action: /* @__PURE__ */ u("button", {
|
|
39
|
+
className: "inline-flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
40
|
+
children: [/* @__PURE__ */ l(s, { className: "h-4 w-4" }), "Add Task"]
|
|
41
|
+
})
|
|
42
|
+
}) : /* @__PURE__ */ l(d, {
|
|
43
|
+
treatment: "glass",
|
|
44
|
+
glow: !0,
|
|
45
|
+
className: "overflow-hidden",
|
|
33
46
|
children: /* @__PURE__ */ l("div", {
|
|
34
47
|
className: "divide-y divide-border",
|
|
35
|
-
children:
|
|
48
|
+
children: g.map((n) => /* @__PURE__ */ u("div", {
|
|
36
49
|
className: "flex items-center justify-between p-4 hover:bg-bg-sunken/50 transition-colors",
|
|
37
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ u("div", {
|
|
38
51
|
className: "flex items-center gap-3",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
52
|
+
children: [/* @__PURE__ */ l(o, { className: `h-5 w-5 ${n.status === "done" ? "text-status-success-text" : "text-text-secondary"}` }), /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
|
|
40
53
|
className: `text-sm font-medium ${n.status === "done" ? "text-text-secondary line-through" : "text-text-primary"}`,
|
|
41
54
|
children: n.title
|
|
42
|
-
}), /* @__PURE__ */
|
|
55
|
+
}), /* @__PURE__ */ u("p", {
|
|
43
56
|
className: "text-xs text-text-secondary",
|
|
44
57
|
children: [
|
|
45
58
|
n.assigneeId ?? "Unassigned",
|
|
@@ -49,25 +62,22 @@ function u() {
|
|
|
49
62
|
"h tracked"
|
|
50
63
|
]
|
|
51
64
|
})] })]
|
|
52
|
-
}), /* @__PURE__ */
|
|
65
|
+
}), /* @__PURE__ */ u("div", {
|
|
53
66
|
className: "flex items-center gap-2",
|
|
54
|
-
children: [/* @__PURE__ */
|
|
67
|
+
children: [/* @__PURE__ */ l("span", {
|
|
55
68
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${e(n.priority)}`,
|
|
56
69
|
children: n.priority
|
|
57
|
-
}), /* @__PURE__ */
|
|
70
|
+
}), /* @__PURE__ */ l("span", {
|
|
58
71
|
className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${t(n.status)}`,
|
|
59
72
|
children: n.status
|
|
60
73
|
})]
|
|
61
74
|
})]
|
|
62
|
-
}, n.id))
|
|
63
|
-
className: "p-8 text-center text-sm text-text-secondary",
|
|
64
|
-
children: "No tasks yet. Add a task to get started."
|
|
65
|
-
})]
|
|
75
|
+
}, n.id))
|
|
66
76
|
})
|
|
67
77
|
})
|
|
68
78
|
});
|
|
69
79
|
}
|
|
70
80
|
//#endregion
|
|
71
|
-
export {
|
|
81
|
+
export { f as TasksPage };
|
|
72
82
|
|
|
73
83
|
//# sourceMappingURL=TasksPage.js.map
|