@startsimpli/funnels 0.1.4 → 0.1.6
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 -3241
- 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 -3194
- 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 -20
- 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 -18
- 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 -389
- 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 -386
- package/dist/store/index.js.map +0 -1
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store types for @startsimpli/funnels
|
|
3
|
+
*
|
|
4
|
+
* Generic Zustand store for managing funnel state.
|
|
5
|
+
* Works with any entity type - no product-specific logic.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
Funnel,
|
|
10
|
+
FunnelStage,
|
|
11
|
+
FunnelRun,
|
|
12
|
+
CreateFunnelInput,
|
|
13
|
+
UpdateFunnelInput,
|
|
14
|
+
CreateStageInput,
|
|
15
|
+
UpdateStageInput,
|
|
16
|
+
} from '../types';
|
|
17
|
+
|
|
18
|
+
import type {
|
|
19
|
+
FunnelListFilters,
|
|
20
|
+
PaginatedResponse,
|
|
21
|
+
} from '../api/client';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Store state interface
|
|
25
|
+
*
|
|
26
|
+
* Generic over entity type TEntity
|
|
27
|
+
*/
|
|
28
|
+
export interface FunnelStore<TEntity = any> {
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Data State
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
/** All loaded funnels */
|
|
34
|
+
funnels: Funnel<TEntity>[];
|
|
35
|
+
|
|
36
|
+
/** Currently selected funnel */
|
|
37
|
+
selectedFunnel: Funnel<TEntity> | null;
|
|
38
|
+
|
|
39
|
+
/** Currently selected stage (for editing) */
|
|
40
|
+
selectedStage: FunnelStage<TEntity> | null;
|
|
41
|
+
|
|
42
|
+
/** Funnel runs for selected funnel */
|
|
43
|
+
runs: FunnelRun[];
|
|
44
|
+
|
|
45
|
+
/** Pagination info */
|
|
46
|
+
pagination: {
|
|
47
|
+
count: number;
|
|
48
|
+
next: string | null;
|
|
49
|
+
previous: string | null;
|
|
50
|
+
currentPage: number;
|
|
51
|
+
pageSize: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// UI State
|
|
56
|
+
// ============================================================================
|
|
57
|
+
|
|
58
|
+
/** Loading state */
|
|
59
|
+
isLoading: boolean;
|
|
60
|
+
|
|
61
|
+
/** Error state */
|
|
62
|
+
error: Error | null;
|
|
63
|
+
|
|
64
|
+
/** Dirty flag - unsaved changes */
|
|
65
|
+
isDirty: boolean;
|
|
66
|
+
|
|
67
|
+
/** Optimistic update rollback state */
|
|
68
|
+
rollbackState: {
|
|
69
|
+
funnels: Funnel<TEntity>[];
|
|
70
|
+
selectedFunnel: Funnel<TEntity> | null;
|
|
71
|
+
} | null;
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Funnel Actions
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Load funnels with optional filters
|
|
79
|
+
*
|
|
80
|
+
* @param filters - Optional filters (status, owner, pagination, etc)
|
|
81
|
+
*/
|
|
82
|
+
loadFunnels: (filters?: FunnelListFilters) => Promise<void>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Select funnel for editing
|
|
86
|
+
*
|
|
87
|
+
* @param id - Funnel ID
|
|
88
|
+
*/
|
|
89
|
+
selectFunnel: (id: string | null) => void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create new funnel
|
|
93
|
+
*
|
|
94
|
+
* @param data - Funnel creation data
|
|
95
|
+
* @returns Created funnel
|
|
96
|
+
*/
|
|
97
|
+
createFunnel: (data: CreateFunnelInput<TEntity>) => Promise<Funnel<TEntity>>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Update funnel (optimistic update)
|
|
101
|
+
*
|
|
102
|
+
* @param id - Funnel ID
|
|
103
|
+
* @param data - Update data
|
|
104
|
+
* @returns Updated funnel
|
|
105
|
+
*/
|
|
106
|
+
updateFunnel: (
|
|
107
|
+
id: string,
|
|
108
|
+
data: Partial<UpdateFunnelInput<TEntity>>
|
|
109
|
+
) => Promise<Funnel<TEntity>>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Delete funnel (optimistic update)
|
|
113
|
+
*
|
|
114
|
+
* @param id - Funnel ID
|
|
115
|
+
*/
|
|
116
|
+
deleteFunnel: (id: string) => Promise<void>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Duplicate funnel
|
|
120
|
+
*
|
|
121
|
+
* @param id - Funnel ID to duplicate
|
|
122
|
+
* @returns New funnel
|
|
123
|
+
*/
|
|
124
|
+
duplicateFunnel: (id: string) => Promise<Funnel<TEntity>>;
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Stage Actions
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Select stage for editing
|
|
132
|
+
*
|
|
133
|
+
* @param stageId - Stage ID (null to clear selection)
|
|
134
|
+
*/
|
|
135
|
+
selectStage: (stageId: string | null) => void;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Create new stage in funnel
|
|
139
|
+
*
|
|
140
|
+
* @param funnelId - Funnel ID
|
|
141
|
+
* @param data - Stage creation data
|
|
142
|
+
* @returns Created stage
|
|
143
|
+
*/
|
|
144
|
+
createStage: (
|
|
145
|
+
funnelId: string,
|
|
146
|
+
data: CreateStageInput<TEntity>
|
|
147
|
+
) => Promise<FunnelStage<TEntity>>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Update stage (optimistic update)
|
|
151
|
+
*
|
|
152
|
+
* @param funnelId - Funnel ID
|
|
153
|
+
* @param stageId - Stage ID
|
|
154
|
+
* @param data - Update data
|
|
155
|
+
* @returns Updated stage
|
|
156
|
+
*/
|
|
157
|
+
updateStage: (
|
|
158
|
+
funnelId: string,
|
|
159
|
+
stageId: string,
|
|
160
|
+
data: Partial<UpdateStageInput<TEntity>>
|
|
161
|
+
) => Promise<FunnelStage<TEntity>>;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Delete stage (optimistic update)
|
|
165
|
+
*
|
|
166
|
+
* @param funnelId - Funnel ID
|
|
167
|
+
* @param stageId - Stage ID
|
|
168
|
+
*/
|
|
169
|
+
deleteStage: (funnelId: string, stageId: string) => Promise<void>;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Reorder stages (optimistic update)
|
|
173
|
+
*
|
|
174
|
+
* @param funnelId - Funnel ID
|
|
175
|
+
* @param stageIds - New order of stage IDs
|
|
176
|
+
*/
|
|
177
|
+
reorderStages: (funnelId: string, stageIds: string[]) => Promise<void>;
|
|
178
|
+
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// Run Actions
|
|
181
|
+
// ============================================================================
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Run funnel
|
|
185
|
+
*
|
|
186
|
+
* @param id - Funnel ID
|
|
187
|
+
* @param options - Run options
|
|
188
|
+
* @returns Created run
|
|
189
|
+
*/
|
|
190
|
+
runFunnel: (
|
|
191
|
+
id: string,
|
|
192
|
+
options?: {
|
|
193
|
+
trigger_type?: 'manual' | 'scheduled' | 'webhook' | 'api';
|
|
194
|
+
metadata?: Record<string, any>;
|
|
195
|
+
}
|
|
196
|
+
) => Promise<FunnelRun>;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Load funnel runs
|
|
200
|
+
*
|
|
201
|
+
* @param funnelId - Funnel ID
|
|
202
|
+
* @param filters - Optional filters
|
|
203
|
+
*/
|
|
204
|
+
loadRuns: (
|
|
205
|
+
funnelId: string,
|
|
206
|
+
filters?: {
|
|
207
|
+
status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
208
|
+
page?: number;
|
|
209
|
+
page_size?: number;
|
|
210
|
+
}
|
|
211
|
+
) => Promise<void>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Cancel running funnel
|
|
215
|
+
*
|
|
216
|
+
* @param runId - Run ID
|
|
217
|
+
*/
|
|
218
|
+
cancelRun: (runId: string) => Promise<FunnelRun>;
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// UI State Actions
|
|
222
|
+
// ============================================================================
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Set dirty flag
|
|
226
|
+
*
|
|
227
|
+
* @param dirty - Dirty state
|
|
228
|
+
*/
|
|
229
|
+
setDirty: (dirty: boolean) => void;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Clear error
|
|
233
|
+
*/
|
|
234
|
+
clearError: () => void;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Reset store to initial state
|
|
238
|
+
*/
|
|
239
|
+
reset: () => void;
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Internal Actions (for optimistic updates)
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Save current state for rollback
|
|
247
|
+
* @internal
|
|
248
|
+
*/
|
|
249
|
+
_saveRollbackState: () => void;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Rollback to saved state
|
|
253
|
+
* @internal
|
|
254
|
+
*/
|
|
255
|
+
_rollback: () => void;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Clear rollback state
|
|
259
|
+
* @internal
|
|
260
|
+
*/
|
|
261
|
+
_clearRollback: () => void;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Initial state factory
|
|
266
|
+
*/
|
|
267
|
+
export const createInitialState = <TEntity = any>(): Pick<
|
|
268
|
+
FunnelStore<TEntity>,
|
|
269
|
+
| 'funnels'
|
|
270
|
+
| 'selectedFunnel'
|
|
271
|
+
| 'selectedStage'
|
|
272
|
+
| 'runs'
|
|
273
|
+
| 'pagination'
|
|
274
|
+
| 'isLoading'
|
|
275
|
+
| 'error'
|
|
276
|
+
| 'isDirty'
|
|
277
|
+
| 'rollbackState'
|
|
278
|
+
> => ({
|
|
279
|
+
funnels: [],
|
|
280
|
+
selectedFunnel: null,
|
|
281
|
+
selectedStage: null,
|
|
282
|
+
runs: [],
|
|
283
|
+
pagination: {
|
|
284
|
+
count: 0,
|
|
285
|
+
next: null,
|
|
286
|
+
previous: null,
|
|
287
|
+
currentPage: 1,
|
|
288
|
+
pageSize: 20,
|
|
289
|
+
},
|
|
290
|
+
isLoading: false,
|
|
291
|
+
error: null,
|
|
292
|
+
isDirty: false,
|
|
293
|
+
rollbackState: null,
|
|
294
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { FunnelCard } from '../components/FunnelCard/FunnelCard';
|
|
3
|
+
import {
|
|
4
|
+
investorFields,
|
|
5
|
+
investorFunnelExample,
|
|
6
|
+
recipeFields,
|
|
7
|
+
recipeFunnelExample,
|
|
8
|
+
leadFields,
|
|
9
|
+
leadFunnelExample,
|
|
10
|
+
} from './demo-data';
|
|
11
|
+
|
|
12
|
+
const meta: Meta = {
|
|
13
|
+
title: 'Cross-Domain/Works with ANY Entity Type',
|
|
14
|
+
parameters: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component: 'Demonstrates that @startsimpli/funnels works with ANY entity type - investors, recipes, leads, or whatever you need!',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
type Story = StoryObj<typeof FunnelCard>;
|
|
26
|
+
|
|
27
|
+
export const InvestorFunnel: Story = {
|
|
28
|
+
render: () => (
|
|
29
|
+
<div style={{ padding: '2rem' }}>
|
|
30
|
+
<h2 style={{ marginBottom: '1rem' }}>Investor Filtering Funnel</h2>
|
|
31
|
+
<p style={{ color: '#666', marginBottom: '2rem' }}>
|
|
32
|
+
Target high-priority seed-stage VCs with strong SaaS focus and recent engagement
|
|
33
|
+
</p>
|
|
34
|
+
<FunnelCard
|
|
35
|
+
funnel={investorFunnelExample}
|
|
36
|
+
onEdit={() => console.log('Edit investor funnel')}
|
|
37
|
+
onRun={() => console.log('Run investor funnel')}
|
|
38
|
+
onDelete={() => console.log('Delete investor funnel')}
|
|
39
|
+
/>
|
|
40
|
+
<div style={{ marginTop: '2rem', padding: '1rem', backgroundColor: '#f9fafb', borderRadius: '8px' }}>
|
|
41
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Available Fields:</h3>
|
|
42
|
+
<ul style={{ fontSize: '0.875rem', lineHeight: '1.6' }}>
|
|
43
|
+
{investorFields.map((field) => (
|
|
44
|
+
<li key={field.name}>
|
|
45
|
+
<strong>{field.label}</strong> ({field.type}) - {field.description}
|
|
46
|
+
</li>
|
|
47
|
+
))}
|
|
48
|
+
</ul>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const RecipeFunnel: Story = {
|
|
55
|
+
render: () => (
|
|
56
|
+
<div style={{ padding: '2rem' }}>
|
|
57
|
+
<h2 style={{ marginBottom: '1rem' }}>Recipe Filtering Funnel</h2>
|
|
58
|
+
<p style={{ color: '#666', marginBottom: '2rem' }}>
|
|
59
|
+
Find quick, healthy, easy recipes with high ratings
|
|
60
|
+
</p>
|
|
61
|
+
<FunnelCard
|
|
62
|
+
funnel={recipeFunnelExample}
|
|
63
|
+
onEdit={() => console.log('Edit recipe funnel')}
|
|
64
|
+
onRun={() => console.log('Run recipe funnel')}
|
|
65
|
+
onDelete={() => console.log('Delete recipe funnel')}
|
|
66
|
+
/>
|
|
67
|
+
<div style={{ marginTop: '2rem', padding: '1rem', backgroundColor: '#f9fafb', borderRadius: '8px' }}>
|
|
68
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Available Fields:</h3>
|
|
69
|
+
<ul style={{ fontSize: '0.875rem', lineHeight: '1.6' }}>
|
|
70
|
+
{recipeFields.map((field) => (
|
|
71
|
+
<li key={field.name}>
|
|
72
|
+
<strong>{field.label}</strong> ({field.type}) - {field.description}
|
|
73
|
+
</li>
|
|
74
|
+
))}
|
|
75
|
+
</ul>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const LeadScoringFunnel: Story = {
|
|
82
|
+
render: () => (
|
|
83
|
+
<div style={{ padding: '2rem' }}>
|
|
84
|
+
<h2 style={{ marginBottom: '1rem' }}>Lead Scoring Funnel</h2>
|
|
85
|
+
<p style={{ color: '#666', marginBottom: '2rem' }}>
|
|
86
|
+
Target high-value enterprise leads with strong engagement
|
|
87
|
+
</p>
|
|
88
|
+
<FunnelCard
|
|
89
|
+
funnel={leadFunnelExample}
|
|
90
|
+
onEdit={() => console.log('Edit lead funnel')}
|
|
91
|
+
onRun={() => console.log('Run lead funnel')}
|
|
92
|
+
onDelete={() => console.log('Delete lead funnel')}
|
|
93
|
+
/>
|
|
94
|
+
<div style={{ marginTop: '2rem', padding: '1rem', backgroundColor: '#f9fafb', borderRadius: '8px' }}>
|
|
95
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Available Fields:</h3>
|
|
96
|
+
<ul style={{ fontSize: '0.875rem', lineHeight: '1.6' }}>
|
|
97
|
+
{leadFields.map((field) => (
|
|
98
|
+
<li key={field.name}>
|
|
99
|
+
<strong>{field.label}</strong> ({field.type}) - {field.description}
|
|
100
|
+
</li>
|
|
101
|
+
))}
|
|
102
|
+
</ul>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const SideBySideComparison: Story = {
|
|
109
|
+
render: () => (
|
|
110
|
+
<div style={{ padding: '2rem' }}>
|
|
111
|
+
<h2 style={{ marginBottom: '1rem' }}>Side-by-Side: Same Component, Different Domains</h2>
|
|
112
|
+
<p style={{ color: '#666', marginBottom: '2rem' }}>
|
|
113
|
+
The exact same FunnelCard component works seamlessly across all entity types
|
|
114
|
+
</p>
|
|
115
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '1.5rem' }}>
|
|
116
|
+
<div>
|
|
117
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Investors</h3>
|
|
118
|
+
<FunnelCard
|
|
119
|
+
funnel={investorFunnelExample}
|
|
120
|
+
onEdit={() => console.log('Edit')}
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
<div>
|
|
124
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Recipes</h3>
|
|
125
|
+
<FunnelCard
|
|
126
|
+
funnel={recipeFunnelExample}
|
|
127
|
+
onEdit={() => console.log('Edit')}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
<h3 style={{ fontSize: '1rem', marginBottom: '0.5rem' }}>Leads</h3>
|
|
132
|
+
<FunnelCard
|
|
133
|
+
funnel={leadFunnelExample}
|
|
134
|
+
onEdit={() => console.log('Edit')}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
<div style={{
|
|
139
|
+
marginTop: '2rem',
|
|
140
|
+
padding: '1rem',
|
|
141
|
+
backgroundColor: '#ecfdf5',
|
|
142
|
+
borderLeft: '4px solid #10b981',
|
|
143
|
+
borderRadius: '4px'
|
|
144
|
+
}}>
|
|
145
|
+
<strong>That's the power of brutal genericity!</strong> The same component adapts to any domain.
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
),
|
|
149
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
title: 'Welcome to @startsimpli/funnels',
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const Introduction = () => (
|
|
6
|
+
<div style={{ padding: '2rem', maxWidth: '800px', fontFamily: 'system-ui, sans-serif' }}>
|
|
7
|
+
<h1 style={{ fontSize: '2.5rem', marginBottom: '1rem' }}>@startsimpli/funnels</h1>
|
|
8
|
+
<p style={{ fontSize: '1.2rem', color: '#666', marginBottom: '2rem' }}>
|
|
9
|
+
Brutally generic filtering pipeline package for any Simpli product.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<h2 style={{ fontSize: '1.8rem', marginTop: '2rem', marginBottom: '1rem' }}>What is this?</h2>
|
|
13
|
+
<p style={{ lineHeight: '1.6', marginBottom: '1rem' }}>
|
|
14
|
+
A reusable package for building multi-stage filtering funnels that work with ANY entity type.
|
|
15
|
+
Create visual, interactive pipelines to filter and segment your data.
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<h2 style={{ fontSize: '1.8rem', marginTop: '2rem', marginBottom: '1rem' }}>Why "brutally generic"?</h2>
|
|
19
|
+
<p style={{ lineHeight: '1.6', marginBottom: '1rem' }}>
|
|
20
|
+
This package doesn't care what you're filtering. It works equally well for:
|
|
21
|
+
</p>
|
|
22
|
+
<ul style={{ lineHeight: '1.8', marginLeft: '2rem', marginBottom: '1rem' }}>
|
|
23
|
+
<li>Investors and VC firms</li>
|
|
24
|
+
<li>Recipes and cooking content</li>
|
|
25
|
+
<li>Leads and sales prospects</li>
|
|
26
|
+
<li>Tasks and project items</li>
|
|
27
|
+
<li>...whatever entity type you need!</li>
|
|
28
|
+
</ul>
|
|
29
|
+
|
|
30
|
+
<h2 style={{ fontSize: '1.8rem', marginTop: '2rem', marginBottom: '1rem' }}>Key Features</h2>
|
|
31
|
+
<ul style={{ lineHeight: '1.8', marginLeft: '2rem', marginBottom: '1rem' }}>
|
|
32
|
+
<li><strong>Multi-stage filtering:</strong> Build complex pipelines with multiple stages</li>
|
|
33
|
+
<li><strong>Visual flow diagrams:</strong> See your funnel logic at a glance</li>
|
|
34
|
+
<li><strong>Dynamic rule builder:</strong> Create AND/OR logic without writing code</li>
|
|
35
|
+
<li><strong>Live preview:</strong> See matches in real-time as you build</li>
|
|
36
|
+
<li><strong>Run history:</strong> Track funnel executions and results</li>
|
|
37
|
+
<li><strong>Type-safe:</strong> Full TypeScript support</li>
|
|
38
|
+
</ul>
|
|
39
|
+
|
|
40
|
+
<h2 style={{ fontSize: '1.8rem', marginTop: '2rem', marginBottom: '1rem' }}>Explore the Components</h2>
|
|
41
|
+
<div style={{ display: 'grid', gap: '1rem', marginTop: '1rem' }}>
|
|
42
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
43
|
+
<strong>FunnelCard</strong> - Visual funnel cards with stats and status
|
|
44
|
+
</div>
|
|
45
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
46
|
+
<strong>FunnelStageBuilder</strong> - Drag-and-drop stage editor
|
|
47
|
+
</div>
|
|
48
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
49
|
+
<strong>FilterRuleEditor</strong> - Dynamic rule builder with field selection
|
|
50
|
+
</div>
|
|
51
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
52
|
+
<strong>FunnelPreview</strong> - Live preview of matches with sample data
|
|
53
|
+
</div>
|
|
54
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
55
|
+
<strong>FunnelVisualFlow</strong> - Interactive flow diagram
|
|
56
|
+
</div>
|
|
57
|
+
<div style={{ padding: '1rem', border: '1px solid #ddd', borderRadius: '8px' }}>
|
|
58
|
+
<strong>FunnelRunHistory</strong> - Track execution history and results
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<h2 style={{ fontSize: '1.8rem', marginTop: '2rem', marginBottom: '1rem' }}>Getting Started</h2>
|
|
63
|
+
<p style={{ lineHeight: '1.6', marginBottom: '1rem' }}>
|
|
64
|
+
Check out the <strong>Cross-Domain</strong> stories to see how the same components work
|
|
65
|
+
with completely different entity types (investors, recipes, leads).
|
|
66
|
+
</p>
|
|
67
|
+
<p style={{ lineHeight: '1.6', marginBottom: '1rem' }}>
|
|
68
|
+
Then explore individual component stories to see all the features and variants.
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
<div style={{
|
|
72
|
+
marginTop: '2rem',
|
|
73
|
+
padding: '1rem',
|
|
74
|
+
backgroundColor: '#f0f9ff',
|
|
75
|
+
borderLeft: '4px solid #0284c7',
|
|
76
|
+
borderRadius: '4px'
|
|
77
|
+
}}>
|
|
78
|
+
<strong>Pro Tip:</strong> Use the Controls panel to interact with component props in real-time!
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|