@elevasis/ui 2.10.2 → 2.12.0

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 (46) hide show
  1. package/dist/app/index.js +2 -2
  2. package/dist/{chunk-YQLE5HR5.js → chunk-235RO24Z.js} +2 -2
  3. package/dist/chunk-3ZMAGTWF.js +18 -0
  4. package/dist/{chunk-AT5XCBTU.js → chunk-7PLBPEBW.js} +2 -2
  5. package/dist/chunk-BRXELOHC.js +47 -0
  6. package/dist/{chunk-KYOF6NYW.js → chunk-ETWKPFOO.js} +1 -1
  7. package/dist/{chunk-M6ZZ2FW5.js → chunk-F6SMVMFC.js} +3 -3
  8. package/dist/{chunk-GJVGV7QZ.js → chunk-GHCYUZZE.js} +276 -5
  9. package/dist/{chunk-XA34RETF.js → chunk-GHIPBT5V.js} +1 -14
  10. package/dist/{chunk-TSX4I3NW.js → chunk-ISVFJCPP.js} +1 -1
  11. package/dist/{chunk-WHQXDETX.js → chunk-MISBW6WW.js} +124 -5
  12. package/dist/{chunk-LPSBID5V.js → chunk-PXFV47B3.js} +1 -1
  13. package/dist/{chunk-CLXMNMIS.js → chunk-TXZXMTZB.js} +652 -110
  14. package/dist/{chunk-6PNHW4X2.js → chunk-TYWZABTP.js} +115 -137
  15. package/dist/{chunk-E3IFHX6A.js → chunk-WM7JTTPX.js} +494 -311
  16. package/dist/{chunk-CYT4PORT.js → chunk-ZKCQEHEJ.js} +7 -51
  17. package/dist/components/index.d.ts +241 -3
  18. package/dist/components/index.js +20 -18
  19. package/dist/execution/index.js +2 -1
  20. package/dist/features/auth/index.d.ts +85 -0
  21. package/dist/features/crm/index.d.ts +94 -2
  22. package/dist/features/crm/index.js +6 -4
  23. package/dist/features/dashboard/index.js +7 -5
  24. package/dist/features/delivery/index.d.ts +132 -13
  25. package/dist/features/delivery/index.js +6 -4
  26. package/dist/features/lead-gen/index.js +10 -8
  27. package/dist/features/monitoring/index.js +8 -6
  28. package/dist/features/operations/index.js +9 -7
  29. package/dist/features/settings/index.d.ts +85 -0
  30. package/dist/features/settings/index.js +7 -5
  31. package/dist/hooks/index.d.ts +426 -52
  32. package/dist/hooks/index.js +5 -3
  33. package/dist/hooks/published.d.ts +426 -52
  34. package/dist/hooks/published.js +5 -3
  35. package/dist/index.d.ts +387 -23
  36. package/dist/index.js +7 -5
  37. package/dist/initialization/index.d.ts +85 -0
  38. package/dist/profile/index.d.ts +85 -0
  39. package/dist/provider/index.js +2 -2
  40. package/dist/supabase/index.d.ts +166 -0
  41. package/dist/supabase/index.js +2 -47
  42. package/dist/theme/index.js +2 -2
  43. package/dist/types/index.d.ts +86 -1
  44. package/dist/zustand/index.d.ts +0 -4
  45. package/dist/zustand/index.js +0 -10
  46. package/package.json +4 -4
@@ -5,16 +5,198 @@ import { SubshellNavItem } from './chunk-CEWTOKE7.js';
5
5
  import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
6
6
  import { FilterBar } from './chunk-PDHTXPSF.js';
7
7
  import { CustomModal } from './chunk-GBMNCNHX.js';
8
- import { useProjects, useDeleteProject, useTableSort, sortData, usePaginationState, useTableSelection, useProject, useProjectNotes, useUpdateMilestone, useCreateNote } from './chunk-E3IFHX6A.js';
8
+ import { useCreateTask, useCreateMilestone, useProjectMilestones, useUpdateTask, useProjects, useDeleteProject, useTableSort, sortData, usePaginationState, useTableSelection, useProjectRealtime, useProject, useProjectTasks, useProjectNotes, useUpdateMilestone, useProjectActivities, useCreateNote, showApiErrorNotification, projectKeys } from './chunk-WM7JTTPX.js';
9
9
  import { SubshellContentContainer } from './chunk-RX4UWZZR.js';
10
10
  import { StatusBadge, EmptyState, PageTitleCaption, CenteredErrorState, StatCard } from './chunk-SQQGLGHW.js';
11
- import { PAGE_SIZE_DEFAULT, formatTimeAgo, formatDate } from './chunk-IOKL7BKE.js';
11
+ import { PAGE_SIZE_DEFAULT, formatTimeAgo, formatDate, formatRelativeTime } from './chunk-IOKL7BKE.js';
12
+ import { useElevasisServices } from './chunk-QEPXAWE2.js';
12
13
  import { useRouterContext } from './chunk-Q7DJKLEN.js';
13
- import { SimpleGrid, Card, Stack, Group, ThemeIcon, Text, RingProgress, Paper, Timeline, Badge, Collapse, ActionIcon, Select, TextInput, Center, Loader, Table, Checkbox, Pagination, Title, Button, Alert, CopyButton, Tooltip, Divider, Tabs, Textarea } from '@mantine/core';
14
- import { IconNotes, IconBriefcase, IconChecklist, IconFlag, IconHeartbeat, IconFileText, IconCalendar, IconInbox, IconLock, IconAlertTriangle, IconCircleCheck, IconClock, IconChevronDown, IconChevronRight, IconDownload, IconListCheck, IconMessageCircle, IconSearch, IconArrowLeft, IconCheck, IconCopy, IconPlus, IconX } from '@tabler/icons-react';
14
+ import { useState, useMemo, useCallback } from 'react';
15
+ import { Stack, Text, Group, Checkbox, ActionIcon, TextInput, Button, Modal, Title, Textarea, Select, SimpleGrid, Card, ThemeIcon, RingProgress, Paper, Timeline, Badge, Collapse, Center, Loader, Table, Pagination, Alert, CopyButton, Tooltip, Divider, Tabs, Anchor, Chip } from '@mantine/core';
16
+ import { IconNotes, IconBriefcase, IconChecklist, IconFlag, IconX, IconPlus, IconHeartbeat, IconFileText, IconCalendar, IconInbox, IconLock, IconAlertTriangle, IconCircleCheck, IconClock, IconChevronDown, IconChevronRight, IconDownload, IconListCheck, IconMessageCircle, IconSearch, IconArrowLeft, IconCheck, IconCopy, IconTerminal2, IconCurrencyDollar, IconBuilding } from '@tabler/icons-react';
15
17
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
16
- import { useState, useMemo } from 'react';
18
+ import { useDisclosure, useClipboard } from '@mantine/hooks';
19
+ import { useQueryClient, useMutation } from '@tanstack/react-query';
17
20
 
