@elevasis/ui 2.0.2 → 2.1.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.
@@ -2,28 +2,29 @@ import { useBreadcrumbs } from '../chunk-MG3NF7QL.js';
2
2
  import '../chunk-SMJLS23U.js';
3
3
  import { NotificationList } from '../chunk-QRHLV74B.js';
4
4
  export { ActivityCard, ActivityFilters as ActivityFiltersBar, ActivityTable, BusinessImpactCard, CostBreakdownCard, CostByModelTable, CostMetricsCard, ErrorAnalysisCard, ErrorBreakdownTable, ExecutionBreakdownTable, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, NotificationItem, NotificationList, monitoringManifest } from '../chunk-QRHLV74B.js';
5
- export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipFeaturePanel, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, WebhookUrlDisplayModal, settingsManifest } from '../chunk-MELNDAZY.js';
5
+ export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipFeaturePanel, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, WebhookUrlDisplayModal, settingsManifest } from '../chunk-MVJ4TSSA.js';
6
6
  import { FilterBar } from '../chunk-PDHTXPSF.js';
7
7
  export { FilterBar } from '../chunk-PDHTXPSF.js';
8
- export { ActionModal, AgentDefinitionDisplay, AgentExecutionLogs, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, CheckpointGroup, CollapsibleJsonSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, CommandQueueTaskRow, CommandViewEdge, CommandViewGraph, CommandViewNode, ConfigCard, ContentSections, ContextUsageBadge, ContractDisplay, ExecutionErrorSection, FormFieldRenderer, LogEntry, LogGroup, NewKnowledgeMapEdge, NewKnowledgeMapGraph, NewKnowledgeMapNode, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceNotFoundState, SessionMemory, ToolsListDisplay, WorkflowDefinitionDisplay, WorkflowExecutionLogs, getExecutionStatusConfig, getIcon, getLogLevelConfig, iconMap, operationsManifest, useNewKnowledgeMapLayout } from '../chunk-CTU2JO57.js';
8
+ import { ResourceExecuteDialog } from '../chunk-H762MTQ5.js';
9
+ export { ActionModal, AgentDefinitionDisplay, AgentExecutionLogs, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, CheckpointGroup, CollapsibleJsonSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, CommandQueueTaskRow, CommandViewEdge, CommandViewGraph, CommandViewNode, ConfigCard, ContentSections, ContextUsageBadge, ContractDisplay, ExecutionErrorSection, FormFieldRenderer, LogEntry, LogGroup, NewKnowledgeMapEdge, NewKnowledgeMapGraph, NewKnowledgeMapNode, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceNotFoundState, SessionMemory, ToolsListDisplay, WorkflowDefinitionDisplay, WorkflowExecutionLogs, getExecutionStatusConfig, getIcon, getLogLevelConfig, iconMap, operationsManifest, useNewKnowledgeMapLayout } from '../chunk-H762MTQ5.js';
9
10
  import '../chunk-ROSMICXG.js';
10
11
  import { SubshellLoader, PageContainer, SubshellSidebarSection, SubshellNavItem, CollapsibleSidebarGroup } from '../chunk-OCP2MBTY.js';
11
12
  export { ResourceHealthPanel } from '../chunk-OKKGD3S6.js';
12
13
  import { CustomModal } from '../chunk-GBMNCNHX.js';
13
14
  export { ConfirmationInputModal, ConfirmationModal, CustomModal } from '../chunk-GBMNCNHX.js';
14
- export { AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationEdge, AgentIterationNode, BaseEdge, BaseNode, EmptyVisualizer, ExecutionStats, ExecutionStatusBadge, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, VisualizerContainer, WorkflowExecutionTimeline, dashboardManifest, getGraphBackgroundStyles, useGraphBackgroundStyles, useGraphTheme } from '../chunk-TQ3HK7ZR.js';
15
+ export { AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationEdge, AgentIterationNode, BaseEdge, BaseNode, EmptyVisualizer, ExecutionStats, ExecutionStatusBadge, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, VisualizerContainer, WorkflowExecutionTimeline, dashboardManifest, getGraphBackgroundStyles, useGraphBackgroundStyles, useGraphTheme } from '../chunk-PQNEE57X.js';
15
16
  export { ResourceHealthChart, getHealthColor } from '../chunk-LGKLC5MG.js';
16
17
  import '../chunk-KFICYU6S.js';
17
18
  import { AppShellLoader } from '../chunk-YEX4MQSY.js';
18
- import '../chunk-EIHG5JZN.js';
19
- import { useUpdateApiKey, useDeleteApiKey, useCreateApiKey, useListApiKeys, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments } from '../chunk-PRLXFMNP.js';
20
- import { usePaginationState, useDeploymentDocs, useResources, useCreateSchedule, useListSchedules, usePauseSchedule, useResumeSchedule, useCancelSchedule, useDeleteSchedule, useDealNotes, useCreateDealNote, useDeals, useSyncDealStage, dealKeys, useDealTasksDue, useCreateDealTask, useMarkAllAsRead, useNotifications, showErrorNotification, showSuccessNotification, showApiErrorNotification } from '../chunk-TZOGB3X4.js';
19
+ import '../chunk-35QO7M43.js';
20
+ import { useUpdateApiKey, useDeleteApiKey, useCreateApiKey, useListApiKeys, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments, useProjects } from '../chunk-PRLXFMNP.js';
21
+ import { usePaginationState, useDeploymentDocs, useResources, useCreateSchedule, useListSchedules, usePauseSchedule, useResumeSchedule, useCancelSchedule, useDeleteSchedule, useDealNotes, useCreateDealNote, useDeals, useSyncDealStage, dealKeys, useDealTasksDue, useCreateDealTask, useDeleteDeal, useTableSort, sortData, useTableSelection, useDealDetail, showApiErrorNotification, acquisitionListKeys, showSuccessNotification, useListsTelemetry, useLists, useCreateList, useList, useListProgress, useListExecutions, useResourceDefinition, useDeleteProject, useMarkAllAsRead, useNotifications, showErrorNotification } from '../chunk-TZOGB3X4.js';
21
22
  export { showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification } from '../chunk-TZOGB3X4.js';
22
23
  import '../chunk-LXHZYSMQ.js';
23
24
  export { Graph_module_css_default as graphStyles } from '../chunk-F6RBK7NJ.js';
24
25
  export { CONTAINER_CONSTANTS, SHARED_VIZ_CONSTANTS } from '../chunk-XA34RETF.js';
25
- import '../chunk-2DSYC52I.js';
26
- import '../chunk-X7CHQ3RE.js';
26
+ import '../chunk-QITPFGWC.js';
27
+ import '../chunk-RB34YOIX.js';
27
28
  import '../chunk-CYXZHBP4.js';
28
29
  import '../chunk-MZPVNRPL.js';
29
30
  import { SubshellContainer, SubshellSidebar, SubshellRightSideContainer, SubshellContentContainer } from '../chunk-RX4UWZZR.js';
@@ -46,12 +47,12 @@ import '../chunk-DD3CCMCZ.js';
46
47
  import { useElevasisServices } from '../chunk-QEPXAWE2.js';
47
48
  import '../chunk-BRJ3QZ4E.js';
48
49
  import { useRouterContext } from '../chunk-Q7DJKLEN.js';
49
- import { Table, Group, Text, Button, Stack, Title, TextInput, Alert, Tooltip, ActionIcon, Paper, Code, CopyButton, SimpleGrid, Badge, Loader, Pagination, useMantineTheme, Box, ScrollArea, Select, Center, Card, SegmentedControl, Switch, Textarea, Divider, Menu, Timeline, ThemeIcon, Tabs, Anchor, Breadcrumbs as Breadcrumbs$1, Drawer, UnstyledButton, Modal, RingProgress, Collapse, Popover, Indicator } from '@mantine/core';
50
- import { IconAddressBook, IconBriefcase, IconTarget, IconChevronUp, IconChevronDown, IconSelector, IconTrash, IconPencil, IconAlertCircle, IconKey, IconCalendar, IconClock, IconAlertTriangle, IconExclamationMark, IconShieldLock, IconCheck, IconCopy, IconPlus, IconRocket, IconRefresh, IconPower, IconPlayerPlay, IconCircleCheck, IconTag, IconBook2, IconFileOff, IconList, IconCalendarRepeat, IconCalendarEvent, IconCalendarTime, IconRobot, IconGitBranch, IconSettings, IconExternalLink, IconDotsVertical, IconPlayerPause, IconPlayerStop, IconCalendarDue, IconCalendarStats, IconCalendarOff, IconListCheck, IconTrophy, IconClockExclamation, IconUser, IconLayoutGrid, IconColumns, IconFileInvoice, IconChecklist, IconHistory, IconBuilding, IconMailCheck, IconSearch, IconChartBar, IconTrendingUp, IconHeartbeat, IconFlag, IconFileText, IconInbox, IconLock, IconChevronRight, IconDownload, IconMessageCircle, IconBell, IconNotes, IconFolderOpen, IconFolder, IconCheckbox, IconMail, IconPhone, IconArrowRight, IconNote } from '@tabler/icons-react';
50
+ import { Table, Group, Text, Button, Stack, Title, TextInput, Alert, Tooltip, ActionIcon, Paper, Code, CopyButton, SimpleGrid, Badge, Loader, Pagination, useMantineTheme, Box, ScrollArea, Select, Center, Card, SegmentedControl, Switch, Textarea, Divider, Menu, Timeline, ThemeIcon, Tabs, Anchor, Breadcrumbs as Breadcrumbs$1, Drawer, UnstyledButton, Modal, Checkbox, RingProgress, Collapse, Popover, Indicator } from '@mantine/core';
51
+ import { IconAddressBook, IconBriefcase, IconTarget, IconChevronUp, IconChevronDown, IconSelector, IconTrash, IconPencil, IconAlertCircle, IconKey, IconCalendar, IconClock, IconAlertTriangle, IconExclamationMark, IconShieldLock, IconCheck, IconCopy, IconPlus, IconRocket, IconRefresh, IconPower, IconPlayerPlay, IconCircleCheck, IconTag, IconBook2, IconFileOff, IconList, IconCalendarRepeat, IconCalendarEvent, IconCalendarTime, IconRobot, IconGitBranch, IconSettings, IconExternalLink, IconDotsVertical, IconPlayerPause, IconPlayerStop, IconCalendarDue, IconCalendarStats, IconCalendarOff, IconListCheck, IconTrophy, IconClockExclamation, IconUser, IconLayoutGrid, IconColumns, IconFileInvoice, IconChecklist, IconHistory, IconSearch, IconTargetArrow, IconArrowLeft, IconFileText, IconX, IconBuilding, IconMailCheck, IconChartBar, IconBuildingFactory2, IconUsers, IconSparkles, IconClockHour4, IconTrendingUp, IconHeartbeat, IconFlag, IconInbox, IconLock, IconChevronRight, IconDownload, IconMessageCircle, IconBell, IconNotes, IconFolderOpen, IconFolder, IconCheckbox, IconMail, IconPhone, IconArrowRight, IconNote } from '@tabler/icons-react';
51
52
  import * as runtime from 'react/jsx-runtime';
