@burdenoff/microfe-timecampus 2026.830.2 → 2026.903.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/timecampus/components/index.js +4 -4
  2. package/dist/timecampus/pages/HomePage.d.ts.map +1 -1
  3. package/dist/timecampus/pages/HomePage.js +142 -131
  4. package/dist/timecampus/pages/HomePage.js.map +1 -1
  5. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js +7 -7
  6. package/dist/timecampus/pages/application-usage/ApplicationUsagePage.js.map +1 -1
  7. package/dist/timecampus/pages/client-portal/ClientPortalPage.js +7 -7
  8. package/dist/timecampus/pages/client-portal/ClientPortalPage.js.map +1 -1
  9. package/dist/timecampus/pages/dashboard/ReportsPage.js +13 -13
  10. package/dist/timecampus/pages/email-tracking/EmailTrackingPage.js +7 -7
  11. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js +7 -7
  12. package/dist/timecampus/pages/expense-tracking/ExpenseTrackingPage.js.map +1 -1
  13. package/dist/timecampus/pages/focus-score/FocusScorePage.js +13 -13
  14. package/dist/timecampus/pages/geofencing/GeofencingPage.js +135 -135
  15. package/dist/timecampus/pages/geofencing/GeofencingPage.js.map +1 -1
  16. package/dist/timecampus/pages/invoicing/InvoicingPage.js +7 -7
  17. package/dist/timecampus/pages/invoicing/InvoicingPage.js.map +1 -1
  18. package/dist/timecampus/pages/lifetime/DeadTimeRadarPage.js +8 -8
  19. package/dist/timecampus/pages/lifetime/FiniteLifePage.js +4 -4
  20. package/dist/timecampus/pages/lifetime/FiniteLifePage.js.map +1 -1
  21. package/dist/timecampus/pages/lifetime/LifeBalancePage.js +104 -104
  22. package/dist/timecampus/pages/lifetime/LifeBalancePage.js.map +1 -1
  23. package/dist/timecampus/pages/lifetime/LifeTimelinePage.js +7 -7
  24. package/dist/timecampus/pages/lifetime/LifeTimelinePage.js.map +1 -1
  25. package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js +33 -33
  26. package/dist/timecampus/pages/lifetime/PersonalCorporatePage.js.map +1 -1
  27. package/dist/timecampus/pages/lifetime/RecommendationsPage.js +80 -80
  28. package/dist/timecampus/pages/lifetime/RecommendationsPage.js.map +1 -1
  29. package/dist/timecampus/pages/lifetime/TimeWellSpentPage.js +16 -16
  30. package/dist/timecampus/pages/lifetime/ValuesGoalsPage.js +11 -11
  31. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js +11 -11
  32. package/dist/timecampus/pages/location-tracking/LocationTrackingPage.js.map +1 -1
  33. package/dist/timecampus/pages/meetings/MeetingDetailPage.js +14 -14
  34. package/dist/timecampus/pages/meetings/MeetingDetailPage.js.map +1 -1
  35. package/dist/timecampus/pages/meetings/MeetingsPage.js +12 -12
  36. package/dist/timecampus/pages/projects/ProjectsPage.js +5 -5
  37. package/dist/timecampus/pages/projects/ProjectsPage.js.map +1 -1
  38. package/dist/timecampus/pages/projects/TasksPage.js +8 -8
  39. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js +8 -8
  40. package/dist/timecampus/pages/resource-planning/ResourcePlanningPage.js.map +1 -1
  41. package/dist/timecampus/pages/team/TeamMembersPage.js +8 -8
  42. package/dist/timecampus/pages/team-activity/TeamActivityPage.js +13 -13
  43. package/dist/timecampus/pages/time/TimeEntriesPage.js +5 -5
  44. package/dist/timecampus/pages/time/TimeEntriesPage.js.map +1 -1
  45. package/dist/timecampus/pages/time/TimeTrackingPage.js +138 -138
  46. package/dist/timecampus/pages/time/TimeTrackingPage.js.map +1 -1
  47. package/dist/timecampus/pages/time/TimerPage.js +14 -14
  48. package/dist/timecampus/pages/time/TimerPage.js.map +1 -1
  49. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js +26 -26
  50. package/dist/timecampus/pages/time-approval/TimeApprovalPage.js.map +1 -1
  51. package/dist/timecampus/pages/timeline/TimelinePage.js +8 -8
  52. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js +79 -79
  53. package/dist/timecampus/pages/work-patterns/WorkPatternsPage.js.map +1 -1
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TimeApprovalPage.js","names":[],"sources":["../../../../src/timecampus/pages/time-approval/TimeApprovalPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n CheckCircle,\n XCircle,\n X,\n Clock,\n MessageSquare,\n MessagesSquare,\n Undo2,\n} from \"lucide-react\";\nimport { ContextConversationWidget } from \"@burdenoff/fe-libs/shared\";\nimport { useRegisterPageConversationContext } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { StatusBadge } from \"../../components/StatusBadge\";\nimport { Modal } from \"../../components/Modal\";\nimport { ToastContainer, useToast } from \"../../components/Toast\";\nimport { ChartCard, DonutChart, ProgressMeter } from \"../../components\";\nimport { getInitials, formatHours, formatDate, cn } from \"../../utils/helpers\";\nimport {\n useListApprovalRequestsQuery,\n useGetApprovalStatsQuery,\n useApproveRequestMutation,\n useRejectRequestMutation,\n useRequestRevisionMutation,\n useWithdrawRequestMutation,\n type ApprovalRequestFieldsFragment,\n type ListApprovalRequestsQuery,\n} from \"@/generated/wspace-operations\";\nimport { ApprovalStatus } from \"@/generated/wspace-types\";\n\nconst PAGE_SIZE = 25;\n\n// Rendered as a child of the review Modal so the registration hook only runs\n// while the modal is mounted — it scopes the shared page-conversation widget to\n// the selected approval request, then releases the context on close/unmount.\nfunction ApprovalReviewThread({\n request,\n}: {\n request: ApprovalRequestFieldsFragment;\n}) {\n useRegisterPageConversationContext({\n entityType: \"TIMECAMPUS_APPROVAL_REQUEST\",\n entityId: request.id,\n contextTitle: `Approval · ${request.period ?? request.id}`,\n });\n\n return <ContextConversationWidget widgetKey=\"approval-review\" />;\n}\n\nconst inputClass =\n \"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\nexport function TimeApprovalPage() {\n const { toasts, addToast, dismissToast } = useToast();\n\n const {\n data: requestsData,\n loading: requestsLoading,\n error: requestsError,\n refetch,\n fetchMore,\n } = useListApprovalRequestsQuery({\n variables: { pagination: { limit: PAGE_SIZE, offset: 0 } },\n notifyOnNetworkStatusChange: true,\n });\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n refetch: refetchStats,\n } = useGetApprovalStatsQuery();\n\n const [approveRequest] = useApproveRequestMutation();\n const [rejectRequest, { loading: rejecting }] = useRejectRequestMutation();\n const [requestRevision, { loading: requestingRevision }] =\n useRequestRevisionMutation();\n const [withdrawRequest] = useWithdrawRequestMutation();\n\n const requests = requestsData?.approvalRequests?.items ?? [];\n const total = requestsData?.approvalRequests?.total ?? 0;\n const hasMore = requestsData?.approvalRequests?.hasMore ?? false;\n const stats = statsData?.approvalStats;\n\n const approvalMix = [\n { name: \"Pending\", value: stats?.pendingCount ?? 0 },\n { name: \"Approved\", value: stats?.approvedCount ?? 0 },\n { name: \"Rejected\", value: stats?.rejectedCount ?? 0 },\n ];\n\n const [loadingMore, setLoadingMore] = useState(false);\n const [busyId, setBusyId] = useState<string | null>(null);\n\n // Reject reason modal\n const [rejectTarget, setRejectTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n const [rejectReason, setRejectReason] = useState(\"\");\n\n // Request revision modal\n const [revisionTarget, setRevisionTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n const [revisionNotes, setRevisionNotes] = useState(\"\");\n\n // Withdraw confirm modal\n const [withdrawTarget, setWithdrawTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n\n // Review / discussion thread modal\n const [reviewTarget, setReviewTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n\n const refreshAll = async () => {\n await Promise.all([refetch(), refetchStats()]);\n };\n\n const handleApprove = async (id: string) => {\n setBusyId(id);\n try {\n await approveRequest({ variables: { id } });\n addToast({ title: \"Timesheet approved\", variant: \"success\" });\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to approve timesheet\", variant: \"error\" });\n } finally {\n setBusyId(null);\n }\n };\n\n const handleReject = async () => {\n if (!rejectTarget || !rejectReason.trim()) return;\n try {\n await rejectRequest({\n variables: { id: rejectTarget.id, reason: rejectReason.trim() },\n });\n addToast({ title: \"Timesheet rejected\", variant: \"success\" });\n setRejectTarget(null);\n setRejectReason(\"\");\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to reject timesheet\", variant: \"error\" });\n }\n };\n\n const handleRequestRevision = async () => {\n if (!revisionTarget || !revisionNotes.trim()) return;\n try {\n await requestRevision({\n variables: { id: revisionTarget.id, notes: revisionNotes.trim() },\n });\n addToast({ title: \"Revision requested\", variant: \"success\" });\n setRevisionTarget(null);\n setRevisionNotes(\"\");\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to request revision\", variant: \"error\" });\n }\n };\n\n const handleWithdraw = async () => {\n if (!withdrawTarget) return;\n try {\n await withdrawRequest({ variables: { id: withdrawTarget.id } });\n addToast({ title: \"Request withdrawn\", variant: \"success\" });\n setWithdrawTarget(null);\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to withdraw request\", variant: \"error\" });\n }\n };\n\n const handleLoadMore = async () => {\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: {\n pagination: { limit: PAGE_SIZE, offset: requests.length },\n },\n updateQuery: (\n prev: ListApprovalRequestsQuery,\n { fetchMoreResult }: { fetchMoreResult?: ListApprovalRequestsQuery },\n ) => {\n if (!fetchMoreResult) return prev;\n return {\n ...prev,\n approvalRequests: {\n ...fetchMoreResult.approvalRequests,\n items: [\n ...prev.approvalRequests.items,\n ...fetchMoreResult.approvalRequests.items,\n ],\n },\n };\n },\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n if (requestsLoading && statsLoading && requests.length === 0) {\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (requestsError && statsError) {\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n >\n <div className=\"rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text\">\n Failed to load approval data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n purpose=\"The reviewer's queue for signing off team timesheets before they're billed or paid — approve, reject or request changes in one place so payroll and invoices go out accurate and on time.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Pending Approvals\"\n value={String(stats?.pendingCount ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-warning-bg text-status-warning-text\"\n />\n <StatCard\n title=\"Approved This Week\"\n value={String(stats?.approvedCount ?? 0)}\n icon={<CheckCircle className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-success-bg text-status-success-text\"\n />\n <StatCard\n title=\"Rejected\"\n value={String(stats?.rejectedCount ?? 0)}\n icon={<XCircle className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-error-bg text-status-error-text\"\n />\n <StatCard\n title=\"Avg. Review Time\"\n value={\n stats?.averageReviewTime\n ? `${Math.round(stats.averageReviewTime)}h`\n : \"N/A\"\n }\n description=\"Target: 24h\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"space-y-4 lg:col-span-2\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-sm font-semibold text-text-primary\">\n Pending Requests\n </h2>\n <p className=\"text-xs text-text-secondary\">\n Showing {requests.length} of {total}\n </p>\n </div>\n\n {requests.length === 0 && !requestsLoading ? (\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No approval requests found\"\n description=\"You're all caught up — submitted timesheets waiting on your review will appear here.\"\n />\n ) : (\n <>\n <div className=\"space-y-3\">\n {requests.map((request: ApprovalRequestFieldsFragment) => {\n const isPending = request.status === ApprovalStatus.Pending;\n const rowBusy = busyId === request.id;\n const selected = reviewTarget?.id === request.id;\n const billablePct =\n request.totalHours > 0\n ? Math.round(\n (request.billableHours / request.totalHours) * 100,\n )\n : 0;\n return (\n <GlassCard\n key={request.id}\n treatment=\"plain\"\n glow={selected}\n className={cn(\n \"p-4\",\n selected && \"border-action-primary-bg/50\",\n )}\n >\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary\">\n {getInitials(request.userId)}\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {request.userId}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {request.period} &middot; Submitted{\" \"}\n {formatDate(request.submittedAt)}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-5\">\n <div className=\"flex items-center gap-6\">\n <div>\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n Total submitted\n </p>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatHours(request.totalHours)}\n </p>\n </div>\n <div>\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n Billable\n </p>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatHours(request.billableHours)}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge\n label={request.status.toLowerCase()}\n status={request.status.toLowerCase()}\n />\n {isPending && (\n <>\n <button\n onClick={() => handleApprove(request.id)}\n disabled={rowBusy}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-status-success-bg px-3 py-1.5 text-sm font-medium text-status-success-text hover:bg-status-success-bg/80 disabled:opacity-50\"\n >\n <CheckCircle className=\"h-4 w-4\" />\n Approve\n </button>\n <button\n onClick={() => {\n setRejectTarget(request);\n setRejectReason(\"\");\n }}\n disabled={rowBusy}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-status-error-bg px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50\"\n >\n <XCircle className=\"h-4 w-4\" />\n Reject\n </button>\n <button\n onClick={() => {\n setRevisionTarget(request);\n setRevisionNotes(\"\");\n }}\n disabled={rowBusy}\n title=\"Request revision\"\n className=\"rounded-md border border-border-seam bg-bg-surface p-1.5 text-status-warning-text hover:bg-status-warning-bg disabled:opacity-50\"\n >\n <MessageSquare className=\"h-4 w-4\" />\n </button>\n <button\n onClick={() => setWithdrawTarget(request)}\n disabled={rowBusy}\n title=\"Withdraw request\"\n className=\"rounded-md border border-border-seam bg-bg-surface p-1.5 text-text-secondary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Undo2 className=\"h-4 w-4\" />\n </button>\n </>\n )}\n <button\n onClick={() =>\n setReviewTarget(selected ? null : request)\n }\n title=\"Review / Discussion\"\n className={cn(\n \"rounded-md border p-1.5\",\n selected\n ? \"border-action-primary-bg bg-action-primary-bg/10 text-primary\"\n : \"border-border-seam bg-bg-surface text-text-secondary hover:bg-bg-sunken\",\n )}\n >\n <MessagesSquare className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {request.totalHours > 0 && (\n <div className=\"mt-4\">\n <ProgressMeter\n value={billablePct}\n max={100}\n tone=\"success\"\n size=\"sm\"\n showValue={false}\n label={`Billable share · ${billablePct}%`}\n />\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n\n {hasMore && (\n <div className=\"flex justify-center\">\n <button\n onClick={handleLoadMore}\n disabled={loadingMore}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50 disabled:opacity-50\"\n >\n {loadingMore ? \"Loading...\" : \"Load more\"}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n\n <div className=\"lg:col-span-1\">\n <div className=\"space-y-4 lg:sticky lg:top-4\">\n <ChartCard\n title=\"Approval mix\"\n description=\"Requests by current status\"\n >\n <DonutChart\n data={approvalMix}\n centerLabel=\"Total\"\n centerValue={stats?.totalRequests ?? 0}\n height={220}\n emptyLabel=\"No requests to summarise yet.\"\n ariaLabel=\"Approval requests by status\"\n />\n </ChartCard>\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between px-1\">\n <h3 className=\"text-sm font-medium text-text-primary\">\n Review discussion\n </h3>\n {reviewTarget && (\n <button\n onClick={() => setReviewTarget(null)}\n title=\"Close thread\"\n className=\"inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs text-text-secondary hover:bg-bg-sunken\"\n >\n <X className=\"h-3.5 w-3.5\" />\n Clear\n </button>\n )}\n </div>\n {reviewTarget ? (\n <>\n <p className=\"px-1 text-xs text-text-secondary\">\n Discussing {reviewTarget.userId} &middot;{\" \"}\n {reviewTarget.period}\n </p>\n <ApprovalReviewThread request={reviewTarget} />\n </>\n ) : (\n <GlassCard\n treatment=\"insight\"\n className=\"border-border-seam p-6\"\n >\n <div className=\"flex flex-col items-center justify-center gap-2 text-center\">\n <MessagesSquare className=\"h-6 w-6 text-text-secondary\" />\n <p className=\"text-sm font-medium text-text-primary\">\n No timesheet selected\n </p>\n <p className=\"text-xs text-text-secondary\">\n Open a request's discussion icon to review it with the\n submitter.\n </p>\n </div>\n </GlassCard>\n )}\n </div>\n </div>\n </div>\n </div>\n\n <Modal\n open={rejectTarget !== null}\n onClose={() => setRejectTarget(null)}\n title=\"Reject timesheet\"\n description={\n rejectTarget\n ? `Rejecting ${rejectTarget.userId}'s ${rejectTarget.period} timesheet.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setRejectTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleReject}\n disabled={rejecting || !rejectReason.trim()}\n className=\"rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50\"\n >\n {rejecting ? \"Rejecting...\" : \"Reject\"}\n </button>\n </>\n }\n >\n <label className=\"block text-sm font-medium text-text-primary\">\n Rejection reason\n </label>\n <textarea\n rows={3}\n placeholder=\"Explain why this timesheet is being rejected\"\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n className={inputClass}\n />\n </Modal>\n\n <Modal\n open={revisionTarget !== null}\n onClose={() => setRevisionTarget(null)}\n title=\"Request revision\"\n description={\n revisionTarget\n ? `Ask ${revisionTarget.userId} to revise their ${revisionTarget.period} timesheet.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setRevisionTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleRequestRevision}\n disabled={requestingRevision || !revisionNotes.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 {requestingRevision ? \"Sending...\" : \"Request Revision\"}\n </button>\n </>\n }\n >\n <label className=\"block text-sm font-medium text-text-primary\">\n What needs changing?\n </label>\n <textarea\n rows={3}\n placeholder=\"Describe the changes needed before this can be approved\"\n value={revisionNotes}\n onChange={(e) => setRevisionNotes(e.target.value)}\n className={inputClass}\n />\n </Modal>\n\n <Modal\n open={withdrawTarget !== null}\n onClose={() => setWithdrawTarget(null)}\n title=\"Withdraw request?\"\n description={\n withdrawTarget\n ? `${withdrawTarget.userId}'s ${withdrawTarget.period} timesheet will be pulled from the review queue.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setWithdrawTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleWithdraw}\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\"\n >\n Withdraw\n </button>\n </>\n }\n >\n <p className=\"text-sm text-text-secondary\">\n Withdrawing removes the request from the approval queue. It can be\n resubmitted later.\n </p>\n </Modal>\n\n <ToastContainer toasts={toasts} onDismiss={dismissToast} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TimeApprovalPage.js","names":[],"sources":["../../../../src/timecampus/pages/time-approval/TimeApprovalPage.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n CheckCircle,\n XCircle,\n X,\n Clock,\n MessageSquare,\n MessagesSquare,\n Undo2,\n} from \"lucide-react\";\nimport { ContextConversationWidget } from \"@burdenoff/fe-libs/shared\";\nimport { useRegisterPageConversationContext } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport { PageLayout } from \"../../components/PageLayout\";\nimport { StatCard } from \"../../components/StatCard\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { LoadingSkeleton } from \"../../components/LoadingSkeleton\";\nimport { StatusBadge } from \"../../components/StatusBadge\";\nimport { Modal } from \"../../components/Modal\";\nimport { ToastContainer, useToast } from \"../../components/Toast\";\nimport { ChartCard, DonutChart, ProgressMeter } from \"../../components\";\nimport { getInitials, formatHours, formatDate, cn } from \"../../utils/helpers\";\nimport {\n useListApprovalRequestsQuery,\n useGetApprovalStatsQuery,\n useApproveRequestMutation,\n useRejectRequestMutation,\n useRequestRevisionMutation,\n useWithdrawRequestMutation,\n type ApprovalRequestFieldsFragment,\n type ListApprovalRequestsQuery,\n} from \"@/generated/wspace-operations\";\nimport { ApprovalStatus } from \"@/generated/wspace-types\";\n\nconst PAGE_SIZE = 25;\n\n// Rendered as a child of the review Modal so the registration hook only runs\n// while the modal is mounted — it scopes the shared page-conversation widget to\n// the selected approval request, then releases the context on close/unmount.\nfunction ApprovalReviewThread({\n request,\n}: {\n request: ApprovalRequestFieldsFragment;\n}) {\n useRegisterPageConversationContext({\n entityType: \"TIMECAMPUS_APPROVAL_REQUEST\",\n entityId: request.id,\n contextTitle: `Approval · ${request.period ?? request.id}`,\n });\n\n return <ContextConversationWidget widgetKey=\"approval-review\" />;\n}\n\nconst inputClass =\n \"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\nexport function TimeApprovalPage() {\n const { toasts, addToast, dismissToast } = useToast();\n\n const {\n data: requestsData,\n loading: requestsLoading,\n error: requestsError,\n refetch,\n fetchMore,\n } = useListApprovalRequestsQuery({\n variables: { pagination: { limit: PAGE_SIZE, offset: 0 } },\n notifyOnNetworkStatusChange: true,\n });\n const {\n data: statsData,\n loading: statsLoading,\n error: statsError,\n refetch: refetchStats,\n } = useGetApprovalStatsQuery();\n\n const [approveRequest] = useApproveRequestMutation();\n const [rejectRequest, { loading: rejecting }] = useRejectRequestMutation();\n const [requestRevision, { loading: requestingRevision }] =\n useRequestRevisionMutation();\n const [withdrawRequest] = useWithdrawRequestMutation();\n\n const requests = requestsData?.approvalRequests?.items ?? [];\n const total = requestsData?.approvalRequests?.total ?? 0;\n const hasMore = requestsData?.approvalRequests?.hasMore ?? false;\n const stats = statsData?.approvalStats;\n\n const approvalMix = [\n { name: \"Pending\", value: stats?.pendingCount ?? 0 },\n { name: \"Approved\", value: stats?.approvedCount ?? 0 },\n { name: \"Rejected\", value: stats?.rejectedCount ?? 0 },\n ];\n\n const [loadingMore, setLoadingMore] = useState(false);\n const [busyId, setBusyId] = useState<string | null>(null);\n\n // Reject reason modal\n const [rejectTarget, setRejectTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n const [rejectReason, setRejectReason] = useState(\"\");\n\n // Request revision modal\n const [revisionTarget, setRevisionTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n const [revisionNotes, setRevisionNotes] = useState(\"\");\n\n // Withdraw confirm modal\n const [withdrawTarget, setWithdrawTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n\n // Review / discussion thread modal\n const [reviewTarget, setReviewTarget] =\n useState<ApprovalRequestFieldsFragment | null>(null);\n\n const refreshAll = async () => {\n await Promise.all([refetch(), refetchStats()]);\n };\n\n const handleApprove = async (id: string) => {\n setBusyId(id);\n try {\n await approveRequest({ variables: { id } });\n addToast({ title: \"Timesheet approved\", variant: \"success\" });\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to approve timesheet\", variant: \"error\" });\n } finally {\n setBusyId(null);\n }\n };\n\n const handleReject = async () => {\n if (!rejectTarget || !rejectReason.trim()) return;\n try {\n await rejectRequest({\n variables: { id: rejectTarget.id, reason: rejectReason.trim() },\n });\n addToast({ title: \"Timesheet rejected\", variant: \"success\" });\n setRejectTarget(null);\n setRejectReason(\"\");\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to reject timesheet\", variant: \"error\" });\n }\n };\n\n const handleRequestRevision = async () => {\n if (!revisionTarget || !revisionNotes.trim()) return;\n try {\n await requestRevision({\n variables: { id: revisionTarget.id, notes: revisionNotes.trim() },\n });\n addToast({ title: \"Revision requested\", variant: \"success\" });\n setRevisionTarget(null);\n setRevisionNotes(\"\");\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to request revision\", variant: \"error\" });\n }\n };\n\n const handleWithdraw = async () => {\n if (!withdrawTarget) return;\n try {\n await withdrawRequest({ variables: { id: withdrawTarget.id } });\n addToast({ title: \"Request withdrawn\", variant: \"success\" });\n setWithdrawTarget(null);\n await refreshAll();\n } catch {\n addToast({ title: \"Failed to withdraw request\", variant: \"error\" });\n }\n };\n\n const handleLoadMore = async () => {\n setLoadingMore(true);\n try {\n await fetchMore({\n variables: {\n pagination: { limit: PAGE_SIZE, offset: requests.length },\n },\n updateQuery: (\n prev: ListApprovalRequestsQuery,\n { fetchMoreResult }: { fetchMoreResult?: ListApprovalRequestsQuery },\n ) => {\n if (!fetchMoreResult) return prev;\n return {\n ...prev,\n approvalRequests: {\n ...fetchMoreResult.approvalRequests,\n items: [\n ...prev.approvalRequests.items,\n ...fetchMoreResult.approvalRequests.items,\n ],\n },\n };\n },\n });\n } finally {\n setLoadingMore(false);\n }\n };\n\n if (requestsLoading && statsLoading && requests.length === 0) {\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n >\n <LoadingSkeleton variant=\"list\" count={4} />\n </PageLayout>\n );\n }\n\n if (requestsError && statsError) {\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n >\n <div className=\"rounded-lg border border-status-error-bg/40 bg-status-error-bg p-4 text-sm text-status-error-text\">\n Failed to load approval data. Please try again later.\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Time Approval\"\n description=\"Review and approve team timesheets\"\n purpose=\"The reviewer's queue for signing off team timesheets before they're billed or paid — approve, reject or request changes in one place so payroll and invoices go out accurate and on time.\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n featured\n title=\"Pending Approvals\"\n value={String(stats?.pendingCount ?? 0)}\n icon={<Clock className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-warning-bg text-status-warning-text\"\n />\n <StatCard\n title=\"Approved This Week\"\n value={String(stats?.approvedCount ?? 0)}\n icon={<CheckCircle className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-success-bg text-status-success-text\"\n />\n <StatCard\n title=\"Rejected\"\n value={String(stats?.rejectedCount ?? 0)}\n icon={<XCircle className=\"h-5 w-5\" />}\n iconBgColor=\"bg-status-error-bg text-status-error-text\"\n />\n <StatCard\n title=\"Avg. Review Time\"\n value={\n stats?.averageReviewTime\n ? `${Math.round(stats.averageReviewTime)}h`\n : \"N/A\"\n }\n description=\"Target: 24h\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"space-y-4 lg:col-span-2\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-sm font-semibold text-text-primary\">\n Pending Requests\n </h2>\n <p className=\"text-xs text-text-secondary\">\n Showing {requests.length} of {total}\n </p>\n </div>\n\n {requests.length === 0 && !requestsLoading ? (\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No approval requests found\"\n description=\"You're all caught up — submitted timesheets waiting on your review will appear here.\"\n />\n ) : (\n <>\n <div className=\"space-y-3\">\n {requests.map((request: ApprovalRequestFieldsFragment) => {\n const isPending = request.status === ApprovalStatus.Pending;\n const rowBusy = busyId === request.id;\n const selected = reviewTarget?.id === request.id;\n const billablePct =\n request.totalHours > 0\n ? Math.round(\n (request.billableHours / request.totalHours) * 100,\n )\n : 0;\n return (\n <GlassCard\n key={request.id}\n treatment=\"plain\"\n glow={selected}\n className={cn(\n \"p-4\",\n selected && \"border-action-primary-bg/50\",\n )}\n >\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/10 text-sm font-medium text-primary\">\n {getInitials(request.userId)}\n </div>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {request.userId}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {request.period} &middot; Submitted{\" \"}\n {formatDate(request.submittedAt)}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-5\">\n <div className=\"flex items-center gap-6\">\n <div>\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n Total submitted\n </p>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatHours(request.totalHours)}\n </p>\n </div>\n <div>\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n Billable\n </p>\n <p className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {formatHours(request.billableHours)}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge\n label={request.status.toLowerCase()}\n status={request.status.toLowerCase()}\n />\n {isPending && (\n <>\n <button\n onClick={() => handleApprove(request.id)}\n disabled={rowBusy}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-status-success-bg px-3 py-1.5 text-sm font-medium text-status-success-text hover:bg-status-success-bg/80 disabled:opacity-50\"\n >\n <CheckCircle className=\"h-4 w-4\" />\n Approve\n </button>\n <button\n onClick={() => {\n setRejectTarget(request);\n setRejectReason(\"\");\n }}\n disabled={rowBusy}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-status-error-bg px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50\"\n >\n <XCircle className=\"h-4 w-4\" />\n Reject\n </button>\n <button\n onClick={() => {\n setRevisionTarget(request);\n setRevisionNotes(\"\");\n }}\n disabled={rowBusy}\n title=\"Request revision\"\n className=\"rounded-md border border-border-seam bg-bg-surface p-1.5 text-status-warning-text hover:bg-status-warning-bg disabled:opacity-50\"\n >\n <MessageSquare className=\"h-4 w-4\" />\n </button>\n <button\n onClick={() => setWithdrawTarget(request)}\n disabled={rowBusy}\n title=\"Withdraw request\"\n className=\"rounded-md border border-border-seam bg-bg-surface p-1.5 text-text-secondary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Undo2 className=\"h-4 w-4\" />\n </button>\n </>\n )}\n <button\n onClick={() =>\n setReviewTarget(selected ? null : request)\n }\n title=\"Review / Discussion\"\n className={cn(\n \"rounded-md border p-1.5\",\n selected\n ? \"border-action-primary-bg bg-action-primary-bg/10 text-primary\"\n : \"border-border-seam bg-bg-surface text-text-secondary hover:bg-bg-sunken\",\n )}\n >\n <MessagesSquare className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {request.totalHours > 0 && (\n <div className=\"mt-4\">\n <ProgressMeter\n value={billablePct}\n max={100}\n tone=\"success\"\n size=\"sm\"\n showValue={false}\n label={`Billable share · ${billablePct}%`}\n />\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n\n {hasMore && (\n <div className=\"flex justify-center\">\n <button\n onClick={handleLoadMore}\n disabled={loadingMore}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50 disabled:opacity-50\"\n >\n {loadingMore ? \"Loading...\" : \"Load more\"}\n </button>\n </div>\n )}\n </>\n )}\n </div>\n\n <div className=\"lg:col-span-1\">\n <div className=\"space-y-4 lg:sticky lg:top-4\">\n <ChartCard\n title=\"Approval mix\"\n description=\"Requests by current status\"\n >\n <DonutChart\n data={approvalMix}\n centerLabel=\"Total\"\n centerValue={stats?.totalRequests ?? 0}\n height={220}\n emptyLabel=\"No requests to summarise yet.\"\n ariaLabel=\"Approval requests by status\"\n />\n </ChartCard>\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between px-1\">\n <h3 className=\"text-sm font-medium text-text-primary\">\n Review discussion\n </h3>\n {reviewTarget && (\n <button\n onClick={() => setReviewTarget(null)}\n title=\"Close thread\"\n className=\"inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs text-text-secondary hover:bg-bg-sunken\"\n >\n <X className=\"h-3.5 w-3.5\" />\n Clear\n </button>\n )}\n </div>\n {reviewTarget ? (\n <>\n <p className=\"px-1 text-xs text-text-secondary\">\n Discussing {reviewTarget.userId} &middot;{\" \"}\n {reviewTarget.period}\n </p>\n <ApprovalReviewThread request={reviewTarget} />\n </>\n ) : (\n <GlassCard\n treatment=\"insight\"\n className=\"border-border-seam p-6\"\n >\n <div className=\"flex flex-col items-center justify-center gap-2 text-center\">\n <MessagesSquare className=\"h-6 w-6 text-text-secondary\" />\n <p className=\"text-sm font-medium text-text-primary\">\n No timesheet selected\n </p>\n <p className=\"text-xs text-text-secondary\">\n Open a request's discussion icon to review it with the\n submitter.\n </p>\n </div>\n </GlassCard>\n )}\n </div>\n </div>\n </div>\n </div>\n\n <Modal\n open={rejectTarget !== null}\n onClose={() => setRejectTarget(null)}\n title=\"Reject timesheet\"\n description={\n rejectTarget\n ? `Rejecting ${rejectTarget.userId}'s ${rejectTarget.period} timesheet.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setRejectTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleReject}\n disabled={rejecting || !rejectReason.trim()}\n className=\"rounded-md bg-status-error-bg px-4 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg/80 disabled:opacity-50\"\n >\n {rejecting ? \"Rejecting...\" : \"Reject\"}\n </button>\n </>\n }\n >\n <label className=\"block text-sm font-medium text-text-primary\">\n Rejection reason\n </label>\n <textarea\n rows={3}\n placeholder=\"Explain why this timesheet is being rejected\"\n value={rejectReason}\n onChange={(e) => setRejectReason(e.target.value)}\n className={inputClass}\n />\n </Modal>\n\n <Modal\n open={revisionTarget !== null}\n onClose={() => setRevisionTarget(null)}\n title=\"Request revision\"\n description={\n revisionTarget\n ? `Ask ${revisionTarget.userId} to revise their ${revisionTarget.period} timesheet.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setRevisionTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleRequestRevision}\n disabled={requestingRevision || !revisionNotes.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 {requestingRevision ? \"Sending...\" : \"Request Revision\"}\n </button>\n </>\n }\n >\n <label className=\"block text-sm font-medium text-text-primary\">\n What needs changing?\n </label>\n <textarea\n rows={3}\n placeholder=\"Describe the changes needed before this can be approved\"\n value={revisionNotes}\n onChange={(e) => setRevisionNotes(e.target.value)}\n className={inputClass}\n />\n </Modal>\n\n <Modal\n open={withdrawTarget !== null}\n onClose={() => setWithdrawTarget(null)}\n title=\"Withdraw request?\"\n description={\n withdrawTarget\n ? `${withdrawTarget.userId}'s ${withdrawTarget.period} timesheet will be pulled from the review queue.`\n : undefined\n }\n size=\"sm\"\n footer={\n <>\n <button\n onClick={() => setWithdrawTarget(null)}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken/50\"\n >\n Cancel\n </button>\n <button\n onClick={handleWithdraw}\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\"\n >\n Withdraw\n </button>\n </>\n }\n >\n <p className=\"text-sm text-text-secondary\">\n Withdrawing removes the request from the approval queue. It can be\n resubmitted later.\n </p>\n </Modal>\n\n <ToastContainer toasts={toasts} onDismiss={dismissToast} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -2,9 +2,9 @@ import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
2
  import { formatDuration as t, formatTime as n } from "../../utils/helpers.js";
3
3
  import { StatCard as r } from "../../components/StatCard.js";
4
4
  import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
5
- import { useGetTimeCampusTimelineQuery as a, useListProjectsQuery as o, useRecategorizeTimeCampusCaptureEventMutation as s } from "../../../generated/wspace-operations.js";
6
- import { PageLayout as c } from "../../components/PageLayout.js";
7
- import { EmptyState as l } from "../../components/EmptyState.js";
5
+ import { EmptyState as a } from "../../components/EmptyState.js";
6
+ import { useGetTimeCampusTimelineQuery as o, useListProjectsQuery as s, useRecategorizeTimeCampusCaptureEventMutation as c } from "../../../generated/wspace-operations.js";
7
+ import { PageLayout as l } from "../../components/PageLayout.js";
8
8
  import { useMemo as u, useState as d } from "react";
9
9
  import { Activity as f, Brain as p, Calendar as m, Coffee as h, FolderOpen as g, Github as _, GripVertical as v, MessageSquare as y, Users as b, Zap as x } from "lucide-react";
10
10
  import { jsx as S, jsxs as C } from "react/jsx-runtime";
@@ -172,17 +172,17 @@ function V(e) {
172
172
  };
173
173
  }