21
+ function Checklist({ items, onToggle, onAdd, onRemove }) {
22
+ const [adding, setAdding] = useState(false);
23
+ const [newItemLabel, setNewItemLabel] = useState("");
24
+ function commitAdd() {
25
+ const label = newItemLabel.trim();
26
+ if (label) onAdd(label);
27
+ setNewItemLabel("");
28
+ }
29
+ const completedCount = items.filter((item) => item.completed).length;
30
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", mt: "sm", children: [
31
+ items.length > 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
32
+ completedCount,
33
+ "/",
34
+ items.length,
35
+ " complete"
36
+ ] }),
37
+ items.map((item) => /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
38
+ /* @__PURE__ */ jsx(
39
+ Checkbox,
40
+ {
41
+ size: "xs",
42
+ checked: item.completed,
43
+ onChange: () => onToggle(item.id),
44
+ label: /* @__PURE__ */ jsx(
45
+ Text,
46
+ {
47
+ size: "sm",
48
+ td: item.completed ? "line-through" : void 0,
49
+ c: item.completed ? "dimmed" : "var(--color-text-subtle)",
50
+ children: item.label
51
+ }
52
+ ),
53
+ styles: { input: { cursor: "pointer" }, label: { cursor: "pointer" } }
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "xs", onClick: () => onRemove(item.id), style: { opacity: 0.4 }, children: /* @__PURE__ */ jsx(IconX, { size: 12 }) })
57
+ ] }, item.id)),
58
+ adding ? /* @__PURE__ */ jsx(
59
+ TextInput,
60
+ {
61
+ size: "xs",
62
+ placeholder: "Item label...",
63
+ value: newItemLabel,
64
+ onChange: (event) => setNewItemLabel(event.target.value),
65
+ onKeyDown: (event) => {
66
+ if (event.key === "Enter") {
67
+ commitAdd();
68
+ setAdding(false);
69
+ }
70
+ if (event.key === "Escape") {
71
+ setNewItemLabel("");
72
+ setAdding(false);
73
+ }
74
+ },
75
+ onBlur: () => {
76
+ if (newItemLabel.trim()) commitAdd();
77
+ setAdding(false);
78
+ },
79
+ autoFocus: true,
80
+ style: { maxWidth: 250 }
81
+ }
82
+ ) : /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(
83
+ Button,
84
+ {
85
+ variant: "subtle",
86
+ size: "compact-xs",
87
+ leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 12 }),
88
+ onClick: () => setAdding(true),
89
+ children: "Add item"
90
+ }
91
+ ) })
92
+ ] });
93
+ }
94
+ var TASK_TYPE_OPTIONS = [
95
+ { value: "documentation", label: "Documentation" },
96
+ { value: "code", label: "Code" },
97
+ { value: "report", label: "Report" },
98
+ { value: "design", label: "Design" },
99
+ { value: "other", label: "Other" }
100
+ ];
101
+ function CreateDeliveryEntityModal({ opened, onClose, projectId, entityType }) {
102
+ const [name, setName] = useState("");
103
+ const [description, setDescription] = useState("");
104
+ const [taskType, setTaskType] = useState("other");
105
+ const [milestoneId, setMilestoneId] = useState(null);
106
+ const { mutate: createTask, isPending: isCreatingTask } = useCreateTask();
107
+ const { mutate: createMilestone, isPending: isCreatingMilestone } = useCreateMilestone();
108
+ const { data: milestones = [] } = useProjectMilestones(entityType === "task" ? projectId : "");
109
+ const isPending = entityType === "task" ? isCreatingTask : isCreatingMilestone;
110
+ const milestoneOptions = milestones.map((m) => ({ value: m.id, label: m.name }));
111
+ function resetForm() {
112
+ setName("");
113
+ setDescription("");
114
+ setTaskType("other");
115
+ setMilestoneId(null);
116
+ }
117
+ function handleClose() {
118
+ resetForm();
119
+ onClose();
120
+ }
121
+ function handleSubmit() {
122
+ const trimmedName = name.trim();
123
+ if (!trimmedName) return;
124
+ if (entityType === "task") {
125
+ createTask(
126
+ {
127
+ project_id: projectId,
128
+ name: trimmedName,
129
+ description: description.trim() || null,
130
+ type: taskType ?? "other",
131
+ milestone_id: milestoneId ?? null
132
+ },
133
+ {
134
+ onSuccess: () => {
135
+ resetForm();
136
+ onClose();
137
+ }
138
+ }
139
+ );
140
+ } else {
141
+ createMilestone(
142
+ {
143
+ project_id: projectId,
144
+ name: trimmedName,
145
+ description: description.trim() || null
146
+ },
147
+ {
148
+ onSuccess: () => {
149
+ resetForm();
150
+ onClose();
151
+ }
152
+ }
153
+ );
154
+ }
155
+ }
156
+ const title = entityType === "task" ? "Create Task" : "Add Milestone";
157
+ return /* @__PURE__ */ jsx(Modal, { opened, onClose: handleClose, size: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
158
+ /* @__PURE__ */ jsx(Title, { order: 3, children: title }),
159
+ /* @__PURE__ */ jsx(
160
+ TextInput,
161
+ {
162
+ label: "Name",
163
+ placeholder: entityType === "task" ? "Task name..." : "Milestone name...",
164
+ value: name,
165
+ onChange: (e) => setName(e.target.value),
166
+ required: true,
167
+ "data-autofocus": true
168
+ }
169
+ ),
170
+ /* @__PURE__ */ jsx(
171
+ Textarea,
172
+ {
173
+ label: "Description",
174
+ placeholder: "Optional description...",
175
+ minRows: 3,
176
+ value: description,
177
+ onChange: (e) => setDescription(e.target.value)
178
+ }
179
+ ),
180
+ entityType === "task" && /* @__PURE__ */ jsxs(Fragment, { children: [
181
+ /* @__PURE__ */ jsx(Select, { label: "Type", data: TASK_TYPE_OPTIONS, value: taskType, onChange: setTaskType }),
182
+ milestoneOptions.length > 0 && /* @__PURE__ */ jsx(
183
+ Select,
184
+ {
185
+ label: "Milestone",
186
+ placeholder: "Assign to milestone (optional)",
187
+ data: milestoneOptions,
188
+ value: milestoneId,
189
+ onChange: setMilestoneId,
190
+ clearable: true
191
+ }
192
+ )
193
+ ] }),
194
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
195
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: isPending, children: "Cancel" }),
196
+ /* @__PURE__ */ jsx(Button, { onClick: handleSubmit, loading: isPending, disabled: !name.trim(), children: title })
197
+ ] })
198
+ ] }) });
199
+ }
18
200
  function ringColor(completed, total) {
19
201
  if (total === 0) return "gray";
20
202
  const pct = completed / total;
@@ -246,7 +428,20 @@ function MilestoneTimeline({ milestones, tasks }) {
246
428
  );
247
429
  }) }) });