52
53
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
53
54
  import { useDisclosure } from '@mantine/hooks';
54
- import { useQueryClient, useQuery } from '@tanstack/react-query';
55
+ import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
55
56
  import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
56
57
  import { useForm } from '@mantine/form';
57
58
  import { Link, RichTextEditor as RichTextEditor$1 } from '@mantine/tiptap';
@@ -60,6 +61,7 @@ import Placeholder from '@tiptap/extension-placeholder';
60
61
  import StarterKit from '@tiptap/starter-kit';
61
62
  import { Prism } from 'react-syntax-highlighter';
62
63
  import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
64
+ import { useNavigate, Link as Link$1 } from '@tanstack/react-router';
63
65
 
64
66
  function SortableHeader({ column, children, sort, onToggle, style, w }) {
65
67
  const isActive = sort.column === column;
@@ -3019,7 +3021,7 @@ function MdxRenderer({ compiledSource }) {
3019
3021
  return /* @__PURE__ */ jsx(Content, { components: mdxComponents });
3020
3022
  }
3021
3023
  var Breadcrumbs = ({ navItems }) => {
3022
- const { Link: Link2 } = useRouterContext();
3024
+ const { Link: Link4 } = useRouterContext();
3023
3025
  const breadcrumbs = useBreadcrumbs({ navItems });
3024
3026
  const items = breadcrumbs.map((item) => {
3025
3027
  const isActive = item.isActive;
@@ -3029,7 +3031,7 @@ var Breadcrumbs = ({ navItems }) => {
3029
3031
  return item.path ? /* @__PURE__ */ jsx(
3030
3032
  Anchor,
3031
3033
  {
3032
- component: Link2,
3034
+ component: Link4,
3033
3035
  to: item.path,
3034
3036
  size: "sm",
3035
3037
  style: {
@@ -4072,6 +4074,410 @@ var crmManifest = {
4072
4074
  featureKey: "acquisition"
4073
4075
  }
4074
4076
  };
4077
+
4078
+ // src/features/crm/pages/shared.ts
4079
+ var DEAL_STAGE_COLORS = {
4080
+ interested: "blue",
4081
+ proposal: "yellow",
4082
+ closing: "orange",
4083
+ closed_won: "green",
4084
+ closed_lost: "red",
4085
+ nurturing: "grape"
4086
+ };
4087
+ var DEAL_STAGE_OPTIONS = [
4088
+ { value: "interested", label: "Interested" },
4089
+ { value: "proposal", label: "Proposal" },
4090
+ { value: "closing", label: "Closing" },
4091
+ { value: "closed_won", label: "Closed Won" },
4092
+ { value: "closed_lost", label: "Closed Lost" },
4093
+ { value: "nurturing", label: "Nurturing" }
4094
+ ];
4095
+ function formatDealStageLabel(stage) {
4096
+ if (!stage) return "Unknown";
4097
+ return stage.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
4098
+ }
4099
+ var sortAccessors = {
4100
+ company: (deal) => deal.contact?.company?.name || deal.discovery_data?.company || deal.contact_email?.split("@")[1] || "",
4101
+ contact: (deal) => [deal.contact?.first_name, deal.contact?.last_name].filter(Boolean).join(" ") || "",
4102
+ email: (deal) => deal.contact_email || "",
4103
+ stage: (deal) => deal.cached_stage || "",
4104
+ updated: (deal) => deal.updated_at || ""
4105
+ };
4106
+ function DealsListPage() {
4107
+ const navigate = useNavigate();
4108
+ const queryClient = useQueryClient();
4109
+ const deleteDeal = useDeleteDeal();
4110
+ const [stageFilter, setStageFilter] = useState(null);
4111
+ const [searchQuery, setSearchQuery] = useState("");
4112
+ const [showBatchDelete, setShowBatchDelete] = useState(false);
4113
+ const { data: deals, isLoading, error } = useDeals({
4114
+ stage: stageFilter || void 0,
4115
+ search: searchQuery || void 0
4116
+ });
4117
+ const { sort, toggleSort } = useTableSort("updated");
4118
+ const sortedDeals = useMemo(() => sortData(deals ?? [], sort, sortAccessors), [deals, sort]);
4119
+ const pagination = usePaginationState(PAGE_SIZE_DEFAULT, [stageFilter, searchQuery], sortedDeals.length);
4120
+ const paginatedDeals = useMemo(
4121
+ () => sortedDeals.slice(pagination.offset, pagination.offset + PAGE_SIZE_DEFAULT),
4122
+ [sortedDeals, pagination.offset]
4123
+ );
4124
+ const selection = useTableSelection(paginatedDeals, sortedDeals);
4125
+ const handleDeleteSelected = async () => {
4126
+ await Promise.all([...selection.selectedIds].map((dealId) => deleteDeal.mutateAsync(dealId)));
4127
+ setShowBatchDelete(false);
4128
+ selection.clear();
4129
+ await queryClient.invalidateQueries({ queryKey: ["deals"] });
4130
+ };
4131
+ return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
4132
+ /* @__PURE__ */ jsxs(PageContainer, { children: [
4133
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(PageTitleCaption, { title: "Deals", caption: "Deal pipeline and stage tracking" }) }),
4134
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { children: [
4135
+ /* @__PURE__ */ jsxs(
4136
+ FilterBar,
4137
+ {
4138
+ actions: /* @__PURE__ */ jsx(
4139
+ TableSelectionToolbar,
4140
+ {
4141
+ selectedCount: selection.selectedCount,
4142
+ onDelete: () => setShowBatchDelete(true),
4143
+ isDeleting: deleteDeal.isPending
4144
+ }
4145
+ ),
4146
+ children: [
4147
+ /* @__PURE__ */ jsx(
4148
+ Select,
4149
+ {
4150
+ placeholder: "All Stages",
4151
+ data: DEAL_STAGE_OPTIONS,
4152
+ style: { minWidth: 180 },
4153
+ size: "sm",
4154
+ clearable: true,
4155
+ value: stageFilter,
4156
+ onChange: (value) => setStageFilter(value ?? null)
4157
+ }
4158
+ ),
4159
+ /* @__PURE__ */ jsx(
4160
+ TextInput,
4161
+ {
4162
+ placeholder: "Search by email...",
4163
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
4164
+ style: { minWidth: 250 },
4165
+ size: "sm",
4166
+ value: searchQuery,
4167
+ onChange: (e) => setSearchQuery(e.currentTarget.value)
4168
+ }
4169
+ )
4170
+ ]
4171
+ }
4172
+ ),
4173
+ isLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : error ? /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load deals" }) : !sortedDeals.length ? /* @__PURE__ */ jsx(EmptyState, { icon: IconTargetArrow, title: "No deals found" }) : /* @__PURE__ */ jsxs(Table, { children: [
4174
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
4175
+ /* @__PURE__ */ jsx(Table.Th, { w: 40, children: /* @__PURE__ */ jsx(
4176
+ Checkbox,
4177
+ {
4178
+ checked: selection.isPageAllSelected,
4179
+ indeterminate: selection.isPagePartiallySelected,
4180
+ onChange: selection.togglePage
4181
+ }
4182
+ ) }),
4183
+ /* @__PURE__ */ jsx(SortableHeader, { column: "company", sort, onToggle: toggleSort, children: "Company" }),
4184
+ /* @__PURE__ */ jsx(SortableHeader, { column: "contact", sort, onToggle: toggleSort, children: "Contact" }),
4185
+ /* @__PURE__ */ jsx(SortableHeader, { column: "email", sort, onToggle: toggleSort, children: "Email" }),
4186
+ /* @__PURE__ */ jsx(SortableHeader, { column: "stage", sort, onToggle: toggleSort, children: "Stage" }),
4187
+ /* @__PURE__ */ jsx(SortableHeader, { column: "updated", sort, onToggle: toggleSort, children: "Updated" })
4188
+ ] }) }),
4189
+ /* @__PURE__ */ jsx(Table.Tbody, { children: paginatedDeals.map((deal) => {
4190
+ const discoveryData = deal.discovery_data;
4191
+ const companyName = deal.contact?.company?.name || discoveryData?.company || deal.contact_email?.split("@")[1] || "-";
4192
+ const contactName = [deal.contact?.first_name, deal.contact?.last_name].filter(Boolean).join(" ");
4193
+ return /* @__PURE__ */ jsxs(
4194
+ Table.Tr,
4195
+ {
4196
+ style: { cursor: "pointer" },
4197
+ onClick: () => navigate({
4198
+ to: "/crm/deals/$dealId",
4199
+ params: { dealId: deal.id }
4200
+ }),
4201
+ children: [
4202
+ /* @__PURE__ */ jsx(Table.Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
4203
+ Checkbox,
4204
+ {
4205
+ checked: selection.isSelected(deal.id),
4206
+ onChange: () => selection.toggle(deal.id)
4207
+ }
4208
+ ) }),
4209
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: companyName }) }),
4210
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", children: contactName || "-" }) }),
4211
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: deal.contact_email || "-" }) }),
4212
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { variant: "light", color: DEAL_STAGE_COLORS[deal.cached_stage || ""] || "gray", size: "sm", children: formatDealStageLabel(deal.cached_stage) }) }),
4213
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatTimeAgo(deal.updated_at) }) })
4214
+ ]
4215
+ },
4216
+ deal.id
4217
+ );
4218
+ }) })
4219
+ ] }),
4220
+ sortedDeals.length > PAGE_SIZE_DEFAULT && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(
4221
+ Pagination,
4222
+ {
4223
+ value: pagination.page,
4224
+ onChange: pagination.setPage,
4225
+ total: pagination.totalPages(sortedDeals.length),
4226
+ size: "sm"
4227
+ }
4228
+ ) })
4229
+ ] }) })
4230
+ ] }),
4231
+ /* @__PURE__ */ jsx(
4232
+ CustomModal,
4233
+ {
4234
+ opened: showBatchDelete,
4235
+ onClose: () => !deleteDeal.isPending && setShowBatchDelete(false),
4236
+ size: "sm",
4237
+ loading: deleteDeal.isPending,
4238
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4239
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
4240
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
4241
+ /* @__PURE__ */ jsxs(Title, { order: 4, children: [
4242
+ "Delete ",
4243
+ selection.selectedCount,
4244
+ " Deals"
4245
+ ] })
4246
+ ] }),
4247
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
4248
+ "Are you sure you want to delete",
4249
+ " ",
4250
+ /* @__PURE__ */ jsx(Text, { span: true, fw: 600, children: selection.selectedCount }),
4251
+ " ",
4252
+ "selected deals?"
4253
+ ] }),
4254
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone." }),
4255
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
4256
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: () => setShowBatchDelete(false), disabled: deleteDeal.isPending, children: "Cancel" }),
4257
+ /* @__PURE__ */ jsx(Button, { color: "red", loading: deleteDeal.isPending, onClick: () => void handleDeleteSelected(), children: "Delete" })
4258
+ ] })
4259
+ ] })
4260
+ }
4261
+ )
4262
+ ] });
4263
+ }
4264
+ function DealDetailPage({ dealId, renderActions, onDealLoaded }) {
4265
+ const navigate = useNavigate();
4266
+ const deleteDeal = useDeleteDeal();
4267
+ const { data: deal, isLoading, error } = useDealDetail(dealId);
4268
+ const [deleteModalOpen, setDeleteModalOpen] = useState(false);
4269
+ useEffect(() => {
4270
+ if (deal) onDealLoaded?.(deal);
4271
+ }, [deal, onDealLoaded]);
4272
+ const title = deal ? `${[deal.contact?.first_name, deal.contact?.last_name].filter(Boolean).join(" ") || "Unknown"} Deal` : "Deal Detail";
4273
+ const contactName = useMemo(
4274
+ () => deal ? [deal.contact?.first_name, deal.contact?.last_name].filter(Boolean).join(" ") : "",
4275
+ [deal]
4276
+ );
4277
+ const companyName = useMemo(() => {
4278
+ if (!deal) return null;
4279
+ return deal.contact?.company?.name || deal.discovery_data?.company || deal.contact_email?.split("@")[1] || "Unknown";
4280
+ }, [deal]);
4281
+ const headerActions = deal ? /* @__PURE__ */ jsxs(Group, { children: [
4282
+ /* @__PURE__ */ jsx(
4283
+ Button,
4284
+ {
4285
+ variant: "light",
4286
+ size: "sm",
4287
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
4288
+ onClick: () => navigate({ to: "/crm/deals" }),
4289
+ children: "Deals"
4290
+ }
4291
+ ),
4292
+ deal.proposal_pdf_url && /* @__PURE__ */ jsx(
4293
+ Button,
4294
+ {
4295
+ variant: "light",
4296
+ leftSection: /* @__PURE__ */ jsx(IconFileText, { size: 16 }),
4297
+ onClick: () => window.open(deal.proposal_pdf_url, "_blank"),
4298
+ children: "View Proposal"
4299
+ }
4300
+ ),
4301
+ renderActions?.(deal),
4302
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", color: "red", onClick: () => setDeleteModalOpen(true), children: /* @__PURE__ */ jsx(IconTrash, { size: 16 }) })
4303
+ ] }) : /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: () => navigate({ to: "/crm/deals" }), children: "Deals" });
4304
+ if (isLoading) {
4305
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
4306
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(PageTitleCaption, { title, caption: "Loading deal details...", rightSection: headerActions }) }),
4307
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) })
4308
+ ] }) });
4309
+ }
4310
+ if (error) {
4311
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
4312
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(PageTitleCaption, { title, caption: "Unable to load deal details", rightSection: headerActions }) }),
4313
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load deal" }) })
4314
+ ] }) });
4315
+ }
4316
+ if (!deal) {
4317
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
4318
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(PageTitleCaption, { title, caption: "Deal not found", rightSection: headerActions }) }),
4319
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(EmptyState, { icon: IconTrash, title: "Deal not found", description: "The selected deal no longer exists." }) })
4320
+ ] }) });
4321
+ }
4322
+ const activityLog = deal.activity_log || [];
4323
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
4324
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(
4325
+ PageTitleCaption,
4326
+ {
4327
+ title,
4328
+ caption: `${companyName || "Unknown"} - ${formatDealStageLabel(deal.cached_stage)}`,
4329
+ rightSection: headerActions
4330
+ }
4331
+ ) }),
4332
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "details", children: [
4333
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
4334
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "details", children: "Details" }),
4335
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "discovery", children: "Discovery Data" }),
4336
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "activity", children: "Activity" })
4337
+ ] }),
4338
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "details", pt: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4339
+ /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
4340
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Deal" }),
4341
+ /* @__PURE__ */ jsxs(Group, { children: [
4342
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Stage:" }),
4343
+ /* @__PURE__ */ jsx(Badge, { color: DEAL_STAGE_COLORS[deal.cached_stage || ""] || "gray", children: formatDealStageLabel(deal.cached_stage) })
4344
+ ] }),
4345
+ /* @__PURE__ */ jsxs(Group, { children: [
4346
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Sent:" }),
4347
+ /* @__PURE__ */ jsx(Text, { children: deal.proposal_sent_at ? new Date(deal.proposal_sent_at).toLocaleString() : "N/A" })
4348
+ ] }),
4349
+ /* @__PURE__ */ jsxs(Group, { children: [
4350
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Envelope ID:" }),
4351
+ /* @__PURE__ */ jsx(Text, { children: deal.signature_envelope_id || "N/A" })
4352
+ ] })
4353
+ ] }) }),
4354
+ /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
4355
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Contact" }),
4356
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "sm", children: [
4357
+ /* @__PURE__ */ jsxs(Group, { children: [
4358
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Name:" }),
4359
+ /* @__PURE__ */ jsx(Text, { children: contactName || "N/A" })
4360
+ ] }),
4361
+ /* @__PURE__ */ jsxs(Group, { children: [
4362
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Email:" }),
4363
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.email || deal.contact_email || "N/A" })
4364
+ ] }),
4365
+ /* @__PURE__ */ jsxs(Group, { children: [
4366
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Title:" }),
4367
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.title || "N/A" })
4368
+ ] }),
4369
+ /* @__PURE__ */ jsxs(Group, { children: [
4370
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Pipeline Status:" }),
4371
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: deal.contact?.pipeline_status ? Object.entries(deal.contact.pipeline_status).map(([key, val]) => {
4372
+ const status = val?.status;
4373
+ return status ? `${key}: ${status}` : null;
4374
+ }).filter(Boolean).join(", ") || "N/A" : "N/A" })
4375
+ ] }),
4376
+ deal.contact?.headline && /* @__PURE__ */ jsxs(Group, { children: [
4377
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Headline:" }),
4378
+ /* @__PURE__ */ jsx(Text, { children: deal.contact.headline })
4379
+ ] }),
4380
+ deal.contact?.linkedin_url && /* @__PURE__ */ jsxs(Group, { children: [
4381
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "LinkedIn:" }),
4382
+ /* @__PURE__ */ jsx(Text, { component: "a", href: deal.contact.linkedin_url, target: "_blank", c: "blue", children: "View Profile" })
4383
+ ] })
4384
+ ] })
4385
+ ] }) }),
4386
+ /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
4387
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Company" }),
4388
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "sm", children: [
4389
+ /* @__PURE__ */ jsxs(Group, { children: [
4390
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Name:" }),
4391
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.company?.name || "N/A" })
4392
+ ] }),
4393
+ /* @__PURE__ */ jsxs(Group, { children: [
4394
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Domain:" }),
4395
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.company?.domain || "N/A" })
4396
+ ] }),
4397
+ /* @__PURE__ */ jsxs(Group, { children: [
4398
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Segment:" }),
4399
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.company?.segment || "N/A" })
4400
+ ] }),
4401
+ /* @__PURE__ */ jsxs(Group, { children: [
4402
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Category:" }),
4403
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.company?.category || "N/A" })
4404
+ ] }),
4405
+ /* @__PURE__ */ jsxs(Group, { children: [
4406
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Employees:" }),
4407
+ /* @__PURE__ */ jsx(Text, { children: deal.contact?.company?.num_employees || "N/A" })
4408
+ ] }),
4409
+ deal.contact?.company?.website && /* @__PURE__ */ jsxs(Group, { children: [
4410
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Website:" }),
4411
+ /* @__PURE__ */ jsx(Text, { component: "a", href: deal.contact.company.website, target: "_blank", c: "blue", children: deal.contact.company.website })
4412
+ ] })
4413
+ ] })
4414
+ ] }) }),
4415
+ ["proposal_signed", "payment_sent", "closed_won"].includes(deal.cached_stage || "") && /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
4416
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Payment" }),
4417
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "sm", children: [
4418
+ /* @__PURE__ */ jsxs(Group, { children: [
4419
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Initial Fee:" }),
4420
+ /* @__PURE__ */ jsxs(Text, { children: [
4421
+ "$",
4422
+ deal.initial_fee?.toLocaleString() || "Not set"
4423
+ ] })
4424
+ ] }),
4425
+ /* @__PURE__ */ jsxs(Group, { children: [
4426
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Monthly Fee:" }),
4427
+ /* @__PURE__ */ jsxs(Text, { children: [
4428
+ "$",
4429
+ deal.monthly_fee?.toLocaleString() || "Not set",
4430
+ "/mo"
4431
+ ] })
4432
+ ] })
4433
+ ] }),
4434
+ deal.stripe_payment_link && /* @__PURE__ */ jsxs(Group, { children: [
4435
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Payment Link:" }),
4436
+ /* @__PURE__ */ jsx(Text, { component: "a", href: deal.stripe_payment_link, target: "_blank", c: "blue", children: deal.stripe_payment_link })
4437
+ ] })
4438
+ ] }) })
4439
+ ] }) }),
4440
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "discovery", pt: "md", children: /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsx(Code, { block: true, children: JSON.stringify(deal.discovery_data, null, 2) }) }) }),
4441
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "activity", pt: "md", children: /* @__PURE__ */ jsx(ActivityTimeline, { activities: activityLog }) })
4442
+ ] }) }),
4443
+ /* @__PURE__ */ jsx(CustomModal, { opened: deleteModalOpen, onClose: () => setDeleteModalOpen(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4444
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
4445
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete deal" }),
4446
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", onClick: () => setDeleteModalOpen(false), children: /* @__PURE__ */ jsx(IconX, { size: 18 }) })
4447
+ ] }),
4448
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
4449
+ "Are you sure you want to delete the deal for ",
4450
+ /* @__PURE__ */ jsx("strong", { children: contactName || deal.contact_email }),
4451
+ "? This will cancel any active schedules and pending tasks for this contact."
4452
+ ] }),
4453
+ (deal.signature_envelope_id || deal.stripe_payment_link) && /* @__PURE__ */ jsxs(Alert, { color: "yellow", variant: "light", children: [
4454
+ "This deal has ",
4455
+ deal.signature_envelope_id ? "a signed contract" : "",
4456
+ deal.signature_envelope_id && deal.stripe_payment_link ? " and " : "",
4457
+ deal.stripe_payment_link ? "an active payment link" : "",
4458
+ " that will not be automatically cleaned up."
4459
+ ] }),
4460
+ /* @__PURE__ */ jsx(Divider, {}),
4461
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
4462
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setDeleteModalOpen(false), disabled: deleteDeal.isPending, children: "Cancel" }),
4463
+ /* @__PURE__ */ jsx(
4464
+ Button,
4465
+ {
4466
+ color: "red",
4467
+ loading: deleteDeal.isPending,
4468
+ onClick: () => deleteDeal.mutate(deal.id, {
4469
+ onSuccess: () => {
4470
+ setDeleteModalOpen(false);
4471
+ void navigate({ to: "/crm/deals" });
4472
+ }
4473
+ }),
4474
+ children: "Delete deal"
4475
+ }
4476
+ )
4477
+ ] })
4478
+ ] }) })
4479
+ ] }) });
4480
+ }
4075
4481
  var LeadGenSidebarTop = () => {
4076
4482
  return /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconTarget, label: "Lead Gen" });
