@notis_ai/cli 0.2.7 → 0.2.8
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/README.md +15 -0
- package/dist/scaffolds/notis-database/app/page.tsx +38 -41
- package/dist/scaffolds/notis-database/lib/types.ts +5 -7
- package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-fixtures.json +1839 -0
- package/dist/scaffolds/notis-database/notis.config.ts +48 -1
- package/dist/scaffolds/notis-database/package-lock.json +3935 -0
- package/dist/scaffolds/notis-database/package.json +2 -1
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/package.json +4 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectActionBar.tsx +7 -2
- package/dist/scaffolds/notis-database/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useMultiSelect.ts +38 -2
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/index.ts +30 -1
- package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/runtime.ts +76 -17
- package/dist/scaffolds/notis-database/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-database/src/mock-runtime.ts +4 -1
- package/dist/scaffolds/notis-journal/CHANGELOG.md +4 -0
- package/dist/scaffolds/notis-journal/app/page.tsx +1 -0
- package/dist/scaffolds/notis-journal/package-lock.json +4615 -0
- package/dist/scaffolds/notis-journal/package.json +2 -2
- package/dist/scaffolds/notis-journal/packages/sdk/src/config.ts +52 -1
- package/dist/scaffolds/notis-notes/app/page.tsx +39 -46
- package/dist/scaffolds/notis-notes/app/phosphor-icons.ts +596 -0
- package/dist/scaffolds/notis-notes/lib/visible-properties.ts +144 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-fixtures.json +752 -0
- package/dist/scaffolds/notis-notes/notis.config.ts +48 -3
- package/dist/scaffolds/notis-notes/package-lock.json +4636 -0
- package/dist/scaffolds/notis-notes/package.json +7 -3
- package/dist/scaffolds/notis-notes/packages/sdk/package.json +36 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectActionBar.tsx +278 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectCheckbox.tsx +91 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useBackend.ts +41 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useMultiSelect.ts +539 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotis.ts +34 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotisNavigation.ts +49 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTool.ts +64 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTools.ts +56 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTopBarSearch.ts +73 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/index.ts +83 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/provider.tsx +43 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/runtime.ts +220 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/ui.ts +15 -0
- package/dist/scaffolds/notis-notes/packages/sdk/src/vite.ts +56 -0
- package/dist/scaffolds/notis-notes/packages/sdk/tsconfig.json +15 -0
- package/dist/scaffolds/notis-random/CHANGELOG.md +12 -2
- package/dist/scaffolds/notis-random/app/history/page.tsx +5 -4
- package/dist/scaffolds/notis-random/app/page.tsx +141 -74
- package/dist/scaffolds/notis-random/components/ui/button.tsx +50 -0
- package/dist/scaffolds/notis-random/components/ui/card.tsx +16 -0
- package/dist/scaffolds/notis-random/components/ui/input.tsx +23 -0
- package/dist/scaffolds/notis-random/lib/notis-tools.ts +26 -7
- package/dist/scaffolds/notis-random/lib/rng.ts +179 -19
- package/dist/scaffolds/notis-random/lib/roll-record.ts +103 -16
- package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-fixtures.json +753 -0
- package/dist/scaffolds/notis-random/notis.config.ts +47 -3
- package/dist/scaffolds/notis-random/package-lock.json +4513 -0
- package/dist/scaffolds/notis-random/package.json +6 -2
- package/dist/scaffolds/notis-random/packages/sdk/package.json +36 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/DocumentEditor.tsx +93 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/Markdown.tsx +60 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectActionBar.tsx +278 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectCheckbox.tsx +91 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectDragOverlay.tsx +39 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/config.ts +196 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/documents.ts +229 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useBackend.ts +41 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDatabaseSchema.ts +85 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocument.ts +78 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocuments.ts +121 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useMultiSelect.ts +539 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotis.ts +34 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotisNavigation.ts +49 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTool.ts +64 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTools.ts +56 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTopBarSearch.ts +73 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useUpsertDocument.ts +95 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/index.ts +83 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/provider.tsx +43 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/runtime.ts +220 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/styles.css +186 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/ui.ts +15 -0
- package/dist/scaffolds/notis-random/packages/sdk/src/vite.ts +56 -0
- package/dist/scaffolds/notis-random/packages/sdk/tsconfig.json +15 -0
- package/dist/scaffolds/notis-random/tailwind.config.ts +8 -1
- package/dist/scaffolds.json +8 -17
- package/package.json +2 -1
- package/skills/notis-apps/SKILL.md +449 -144
- package/skills/notis-apps/cli.md +15 -0
- package/skills/notis-cli/SKILL.md +8 -4
- package/skills/notis-onboarding/BRIEF.md +93 -0
- package/src/cli.js +50 -12
- package/src/command-specs/apps.js +154 -21
- package/src/command-specs/index.js +2 -0
- package/src/command-specs/onboarding.js +216 -0
- package/src/command-specs/tools.js +8 -4
- package/src/runtime/app-platform.js +65 -4
- package/src/runtime/desktop-auth.js +66 -17
- package/src/runtime/errors.js +1 -0
- package/src/runtime/output.js +9 -2
- package/src/runtime/profiles.js +179 -17
- package/src/runtime/telemetry.js +92 -0
- package/src/runtime/transport.js +26 -1
- package/template/.harness/index.html.tmpl +30 -2
- package/template/packages/sdk/src/config.ts +38 -1
- package/dist/scaffolds/notis-affiliate-prospects/CHANGELOG.md +0 -7
- package/dist/scaffolds/notis-affiliate-prospects/README.md +0 -20
- package/dist/scaffolds/notis-affiliate-prospects/app/globals.css +0 -42
- package/dist/scaffolds/notis-affiliate-prospects/app/layout.tsx +0 -7
- package/dist/scaffolds/notis-affiliate-prospects/app/page.tsx +0 -248
- package/dist/scaffolds/notis-affiliate-prospects/app/prospects/page.tsx +0 -134
- package/dist/scaffolds/notis-affiliate-prospects/app/segments/page.tsx +0 -108
- package/dist/scaffolds/notis-affiliate-prospects/components/ui/card.tsx +0 -35
- package/dist/scaffolds/notis-affiliate-prospects/index.html +0 -12
- package/dist/scaffolds/notis-affiliate-prospects/lib/affiliate-data.ts +0 -218
- package/dist/scaffolds/notis-affiliate-prospects/lib/demo-prospects.ts +0 -52
- package/dist/scaffolds/notis-affiliate-prospects/lib/notis-tools.ts +0 -100
- package/dist/scaffolds/notis-affiliate-prospects/lib/utils.ts +0 -25
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-affiliate-prospects/metadata/screenshot-fixtures.json +0 -187
- package/dist/scaffolds/notis-affiliate-prospects/notis.config.ts +0 -65
- package/dist/scaffolds/notis-affiliate-prospects/package.json +0 -32
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/config.ts +0 -90
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/hooks/useDatabase.ts +0 -76
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/hooks/useUpsertDocument.ts +0 -50
- package/dist/scaffolds/notis-affiliate-prospects/packages/sdk/src/styles.css +0 -38
- package/dist/scaffolds/notis-affiliate-prospects/postcss.config.mjs +0 -6
- package/dist/scaffolds/notis-affiliate-prospects/src/dev-main.tsx +0 -72
- package/dist/scaffolds/notis-affiliate-prospects/src/mock-runtime.ts +0 -242
- package/dist/scaffolds/notis-affiliate-prospects/tailwind.config.ts +0 -51
- package/dist/scaffolds/notis-affiliate-prospects/tsconfig.json +0 -23
- package/dist/scaffolds/notis-affiliate-prospects/vite.config.ts +0 -11
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useBackend.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useNotis.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useNotisNavigation.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTool.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTools.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/hooks/useTopBarSearch.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/provider.tsx +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/ui.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/src/vite.ts +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-database}/packages/sdk/tsconfig.json +0 -0
- /package/dist/scaffolds/{notis-affiliate-prospects → notis-random}/components.json +0 -0
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
export const SEGMENTS = [
|
|
2
|
-
{
|
|
3
|
-
name: 'Customer Advocate',
|
|
4
|
-
short: 'Customers',
|
|
5
|
-
description: 'Power users and existing referrers with firsthand product credibility.',
|
|
6
|
-
source: 'Rewardful + product usage',
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
name: 'Automation Agency',
|
|
10
|
-
short: 'Agencies',
|
|
11
|
-
description: 'Zapier, Make, n8n, and AI automation consultants who recommend tools to clients.',
|
|
12
|
-
source: 'Partner directories + LinkedIn',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
name: 'AI Creator',
|
|
16
|
-
short: 'Creators',
|
|
17
|
-
description: 'AI, productivity, and automation creators, newsletters, and educators.',
|
|
18
|
-
source: 'YouTube + LinkedIn + newsletters',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: 'SEO Publisher',
|
|
22
|
-
short: 'Publishers',
|
|
23
|
-
description: 'Comparison sites and writers ranking for high-intent automation searches.',
|
|
24
|
-
source: 'DataForSEO SERPs',
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: 'Integration Partner',
|
|
28
|
-
short: 'Partners',
|
|
29
|
-
description: 'Complementary SaaS teams, implementation partners, and integration ecosystems.',
|
|
30
|
-
source: 'Integration catalog + partner pages',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'Community Educator',
|
|
34
|
-
short: 'Communities',
|
|
35
|
-
description: 'Operators of trusted no-code, RevOps, AI, and founder communities.',
|
|
36
|
-
source: 'Community directories + events',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: 'Affiliate Marketplace',
|
|
40
|
-
short: 'Marketplaces',
|
|
41
|
-
description: 'Experienced B2B SaaS affiliates active in curated partner marketplaces.',
|
|
42
|
-
source: 'PartnerStack + impact.com',
|
|
43
|
-
},
|
|
44
|
-
] as const;
|
|
45
|
-
|
|
46
|
-
export const PIPELINE = [
|
|
47
|
-
'New',
|
|
48
|
-
'Researching',
|
|
49
|
-
'Qualified',
|
|
50
|
-
'Ready for Outreach',
|
|
51
|
-
'Contacted',
|
|
52
|
-
'Replied',
|
|
53
|
-
'Interested',
|
|
54
|
-
'Applied',
|
|
55
|
-
'Activated',
|
|
56
|
-
'Nurture',
|
|
57
|
-
'Disqualified',
|
|
58
|
-
] as const;
|
|
59
|
-
|
|
60
|
-
export type SegmentName = (typeof SEGMENTS)[number]['name'];
|
|
61
|
-
export type ProspectStatus = (typeof PIPELINE)[number];
|
|
62
|
-
|
|
63
|
-
export interface AffiliateProspect {
|
|
64
|
-
id: string;
|
|
65
|
-
name: string;
|
|
66
|
-
company: string;
|
|
67
|
-
segment: SegmentName;
|
|
68
|
-
status: ProspectStatus;
|
|
69
|
-
priority: 'P0' | 'P1' | 'P2' | 'P3';
|
|
70
|
-
fitScore: number;
|
|
71
|
-
email: string;
|
|
72
|
-
linkedInUrl: string;
|
|
73
|
-
website: string;
|
|
74
|
-
source: string;
|
|
75
|
-
audienceSize: number;
|
|
76
|
-
trafficEstimate: number;
|
|
77
|
-
enrichmentStatus: string;
|
|
78
|
-
outreachChannel: string;
|
|
79
|
-
nextAction: string;
|
|
80
|
-
nextActionDate: string;
|
|
81
|
-
lastTouchDate: string;
|
|
82
|
-
referredSignups: number;
|
|
83
|
-
activatedReferrals: number;
|
|
84
|
-
attributedMrr: number;
|
|
85
|
-
notes: string;
|
|
86
|
-
optedOut: boolean;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
interface DocumentLike {
|
|
90
|
-
id?: string;
|
|
91
|
-
document_id?: string;
|
|
92
|
-
title?: string;
|
|
93
|
-
properties?: Record<string, unknown>;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function normalizeProspect(document: DocumentLike): AffiliateProspect {
|
|
97
|
-
const properties = document.properties ?? {};
|
|
98
|
-
return {
|
|
99
|
-
id: String(document.id ?? document.document_id ?? document.title ?? crypto.randomUUID()),
|
|
100
|
-
name: textValue(properties.Name) || document.title || 'Untitled prospect',
|
|
101
|
-
company: textValue(properties.Company),
|
|
102
|
-
segment: segmentValue(textValue(properties.Segment)),
|
|
103
|
-
status: statusValue(textValue(properties.Status)),
|
|
104
|
-
priority: priorityValue(textValue(properties.Priority)),
|
|
105
|
-
fitScore: numberValue(properties['Fit Score']),
|
|
106
|
-
email: textValue(properties.Email),
|
|
107
|
-
linkedInUrl: textValue(properties.LinkedIn),
|
|
108
|
-
website: textValue(properties.Website),
|
|
109
|
-
source: textValue(properties.Source),
|
|
110
|
-
audienceSize: numberValue(properties['Audience Size']),
|
|
111
|
-
trafficEstimate: numberValue(properties['Monthly Traffic']),
|
|
112
|
-
enrichmentStatus: textValue(properties['Enrichment Status']),
|
|
113
|
-
outreachChannel: textValue(properties['Outreach Channel']),
|
|
114
|
-
nextAction: textValue(properties['Next Action']),
|
|
115
|
-
nextActionDate: dateValue(properties['Next Action Date']),
|
|
116
|
-
lastTouchDate: dateValue(properties['Last Touch Date']),
|
|
117
|
-
referredSignups: numberValue(properties['Referred Signups']),
|
|
118
|
-
activatedReferrals: numberValue(properties['Activated Referrals']),
|
|
119
|
-
attributedMrr: numberValue(properties['Attributed MRR']),
|
|
120
|
-
notes: textValue(properties.Notes),
|
|
121
|
-
optedOut: booleanValue(properties['Opted Out']),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function statusTone(status: ProspectStatus): string {
|
|
126
|
-
if (status === 'Activated') return 'bg-emerald-500/10 text-emerald-700 dark:text-emerald-300';
|
|
127
|
-
if (['Interested', 'Applied'].includes(status)) return 'bg-violet-500/10 text-violet-700 dark:text-violet-300';
|
|
128
|
-
if (['Contacted', 'Replied'].includes(status)) return 'bg-sky-500/10 text-sky-700 dark:text-sky-300';
|
|
129
|
-
if (['Nurture', 'Disqualified'].includes(status)) return 'bg-muted text-muted-foreground';
|
|
130
|
-
return 'bg-amber-500/10 text-amber-700 dark:text-amber-300';
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function compactNumber(value: number): string {
|
|
134
|
-
return new Intl.NumberFormat('en', { notation: 'compact', maximumFractionDigits: 1 }).format(value);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function money(value: number): string {
|
|
138
|
-
return new Intl.NumberFormat('en', {
|
|
139
|
-
style: 'currency',
|
|
140
|
-
currency: 'USD',
|
|
141
|
-
maximumFractionDigits: 0,
|
|
142
|
-
}).format(value);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function segmentValue(value: string): SegmentName {
|
|
146
|
-
const normalized = value.trim().toLowerCase();
|
|
147
|
-
const aliases: Record<string, SegmentName> = {
|
|
148
|
-
'customer advocate': 'Customer Advocate',
|
|
149
|
-
'customer advocates': 'Customer Advocate',
|
|
150
|
-
'automation agency': 'Automation Agency',
|
|
151
|
-
'automation agencies': 'Automation Agency',
|
|
152
|
-
'ai creator': 'AI Creator',
|
|
153
|
-
'ai creators': 'AI Creator',
|
|
154
|
-
'seo publisher': 'SEO Publisher',
|
|
155
|
-
'seo publishers': 'SEO Publisher',
|
|
156
|
-
'integration partner': 'Integration Partner',
|
|
157
|
-
'integration partners': 'Integration Partner',
|
|
158
|
-
'community educator': 'Community Educator',
|
|
159
|
-
'community educators': 'Community Educator',
|
|
160
|
-
'affiliate marketplace': 'Affiliate Marketplace',
|
|
161
|
-
'affiliate marketplaces': 'Affiliate Marketplace',
|
|
162
|
-
};
|
|
163
|
-
return aliases[normalized] ?? 'Customer Advocate';
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function statusValue(value: string): ProspectStatus {
|
|
167
|
-
return (PIPELINE.find((status) => status === value) ?? 'New') as ProspectStatus;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function priorityValue(value: string): AffiliateProspect['priority'] {
|
|
171
|
-
return value === 'P0' || value === 'P1' || value === 'P2' || value === 'P3' ? value : 'P2';
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function textValue(value: unknown): string {
|
|
175
|
-
if (typeof value === 'string') return value;
|
|
176
|
-
if (!value || typeof value !== 'object') return '';
|
|
177
|
-
const typed = value as Record<string, unknown>;
|
|
178
|
-
if (typeof typed.url === 'string') return typed.url;
|
|
179
|
-
if (typeof typed.email === 'string') return typed.email;
|
|
180
|
-
if (typed.select && typeof typed.select === 'object') return String((typed.select as Record<string, unknown>).name ?? '');
|
|
181
|
-
if (typed.status && typeof typed.status === 'object') return String((typed.status as Record<string, unknown>).name ?? '');
|
|
182
|
-
for (const key of ['title', 'rich_text']) {
|
|
183
|
-
const rows = typed[key];
|
|
184
|
-
if (Array.isArray(rows)) {
|
|
185
|
-
return rows
|
|
186
|
-
.map((row) => {
|
|
187
|
-
if (!row || typeof row !== 'object') return '';
|
|
188
|
-
const record = row as Record<string, unknown>;
|
|
189
|
-
if (typeof record.plain_text === 'string') return record.plain_text;
|
|
190
|
-
const text = record.text as Record<string, unknown> | undefined;
|
|
191
|
-
return typeof text?.content === 'string' ? text.content : '';
|
|
192
|
-
})
|
|
193
|
-
.join('');
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return '';
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function numberValue(value: unknown): number {
|
|
200
|
-
if (typeof value === 'number') return value;
|
|
201
|
-
if (value && typeof value === 'object' && typeof (value as Record<string, unknown>).number === 'number') {
|
|
202
|
-
return (value as Record<string, unknown>).number as number;
|
|
203
|
-
}
|
|
204
|
-
return 0;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function booleanValue(value: unknown): boolean {
|
|
208
|
-
if (typeof value === 'boolean') return value;
|
|
209
|
-
if (value && typeof value === 'object') return Boolean((value as Record<string, unknown>).checkbox);
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function dateValue(value: unknown): string {
|
|
214
|
-
if (typeof value === 'string') return value;
|
|
215
|
-
if (!value || typeof value !== 'object') return '';
|
|
216
|
-
const date = (value as Record<string, unknown>).date;
|
|
217
|
-
return date && typeof date === 'object' ? String((date as Record<string, unknown>).start ?? '') : '';
|
|
218
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { AffiliateProspect, ProspectStatus, SegmentName } from '@/lib/affiliate-data';
|
|
2
|
-
|
|
3
|
-
export const DEMO_PROSPECTS: AffiliateProspect[] = [
|
|
4
|
-
demo('Alex Morgan', 'FlowNorth', 'Automation Agency', 'Interested', 94, 'Zapier Solution Partner Directory', 22200, 0, 'Send partner economics one-pager'),
|
|
5
|
-
demo('Maya Chen', 'Agent Ops Weekly', 'AI Creator', 'Replied', 91, 'Newsletter discovery', 60000, 0, 'Share creator demo kit'),
|
|
6
|
-
demo('Noah Williams', 'Automate Better', 'SEO Publisher', 'Ready for Outreach', 88, 'DataForSEO: Zapier alternatives', 76000, 0, 'Approve comparison-page pitch'),
|
|
7
|
-
demo('Sofia Rossi', 'RevOps Circle', 'Community Educator', 'Qualified', 86, 'Community operator list', 14500, 0, 'Enrich sponsor history'),
|
|
8
|
-
demo('Theo Martin', 'Notis customer', 'Customer Advocate', 'Activated', 97, 'Rewardful + product usage', 0, 1680, ''),
|
|
9
|
-
demo('Lena Fischer', 'StackPilot', 'Integration Partner', 'Applied', 92, 'Integration overlap analysis', 62000, 0, 'Confirm co-marketing launch date'),
|
|
10
|
-
demo('Sam Patel', 'SaaS Growth Lab', 'Affiliate Marketplace', 'Contacted', 82, 'PartnerStack marketplace', 51000, 0, 'Follow up with use-case proof'),
|
|
11
|
-
demo('Jordan Lee', 'OpsCraft', 'Automation Agency', 'Qualified', 84, 'Make Partner Directory', 5400, 0, 'Review recent client verticals'),
|
|
12
|
-
demo('Camille Laurent', 'Productive AI', 'SEO Publisher', 'Activated', 90, 'DataForSEO: AI automation tools', 92000, 2940, ''),
|
|
13
|
-
demo('Owen King', 'Notis customer', 'Customer Advocate', 'Contacted', 80, 'Product usage', 0, 0, 'Invite to advocate cohort'),
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
function demo(
|
|
17
|
-
name: string,
|
|
18
|
-
company: string,
|
|
19
|
-
segment: SegmentName,
|
|
20
|
-
status: ProspectStatus,
|
|
21
|
-
fitScore: number,
|
|
22
|
-
source: string,
|
|
23
|
-
reach: number,
|
|
24
|
-
attributedMrr: number,
|
|
25
|
-
nextAction: string,
|
|
26
|
-
): AffiliateProspect {
|
|
27
|
-
return {
|
|
28
|
-
id: `demo-${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,
|
|
29
|
-
name,
|
|
30
|
-
company,
|
|
31
|
-
segment,
|
|
32
|
-
status,
|
|
33
|
-
priority: fitScore >= 90 ? 'P0' : fitScore >= 75 ? 'P1' : 'P2',
|
|
34
|
-
fitScore,
|
|
35
|
-
email: `${name.split(' ')[0].toLowerCase()}@example.com`,
|
|
36
|
-
linkedInUrl: 'https://linkedin.com',
|
|
37
|
-
website: '',
|
|
38
|
-
source,
|
|
39
|
-
audienceSize: reach,
|
|
40
|
-
trafficEstimate: 0,
|
|
41
|
-
enrichmentStatus: 'Verified',
|
|
42
|
-
outreachChannel: 'Email + LinkedIn',
|
|
43
|
-
nextAction,
|
|
44
|
-
nextActionDate: nextAction ? '2026-07-25' : '',
|
|
45
|
-
lastTouchDate: '',
|
|
46
|
-
referredSignups: attributedMrr ? 12 : 0,
|
|
47
|
-
activatedReferrals: attributedMrr ? 5 : 0,
|
|
48
|
-
attributedMrr,
|
|
49
|
-
notes: '',
|
|
50
|
-
optedOut: false,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
-
import { useNotis, useTool } from '@notis/sdk';
|
|
5
|
-
|
|
6
|
-
import { normalizeProspect, type AffiliateProspect } from '@/lib/affiliate-data';
|
|
7
|
-
import { DEMO_PROSPECTS } from '@/lib/demo-prospects';
|
|
8
|
-
|
|
9
|
-
type QueryArgs = {
|
|
10
|
-
database_slug: 'affiliate_prospects_1';
|
|
11
|
-
query: { page_size: number };
|
|
12
|
-
offset?: number;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type QueryResult = {
|
|
16
|
-
documents?: Array<{
|
|
17
|
-
id?: string;
|
|
18
|
-
document_id?: string;
|
|
19
|
-
title?: string;
|
|
20
|
-
properties?: Record<string, unknown>;
|
|
21
|
-
}>;
|
|
22
|
-
error?: string;
|
|
23
|
-
message?: string;
|
|
24
|
-
has_more?: boolean;
|
|
25
|
-
next_offset?: number | null;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
function isDevelopmentPreview(appId?: string) {
|
|
29
|
-
if (appId === 'harness-app') return true;
|
|
30
|
-
if (typeof window === 'undefined') return false;
|
|
31
|
-
return window.location.pathname.includes('/apps/affiliate-prospects-dev-');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function useAffiliateProspects() {
|
|
35
|
-
const { app } = useNotis();
|
|
36
|
-
const query = useTool<QueryArgs, QueryResult>('LOCAL_NOTIS_DATABASE_QUERY');
|
|
37
|
-
const [prospects, setProspects] = useState<AffiliateProspect[]>([]);
|
|
38
|
-
const [localError, setLocalError] = useState<Error | null>(null);
|
|
39
|
-
const [usingPreviewFixture, setUsingPreviewFixture] = useState(false);
|
|
40
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
41
|
-
|
|
42
|
-
const refetch = useCallback(() => setFetchKey((key) => key + 1), []);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
let cancelled = false;
|
|
46
|
-
setLocalError(null);
|
|
47
|
-
setUsingPreviewFixture(false);
|
|
48
|
-
const fetchAllProspects = async () => {
|
|
49
|
-
const documents: NonNullable<QueryResult['documents']> = [];
|
|
50
|
-
let offset = 0;
|
|
51
|
-
while (true) {
|
|
52
|
-
const result = await query.call({
|
|
53
|
-
database_slug: 'affiliate_prospects_1',
|
|
54
|
-
query: { page_size: 500 },
|
|
55
|
-
...(offset ? { offset } : {}),
|
|
56
|
-
});
|
|
57
|
-
if (!result.documents && (result.error || result.message)) {
|
|
58
|
-
throw new Error(result.error ?? result.message);
|
|
59
|
-
}
|
|
60
|
-
documents.push(...(result.documents ?? []));
|
|
61
|
-
if (!result.has_more) return documents;
|
|
62
|
-
if (typeof result.next_offset !== 'number' || result.next_offset <= offset) {
|
|
63
|
-
throw new Error('Prospect query returned an invalid pagination offset');
|
|
64
|
-
}
|
|
65
|
-
offset = result.next_offset;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
void fetchAllProspects()
|
|
70
|
-
.then((documents) => {
|
|
71
|
-
if (cancelled) return;
|
|
72
|
-
const normalized = documents.map(normalizeProspect);
|
|
73
|
-
const shouldUsePreviewFixture = !normalized.length && isDevelopmentPreview(app?.id);
|
|
74
|
-
setUsingPreviewFixture(shouldUsePreviewFixture);
|
|
75
|
-
setProspects(shouldUsePreviewFixture ? DEMO_PROSPECTS : normalized);
|
|
76
|
-
})
|
|
77
|
-
.catch((error) => {
|
|
78
|
-
if (cancelled) return;
|
|
79
|
-
if (isDevelopmentPreview(app?.id)) {
|
|
80
|
-
setProspects(DEMO_PROSPECTS);
|
|
81
|
-
setLocalError(null);
|
|
82
|
-
setUsingPreviewFixture(true);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
setProspects([]);
|
|
86
|
-
setUsingPreviewFixture(false);
|
|
87
|
-
setLocalError(error instanceof Error ? error : new Error(String(error)));
|
|
88
|
-
});
|
|
89
|
-
return () => {
|
|
90
|
-
cancelled = true;
|
|
91
|
-
};
|
|
92
|
-
}, [app?.id, fetchKey, query.call]);
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
prospects,
|
|
96
|
-
loading: query.loading,
|
|
97
|
-
error: usingPreviewFixture ? null : query.error ?? localError,
|
|
98
|
-
refetch,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { clsx, type ClassValue } from 'clsx';
|
|
2
|
-
import { twMerge } from 'tailwind-merge';
|
|
3
|
-
|
|
4
|
-
export function cn(...inputs: ClassValue[]): string {
|
|
5
|
-
return twMerge(clsx(inputs));
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function formatNumber(value: number): string {
|
|
9
|
-
if (Number.isInteger(value)) return value.toString();
|
|
10
|
-
return value.toFixed(4).replace(/0+$/, '').replace(/\.$/, '');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function relativeTime(iso: string | null | undefined): string {
|
|
14
|
-
if (!iso) return '';
|
|
15
|
-
const then = new Date(iso).getTime();
|
|
16
|
-
if (Number.isNaN(then)) return '';
|
|
17
|
-
const diffSeconds = Math.round((Date.now() - then) / 1000);
|
|
18
|
-
if (diffSeconds < 5) return 'just now';
|
|
19
|
-
if (diffSeconds < 60) return `${diffSeconds}s ago`;
|
|
20
|
-
const diffMinutes = Math.round(diffSeconds / 60);
|
|
21
|
-
if (diffMinutes < 60) return `${diffMinutes}m ago`;
|
|
22
|
-
const diffHours = Math.round(diffMinutes / 60);
|
|
23
|
-
if (diffHours < 24) return `${diffHours}h ago`;
|
|
24
|
-
return new Date(iso).toLocaleDateString();
|
|
25
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"tools": {
|
|
3
|
-
"LOCAL_NOTIS_DATABASE_QUERY": {
|
|
4
|
-
"documents": [
|
|
5
|
-
{
|
|
6
|
-
"id": "demo-alex",
|
|
7
|
-
"title": "Alex Morgan",
|
|
8
|
-
"properties": {
|
|
9
|
-
"Name": "Alex Morgan",
|
|
10
|
-
"Company": "FlowNorth",
|
|
11
|
-
"Segment": "Automation Agency",
|
|
12
|
-
"Status": "Interested",
|
|
13
|
-
"Priority": "P0",
|
|
14
|
-
"Fit Score": 94,
|
|
15
|
-
"Email": "alex@flownorth.example",
|
|
16
|
-
"LinkedIn": "https://linkedin.com/in/alex-morgan",
|
|
17
|
-
"Source": "Zapier Solution Partner Directory",
|
|
18
|
-
"Audience Size": 8200,
|
|
19
|
-
"Monthly Traffic": 14000,
|
|
20
|
-
"Next Action": "Send partner economics one-pager",
|
|
21
|
-
"Next Action Date": "2026-07-24"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"id": "demo-maya",
|
|
26
|
-
"title": "Maya Chen",
|
|
27
|
-
"properties": {
|
|
28
|
-
"Name": "Maya Chen",
|
|
29
|
-
"Company": "Agent Ops Weekly",
|
|
30
|
-
"Segment": "AI Creator",
|
|
31
|
-
"Status": "Replied",
|
|
32
|
-
"Priority": "P0",
|
|
33
|
-
"Fit Score": 91,
|
|
34
|
-
"Email": "maya@agentopsweekly.example",
|
|
35
|
-
"LinkedIn": "https://linkedin.com/in/maya-chen",
|
|
36
|
-
"Source": "Newsletter discovery",
|
|
37
|
-
"Audience Size": 38000,
|
|
38
|
-
"Monthly Traffic": 22000,
|
|
39
|
-
"Next Action": "Share creator demo kit",
|
|
40
|
-
"Next Action Date": "2026-07-24"
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"id": "demo-noah",
|
|
45
|
-
"title": "Noah Williams",
|
|
46
|
-
"properties": {
|
|
47
|
-
"Name": "Noah Williams",
|
|
48
|
-
"Company": "Automate Better",
|
|
49
|
-
"Segment": "SEO Publisher",
|
|
50
|
-
"Status": "Ready for Outreach",
|
|
51
|
-
"Priority": "P1",
|
|
52
|
-
"Fit Score": 88,
|
|
53
|
-
"Email": "noah@automatebetter.example",
|
|
54
|
-
"Website": "https://automatebetter.example",
|
|
55
|
-
"Source": "DataForSEO: Zapier alternatives",
|
|
56
|
-
"Monthly Traffic": 76000,
|
|
57
|
-
"Next Action": "Approve comparison-page pitch",
|
|
58
|
-
"Next Action Date": "2026-07-25"
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"id": "demo-sofia",
|
|
63
|
-
"title": "Sofia Rossi",
|
|
64
|
-
"properties": {
|
|
65
|
-
"Name": "Sofia Rossi",
|
|
66
|
-
"Company": "RevOps Circle",
|
|
67
|
-
"Segment": "Community Educator",
|
|
68
|
-
"Status": "Qualified",
|
|
69
|
-
"Priority": "P1",
|
|
70
|
-
"Fit Score": 86,
|
|
71
|
-
"LinkedIn": "https://linkedin.com/in/sofia-rossi",
|
|
72
|
-
"Source": "Community operator list",
|
|
73
|
-
"Audience Size": 14500,
|
|
74
|
-
"Next Action": "Enrich sponsor history",
|
|
75
|
-
"Next Action Date": "2026-07-25"
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"id": "demo-theo",
|
|
80
|
-
"title": "Theo Martin",
|
|
81
|
-
"properties": {
|
|
82
|
-
"Name": "Theo Martin",
|
|
83
|
-
"Company": "Notis customer",
|
|
84
|
-
"Segment": "Customer Advocate",
|
|
85
|
-
"Status": "Activated",
|
|
86
|
-
"Priority": "P0",
|
|
87
|
-
"Fit Score": 97,
|
|
88
|
-
"Source": "Rewardful + product usage",
|
|
89
|
-
"Referred Signups": 19,
|
|
90
|
-
"Activated Referrals": 7,
|
|
91
|
-
"Attributed MRR": 1680
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"id": "demo-lena",
|
|
96
|
-
"title": "Lena Fischer",
|
|
97
|
-
"properties": {
|
|
98
|
-
"Name": "Lena Fischer",
|
|
99
|
-
"Company": "StackPilot",
|
|
100
|
-
"Segment": "Integration Partner",
|
|
101
|
-
"Status": "Applied",
|
|
102
|
-
"Priority": "P0",
|
|
103
|
-
"Fit Score": 92,
|
|
104
|
-
"Email": "lena@stackpilot.example",
|
|
105
|
-
"LinkedIn": "https://linkedin.com/in/lena-fischer",
|
|
106
|
-
"Source": "Integration overlap analysis",
|
|
107
|
-
"Audience Size": 21000,
|
|
108
|
-
"Monthly Traffic": 41000,
|
|
109
|
-
"Next Action": "Confirm co-marketing launch date",
|
|
110
|
-
"Next Action Date": "2026-07-28"
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
"id": "demo-sam",
|
|
115
|
-
"title": "Sam Patel",
|
|
116
|
-
"properties": {
|
|
117
|
-
"Name": "Sam Patel",
|
|
118
|
-
"Company": "SaaS Growth Lab",
|
|
119
|
-
"Segment": "Affiliate Marketplace",
|
|
120
|
-
"Status": "Contacted",
|
|
121
|
-
"Priority": "P1",
|
|
122
|
-
"Fit Score": 82,
|
|
123
|
-
"Email": "sam@saasgrowthlab.example",
|
|
124
|
-
"Source": "PartnerStack marketplace",
|
|
125
|
-
"Audience Size": 18000,
|
|
126
|
-
"Monthly Traffic": 33000,
|
|
127
|
-
"Next Action": "Follow up with use-case proof",
|
|
128
|
-
"Next Action Date": "2026-07-27"
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"id": "demo-jordan",
|
|
133
|
-
"title": "Jordan Lee",
|
|
134
|
-
"properties": {
|
|
135
|
-
"Name": "Jordan Lee",
|
|
136
|
-
"Company": "OpsCraft",
|
|
137
|
-
"Segment": "Automation Agency",
|
|
138
|
-
"Status": "Qualified",
|
|
139
|
-
"Priority": "P1",
|
|
140
|
-
"Fit Score": 84,
|
|
141
|
-
"Email": "jordan@opscraft.example",
|
|
142
|
-
"LinkedIn": "https://linkedin.com/in/jordan-lee",
|
|
143
|
-
"Source": "Make Partner Directory",
|
|
144
|
-
"Audience Size": 5400,
|
|
145
|
-
"Next Action": "Review recent client verticals",
|
|
146
|
-
"Next Action Date": "2026-07-25"
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"id": "demo-camille",
|
|
151
|
-
"title": "Camille Laurent",
|
|
152
|
-
"properties": {
|
|
153
|
-
"Name": "Camille Laurent",
|
|
154
|
-
"Company": "Productive AI",
|
|
155
|
-
"Segment": "SEO Publisher",
|
|
156
|
-
"Status": "Activated",
|
|
157
|
-
"Priority": "P0",
|
|
158
|
-
"Fit Score": 90,
|
|
159
|
-
"Email": "camille@productiveai.example",
|
|
160
|
-
"Website": "https://productiveai.example",
|
|
161
|
-
"Source": "DataForSEO: AI automation tools",
|
|
162
|
-
"Monthly Traffic": 92000,
|
|
163
|
-
"Referred Signups": 31,
|
|
164
|
-
"Activated Referrals": 11,
|
|
165
|
-
"Attributed MRR": 2940
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
"id": "demo-owen",
|
|
170
|
-
"title": "Owen King",
|
|
171
|
-
"properties": {
|
|
172
|
-
"Name": "Owen King",
|
|
173
|
-
"Company": "Notis customer",
|
|
174
|
-
"Segment": "Customer Advocate",
|
|
175
|
-
"Status": "Contacted",
|
|
176
|
-
"Priority": "P1",
|
|
177
|
-
"Fit Score": 80,
|
|
178
|
-
"Email": "owen@example.com",
|
|
179
|
-
"Source": "Product usage: 25 successful workflows",
|
|
180
|
-
"Next Action": "Invite to advocate cohort",
|
|
181
|
-
"Next Action Date": "2026-07-26"
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
]
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { defineNotisApp } from '@notis/sdk/config';
|
|
2
|
-
|
|
3
|
-
export default defineNotisApp({
|
|
4
|
-
name: 'affiliate-prospects',
|
|
5
|
-
title: 'Affiliate Prospects',
|
|
6
|
-
description:
|
|
7
|
-
'A campaign control center for sourcing, qualifying, contacting, and activating high-fit Notis affiliates.',
|
|
8
|
-
icon: 'phosphor:users-three',
|
|
9
|
-
accent: 'violet',
|
|
10
|
-
author: { name: 'Florian (Flo) Pariset' },
|
|
11
|
-
categories: ['Sales & Marketing', 'Operations'],
|
|
12
|
-
tagline: 'Turn affiliate recruiting into a measurable, repeatable pipeline.',
|
|
13
|
-
screenshots: [
|
|
14
|
-
{
|
|
15
|
-
path: 'metadata/screenshot-1.png',
|
|
16
|
-
alt: 'Affiliate campaign dashboard with pipeline, priority queue, and segment performance.',
|
|
17
|
-
route: 'dashboard',
|
|
18
|
-
scenario: 'affiliate-dashboard',
|
|
19
|
-
focus: '[data-store-screenshot="dashboard"]',
|
|
20
|
-
theme: 'light',
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
path: 'metadata/screenshot-2.png',
|
|
24
|
-
alt: 'Affiliate prospect list with status, segment, fit score, source, and next action.',
|
|
25
|
-
route: 'prospects',
|
|
26
|
-
scenario: 'affiliate-prospects',
|
|
27
|
-
focus: '[data-store-screenshot="prospects"]',
|
|
28
|
-
theme: 'light',
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
path: 'metadata/screenshot-3.png',
|
|
32
|
-
alt: 'Affiliate segment scorecards showing campaign progress and sourcing playbooks.',
|
|
33
|
-
route: 'segments',
|
|
34
|
-
scenario: 'affiliate-segments',
|
|
35
|
-
focus: '[data-store-screenshot="segments"]',
|
|
36
|
-
theme: 'dark',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
|
|
40
|
-
databases: ['affiliate_prospects_1', 'affiliate_outreach_events_1'],
|
|
41
|
-
|
|
42
|
-
routes: [
|
|
43
|
-
{
|
|
44
|
-
path: '/',
|
|
45
|
-
slug: 'dashboard',
|
|
46
|
-
name: 'Dashboard',
|
|
47
|
-
icon: 'phosphor:squares-four',
|
|
48
|
-
default: true,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
path: '/prospects',
|
|
52
|
-
slug: 'prospects',
|
|
53
|
-
name: 'Prospects',
|
|
54
|
-
icon: 'phosphor:users',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
path: '/segments',
|
|
58
|
-
slug: 'segments',
|
|
59
|
-
name: 'Segments',
|
|
60
|
-
icon: 'phosphor:circles-three-plus',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
|
|
64
|
-
tools: ['LOCAL_NOTIS_DATABASE_QUERY'],
|
|
65
|
-
});
|