248
430
  }
431
+ function parseChecklist(task) {
432
+ const raw = task.checklist;
433
+ if (!Array.isArray(raw)) return [];
434
+ return raw;
435
+ }
249
436
  function TaskCard({ task }) {
437
+ const { mutate: updateTask } = useUpdateTask();
438
+ const items = parseChecklist(task);
439
+ function saveChecklist(updated) {
440
+ const updates = {
441
+ checklist: updated
442
+ };
443
+ updateTask({ id: task.id, updates });
444
+ }
250
445
  return /* @__PURE__ */ jsx(Card, { withBorder: true, radius: "sm", p: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
251
446
  /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
252
447
  /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", style: { minWidth: 0 }, children: [
@@ -272,7 +467,22 @@ function TaskCard({ task }) {
272
467
  task.due_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
273
468
  "Due ",
274
469
  new Date(task.due_date).toLocaleDateString()
275
- ] })
470
+ ] }),
471
+ items.length > 0 && /* @__PURE__ */ jsx(
472
+ Checklist,
473
+ {
474
+ items,
475
+ onToggle: (itemId) => {
476
+ saveChecklist(items.map((item) => item.id === itemId ? { ...item, completed: !item.completed } : item));
477
+ },
478
+ onAdd: (label) => {
479
+ saveChecklist([...items, { id: crypto.randomUUID(), label, completed: false }]);
480
+ },
481
+ onRemove: (itemId) => {
482
+ saveChecklist(items.filter((item) => item.id !== itemId));
483
+ }
484
+ }
485
+ )
276
486
  ] }) });
277
487
  }
278
488
  var ProjectsSidebarTop = () => {
@@ -554,22 +764,273 @@ function ProjectsListPage({ onProjectClick } = {}) {
554
764
  )
555
765
  ] });
556
766
  }