4077
4483
  };
@@ -4116,6 +4522,968 @@ var leadGenManifest = {
4116
4522
  featureKey: "acquisition"
4117
4523
  }
4118
4524
  };
4525
+ var LEAD_GEN_ROUTE_LINKS = [
4526
+ { label: "Overview", to: "/lead-gen" },
4527
+ { label: "Lists", to: "/lead-gen/lists" },
4528
+ { label: "Companies", to: "/lead-gen/companies" },
4529
+ { label: "Contacts", to: "/lead-gen/contacts" },
4530
+ { label: "Deliverability", to: "/lead-gen/deliverability" }
4531
+ ];
4532
+ function LeadGenRouteShell({
4533
+ title,
4534
+ caption,
4535
+ body,
4536
+ links = LEAD_GEN_ROUTE_LINKS
4537
+ }) {
4538
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4539
+ /* @__PURE__ */ jsx(PageTitleCaption, { title, caption }),
4540
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "lg", children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
4541
+ body,
4542
+ /* @__PURE__ */ jsx(Text, { children: links.map((link, index) => /* @__PURE__ */ jsxs("span", { children: [
4543
+ index > 0 ? " | " : null,
4544
+ /* @__PURE__ */ jsx(Anchor, { component: Link$1, to: link.to, children: link.label })
4545
+ ] }, link.to)) })
4546
+ ] }) })
4547
+ ] }) }) });
4548
+ }
4549
+ function formatDate2(dateString) {
4550
+ return new Date(dateString).toLocaleDateString("en-US", {
4551
+ month: "short",
4552
+ day: "numeric",
4553
+ year: "numeric"
4554
+ });
4555
+ }
4556
+ function getStatusColor3(status) {
4557
+ return status === "active" ? "green" : status === "invalid" ? "red" : "gray";
4558
+ }
4559
+ function getEnrichmentColor(status) {
4560
+ switch (status) {
4561
+ case "complete":
4562
+ return "green";
4563
+ case "pending":
4564
+ return "yellow";
4565
+ case "failed":
4566
+ return "red";
4567
+ default:
4568
+ return "gray";
4569
+ }
4570
+ }
4571
+ var LIST_TEMPLATE_OPTIONS = [
4572
+ {
4573
+ value: "blank",
4574
+ label: "Blank",
4575
+ description: "Create an empty draft list with qualification defaults and no pipeline steps."
4576
+ },
4577
+ {
4578
+ value: "full_pipeline",
4579
+ label: "Full 6-Stage",
4580
+ description: "Create a complete lead-gen pipeline from scrape through personalization."
4581
+ },
4582
+ {
4583
+ value: "personalize_only",
4584
+ label: "Personalize Only",
4585
+ description: "Start with personalization and upload-focused steps for already-prepared contacts."
4586
+ },
4587
+ {
4588
+ value: "email_refresh",
4589
+ label: "Email Refresh",
4590
+ description: "Run discovery, verification, and personalization for an existing company set."
4591
+ }
4592
+ ];
4593
+ function buildListConfig(template, targetDescription) {
4594
+ const qualification = {
4595
+ targetDescription,
4596
+ minReviewCount: 5,
4597
+ minRating: 4,
4598
+ excludeFranchises: true,
4599
+ customRules: ""
4600
+ };
4601
+ const personalization = {
4602
+ industryContext: targetDescription,
4603
+ emailBody: "",
4604
+ creativeDirection: "",
4605
+ exclusionRules: []
4606
+ };
4607
+ switch (template) {
4608
+ case "full_pipeline":
4609
+ return {
4610
+ qualification,
4611
+ enrichment: {
4612
+ emailDiscovery: { primary: "tomba" },
4613
+ emailVerification: { provider: "millionverifier", threshold: "ok" }
4614
+ },
4615
+ personalization,
4616
+ pipeline: {
4617
+ steps: [
4618
+ {
4619
+ key: "scrape",
4620
+ label: "Scrape Companies",
4621
+ resourceId: "lgn-01a-google-maps-scrape-workflow",
4622
+ inputTemplate: {},
4623
+ enabled: true,
4624
+ order: 1
4625
+ },
4626
+ {
4627
+ key: "acquire",
4628
+ label: "Import Companies",
4629
+ resourceId: "lgn-01b-apify-acquire-workflow",
4630
+ inputTemplate: {},
4631
+ enabled: true,
4632
+ order: 2
4633
+ },
4634
+ {
4635
+ key: "extract",
4636
+ label: "Extract Website Data",
4637
+ resourceId: "lgn-02-website-extract-workflow",
4638
+ inputTemplate: {},
4639
+ enabled: true,
4640
+ order: 3
4641
+ },
4642
+ {
4643
+ key: "qualify",
4644
+ label: "Qualify Companies",
4645
+ resourceId: "lgn-03-company-qualification-workflow",
4646
+ inputTemplate: {},
4647
+ enabled: true,
4648
+ order: 4
4649
+ },
4650
+ {
4651
+ key: "discover",
4652
+ label: "Discover Emails",
4653
+ resourceId: "lgn-04-email-discovery-workflow",
4654
+ inputTemplate: {},
4655
+ enabled: true,
4656
+ order: 5
4657
+ },
4658
+ {
4659
+ key: "verify",
4660
+ label: "Verify Emails",
4661
+ resourceId: "lgn-05-email-verification-workflow",
4662
+ inputTemplate: {},
4663
+ enabled: true,
4664
+ order: 6
4665
+ },
4666
+ {
4667
+ key: "personalize",
4668
+ label: "Personalize Outreach",
4669
+ resourceId: "ist-personalization-workflow",
4670
+ inputTemplate: {},
4671
+ enabled: true,
4672
+ order: 7
4673
+ }
4674
+ ]
4675
+ }
4676
+ };
4677
+ case "personalize_only":
4678
+ return {
4679
+ qualification,
4680
+ personalization,
4681
+ pipeline: {
4682
+ steps: [
4683
+ {
4684
+ key: "personalize",
4685
+ label: "Personalize Outreach",
4686
+ resourceId: "ist-personalization-workflow",
4687
+ inputTemplate: {},
4688
+ enabled: true,
4689
+ order: 1
4690
+ },
4691
+ {
4692
+ key: "upload",
4693
+ label: "Upload Contacts",
4694
+ resourceId: "ist-upload-contacts-workflow",
4695
+ inputTemplate: { requireOpeningLine: true },
4696
+ enabled: true,
4697
+ order: 2
4698
+ }
4699
+ ]
4700
+ }
4701
+ };
4702
+ case "email_refresh":
4703
+ return {
4704
+ qualification,
4705
+ enrichment: {
4706
+ emailDiscovery: { primary: "tomba" },
4707
+ emailVerification: { provider: "millionverifier", threshold: "ok" }
4708
+ },
4709
+ personalization,
4710
+ pipeline: {
4711
+ steps: [
4712
+ {
4713
+ key: "discover",
4714
+ label: "Discover Emails",
4715
+ resourceId: "lgn-04-email-discovery-workflow",
4716
+ inputTemplate: {},
4717
+ enabled: true,
4718
+ order: 1
4719
+ },
4720
+ {
4721
+ key: "verify",
4722
+ label: "Verify Emails",
4723
+ resourceId: "lgn-05-email-verification-workflow",
4724
+ inputTemplate: {},
4725
+ enabled: true,
4726
+ order: 2
4727
+ },
4728
+ {
4729
+ key: "personalize",
4730
+ label: "Personalize Outreach",
4731
+ resourceId: "ist-personalization-workflow",
4732
+ inputTemplate: {},
4733
+ enabled: true,
4734
+ order: 3
4735
+ }
4736
+ ]
4737
+ }
4738
+ };
4739
+ case "blank":
4740
+ default:
4741
+ return {
4742
+ qualification,
4743
+ pipeline: {
4744
+ steps: []
4745
+ }
4746
+ };
4747
+ }
4748
+ }
4749
+ function useDeleteLists() {
4750
+ const { apiRequest, organizationId } = useElevasisServices();
4751
+ const queryClient = useQueryClient();
4752
+ return useMutation({
4753
+ mutationFn: async (listIds) => {
4754
+ const uniqueIds = [...new Set(listIds)].filter(Boolean);
4755
+ if (uniqueIds.length === 0) return;
4756
+ await Promise.all(
4757
+ uniqueIds.map(
4758
+ (listId) => apiRequest(`/acquisition/lists/${listId}`, {
4759
+ method: "DELETE"
4760
+ })
4761
+ )
4762
+ );
4763
+ },
4764
+ onSuccess: () => {
4765
+ queryClient.invalidateQueries({ queryKey: acquisitionListKeys.list(organizationId) });
4766
+ queryClient.invalidateQueries({ queryKey: acquisitionListKeys.telemetry(organizationId) });
4767
+ showSuccessNotification("Lists deleted");
4768
+ },
4769
+ onError: (error) => {
4770
+ showApiErrorNotification(error);
4771
+ }
4772
+ });
4773
+ }
4774
+ var EM_DASH = "\u2014";
4775
+ function LeadGenOverviewPage() {
4776
+ const { data, isLoading, isError, error } = useListsTelemetry();
4777
+ const totalCompanies = data?.reduce((sum, list) => sum + list.totalCompanies, 0) ?? 0;
4778
+ const totalContacts = data?.reduce((sum, list) => sum + list.totalContacts, 0) ?? 0;
4779
+ const completionLabel = (() => {
4780
+ if (!data?.length) return EM_DASH;
4781
+ const populated = data.reduce((sum, list) => sum + list.stageCounts.populated, 0);
4782
+ const personalized = data.reduce((sum, list) => sum + list.stageCounts.personalized, 0);
4783
+ return populated === 0 ? EM_DASH : `${Math.round(personalized / populated * 100)}%`;
4784
+ })();
4785
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4786
+ /* @__PURE__ */ jsx(
4787
+ PageTitleCaption,
4788
+ {
4789
+ title: "Lead Gen Overview",
4790
+ caption: "Pipeline health, list roll-up, and active work at a glance"
4791
+ }
4792
+ ),
4793
+ isLoading ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) }) : isError ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load list telemetry" }) }) : !data?.length ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { h: 300, children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "No lists yet." }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4794
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 2, sm: 4 }, children: [
4795
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChartBar, value: data.length, label: "Total Lists" }),
4796
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconBuildingFactory2, value: totalCompanies, label: "Total Companies" }),
4797
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconUsers, value: totalContacts, label: "Total Contacts" }),
4798
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChecklist, value: completionLabel, label: "Overall Completion" })
4799
+ ] }),
4800
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
4801
+ "View per-list detail on the",
4802
+ " ",
4803
+ /* @__PURE__ */ jsx(Anchor, { component: Link$1, to: "/lead-gen/lists", size: "sm", children: "Lists" }),
4804
+ " ",
4805
+ "page."
4806
+ ] })
4807
+ ] })
4808
+ ] }) }) });
4809
+ }
4810
+ function computeBounceRate(d) {
4811
+ const denominator = d.valid + d.risky + d.invalid + d.bounced;
4812
+ if (denominator === 0) return EM_DASH;
4813
+ return `${(d.bounced / denominator * 100).toFixed(1)}%`;
4814
+ }
4815
+ function LeadGenDeliverabilityPage() {
4816
+ const { data, isLoading, error } = useListsTelemetry();
4817
+ if (isLoading) {
4818
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4819
+ /* @__PURE__ */ jsx(
4820
+ PageTitleCaption,
4821
+ {
4822
+ title: "Deliverability",
4823
+ caption: "Email validity breakdown and bounce health across lists"
4824
+ }
4825
+ ),
4826
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) })
4827
+ ] }) }) });
4828
+ }
4829
+ if (error) {
4830
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4831
+ /* @__PURE__ */ jsx(
4832
+ PageTitleCaption,
4833
+ {
4834
+ title: "Deliverability",
4835
+ caption: "Email validity breakdown and bounce health across lists"
4836
+ }
4837
+ ),
4838
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load deliverability data" }) })
4839
+ ] }) }) });
4840
+ }
4841
+ if (data?.length === 0) {
4842
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4843
+ /* @__PURE__ */ jsx(
4844
+ PageTitleCaption,
4845
+ {
4846
+ title: "Deliverability",
4847
+ caption: "Email validity breakdown and bounce health across lists"
4848
+ }
4849
+ ),
4850
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { h: 300, children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconMailCheck, { size: 16 }), color: "gray", variant: "light", children: "No lists yet. Deliverability will populate once contacts are validated." }) }) })
4851
+ ] }) }) });
4852
+ }
4853
+ const lists = data ?? [];
4854
+ const totals = lists.reduce(
4855
+ (acc, list) => ({
4856
+ valid: acc.valid + list.deliverability.valid,
4857
+ risky: acc.risky + list.deliverability.risky,
4858
+ invalid: acc.invalid + list.deliverability.invalid,
4859
+ unknown: acc.unknown + list.deliverability.unknown,
4860
+ bounced: acc.bounced + list.deliverability.bounced
4861
+ }),
4862
+ { valid: 0, risky: 0, invalid: 0, unknown: 0, bounced: 0 }
4863
+ );
4864
+ const summaryTiles = [
4865
+ { label: "Valid", value: totals.valid },
4866
+ { label: "Risky", value: totals.risky },
4867
+ { label: "Invalid", value: totals.invalid },
4868
+ { label: "Unknown", value: totals.unknown },
4869
+ { label: "Bounced", value: totals.bounced },
4870
+ { label: "Bounce Rate", value: computeBounceRate(totals) }
4871
+ ];
4872
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4873
+ /* @__PURE__ */ jsx(
4874
+ PageTitleCaption,
4875
+ {
4876
+ title: "Deliverability",
4877
+ caption: "Email validity breakdown and bounce health across lists"
4878
+ }
4879
+ ),
4880
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsx(SimpleGrid, { cols: 6, children: summaryTiles.map((tile) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
4881
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mb: 4, children: tile.label }),
4882
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "lg", children: tile.value })
4883
+ ] }, tile.label)) }) }),
4884
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Table, { children: [
4885
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
4886
+ /* @__PURE__ */ jsx(Table.Th, { children: "List ID" }),
4887
+ /* @__PURE__ */ jsx(Table.Th, { children: "Valid" }),
4888
+ /* @__PURE__ */ jsx(Table.Th, { children: "Risky" }),
4889
+ /* @__PURE__ */ jsx(Table.Th, { children: "Invalid" }),
4890
+ /* @__PURE__ */ jsx(Table.Th, { children: "Unknown" }),
4891
+ /* @__PURE__ */ jsx(Table.Th, { children: "Bounced" }),
4892
+ /* @__PURE__ */ jsx(Table.Th, { children: "Bounce Rate" })
4893
+ ] }) }),
4894
+ /* @__PURE__ */ jsx(Table.Tbody, { children: lists.map((list) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
4895
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: list.listId }) }),
4896
+ /* @__PURE__ */ jsx(Table.Td, { children: list.deliverability.valid }),
4897
+ /* @__PURE__ */ jsx(Table.Td, { children: list.deliverability.risky }),
4898
+ /* @__PURE__ */ jsx(Table.Td, { children: list.deliverability.invalid }),
4899
+ /* @__PURE__ */ jsx(Table.Td, { children: list.deliverability.unknown }),
4900
+ /* @__PURE__ */ jsx(Table.Td, { children: list.deliverability.bounced }),
4901
+ /* @__PURE__ */ jsx(Table.Td, { children: computeBounceRate(list.deliverability) })
4902
+ ] }, list.listId)) })
4903
+ ] }) })
4904
+ ] }) }) });
4905
+ }
4906
+ var PAGE_SIZE_DEFAULT2 = 20;
4907
+ function LeadGenListsPage() {
4908
+ const navigate = useNavigate();
4909
+ const [searchQuery, setSearchQuery] = useState("");
4910
+ const [showCreateList, setShowCreateList] = useState(false);
4911
+ const [newListName, setNewListName] = useState("");
4912
+ const [newListDescription, setNewListDescription] = useState("");
4913
+ const [selectedTemplate, setSelectedTemplate] = useState("full_pipeline");
4914
+ const [showBatchDelete, setShowBatchDelete] = useState(false);
4915
+ const { data: lists, isLoading: listsLoading } = useLists();
4916
+ const { data: telemetry, isLoading: telemetryLoading } = useListsTelemetry();
4917
+ const createListMutation = useCreateList();
4918
+ const deleteListsMutation = useDeleteLists();
4919
+ const { sort, toggleSort } = useTableSort("created");
4920
+ const contactCountByListId = useMemo(
4921
+ () => new Map((telemetry ?? []).map((item) => [item.listId, item.totalContacts])),
4922
+ [telemetry]
4923
+ );
4924
+ const sortAccessors2 = useMemo(
4925
+ () => ({
4926
+ name: (list) => list.name,
4927
+ description: (list) => list.description || "",
4928
+ contacts: (list) => contactCountByListId.get(list.id) ?? 0,
4929
+ created: (list) => list.createdAt
4930
+ }),
4931
+ [contactCountByListId]
4932
+ );
4933
+ const filteredLists = useMemo(() => {
4934
+ if (!lists) return [];
4935
+ if (!searchQuery.trim()) return lists;
4936
+ const query = searchQuery.toLowerCase();
4937
+ return lists.filter((list) => list.name.toLowerCase().includes(query));
4938
+ }, [lists, searchQuery]);
4939
+ const sortedLists = useMemo(() => sortData(filteredLists, sort, sortAccessors2), [filteredLists, sort, sortAccessors2]);
4940
+ const pagination = usePaginationState(PAGE_SIZE_DEFAULT2, [searchQuery], sortedLists.length);
4941
+ const paginatedLists = useMemo(
4942
+ () => sortedLists.slice(pagination.offset, pagination.offset + PAGE_SIZE_DEFAULT2),
4943
+ [sortedLists, pagination.offset]
4944
+ );
4945
+ const selection = useTableSelection(paginatedLists, sortedLists);
4946
+ const selectedTemplateMeta = LIST_TEMPLATE_OPTIONS.find((option) => option.value === selectedTemplate);
4947
+ function resetCreateListModal() {
4948
+ setNewListName("");
4949
+ setNewListDescription("");
4950
+ setSelectedTemplate("full_pipeline");
4951
+ setShowCreateList(false);
4952
+ }
4953
+ function handleCreateList() {
4954
+ const trimmedName = newListName.trim();
4955
+ if (!trimmedName) return;
4956
+ const body = {
4957
+ name: trimmedName,
4958
+ description: newListDescription.trim() || null,
4959
+ type: selectedTemplate,
4960
+ config: buildListConfig(selectedTemplate, trimmedName)
4961
+ };
4962
+ createListMutation.mutate(body, {
4963
+ onSuccess: (list) => {
4964
+ resetCreateListModal();
4965
+ navigate({ to: "/lead-gen/lists/$listId", params: { listId: list.id } });
4966
+ }
4967
+ });
4968
+ }
4969
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
4970
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(
4971
+ PageTitleCaption,
4972
+ {
4973
+ title: "Lists",
4974
+ caption: "Lead lists and contact organization",
4975
+ rightSection: /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setShowCreateList(true), children: "New List" })
4976
+ }
4977
+ ) }),
4978
+ /* @__PURE__ */ jsx(Paper, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4979
+ /* @__PURE__ */ jsx(
4980
+ FilterBar,
4981
+ {
4982
+ actions: /* @__PURE__ */ jsx(
4983
+ TableSelectionToolbar,
4984
+ {
4985
+ selectedCount: selection.selectedCount,
4986
+ onDelete: () => setShowBatchDelete(true),
4987
+ isDeleting: deleteListsMutation.isPending
4988
+ }
4989
+ ),
4990
+ children: /* @__PURE__ */ jsx(
4991
+ TextInput,
4992
+ {
4993
+ placeholder: "Search by name...",
4994
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
4995
+ value: searchQuery,
4996
+ onChange: (e) => setSearchQuery(e.currentTarget.value)
4997
+ }
4998
+ )
4999
+ }
5000
+ ),
5001
+ listsLoading || telemetryLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : !filteredLists.length ? /* @__PURE__ */ jsx(
5002
+ EmptyState,
5003
+ {
5004
+ icon: IconList,
5005
+ title: searchQuery.trim() ? "No lists match your search" : "No lists yet",
5006
+ description: searchQuery.trim() ? void 0 : "Create one to get started.",
5007
+ action: searchQuery.trim() ? void 0 : {
5008
+ label: "Create List",
5009
+ onClick: () => setShowCreateList(true),
5010
+ icon: /* @__PURE__ */ jsx(IconPlus, { size: 16 })
5011
+ }
5012
+ }
5013
+ ) : /* @__PURE__ */ jsxs(Table, { children: [
5014
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5015
+ /* @__PURE__ */ jsx(Table.Th, { w: 40, children: /* @__PURE__ */ jsx(
5016
+ Checkbox,
5017
+ {
5018
+ checked: selection.isPageAllSelected,
5019
+ indeterminate: selection.isPagePartiallySelected,
5020
+ onChange: selection.togglePage
5021
+ }
5022
+ ) }),
5023
+ /* @__PURE__ */ jsx(SortableHeader, { column: "name", sort, onToggle: toggleSort, children: "Name" }),
5024
+ /* @__PURE__ */ jsx(SortableHeader, { column: "description", sort, onToggle: toggleSort, children: "Description" }),
5025
+ /* @__PURE__ */ jsx(SortableHeader, { column: "contacts", sort, onToggle: toggleSort, children: "Contacts" }),
5026
+ /* @__PURE__ */ jsx(SortableHeader, { column: "created", sort, onToggle: toggleSort, children: "Created" })
5027
+ ] }) }),
5028
+ /* @__PURE__ */ jsx(Table.Tbody, { children: paginatedLists.map((list) => /* @__PURE__ */ jsxs(
5029
+ Table.Tr,
5030
+ {
5031
+ style: { cursor: "pointer" },
5032
+ onClick: () => navigate({ to: "/lead-gen/lists/$listId", params: { listId: list.id } }),
5033
+ children: [
5034
+ /* @__PURE__ */ jsx(Table.Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(Checkbox, { checked: selection.isSelected(list.id), onChange: () => selection.toggle(list.id) }) }),
5035
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: list.name }) }),
5036
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: list.description || "-" }) }),
5037
+ /* @__PURE__ */ jsx(Table.Td, { children: contactCountByListId.get(list.id) ?? 0 }),
5038
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDate2(list.createdAt) }) })
5039
+ ]
5040
+ },
5041
+ list.id
5042
+ )) })
5043
+ ] }),
5044
+ sortedLists.length > PAGE_SIZE_DEFAULT2 && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(
5045
+ Pagination,
5046
+ {
5047
+ value: pagination.page,
5048
+ onChange: pagination.setPage,
5049
+ total: pagination.totalPages(sortedLists.length),
5050
+ size: "sm"
5051
+ }
5052
+ ) })
5053
+ ] }) }),
5054
+ /* @__PURE__ */ jsx(
5055
+ CustomModal,
5056
+ {
5057
+ opened: showCreateList,
5058
+ onClose: () => !createListMutation.isPending && resetCreateListModal(),
5059
+ size: "md",
5060
+ loading: createListMutation.isPending,
5061
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5062
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
5063
+ /* @__PURE__ */ jsx(IconSparkles, { size: 24 }),
5064
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Create List" })
5065
+ ] }),
5066
+ /* @__PURE__ */ jsx(
5067
+ TextInput,
5068
+ {
5069
+ label: "List Name",
5070
+ placeholder: "e.g. Orange County Vets Q2",
5071
+ value: newListName,
5072
+ onChange: (event) => setNewListName(event.currentTarget.value),
5073
+ disabled: createListMutation.isPending,
5074
+ required: true
5075
+ }
5076
+ ),
5077
+ /* @__PURE__ */ jsx(
5078
+ Textarea,
5079
+ {
5080
+ label: "Description",
5081
+ placeholder: "Optional context for this list",
5082
+ value: newListDescription,
5083
+ onChange: (event) => setNewListDescription(event.currentTarget.value),
5084
+ disabled: createListMutation.isPending,
5085
+ minRows: 3
5086
+ }
5087
+ ),
5088
+ /* @__PURE__ */ jsx(
5089
+ Select,
5090
+ {
5091
+ label: "Pipeline Template",
5092
+ data: LIST_TEMPLATE_OPTIONS.map((option) => ({
5093
+ value: option.value,
5094
+ label: option.label
5095
+ })),
5096
+ value: selectedTemplate,
5097
+ onChange: (value) => setSelectedTemplate(value ?? "full_pipeline"),
5098
+ disabled: createListMutation.isPending,
5099
+ allowDeselect: false
5100
+ }
5101
+ ),
5102
+ selectedTemplateMeta ? /* @__PURE__ */ jsx(Alert, { variant: "light", color: "blue", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: selectedTemplateMeta.description }) }) : null,
5103
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "The list will open in draft mode after creation so you can review configuration, edit pipeline steps, and run workflows from the detail page." }),
5104
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
5105
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: resetCreateListModal, disabled: createListMutation.isPending, children: "Cancel" }),
5106
+ /* @__PURE__ */ jsx(Button, { onClick: handleCreateList, loading: createListMutation.isPending, disabled: !newListName.trim(), children: "Create List" })
5107
+ ] })
5108
+ ] })
5109
+ }
5110
+ ),
5111
+ /* @__PURE__ */ jsx(
5112
+ CustomModal,
5113
+ {
5114
+ opened: showBatchDelete,
5115
+ onClose: () => !deleteListsMutation.isPending && setShowBatchDelete(false),
5116
+ size: "sm",
5117
+ loading: deleteListsMutation.isPending,
5118
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5119
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
5120
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
5121
+ /* @__PURE__ */ jsxs(Title, { order: 4, children: [
5122
+ "Delete ",
5123
+ selection.selectedCount,
5124
+ " Lists"
5125
+ ] })
5126
+ ] }),
5127
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5128
+ "Are you sure you want to delete",
5129
+ " ",
5130
+ /* @__PURE__ */ jsx(Text, { span: true, fw: 600, children: selection.selectedCount }),
5131
+ " ",
5132
+ "selected lists?"
5133
+ ] }),
5134
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone." }),
5135
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
5136
+ /* @__PURE__ */ jsx(
5137
+ Button,
5138
+ {
5139
+ variant: "light",
5140
+ onClick: () => setShowBatchDelete(false),
5141
+ disabled: deleteListsMutation.isPending,
5142
+ children: "Cancel"
5143
+ }
5144
+ ),
5145
+ /* @__PURE__ */ jsx(
5146
+ Button,
5147
+ {
5148
+ color: "red",
5149
+ loading: deleteListsMutation.isPending,
5150
+ onClick: () => {
5151
+ deleteListsMutation.mutate([...selection.selectedIds], {
5152
+ onSuccess: () => {
5153
+ setShowBatchDelete(false);
5154
+ selection.clear();
5155
+ }
5156
+ });
5157
+ },
5158
+ children: "Delete"
5159
+ }
5160
+ )
5161
+ ] })
5162
+ ] })
5163
+ }
5164
+ )
5165
+ ] }) });
5166
+ }
5167
+ function formatDateTime2(value) {
5168
+ if (!value) return "Not yet";
5169
+ return new Date(value).toLocaleString("en-US", {
5170
+ month: "short",
5171
+ day: "numeric",
5172
+ year: "numeric",
5173
+ hour: "numeric",
5174
+ minute: "2-digit"
5175
+ });
5176
+ }
5177
+ function LeadGenListDetailPage({ listId }) {
5178
+ const navigate = useNavigate();
5179
+ const [selectedStepKey, setSelectedStepKey] = useState(null);
5180
+ const listQuery = useList(listId);
5181
+ const progressQuery = useListProgress(listId);
5182
+ const executionsQuery = useListExecutions(listId);
5183
+ const selectedStep = useMemo(
5184
+ () => listQuery.data?.config.pipeline?.steps?.slice().sort((a, b) => a.order - b.order).find((step) => step.key === selectedStepKey) ?? null,
5185
+ [listQuery.data?.config.pipeline?.steps, selectedStepKey]
5186
+ );
5187
+ const resourceDefinitionQuery = useResourceDefinition(selectedStep?.resourceId ?? "", !!selectedStep?.resourceId);
5188
+ const isLoading = listQuery.isLoading || progressQuery.isLoading || executionsQuery.isLoading;
5189
+ const error = listQuery.error ?? progressQuery.error ?? executionsQuery.error;
5190
+ if (isLoading) {
5191
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
5192
+ /* @__PURE__ */ jsx(
5193
+ PageTitleCaption,
5194
+ {
5195
+ title: "List Detail",
5196
+ caption: "Configuration, progress, and execution history for a single lead-gen list",
5197
+ rightSection: /* @__PURE__ */ jsx(
5198
+ Button,
5199
+ {
5200
+ variant: "light",
5201
+ size: "sm",
5202
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
5203
+ onClick: () => navigate({ to: "/lead-gen/lists" }),
5204
+ children: "Lists"
5205
+ }
5206
+ )
5207
+ }
5208
+ ),
5209
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) })
5210
+ ] }) }) });
5211
+ }
5212
+ if (error) {
5213
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
5214
+ /* @__PURE__ */ jsx(
5215
+ PageTitleCaption,
5216
+ {
5217
+ title: "List Detail",
5218
+ caption: "Configuration, progress, and execution history for a single lead-gen list",
5219
+ rightSection: /* @__PURE__ */ jsx(
5220
+ Button,
5221
+ {
5222
+ variant: "light",
5223
+ size: "sm",
5224
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
5225
+ onClick: () => navigate({ to: "/lead-gen/lists" }),
5226
+ children: "Lists"
5227
+ }
5228
+ )
5229
+ }
5230
+ ),
5231
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load list detail" }) })
5232
+ ] }) }) });
5233
+ }
5234
+ if (!listQuery.data || !progressQuery.data) {
5235
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
5236
+ /* @__PURE__ */ jsx(
5237
+ PageTitleCaption,
5238
+ {
5239
+ title: "List Not Found",
5240
+ caption: "The requested lead-gen list is unavailable.",
5241
+ rightSection: /* @__PURE__ */ jsx(
5242
+ Button,
5243
+ {
5244
+ variant: "light",
5245
+ size: "sm",
5246
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
5247
+ onClick: () => navigate({ to: "/lead-gen/lists" }),
5248
+ children: "Lists"
5249
+ }
5250
+ )
5251
+ }
5252
+ ),
5253
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { h: 240, children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "The requested list could not be found." }) }) })
5254
+ ] }) }) });
5255
+ }
5256
+ const list = listQuery.data;
5257
+ const progress = progressQuery.data;
5258
+ const executions = executionsQuery.data ?? [];
5259
+ const pipelineSteps = list.config.pipeline?.steps?.slice().sort((a, b) => a.order - b.order) ?? [];
5260
+ const stageTiles = [
5261
+ { label: "Populated", value: progress.stageCounts.populated },
5262
+ { label: "Extracted", value: progress.stageCounts.extracted },
5263
+ { label: "Qualified", value: progress.stageCounts.qualified },
5264
+ { label: "Discovered", value: progress.stageCounts.discovered },
5265
+ { label: "Verified", value: progress.stageCounts.verified },
5266
+ { label: "Personalized", value: progress.stageCounts.personalized },
5267
+ { label: "Uploaded", value: progress.stageCounts.uploaded }
5268
+ ];
5269
+ const deliverabilityTiles = [
5270
+ { label: "Valid", value: progress.deliverability.valid },
5271
+ { label: "Risky", value: progress.deliverability.risky },
5272
+ { label: "Invalid", value: progress.deliverability.invalid },
5273
+ { label: "Unknown", value: progress.deliverability.unknown },
5274
+ { label: "Bounced", value: progress.deliverability.bounced }
5275
+ ];
5276
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
5277
+ /* @__PURE__ */ jsxs(Stack, { children: [
5278
+ /* @__PURE__ */ jsx(
5279
+ PageTitleCaption,
5280
+ {
5281
+ title: list.name,
5282
+ caption: list.description ?? "Configuration, progress, and execution history for this list",
5283
+ rightSection: /* @__PURE__ */ jsx(
5284
+ Button,
5285
+ {
5286
+ variant: "light",
5287
+ size: "sm",
5288
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
5289
+ onClick: () => navigate({ to: "/lead-gen/lists" }),
5290
+ children: "Lists"
5291
+ }
5292
+ )
5293
+ }
5294
+ ),
5295
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
5296
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor3(list.status), children: list.status }),
5297
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
5298
+ "Created ",
5299
+ formatDateTime2(list.createdAt)
5300
+ ] })
5301
+ ] }),
5302
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2, lg: 4 }, children: [
5303
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
5304
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mb: "xs", children: "Companies" }),
5305
+ /* @__PURE__ */ jsx(Title, { order: 3, children: progress.totalCompanies })
5306
+ ] }),
5307
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
5308
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mb: "xs", children: "Contacts" }),
5309
+ /* @__PURE__ */ jsx(Title, { order: 3, children: progress.totalContacts })
5310
+ ] }),
5311
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
5312
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mb: "xs", children: "Pipeline Steps" }),
5313
+ /* @__PURE__ */ jsx(Title, { order: 3, children: pipelineSteps.length })
5314
+ ] }),
5315
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
5316
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mb: "xs", children: "Executions" }),
5317
+ /* @__PURE__ */ jsx(Title, { order: 3, children: executions.length })
5318
+ ] })
5319
+ ] }),
5320
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5321
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Pipeline Progress" }),
5322
+ /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 2, sm: 3, lg: 7 }, children: stageTiles.map((tile) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
5323
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: tile.label }),
5324
+ /* @__PURE__ */ jsx(Title, { order: 4, children: tile.value })
5325
+ ] }, tile.label)) })
5326
+ ] }) }),
5327
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5328
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Deliverability" }),
5329
+ /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 2, sm: 3, lg: 5 }, children: deliverabilityTiles.map((tile) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
5330
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: tile.label }),
5331
+ /* @__PURE__ */ jsx(Title, { order: 4, children: tile.value })
5332
+ ] }, tile.label)) })
5333
+ ] }) }),
5334
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5335
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Configuration" }),
5336
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, lg: 2 }, children: [
5337
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
5338
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: "Qualification" }),
5339
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5340
+ "Target: ",
5341
+ list.config.qualification.targetDescription
5342
+ ] }),
5343
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5344
+ "Minimum reviews: ",
5345
+ list.config.qualification.minReviewCount
5346
+ ] }),
5347
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5348
+ "Minimum rating: ",
5349
+ list.config.qualification.minRating
5350
+ ] }),
5351
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5352
+ "Exclude franchises: ",
5353
+ list.config.qualification.excludeFranchises ? "Yes" : "No"
5354
+ ] })
5355
+ ] }) }),
5356
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
5357
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: "Enrichment + Personalization" }),
5358
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5359
+ "Discovery provider: ",
5360
+ list.config.enrichment?.emailDiscovery?.primary ?? "Inherited default"
5361
+ ] }),
5362
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5363
+ "Verification provider: ",
5364
+ list.config.enrichment?.emailVerification?.provider ?? "Inherited default"
5365
+ ] }),
5366
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5367
+ "Industry context: ",
5368
+ list.config.personalization?.industryContext ?? "Inherited default"
5369
+ ] }),
5370
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5371
+ "Creative direction: ",
5372
+ list.config.personalization?.creativeDirection ?? "Inherited default"
5373
+ ] })
5374
+ ] }) })
5375
+ ] }),
5376
+ list.config.personalization?.emailBody ? /* @__PURE__ */ jsxs(Box, { children: [
5377
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, mb: "xs", children: "Email Body Template" }),
5378
+ /* @__PURE__ */ jsx(Code, { block: true, children: list.config.personalization.emailBody })
5379
+ ] }) : null
5380
+ ] }) }),
5381
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5382
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Pipeline Steps" }),
5383
+ !pipelineSteps.length ? /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "This list does not have any configured pipeline steps yet." }) : /* @__PURE__ */ jsxs(Table, { children: [
5384
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5385
+ /* @__PURE__ */ jsx(Table.Th, { children: "Order" }),
5386
+ /* @__PURE__ */ jsx(Table.Th, { children: "Step" }),
5387
+ /* @__PURE__ */ jsx(Table.Th, { children: "Resource" }),
5388
+ /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
5389
+ /* @__PURE__ */ jsx(Table.Th, { children: "Action" })
5390
+ ] }) }),
5391
+ /* @__PURE__ */ jsx(Table.Tbody, { children: pipelineSteps.map((step) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
5392
+ /* @__PURE__ */ jsx(Table.Td, { children: step.order }),
5393
+ /* @__PURE__ */ jsxs(Table.Td, { children: [
5394
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: step.label }),
5395
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: step.key })
5396
+ ] }),
5397
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: step.resourceId }) }),
5398
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: step.enabled ? "light" : "outline", color: step.enabled ? "green" : "gray", children: step.enabled ? "Enabled" : "Disabled" }) }),
5399
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(
5400
+ Button,
5401
+ {
5402
+ size: "xs",
5403
+ variant: "light",
5404
+ leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 }),
5405
+ disabled: !step.enabled,
5406
+ onClick: () => setSelectedStepKey(step.key),
5407
+ children: "Run"
5408
+ }
5409
+ ) })
5410
+ ] }, step.key)) })
5411
+ ] })
5412
+ ] }) }),
5413
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5414
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Execution History" }),
5415
+ !executions.length ? /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconClockHour4, { size: 16 }), color: "gray", variant: "light", children: "No executions recorded for this list yet." }) : /* @__PURE__ */ jsxs(Table, { children: [
5416
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5417
+ /* @__PURE__ */ jsx(Table.Th, { children: "Resource" }),
5418
+ /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
5419
+ /* @__PURE__ */ jsx(Table.Th, { children: "Started" }),
5420
+ /* @__PURE__ */ jsx(Table.Th, { children: "Completed" }),
5421
+ /* @__PURE__ */ jsx(Table.Th, { children: "Duration" })
5422
+ ] }) }),
5423
+ /* @__PURE__ */ jsx(Table.Tbody, { children: executions.map((execution) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
5424
+ /* @__PURE__ */ jsxs(Table.Td, { children: [
5425
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: execution.resourceId }),
5426
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: execution.executionId })
5427
+ ] }),
5428
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor3(execution.status), children: execution.status }) }),
5429
+ /* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(execution.createdAt) }),
5430
+ /* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(execution.completedAt) }),
5431
+ /* @__PURE__ */ jsx(Table.Td, { children: execution.durationMs == null ? "n/a" : `${execution.durationMs} ms` })
5432
+ ] }, execution.executionId)) })
5433
+ ] })
5434
+ ] }) })
5435
+ ] }),
5436
+ selectedStep ? /* @__PURE__ */ jsx(
5437
+ ResourceExecuteDialog,
5438
+ {
5439
+ opened: !!selectedStep && !resourceDefinitionQuery.isLoading,
5440
+ onClose: () => setSelectedStepKey(null),
5441
+ resource: {
5442
+ resourceId: selectedStep.resourceId,
5443
+ resourceType: "workflow",
5444
+ name: selectedStep.label,
5445
+ formSchema: resourceDefinitionQuery.data?.interface?.form
5446
+ }
5447
+ }
5448
+ ) : null,
5449
+ /* @__PURE__ */ jsx(
5450
+ Modal,
5451
+ {
5452
+ opened: resourceDefinitionQuery.isLoading && !!selectedStep,
5453
+ onClose: () => setSelectedStepKey(null),
5454
+ withCloseButton: false,
5455
+ centered: true,
5456
+ children: /* @__PURE__ */ jsx(Center, { p: "md", children: /* @__PURE__ */ jsx(Loader, {}) })
5457
+ }
5458
+ )
5459
+ ] }) });
5460
+ }
5461
+ function LeadGenCompaniesPage() {
5462
+ return /* @__PURE__ */ jsx(
5463
+ LeadGenRouteShell,
5464
+ {
5465
+ title: "Companies",
5466
+ caption: "Shared lead-gen navigation shell",
5467
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [
5468
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Company records and enrichment workflows stay app-owned here." }),
5469
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "The shared Lead Gen package keeps this route reachable so the navigation stays aligned across the template and derived workspaces without pretending to own the data-heavy company table." })
5470
+ ] })
5471
+ }
5472
+ );
5473
+ }
5474
+ function LeadGenContactsPage() {
5475
+ return /* @__PURE__ */ jsx(
5476
+ LeadGenRouteShell,
5477
+ {
5478
+ title: "Contacts",
5479
+ caption: "Shared lead-gen navigation shell",
5480
+ body: /* @__PURE__ */ jsxs(Fragment, { children: [
5481
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Contact management stays app-owned here." }),
5482
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "The shared package preserves the route and sibling links so every workspace keeps the same lead-gen surface, even when the detailed contact experience remains local." })
5483
+ ] })
5484
+ }
5485
+ );
5486
+ }
4119
5487
  var SEOSidebarTop = () => {
4120
5488
  return /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSearch, label: "SEO" });
