@startsimpli/funnels 0.1.3 → 0.1.5
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/package.json +9 -31
- package/src/api/README.md +507 -0
- package/src/api/adapter.ts +106 -0
- package/src/api/client.test.ts +640 -0
- package/src/api/client.ts +385 -0
- package/src/api/default-adapter.ts +243 -0
- package/src/api/index.ts +24 -0
- package/src/components/FilterRuleEditor/ARCHITECTURE.md +354 -0
- package/src/components/FilterRuleEditor/FieldSelector.tsx +91 -0
- package/src/components/FilterRuleEditor/FilterRuleEditor.stories.tsx +462 -0
- package/src/components/FilterRuleEditor/FilterRuleEditor.test.tsx +520 -0
- package/src/components/FilterRuleEditor/FilterRuleEditor.tsx +225 -0
- package/src/components/FilterRuleEditor/LogicToggle.tsx +64 -0
- package/src/components/FilterRuleEditor/OperatorSelector.tsx +75 -0
- package/src/components/FilterRuleEditor/README.md +291 -0
- package/src/components/FilterRuleEditor/RuleRow.tsx +246 -0
- package/src/components/FilterRuleEditor/ValueInputs/BooleanValueInput.tsx +54 -0
- package/src/components/FilterRuleEditor/ValueInputs/ChoiceValueInput.tsx +83 -0
- package/src/components/FilterRuleEditor/ValueInputs/DateValueInput.tsx +70 -0
- package/src/components/FilterRuleEditor/ValueInputs/MultiChoiceValueInput.tsx +132 -0
- package/src/components/FilterRuleEditor/ValueInputs/NumberValueInput.tsx +73 -0
- package/src/components/FilterRuleEditor/ValueInputs/TextValueInput.tsx +50 -0
- package/src/components/FilterRuleEditor/ValueInputs/index.ts +12 -0
- package/src/components/FilterRuleEditor/constants.ts +64 -0
- package/src/components/FilterRuleEditor/index.ts +14 -0
- package/src/components/FunnelCard/DESIGN.md +447 -0
- package/src/components/FunnelCard/FunnelCard.stories.tsx +484 -0
- package/src/components/FunnelCard/FunnelCard.test.ts +257 -0
- package/src/components/FunnelCard/FunnelCard.test.tsx +336 -0
- package/src/components/FunnelCard/FunnelCard.tsx +204 -0
- package/src/components/FunnelCard/FunnelStats.tsx +68 -0
- package/src/components/FunnelCard/IMPLEMENTATION_SUMMARY.md +505 -0
- package/src/components/FunnelCard/INSTALLATION.md +304 -0
- package/src/components/FunnelCard/MatchBar.tsx +49 -0
- package/src/components/FunnelCard/README.md +294 -0
- package/src/components/FunnelCard/StageIndicator.tsx +62 -0
- package/src/components/FunnelCard/StatusBadge.tsx +52 -0
- package/src/components/FunnelCard/index.ts +14 -0
- package/src/components/FunnelPreview/EntityCard.tsx +72 -0
- package/src/components/FunnelPreview/FunnelPreview.stories.tsx +227 -0
- package/src/components/FunnelPreview/FunnelPreview.test.tsx +316 -0
- package/src/components/FunnelPreview/FunnelPreview.tsx +249 -0
- package/src/components/FunnelPreview/LoadingPreview.tsx +60 -0
- package/src/components/FunnelPreview/PreviewStats.tsx +78 -0
- package/src/components/FunnelPreview/README.md +337 -0
- package/src/components/FunnelPreview/StageBreakdown.tsx +94 -0
- package/src/components/FunnelPreview/example.tsx +286 -0
- package/src/components/FunnelPreview/index.ts +14 -0
- package/src/components/FunnelRunHistory/COMPONENT_SUMMARY.md +246 -0
- package/src/components/FunnelRunHistory/FunnelRunHistory.stories.tsx +272 -0
- package/src/components/FunnelRunHistory/FunnelRunHistory.test.tsx +323 -0
- package/src/components/FunnelRunHistory/FunnelRunHistory.tsx +329 -0
- package/src/components/FunnelRunHistory/README.md +325 -0
- package/src/components/FunnelRunHistory/RunActions.tsx +168 -0
- package/src/components/FunnelRunHistory/RunDetailsModal.tsx +221 -0
- package/src/components/FunnelRunHistory/RunFilters.tsx +128 -0
- package/src/components/FunnelRunHistory/RunRow.tsx +122 -0
- package/src/components/FunnelRunHistory/RunStatusBadge.tsx +75 -0
- package/src/components/FunnelRunHistory/StageBreakdownList.tsx +110 -0
- package/src/components/FunnelRunHistory/index.ts +51 -0
- package/src/components/FunnelRunHistory/types.ts +40 -0
- package/src/components/FunnelRunHistory/utils.test.ts +126 -0
- package/src/components/FunnelRunHistory/utils.ts +100 -0
- package/src/components/FunnelStageBuilder/AddStageButton.tsx +52 -0
- package/src/components/FunnelStageBuilder/FunnelStageBuilder.css +413 -0
- package/src/components/FunnelStageBuilder/FunnelStageBuilder.stories.tsx +312 -0
- package/src/components/FunnelStageBuilder/FunnelStageBuilder.test.tsx +304 -0
- package/src/components/FunnelStageBuilder/FunnelStageBuilder.tsx +321 -0
- package/src/components/FunnelStageBuilder/README.md +341 -0
- package/src/components/FunnelStageBuilder/StageActions.test.tsx +205 -0
- package/src/components/FunnelStageBuilder/StageActions.tsx +126 -0
- package/src/components/FunnelStageBuilder/StageCard.tsx +202 -0
- package/src/components/FunnelStageBuilder/StageForm.tsx +262 -0
- package/src/components/FunnelStageBuilder/TagInput.test.tsx +178 -0
- package/src/components/FunnelStageBuilder/TagInput.tsx +129 -0
- package/src/components/FunnelStageBuilder/index.ts +21 -0
- package/src/components/FunnelVisualFlow/FlowLegend.tsx +77 -0
- package/{dist/components/index.css → src/components/FunnelVisualFlow/FunnelVisualFlow.css} +89 -13
- package/src/components/FunnelVisualFlow/FunnelVisualFlow.stories.tsx +254 -0
- package/src/components/FunnelVisualFlow/FunnelVisualFlow.test.tsx +208 -0
- package/src/components/FunnelVisualFlow/FunnelVisualFlow.tsx +229 -0
- package/src/components/FunnelVisualFlow/README.md +323 -0
- package/src/components/FunnelVisualFlow/StageNode.tsx +188 -0
- package/src/components/FunnelVisualFlow/example.tsx +227 -0
- package/src/components/FunnelVisualFlow/index.ts +10 -0
- package/src/components/index.ts +102 -0
- package/src/core/README.md +307 -0
- package/src/core/engine.test.ts +1087 -0
- package/src/core/engine.ts +329 -0
- package/src/core/evaluator.example.ts +353 -0
- package/src/core/evaluator.test.ts +639 -0
- package/src/core/evaluator.ts +261 -0
- package/src/core/field-resolver.example.ts +175 -0
- package/src/core/field-resolver.test.ts +541 -0
- package/src/core/field-resolver.ts +247 -0
- package/src/core/index.ts +34 -0
- package/src/core/operators.test.ts +539 -0
- package/src/core/operators.ts +241 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useDebouncedValue.ts +28 -0
- package/src/index.ts +155 -0
- package/src/store/README.md +342 -0
- package/src/store/create-funnel-store.test.ts +686 -0
- package/src/store/create-funnel-store.ts +538 -0
- package/src/store/index.ts +9 -0
- package/src/store/types.ts +294 -0
- package/src/stories/CrossDomain.stories.tsx +149 -0
- package/src/stories/Welcome.stories.tsx +81 -0
- package/src/stories/demo-data/index.ts +3 -0
- package/src/stories/demo-data/investors.ts +216 -0
- package/src/stories/demo-data/leads.ts +223 -0
- package/src/stories/demo-data/recipes.ts +217 -0
- package/src/test/setup.ts +5 -0
- package/src/types/index.ts +843 -0
- package/dist/client-3ESO2NHy.d.ts +0 -310
- package/dist/client-CZu03ACp.d.cts +0 -310
- package/dist/components/index.cjs +0 -3243
- package/dist/components/index.cjs.map +0 -1
- package/dist/components/index.css.map +0 -1
- package/dist/components/index.d.cts +0 -726
- package/dist/components/index.d.ts +0 -726
- package/dist/components/index.js +0 -3196
- package/dist/components/index.js.map +0 -1
- package/dist/core/index.cjs +0 -500
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -359
- package/dist/core/index.d.ts +0 -359
- package/dist/core/index.js +0 -486
- package/dist/core/index.js.map +0 -1
- package/dist/hooks/index.cjs +0 -21
- package/dist/hooks/index.cjs.map +0 -1
- package/dist/hooks/index.d.cts +0 -11
- package/dist/hooks/index.d.ts +0 -11
- package/dist/hooks/index.js +0 -19
- package/dist/hooks/index.js.map +0 -1
- package/dist/index-BGDEXbuz.d.cts +0 -434
- package/dist/index-BGDEXbuz.d.ts +0 -434
- package/dist/index.cjs +0 -4499
- package/dist/index.cjs.map +0 -1
- package/dist/index.css +0 -198
- package/dist/index.css.map +0 -1
- package/dist/index.d.cts +0 -99
- package/dist/index.d.ts +0 -99
- package/dist/index.js +0 -4421
- package/dist/index.js.map +0 -1
- package/dist/store/index.cjs +0 -391
- package/dist/store/index.cjs.map +0 -1
- package/dist/store/index.d.cts +0 -225
- package/dist/store/index.d.ts +0 -225
- package/dist/store/index.js +0 -388
- package/dist/store/index.js.map +0 -1
|
@@ -1,23 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* FunnelVisualFlow Styles
|
|
3
|
+
*
|
|
4
|
+
* Design System:
|
|
5
|
+
* - Uses Tailwind-like utility values
|
|
6
|
+
* - Consistent spacing (4px grid)
|
|
7
|
+
* - Clean, minimal aesthetic
|
|
8
|
+
* - Smooth transitions
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* =============================================================================
|
|
12
|
+
* Flow Container
|
|
13
|
+
* ============================================================================= */
|
|
14
|
+
|
|
2
15
|
.funnel-visual-flow {
|
|
3
16
|
position: relative;
|
|
4
17
|
width: 100%;
|
|
5
|
-
background: #f9fafb;
|
|
18
|
+
background: #f9fafb; /* gray-50 */
|
|
6
19
|
border-radius: 8px;
|
|
7
20
|
overflow: hidden;
|
|
8
21
|
}
|
|
22
|
+
|
|
9
23
|
.funnel-visual-flow-empty {
|
|
10
24
|
display: flex;
|
|
11
25
|
align-items: center;
|
|
12
26
|
justify-content: center;
|
|
13
27
|
background: #f9fafb;
|
|
14
|
-
border: 2px dashed #d1d5db;
|
|
28
|
+
border: 2px dashed #d1d5db; /* gray-300 */
|
|
15
29
|
border-radius: 8px;
|
|
16
30
|
}
|
|
31
|
+
|
|
17
32
|
.empty-state {
|
|
18
33
|
text-align: center;
|
|
19
34
|
padding: 32px;
|
|
20
35
|
}
|
|
36
|
+
|
|
37
|
+
/* =============================================================================
|
|
38
|
+
* Stage Node
|
|
39
|
+
* ============================================================================= */
|
|
40
|
+
|
|
21
41
|
.stage-node {
|
|
22
42
|
padding: 16px;
|
|
23
43
|
border-radius: 8px;
|
|
@@ -29,34 +49,44 @@
|
|
|
29
49
|
cursor: pointer;
|
|
30
50
|
transition: all 0.2s ease;
|
|
31
51
|
}
|
|
52
|
+
|
|
32
53
|
.stage-node:hover {
|
|
33
54
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
34
55
|
transform: translateY(-2px);
|
|
35
56
|
}
|
|
57
|
+
|
|
36
58
|
.stage-node:focus {
|
|
37
59
|
outline: none;
|
|
38
60
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
|
|
39
61
|
}
|
|
62
|
+
|
|
63
|
+
/* Stage number (circled number) */
|
|
40
64
|
.stage-number {
|
|
41
65
|
font-size: 28px;
|
|
42
66
|
font-weight: 700;
|
|
43
67
|
line-height: 1;
|
|
44
68
|
margin-bottom: 8px;
|
|
45
69
|
}
|
|
70
|
+
|
|
71
|
+
/* Stage name */
|
|
46
72
|
.stage-name {
|
|
47
73
|
font-size: 16px;
|
|
48
74
|
font-weight: 600;
|
|
49
|
-
color: #111827;
|
|
75
|
+
color: #111827; /* gray-900 */
|
|
50
76
|
margin-bottom: 4px;
|
|
51
77
|
overflow: hidden;
|
|
52
78
|
text-overflow: ellipsis;
|
|
53
79
|
white-space: nowrap;
|
|
54
80
|
}
|
|
81
|
+
|
|
82
|
+
/* Rule count */
|
|
55
83
|
.stage-rules {
|
|
56
84
|
font-size: 13px;
|
|
57
|
-
color: #6b7280;
|
|
85
|
+
color: #6b7280; /* gray-500 */
|
|
58
86
|
margin-bottom: 6px;
|
|
59
87
|
}
|
|
88
|
+
|
|
89
|
+
/* Action label */
|
|
60
90
|
.stage-action {
|
|
61
91
|
font-size: 12px;
|
|
62
92
|
font-weight: 600;
|
|
@@ -64,38 +94,51 @@
|
|
|
64
94
|
letter-spacing: 0.5px;
|
|
65
95
|
margin-bottom: 8px;
|
|
66
96
|
}
|
|
97
|
+
|
|
98
|
+
/* Stats section */
|
|
67
99
|
.stage-stats {
|
|
68
100
|
margin-top: 12px;
|
|
69
101
|
padding-top: 12px;
|
|
70
|
-
border-top: 1px solid #e5e7eb;
|
|
102
|
+
border-top: 1px solid #e5e7eb; /* gray-200 */
|
|
71
103
|
}
|
|
104
|
+
|
|
72
105
|
.stat-row {
|
|
73
106
|
display: flex;
|
|
74
107
|
justify-content: space-between;
|
|
75
108
|
font-size: 13px;
|
|
76
109
|
margin-bottom: 4px;
|
|
77
110
|
}
|
|
111
|
+
|
|
78
112
|
.stat-label {
|
|
79
|
-
color: #6b7280;
|
|
113
|
+
color: #6b7280; /* gray-500 */
|
|
80
114
|
font-weight: 500;
|
|
81
115
|
}
|
|
116
|
+
|
|
82
117
|
.stat-value {
|
|
83
118
|
font-weight: 600;
|
|
84
|
-
color: #111827;
|
|
119
|
+
color: #111827; /* gray-900 */
|
|
85
120
|
}
|
|
121
|
+
|
|
122
|
+
/* Description (if shown) */
|
|
86
123
|
.stage-description {
|
|
87
124
|
margin-top: 8px;
|
|
88
125
|
font-size: 12px;
|
|
89
|
-
color: #9ca3af;
|
|
126
|
+
color: #9ca3af; /* gray-400 */
|
|
90
127
|
font-style: italic;
|
|
91
128
|
overflow: hidden;
|
|
92
129
|
text-overflow: ellipsis;
|
|
93
130
|
white-space: nowrap;
|
|
94
131
|
}
|
|
132
|
+
|
|
133
|
+
/* =============================================================================
|
|
134
|
+
* Flow Legend
|
|
135
|
+
* ============================================================================= */
|
|
136
|
+
|
|
95
137
|
.flow-legend-panel {
|
|
96
138
|
background: transparent;
|
|
97
139
|
border: none;
|
|
98
140
|
}
|
|
141
|
+
|
|
99
142
|
.flow-legend {
|
|
100
143
|
background: white;
|
|
101
144
|
border-radius: 8px;
|
|
@@ -103,6 +146,7 @@
|
|
|
103
146
|
padding: 12px;
|
|
104
147
|
min-width: 140px;
|
|
105
148
|
}
|
|
149
|
+
|
|
106
150
|
.legend-toggle {
|
|
107
151
|
width: 100%;
|
|
108
152
|
display: flex;
|
|
@@ -114,85 +158,117 @@
|
|
|
114
158
|
padding: 0;
|
|
115
159
|
margin-bottom: 8px;
|
|
116
160
|
}
|
|
161
|
+
|
|
117
162
|
.legend-toggle:hover {
|
|
118
163
|
opacity: 0.8;
|
|
119
164
|
}
|
|
165
|
+
|
|
120
166
|
.legend-toggle:focus {
|
|
121
167
|
outline: 2px solid #3b82f6;
|
|
122
168
|
outline-offset: 2px;
|
|
123
169
|
border-radius: 4px;
|
|
124
170
|
}
|
|
171
|
+
|
|
125
172
|
.legend-title {
|
|
126
173
|
font-size: 13px;
|
|
127
174
|
font-weight: 600;
|
|
128
|
-
color: #374151;
|
|
175
|
+
color: #374151; /* gray-700 */
|
|
129
176
|
}
|
|
177
|
+
|
|
130
178
|
.legend-chevron {
|
|
131
179
|
transition: transform 0.2s ease;
|
|
132
|
-
color: #6b7280;
|
|
180
|
+
color: #6b7280; /* gray-500 */
|
|
133
181
|
}
|
|
182
|
+
|
|
134
183
|
.legend-chevron.expanded {
|
|
135
184
|
transform: rotate(180deg);
|
|
136
185
|
}
|
|
186
|
+
|
|
137
187
|
.legend-items {
|
|
138
188
|
display: flex;
|
|
139
189
|
flex-direction: column;
|
|
140
190
|
gap: 8px;
|
|
141
191
|
}
|
|
192
|
+
|
|
142
193
|
.legend-item {
|
|
143
194
|
display: flex;
|
|
144
195
|
align-items: center;
|
|
145
196
|
gap: 8px;
|
|
146
197
|
}
|
|
198
|
+
|
|
147
199
|
.legend-color {
|
|
148
200
|
width: 16px;
|
|
149
201
|
height: 16px;
|
|
150
202
|
border-radius: 4px;
|
|
151
203
|
flex-shrink: 0;
|
|
152
204
|
}
|
|
205
|
+
|
|
153
206
|
.legend-label {
|
|
154
207
|
font-size: 12px;
|
|
155
|
-
color: #4b5563;
|
|
208
|
+
color: #4b5563; /* gray-600 */
|
|
156
209
|
font-weight: 500;
|
|
157
210
|
}
|
|
211
|
+
|
|
212
|
+
/* =============================================================================
|
|
213
|
+
* React Flow Overrides
|
|
214
|
+
* ============================================================================= */
|
|
215
|
+
|
|
216
|
+
/* Make edges more visible */
|
|
158
217
|
.react-flow__edge-path {
|
|
159
218
|
stroke-width: 2;
|
|
160
219
|
}
|
|
220
|
+
|
|
221
|
+
/* Edge labels */
|
|
161
222
|
.react-flow__edge-text {
|
|
162
223
|
font-size: 12px;
|
|
163
224
|
font-weight: 600;
|
|
164
225
|
}
|
|
226
|
+
|
|
227
|
+
/* Controls */
|
|
165
228
|
.react-flow__controls {
|
|
166
229
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
167
230
|
}
|
|
231
|
+
|
|
168
232
|
.react-flow__controls-button {
|
|
169
233
|
border-bottom: 1px solid #e5e7eb;
|
|
170
234
|
}
|
|
235
|
+
|
|
171
236
|
.react-flow__controls-button:hover {
|
|
172
237
|
background: #f3f4f6;
|
|
173
238
|
}
|
|
239
|
+
|
|
240
|
+
/* Background */
|
|
174
241
|
.react-flow__background {
|
|
175
242
|
background-color: #f9fafb;
|
|
176
243
|
}
|
|
244
|
+
|
|
245
|
+
/* Attribution */
|
|
177
246
|
.react-flow__attribution {
|
|
178
247
|
opacity: 0.5;
|
|
179
248
|
font-size: 10px;
|
|
180
249
|
}
|
|
250
|
+
|
|
251
|
+
/* =============================================================================
|
|
252
|
+
* Responsive Design
|
|
253
|
+
* ============================================================================= */
|
|
254
|
+
|
|
181
255
|
@media (max-width: 640px) {
|
|
182
256
|
.stage-node {
|
|
183
257
|
min-width: 180px;
|
|
184
258
|
max-width: 220px;
|
|
185
259
|
padding: 12px;
|
|
186
260
|
}
|
|
261
|
+
|
|
187
262
|
.stage-number {
|
|
188
263
|
font-size: 24px;
|
|
189
264
|
}
|
|
265
|
+
|
|
190
266
|
.stage-name {
|
|
191
267
|
font-size: 14px;
|
|
192
268
|
}
|
|
269
|
+
|
|
193
270
|
.flow-legend {
|
|
194
271
|
min-width: 120px;
|
|
195
272
|
padding: 8px;
|
|
196
273
|
}
|
|
197
274
|
}
|
|
198
|
-
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FunnelVisualFlow Storybook Stories
|
|
3
|
+
*
|
|
4
|
+
* Visual testing and documentation for the FunnelVisualFlow component.
|
|
5
|
+
*
|
|
6
|
+
* Stories:
|
|
7
|
+
* 1. Empty (no stages)
|
|
8
|
+
* 2. Single stage
|
|
9
|
+
* 3. Simple funnel (3 stages)
|
|
10
|
+
* 4. Complex funnel (5+ stages)
|
|
11
|
+
* 5. With run data (shows stats)
|
|
12
|
+
* 6. Different action types (color coding)
|
|
13
|
+
* 7. Interactive (click callbacks)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
17
|
+
import { FunnelVisualFlow } from './FunnelVisualFlow';
|
|
18
|
+
import { Funnel, FunnelStage, FunnelRun } from '../../types';
|
|
19
|
+
|
|
20
|
+
const meta: Meta<typeof FunnelVisualFlow> = {
|
|
21
|
+
title: 'Components/FunnelVisualFlow',
|
|
22
|
+
component: FunnelVisualFlow,
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: 'fullscreen',
|
|
25
|
+
},
|
|
26
|
+
tags: ['autodocs'],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
type Story = StoryObj<typeof FunnelVisualFlow>;
|
|
31
|
+
|
|
32
|
+
// Helper to create stages
|
|
33
|
+
const createStage = (
|
|
34
|
+
id: string,
|
|
35
|
+
name: string,
|
|
36
|
+
order: number,
|
|
37
|
+
matchAction: any = 'continue',
|
|
38
|
+
noMatchAction: any = 'exclude'
|
|
39
|
+
): FunnelStage => ({
|
|
40
|
+
id,
|
|
41
|
+
order,
|
|
42
|
+
name,
|
|
43
|
+
description: `${name} stage filters entities`,
|
|
44
|
+
filter_logic: 'AND',
|
|
45
|
+
rules: [
|
|
46
|
+
{
|
|
47
|
+
field_path: 'score',
|
|
48
|
+
operator: 'gte',
|
|
49
|
+
value: 50,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
field_path: 'status',
|
|
53
|
+
operator: 'eq',
|
|
54
|
+
value: 'active',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
match_action: matchAction,
|
|
58
|
+
no_match_action: noMatchAction,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Helper to create funnel
|
|
62
|
+
const createFunnel = (
|
|
63
|
+
stages: FunnelStage[],
|
|
64
|
+
name: string = 'Sample Funnel'
|
|
65
|
+
): Funnel => ({
|
|
66
|
+
id: 'funnel-1',
|
|
67
|
+
name,
|
|
68
|
+
description: 'A sample funnel for visualization',
|
|
69
|
+
status: 'active',
|
|
70
|
+
input_type: 'contacts',
|
|
71
|
+
stages,
|
|
72
|
+
created_at: new Date().toISOString(),
|
|
73
|
+
updated_at: new Date().toISOString(),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Empty state
|
|
77
|
+
export const Empty: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
funnel: createFunnel([]),
|
|
80
|
+
height: 400,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Single stage
|
|
85
|
+
export const SingleStage: Story = {
|
|
86
|
+
args: {
|
|
87
|
+
funnel: createFunnel([createStage('stage-1', 'High ICP Score', 0)]),
|
|
88
|
+
height: 400,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Simple funnel (3 stages)
|
|
93
|
+
export const SimpleFunnel: Story = {
|
|
94
|
+
args: {
|
|
95
|
+
funnel: createFunnel(
|
|
96
|
+
[
|
|
97
|
+
createStage('stage-1', 'High ICP Score', 0),
|
|
98
|
+
createStage('stage-2', 'Frontend Stack', 1),
|
|
99
|
+
createStage('stage-3', 'Testing Tools', 2, 'output', 'exclude'),
|
|
100
|
+
],
|
|
101
|
+
'Frontend Developer Funnel'
|
|
102
|
+
),
|
|
103
|
+
height: 600,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Complex funnel (5 stages)
|
|
108
|
+
export const ComplexFunnel: Story = {
|
|
109
|
+
args: {
|
|
110
|
+
funnel: createFunnel(
|
|
111
|
+
[
|
|
112
|
+
createStage('stage-1', 'High ICP Score', 0),
|
|
113
|
+
createStage('stage-2', 'Frontend Stack', 1),
|
|
114
|
+
createStage('stage-3', 'Testing Tools', 2),
|
|
115
|
+
createStage('stage-4', 'Likely SMB', 3),
|
|
116
|
+
createStage('stage-5', 'Not Enterprise', 4, 'output', 'exclude'),
|
|
117
|
+
],
|
|
118
|
+
'SMB Frontend Developer Funnel'
|
|
119
|
+
),
|
|
120
|
+
height: 800,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// With run data (shows stats)
|
|
125
|
+
export const WithRunData: Story = {
|
|
126
|
+
args: {
|
|
127
|
+
funnel: createFunnel(
|
|
128
|
+
[
|
|
129
|
+
createStage('stage-1', 'High ICP Score', 0),
|
|
130
|
+
createStage('stage-2', 'Frontend Stack', 1),
|
|
131
|
+
createStage('stage-3', 'Testing Tools', 2, 'output', 'exclude'),
|
|
132
|
+
],
|
|
133
|
+
'Frontend Developer Funnel'
|
|
134
|
+
),
|
|
135
|
+
runData: {
|
|
136
|
+
id: 'run-1',
|
|
137
|
+
funnel_id: 'funnel-1',
|
|
138
|
+
status: 'completed',
|
|
139
|
+
trigger_type: 'manual',
|
|
140
|
+
started_at: new Date().toISOString(),
|
|
141
|
+
completed_at: new Date().toISOString(),
|
|
142
|
+
duration_ms: 1234,
|
|
143
|
+
total_input: 1000,
|
|
144
|
+
total_matched: 235,
|
|
145
|
+
total_excluded: 765,
|
|
146
|
+
total_tagged: 0,
|
|
147
|
+
stage_stats: {
|
|
148
|
+
'stage-1': {
|
|
149
|
+
stage_id: 'stage-1',
|
|
150
|
+
stage_name: 'High ICP Score',
|
|
151
|
+
input_count: 1000,
|
|
152
|
+
matched_count: 500,
|
|
153
|
+
not_matched_count: 500,
|
|
154
|
+
excluded_count: 500,
|
|
155
|
+
tagged_count: 0,
|
|
156
|
+
continued_count: 500,
|
|
157
|
+
},
|
|
158
|
+
'stage-2': {
|
|
159
|
+
stage_id: 'stage-2',
|
|
160
|
+
stage_name: 'Frontend Stack',
|
|
161
|
+
input_count: 500,
|
|
162
|
+
matched_count: 350,
|
|
163
|
+
not_matched_count: 150,
|
|
164
|
+
excluded_count: 150,
|
|
165
|
+
tagged_count: 0,
|
|
166
|
+
continued_count: 350,
|
|
167
|
+
},
|
|
168
|
+
'stage-3': {
|
|
169
|
+
stage_id: 'stage-3',
|
|
170
|
+
stage_name: 'Testing Tools',
|
|
171
|
+
input_count: 350,
|
|
172
|
+
matched_count: 235,
|
|
173
|
+
not_matched_count: 115,
|
|
174
|
+
excluded_count: 115,
|
|
175
|
+
tagged_count: 0,
|
|
176
|
+
continued_count: 235,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
} as FunnelRun,
|
|
180
|
+
height: 600,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Different action types (color coding)
|
|
185
|
+
export const ActionTypes: Story = {
|
|
186
|
+
args: {
|
|
187
|
+
funnel: createFunnel(
|
|
188
|
+
[
|
|
189
|
+
createStage('stage-1', 'Continue Action', 0, 'continue', 'continue'),
|
|
190
|
+
createStage('stage-2', 'Tag Action', 1, 'tag', 'continue'),
|
|
191
|
+
createStage('stage-3', 'Tag & Continue', 2, 'tag_continue', 'exclude'),
|
|
192
|
+
createStage('stage-4', 'Exclude Action', 3, 'continue', 'exclude'),
|
|
193
|
+
createStage('stage-5', 'Output Action', 4, 'output', 'exclude'),
|
|
194
|
+
],
|
|
195
|
+
'Action Types Demo'
|
|
196
|
+
),
|
|
197
|
+
height: 800,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Interactive (with callbacks)
|
|
202
|
+
export const Interactive: Story = {
|
|
203
|
+
args: {
|
|
204
|
+
funnel: createFunnel(
|
|
205
|
+
[
|
|
206
|
+
createStage('stage-1', 'High ICP Score', 0),
|
|
207
|
+
createStage('stage-2', 'Frontend Stack', 1),
|
|
208
|
+
createStage('stage-3', 'Testing Tools', 2, 'output', 'exclude'),
|
|
209
|
+
],
|
|
210
|
+
'Interactive Funnel'
|
|
211
|
+
),
|
|
212
|
+
onStageClick: (stage: FunnelStage) => {
|
|
213
|
+
alert(`Clicked stage: ${stage.name}`);
|
|
214
|
+
},
|
|
215
|
+
onEdgeClick: (fromStage: string, toStage: string) => {
|
|
216
|
+
alert(`Clicked edge from ${fromStage} to ${toStage}`);
|
|
217
|
+
},
|
|
218
|
+
height: 600,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Custom height
|
|
223
|
+
export const CustomHeight: Story = {
|
|
224
|
+
args: {
|
|
225
|
+
funnel: createFunnel(
|
|
226
|
+
[
|
|
227
|
+
createStage('stage-1', 'High ICP Score', 0),
|
|
228
|
+
createStage('stage-2', 'Frontend Stack', 1),
|
|
229
|
+
createStage('stage-3', 'Testing Tools', 2, 'output', 'exclude'),
|
|
230
|
+
],
|
|
231
|
+
'Custom Height Funnel'
|
|
232
|
+
),
|
|
233
|
+
height: 400,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Large funnel (10 stages)
|
|
238
|
+
export const LargeFunnel: Story = {
|
|
239
|
+
args: {
|
|
240
|
+
funnel: createFunnel(
|
|
241
|
+
Array.from({ length: 10 }, (_, i) =>
|
|
242
|
+
createStage(
|
|
243
|
+
`stage-${i + 1}`,
|
|
244
|
+
`Stage ${i + 1}`,
|
|
245
|
+
i,
|
|
246
|
+
i === 9 ? 'output' : 'continue',
|
|
247
|
+
'exclude'
|
|
248
|
+
)
|
|
249
|
+
),
|
|
250
|
+
'Large Funnel (10 Stages)'
|
|
251
|
+
),
|
|
252
|
+
height: 1000,
|
|
253
|
+
},
|
|
254
|
+
};
|