767
+ function isResumeContext(val) {
768
+ return !!val && typeof val === "object" && !Array.isArray(val);
769
+ }
770
+ function ResumeContextPreview({ tasks }) {
771
+ const candidate = tasks.filter((t) => isResumeContext(t.resume_context)).sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())[0];
772
+ if (!candidate) return null;
773
+ const ctx = candidate.resume_context;
774
+ return /* @__PURE__ */ jsx(
775
+ Paper,
776
+ {
777
+ p: "sm",
778
+ style: {
779
+ border: "1px solid var(--color-border)",
780
+ borderRadius: "var(--mantine-radius-default)",
781
+ backgroundColor: "color-mix(in srgb, var(--color-primary) 5%, var(--color-surface))"
782
+ },
783
+ children: /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
784
+ /* @__PURE__ */ jsx(Group, { gap: "xs", children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
785
+ "Last worked",
786
+ " ",
787
+ /* @__PURE__ */ jsx(Text, { component: "span", size: "xs", fw: 500, c: "var(--color-text)", children: formatRelativeTime(candidate.updated_at) }),
788
+ " ",
789
+ "on",
790
+ " ",
791
+ /* @__PURE__ */ jsx(Text, { component: "span", size: "xs", fw: 500, c: "var(--color-text)", children: candidate.name })
792
+ ] }) }),
793
+ ctx.current_state && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
794
+ "Current state:",
795
+ " ",
796
+ /* @__PURE__ */ jsx(Text, { component: "span", size: "xs", c: "var(--color-text-subtle)", children: ctx.current_state })
797
+ ] }),
798
+ ctx.next_steps && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
799
+ "Next:",
800
+ " ",
801
+ /* @__PURE__ */ jsx(Text, { component: "span", size: "xs", c: "var(--color-text-subtle)", children: ctx.next_steps })
802
+ ] })
803
+ ] })
804
+ }
805
+ );
806
+ }
807
+ var buildBootstrapCommand = (projectId) => `/project work ${projectId}`;
808
+ function QuickActionsRow({
809
+ onCreateTask,
810
+ onAddMilestone,
811
+ onLogBlocker,
812
+ onResumeBootstrap
813
+ }) {
814
+ return /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "wrap", children: [
815
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "compact-sm", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }), onClick: onCreateTask, children: "Create Task" }),
816
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "compact-sm", leftSection: /* @__PURE__ */ jsx(IconFlag, { size: 14 }), onClick: onAddMilestone, children: "Add Milestone" }),
817
+ /* @__PURE__ */ jsx(
818
+ Button,
819
+ {
820
+ variant: "light",
821
+ size: "compact-sm",
822
+ color: "orange",
823
+ leftSection: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 14 }),
824
+ onClick: onLogBlocker,
825
+ children: "Log Blocker"
826
+ }
827
+ ),
828
+ /* @__PURE__ */ jsx(Tooltip, { label: "Copies bootstrap command to clipboard", children: /* @__PURE__ */ jsx(
829
+ Button,
830
+ {
831
+ variant: "light",
832
+ size: "compact-sm",
833
+ color: "grape",
834
+ leftSection: /* @__PURE__ */ jsx(IconTerminal2, { size: 14 }),
835
+ onClick: onResumeBootstrap,
836
+ children: "Resume Bootstrap"
837
+ }
838
+ ) })
839
+ ] });
840
+ }
841
+ function LinkedRecordChips({ dealId, clientCompanyId }) {
842
+ if (!dealId && !clientCompanyId) return null;
843
+ return /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "wrap", children: [
844
+ dealId && /* @__PURE__ */ jsx(Anchor, { href: `/crm/deals/${dealId}`, underline: "never", children: /* @__PURE__ */ jsx(
845
+ Badge,
846
+ {
847
+ variant: "light",
848
+ color: "blue",
849
+ leftSection: /* @__PURE__ */ jsx(IconCurrencyDollar, { size: 12 }),
850
+ style: { cursor: "pointer" },
851
+ children: "Deal"
852
+ }
853
+ ) }),
854
+ clientCompanyId && /* @__PURE__ */ jsx(Anchor, { href: `/crm/companies/${clientCompanyId}`, underline: "never", children: /* @__PURE__ */ jsx(Badge, { variant: "light", color: "teal", leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 12 }), style: { cursor: "pointer" }, children: "Company" }) })
855
+ ] });
856
+ }
857
+ function ProjectActivityTimeline({ projectId }) {
858
+ const { data: activities, isLoading, error } = useProjectActivities(projectId);
859
+ if (isLoading) {
860
+ return /* @__PURE__ */ jsx(Center, { py: "xl", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) });
861
+ }
862
+ if (error) {
863
+ return /* @__PURE__ */ jsx(Alert, { color: "red", title: "Failed to load activity", children: "Could not fetch project activity. Please refresh." });
864
+ }
865
+ if (!activities?.length) {
866
+ return /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "No activity recorded for this project yet." });
867
+ }
868
+ return /* @__PURE__ */ jsx(Timeline, { bulletSize: 18, lineWidth: 2, children: activities.map((activity) => /* @__PURE__ */ jsxs(
869
+ Timeline.Item,
870
+ {
871
+ title: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: activity.title }),
872
+ children: [
873
+ activity.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mt: 2, children: activity.description }),
874
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mt: 2, children: formatTimeAgo(activity.occurredAt) })
875
+ ]
876
+ },
877
+ activity.id
878
+ )) });
879
+ }
880
+ var NOTE_FILTER_OPTIONS = [
881
+ { value: "call_note", label: "Call Notes" },
882
+ { value: "status_update", label: "Status Updates" },
883
+ { value: "issue", label: "Issues" },
884
+ { value: "blocker", label: "Blockers" }
885
+ ];
886
+ function isWithinLastWeek(dateStr) {
887
+ if (!dateStr) return false;
888
+ const date = new Date(dateStr);
889
+ const cutoff = /* @__PURE__ */ new Date();
890
+ cutoff.setDate(cutoff.getDate() - 7);
891
+ return date >= cutoff;
892
+ }
893
+ function NotesTabContent({ notes, onAddNote }) {
894
+ const [activeFilter, setActiveFilter] = useState(null);
895
+ const allNotes = notes ?? [];
896
+ const thisWeek = allNotes.filter((n) => isWithinLastWeek(n.occurred_at));
897
+ const weeklyByType = NOTE_FILTER_OPTIONS.map(({ value, label }) => ({
898
+ value,
899
+ label,
900
+ count: thisWeek.filter((n) => n.type === value).length
901
+ })).filter((entry) => entry.count > 0);
902
+ const rollupText = weeklyByType.length > 0 ? weeklyByType.map((e) => `${e.count} ${e.label.toLowerCase()}`).join(", ") + " this week" : null;
903
+ const visibleNotes = activeFilter ? allNotes.filter((n) => n.type === activeFilter) : allNotes;
904
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
905
+ rollupText && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 500, children: rollupText }),
906
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", wrap: "wrap", children: [
907
+ /* @__PURE__ */ jsx(Chip.Group, { value: activeFilter ?? "", onChange: (val) => setActiveFilter(val || null), children: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
908
+ /* @__PURE__ */ jsx(Chip, { value: "", size: "xs", variant: "light", children: "All" }),
909
+ NOTE_FILTER_OPTIONS.map(({ value, label }) => /* @__PURE__ */ jsx(Chip, { value, size: "xs", variant: "light", children: label }, value))
910
+ ] }) }),
911
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: onAddNote, children: "Add Note" })
912
+ ] }),
913
+ !visibleNotes.length ? /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: activeFilter ? `No ${formatStatusLabel(activeFilter)} notes yet.` : "No notes yet." }) : /* @__PURE__ */ jsx(Stack, { gap: "sm", children: visibleNotes.map((note) => /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
914
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
915
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: noteTypeColors[note.type ?? ""] ?? "gray", size: "sm", children: formatStatusLabel(note.type ?? "note") }),
916
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime(note.occurred_at) })
917
+ ] }),
918
+ note.summary && /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: note.summary }),
919
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: note.content })
920
+ ] }) }, note.id)) })
921
+ ] });
922
+ }
923
+ function isResumeContext2(val) {
924
+ return !!val && typeof val === "object" && !Array.isArray(val);
925
+ }
926
+ function extractContext(task) {
927
+ if (isResumeContext2(task.resume_context)) return task.resume_context;
928
+ return {};
929
+ }
930
+ function useMergeResumeContext() {
931
+ const { apiRequest } = useElevasisServices();
932
+ const queryClient = useQueryClient();
933
+ return useMutation({
934
+ mutationFn: async ({ taskId, patch }) => {
935
+ const res = await apiRequest(`/project-tasks/${taskId}/resume-context`, {
936
+ method: "PATCH",
937
+ body: JSON.stringify(patch)
938
+ });
939
+ return res.task;
940
+ },
941
+ onSuccess: (_data, variables) => {
942
+ queryClient.invalidateQueries({ queryKey: projectKeys.tasks(variables.projectId) });
943
+ },
944
+ onError: (error) => {
945
+ showApiErrorNotification(error);
946
+ }
947
+ });
948
+ }
949
+ function InlineResumeContextEditor({ task, projectId }) {
950
+ const [expanded, setExpanded] = useState(false);
951
+ const ctx = extractContext(task);
952
+ const [currentState, setCurrentState] = useState(ctx.current_state ?? "");
953
+ const [nextSteps, setNextSteps] = useState(ctx.next_steps ?? "");
954
+ const [filesModified, setFilesModified] = useState(typeof ctx.files_modified === "string" ? ctx.files_modified : "");
955
+ const { mutate: mergeContext, isPending } = useMergeResumeContext();
956
+ const save = useCallback(
957
+ (patch) => {
958
+ const nonEmpty = Object.fromEntries(Object.entries(patch).filter(([, v]) => v !== void 0));
959
+ if (Object.keys(nonEmpty).length === 0) return;
960
+ mergeContext({ taskId: task.id, projectId, patch: nonEmpty });
961
+ },
962
+ [mergeContext, task.id, projectId]
963
+ );
964
+ return /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
965
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", style: { cursor: "pointer", userSelect: "none" }, onClick: () => setExpanded((v) => !v), children: [
966
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "xs", tabIndex: -1, children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 12 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 12 }) }),
967
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Resume context" }),
968
+ isPending && /* @__PURE__ */ jsx(Loader, { size: 10 })
969
+ ] }),
970
+ /* @__PURE__ */ jsx(Collapse, { in: expanded, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", pl: "md", pt: 4, children: [
971
+ /* @__PURE__ */ jsx(
972
+ Textarea,
973
+ {
974
+ label: "Current state",
975
+ placeholder: "What is the task's current state?",
976
+ size: "xs",
977
+ minRows: 2,
978
+ autosize: true,
979
+ value: currentState,
980
+ onChange: (e) => setCurrentState(e.target.value),
981
+ onBlur: () => {
982
+ if (currentState !== (ctx.current_state ?? "")) save({ current_state: currentState });
983
+ }
984
+ }
985
+ ),
986
+ /* @__PURE__ */ jsx(
987
+ Textarea,
988
+ {
989
+ label: "Next steps",
990
+ placeholder: "What should happen next?",
991
+ size: "xs",
992
+ minRows: 2,
993
+ autosize: true,
994
+ value: nextSteps,
995
+ onChange: (e) => setNextSteps(e.target.value),
996
+ onBlur: () => {
997
+ if (nextSteps !== (ctx.next_steps ?? "")) save({ next_steps: nextSteps });
998
+ }
999
+ }
1000
+ ),
1001
+ /* @__PURE__ */ jsx(
1002
+ Textarea,
1003
+ {
1004
+ label: "Files modified (one per line)",
1005
+ placeholder: "src/foo.ts\nsrc/bar.ts",
1006
+ size: "xs",
1007
+ minRows: 2,
1008
+ autosize: true,
1009
+ value: filesModified,
1010
+ onChange: (e) => setFilesModified(e.target.value),
1011
+ onBlur: () => {
1012
+ const original = typeof ctx.files_modified === "string" ? ctx.files_modified : "";
1013
+ if (filesModified !== original) save({ files_modified: filesModified });
1014
+ }
1015
+ }
1016
+ )
1017
+ ] }) })
1018
+ ] });
1019
+ }
557
1020
  var noteTypeOptions = [
558
1021
  { value: "call_note", label: "Call Note" },
559
1022
  { value: "status_update", label: "Status Update" },
560
1023
  { value: "issue", label: "Issue" },
561
1024
  { value: "blocker", label: "Blocker" }
562
1025
  ];