4121
5489
  };
@@ -4164,7 +5532,7 @@ function ringValue(completed, total) {
4164
5532
  if (total === 0) return 0;
4165
5533
  return Math.round(completed / total * 100);
4166
5534
  }
4167
- function formatDate2(iso) {
5535
+ function formatDate3(iso) {
4168
5536
  return new Date(iso).toLocaleDateString();
4169
5537
  }
4170
5538
  function daysRelative(targetEndDate) {
@@ -4252,17 +5620,17 @@ function HealthStatusCard({
4252
5620
  ] }),
4253
5621
  /* @__PURE__ */ jsx(Stack, { gap: 2, children: startDate && targetEndDate ? /* @__PURE__ */ jsxs(Fragment, { children: [
4254
5622
  /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
4255
- formatDate2(startDate),
5623
+ formatDate3(startDate),
4256
5624
  " \u2192 ",
4257
- formatDate2(targetEndDate)
5625
+ formatDate3(targetEndDate)
4258
5626
  ] }),
4259
5627
  timeInfo && /* @__PURE__ */ jsx(Text, { size: "xs", c: timeInfo.overdue ? "red" : "dimmed", children: timeInfo.label })
4260
5628
  ] }) : startDate ? /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
4261
5629
  "Started ",
4262
- formatDate2(startDate)
5630
+ formatDate3(startDate)
4263
5631
  ] }) : targetEndDate ? /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
