@elevasis/ui 2.23.0 → 2.24.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.
- package/dist/app/index.d.ts +2915 -0
- package/dist/app/index.js +5 -4
- package/dist/{chunk-3HEUGBOT.js → chunk-2WZ635SS.js} +2 -2
- package/dist/{chunk-D3KQAABP.js → chunk-4NWNS7TX.js} +1 -1
- package/dist/{chunk-7PGEGSUM.js → chunk-FUEXGRFR.js} +2 -2
- package/dist/{chunk-6IA2OMAE.js → chunk-HC2KV6BU.js} +9 -0
- package/dist/{chunk-YU6MBDVO.js → chunk-KCJ6VATY.js} +4 -68
- package/dist/{chunk-FXWETLEB.js → chunk-KLFIJDTD.js} +1 -1
- package/dist/{chunk-PXGSJNBH.js → chunk-M2HWJY6O.js} +704 -375
- package/dist/{chunk-N6WLOWOD.js → chunk-MTR6AN2C.js} +3 -12
- package/dist/chunk-OWHQ65EQ.js +211 -0
- package/dist/{chunk-XOTJNW4Q.js → chunk-QIW6OCEI.js} +18 -1
- package/dist/{chunk-GUJUK6EH.js → chunk-QULLZ5PE.js} +172 -2
- package/dist/{chunk-QZJM3RYI.js → chunk-SNHGSCKH.js} +1 -1
- package/dist/{chunk-LVUCBY7X.js → chunk-UDJE54WN.js} +85 -3
- package/dist/{chunk-EPV7NU2E.js → chunk-VGNAV3TH.js} +385 -188
- package/dist/{chunk-PTUOINQ2.js → chunk-YBZT7MJR.js} +3 -3
- package/dist/{chunk-SQ5JGELM.js → chunk-ZDKQNQ4X.js} +19 -1
- package/dist/components/index.d.ts +488 -452
- package/dist/components/index.js +58 -22
- package/dist/components/navigation/index.js +2 -2
- package/dist/features/auth/index.d.ts +463 -377
- package/dist/features/crm/index.d.ts +459 -379
- package/dist/features/crm/index.js +8 -8
- package/dist/features/dashboard/index.js +8 -8
- package/dist/features/delivery/index.d.ts +457 -371
- package/dist/features/delivery/index.js +8 -8
- package/dist/features/lead-gen/index.d.ts +213 -65
- package/dist/features/lead-gen/index.js +9 -8
- package/dist/features/monitoring/index.js +9 -9
- package/dist/features/monitoring/requests/index.js +7 -7
- package/dist/features/operations/index.js +11 -10
- package/dist/features/settings/index.d.ts +463 -377
- package/dist/features/settings/index.js +9 -9
- package/dist/hooks/delivery/index.d.ts +457 -371
- package/dist/hooks/index.d.ts +936 -718
- package/dist/hooks/index.js +7 -7
- package/dist/hooks/published.d.ts +936 -718
- package/dist/hooks/published.js +7 -7
- package/dist/index.d.ts +1313 -1027
- package/dist/index.js +8 -8
- package/dist/initialization/index.d.ts +463 -377
- package/dist/organization/index.d.ts +11 -1
- package/dist/organization/index.js +2 -2
- package/dist/profile/index.d.ts +463 -377
- package/dist/provider/index.d.ts +3132 -169
- package/dist/provider/index.js +6 -6
- package/dist/provider/published.d.ts +3098 -168
- package/dist/provider/published.js +3 -3
- package/dist/supabase/index.d.ts +559 -389
- package/dist/test-utils/index.d.ts +21 -1
- package/dist/test-utils/index.js +13 -4
- package/dist/theme/index.js +2 -2
- package/dist/types/index.d.ts +463 -377
- package/package.json +4 -4
- package/src/test-utils/README.md +2 -0
- /package/dist/{chunk-ZBCTB5CA.js → chunk-EIOJNUPL.js} +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { LEAD_GEN_STAGE_CATALOG, LEAD_GEN_PIPELINE_DEFINITIONS, findPipeline } from './chunk-OWHQ65EQ.js';
|
|
1
2
|
import { PageContainer } from './chunk-BZZCNLT6.js';
|
|
2
3
|
import { TableSelectionToolbar, SortableHeader } from './chunk-TUMSNGTX.js';
|
|
3
4
|
import { SubshellNavItem } from './chunk-CEWTOKE7.js';
|
|
4
5
|
import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
|
|
5
6
|
import { FilterBar } from './chunk-PDHTXPSF.js';
|
|
6
7
|
import { CustomModal } from './chunk-KVJ3LFH2.js';
|
|
7
|
-
import { acquisitionListKeys, useListsTelemetry, useLists, useCreateList, useTableSort, sortData, usePaginationState, useTableSelection, useList, useListProgress, useListExecutions,
|
|
8
|
+
import { acquisitionListKeys, useListsTelemetry, useLists, useCreateList, useTableSort, sortData, usePaginationState, useTableSelection, useList, useListProgress, useListExecutions, useCompanyFacets, useCompanies, useDeleteCompanies, useContacts, useDeleteContacts, useArtifacts, useListMembers, useListMember, useTransitionListMember, useDeriveActions } from './chunk-QULLZ5PE.js';
|
|
8
9
|
import { showApiErrorNotification, showSuccessNotification } from './chunk-Z6FAH4XV.js';
|
|
9
10
|
import { SubshellContentContainer } from './chunk-TKAYX2SP.js';
|
|
10
|
-
import { PageTitleCaption, CenteredErrorState, StatCard, CardHeader, EmptyState } from './chunk-XUYBOO32.js';
|
|
11
|
+
import { PageTitleCaption, CenteredErrorState, StatCard, CardHeader, EmptyState, JsonViewer } from './chunk-XUYBOO32.js';
|
|
11
12
|
import { useRouterContext } from './chunk-Q7DJKLEN.js';
|
|
12
13
|
import { useElevasisServices } from './chunk-IRW7JMQ4.js';
|
|
13
|
-
import { Stack, Paper, Text, Anchor, Group, Title, ActionIcon, Divider, Box, SimpleGrid, Badge, Card, Button, Center, Loader, Alert, Table, TextInput, Checkbox, Pagination, Textarea,
|
|
14
|
-
import { IconLayoutGrid, IconList, IconBuilding, IconAddressBook, IconTarget, IconExternalLink, IconX, IconAlertCircle, IconPlayerPlay, IconArrowRight, IconSparkles, IconListDetails, IconPlus, IconSearch, IconAlertTriangle,
|
|
14
|
+
import { Stack, Paper, Text, Anchor, Group, Title, ActionIcon, Divider, Box, SimpleGrid, Badge, Card, Button, Center, Loader, Alert, Table, TextInput, Select, Checkbox, Pagination, Textarea, Tabs, SegmentedControl, Drawer, Progress } from '@mantine/core';
|
|
15
|
+
import { IconLayoutGrid, IconList, IconBuilding, IconAddressBook, IconTarget, IconExternalLink, IconX, IconAlertCircle, IconPlayerPlay, IconArrowRight, IconSparkles, IconListDetails, IconPlus, IconSearch, IconAlertTriangle, IconCopy, IconUsers, IconDatabase, IconBuildingFactory2, IconArrowLeft, IconChevronRight, IconMail, IconUser } from '@tabler/icons-react';
|
|
15
16
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
16
|
-
import { Link, useNavigate } from '@tanstack/react-router';
|
|
17
|
+
import { Link, useNavigate, useSearch } from '@tanstack/react-router';
|
|
17
18
|
import { useQueryClient, useMutation } from '@tanstack/react-query';
|
|
18
19
|
import { useState, useMemo, useEffect } from 'react';
|
|
19
20
|
|
|
@@ -89,6 +90,22 @@ function formatDate(dateValue) {
|
|
|
89
90
|
function getStatusColor(status) {
|
|
90
91
|
return status === "active" ? "green" : status === "invalid" ? "red" : "gray";
|
|
91
92
|
}
|
|
93
|
+
function getStateKeyColor(stateKey) {
|
|
94
|
+
switch (stateKey) {
|
|
95
|
+
case "draft":
|
|
96
|
+
return "gray";
|
|
97
|
+
case "enriching":
|
|
98
|
+
return "blue";
|
|
99
|
+
case "launched":
|
|
100
|
+
return "green";
|
|
101
|
+
case "closing":
|
|
102
|
+
return "yellow";
|
|
103
|
+
case "archived":
|
|
104
|
+
return "dimmed";
|
|
105
|
+
default:
|
|
106
|
+
return "gray";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
92
109
|
function getEnrichmentColor(status) {
|
|
93
110
|
switch (status) {
|
|
94
111
|
case "complete":
|
|
@@ -236,184 +253,6 @@ function ContactDetailModal({
|
|
|
236
253
|
] })
|
|
237
254
|
] }) : null });
|
|
238
255
|
}
|
|
239
|
-
var LIST_TEMPLATE_OPTIONS = [
|
|
240
|
-
{
|
|
241
|
-
value: "blank",
|
|
242
|
-
label: "Blank",
|
|
243
|
-
description: "Create an empty draft list with qualification defaults and no pipeline steps."
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
value: "full_pipeline",
|
|
247
|
-
label: "Full 6-Stage",
|
|
248
|
-
description: "Create a complete lead-gen pipeline from scrape through personalization."
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
value: "personalize_only",
|
|
252
|
-
label: "Personalize Only",
|
|
253
|
-
description: "Start with personalization and upload-focused steps for already-prepared contacts."
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
value: "email_refresh",
|
|
257
|
-
label: "Email Refresh",
|
|
258
|
-
description: "Run discovery, verification, and personalization for an existing company set."
|
|
259
|
-
}
|
|
260
|
-
];
|
|
261
|
-
function buildListConfig(template, targetDescription) {
|
|
262
|
-
const qualification = {
|
|
263
|
-
targetDescription,
|
|
264
|
-
minReviewCount: 5,
|
|
265
|
-
minRating: 4,
|
|
266
|
-
excludeFranchises: true,
|
|
267
|
-
customRules: ""
|
|
268
|
-
};
|
|
269
|
-
const personalization = {
|
|
270
|
-
industryContext: targetDescription,
|
|
271
|
-
emailBody: "",
|
|
272
|
-
creativeDirection: "",
|
|
273
|
-
exclusionRules: []
|
|
274
|
-
};
|
|
275
|
-
switch (template) {
|
|
276
|
-
case "full_pipeline":
|
|
277
|
-
return {
|
|
278
|
-
qualification,
|
|
279
|
-
enrichment: {
|
|
280
|
-
emailDiscovery: { primary: "tomba" },
|
|
281
|
-
emailVerification: { provider: "millionverifier", threshold: "ok" }
|
|
282
|
-
},
|
|
283
|
-
personalization,
|
|
284
|
-
pipeline: {
|
|
285
|
-
steps: [
|
|
286
|
-
{
|
|
287
|
-
key: "scrape",
|
|
288
|
-
label: "Scrape Companies",
|
|
289
|
-
resourceId: "lgn-01a-google-maps-scrape-workflow",
|
|
290
|
-
inputTemplate: {},
|
|
291
|
-
enabled: true,
|
|
292
|
-
order: 1
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
key: "acquire",
|
|
296
|
-
label: "Import Companies",
|
|
297
|
-
resourceId: "lgn-01b-apify-acquire-workflow",
|
|
298
|
-
inputTemplate: {},
|
|
299
|
-
enabled: true,
|
|
300
|
-
order: 2
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
key: "extract",
|
|
304
|
-
label: "Extract Website Data",
|
|
305
|
-
resourceId: "lgn-02-website-extract-workflow",
|
|
306
|
-
inputTemplate: {},
|
|
307
|
-
enabled: true,
|
|
308
|
-
order: 3
|
|
309
|
-
},
|
|
310
|
-
{
|
|
311
|
-
key: "qualify",
|
|
312
|
-
label: "Qualify Companies",
|
|
313
|
-
resourceId: "lgn-03-company-qualification-workflow",
|
|
314
|
-
inputTemplate: {},
|
|
315
|
-
enabled: true,
|
|
316
|
-
order: 4
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
key: "discover",
|
|
320
|
-
label: "Discover Emails",
|
|
321
|
-
resourceId: "lgn-04-email-discovery-workflow",
|
|
322
|
-
inputTemplate: {},
|
|
323
|
-
enabled: true,
|
|
324
|
-
order: 5
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
key: "verify",
|
|
328
|
-
label: "Verify Emails",
|
|
329
|
-
resourceId: "lgn-05-email-verification-workflow",
|
|
330
|
-
inputTemplate: {},
|
|
331
|
-
enabled: true,
|
|
332
|
-
order: 6
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
key: "personalize",
|
|
336
|
-
label: "Personalize Outreach",
|
|
337
|
-
resourceId: "ist-personalization-workflow",
|
|
338
|
-
inputTemplate: {},
|
|
339
|
-
enabled: true,
|
|
340
|
-
order: 7
|
|
341
|
-
}
|
|
342
|
-
]
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
case "personalize_only":
|
|
346
|
-
return {
|
|
347
|
-
qualification,
|
|
348
|
-
personalization,
|
|
349
|
-
pipeline: {
|
|
350
|
-
steps: [
|
|
351
|
-
{
|
|
352
|
-
key: "personalize",
|
|
353
|
-
label: "Personalize Outreach",
|
|
354
|
-
resourceId: "ist-personalization-workflow",
|
|
355
|
-
inputTemplate: {},
|
|
356
|
-
enabled: true,
|
|
357
|
-
order: 1
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
key: "upload",
|
|
361
|
-
label: "Upload Contacts",
|
|
362
|
-
resourceId: "ist-upload-contacts-workflow",
|
|
363
|
-
inputTemplate: { requireOpeningLine: true },
|
|
364
|
-
enabled: true,
|
|
365
|
-
order: 2
|
|
366
|
-
}
|
|
367
|
-
]
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
case "email_refresh":
|
|
371
|
-
return {
|
|
372
|
-
qualification,
|
|
373
|
-
enrichment: {
|
|
374
|
-
emailDiscovery: { primary: "tomba" },
|
|
375
|
-
emailVerification: { provider: "millionverifier", threshold: "ok" }
|
|
376
|
-
},
|
|
377
|
-
personalization,
|
|
378
|
-
pipeline: {
|
|
379
|
-
steps: [
|
|
380
|
-
{
|
|
381
|
-
key: "discover",
|
|
382
|
-
label: "Discover Emails",
|
|
383
|
-
resourceId: "lgn-04-email-discovery-workflow",
|
|
384
|
-
inputTemplate: {},
|
|
385
|
-
enabled: true,
|
|
386
|
-
order: 1
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
key: "verify",
|
|
390
|
-
label: "Verify Emails",
|
|
391
|
-
resourceId: "lgn-05-email-verification-workflow",
|
|
392
|
-
inputTemplate: {},
|
|
393
|
-
enabled: true,
|
|
394
|
-
order: 2
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
key: "personalize",
|
|
398
|
-
label: "Personalize Outreach",
|
|
399
|
-
resourceId: "ist-personalization-workflow",
|
|
400
|
-
inputTemplate: {},
|
|
401
|
-
enabled: true,
|
|
402
|
-
order: 3
|
|
403
|
-
}
|
|
404
|
-
]
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
case "blank":
|
|
408
|
-
default:
|
|
409
|
-
return {
|
|
410
|
-
qualification,
|
|
411
|
-
pipeline: {
|
|
412
|
-
steps: []
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
256
|
function useDeleteLists() {
|
|
418
257
|
const { apiRequest, organizationId } = useElevasisServices();
|
|
419
258
|
const queryClient = useQueryClient();
|
|
@@ -710,13 +549,22 @@ function LeadGenOverviewPage() {
|
|
|
710
549
|
] }) }) });
|
|
711
550
|
}
|
|
712
551
|
var PAGE_SIZE_DEFAULT = 20;
|
|
552
|
+
var STATUS_FILTER_OPTIONS = [
|
|
553
|
+
{ value: "", label: "All statuses" },
|
|
554
|
+
{ value: "draft", label: "Draft" },
|
|
555
|
+
{ value: "enriching", label: "Enriching" },
|
|
556
|
+
{ value: "launched", label: "Launched" },
|
|
557
|
+
{ value: "closing", label: "Closing" },
|
|
558
|
+
{ value: "archived", label: "Archived" }
|
|
559
|
+
];
|
|
713
560
|
function LeadGenListsPage() {
|
|
714
561
|
const navigate = useNavigate();
|
|
715
562
|
const [searchQuery, setSearchQuery] = useState("");
|
|
563
|
+
const [statusFilter, setStatusFilter] = useState("");
|
|
716
564
|
const [showCreateList, setShowCreateList] = useState(false);
|
|
717
565
|
const [newListName, setNewListName] = useState("");
|
|
718
566
|
const [newListDescription, setNewListDescription] = useState("");
|
|
719
|
-
const [
|
|
567
|
+
const [newRubricKey, setNewRubricKey] = useState("");
|
|
720
568
|
const [showBatchDelete, setShowBatchDelete] = useState(false);
|
|
721
569
|
const { data: lists, isLoading: listsLoading } = useLists();
|
|
722
570
|
const { data: telemetry, isLoading: telemetryLoading } = useListsTelemetry();
|
|
@@ -732,38 +580,46 @@ function LeadGenListsPage() {
|
|
|
732
580
|
name: (list) => list.name,
|
|
733
581
|
description: (list) => list.description || "",
|
|
734
582
|
contacts: (list) => contactCountByListId.get(list.id) ?? 0,
|
|
735
|
-
|
|
583
|
+
batches: (list) => list.batchIds.length,
|
|
584
|
+
created: (list) => list.createdAt,
|
|
585
|
+
status: (list) => list.status
|
|
736
586
|
}),
|
|
737
587
|
[contactCountByListId]
|
|
738
588
|
);
|
|
739
589
|
const filteredLists = useMemo(() => {
|
|
740
590
|
if (!lists) return [];
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
591
|
+
let result = lists;
|
|
592
|
+
if (searchQuery.trim()) {
|
|
593
|
+
const query = searchQuery.toLowerCase();
|
|
594
|
+
result = result.filter((list) => list.name.toLowerCase().includes(query));
|
|
595
|
+
}
|
|
596
|
+
if (statusFilter) {
|
|
597
|
+
result = result.filter((list) => list.status === statusFilter);
|
|
598
|
+
}
|
|
599
|
+
return result;
|
|
600
|
+
}, [lists, searchQuery, statusFilter]);
|
|
745
601
|
const sortedLists = useMemo(() => sortData(filteredLists, sort, sortAccessors), [filteredLists, sort, sortAccessors]);
|
|
746
|
-
const pagination = usePaginationState(PAGE_SIZE_DEFAULT, [searchQuery], sortedLists.length);
|
|
602
|
+
const pagination = usePaginationState(PAGE_SIZE_DEFAULT, [searchQuery, statusFilter], sortedLists.length);
|
|
747
603
|
const paginatedLists = useMemo(
|
|
748
604
|
() => sortedLists.slice(pagination.offset, pagination.offset + PAGE_SIZE_DEFAULT),
|
|
749
605
|
[sortedLists, pagination.offset]
|
|
750
606
|
);
|
|
751
607
|
const selection = useTableSelection(paginatedLists, sortedLists);
|
|
752
|
-
const selectedTemplateMeta = LIST_TEMPLATE_OPTIONS.find((option) => option.value === selectedTemplate);
|
|
753
608
|
function resetCreateListModal() {
|
|
754
609
|
setNewListName("");
|
|
755
610
|
setNewListDescription("");
|
|
756
|
-
|
|
611
|
+
setNewRubricKey("");
|
|
757
612
|
setShowCreateList(false);
|
|
758
613
|
}
|
|
759
614
|
function handleCreateList() {
|
|
760
615
|
const trimmedName = newListName.trim();
|
|
761
616
|
if (!trimmedName) return;
|
|
617
|
+
const trimmedRubric = newRubricKey.trim();
|
|
618
|
+
const icp = trimmedRubric ? { qualificationRubricKey: trimmedRubric } : void 0;
|
|
762
619
|
const body = {
|
|
763
620
|
name: trimmedName,
|
|
764
621
|
description: newListDescription.trim() || null,
|
|
765
|
-
|
|
766
|
-
config: buildListConfig(selectedTemplate, trimmedName)
|
|
622
|
+
...icp ? { icp } : {}
|
|
767
623
|
};
|
|
768
624
|
createListMutation.mutate(body, {
|
|
769
625
|
onSuccess: (list) => {
|
|
@@ -791,7 +647,7 @@ function LeadGenListsPage() {
|
|
|
791
647
|
}
|
|
792
648
|
) }),
|
|
793
649
|
/* @__PURE__ */ jsx(Paper, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
794
|
-
/* @__PURE__ */
|
|
650
|
+
/* @__PURE__ */ jsxs(
|
|
795
651
|
FilterBar,
|
|
796
652
|
{
|
|
797
653
|
actions: /* @__PURE__ */ jsx(
|
|
@@ -802,24 +658,38 @@ function LeadGenListsPage() {
|
|
|
802
658
|
isDeleting: deleteListsMutation.isPending
|
|
803
659
|
}
|
|
804
660
|
),
|
|
805
|
-
children:
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
661
|
+
children: [
|
|
662
|
+
/* @__PURE__ */ jsx(
|
|
663
|
+
TextInput,
|
|
664
|
+
{
|
|
665
|
+
placeholder: "Search by name...",
|
|
666
|
+
leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
|
|
667
|
+
value: searchQuery,
|
|
668
|
+
onChange: (e) => setSearchQuery(e.currentTarget.value)
|
|
669
|
+
}
|
|
670
|
+
),
|
|
671
|
+
/* @__PURE__ */ jsx(
|
|
672
|
+
Select,
|
|
673
|
+
{
|
|
674
|
+
placeholder: "All statuses",
|
|
675
|
+
data: STATUS_FILTER_OPTIONS,
|
|
676
|
+
value: statusFilter,
|
|
677
|
+
onChange: (value) => setStatusFilter(value ?? ""),
|
|
678
|
+
clearable: true,
|
|
679
|
+
size: "sm",
|
|
680
|
+
w: 160
|
|
681
|
+
}
|
|
682
|
+
)
|
|
683
|
+
]
|
|
814
684
|
}
|
|
815
685
|
),
|
|
816
686
|
listsLoading || telemetryLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : !filteredLists.length ? /* @__PURE__ */ jsx(
|
|
817
687
|
EmptyState,
|
|
818
688
|
{
|
|
819
689
|
icon: IconList,
|
|
820
|
-
title: searchQuery.trim() ? "No lists match your
|
|
821
|
-
description: searchQuery.trim() ? void 0 : "Create one to get started.",
|
|
822
|
-
action: searchQuery.trim() ? void 0 : {
|
|
690
|
+
title: searchQuery.trim() || statusFilter ? "No lists match your filters" : "No lists yet",
|
|
691
|
+
description: searchQuery.trim() || statusFilter ? void 0 : "Create one to get started.",
|
|
692
|
+
action: searchQuery.trim() || statusFilter ? void 0 : {
|
|
823
693
|
label: "Create List",
|
|
824
694
|
onClick: () => setShowCreateList(true),
|
|
825
695
|
icon: /* @__PURE__ */ jsx(IconPlus, { size: 16 })
|
|
@@ -837,24 +707,53 @@ function LeadGenListsPage() {
|
|
|
837
707
|
) }),
|
|
838
708
|
/* @__PURE__ */ jsx(SortableHeader, { column: "name", sort, onToggle: toggleSort, children: "Name" }),
|
|
839
709
|
/* @__PURE__ */ jsx(SortableHeader, { column: "description", sort, onToggle: toggleSort, children: "Description" }),
|
|
710
|
+
/* @__PURE__ */ jsx(SortableHeader, { column: "status", sort, onToggle: toggleSort, children: "Status" }),
|
|
711
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "ICP Rubric" }),
|
|
840
712
|
/* @__PURE__ */ jsx(SortableHeader, { column: "contacts", sort, onToggle: toggleSort, children: "Contacts" }),
|
|
713
|
+
/* @__PURE__ */ jsx(SortableHeader, { column: "batches", sort, onToggle: toggleSort, children: "Batches" }),
|
|
841
714
|
/* @__PURE__ */ jsx(SortableHeader, { column: "created", sort, onToggle: toggleSort, children: "Created" })
|
|
842
715
|
] }) }),
|
|
843
|
-
/* @__PURE__ */ jsx(Table.Tbody, { children: paginatedLists.map((list) =>
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
716
|
+
/* @__PURE__ */ jsx(Table.Tbody, { children: paginatedLists.map((list) => {
|
|
717
|
+
const rubricKey = list.icp?.qualificationRubricKey;
|
|
718
|
+
return /* @__PURE__ */ jsxs(
|
|
719
|
+
Table.Tr,
|
|
720
|
+
{
|
|
721
|
+
style: { cursor: "pointer" },
|
|
722
|
+
onClick: () => navigate({ to: "/lead-gen/lists/$listId", params: { listId: list.id } }),
|
|
723
|
+
children: [
|
|
724
|
+
/* @__PURE__ */ jsx(Table.Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
|
|
725
|
+
Checkbox,
|
|
726
|
+
{
|
|
727
|
+
checked: selection.isSelected(list.id),
|
|
728
|
+
onChange: () => selection.toggle(list.id)
|
|
729
|
+
}
|
|
730
|
+
) }),
|
|
731
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", children: [
|
|
732
|
+
/* @__PURE__ */ jsx(Text, { fw: 500, children: list.name }),
|
|
733
|
+
list.instantlyCampaignId ? /* @__PURE__ */ jsx(
|
|
734
|
+
Anchor,
|
|
735
|
+
{
|
|
736
|
+
href: `https://app.instantly.ai/app/campaign/${list.instantlyCampaignId}/analytics`,
|
|
737
|
+
target: "_blank",
|
|
738
|
+
rel: "noreferrer",
|
|
739
|
+
onClick: (e) => e.stopPropagation(),
|
|
740
|
+
c: "dimmed",
|
|
741
|
+
lh: 1,
|
|
742
|
+
children: /* @__PURE__ */ jsx(IconExternalLink, { size: 16 })
|
|
743
|
+
}
|
|
744
|
+
) : null
|
|
745
|
+
] }) }),
|
|
746
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: list.description || "-" }) }),
|
|
747
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", color: getStateKeyColor(list.status), variant: "light", children: list.status }) }),
|
|
748
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: rubricKey || "\u2014" }) }),
|
|
749
|
+
/* @__PURE__ */ jsx(Table.Td, { children: contactCountByListId.get(list.id) ?? 0 }),
|
|
750
|
+
/* @__PURE__ */ jsx(Table.Td, { children: list.batchIds.length }),
|
|
751
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDate(list.createdAt) }) })
|
|
752
|
+
]
|
|
753
|
+
},
|
|
754
|
+
list.id
|
|
755
|
+
);
|
|
756
|
+
}) })
|
|
858
757
|
] }),
|
|
859
758
|
sortedLists.length > PAGE_SIZE_DEFAULT && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(
|
|
860
759
|
Pagination,
|
|
@@ -901,20 +800,16 @@ function LeadGenListsPage() {
|
|
|
901
800
|
}
|
|
902
801
|
),
|
|
903
802
|
/* @__PURE__ */ jsx(
|
|
904
|
-
|
|
803
|
+
TextInput,
|
|
905
804
|
{
|
|
906
|
-
label: "
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
onChange: (value) => setSelectedTemplate(value ?? "full_pipeline"),
|
|
913
|
-
disabled: createListMutation.isPending,
|
|
914
|
-
allowDeselect: false
|
|
805
|
+
label: "ICP Rubric Key",
|
|
806
|
+
description: "Optional free-form text key identifying the qualification rubric for this list.",
|
|
807
|
+
placeholder: "e.g. smb-veterinary-us",
|
|
808
|
+
value: newRubricKey,
|
|
809
|
+
onChange: (event) => setNewRubricKey(event.currentTarget.value),
|
|
810
|
+
disabled: createListMutation.isPending
|
|
915
811
|
}
|
|
916
812
|
),
|
|
917
|
-
selectedTemplateMeta ? /* @__PURE__ */ jsx(Alert, { variant: "light", color: "blue", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: selectedTemplateMeta.description }) }) : null,
|
|
918
813
|
/* @__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." }),
|
|
919
814
|
/* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
|
|
920
815
|
/* @__PURE__ */ jsx(Button, { variant: "light", onClick: resetCreateListModal, disabled: createListMutation.isPending, children: "Cancel" }),
|
|
@@ -989,37 +884,554 @@ function formatDateTime(value) {
|
|
|
989
884
|
minute: "2-digit"
|
|
990
885
|
});
|
|
991
886
|
}
|
|
887
|
+
function resolveMemberStateLabel(member) {
|
|
888
|
+
const defs = LEAD_GEN_PIPELINE_DEFINITIONS["acq.list-member"];
|
|
889
|
+
if (!defs) return null;
|
|
890
|
+
const pipeline = findPipeline(defs, member.pipelineKey);
|
|
891
|
+
if (!pipeline) return null;
|
|
892
|
+
const stage = pipeline.stages.find((s) => s.stageKey === member.stageKey);
|
|
893
|
+
if (!stage) return null;
|
|
894
|
+
const state = stage.states.find((s) => s.stateKey === member.stateKey);
|
|
895
|
+
return {
|
|
896
|
+
stageLabel: stage.label,
|
|
897
|
+
stateLabel: state?.label ?? member.stateKey
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function getMemberStateColor(stateKey) {
|
|
901
|
+
switch (stateKey) {
|
|
902
|
+
case "personalized":
|
|
903
|
+
case "verified":
|
|
904
|
+
case "qualified":
|
|
905
|
+
case "interested":
|
|
906
|
+
return "green";
|
|
907
|
+
case "uploaded":
|
|
908
|
+
case "discovered":
|
|
909
|
+
case "extracted":
|
|
910
|
+
case "populated":
|
|
911
|
+
return "blue";
|
|
912
|
+
case "pending":
|
|
913
|
+
return "gray";
|
|
914
|
+
default:
|
|
915
|
+
return "gray";
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function ArtifactsPanel({ listMemberId }) {
|
|
919
|
+
const { data, isLoading, error } = useArtifacts({ ownerKind: "list_member", ownerId: listMemberId });
|
|
920
|
+
const artifacts = data?.artifacts ?? [];
|
|
921
|
+
if (isLoading) {
|
|
922
|
+
return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) });
|
|
923
|
+
}
|
|
924
|
+
if (error) {
|
|
925
|
+
return /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load artifacts" });
|
|
926
|
+
}
|
|
927
|
+
if (!artifacts.length) {
|
|
928
|
+
return /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconDatabase, { size: 16 }), color: "gray", variant: "light", children: "No artifacts recorded for this member yet." });
|
|
929
|
+
}
|
|
930
|
+
return /* @__PURE__ */ jsx(Stack, { gap: "sm", children: artifacts.map((artifact) => /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
|
|
931
|
+
/* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
|
|
932
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
933
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: "blue", children: artifact.kind }),
|
|
934
|
+
/* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
935
|
+
"v",
|
|
936
|
+
artifact.version
|
|
937
|
+
] })
|
|
938
|
+
] }),
|
|
939
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatDateTime(artifact.createdAt) })
|
|
940
|
+
] }),
|
|
941
|
+
/* @__PURE__ */ jsx(JsonViewer, { data: artifact.content, maxHeight: 240 })
|
|
942
|
+
] }) }, artifact.id)) });
|
|
943
|
+
}
|
|
944
|
+
function ListMemberDrawerContent({ member, listId }) {
|
|
945
|
+
const transitionMember = useTransitionListMember();
|
|
946
|
+
const statefulItem = useMemo(
|
|
947
|
+
() => ({
|
|
948
|
+
id: member.id,
|
|
949
|
+
pipeline_key: member.pipelineKey,
|
|
950
|
+
stage_key: member.stageKey,
|
|
951
|
+
state_key: member.stateKey,
|
|
952
|
+
activity_log: member.activityLog
|
|
953
|
+
}),
|
|
954
|
+
[member]
|
|
955
|
+
);
|
|
956
|
+
const derivedActions = useDeriveActions(statefulItem);
|
|
957
|
+
const resolved = resolveMemberStateLabel(member);
|
|
958
|
+
const contactName = [member.contact?.firstName, member.contact?.lastName].filter(Boolean).join(" ").trim() || member.contact?.email || "\u2014";
|
|
959
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "md", p: "md", children: [
|
|
960
|
+
/* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
|
|
961
|
+
/* @__PURE__ */ jsx(Group, { gap: "xs", align: "center", children: resolved ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
962
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: "blue", children: resolved.stageLabel }),
|
|
963
|
+
/* @__PURE__ */ jsx(IconChevronRight, { size: 14, style: { color: "var(--color-text-dimmed)" } }),
|
|
964
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "filled", color: getMemberStateColor(member.stateKey), children: resolved.stateLabel })
|
|
965
|
+
] }) : /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "filled", color: getMemberStateColor(member.stateKey), children: member.stateKey }) }),
|
|
966
|
+
/* @__PURE__ */ jsx(Title, { order: 4, children: contactName }),
|
|
967
|
+
member.contact?.email && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
968
|
+
/* @__PURE__ */ jsx(IconMail, { size: 14, style: { color: "var(--color-text-dimmed)" } }),
|
|
969
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: member.contact.email })
|
|
970
|
+
] }),
|
|
971
|
+
member.contact?.title && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
972
|
+
/* @__PURE__ */ jsx(IconUser, { size: 14, style: { color: "var(--color-text-dimmed)" } }),
|
|
973
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: member.contact.title })
|
|
974
|
+
] })
|
|
975
|
+
] }),
|
|
976
|
+
derivedActions.length > 0 && /* @__PURE__ */ jsx(Group, { gap: "xs", children: derivedActions.map((action) => /* @__PURE__ */ jsx(
|
|
977
|
+
Button,
|
|
978
|
+
{
|
|
979
|
+
variant: "light",
|
|
980
|
+
size: "xs",
|
|
981
|
+
loading: transitionMember.isPending,
|
|
982
|
+
onClick: () => {
|
|
983
|
+
transitionMember.mutate({
|
|
984
|
+
memberId: member.id,
|
|
985
|
+
listId,
|
|
986
|
+
pipelineKey: member.pipelineKey,
|
|
987
|
+
// Lead-gen action dispatch targets are resolved server-side via the action key.
|
|
988
|
+
// Stage/state keys are no longer embedded in the client-side Action shape.
|
|
989
|
+
stageKey: action.key,
|
|
990
|
+
stateKey: null
|
|
991
|
+
});
|
|
992
|
+
},
|
|
993
|
+
children: action.label
|
|
994
|
+
},
|
|
995
|
+
action.key
|
|
996
|
+
)) }),
|
|
997
|
+
/* @__PURE__ */ jsx(ArtifactsPanel, { listMemberId: member.id })
|
|
998
|
+
] });
|
|
999
|
+
}
|
|
1000
|
+
function CompanyMemberDrawerContent({ companyId: _companyId }) {
|
|
1001
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "md", p: "md", children: [
|
|
1002
|
+
/* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
|
|
1003
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: "gray", children: "company member" }),
|
|
1004
|
+
/* @__PURE__ */ jsx(Title, { order: 4, children: "Company" })
|
|
1005
|
+
] }),
|
|
1006
|
+
/* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "blue", variant: "light", children: "Company-level pipeline transitions are not yet available in this view." })
|
|
1007
|
+
] });
|
|
1008
|
+
}
|
|
1009
|
+
function ContactMemberDrawerShell({ contactId, listId }) {
|
|
1010
|
+
const { data: membersData, isLoading, error } = useListMembers({ listId });
|
|
1011
|
+
const listMember = useMemo(() => {
|
|
1012
|
+
if (!membersData?.members) return null;
|
|
1013
|
+
return membersData.members.find((m) => m.contactId === contactId) ?? null;
|
|
1014
|
+
}, [membersData, contactId]);
|
|
1015
|
+
const directQuery = useListMember(listMember === null && !isLoading ? contactId : "");
|
|
1016
|
+
const resolvedMember = listMember ?? directQuery.data ?? null;
|
|
1017
|
+
if (isLoading) {
|
|
1018
|
+
return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) });
|
|
1019
|
+
}
|
|
1020
|
+
if (error) {
|
|
1021
|
+
return /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load member detail" });
|
|
1022
|
+
}
|
|
1023
|
+
if (!resolvedMember) {
|
|
1024
|
+
return /* @__PURE__ */ jsx(Stack, { gap: "md", p: "md", children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "Member detail not found. The member may have been removed from this list." }) });
|
|
1025
|
+
}
|
|
1026
|
+
return /* @__PURE__ */ jsx(ListMemberDrawerContent, { member: resolvedMember, listId });
|
|
1027
|
+
}
|
|
1028
|
+
function ListMemberDrawer({ memberId, memberKind, listId, onClose }) {
|
|
1029
|
+
const opened = !!memberId && !!memberKind;
|
|
1030
|
+
return /* @__PURE__ */ jsxs(
|
|
1031
|
+
Drawer,
|
|
1032
|
+
{
|
|
1033
|
+
opened,
|
|
1034
|
+
onClose,
|
|
1035
|
+
position: "right",
|
|
1036
|
+
size: "lg",
|
|
1037
|
+
title: "Member Detail",
|
|
1038
|
+
styles: {
|
|
1039
|
+
body: { padding: 0 }
|
|
1040
|
+
},
|
|
1041
|
+
children: [
|
|
1042
|
+
opened && memberId && memberKind === "contact" && /* @__PURE__ */ jsx(ContactMemberDrawerShell, { contactId: memberId, listId }),
|
|
1043
|
+
opened && memberId && memberKind === "company" && /* @__PURE__ */ jsx(CompanyMemberDrawerContent, { companyId: memberId })
|
|
1044
|
+
]
|
|
1045
|
+
}
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
function formatDateTime2(value) {
|
|
1049
|
+
if (!value) return "Not yet";
|
|
1050
|
+
return new Date(value).toLocaleString("en-US", {
|
|
1051
|
+
month: "short",
|
|
1052
|
+
day: "numeric",
|
|
1053
|
+
year: "numeric",
|
|
1054
|
+
hour: "numeric",
|
|
1055
|
+
minute: "2-digit"
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
992
1058
|
function contactDisplayName(firstName, lastName) {
|
|
993
1059
|
const full = [firstName, lastName].filter(Boolean).join(" ").trim();
|
|
994
1060
|
return full || "\u2014";
|
|
995
1061
|
}
|
|
1062
|
+
function getStatusColor2(status) {
|
|
1063
|
+
switch (status) {
|
|
1064
|
+
case "draft":
|
|
1065
|
+
return "gray";
|
|
1066
|
+
case "enriching":
|
|
1067
|
+
return "blue";
|
|
1068
|
+
case "launched":
|
|
1069
|
+
return "green";
|
|
1070
|
+
case "closing":
|
|
1071
|
+
return "yellow";
|
|
1072
|
+
case "archived":
|
|
1073
|
+
return "red";
|
|
1074
|
+
default:
|
|
1075
|
+
return "gray";
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function getMemberStateColor2(stateKey) {
|
|
1079
|
+
switch (stateKey) {
|
|
1080
|
+
case "personalized":
|
|
1081
|
+
case "verified":
|
|
1082
|
+
case "qualified":
|
|
1083
|
+
case "interested":
|
|
1084
|
+
return "green";
|
|
1085
|
+
case "uploaded":
|
|
1086
|
+
case "discovered":
|
|
1087
|
+
case "extracted":
|
|
1088
|
+
case "populated":
|
|
1089
|
+
return "blue";
|
|
1090
|
+
case "pending":
|
|
1091
|
+
return "gray";
|
|
1092
|
+
default:
|
|
1093
|
+
return "gray";
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
var ORPHAN_STAGE_ORDER = 9999;
|
|
1097
|
+
function sortStageKeys(keys) {
|
|
1098
|
+
return keys.slice().sort((a, b) => {
|
|
1099
|
+
const oa = LEAD_GEN_STAGE_CATALOG[a]?.order ?? ORPHAN_STAGE_ORDER;
|
|
1100
|
+
const ob = LEAD_GEN_STAGE_CATALOG[b]?.order ?? ORPHAN_STAGE_ORDER;
|
|
1101
|
+
return oa - ob || a.localeCompare(b);
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
function PipelineSection({
|
|
1105
|
+
title,
|
|
1106
|
+
byStage,
|
|
1107
|
+
emptyText
|
|
1108
|
+
}) {
|
|
1109
|
+
const orderedKeys = sortStageKeys(Object.keys(byStage));
|
|
1110
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
|
|
1111
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: title }),
|
|
1112
|
+
orderedKeys.length === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: emptyText }) : /* @__PURE__ */ jsx(Stack, { gap: "xs", children: orderedKeys.map((key) => {
|
|
1113
|
+
const entry = byStage[key];
|
|
1114
|
+
const done = entry?.done ?? 0;
|
|
1115
|
+
const total = entry?.total ?? 0;
|
|
1116
|
+
const percent = total > 0 ? Math.round(done / total * 100) : 0;
|
|
1117
|
+
const label = LEAD_GEN_STAGE_CATALOG[key]?.label ?? key;
|
|
1118
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
|
|
1119
|
+
/* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
|
|
1120
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: label }),
|
|
1121
|
+
/* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1122
|
+
done,
|
|
1123
|
+
" / ",
|
|
1124
|
+
total,
|
|
1125
|
+
" (",
|
|
1126
|
+
percent,
|
|
1127
|
+
"%)"
|
|
1128
|
+
] })
|
|
1129
|
+
] }),
|
|
1130
|
+
/* @__PURE__ */ jsx(Progress, { value: percent, size: "sm", color: getMemberStateColor2(key) })
|
|
1131
|
+
] }, key);
|
|
1132
|
+
}) })
|
|
1133
|
+
] });
|
|
1134
|
+
}
|
|
1135
|
+
function PipelineStagesCard({ list, progress }) {
|
|
1136
|
+
const hasAnyActivity = Object.keys(progress.byCompanyStage).length > 0 || Object.keys(progress.byContactStage).length > 0;
|
|
1137
|
+
return /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
|
|
1138
|
+
/* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
|
|
1139
|
+
/* @__PURE__ */ jsx(Title, { order: 5, children: "Pipeline Stages" }),
|
|
1140
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1141
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "filled", color: getStatusColor2(list.status), children: list.status }),
|
|
1142
|
+
list.launchedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1143
|
+
"Launched ",
|
|
1144
|
+
formatDateTime2(list.launchedAt)
|
|
1145
|
+
] }),
|
|
1146
|
+
list.completedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1147
|
+
"Completed ",
|
|
1148
|
+
formatDateTime2(list.completedAt)
|
|
1149
|
+
] })
|
|
1150
|
+
] })
|
|
1151
|
+
] }),
|
|
1152
|
+
!hasAnyActivity ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No pipeline activity yet \u2014 stages appear here as workflows write processing_state flags." }) : /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
|
|
1153
|
+
/* @__PURE__ */ jsx(
|
|
1154
|
+
PipelineSection,
|
|
1155
|
+
{
|
|
1156
|
+
title: `Company Pipeline (${progress.totalCompanies})`,
|
|
1157
|
+
byStage: progress.byCompanyStage,
|
|
1158
|
+
emptyText: "No company-stage flags recorded yet."
|
|
1159
|
+
}
|
|
1160
|
+
),
|
|
1161
|
+
/* @__PURE__ */ jsx(
|
|
1162
|
+
PipelineSection,
|
|
1163
|
+
{
|
|
1164
|
+
title: `Contact Pipeline (${progress.totalMembers})`,
|
|
1165
|
+
byStage: progress.byContactStage,
|
|
1166
|
+
emptyText: "No contact-stage flags recorded yet."
|
|
1167
|
+
}
|
|
1168
|
+
)
|
|
1169
|
+
] })
|
|
1170
|
+
] }) });
|
|
1171
|
+
}
|
|
1172
|
+
function ListConfigCard({ list }) {
|
|
1173
|
+
const icp = list.icp ?? {};
|
|
1174
|
+
const scraping = list.scrapingConfig ?? {};
|
|
1175
|
+
const hasIcp = Object.values(icp).some((v) => v !== void 0 && v !== null && v !== "");
|
|
1176
|
+
const hasScraping = Object.values(scraping).some((v) => v !== void 0 && v !== null && v !== "");
|
|
1177
|
+
if (!hasIcp && !hasScraping) {
|
|
1178
|
+
return /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
|
|
1179
|
+
/* @__PURE__ */ jsx(Title, { order: 5, children: "List Config" }),
|
|
1180
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No ICP rubric or scraping criteria configured for this list." })
|
|
1181
|
+
] }) });
|
|
1182
|
+
}
|
|
1183
|
+
return /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
|
|
1184
|
+
/* @__PURE__ */ jsx(Title, { order: 5, children: "List Config" }),
|
|
1185
|
+
/* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
|
|
1186
|
+
hasIcp && /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
|
|
1187
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: "ICP Rubric" }),
|
|
1188
|
+
icp.qualificationRubricKey && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1189
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Rubric Key" }),
|
|
1190
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: icp.qualificationRubricKey })
|
|
1191
|
+
] }),
|
|
1192
|
+
icp.targetDescription && /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
|
|
1193
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Target" }),
|
|
1194
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: icp.targetDescription })
|
|
1195
|
+
] }),
|
|
1196
|
+
(icp.minReviewCount !== void 0 || icp.minRating !== void 0) && /* @__PURE__ */ jsxs(Group, { gap: "md", children: [
|
|
1197
|
+
icp.minReviewCount !== void 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1198
|
+
"Min reviews:",
|
|
1199
|
+
" ",
|
|
1200
|
+
/* @__PURE__ */ jsx(Text, { span: true, size: "xs", c: "bright", children: icp.minReviewCount })
|
|
1201
|
+
] }),
|
|
1202
|
+
icp.minRating !== void 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1203
|
+
"Min rating:",
|
|
1204
|
+
" ",
|
|
1205
|
+
/* @__PURE__ */ jsx(Text, { span: true, size: "xs", c: "bright", children: icp.minRating })
|
|
1206
|
+
] })
|
|
1207
|
+
] }),
|
|
1208
|
+
icp.excludeFranchises !== void 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1209
|
+
"Exclude franchises:",
|
|
1210
|
+
" ",
|
|
1211
|
+
/* @__PURE__ */ jsx(Text, { span: true, size: "xs", c: "bright", children: String(icp.excludeFranchises) })
|
|
1212
|
+
] }),
|
|
1213
|
+
icp.customRules && /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
|
|
1214
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Custom rules" }),
|
|
1215
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: icp.customRules })
|
|
1216
|
+
] })
|
|
1217
|
+
] }),
|
|
1218
|
+
hasScraping && /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
|
|
1219
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: "Scraping Criteria" }),
|
|
1220
|
+
scraping.vertical && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1221
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Vertical" }),
|
|
1222
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: scraping.vertical })
|
|
1223
|
+
] }),
|
|
1224
|
+
scraping.geography && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1225
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Geography" }),
|
|
1226
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: scraping.geography })
|
|
1227
|
+
] }),
|
|
1228
|
+
scraping.size && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1229
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Size" }),
|
|
1230
|
+
/* @__PURE__ */ jsx(Text, { size: "sm", children: scraping.size })
|
|
1231
|
+
] }),
|
|
1232
|
+
scraping.apifyInput && Object.keys(scraping.apifyInput).length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
|
|
1233
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Apify input" }),
|
|
1234
|
+
/* @__PURE__ */ jsx(JsonViewer, { data: scraping.apifyInput, maxHeight: 160, fontSize: "0.75rem" })
|
|
1235
|
+
] })
|
|
1236
|
+
] })
|
|
1237
|
+
] })
|
|
1238
|
+
] }) });
|
|
1239
|
+
}
|
|
1240
|
+
function OverviewTab({ list, progress }) {
|
|
1241
|
+
const hasMetadata = list.metadata && Object.keys(list.metadata).length > 0;
|
|
1242
|
+
return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
|
|
1243
|
+
/* @__PURE__ */ jsx(PipelineStagesCard, { list, progress }),
|
|
1244
|
+
/* @__PURE__ */ jsx(ListConfigCard, { list }),
|
|
1245
|
+
/* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
|
|
1246
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Companies", value: progress.totalCompanies, icon: IconBuilding }),
|
|
1247
|
+
/* @__PURE__ */ jsx(StatCard, { label: "Members", value: progress.totalMembers, icon: IconUsers })
|
|
1248
|
+
] }),
|
|
1249
|
+
hasMetadata && /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
|
|
1250
|
+
/* @__PURE__ */ jsx(Title, { order: 5, children: "Metadata / Qualification Signals" }),
|
|
1251
|
+
/* @__PURE__ */ jsx(JsonViewer, { data: list.metadata, maxHeight: 320 })
|
|
1252
|
+
] }) })
|
|
1253
|
+
] });
|
|
1254
|
+
}
|
|
1255
|
+
function MembersTab({
|
|
1256
|
+
listId,
|
|
1257
|
+
progress,
|
|
1258
|
+
onMemberClick
|
|
1259
|
+
}) {
|
|
1260
|
+
const [memberTab, setMemberTab] = useState("contacts");
|
|
1261
|
+
const contactsQuery = useContacts({ listId, limit: 100, offset: 0 });
|
|
1262
|
+
const companiesQuery = useCompanies({ listId, limit: 100, offset: 0 });
|
|
1263
|
+
const contacts = contactsQuery.data?.data ?? [];
|
|
1264
|
+
const companies = companiesQuery.data?.data ?? [];
|
|
1265
|
+
return /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
|
|
1266
|
+
/* @__PURE__ */ jsx(
|
|
1267
|
+
CardHeader,
|
|
1268
|
+
{
|
|
1269
|
+
icon: /* @__PURE__ */ jsx(IconAddressBook, { size: 16 }),
|
|
1270
|
+
title: "Members",
|
|
1271
|
+
rightSection: /* @__PURE__ */ jsx(
|
|
1272
|
+
SegmentedControl,
|
|
1273
|
+
{
|
|
1274
|
+
value: memberTab,
|
|
1275
|
+
onChange: (value) => setMemberTab(value),
|
|
1276
|
+
size: "xs",
|
|
1277
|
+
data: [
|
|
1278
|
+
{ label: `Members (${progress.totalMembers})`, value: "contacts" },
|
|
1279
|
+
{ label: `Companies (${progress.totalCompanies})`, value: "companies" }
|
|
1280
|
+
]
|
|
1281
|
+
}
|
|
1282
|
+
)
|
|
1283
|
+
}
|
|
1284
|
+
),
|
|
1285
|
+
memberTab === "contacts" && /* @__PURE__ */ jsx(Fragment, { children: contactsQuery.isLoading ? /* @__PURE__ */ jsx(Center, { p: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : !contacts.length ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No contacts attached to this list yet." }) : /* @__PURE__ */ jsxs(Table, { highlightOnHover: true, children: [
|
|
1286
|
+
/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1287
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Name" }),
|
|
1288
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Email" }),
|
|
1289
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Title" }),
|
|
1290
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Company" }),
|
|
1291
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
|
|
1292
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "State" }),
|
|
1293
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Created" })
|
|
1294
|
+
] }) }),
|
|
1295
|
+
/* @__PURE__ */ jsx(Table.Tbody, { children: contacts.map((contact) => {
|
|
1296
|
+
const handleRowClick = () => onMemberClick?.(contact.id, "contact");
|
|
1297
|
+
const memberState = contact.stateKey ?? null;
|
|
1298
|
+
return /* @__PURE__ */ jsxs(Table.Tr, { onClick: handleRowClick, style: { cursor: "pointer" }, children: [
|
|
1299
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: contactDisplayName(contact.firstName, contact.lastName) }) }),
|
|
1300
|
+
/* @__PURE__ */ jsx(Table.Td, { children: contact.email }),
|
|
1301
|
+
/* @__PURE__ */ jsx(Table.Td, { children: contact.title ?? "\u2014" }),
|
|
1302
|
+
/* @__PURE__ */ jsx(Table.Td, { children: contact.company?.name ?? "\u2014" }),
|
|
1303
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor2(contact.status), children: contact.status }) }),
|
|
1304
|
+
/* @__PURE__ */ jsx(Table.Td, { children: memberState ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberState), children: memberState }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
|
|
1305
|
+
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(contact.createdAt) })
|
|
1306
|
+
] }, contact.id);
|
|
1307
|
+
}) })
|
|
1308
|
+
] }) }),
|
|
1309
|
+
memberTab === "companies" && /* @__PURE__ */ jsx(Fragment, { children: companiesQuery.isLoading ? /* @__PURE__ */ jsx(Center, { p: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : !companies.length ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No companies attached to this list yet." }) : /* @__PURE__ */ jsxs(Table, { highlightOnHover: true, children: [
|
|
1310
|
+
/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1311
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Name" }),
|
|
1312
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Domain" }),
|
|
1313
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Segment" }),
|
|
1314
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Contacts" }),
|
|
1315
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
|
|
1316
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "State" }),
|
|
1317
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Created" })
|
|
1318
|
+
] }) }),
|
|
1319
|
+
/* @__PURE__ */ jsx(Table.Tbody, { children: companies.map((company) => {
|
|
1320
|
+
const handleRowClick = () => onMemberClick?.(company.id, "company");
|
|
1321
|
+
const memberState = company.stateKey ?? null;
|
|
1322
|
+
return /* @__PURE__ */ jsxs(Table.Tr, { onClick: handleRowClick, style: { cursor: "pointer" }, children: [
|
|
1323
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: company.name }) }),
|
|
1324
|
+
/* @__PURE__ */ jsx(Table.Td, { children: company.domain ?? "\u2014" }),
|
|
1325
|
+
/* @__PURE__ */ jsx(Table.Td, { children: company.segment ?? "\u2014" }),
|
|
1326
|
+
/* @__PURE__ */ jsx(Table.Td, { children: company.contactCount }),
|
|
1327
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor2(company.status), children: company.status }) }),
|
|
1328
|
+
/* @__PURE__ */ jsx(Table.Td, { children: memberState ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberState), children: memberState }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
|
|
1329
|
+
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(company.createdAt) })
|
|
1330
|
+
] }, company.id);
|
|
1331
|
+
}) })
|
|
1332
|
+
] }) })
|
|
1333
|
+
] });
|
|
1334
|
+
}
|
|
1335
|
+
function ArtifactsTab({ listId }) {
|
|
1336
|
+
const { data, isLoading, error } = useArtifacts({ ownerKind: "list", ownerId: listId });
|
|
1337
|
+
const artifacts = data?.artifacts ?? [];
|
|
1338
|
+
if (isLoading) {
|
|
1339
|
+
return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) });
|
|
1340
|
+
}
|
|
1341
|
+
if (error) {
|
|
1342
|
+
return /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load artifacts" });
|
|
1343
|
+
}
|
|
1344
|
+
if (!artifacts.length) {
|
|
1345
|
+
return /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconDatabase, { size: 16 }), color: "gray", variant: "light", children: "No artifacts recorded for this list yet." });
|
|
1346
|
+
}
|
|
1347
|
+
return /* @__PURE__ */ jsx(Stack, { gap: "sm", children: artifacts.map((artifact) => /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
|
|
1348
|
+
/* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
|
|
1349
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1350
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: "blue", children: artifact.kind }),
|
|
1351
|
+
/* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
|
|
1352
|
+
"v",
|
|
1353
|
+
artifact.version
|
|
1354
|
+
] })
|
|
1355
|
+
] }),
|
|
1356
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatDateTime2(artifact.createdAt) })
|
|
1357
|
+
] }),
|
|
1358
|
+
/* @__PURE__ */ jsx(JsonViewer, { data: artifact.content, maxHeight: 240 })
|
|
1359
|
+
] }) }, artifact.id)) });
|
|
1360
|
+
}
|
|
1361
|
+
function ExecutionHistorySection({
|
|
1362
|
+
executions
|
|
1363
|
+
}) {
|
|
1364
|
+
if (!executions.length) {
|
|
1365
|
+
return /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No executions recorded for this list yet." });
|
|
1366
|
+
}
|
|
1367
|
+
return /* @__PURE__ */ jsxs(Table, { children: [
|
|
1368
|
+
/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1369
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Resource" }),
|
|
1370
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
|
|
1371
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Started" }),
|
|
1372
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Completed" }),
|
|
1373
|
+
/* @__PURE__ */ jsx(Table.Th, { children: "Duration" })
|
|
1374
|
+
] }) }),
|
|
1375
|
+
/* @__PURE__ */ jsx(Table.Tbody, { children: executions.map((execution) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1376
|
+
/* @__PURE__ */ jsxs(Table.Td, { children: [
|
|
1377
|
+
/* @__PURE__ */ jsx(Text, { fw: 500, children: execution.resourceId }),
|
|
1378
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: execution.executionId })
|
|
1379
|
+
] }),
|
|
1380
|
+
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor2(execution.status), children: execution.status }) }),
|
|
1381
|
+
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(execution.createdAt) }),
|
|
1382
|
+
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime2(execution.completedAt) }),
|
|
1383
|
+
/* @__PURE__ */ jsx(Table.Td, { children: execution.durationMs == null ? "n/a" : `${execution.durationMs} ms` })
|
|
1384
|
+
] }, execution.executionId)) })
|
|
1385
|
+
] });
|
|
1386
|
+
}
|
|
1387
|
+
function ListDetailHeader({
|
|
1388
|
+
title,
|
|
1389
|
+
caption,
|
|
1390
|
+
rightSection
|
|
1391
|
+
}) {
|
|
1392
|
+
return /* @__PURE__ */ jsx(PageTitleCaption, { title, caption, rightSection });
|
|
1393
|
+
}
|
|
996
1394
|
function LeadGenListDetailPage({ listId }) {
|
|
997
1395
|
const navigate = useNavigate();
|
|
1396
|
+
const rawSearch = useSearch({ strict: false });
|
|
1397
|
+
const memberId = rawSearch.member ?? null;
|
|
1398
|
+
const memberKind = rawSearch.memberKind ?? null;
|
|
1399
|
+
const handleMemberClick = (id, kind) => {
|
|
1400
|
+
const params = new URLSearchParams(window.location.search);
|
|
1401
|
+
params.set("member", id);
|
|
1402
|
+
params.set("memberKind", kind);
|
|
1403
|
+
window.history.pushState(null, "", `${window.location.pathname}?${params.toString()}`);
|
|
1404
|
+
};
|
|
1405
|
+
const handleDrawerClose = () => {
|
|
1406
|
+
const params = new URLSearchParams(window.location.search);
|
|
1407
|
+
params.delete("member");
|
|
1408
|
+
params.delete("memberKind");
|
|
1409
|
+
const qs = params.toString();
|
|
1410
|
+
window.history.pushState(null, "", qs ? `${window.location.pathname}?${qs}` : window.location.pathname);
|
|
1411
|
+
};
|
|
998
1412
|
const listQuery = useList(listId);
|
|
999
1413
|
const progressQuery = useListProgress(listId);
|
|
1000
1414
|
const executionsQuery = useListExecutions(listId);
|
|
1001
|
-
const contactsQuery = useContacts({ listId, limit: 100, offset: 0 });
|
|
1002
|
-
const companiesQuery = useCompanies({ listId, limit: 100, offset: 0 });
|
|
1003
|
-
const [memberTab, setMemberTab] = useState("contacts");
|
|
1004
1415
|
const isLoading = listQuery.isLoading || progressQuery.isLoading || executionsQuery.isLoading;
|
|
1005
1416
|
const error = listQuery.error ?? progressQuery.error ?? executionsQuery.error;
|
|
1417
|
+
const backButton = /* @__PURE__ */ jsx(
|
|
1418
|
+
Button,
|
|
1419
|
+
{
|
|
1420
|
+
variant: "light",
|
|
1421
|
+
size: "xs",
|
|
1422
|
+
leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
|
|
1423
|
+
onClick: () => navigate({ to: "/lead-gen/lists" }),
|
|
1424
|
+
children: "Lists"
|
|
1425
|
+
}
|
|
1426
|
+
);
|
|
1006
1427
|
if (isLoading) {
|
|
1007
1428
|
return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
1008
1429
|
/* @__PURE__ */ jsx(
|
|
1009
|
-
|
|
1430
|
+
ListDetailHeader,
|
|
1010
1431
|
{
|
|
1011
1432
|
title: "List Detail",
|
|
1012
1433
|
caption: "Configuration, progress, and execution history for a single lead-gen list",
|
|
1013
|
-
rightSection:
|
|
1014
|
-
Button,
|
|
1015
|
-
{
|
|
1016
|
-
variant: "light",
|
|
1017
|
-
size: "xs",
|
|
1018
|
-
leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
|
|
1019
|
-
onClick: () => navigate({ to: "/lead-gen/lists" }),
|
|
1020
|
-
children: "Lists"
|
|
1021
|
-
}
|
|
1022
|
-
)
|
|
1434
|
+
rightSection: backButton
|
|
1023
1435
|
}
|
|
1024
1436
|
),
|
|
1025
1437
|
/* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) })
|
|
@@ -1028,20 +1440,11 @@ function LeadGenListDetailPage({ listId }) {
|
|
|
1028
1440
|
if (error) {
|
|
1029
1441
|
return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
1030
1442
|
/* @__PURE__ */ jsx(
|
|
1031
|
-
|
|
1443
|
+
ListDetailHeader,
|
|
1032
1444
|
{
|
|
1033
1445
|
title: "List Detail",
|
|
1034
1446
|
caption: "Configuration, progress, and execution history for a single lead-gen list",
|
|
1035
|
-
rightSection:
|
|
1036
|
-
Button,
|
|
1037
|
-
{
|
|
1038
|
-
variant: "light",
|
|
1039
|
-
size: "xs",
|
|
1040
|
-
leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
|
|
1041
|
-
onClick: () => navigate({ to: "/lead-gen/lists" }),
|
|
1042
|
-
children: "Lists"
|
|
1043
|
-
}
|
|
1044
|
-
)
|
|
1447
|
+
rightSection: backButton
|
|
1045
1448
|
}
|
|
1046
1449
|
),
|
|
1047
1450
|
/* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load list detail" }) })
|
|
@@ -1050,20 +1453,11 @@ function LeadGenListDetailPage({ listId }) {
|
|
|
1050
1453
|
if (!listQuery.data || !progressQuery.data) {
|
|
1051
1454
|
return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
1052
1455
|
/* @__PURE__ */ jsx(
|
|
1053
|
-
|
|
1456
|
+
ListDetailHeader,
|
|
1054
1457
|
{
|
|
1055
1458
|
title: "List Not Found",
|
|
1056
1459
|
caption: "The requested lead-gen list is unavailable.",
|
|
1057
|
-
rightSection:
|
|
1058
|
-
Button,
|
|
1059
|
-
{
|
|
1060
|
-
variant: "light",
|
|
1061
|
-
size: "xs",
|
|
1062
|
-
leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
|
|
1063
|
-
onClick: () => navigate({ to: "/lead-gen/lists" }),
|
|
1064
|
-
children: "Lists"
|
|
1065
|
-
}
|
|
1066
|
-
)
|
|
1460
|
+
rightSection: backButton
|
|
1067
1461
|
}
|
|
1068
1462
|
),
|
|
1069
1463
|
/* @__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." }) }) })
|
|
@@ -1072,117 +1466,52 @@ function LeadGenListDetailPage({ listId }) {
|
|
|
1072
1466
|
const list = listQuery.data;
|
|
1073
1467
|
const progress = progressQuery.data;
|
|
1074
1468
|
const executions = executionsQuery.data ?? [];
|
|
1075
|
-
const
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
title: list.name,
|
|
1082
|
-
caption: list.description ?? "Configuration, progress, and execution history for this list",
|
|
1083
|
-
rightSection: /* @__PURE__ */ jsx(
|
|
1084
|
-
Button,
|
|
1085
|
-
{
|
|
1086
|
-
variant: "light",
|
|
1087
|
-
size: "xs",
|
|
1088
|
-
leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
|
|
1089
|
-
onClick: () => navigate({ to: "/lead-gen/lists" }),
|
|
1090
|
-
children: "Lists"
|
|
1091
|
-
}
|
|
1092
|
-
)
|
|
1093
|
-
}
|
|
1094
|
-
),
|
|
1095
|
-
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1096
|
-
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor(list.status), children: list.status }),
|
|
1097
|
-
/* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
|
|
1098
|
-
"Created ",
|
|
1099
|
-
formatDateTime(list.createdAt)
|
|
1100
|
-
] })
|
|
1101
|
-
] }),
|
|
1102
|
-
/* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
|
|
1103
|
-
/* @__PURE__ */ jsx(StatCard, { label: "Companies", value: progress.totalCompanies, icon: IconBuilding }),
|
|
1104
|
-
/* @__PURE__ */ jsx(StatCard, { label: "Contacts", value: progress.totalContacts, icon: IconUsers })
|
|
1105
|
-
] }),
|
|
1106
|
-
/* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
|
|
1469
|
+
const handleCopyListCommand = () => {
|
|
1470
|
+
void navigator.clipboard.writeText(`/acquisition --lead-gen list ${list.id}`);
|
|
1471
|
+
showSuccessNotification("Copied list command to clipboard");
|
|
1472
|
+
};
|
|
1473
|
+
return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
|
|
1474
|
+
/* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
|
|
1107
1475
|
/* @__PURE__ */ jsx(
|
|
1108
|
-
|
|
1476
|
+
ListDetailHeader,
|
|
1109
1477
|
{
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
rightSection: /* @__PURE__ */ jsx(
|
|
1113
|
-
SegmentedControl,
|
|
1114
|
-
{
|
|
1115
|
-
value: memberTab,
|
|
1116
|
-
onChange: (value) => setMemberTab(value),
|
|
1117
|
-
size: "xs",
|
|
1118
|
-
data: [
|
|
1119
|
-
{ label: `Contacts (${progress.totalContacts})`, value: "contacts" },
|
|
1120
|
-
{ label: `Companies (${progress.totalCompanies})`, value: "companies" }
|
|
1121
|
-
]
|
|
1122
|
-
}
|
|
1123
|
-
)
|
|
1478
|
+
title: list.name,
|
|
1479
|
+
caption: list.description ?? "Configuration, progress, and execution history for this list"
|
|
1124
1480
|
}
|
|
1125
1481
|
),
|
|
1126
|
-
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */ jsx(
|
|
1129
|
-
/* @__PURE__ */
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
/* @__PURE__ */ jsx(Table.Td, { children: contact.title ?? "\u2014" }),
|
|
1139
|
-
/* @__PURE__ */ jsx(Table.Td, { children: contact.company?.name ?? "\u2014" }),
|
|
1140
|
-
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor(contact.status), children: contact.status }) }),
|
|
1141
|
-
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime(contact.createdAt) })
|
|
1142
|
-
] }, contact.id)) })
|
|
1143
|
-
] }) }),
|
|
1144
|
-
memberTab === "companies" && /* @__PURE__ */ jsx(Fragment, { children: companiesQuery.isLoading ? /* @__PURE__ */ jsx(Center, { p: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : !companies.length ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No companies attached to this list yet." }) : /* @__PURE__ */ jsxs(Table, { children: [
|
|
1145
|
-
/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1146
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Name" }),
|
|
1147
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Domain" }),
|
|
1148
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Segment" }),
|
|
1149
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Contacts" }),
|
|
1150
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
|
|
1151
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Created" })
|
|
1152
|
-
] }) }),
|
|
1153
|
-
/* @__PURE__ */ jsx(Table.Tbody, { children: companies.map((company) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1154
|
-
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: company.name }) }),
|
|
1155
|
-
/* @__PURE__ */ jsx(Table.Td, { children: company.domain ?? "\u2014" }),
|
|
1156
|
-
/* @__PURE__ */ jsx(Table.Td, { children: company.segment ?? "\u2014" }),
|
|
1157
|
-
/* @__PURE__ */ jsx(Table.Td, { children: company.contactCount }),
|
|
1158
|
-
/* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor(company.status), children: company.status }) }),
|
|
1159
|
-
/* @__PURE__ */ jsx(Table.Td, { children: formatDateTime(company.createdAt) })
|
|
1160
|
-
] }, company.id)) })
|
|
1161
|
-
] }) })
|
|
1162
|
-
] }),
|
|
1163
|
-
/* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
|
|
1164
|
-
/* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }), title: "Execution History" }),
|
|
1165
|
-
!executions.length ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No executions recorded for this list yet." }) : /* @__PURE__ */ jsxs(Table, { children: [
|
|
1166
|
-
/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1167
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Resource" }),
|
|
1168
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
|
|
1169
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Started" }),
|
|
1170
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Completed" }),
|
|
1171
|
-
/* @__PURE__ */ jsx(Table.Th, { children: "Duration" })
|
|
1172
|
-
] }) }),
|
|
1173
|
-
/* @__PURE__ */ jsx(Table.Tbody, { children: executions.map((execution) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
|
|
1174
|
-
/* @__PURE__ */ jsxs(Table.Td, { children: [
|
|
1175
|
-
/* @__PURE__ */ jsx(Text, { fw: 500, children: execution.resourceId }),
|
|
1176
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: execution.executionId })
|
|
1482
|
+
/* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
|
|
1483
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1484
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", variant: "filled", color: getStatusColor2(list.status), children: list.status }),
|
|
1485
|
+
/* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
|
|
1486
|
+
"Created ",
|
|
1487
|
+
formatDateTime2(list.createdAt)
|
|
1488
|
+
] })
|
|
1489
|
+
] }),
|
|
1490
|
+
/* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
|
|
1491
|
+
/* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", onClick: handleCopyListCommand, style: { cursor: "pointer" }, children: [
|
|
1492
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ff: "monospace", children: list.id }),
|
|
1493
|
+
/* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", "aria-label": "Copy list command", children: /* @__PURE__ */ jsx(IconCopy, { size: 14 }) })
|
|
1177
1494
|
] }),
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1495
|
+
backButton
|
|
1496
|
+
] })
|
|
1497
|
+
] }),
|
|
1498
|
+
/* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "overview", children: [
|
|
1499
|
+
/* @__PURE__ */ jsxs(Tabs.List, { children: [
|
|
1500
|
+
/* @__PURE__ */ jsx(Tabs.Tab, { value: "overview", leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }), children: "Overview" }),
|
|
1501
|
+
/* @__PURE__ */ jsx(Tabs.Tab, { value: "members", leftSection: /* @__PURE__ */ jsx(IconUsers, { size: 14 }), children: "Members" }),
|
|
1502
|
+
/* @__PURE__ */ jsx(Tabs.Tab, { value: "artifacts", leftSection: /* @__PURE__ */ jsx(IconDatabase, { size: 14 }), children: "Artifacts" })
|
|
1503
|
+
] }),
|
|
1504
|
+
/* @__PURE__ */ jsx(Tabs.Panel, { value: "overview", pt: "sm", children: /* @__PURE__ */ jsx(OverviewTab, { list, progress }) }),
|
|
1505
|
+
/* @__PURE__ */ jsx(Tabs.Panel, { value: "members", pt: "sm", children: /* @__PURE__ */ jsx(MembersTab, { listId, progress, onMemberClick: handleMemberClick }) }),
|
|
1506
|
+
/* @__PURE__ */ jsx(Tabs.Panel, { value: "artifacts", pt: "sm", children: /* @__PURE__ */ jsx(ArtifactsTab, { listId }) })
|
|
1507
|
+
] }) }),
|
|
1508
|
+
/* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "md", children: [
|
|
1509
|
+
/* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }), title: "Execution History" }),
|
|
1510
|
+
/* @__PURE__ */ jsx(ExecutionHistorySection, { executions })
|
|
1183
1511
|
] })
|
|
1184
|
-
] })
|
|
1185
|
-
|
|
1512
|
+
] }) }),
|
|
1513
|
+
/* @__PURE__ */ jsx(ListMemberDrawer, { memberId, memberKind, listId, onClose: handleDrawerClose })
|
|
1514
|
+
] });
|
|
1186
1515
|
}
|
|
1187
1516
|
var PAGE_SIZE_DEFAULT2 = 20;
|
|
1188
1517
|
function LeadGenCompaniesPage() {
|
|
@@ -1542,4 +1871,4 @@ function LeadGenContactsPage() {
|
|
|
1542
1871
|
] }) });
|
|
1543
1872
|
}
|
|
1544
1873
|
|
|
1545
|
-
export { CompanyDetailModal, ContactDetailModal, LEAD_GEN_ITEMS, LEAD_GEN_ROUTE_LINKS,
|
|
1874
|
+
export { CompanyDetailModal, ContactDetailModal, LEAD_GEN_ITEMS, LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, formatDate, getEnrichmentColor, getEnrichmentStatus, getStateKeyColor, getStatusColor, leadGenManifest, useDeleteLists };
|