563
- function parseChecklist(milestone) {
1026
+ function parseChecklist2(milestone) {
564
1027
  const raw = milestone.checklist;
565
1028
  if (!Array.isArray(raw)) return [];
566
1029
  return raw;
567
1030
  }
568
1031
  function MilestoneChecklist({ milestone }) {
569
- const items = parseChecklist(milestone);
1032
+ const items = parseChecklist2(milestone);
570
1033
  const { mutate: updateMilestone } = useUpdateMilestone();
571
- const [newItemLabel, setNewItemLabel] = useState("");
572
- const [adding, setAdding] = useState(false);
573
1034
  function saveChecklist(updated) {
574
1035
  const allComplete = updated.length > 0 && updated.every((item) => item.completed);
575
1036
  const wasComplete = milestone.status === "completed";
@@ -585,75 +1046,23 @@ function MilestoneChecklist({ milestone }) {
585
1046
  }
586
1047
  updateMilestone({ id: milestone.id, updates });
587
1048
  }
588
- function toggleItem(itemId) {
589
- const updated = items.map((item) => item.id === itemId ? { ...item, completed: !item.completed } : item);
590
- saveChecklist(updated);
591
- }
592
- function addItem() {
593
- const label = newItemLabel.trim();
594
- if (!label) return;
595
- const newItem = { id: crypto.randomUUID(), label, completed: false };
596
- saveChecklist([...items, newItem]);
597
- setNewItemLabel("");
598
- }
599
- function removeItem(itemId) {
600
- saveChecklist(items.filter((item) => item.id !== itemId));
601
- }
602
- const completedCount = items.filter((item) => item.completed).length;
603
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", mt: "sm", children: [
604
- items.length > 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
605
- completedCount,
606
- "/",
607
- items.length,
608
- " complete"
609
- ] }),
610
- items.map((item) => /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
611
- /* @__PURE__ */ jsx(
612
- Checkbox,
613
- {
614
- size: "xs",
615
- checked: item.completed,
616
- onChange: () => toggleItem(item.id),
617
- label: /* @__PURE__ */ jsx(
618
- Text,
619
- {
620
- size: "sm",
621
- td: item.completed ? "line-through" : void 0,
622
- c: item.completed ? "dimmed" : "var(--color-text-subtle)",
623
- children: item.label
624
- }
625
- ),
626
- styles: { input: { cursor: "pointer" }, label: { cursor: "pointer" } }
627
- }
628
- ),
629
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "xs", onClick: () => removeItem(item.id), style: { opacity: 0.4 }, children: /* @__PURE__ */ jsx(IconX, { size: 12 }) })
630
- ] }, item.id)),
631
- adding ? /* @__PURE__ */ jsx(
632
- TextInput,
633
- {
634
- size: "xs",
635
- placeholder: "Item label...",
636
- value: newItemLabel,
637
- onChange: (event) => setNewItemLabel(event.target.value),
638
- onKeyDown: (event) => {
639
- if (event.key === "Enter") {
640
- addItem();
641
- setAdding(false);
642
- }
643
- if (event.key === "Escape") {
644
- setNewItemLabel("");
645
- setAdding(false);
646
- }
647
- },
648
- onBlur: () => {
649
- if (newItemLabel.trim()) addItem();
650
- setAdding(false);
651
- },
652
- autoFocus: true,
653
- style: { maxWidth: 250 }
1049
+ return /* @__PURE__ */ jsx(
1050
+ Checklist,
1051
+ {
1052
+ items,
1053
+ onToggle: (itemId) => {
1054
+ const updated = items.map((item) => item.id === itemId ? { ...item, completed: !item.completed } : item);
1055
+ saveChecklist(updated);
1056
+ },
1057
+ onAdd: (label) => {
1058
+ const newItem = { id: crypto.randomUUID(), label, completed: false };
1059
+ saveChecklist([...items, newItem]);
1060
+ },
1061
+ onRemove: (itemId) => {
1062
+ saveChecklist(items.filter((item) => item.id !== itemId));
654
1063
  }
655
- ) : /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Button, { variant: "subtle", size: "compact-xs", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 12 }), onClick: () => setAdding(true), children: "Add item" }) })
656
- ] });
1064
+ }
1065
+ );
657
1066
  }