4264
5632
  "Due ",
4265
- formatDate2(targetEndDate)
5633
+ formatDate3(targetEndDate)
4266
5634
  ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No dates set" }) })
4267
5635
  ] }) })
4268
5636
  ] });
@@ -4469,6 +5837,181 @@ var deliveryManifest = {
4469
5837
  sidebar: ProjectsSidebar,
4470
5838
  subshellRoutes: ["/projects"]
4471
5839
  };
5840
+ var STATUS_OPTIONS = [
5841
+ { value: "active", label: "Active" },
5842
+ { value: "on_track", label: "On Track" },
5843
+ { value: "at_risk", label: "At Risk" },
5844
+ { value: "blocked", label: "Blocked" },
5845
+ { value: "completed", label: "Completed" },
5846
+ { value: "paused", label: "Paused" }
5847
+ ];
5848
+ function ProjectsListPage({ onProjectClick } = {}) {
5849
+ const [statusFilter, setStatusFilter] = useState(null);
5850
+ const [searchQuery, setSearchQuery] = useState("");
5851
+ const [showBatchDelete, setShowBatchDelete] = useState(false);
5852
+ const { data: projects, isLoading, error } = useProjects();
5853
+ const deleteProject = useDeleteProject();
5854
+ const { sort, toggleSort } = useTableSort("updated");
5855
+ const filteredProjects = useMemo(() => {
5856
+ const source = projects ?? [];
5857
+ const query = searchQuery.trim().toLowerCase();
5858
+ return source.filter((project) => {
5859
+ const matchesStatus = !statusFilter || project.status === statusFilter;
5860
+ const matchesSearch = !query || project.name.toLowerCase().includes(query);
5861
+ return matchesStatus && matchesSearch;
5862
+ });
5863
+ }, [projects, searchQuery, statusFilter]);
5864
+ const sortAccessors2 = useMemo(
5865
+ () => ({
5866
+ name: (p) => p.name || "",
5867
+ status: (p) => p.status || "",
5868
+ updated: (p) => p.updated_at || ""
5869
+ }),
5870
+ []
5871
+ );
5872
+ const sortedProjects = useMemo(() => sortData(filteredProjects, sort, sortAccessors2), [filteredProjects, sort, sortAccessors2]);
5873
+ const pagination = usePaginationState(PAGE_SIZE_DEFAULT, [statusFilter, searchQuery], sortedProjects.length);
5874
+ const paginatedProjects = useMemo(
5875
+ () => sortedProjects.slice(pagination.offset, pagination.offset + PAGE_SIZE_DEFAULT),
5876
+ [sortedProjects, pagination.offset]
5877
+ );
5878
+ const selection = useTableSelection(paginatedProjects, sortedProjects);
5879
+ const handleDeleteSelected = async () => {
5880
+ await Promise.all([...selection.selectedIds].map((projectId) => deleteProject.mutateAsync(projectId)));
5881
+ setShowBatchDelete(false);
5882
+ selection.clear();
5883
+ };
5884
+ return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
5885
+ /* @__PURE__ */ jsxs(PageContainer, { children: [
5886
+ /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(PageTitleCaption, { title: "Projects", caption: "Client delivery tracking and milestone management" }) }),
5887
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { children: [
5888
+ /* @__PURE__ */ jsxs(
5889
+ FilterBar,
5890
+ {
5891
+ actions: /* @__PURE__ */ jsx(
5892
+ TableSelectionToolbar,
5893
+ {
5894
+ selectedCount: selection.selectedCount,
5895
+ onDelete: () => setShowBatchDelete(true),
5896
+ isDeleting: deleteProject.isPending
5897
+ }
5898
+ ),
5899
+ children: [
5900
+ /* @__PURE__ */ jsx(
5901
+ Select,
5902
+ {
5903
+ placeholder: "All Statuses",
5904
+ data: STATUS_OPTIONS,
5905
+ style: { minWidth: 180 },
5906
+ size: "sm",
5907
+ clearable: true,
5908
+ value: statusFilter,
5909
+ onChange: setStatusFilter
5910
+ }
5911
+ ),
5912
+ /* @__PURE__ */ jsx(
5913
+ TextInput,
5914
+ {
5915
+ placeholder: "Search by name...",
5916
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
5917
+ style: { minWidth: 250 },
5918
+ size: "sm",
5919
+ value: searchQuery,
5920
+ onChange: (e) => setSearchQuery(e.currentTarget.value)
5921
+ }
5922
+ )
5923
+ ]
5924
+ }
5925
+ ),
5926
+ isLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : error ? /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load projects" }) : !sortedProjects.length ? /* @__PURE__ */ jsx(EmptyState, { icon: IconBriefcase, title: "No projects found" }) : /* @__PURE__ */ jsxs(Table, { children: [
5927
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5928
+ /* @__PURE__ */ jsx(Table.Th, { w: 40, children: /* @__PURE__ */ jsx(
5929
+ Checkbox,
5930
+ {
5931
+ checked: selection.isPageAllSelected,
5932
+ indeterminate: selection.isPagePartiallySelected,
5933
+ onChange: selection.togglePage
5934
+ }
5935
+ ) }),
5936
+ /* @__PURE__ */ jsx(SortableHeader, { column: "name", sort, onToggle: toggleSort, children: "Name" }),
5937
+ /* @__PURE__ */ jsx(SortableHeader, { column: "status", sort, onToggle: toggleSort, children: "Status" }),
5938
+ /* @__PURE__ */ jsx(Table.Th, { children: "Milestones" }),
5939
+ /* @__PURE__ */ jsx(Table.Th, { children: "Tasks" }),
5940
+ /* @__PURE__ */ jsx(SortableHeader, { column: "updated", sort, onToggle: toggleSort, children: "Updated" })
5941
+ ] }) }),
5942
+ /* @__PURE__ */ jsx(Table.Tbody, { children: paginatedProjects.map((project) => {
5943
+ const rowProps = onProjectClick ? {
5944
+ style: { cursor: "pointer" },
5945
+ onClick: () => onProjectClick(project.id)
5946
+ } : void 0;
5947
+ return /* @__PURE__ */ jsxs(Table.Tr, { ...rowProps, children: [
5948
+ /* @__PURE__ */ jsx(Table.Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
5949
+ Checkbox,
5950
+ {
5951
+ checked: selection.isSelected(project.id),
5952
+ onChange: () => selection.toggle(project.id)
5953
+ }
5954
+ ) }),
5955
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: project.name }) }),
5956
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { variant: "light", color: projectStatusColors[project.status || ""] || "gray", size: "sm", children: formatStatusLabel(project.status || "unknown") }) }),
5957
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5958
+ project.completedMilestones ?? 0,
5959
+ "/",
5960
+ project.milestoneCount
5961
+ ] }) }),
5962
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5963
+ project.completedTasks ?? 0,
5964
+ "/",
5965
+ project.taskCount
5966
+ ] }) }),
5967
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatTimeAgo(project.updated_at) }) })
5968
+ ] }, project.id);
5969
+ }) })
5970
+ ] }),
5971
+ sortedProjects.length > PAGE_SIZE_DEFAULT && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(
5972
+ Pagination,
5973
+ {
5974
+ value: pagination.page,
5975
+ onChange: pagination.setPage,
5976
+ total: pagination.totalPages(sortedProjects.length),
5977
+ size: "sm"
5978
+ }
5979
+ ) })
5980
+ ] }) })
5981
+ ] }),
5982
+ /* @__PURE__ */ jsx(
5983
+ CustomModal,
5984
+ {
5985
+ opened: showBatchDelete,
5986
+ onClose: () => !deleteProject.isPending && setShowBatchDelete(false),
5987
+ size: "sm",
5988
+ loading: deleteProject.isPending,
5989
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5990
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
5991
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
5992
+ /* @__PURE__ */ jsxs(Title, { order: 4, children: [
5993
+ "Delete ",
5994
+ selection.selectedCount,
5995
+ " Projects"
5996
+ ] })
5997
+ ] }),
5998
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
5999
+ "Are you sure you want to delete",
6000
+ " ",
6001
+ /* @__PURE__ */ jsx(Text, { span: true, fw: 600, children: selection.selectedCount }),
6002
+ " ",
6003
+ "selected projects?"
6004
+ ] }),
6005
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone." }),
6006
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
6007
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: () => setShowBatchDelete(false), disabled: deleteProject.isPending, children: "Cancel" }),
6008
+ /* @__PURE__ */ jsx(Button, { color: "red", loading: deleteProject.isPending, onClick: () => void handleDeleteSelected(), children: "Delete" })
6009
+ ] })
6010
+ ] })
6011
+ }
6012
+ )
6013
+ ] });
6014
+ }
4472
6015
  function NotificationPanel({ notifications, isLoading, onClose, onNavigate }) {
4473
6016
  const markAllAsRead = useMarkAllAsRead();
4474
6017
  const hasUnread = notifications.some((n) => !n.read);
@@ -4521,4 +6064,4 @@ function NotificationBell({ unreadCount, onNavigate }) {
4521
6064
  ] });