174
174
  function H() {
175
- let { workspaceId: h = "" } = e(), [g, _] = d(() => B(/* @__PURE__ */ new Date())), [y, b] = d(null), { from: k, to: A } = u(() => V(g), [g]), { data: P, loading: I, error: L, refetch: H } = a({
175
+ let { workspaceId: h = "" } = e(), [g, _] = d(() => B(/* @__PURE__ */ new Date())), [y, b] = d(null), { from: k, to: A } = u(() => V(g), [g]), { data: P, loading: I, error: L, refetch: H } = o({
176
176
  variables: {
177
177
  from: k,
178
178
  to: A
179
179
  },
180
180
  skip: !h,
181
181
  fetchPolicy: "cache-and-network"
182
- }), { data: U } = o({
182
+ }), { data: U } = s({
183
183
  variables: { pagination: { limit: 200 } },
184
184
  skip: !h
185
- }), [W, { loading: G }] = s(), K = M(j(O, { activationConstraint: { distance: 6 } }), j(D)), q = P?.timeCampusTimeline, J = q?.segments ?? [], Y = q?.summary, X = u(() => {
185
+ }), [W, { loading: G }] = c(), K = M(j(O, { activationConstraint: { distance: 6 } }), j(D)), q = P?.timeCampusTimeline, J = q?.segments ?? [], Y = q?.summary, X = u(() => {
186
186
  let e = /* @__PURE__ */ new Map();
187
187
  for (let t of U?.projects?.items ?? []) e.set(t.id, t.name);
188
188
  return e;
@@ -209,7 +209,7 @@ function H() {
209
209
  let r = n.replace(/^category:/, "");
210
210
  F.includes(r) && Q(t, r);
211
211
  }, ne = Y && Y.focusRatio != null ? Math.round(Y.focusRatio * 100) : 0, $ = Y?.firstActivityAt && Y?.lastActivityAt ? `${n(Y.firstActivityAt)} – ${n(Y.lastActivityAt)}` : null;
212
- return /* @__PURE__ */ S(c, {
212
+ return /* @__PURE__ */ S(l, {
213
213
  title: "Timeline",
214
214
  description: "Your day, assembled automatically",
215
215
  purpose: "See where your time actually went — meetings, deep work, communication and breaks stitched into one honest, chronological view from everything TimeCampus captures, so you can spot the patterns worth changing.",
@@ -304,7 +304,7 @@ function H() {
304
304
  })
305
305
  ]
306
306
  }),
307
- J.length === 0 ? /* @__PURE__ */ S(l, {
307
+ J.length === 0 ? /* @__PURE__ */ S(a, {
308
308
  illustration: "empty-generic",
309
309
  title: "No activity captured for this day",
310
310
  description: "As you track time, hold meetings, run focus sessions, and connect shared integrations, your day assembles here automatically — categorized and in order."
@@ -1,20 +1,20 @@
1
1
  import { useTimeCampus as e } from "../../providers/TimeCampusProvider.js";
2
2
  import { StatCard as t } from "../../components/StatCard.js";
3
3
  import { LoadingSkeleton as n } from "../../components/LoadingSkeleton.js";
4
- import { useGetWorkPatternSummaryQuery as r, useListWorkPatternsQuery as ee } from "../../../generated/wspace-operations.js";
5
- import { PageLayout as i } from "../../components/PageLayout.js";
6
- import { StatusBadge as a } from "../../components/StatusBadge.js";
7
- import { EmptyState as o } from "../../components/EmptyState.js";
4
+ import { EmptyState as r } from "../../components/EmptyState.js";
5
+ import { useGetWorkPatternSummaryQuery as i, useListWorkPatternsQuery as ee } from "../../../generated/wspace-operations.js";
6
+ import { PageLayout as a } from "../../components/PageLayout.js";
7
+ import { StatusBadge as o } from "../../components/StatusBadge.js";
8
8
  import { ChartCard as s } from "../../components/ChartCard.js";
9
- import { TrendChart as c } from "../../components/charts/TrendChart.js";
10
- import { Heatmap as l } from "../../components/charts/Heatmap.js";
9
+ import { TrendChart as te } from "../../components/charts/TrendChart.js";
10
+ import { Heatmap as c } from "../../components/charts/Heatmap.js";
11
11
  import "../../components/index.js";
12
- import { WorkPatternInsightType as u } from "../../../generated/wspace-types.js";
13
- import { AlertTriangle as d, ArrowRight as f, Brain as te, Clock as ne, Lightbulb as p, ShieldCheck as m, TrendingUp as h, Zap as g } from "lucide-react";
14
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
15
- import { GlassCard as y } from "@burdenoff/fe-libs/ui";
12
+ import { WorkPatternInsightType as l } from "../../../generated/wspace-types.js";
13
+ import { AlertTriangle as u, ArrowRight as d, Brain as f, Clock as p, Lightbulb as m, ShieldCheck as h, TrendingUp as ne, Zap as re } from "lucide-react";
14
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
15
+ import { GlassCard as v } from "@burdenoff/fe-libs/ui";
16
16
  //#region src/timecampus/pages/work-patterns/WorkPatternsPage.tsx
17
- var b = [
17
+ var y = [
18
18
  "Mon",
19
19
  "Tue",
20
20
  "Wed",
@@ -23,21 +23,21 @@ var b = [
23
23
  "Sat",
24
24
  "Sun"
25
25
  ];
26
- function x(e) {
26
+ function b(e) {
27
27
  return (e.getDay() + 6) % 7;
28
28
  }
29
- function S(e) {
29
+ function x(e) {
30
30
  let t = new Date(e);
31
- return t.setDate(e.getDate() - x(e)), t.setHours(0, 0, 0, 0), t;
31
+ return t.setDate(e.getDate() - b(e)), t.setHours(0, 0, 0, 0), t;
32
32
  }
33
- function C(e) {
33
+ function S(e) {
34
34
  let t = new Date(e);
35
35
  return Number.isNaN(t.getTime()) ? "" : t.toLocaleDateString(void 0, {
36
36
  month: "short",
37
37
  day: "numeric"
38
38
  });
39
39
  }
40
- var re = {
40
+ var C = {
41
41
  VERY_LOW: 1,
42
42
  LOW: 2,
43
43
  MEDIUM: 3,
@@ -50,144 +50,144 @@ var re = {
50
50
  POSITIVE: 4,
51
51
  VERY_POSITIVE: 5
52
52
  }, ae = /* @__PURE__ */ new Set(["HIGH", "VERY_HIGH"]), oe = /* @__PURE__ */ new Set(["LOW", "VERY_LOW"]), se = (e) => `${e.toFixed(1)}h`, ce = {
53
- [u.Positive]: "success",
54
- [u.Negative]: "error",
55
- [u.Warning]: "warning",
56
- [u.Recommendation]: "info",
57
- [u.Neutral]: "muted"
53
+ [l.Positive]: "success",
54
+ [l.Negative]: "error",
55
+ [l.Warning]: "warning",
56
+ [l.Recommendation]: "info",
57
+ [l.Neutral]: "muted"
58
58
  }, le = {
59
- [u.Positive]: "Positive",
60
- [u.Negative]: "Negative",
61
- [u.Warning]: "Warning",
62
- [u.Recommendation]: "Tip",
63
- [u.Neutral]: "Neutral"
59
+ [l.Positive]: "Positive",
60
+ [l.Negative]: "Negative",
61
+ [l.Warning]: "Warning",
62
+ [l.Recommendation]: "Tip",
63
+ [l.Neutral]: "Neutral"
64
64
  };
65
65
  function w() {
66
66
  let { workspaceId: w = "" } = e(), { data: ue, loading: T, error: E } = ee({
67
67
  variables: { pagination: { limit: 30 } },
68
68
  skip: !w
69
- }), { data: D, loading: O, error: k } = r({ skip: !w }), A = T || O, j = E || k, M = D?.workPatternSummary, N = ue?.workPatterns ?? [], P = M?.insights ?? [], F = [...N].sort((e, t) => {
69
+ }), { data: D, loading: O, error: k } = i({ skip: !w }), A = T || O, j = E || k, M = D?.workPatternSummary, N = ue?.workPatterns ?? [], P = M?.insights ?? [], F = [...N].sort((e, t) => {
70
70
  let n = new Date(e.date).getTime(), r = new Date(t.date).getTime();
71
71
  return (Number.isNaN(n) ? 0 : n) - (Number.isNaN(r) ? 0 : r);
72
72
  }), I = N[0], L = M?.averageProductivity == null ? "--" : `${Math.round(M.averageProductivity)}%`, R = I?.focusHours == null ? "--" : `${I.focusHours.toFixed(1)}h`, z = I ? (I.focusHours + I.meetingHours + I.breakHours).toFixed(0) : "8", B = I?.deepWorkSessions == null ? "--" : String(I.deepWorkSessions), de = M?.mostProductiveDay ?? "--", V = [];
73
73
  for (let e of F) {
74
74
  let t = new Date(e.date);
75
75
  if (Number.isNaN(t.getTime())) continue;
76
- let n = S(t).getTime();
76
+ let n = x(t).getTime();
77
77
  V.includes(n) || V.push(n);
78
78
  }
79
- let H = V.slice(-6), fe = H.map((e) => C(new Date(e).toISOString())), U = b.map(() => H.map(() => null));
79
+ let H = V.slice(-6), fe = H.map((e) => S(new Date(e).toISOString())), U = y.map(() => H.map(() => null));
80
80
  for (let e of F) {
81
81
  let t = new Date(e.date);
82
82
  if (Number.isNaN(t.getTime())) continue;
83
- let n = H.indexOf(S(t).getTime());
84
- n < 0 || (U[x(t)][n] = e.focusHours);
83
+ let n = H.indexOf(x(t).getTime());
84
+ n < 0 || (U[b(t)][n] = e.focusHours);
85
85
  }
86
86
  let W = F.map((e) => ({
87
- date: C(e.date),
88
- energy: e.energyLevel == null ? null : re[e.energyLevel] ?? null,
87
+ date: S(e.date),
88
+ energy: e.energyLevel == null ? null : C[e.energyLevel] ?? null,
89
89
  mood: e.mood == null ? null : ie[e.mood] ?? null
90
- })), pe = W.some((e) => e.energy != null || e.mood != null), G = N.slice(0, 7), K = G.length, q = G.filter((e) => e.stressLevel != null && ae.has(e.stressLevel)).length, J = G.filter((e) => e.energyLevel != null && oe.has(e.energyLevel)).length, Y = P.find((e) => e.type === u.Warning || e.type === u.Negative), X = Math.ceil(Math.max(K, 1) / 2), Z = "success";
91
- K > 0 && q >= X ? Z = "danger" : (q > 0 || J >= X || Y) && (Z = "warning"), Y?.type === u.Negative && (Z = "danger");
90
+ })), pe = W.some((e) => e.energy != null || e.mood != null), G = N.slice(0, 7), K = G.length, q = G.filter((e) => e.stressLevel != null && ae.has(e.stressLevel)).length, J = G.filter((e) => e.energyLevel != null && oe.has(e.energyLevel)).length, Y = P.find((e) => e.type === l.Warning || e.type === l.Negative), X = Math.ceil(Math.max(K, 1) / 2), Z = "success";
91
+ K > 0 && q >= X ? Z = "danger" : (q > 0 || J >= X || Y) && (Z = "warning"), Y?.type === l.Negative && (Z = "danger");
92
92
  let Q = [];
93
93
  q > 0 && Q.push(`${q} of your last ${K} logged day${K === 1 ? "" : "s"} showed high stress`), J > 0 && Q.push(`${J} showed low energy`);
94
94
  let me = Y?.title ?? (Z === "danger" ? "Sustained overload detected" : Z === "warning" ? "Watch your workload" : "Balanced workload"), he = Y?.description ?? (Z === "success" ? "Your recent stress and energy levels look healthy — keep protecting your focus blocks." : Q.length > 0 ? `${Q.join(" and ")}. Protect your deep-work time before it erodes.` : "Recent signals suggest an uneven balance — schedule focus time to stay ahead of overload."), $ = Y?.recommendation ?? null, ge = Z === "danger" ? "bg-status-error-bg text-status-error-text" : Z === "warning" ? "bg-status-warning-bg text-status-warning-text" : "bg-status-success-bg text-status-success-text";
95
- return A ? /* @__PURE__ */ _(i, {
95
+ return A ? /* @__PURE__ */ g(a, {
96
96
  title: "Work Patterns",
97
97
  description: "Analyze your work habits and productivity patterns",
98
- children: /* @__PURE__ */ _(n, {
98
+ children: /* @__PURE__ */ g(n, {
99
99
  variant: "card",
100
100
  count: 4
101
101
  })
102
- }) : j ? /* @__PURE__ */ _(i, {
102
+ }) : j ? /* @__PURE__ */ g(a, {
103
103
  title: "Work Patterns",
104
104
  description: "Analyze your work habits and productivity patterns",
105
- children: /* @__PURE__ */ _("div", {
105
+ children: /* @__PURE__ */ g("div", {
106
106
  className: "rounded-xl border border-status-error-border/50 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
107
107
  children: "Failed to load work patterns. Please try again later."
108
108
  })
109
- }) : /* @__PURE__ */ _(i, {
109
+ }) : /* @__PURE__ */ g(a, {
110
110
  title: "Work Patterns",
111
111
  description: "Analyze your work habits and productivity patterns",
112
112
  purpose: "Learn how you actually work across a typical week — when you focus best, where meetings pile up, and which day is your peak — so you can schedule deep work for the hours you're sharpest.",
113
- children: /* @__PURE__ */ v("div", {
113
+ children: /* @__PURE__ */ _("div", {
114
114
  className: "space-y-6",
115
115
  children: [
116
- /* @__PURE__ */ v("div", {
116
+ /* @__PURE__ */ _("div", {
117
117
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
118
118
  children: [
119
- /* @__PURE__ */ _(t, {
119
+ /* @__PURE__ */ g(t, {
120
120
  featured: !0,
121
121
  title: "Productivity Score",
122
122
  value: L,
123
- icon: /* @__PURE__ */ _(h, { className: "h-5 w-5" }),
123
+ icon: /* @__PURE__ */ g(ne, { className: "h-5 w-5" }),
124
124
  trend: M?.averageProductivity == null ? void 0 : {
125
125
  value: 5,
126
126
  label: "vs last week"
127
127
  }
128
128
  }),
129
- /* @__PURE__ */ _(t, {
129
+ /* @__PURE__ */ g(t, {
130
130
  title: "Focus Hours",
131
131
  value: R,
132
- icon: /* @__PURE__ */ _(te, { className: "h-5 w-5" }),
132
+ icon: /* @__PURE__ */ g(f, { className: "h-5 w-5" }),
133
133
  description: `Out of ${z}h total`
134
134
  }),
135
- /* @__PURE__ */ _(t, {
135
+ /* @__PURE__ */ g(t, {
136
136
  title: "Peak Day",
137
137
  value: de,
138
- icon: /* @__PURE__ */ _(g, { className: "h-5 w-5" }),
138
+ icon: /* @__PURE__ */ g(re, { className: "h-5 w-5" }),
139
139
  description: "Most productive day"
140
140
  }),
141
- /* @__PURE__ */ _(t, {
141
+ /* @__PURE__ */ g(t, {
142
142
  title: "Deep Work",
143
143
  value: `${B} sessions`,
144
- icon: /* @__PURE__ */ _(ne, { className: "h-5 w-5" }),
144
+ icon: /* @__PURE__ */ g(p, { className: "h-5 w-5" }),
145
145
  description: "90+ min uninterrupted"
146
146
  })
147
147
  ]
148
148
  }),
149
- /* @__PURE__ */ _(y, {
149
+ /* @__PURE__ */ g(v, {
150
150
  treatment: "glass",
151
151
  glow: Z !== "success",
152
152
  className: "p-5 sm:p-6",
153
- children: /* @__PURE__ */ v("div", {
153
+ children: /* @__PURE__ */ _("div", {
154
154
  className: "flex flex-col gap-4 sm:flex-row sm:items-start",
155
- children: [/* @__PURE__ */ _("div", {
155
+ children: [/* @__PURE__ */ g("div", {
156
156
  className: `flex h-11 w-11 shrink-0 items-center justify-center rounded-xl ${ge}`,
157
- children: _(Z === "success" ? m : d, { className: "h-5 w-5" })
158
- }), /* @__PURE__ */ v("div", {
157
+ children: g(Z === "success" ? h : u, { className: "h-5 w-5" })
158
+ }), /* @__PURE__ */ _("div", {
159
159
  className: "min-w-0 flex-1",
160
160
  children: [
161
- /* @__PURE__ */ v("div", {
161
+ /* @__PURE__ */ _("div", {
162
162
  className: "flex flex-wrap items-center gap-2",
163
- children: [/* @__PURE__ */ _("h3", {
163
+ children: [/* @__PURE__ */ g("h3", {
164
164
  className: "text-base font-semibold text-text-primary",
165
165
  children: "Burnout Signal"
166
- }), /* @__PURE__ */ _(a, {
166
+ }), /* @__PURE__ */ g(o, {
167
167
  variant: Z === "danger" ? "error" : Z === "warning" ? "warning" : "success",
168
168
  label: me
169
169
  })]
170
170
  }),
171
- /* @__PURE__ */ _("p", {
171
+ /* @__PURE__ */ g("p", {
172
172
  className: "mt-1.5 text-sm text-text-secondary",
173
173
  children: he
174
174
  }),
175
- $ && /* @__PURE__ */ v("p", {
175
+ $ && /* @__PURE__ */ _("p", {
176
176
  className: "mt-2 flex items-start gap-1.5 text-sm text-text-primary",
177
- children: [/* @__PURE__ */ _(p, { className: "mt-0.5 h-4 w-4 shrink-0 text-primary" }), /* @__PURE__ */ _("span", { children: $ })]
177
+ children: [/* @__PURE__ */ g(m, { className: "mt-0.5 h-4 w-4 shrink-0 text-primary" }), /* @__PURE__ */ g("span", { children: $ })]
178
178
  })
179
179
  ]
180
180
  })]
181
181
  })
182
182
  }),
183
- /* @__PURE__ */ v("div", {
183
+ /* @__PURE__ */ _("div", {
184
184
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
185
- children: [/* @__PURE__ */ _(s, {
185
+ children: [/* @__PURE__ */ g(s, {
186
186
  title: "Weekly Productive Hours",
187
187
  description: "Focused hours logged by weekday across recent weeks",
188
- children: /* @__PURE__ */ _(l, {
188
+ children: /* @__PURE__ */ g(c, {
189
189
  data: U,
190
- rowLabels: [...b],
190
+ rowLabels: [...y],
191
191
  columnLabels: fe,
192
192
  rowsLabel: "Day",
193
193
  valueFormat: se,
@@ -196,10 +196,10 @@ function w() {
196
196
  emptyLabel: "No work-pattern days logged yet.",
197
197
  ariaLabel: "Focused hours by weekday and week"
198
198
  })
199
- }), /* @__PURE__ */ _(s, {
199
+ }), /* @__PURE__ */ g(s, {
200
200
  title: "Energy & Mood Trends",
201
201
  description: "Self-reported energy and mood, each on a 1 (low) – 5 (high) scale",
202
- children: pe ? /* @__PURE__ */ _(c, {
202
+ children: pe ? /* @__PURE__ */ g(te, {
203
203
  data: W,
204
204
  xKey: "date",
205
205
  series: [{
@@ -213,40 +213,40 @@ function w() {
213
213
  height: 240,
214
214
  emptyLabel: "No energy or mood check-ins yet.",
215
215
  ariaLabel: "Energy and mood over time"
216
- }) : /* @__PURE__ */ _(o, {
216
+ }) : /* @__PURE__ */ g(r, {
217
217
  title: "No energy or mood data yet",
218
218
  description: "Log how you feel on your work-pattern entries to see the trend here."
219
219
  })
220
220
  })]
221
221
  }),
222
- P.length > 0 && /* @__PURE__ */ v(y, {
222
+ P.length > 0 && /* @__PURE__ */ _(v, {
223
223
  treatment: "glass",
224
224
  className: "p-5 sm:p-6",
225
- children: [/* @__PURE__ */ v("h3", {
225
+ children: [/* @__PURE__ */ _("h3", {
226
226
  className: "mb-4 flex items-center gap-2 text-sm font-semibold text-text-primary",
227
- children: [/* @__PURE__ */ _(p, { className: "h-4 w-4 text-primary" }), "Insights"]
228
- }), /* @__PURE__ */ _("div", {
227
+ children: [/* @__PURE__ */ g(m, { className: "h-4 w-4 text-primary" }), "Insights"]
228
+ }), /* @__PURE__ */ g("div", {
229
229
  className: "space-y-3",
230
- children: P.map((e, t) => /* @__PURE__ */ v("div", {
230
+ children: P.map((e, t) => /* @__PURE__ */ _("div", {
231
231
  className: "rounded-lg border border-border-subtle bg-bg-surface/40 p-4",
232
232
  children: [
233
- /* @__PURE__ */ v("div", {
233
+ /* @__PURE__ */ _("div", {
234
234
  className: "flex flex-wrap items-center gap-2",
235
- children: [/* @__PURE__ */ _(a, {
235
+ children: [/* @__PURE__ */ g(o, {
236
236
  variant: ce[e.type],
237
237
  label: le[e.type]
238
- }), /* @__PURE__ */ _("p", {
238
+ }), /* @__PURE__ */ g("p", {
239
239
  className: "text-sm font-medium text-text-primary",
240
240
  children: e.title
241
241
  })]
242
242
  }),
243
- /* @__PURE__ */ _("p", {
243
+ /* @__PURE__ */ g("p", {
244
244
  className: "mt-1.5 text-sm text-text-secondary",
245
245
  children: e.description
246
246
  }),
247
- e.recommendation && /* @__PURE__ */ v("p", {
247
+ e.recommendation && /* @__PURE__ */ _("p", {
248
248
  className: "mt-2 flex items-start gap-1.5 text-xs text-text-primary",
249
- children: [/* @__PURE__ */ _(f, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-primary" }), /* @__PURE__ */ _("span", { children: e.recommendation })]
249
+ children: [/* @__PURE__ */ g(d, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-primary" }), /* @__PURE__ */ g("span", { children: e.recommendation })]
250
250
  })
251
251
  ]
252
252
  }, `${e.type}-${t}`))