658
1067
  function AddNoteModal({ opened, onClose, projectId }) {
659
1068
  const [noteType, setNoteType] = useState("call_note");
@@ -711,12 +1120,69 @@ function AddNoteModal({ opened, onClose, projectId }) {
711
1120
  ] })
712
1121
  ] }) });
713
1122
  }
1123
+ function LogBlockerModal({ opened, onClose, projectId }) {
1124
+ const [content, setContent] = useState("");
1125
+ const [summary, setSummary] = useState("");
1126
+ const { mutate: createNote, isPending } = useCreateNote();
1127
+ function handleSubmit() {
1128
+ if (!content.trim()) return;
1129
+ createNote(
1130
+ {
1131
+ project_id: projectId,
1132
+ type: "blocker",
1133
+ content: content.trim(),
1134
+ summary: summary.trim() || null
1135
+ },
1136
+ {
1137
+ onSuccess: () => {
1138
+ setContent("");
1139
+ setSummary("");
1140
+ onClose();
1141
+ }
1142
+ }
1143
+ );
1144
+ }
1145
+ return /* @__PURE__ */ jsx(Modal, { opened, onClose, size: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1146
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Log Blocker" }),
1147
+ /* @__PURE__ */ jsx(
1148
+ TextInput,
1149
+ {
1150
+ label: "Summary",
1151
+ placeholder: "Brief blocker summary (optional)",
1152
+ value: summary,
1153
+ onChange: (e) => setSummary(e.target.value)
1154
+ }
1155
+ ),
1156
+ /* @__PURE__ */ jsx(
1157
+ Textarea,
1158
+ {
1159
+ label: "Description",
1160
+ placeholder: "Describe the blocker...",
1161
+ minRows: 4,
1162
+ value: content,
1163
+ onChange: (e) => setContent(e.target.value),
1164
+ required: true
1165
+ }
1166
+ ),
1167
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1168
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: onClose, disabled: isPending, children: "Cancel" }),
1169
+ /* @__PURE__ */ jsx(Button, { color: "orange", onClick: handleSubmit, loading: isPending, disabled: !content.trim(), children: "Log Blocker" })
1170
+ ] })
1171
+ ] }) });
1172
+ }
714
1173
  function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
1174
+ useProjectRealtime(projectId);
715
1175
  const { data: project, isLoading, error } = useProject(projectId);
1176
+ const { data: milestones = [] } = useProjectMilestones(projectId);
1177
+ const { data: tasks = [] } = useProjectTasks(projectId);
716
1178
  const { data: notes } = useProjectNotes({ projectId });
717
1179
  const { mutate: deleteProject, isPending: isDeleting } = useDeleteProject();
718
1180
  const [addNoteOpen, setAddNoteOpen] = useState(false);
719
1181
  const [deleteModalOpen, setDeleteModalOpen] = useState(false);
1182
+ const [logBlockerOpen, { open: openLogBlocker, close: closeLogBlocker }] = useDisclosure(false);
1183
+ const [createTaskOpen, { open: openCreateTask, close: closeCreateTask }] = useDisclosure(false);
1184
+ const [addMilestoneOpen, { open: openAddMilestone, close: closeAddMilestone }] = useDisclosure(false);
1185
+ const clipboard = useClipboard({ timeout: 2e3 });
720
1186
  if (isLoading) {
721
1187
  return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Loader, {}) }) });
722
1188
  }
@@ -726,8 +1192,6 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
726
1192
  if (!project) {
727
1193
  return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Alert, { color: "yellow", children: "Project not found" }) }) });
728
1194
  }
729
- const milestones = project.milestones ?? [];
730
- const tasks = project.tasks ?? [];
731
1195
  const totalMilestones = milestones.length;
732
1196
  const completedMilestones = milestones.filter((milestone) => milestone.status === "completed").length;
733
1197
  const totalTasks = tasks.length;