4522
6065
  }
4523
6066
 
4524
- export { AbsoluteScheduleForm, ActivityFeedWidget, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CrashErrorFallback, CreateApiKeyModal, CreateScheduleModal, CrmOverview, CrmSidebar, CrmSidebarMiddle, CrmSidebarTop, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealDrawer, DealKanbanCard, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, DocTreeNav, EditApiKeyModal, ErrorReportCard, HealthStatusCard, KanbanBoard, KnowledgeBasePage, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, MdxRenderer, MetricsStrip, MilestoneTimeline, MyTasksPanel, NotificationBell, NotificationPanel, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, QuickCreateActions, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, SAVED_VIEW_PRESETS, SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, SavedViewsPanel, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, SortableHeader, TableSelectionToolbar, TaskCard, TaskScheduler, TasksDueWidget, buildErrorReport, calculateProgress, crmManifest, deliveryManifest, formatStatusLabel, leadGenManifest, mdxComponents, milestoneStatusColors, noteTypeColors, projectStatusColors, seoManifest, taskStatusColors, taskTypeColors, useCrmPipelineSummary, useCrmQuickMetrics, useRecentCrmActivity };
6067
+ export { AbsoluteScheduleForm, ActivityFeedWidget, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CrashErrorFallback, CreateApiKeyModal, CreateScheduleModal, CrmOverview, CrmSidebar, CrmSidebarMiddle, CrmSidebarTop, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealDetailPage, DealDrawer, DealKanbanCard, DealsListPage, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, DocTreeNav, EditApiKeyModal, ErrorReportCard, HealthStatusCard, KanbanBoard, KnowledgeBasePage, LEAD_GEN_ROUTE_LINKS, LIST_TEMPLATE_OPTIONS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenDeliverabilityPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, MdxRenderer, MetricsStrip, MilestoneTimeline, MyTasksPanel, NotificationBell, NotificationPanel, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, QuickCreateActions, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, SAVED_VIEW_PRESETS, SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, SavedViewsPanel, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, SortableHeader, TableSelectionToolbar, TaskCard, TaskScheduler, TasksDueWidget, buildErrorReport, buildListConfig, calculateProgress, crmManifest, deliveryManifest, formatStatusLabel, getEnrichmentColor, getStatusColor3 as getStatusColor, leadGenManifest, mdxComponents, milestoneStatusColors, noteTypeColors, projectStatusColors, seoManifest, taskStatusColors, taskTypeColors, useCrmPipelineSummary, useCrmQuickMetrics, useDeleteLists, useRecentCrmActivity };