@@ -735,6 +1199,8 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
735
1199
  const milestoneProgress = calculateProgress(completedMilestones, totalMilestones);
736
1200
  const taskProgress = calculateProgress(approvedTasks, totalTasks);
737
1201
  const companyName = project.company?.name ?? null;
1202
+ const isEmpty = milestones.length === 0 && tasks.length === 0 && !notes?.length;
1203
+ const defaultTab = isEmpty ? "details" : "status";
738
1204
  return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
739
1205
  /* @__PURE__ */ jsx(
740
1206
  PageTitleCaption,
@@ -744,6 +1210,16 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
744
1210
  rightSection: /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onBack, children: backLabel }) })
745
1211
  }
746
1212
  ),
1213
+ /* @__PURE__ */ jsx(
1214
+ QuickActionsRow,
1215
+ {
1216
+ projectId,
1217
+ onCreateTask: openCreateTask,
1218
+ onAddMilestone: openAddMilestone,
1219
+ onLogBlocker: openLogBlocker,
1220
+ onResumeBootstrap: () => clipboard.copy(buildBootstrapCommand(projectId))
1221
+ }
1222
+ ),
747
1223
  /* @__PURE__ */ jsxs(SimpleGrid, { cols: 4, children: [
748
1224
  /* @__PURE__ */ jsx(
749
1225
  StatCard,
@@ -755,19 +1231,38 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
755
1231
  valueColor: `var(--mantine-color-${projectStatusColors[project.status || ""] || "gray"}-6)`
756
1232
  }
757
1233
  ),
758
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconFlag, value: `${completedMilestones}/${totalMilestones}`, label: "Milestones", children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
759
- milestoneProgress,
760
- "% complete"
761
- ] }) }),
1234
+ /* @__PURE__ */ jsx(
1235
+ StatCard,
1236
+ {
1237
+ variant: "hero",
1238
+ icon: IconFlag,
1239
+ value: `${completedMilestones}/${totalMilestones}`,
1240
+ label: "Milestones",
1241
+ children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1242
+ milestoneProgress,
1243
+ "% complete"
1244
+ ] })
1245
+ }
1246
+ ),
762
1247
  /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChecklist, value: `${approvedTasks}/${totalTasks}`, label: "Tasks", children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
763
1248
  taskProgress,
764
1249
  "% complete"
765
1250
  ] }) }),
766
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconCalendar, value: project.start_date ? formatDate(project.start_date) : "-", label: "Timeline", children: project.target_end_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
767
- "to ",
768
- formatDate(project.target_end_date)
769
- ] }) })
1251
+ /* @__PURE__ */ jsx(
1252
+ StatCard,
1253
+ {
1254
+ variant: "hero",
1255
+ icon: IconCalendar,
1256
+ value: project.start_date ? formatDate(project.start_date) : "-",
1257
+ label: "Timeline",
1258
+ children: project.target_end_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1259
+ "to ",
1260
+ formatDate(project.target_end_date)
1261
+ ] })
1262
+ }
1263
+ )
770
1264
  ] }),
1265
+ /* @__PURE__ */ jsx(ResumeContextPreview, { tasks }),
771
1266
  /* @__PURE__ */ jsxs(
772
1267
  Paper,
773
1268
  {
@@ -784,8 +1279,18 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
784
1279
  /* @__PURE__ */ jsx(Badge, { variant: "light", color: projectStatusColors[project.status || ""] || "gray", children: formatStatusLabel(project.status || "unknown") })
785
1280
  ] }),
786
1281
  /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1282
+ /* @__PURE__ */ jsx(LinkedRecordChips, { dealId: project.deal_id, clientCompanyId: project.client_company_id }),
787
1283
  /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: project.id }),
788
- /* @__PURE__ */ jsx(CopyButton, { value: project.id, children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ jsx(ActionIcon, { onClick: copy, variant: "subtle", size: "xs", color: copied ? "green" : "var(--color-text-subtle)", children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 }) }) }) })
1284
+ /* @__PURE__ */ jsx(CopyButton, { value: `/project work ${project.id}`, children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ jsx(
1285
+ ActionIcon,
1286
+ {
1287
+ onClick: copy,
1288
+ variant: "subtle",
1289
+ size: "xs",
1290
+ color: copied ? "green" : "var(--color-text-subtle)",
1291
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1292
+ }
1293
+ ) }) })
789
1294
  ] })
790
1295
  ] }),
791
1296
  /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
@@ -812,7 +1317,7 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
812
1317
  ] })
813
1318
  ] }),
814
1319
  /* @__PURE__ */ jsx(Divider, { my: "md" }),
815
- /* @__PURE__ */ jsxs(Tabs, { defaultValue: "status", children: [
1320
+ /* @__PURE__ */ jsxs(Tabs, { defaultValue: defaultTab, children: [
816
1321
  /* @__PURE__ */ jsxs(Tabs.List, { children: [
817
1322
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "status", children: "Status" }),
818
1323
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "details", children: "Details" }),
@@ -856,7 +1361,15 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
856
1361
  ) : void 0,
857
1362
  title: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
858
1363
  /* @__PURE__ */ jsx(Text, { fw: 500, children: milestone.name }),
859
- /* @__PURE__ */ jsx(Badge, { variant: "light", color: milestoneStatusColors[milestone.status || ""] || "gray", size: "sm", children: formatStatusLabel(milestone.status || "unknown") }),
1364
+ /* @__PURE__ */ jsx(
1365
+ Badge,
1366
+ {
1367
+ variant: "light",
1368
+ color: milestoneStatusColors[milestone.status || ""] || "gray",
1369
+ size: "sm",
1370
+ children: formatStatusLabel(milestone.status || "unknown")
1371
+ }
1372
+ ),
860
1373
  milestone.due_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
861
1374
  "Due ",
862
1375
  formatDate(milestone.due_date)
@@ -865,12 +1378,31 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
865
1378
  children: [
866
1379
  milestone.description && /* @__PURE__ */ jsx(Text, { size: "sm", mt: "xs", children: milestone.description }),
867
1380
  /* @__PURE__ */ jsx(MilestoneChecklist, { milestone }),
868
- milestoneTasks.length > 0 && /* @__PURE__ */ jsx(Stack, { gap: "xs", mt: "sm", children: milestoneTasks.map((task) => /* @__PURE__ */ jsx(Card, { withBorder: true, p: "xs", children: /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", children: [
869
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: task.name }),
870
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
871
- /* @__PURE__ */ jsx(Badge, { variant: "light", color: taskTypeColors[task.type || ""] || "gray", size: "xs", children: formatStatusLabel(task.type || "other") }),
872
- /* @__PURE__ */ jsx(Badge, { variant: "light", color: taskStatusColors[task.status || ""] || "gray", size: "xs", children: formatStatusLabel(task.status || "pending") })
873
- ] })
1381
+ milestoneTasks.length > 0 && /* @__PURE__ */ jsx(Stack, { gap: "xs", mt: "sm", children: milestoneTasks.map((task) => /* @__PURE__ */ jsx(Card, { withBorder: true, p: "xs", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1382
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", children: [
1383
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: task.name }),
1384
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1385
+ /* @__PURE__ */ jsx(
1386
+ Badge,
1387
+ {
1388
+ variant: "light",
1389
+ color: taskTypeColors[task.type || ""] || "gray",
1390
+ size: "xs",
1391
+ children: formatStatusLabel(task.type || "other")
1392
+ }
1393
+ ),
1394
+ /* @__PURE__ */ jsx(
1395
+ Badge,
1396
+ {
1397
+ variant: "light",
1398
+ color: taskStatusColors[task.status || ""] || "gray",
1399
+ size: "xs",
1400
+ children: formatStatusLabel(task.status || "pending")
1401
+ }
1402
+ )
1403
+ ] })
1404
+ ] }),
1405
+ /* @__PURE__ */ jsx(InlineResumeContextEditor, { task, projectId })
874
1406
  ] }) }, task.id)) })
875
1407
  ]
876
1408
  },
@@ -880,6 +1412,7 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
880
1412
  }
881
1413
  ) }),
882
1414
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "details", pt: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1415
+ isEmpty && /* @__PURE__ */ jsx(Alert, { color: "blue", title: "Get started", children: "This project has no milestones, tasks, or notes yet. Add a milestone or create a task to begin tracking progress." }),
883
1416
  /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
884
1417
  /* @__PURE__ */ jsx(Title, { order: 3, children: "Project Details" }),
885
1418
  project.description && /* @__PURE__ */ jsxs("div", { children: [
@@ -914,23 +1447,32 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
914
1447
  project.company.domain && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: project.company.domain })
915
1448
  ] }) })
916
1449
  ] }) }),
917
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "notes", pt: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
918
- /* @__PURE__ */ jsx(Group, { justify: "flex-end", children: /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setAddNoteOpen(true), children: "Add Note" }) }),
919
- !notes?.length ? /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "No notes yet." }) : /* @__PURE__ */ jsx(Stack, { gap: "sm", children: notes.map((note) => /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
920
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
921
- /* @__PURE__ */ jsx(Badge, { variant: "light", color: noteTypeColors[note.type || ""] || "gray", size: "sm", children: formatStatusLabel(note.type || "note") }),
922
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatTimeAgo(note.occurred_at) })
923
- ] }),
924
- note.summary && /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: note.summary }),
925
- /* @__PURE__ */ jsx(Text, { size: "sm", children: note.content })
926
- ] }) }, note.id)) })
927
- ] }) }),
928
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "activity", pt: "md", children: /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "Activity feed coming soon." }) })
1450
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "notes", pt: "md", children: /* @__PURE__ */ jsx(NotesTabContent, { notes, onAddNote: () => setAddNoteOpen(true) }) }),
1451
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "activity", pt: "md", children: /* @__PURE__ */ jsx(ProjectActivityTimeline, { projectId }) })
929
1452
  ] })
930
1453
  ]
931
1454
  }
932
1455
  ),
933
1456
  /* @__PURE__ */ jsx(AddNoteModal, { opened: addNoteOpen, onClose: () => setAddNoteOpen(false), projectId }),
1457
+ /* @__PURE__ */ jsx(LogBlockerModal, { opened: logBlockerOpen, onClose: closeLogBlocker, projectId }),
1458
+ /* @__PURE__ */ jsx(
1459
+ CreateDeliveryEntityModal,
1460
+ {
1461
+ opened: createTaskOpen,
1462
+ onClose: closeCreateTask,
1463
+ projectId,
1464
+ entityType: "task"
1465
+ }
1466
+ ),
1467
+ /* @__PURE__ */ jsx(
1468
+ CreateDeliveryEntityModal,
1469
+ {
1470
+ opened: addMilestoneOpen,
1471
+ onClose: closeAddMilestone,
1472
+ projectId,
1473
+ entityType: "milestone"
1474
+ }
1475
+ ),
934
1476
  /* @__PURE__ */ jsx(CustomModal, { opened: deleteModalOpen, onClose: () => setDeleteModalOpen(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
935
1477
  /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
936
1478
  /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete project" }),
@@ -963,4 +1505,4 @@ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
963
1505
  ] }) }) });
964
1506
  }
965
1507
 
966
- export { AllTasksPage, DELIVERY_COMMUNICATION_ITEMS, DELIVERY_PROJECT_ITEMS, DELIVERY_WORK_ITEMS, HealthStatusCard, MilestoneTimeline, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, TaskCard, UpcomingMilestonesPage, calculateProgress, deliveryManifest, formatStatusLabel, milestoneStatusColors, noteTypeColors, projectStatusColors, taskStatusColors, taskTypeColors };
1508
+ export { AllTasksPage, Checklist, CreateDeliveryEntityModal, DELIVERY_COMMUNICATION_ITEMS, DELIVERY_PROJECT_ITEMS, DELIVERY_WORK_ITEMS, HealthStatusCard, MilestoneTimeline, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, TaskCard, UpcomingMilestonesPage, calculateProgress, deliveryManifest, formatStatusLabel, milestoneStatusColors, noteTypeColors, projectStatusColors, taskStatusColors, taskTypeColors };