@framed-dev/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5799 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3314 -0
- package/dist/index.d.ts +3314 -0
- package/dist/index.js +5618 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,3314 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
export { SupabaseClient } from '@supabase/supabase-js';
|
|
3
|
+
|
|
4
|
+
type LocalizedContent = Record<string, string>;
|
|
5
|
+
type LocalizableString = string | LocalizedContent;
|
|
6
|
+
declare const isLocalizedContent: (value: LocalizableString) => value is LocalizedContent;
|
|
7
|
+
declare const getLocalizedValue: (value: LocalizableString | undefined, language: string, primaryLanguage?: string) => string;
|
|
8
|
+
declare const toLocalizedContent: (value: LocalizableString, primaryLanguage: string) => LocalizedContent;
|
|
9
|
+
declare const ensureLocalizedContent: (value: LocalizableString | undefined, primaryLanguage: string) => LocalizedContent;
|
|
10
|
+
declare const str: (value: LocalizableString | undefined, lang?: string) => string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* i18n utilities - Stub implementations
|
|
14
|
+
*
|
|
15
|
+
* These are placeholder functions for internationalization.
|
|
16
|
+
* In the full SaaS app, this would use react-i18next.
|
|
17
|
+
* For the widget/SDK, translations should be provided by the host app.
|
|
18
|
+
*/
|
|
19
|
+
type TranslationOptions = {
|
|
20
|
+
[key: string]: string | number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Translation function type
|
|
24
|
+
* Returns the translation for a key, or the fallback if provided
|
|
25
|
+
*/
|
|
26
|
+
type TFunction = (key: string, fallbackOrOptions?: string | TranslationOptions) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Stub useTranslation hook
|
|
29
|
+
*
|
|
30
|
+
* Returns a simple t function that:
|
|
31
|
+
* - If second arg is a string, returns it as fallback
|
|
32
|
+
* - If second arg is an object with interpolation values, returns key with values interpolated
|
|
33
|
+
* - Otherwise returns the key
|
|
34
|
+
*/
|
|
35
|
+
declare function useTranslation(_namespaces?: string[]): {
|
|
36
|
+
t: TFunction;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
interface Phase2Data {
|
|
40
|
+
pages: PageDetail[];
|
|
41
|
+
}
|
|
42
|
+
interface PageDetail {
|
|
43
|
+
id?: string;
|
|
44
|
+
name: string;
|
|
45
|
+
layout_type: string;
|
|
46
|
+
sections: Section[];
|
|
47
|
+
features: string[];
|
|
48
|
+
}
|
|
49
|
+
interface Section {
|
|
50
|
+
id?: string;
|
|
51
|
+
type: string;
|
|
52
|
+
order: number;
|
|
53
|
+
custom_name?: string;
|
|
54
|
+
title: LocalizableString;
|
|
55
|
+
content: LocalizableString;
|
|
56
|
+
media: MediaInfo[];
|
|
57
|
+
ctas: CTAInfo[];
|
|
58
|
+
additional_content?: AdditionalContentItem[];
|
|
59
|
+
skip_section: boolean;
|
|
60
|
+
skip_reason?: string;
|
|
61
|
+
is_completed?: boolean;
|
|
62
|
+
is_cms_managed?: boolean;
|
|
63
|
+
cms_fields?: string[];
|
|
64
|
+
type_data?: SectionTypeData;
|
|
65
|
+
ai_layout_hints?: {
|
|
66
|
+
columns?: number;
|
|
67
|
+
mediaPosition?: 'left' | 'right' | 'top' | 'bottom' | 'background';
|
|
68
|
+
style?: 'minimal' | 'bold' | 'elegant' | 'playful';
|
|
69
|
+
};
|
|
70
|
+
layout_notes?: string;
|
|
71
|
+
}
|
|
72
|
+
type AdditionalContentType = 'text' | 'image' | 'button' | 'video' | 'heading' | 'list';
|
|
73
|
+
interface AdditionalContentItem {
|
|
74
|
+
id: string;
|
|
75
|
+
type: AdditionalContentType;
|
|
76
|
+
order: number;
|
|
77
|
+
data: {
|
|
78
|
+
text?: LocalizableString;
|
|
79
|
+
media?: MediaInfo;
|
|
80
|
+
cta?: CTAInfo;
|
|
81
|
+
heading?: LocalizableString;
|
|
82
|
+
heading_level?: 'h2' | 'h3' | 'h4';
|
|
83
|
+
list_items?: LocalizableString | string[];
|
|
84
|
+
list_style?: 'bullet' | 'numbered';
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
interface SectionTypeData {
|
|
88
|
+
map_address?: string;
|
|
89
|
+
map_zoom?: number;
|
|
90
|
+
form_fields?: string[];
|
|
91
|
+
form_submit_email?: string;
|
|
92
|
+
pricing_tiers?: PricingTier[];
|
|
93
|
+
stats?: Stat[];
|
|
94
|
+
faqs?: FAQ[];
|
|
95
|
+
}
|
|
96
|
+
interface PricingTier {
|
|
97
|
+
name: string;
|
|
98
|
+
price: string;
|
|
99
|
+
features: string[];
|
|
100
|
+
highlighted?: boolean;
|
|
101
|
+
}
|
|
102
|
+
interface Stat {
|
|
103
|
+
number: string;
|
|
104
|
+
label: string;
|
|
105
|
+
suffix?: string;
|
|
106
|
+
}
|
|
107
|
+
interface FAQ {
|
|
108
|
+
question: string;
|
|
109
|
+
answer: string;
|
|
110
|
+
}
|
|
111
|
+
interface MediaInfo {
|
|
112
|
+
type: 'image' | 'video' | 'illustration' | 'icon' | 'none';
|
|
113
|
+
description: LocalizableString;
|
|
114
|
+
alt?: string;
|
|
115
|
+
url: string | null;
|
|
116
|
+
uploaded_file?: {
|
|
117
|
+
name: string;
|
|
118
|
+
size: number;
|
|
119
|
+
type: string;
|
|
120
|
+
path: string;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
interface CTAInfo {
|
|
124
|
+
text: LocalizableString;
|
|
125
|
+
action: string;
|
|
126
|
+
target: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
type PlanTier = 'free' | 'pro' | 'team';
|
|
130
|
+
type AuthMode = 'dev' | 'local' | 'magic_link' | 'framed_login';
|
|
131
|
+
type TaskStatus = 'open' | 'in_progress' | 'done' | 'rejected';
|
|
132
|
+
type TaskType = 'text_change' | 'bug_report' | 'style_change' | 'feature_request' | 'content_update' | 'general_feedback';
|
|
133
|
+
interface FramedConfig {
|
|
134
|
+
projectId: string;
|
|
135
|
+
mode: 'local' | 'sync';
|
|
136
|
+
auth: AuthConfig;
|
|
137
|
+
ai?: AIConfig;
|
|
138
|
+
sync?: SyncConfig;
|
|
139
|
+
widget?: WidgetConfig;
|
|
140
|
+
features?: Partial<WidgetFeatures>;
|
|
141
|
+
}
|
|
142
|
+
interface AuthConfig {
|
|
143
|
+
mode: AuthMode;
|
|
144
|
+
loginRoute?: string;
|
|
145
|
+
allowedEmails?: string[];
|
|
146
|
+
}
|
|
147
|
+
interface AIConfig {
|
|
148
|
+
provider: 'openrouter' | 'anthropic';
|
|
149
|
+
apiKey: string;
|
|
150
|
+
model?: string;
|
|
151
|
+
}
|
|
152
|
+
interface SyncConfig {
|
|
153
|
+
apiKey: string;
|
|
154
|
+
supabaseUrl: string;
|
|
155
|
+
}
|
|
156
|
+
interface WidgetConfig {
|
|
157
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
158
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
159
|
+
hotkey?: string;
|
|
160
|
+
}
|
|
161
|
+
interface WidgetFeatures {
|
|
162
|
+
elementSelect: boolean;
|
|
163
|
+
textEdit: boolean;
|
|
164
|
+
annotate: boolean;
|
|
165
|
+
screenshot: boolean;
|
|
166
|
+
regionSelect: boolean;
|
|
167
|
+
screenRecording: boolean;
|
|
168
|
+
voiceInput: boolean;
|
|
169
|
+
mobilePreview: boolean;
|
|
170
|
+
feedbackDrawer: boolean;
|
|
171
|
+
multiplayer: boolean;
|
|
172
|
+
presence: boolean;
|
|
173
|
+
assignments: boolean;
|
|
174
|
+
mentions: boolean;
|
|
175
|
+
activityFeed: boolean;
|
|
176
|
+
teamRoles: boolean;
|
|
177
|
+
}
|
|
178
|
+
interface Session {
|
|
179
|
+
id: string;
|
|
180
|
+
user: {
|
|
181
|
+
id: string;
|
|
182
|
+
name: string;
|
|
183
|
+
email?: string;
|
|
184
|
+
};
|
|
185
|
+
permissions: {
|
|
186
|
+
canSubmitFeedback: boolean;
|
|
187
|
+
canViewTasks: boolean;
|
|
188
|
+
canEditTasks: boolean;
|
|
189
|
+
};
|
|
190
|
+
limits: UsageLimits;
|
|
191
|
+
expiresAt: string;
|
|
192
|
+
}
|
|
193
|
+
interface UsageLimits {
|
|
194
|
+
feedbackPerMonth: number;
|
|
195
|
+
feedbackUsed: number;
|
|
196
|
+
aiParsesPerMonth: number;
|
|
197
|
+
aiParsesUsed: number;
|
|
198
|
+
projects: number;
|
|
199
|
+
reviewersPerProject: number;
|
|
200
|
+
historyRetentionDays: number;
|
|
201
|
+
}
|
|
202
|
+
interface Task {
|
|
203
|
+
id: string;
|
|
204
|
+
type: TaskType;
|
|
205
|
+
status: TaskStatus;
|
|
206
|
+
element?: ElementInfo;
|
|
207
|
+
page: PageInfo;
|
|
208
|
+
feedback: FeedbackInfo;
|
|
209
|
+
task: TaskInfo;
|
|
210
|
+
attachments?: Attachment[];
|
|
211
|
+
assignment?: Assignment;
|
|
212
|
+
mentions?: Mention[];
|
|
213
|
+
comments?: Comment[];
|
|
214
|
+
meta: TaskMeta;
|
|
215
|
+
}
|
|
216
|
+
interface ElementInfo {
|
|
217
|
+
selector: string;
|
|
218
|
+
xpath: string;
|
|
219
|
+
tagName: string;
|
|
220
|
+
textContent?: string;
|
|
221
|
+
rect: DOMRect;
|
|
222
|
+
}
|
|
223
|
+
interface PageInfo {
|
|
224
|
+
url: string;
|
|
225
|
+
path: string;
|
|
226
|
+
title: string;
|
|
227
|
+
}
|
|
228
|
+
interface FeedbackInfo {
|
|
229
|
+
text: string;
|
|
230
|
+
originalText?: string;
|
|
231
|
+
voiceTranscript?: string;
|
|
232
|
+
}
|
|
233
|
+
interface TaskInfo {
|
|
234
|
+
title: string;
|
|
235
|
+
description: string;
|
|
236
|
+
suggestedChanges?: string;
|
|
237
|
+
}
|
|
238
|
+
interface Attachment {
|
|
239
|
+
id: string;
|
|
240
|
+
type: 'screenshot' | 'recording' | 'annotation';
|
|
241
|
+
url: string;
|
|
242
|
+
thumbnailUrl?: string;
|
|
243
|
+
mimeType: string;
|
|
244
|
+
size: number;
|
|
245
|
+
}
|
|
246
|
+
interface Assignment {
|
|
247
|
+
userId: string;
|
|
248
|
+
userName: string;
|
|
249
|
+
assignedAt: string;
|
|
250
|
+
}
|
|
251
|
+
interface Mention {
|
|
252
|
+
userId: string;
|
|
253
|
+
userName: string;
|
|
254
|
+
position: {
|
|
255
|
+
start: number;
|
|
256
|
+
end: number;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
interface TaskComment {
|
|
260
|
+
id: string;
|
|
261
|
+
userId: string;
|
|
262
|
+
userName: string;
|
|
263
|
+
text: string;
|
|
264
|
+
createdAt: string;
|
|
265
|
+
}
|
|
266
|
+
/** @deprecated Use TaskComment instead */
|
|
267
|
+
type Comment = TaskComment;
|
|
268
|
+
interface TaskMeta {
|
|
269
|
+
createdAt: string;
|
|
270
|
+
updatedAt: string;
|
|
271
|
+
createdBy: string;
|
|
272
|
+
projectId: string;
|
|
273
|
+
}
|
|
274
|
+
interface WidgetDataLayer {
|
|
275
|
+
getSession(): Promise<Session | null>;
|
|
276
|
+
loadTasks(page?: string): Promise<Task[]>;
|
|
277
|
+
saveTask(task: Task): Promise<void>;
|
|
278
|
+
updateTask(id: string, updates: Partial<Task>): Promise<void>;
|
|
279
|
+
uploadFile(file: File): Promise<{
|
|
280
|
+
url: string;
|
|
281
|
+
path: string;
|
|
282
|
+
}>;
|
|
283
|
+
checkLimits(): Promise<LimitStatus>;
|
|
284
|
+
sync?(): Promise<SyncResult>;
|
|
285
|
+
}
|
|
286
|
+
interface LimitStatus {
|
|
287
|
+
canSubmitFeedback: boolean;
|
|
288
|
+
feedbackRemaining: number;
|
|
289
|
+
canUseAI: boolean;
|
|
290
|
+
aiParsesRemaining: number;
|
|
291
|
+
}
|
|
292
|
+
interface SyncResult {
|
|
293
|
+
success: boolean;
|
|
294
|
+
syncedTasks: number;
|
|
295
|
+
errors?: string[];
|
|
296
|
+
}
|
|
297
|
+
type AnnotationMode = 'select' | 'text-edit' | 'highlight' | 'underline' | 'strikethrough' | 'circle' | 'bracket' | 'draw' | null;
|
|
298
|
+
type ViewportMode = 'desktop' | 'tablet' | 'mobile';
|
|
299
|
+
interface Position {
|
|
300
|
+
x: number;
|
|
301
|
+
y: number;
|
|
302
|
+
}
|
|
303
|
+
interface AnnotationData {
|
|
304
|
+
type: string;
|
|
305
|
+
color: string;
|
|
306
|
+
}
|
|
307
|
+
interface PendingAttachment {
|
|
308
|
+
id: string;
|
|
309
|
+
file: File;
|
|
310
|
+
type: string;
|
|
311
|
+
previewUrl: string | null;
|
|
312
|
+
}
|
|
313
|
+
interface ElementHierarchy {
|
|
314
|
+
tagName: string;
|
|
315
|
+
id?: string;
|
|
316
|
+
className?: string;
|
|
317
|
+
}
|
|
318
|
+
interface FeedbackComment {
|
|
319
|
+
id: string;
|
|
320
|
+
content: string;
|
|
321
|
+
contentHtml?: string;
|
|
322
|
+
author: string;
|
|
323
|
+
createdAt: string;
|
|
324
|
+
resolved: boolean;
|
|
325
|
+
pageUrl?: string;
|
|
326
|
+
pageTitle?: string;
|
|
327
|
+
position?: Position;
|
|
328
|
+
selector?: string;
|
|
329
|
+
elementText?: string;
|
|
330
|
+
elementType?: string;
|
|
331
|
+
elementId?: string;
|
|
332
|
+
elementClassName?: string;
|
|
333
|
+
parentHierarchy?: ElementHierarchy[];
|
|
334
|
+
attachments?: {
|
|
335
|
+
url: string;
|
|
336
|
+
type: string;
|
|
337
|
+
fileName: string;
|
|
338
|
+
}[];
|
|
339
|
+
annotation?: AnnotationData;
|
|
340
|
+
textEdit?: {
|
|
341
|
+
originalText: string;
|
|
342
|
+
newText: string;
|
|
343
|
+
};
|
|
344
|
+
viewport?: {
|
|
345
|
+
width: number;
|
|
346
|
+
height: number;
|
|
347
|
+
type: ViewportMode;
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
interface WidgetUIState {
|
|
351
|
+
feedbackPanelOpen: boolean;
|
|
352
|
+
quickInputOpen: boolean;
|
|
353
|
+
chatModalOpen: boolean;
|
|
354
|
+
annotationMode: AnnotationMode;
|
|
355
|
+
annotationColor: string;
|
|
356
|
+
selectedElement: Element | null;
|
|
357
|
+
hoveredElement: Element | null;
|
|
358
|
+
originalText: string;
|
|
359
|
+
editedText: string;
|
|
360
|
+
isDrawing: boolean;
|
|
361
|
+
drawingPaths: {
|
|
362
|
+
points: Position[];
|
|
363
|
+
color: string;
|
|
364
|
+
}[];
|
|
365
|
+
comments: FeedbackComment[];
|
|
366
|
+
showResolved: boolean;
|
|
367
|
+
isCapturing: boolean;
|
|
368
|
+
isRegionSelectMode: boolean;
|
|
369
|
+
isRecording: boolean;
|
|
370
|
+
pendingAttachments: PendingAttachment[];
|
|
371
|
+
richTextMode: boolean;
|
|
372
|
+
viewportMode: ViewportMode;
|
|
373
|
+
currentPageUrl: string;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* SDK Configuration for dual-client architecture.
|
|
377
|
+
* - User's Supabase → Data storage (projects, tasks, files)
|
|
378
|
+
* - Framed API → AI/premium features
|
|
379
|
+
*/
|
|
380
|
+
interface SDKConfig {
|
|
381
|
+
supabaseUrl: string;
|
|
382
|
+
supabaseKey: string;
|
|
383
|
+
framedApiKey?: string;
|
|
384
|
+
projectId?: string;
|
|
385
|
+
theme?: 'light' | 'dark';
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Result wrapper for AI-enhanced operations.
|
|
389
|
+
* Indicates whether AI was used or fallback occurred.
|
|
390
|
+
*/
|
|
391
|
+
interface AIFeatureResult<T> {
|
|
392
|
+
data: T;
|
|
393
|
+
wasEnhanced: boolean;
|
|
394
|
+
fallbackReason?: string;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Generic upload result for file operations.
|
|
398
|
+
*/
|
|
399
|
+
interface UploadResult {
|
|
400
|
+
url: string;
|
|
401
|
+
name: string;
|
|
402
|
+
type?: string;
|
|
403
|
+
size?: number;
|
|
404
|
+
format?: string;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Result from AI translation service.
|
|
408
|
+
*/
|
|
409
|
+
interface TranslationResult {
|
|
410
|
+
translations: Record<string, string>;
|
|
411
|
+
errors: Record<string, string>;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Callback interface for wizard components.
|
|
415
|
+
* These are implemented by the SDK using the dual-client architecture.
|
|
416
|
+
*/
|
|
417
|
+
interface WizardCallbacks {
|
|
418
|
+
onUploadFile: (file: File) => Promise<UploadResult>;
|
|
419
|
+
onUploadFont: (file: File) => Promise<UploadResult>;
|
|
420
|
+
onLogoUpload: (file: File) => Promise<void>;
|
|
421
|
+
onTranslateAll: (value: Record<string, string>, primaryLanguage: string, targetLanguages: string[]) => Promise<TranslationResult>;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Section completion status for Phase 2 navigation.
|
|
426
|
+
*/
|
|
427
|
+
type SectionStatus = 'empty' | 'in_progress' | 'completed' | 'skipped';
|
|
428
|
+
/**
|
|
429
|
+
* Global subsection types for Phase 2 navigation.
|
|
430
|
+
*/
|
|
431
|
+
type GlobalsSubType = 'navigation' | 'footer' | 'cta' | 'sitemap' | 'media' | 'review';
|
|
432
|
+
/**
|
|
433
|
+
* Phase 2 navigation state.
|
|
434
|
+
*/
|
|
435
|
+
interface Phase2NavigationState {
|
|
436
|
+
activePageIndex: number;
|
|
437
|
+
activeSectionIndex: number;
|
|
438
|
+
activeGlobalsType: GlobalsSubType | null;
|
|
439
|
+
isGlobalsExpanded: boolean;
|
|
440
|
+
totalSections: number;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Phase 2 navigation actions.
|
|
444
|
+
*/
|
|
445
|
+
interface Phase2NavigationActions {
|
|
446
|
+
setActivePageIndex: (index: number) => void;
|
|
447
|
+
setActiveSectionIndex: (index: number) => void;
|
|
448
|
+
setActiveGlobalsType: (type: GlobalsSubType | null) => void;
|
|
449
|
+
setIsGlobalsExpanded: (expanded: boolean) => void;
|
|
450
|
+
goToNextSection: () => void;
|
|
451
|
+
goToPreviousSection: () => void;
|
|
452
|
+
goToPage: (pageIndex: number, sectionIndex?: number) => void;
|
|
453
|
+
goToGlobals: (type: GlobalsSubType) => void;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Get page completion status based on sections.
|
|
457
|
+
*/
|
|
458
|
+
declare const getPageStatus: (page: PageDetail) => SectionStatus;
|
|
459
|
+
/**
|
|
460
|
+
* Get section completion status.
|
|
461
|
+
*/
|
|
462
|
+
declare const getSectionStatus: (section: Section) => SectionStatus;
|
|
463
|
+
|
|
464
|
+
declare const PLAN_LIMITS: Record<PlanTier, UsageLimits>;
|
|
465
|
+
declare const FEATURE_DEFAULTS: Record<PlanTier, WidgetFeatures>;
|
|
466
|
+
declare function canSubmitFeedback(limits: UsageLimits): boolean;
|
|
467
|
+
declare function canUseAI(limits: UsageLimits): boolean;
|
|
468
|
+
declare function getFeaturesForTier(tier: PlanTier): WidgetFeatures;
|
|
469
|
+
declare function mergeFeatures(tier: PlanTier, overrides?: Partial<WidgetFeatures>): WidgetFeatures;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Core modules in the Framed application
|
|
473
|
+
* - build: Discovery (Phase 1), Project Details (Phase 2), Overview & Export (Phase 3)
|
|
474
|
+
* - review: Feedback & Review (Phase 4)
|
|
475
|
+
* - manage: Manage & Maintain (Phase 5)
|
|
476
|
+
*/
|
|
477
|
+
type ModuleType = 'build' | 'review' | 'manage';
|
|
478
|
+
/**
|
|
479
|
+
* Mapping of modules to their constituent phases
|
|
480
|
+
*/
|
|
481
|
+
declare const MODULE_PHASES: Record<ModuleType, number[]>;
|
|
482
|
+
/**
|
|
483
|
+
* Mapping of phases to their parent module
|
|
484
|
+
*/
|
|
485
|
+
declare const PHASE_TO_MODULE: Record<number, ModuleType>;
|
|
486
|
+
/**
|
|
487
|
+
* Module display information
|
|
488
|
+
*/
|
|
489
|
+
interface ModuleInfo {
|
|
490
|
+
id: ModuleType;
|
|
491
|
+
name: string;
|
|
492
|
+
shortName: string;
|
|
493
|
+
description: string;
|
|
494
|
+
phases: number[];
|
|
495
|
+
icon: string;
|
|
496
|
+
}
|
|
497
|
+
declare const MODULES: ModuleInfo[];
|
|
498
|
+
/**
|
|
499
|
+
* Module limits per agency (null = unlimited)
|
|
500
|
+
*/
|
|
501
|
+
interface ModuleLimits {
|
|
502
|
+
build: number | null;
|
|
503
|
+
review: number | null;
|
|
504
|
+
manage: number | null;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Module usage statistics for an agency
|
|
508
|
+
*/
|
|
509
|
+
interface ModuleUsageStats {
|
|
510
|
+
module: ModuleType;
|
|
511
|
+
used: number;
|
|
512
|
+
limit: number | null;
|
|
513
|
+
remaining: number | null;
|
|
514
|
+
percentage: number | null;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Plan configuration with module limits
|
|
518
|
+
*/
|
|
519
|
+
interface PlanConfiguration {
|
|
520
|
+
id: string;
|
|
521
|
+
plan_type: PlanType;
|
|
522
|
+
display_name: string;
|
|
523
|
+
description: string;
|
|
524
|
+
build_limit: number | null;
|
|
525
|
+
review_limit: number | null;
|
|
526
|
+
manage_limit: number | null;
|
|
527
|
+
total_project_limit: number | null;
|
|
528
|
+
included_features: string[];
|
|
529
|
+
price_monthly_cents?: number;
|
|
530
|
+
price_yearly_cents?: number;
|
|
531
|
+
currency: string;
|
|
532
|
+
is_active: boolean;
|
|
533
|
+
sort_order: number;
|
|
534
|
+
}
|
|
535
|
+
type PlanType = 'oneoff' | 'silver' | 'gold';
|
|
536
|
+
type SubscriptionStatus = 'active' | 'expired' | 'cancelled' | 'trialing';
|
|
537
|
+
interface ProjectLike {
|
|
538
|
+
project_type?: 'standard' | 'review_only' | 'manage_only';
|
|
539
|
+
enabled_modules?: ModuleType[] | null;
|
|
540
|
+
visible_modules?: ModuleType[] | null;
|
|
541
|
+
disabled_phases?: number[];
|
|
542
|
+
}
|
|
543
|
+
interface AgencyLike {
|
|
544
|
+
plan_type?: PlanType;
|
|
545
|
+
module_limits?: ModuleLimits;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Get default enabled modules based on project type
|
|
549
|
+
*/
|
|
550
|
+
declare const getDefaultModules: (project: ProjectLike) => ModuleType[];
|
|
551
|
+
/**
|
|
552
|
+
* Check if a module is enabled for a project
|
|
553
|
+
* Enabled modules have the feature available (can be accessed)
|
|
554
|
+
*/
|
|
555
|
+
declare const isModuleEnabled: (project: ProjectLike | null, module: ModuleType) => boolean;
|
|
556
|
+
/**
|
|
557
|
+
* Check if a module is visible in the UI for a project
|
|
558
|
+
* Visible modules show in navigation (enabled + not hidden)
|
|
559
|
+
*/
|
|
560
|
+
declare const isModuleVisible: (project: ProjectLike | null, module: ModuleType) => boolean;
|
|
561
|
+
/**
|
|
562
|
+
* Check if a specific phase is accessible based on module configuration
|
|
563
|
+
*/
|
|
564
|
+
declare const isPhaseAccessible: (project: ProjectLike | null, phase: number) => boolean;
|
|
565
|
+
/**
|
|
566
|
+
* Check if a specific phase should be shown in navigation
|
|
567
|
+
* Combines module visibility with legacy disabled_phases support
|
|
568
|
+
*/
|
|
569
|
+
declare const isPhaseVisible: (project: ProjectLike | null, phase: number) => boolean;
|
|
570
|
+
/**
|
|
571
|
+
* Get the phases that are visible for a project (shown in navigation)
|
|
572
|
+
*/
|
|
573
|
+
declare const getVisiblePhases: (project: ProjectLike | null) => number[];
|
|
574
|
+
/**
|
|
575
|
+
* Get the phases that are accessible for a project (can be navigated to, even if hidden from nav)
|
|
576
|
+
*/
|
|
577
|
+
declare const getAccessiblePhases: (project: ProjectLike | null) => number[];
|
|
578
|
+
/**
|
|
579
|
+
* Get the first accessible phase for a project
|
|
580
|
+
* Uses accessible phases (not just visible) so hidden phases can still be accessed
|
|
581
|
+
*/
|
|
582
|
+
declare const getFirstAccessiblePhase: (project: ProjectLike | null) => number;
|
|
583
|
+
/**
|
|
584
|
+
* Get the first visible phase for a project
|
|
585
|
+
* Used for dashboard navigation - respects hidden phases (e.g., completed review phase)
|
|
586
|
+
*/
|
|
587
|
+
declare const getFirstVisiblePhase: (project: ProjectLike | null) => number;
|
|
588
|
+
/**
|
|
589
|
+
* Get module limits for an agency based on plan type or explicit limits
|
|
590
|
+
*/
|
|
591
|
+
declare const getModuleLimits: (agency: AgencyLike | null) => ModuleLimits;
|
|
592
|
+
/**
|
|
593
|
+
* Check if a module limit is unlimited
|
|
594
|
+
*/
|
|
595
|
+
declare const isModuleUnlimited: (agency: AgencyLike | null, module: ModuleType) => boolean;
|
|
596
|
+
/**
|
|
597
|
+
* Get display name for a module
|
|
598
|
+
*/
|
|
599
|
+
declare const getModuleDisplayName: (module: ModuleType) => string;
|
|
600
|
+
/**
|
|
601
|
+
* Get module description
|
|
602
|
+
*/
|
|
603
|
+
declare const getModuleDescription: (module: ModuleType) => string;
|
|
604
|
+
/**
|
|
605
|
+
* Get phases included in a module as a readable string
|
|
606
|
+
*/
|
|
607
|
+
declare const getModulePhasesLabel: (module: ModuleType) => string;
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Project categories - defines the type of digital product being specified
|
|
611
|
+
* @default 'website' for backwards compatibility
|
|
612
|
+
*/
|
|
613
|
+
type ProjectCategory = 'website' | 'saas' | 'mobile_app' | 'ecommerce' | 'api_backend' | 'custom';
|
|
614
|
+
type MobilePlatform = 'ios' | 'android' | 'cross_platform' | 'pwa';
|
|
615
|
+
type SaasCategory = 'b2b' | 'b2c' | 'internal' | 'marketplace';
|
|
616
|
+
type ApiStyle = 'rest' | 'graphql' | 'grpc' | 'websocket';
|
|
617
|
+
/**
|
|
618
|
+
* Screen types - universal term for pages/screens/endpoints across project types
|
|
619
|
+
*/
|
|
620
|
+
type ScreenType = 'page' | 'screen' | 'endpoint' | 'flow' | 'dashboard' | 'modal' | 'email';
|
|
621
|
+
/**
|
|
622
|
+
* Universal screen definition - replaces "pages" concept for multi-type support
|
|
623
|
+
*/
|
|
624
|
+
interface ScreenDefinition {
|
|
625
|
+
id: string;
|
|
626
|
+
name: string;
|
|
627
|
+
type: ScreenType;
|
|
628
|
+
order: number;
|
|
629
|
+
description?: LocalizableString;
|
|
630
|
+
features: string[];
|
|
631
|
+
ai_generated?: boolean;
|
|
632
|
+
template_source?: string;
|
|
633
|
+
website_page?: WebsitePageConfig;
|
|
634
|
+
app_screen?: AppScreenConfig;
|
|
635
|
+
api_endpoint?: ApiEndpointConfig;
|
|
636
|
+
user_flow?: UserFlowConfig;
|
|
637
|
+
}
|
|
638
|
+
interface WebsitePageConfig {
|
|
639
|
+
is_landing_page?: boolean;
|
|
640
|
+
seo_priority?: 'high' | 'medium' | 'low';
|
|
641
|
+
content_type?: 'static' | 'dynamic' | 'cms_managed';
|
|
642
|
+
}
|
|
643
|
+
interface AppScreenConfig {
|
|
644
|
+
navigation_type: 'stack' | 'tab' | 'drawer' | 'modal';
|
|
645
|
+
has_header: boolean;
|
|
646
|
+
has_bottom_nav: boolean;
|
|
647
|
+
scroll_behavior: 'scroll' | 'fixed' | 'paginated';
|
|
648
|
+
gesture_interactions: string[];
|
|
649
|
+
}
|
|
650
|
+
interface ApiEndpointConfig {
|
|
651
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
652
|
+
path: string;
|
|
653
|
+
authentication_required: boolean;
|
|
654
|
+
rate_limited: boolean;
|
|
655
|
+
request_body?: DataModelReference;
|
|
656
|
+
response_body?: DataModelReference;
|
|
657
|
+
}
|
|
658
|
+
interface UserFlowConfig {
|
|
659
|
+
steps: FlowStep[];
|
|
660
|
+
entry_points: string[];
|
|
661
|
+
exit_points: string[];
|
|
662
|
+
branching_logic?: BranchingRule[];
|
|
663
|
+
}
|
|
664
|
+
interface FlowStep {
|
|
665
|
+
id: string;
|
|
666
|
+
name: string;
|
|
667
|
+
screen_id?: string;
|
|
668
|
+
description?: string;
|
|
669
|
+
order: number;
|
|
670
|
+
}
|
|
671
|
+
interface BranchingRule {
|
|
672
|
+
condition: string;
|
|
673
|
+
target_step_id: string;
|
|
674
|
+
}
|
|
675
|
+
interface DataModelReference {
|
|
676
|
+
model_name: string;
|
|
677
|
+
fields?: string[];
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* SaaS application specific details
|
|
681
|
+
*/
|
|
682
|
+
interface SaasDetails {
|
|
683
|
+
category: SaasCategory;
|
|
684
|
+
has_user_accounts: boolean;
|
|
685
|
+
user_types: string[];
|
|
686
|
+
subscription_model: 'free' | 'freemium' | 'paid' | 'enterprise' | null;
|
|
687
|
+
key_features: string[];
|
|
688
|
+
integrations_needed: string[];
|
|
689
|
+
data_sensitivity: 'public' | 'private' | 'sensitive' | 'regulated';
|
|
690
|
+
estimated_users: 'small' | 'medium' | 'large' | 'enterprise';
|
|
691
|
+
real_time_features?: boolean;
|
|
692
|
+
collaboration_features?: boolean;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Mobile app specific details
|
|
696
|
+
*/
|
|
697
|
+
interface MobileAppDetails {
|
|
698
|
+
platforms: MobilePlatform[];
|
|
699
|
+
distribution: 'app_store' | 'enterprise' | 'sideload';
|
|
700
|
+
offline_support: boolean;
|
|
701
|
+
push_notifications: boolean;
|
|
702
|
+
native_features: string[];
|
|
703
|
+
monetization: 'free' | 'paid' | 'freemium' | 'ads' | 'subscription';
|
|
704
|
+
minimum_os_versions?: {
|
|
705
|
+
ios?: string;
|
|
706
|
+
android?: string;
|
|
707
|
+
};
|
|
708
|
+
tablet_support?: boolean;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* API/Backend specific details
|
|
712
|
+
*/
|
|
713
|
+
interface ApiBackendDetails {
|
|
714
|
+
api_style: ApiStyle;
|
|
715
|
+
authentication: 'none' | 'api_key' | 'oauth' | 'jwt' | 'custom';
|
|
716
|
+
consumers: string[];
|
|
717
|
+
estimated_requests: 'low' | 'medium' | 'high' | 'enterprise';
|
|
718
|
+
data_models: DataModelDefinition[];
|
|
719
|
+
versioning_strategy?: 'url' | 'header' | 'query_param';
|
|
720
|
+
rate_limiting?: boolean;
|
|
721
|
+
webhooks?: boolean;
|
|
722
|
+
}
|
|
723
|
+
interface DataModelDefinition {
|
|
724
|
+
name: string;
|
|
725
|
+
description?: string;
|
|
726
|
+
fields: DataFieldDefinition[];
|
|
727
|
+
relationships?: DataRelationship[];
|
|
728
|
+
}
|
|
729
|
+
interface DataFieldDefinition {
|
|
730
|
+
name: string;
|
|
731
|
+
type: 'string' | 'number' | 'boolean' | 'date' | 'array' | 'object' | 'file';
|
|
732
|
+
required: boolean;
|
|
733
|
+
description?: string;
|
|
734
|
+
}
|
|
735
|
+
interface DataRelationship {
|
|
736
|
+
target_model: string;
|
|
737
|
+
type: 'one_to_one' | 'one_to_many' | 'many_to_many';
|
|
738
|
+
field_name: string;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Enhanced e-commerce details (upgraded from existing ecommerce_details)
|
|
742
|
+
*/
|
|
743
|
+
interface EnhancedEcommerceDetails {
|
|
744
|
+
product_types: string;
|
|
745
|
+
payment_methods: string[];
|
|
746
|
+
shipping_info: string;
|
|
747
|
+
has_existing_products: boolean;
|
|
748
|
+
inventory_management: boolean;
|
|
749
|
+
multi_vendor: boolean;
|
|
750
|
+
subscription_products: boolean;
|
|
751
|
+
digital_products: boolean;
|
|
752
|
+
international_shipping: boolean;
|
|
753
|
+
tax_handling: 'simple' | 'complex' | 'automated';
|
|
754
|
+
product_variants: boolean;
|
|
755
|
+
reviews_enabled: boolean;
|
|
756
|
+
wishlist_enabled: boolean;
|
|
757
|
+
}
|
|
758
|
+
type QuestionType = 'text' | 'textarea' | 'select' | 'multiselect' | 'boolean' | 'scale' | 'conditional';
|
|
759
|
+
type QuestionCategory = 'core' | 'feature' | 'technical' | 'business' | 'ux' | 'integration';
|
|
760
|
+
/**
|
|
761
|
+
* AI-generated question for dynamic discovery
|
|
762
|
+
*/
|
|
763
|
+
interface AIQuestion {
|
|
764
|
+
id: string;
|
|
765
|
+
question: LocalizableString;
|
|
766
|
+
type: QuestionType;
|
|
767
|
+
options?: QuestionOption[];
|
|
768
|
+
validation?: ValidationRule;
|
|
769
|
+
depends_on?: DependencyRule;
|
|
770
|
+
ai_generated: boolean;
|
|
771
|
+
priority: number;
|
|
772
|
+
category: QuestionCategory;
|
|
773
|
+
help_text?: LocalizableString;
|
|
774
|
+
placeholder?: LocalizableString;
|
|
775
|
+
}
|
|
776
|
+
interface QuestionOption {
|
|
777
|
+
value: string;
|
|
778
|
+
label: LocalizableString;
|
|
779
|
+
description?: LocalizableString;
|
|
780
|
+
icon?: string;
|
|
781
|
+
}
|
|
782
|
+
interface ValidationRule {
|
|
783
|
+
required?: boolean;
|
|
784
|
+
min_length?: number;
|
|
785
|
+
max_length?: number;
|
|
786
|
+
pattern?: string;
|
|
787
|
+
custom_message?: LocalizableString;
|
|
788
|
+
}
|
|
789
|
+
interface DependencyRule {
|
|
790
|
+
question_id: string;
|
|
791
|
+
operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'exists';
|
|
792
|
+
value: unknown;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* AI conversation context for dynamic questioning
|
|
796
|
+
*/
|
|
797
|
+
interface SuggestedPage {
|
|
798
|
+
id: string;
|
|
799
|
+
name: string;
|
|
800
|
+
reason: string;
|
|
801
|
+
}
|
|
802
|
+
interface AIConversation {
|
|
803
|
+
project_idea: string;
|
|
804
|
+
inferred_category?: ProjectCategory;
|
|
805
|
+
confidence_score?: number;
|
|
806
|
+
detected_features?: string[];
|
|
807
|
+
suggested_pages?: SuggestedPage[];
|
|
808
|
+
follow_up_questions: AIQuestion[];
|
|
809
|
+
answers: Record<string, unknown>;
|
|
810
|
+
conversation_history?: AIConversationTurn[];
|
|
811
|
+
analyzed_context?: {
|
|
812
|
+
url_insights?: string;
|
|
813
|
+
document_insights?: string;
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Project context for AI analysis
|
|
818
|
+
* Allows users to provide additional context like existing websites, briefs, or documents
|
|
819
|
+
*/
|
|
820
|
+
interface ProjectContextFile {
|
|
821
|
+
name: string;
|
|
822
|
+
url: string;
|
|
823
|
+
type: 'pdf' | 'doc' | 'image' | 'text';
|
|
824
|
+
size?: number;
|
|
825
|
+
extracted_text?: string;
|
|
826
|
+
}
|
|
827
|
+
interface ProjectContext {
|
|
828
|
+
existing_url?: string;
|
|
829
|
+
context_text?: string;
|
|
830
|
+
context_files?: ProjectContextFile[];
|
|
831
|
+
}
|
|
832
|
+
interface AIConversationTurn {
|
|
833
|
+
role: 'system' | 'user' | 'assistant';
|
|
834
|
+
content: string;
|
|
835
|
+
timestamp: string;
|
|
836
|
+
}
|
|
837
|
+
interface GlobalElements {
|
|
838
|
+
navigation: {
|
|
839
|
+
logo_position: 'left' | 'center' | 'right';
|
|
840
|
+
menu_style: 'horizontal' | 'hamburger' | 'sidebar';
|
|
841
|
+
menu_items: LocalizableString;
|
|
842
|
+
cta_button?: {
|
|
843
|
+
text: LocalizableString;
|
|
844
|
+
action: string;
|
|
845
|
+
style: 'primary' | 'secondary' | 'outline';
|
|
846
|
+
};
|
|
847
|
+
};
|
|
848
|
+
footer: {
|
|
849
|
+
columns: number;
|
|
850
|
+
content: LocalizableString;
|
|
851
|
+
show_social: boolean;
|
|
852
|
+
social_links?: string;
|
|
853
|
+
copyright: LocalizableString;
|
|
854
|
+
};
|
|
855
|
+
global_cta: {
|
|
856
|
+
primary_cta: LocalizableString;
|
|
857
|
+
secondary_cta?: LocalizableString;
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
interface PageContent {
|
|
861
|
+
description: LocalizableString;
|
|
862
|
+
features: string[];
|
|
863
|
+
}
|
|
864
|
+
interface Reference {
|
|
865
|
+
url: string;
|
|
866
|
+
notes: string;
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* AI-generated project overview shown between Phase 1 and Phase 2
|
|
870
|
+
* Allows users to review and edit AI's understanding before proceeding
|
|
871
|
+
*/
|
|
872
|
+
interface ProjectOverview {
|
|
873
|
+
/** High-level project summary (2-3 sentences) */
|
|
874
|
+
project_summary: string;
|
|
875
|
+
/** Key features extracted from discovery (3-5 items) */
|
|
876
|
+
key_features: string[];
|
|
877
|
+
/** Target audience summary */
|
|
878
|
+
target_audience_summary: string;
|
|
879
|
+
/** Design direction based on style keywords */
|
|
880
|
+
design_direction: string;
|
|
881
|
+
/** Purpose of each page/screen */
|
|
882
|
+
recommended_pages: Array<{
|
|
883
|
+
name: string;
|
|
884
|
+
purpose: string;
|
|
885
|
+
}>;
|
|
886
|
+
/** When the overview was last edited by user */
|
|
887
|
+
edited_at?: string;
|
|
888
|
+
/** User's choice for content approach */
|
|
889
|
+
content_approach?: 'manual' | 'ai_generated' | 'scrape_existing';
|
|
890
|
+
/** When the overview was generated */
|
|
891
|
+
generated_at?: string;
|
|
892
|
+
/** Imported content from existing website (when content_approach is 'scrape_existing') */
|
|
893
|
+
imported_content?: ImportedContentData;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Data structure for content imported from an existing website
|
|
897
|
+
*/
|
|
898
|
+
interface ImportedContentData {
|
|
899
|
+
/** Source URL that was crawled */
|
|
900
|
+
source_url: string;
|
|
901
|
+
/** When the content was imported */
|
|
902
|
+
imported_at: string;
|
|
903
|
+
/** Crawled pages with their content */
|
|
904
|
+
pages: ImportedPageData[];
|
|
905
|
+
/** Downloaded images */
|
|
906
|
+
images: ImportedImageData[];
|
|
907
|
+
}
|
|
908
|
+
interface ImportedPageData {
|
|
909
|
+
/** Page name/title */
|
|
910
|
+
name: string;
|
|
911
|
+
/** Original URL */
|
|
912
|
+
url: string;
|
|
913
|
+
/** Content sections */
|
|
914
|
+
sections: ImportedSectionData[];
|
|
915
|
+
}
|
|
916
|
+
interface ImportedSectionData {
|
|
917
|
+
id: string;
|
|
918
|
+
name: string;
|
|
919
|
+
order: number;
|
|
920
|
+
blocks: ImportedBlockData[];
|
|
921
|
+
}
|
|
922
|
+
interface ImportedBlockData {
|
|
923
|
+
id: string;
|
|
924
|
+
type: 'heading' | 'text' | 'list' | 'button';
|
|
925
|
+
tagName: string;
|
|
926
|
+
content: string;
|
|
927
|
+
order: number;
|
|
928
|
+
level?: number;
|
|
929
|
+
items?: string[];
|
|
930
|
+
href?: string;
|
|
931
|
+
}
|
|
932
|
+
interface ImportedImageData {
|
|
933
|
+
/** Original URL from source site */
|
|
934
|
+
originalUrl: string;
|
|
935
|
+
/** Stored URL in our bucket */
|
|
936
|
+
storedUrl: string;
|
|
937
|
+
/** Alt text */
|
|
938
|
+
alt?: string;
|
|
939
|
+
/** Source page URL */
|
|
940
|
+
pageUrl: string;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Phase 1 Data - Discovery phase
|
|
944
|
+
*/
|
|
945
|
+
interface Phase1Data {
|
|
946
|
+
/**
|
|
947
|
+
* Project category - determines the type of digital product
|
|
948
|
+
* @default 'website' for backwards compatibility
|
|
949
|
+
*/
|
|
950
|
+
project_category?: ProjectCategory;
|
|
951
|
+
/**
|
|
952
|
+
* AI conversation context for dynamic questioning
|
|
953
|
+
*/
|
|
954
|
+
ai_conversation?: AIConversation;
|
|
955
|
+
/**
|
|
956
|
+
* Universal screens array - replaces pages for multi-type support
|
|
957
|
+
* For websites, these map to pages; for apps, to screens; for APIs, to endpoints
|
|
958
|
+
*/
|
|
959
|
+
screens?: ScreenDefinition[];
|
|
960
|
+
/**
|
|
961
|
+
* Category-specific details
|
|
962
|
+
*/
|
|
963
|
+
saas_details?: SaasDetails;
|
|
964
|
+
mobile_details?: MobileAppDetails;
|
|
965
|
+
api_details?: ApiBackendDetails;
|
|
966
|
+
enhanced_ecommerce_details?: EnhancedEcommerceDetails;
|
|
967
|
+
/**
|
|
968
|
+
* Project context for AI analysis
|
|
969
|
+
* Allows users to provide existing website URLs, briefs, or documents
|
|
970
|
+
*/
|
|
971
|
+
project_context?: ProjectContext;
|
|
972
|
+
business_name: string;
|
|
973
|
+
industry: string;
|
|
974
|
+
goal: LocalizableString;
|
|
975
|
+
audience: LocalizableString;
|
|
976
|
+
primary_device: 'mobile' | 'desktop' | 'both';
|
|
977
|
+
/** @deprecated Use project_category === 'ecommerce' and enhanced_ecommerce_details instead */
|
|
978
|
+
is_ecommerce: boolean;
|
|
979
|
+
/** @deprecated Use enhanced_ecommerce_details instead */
|
|
980
|
+
ecommerce_details?: {
|
|
981
|
+
product_types: string;
|
|
982
|
+
payment_methods: string[];
|
|
983
|
+
shipping_info: string;
|
|
984
|
+
has_existing_products: boolean;
|
|
985
|
+
};
|
|
986
|
+
/** @deprecated Use screens array instead */
|
|
987
|
+
pages: string[];
|
|
988
|
+
/** @deprecated Use screens array instead */
|
|
989
|
+
custom_pages: string[];
|
|
990
|
+
page_names: Record<string, string>;
|
|
991
|
+
page_content: Record<string, PageContent>;
|
|
992
|
+
legal_content_preference: 'has_content' | 'needs_creation' | 'not_sure';
|
|
993
|
+
has_logo: boolean;
|
|
994
|
+
logo_url: string | null;
|
|
995
|
+
colors: {
|
|
996
|
+
primary: string | null;
|
|
997
|
+
secondary: string | null;
|
|
998
|
+
accent: string | null;
|
|
999
|
+
no_idea: boolean;
|
|
1000
|
+
};
|
|
1001
|
+
font: {
|
|
1002
|
+
primary: string | null;
|
|
1003
|
+
secondary: string | null;
|
|
1004
|
+
custom_fonts: string[];
|
|
1005
|
+
custom_font_files: {
|
|
1006
|
+
name: string;
|
|
1007
|
+
url: string;
|
|
1008
|
+
format: 'woff' | 'woff2' | 'ttf' | 'otf';
|
|
1009
|
+
}[];
|
|
1010
|
+
no_idea: boolean;
|
|
1011
|
+
};
|
|
1012
|
+
style_keywords: string[];
|
|
1013
|
+
references: Reference[];
|
|
1014
|
+
globals?: GlobalElements;
|
|
1015
|
+
functionality?: {
|
|
1016
|
+
cms: {
|
|
1017
|
+
type: 'none' | 'custom' | 'existing' | 'headless';
|
|
1018
|
+
existing_cms?: string;
|
|
1019
|
+
cms_features?: string[];
|
|
1020
|
+
};
|
|
1021
|
+
languages: {
|
|
1022
|
+
is_multilingual: boolean;
|
|
1023
|
+
primary_language: string;
|
|
1024
|
+
additional_languages: string[];
|
|
1025
|
+
translation_method?: 'manual' | 'automated' | 'hybrid';
|
|
1026
|
+
};
|
|
1027
|
+
integrations: {
|
|
1028
|
+
analytics: string[];
|
|
1029
|
+
marketing: string[];
|
|
1030
|
+
social: string[];
|
|
1031
|
+
payment: string[];
|
|
1032
|
+
other: string[];
|
|
1033
|
+
};
|
|
1034
|
+
authentication: {
|
|
1035
|
+
needs_auth: boolean;
|
|
1036
|
+
auth_type?: 'social' | 'email' | 'sso' | 'custom';
|
|
1037
|
+
user_roles?: string[];
|
|
1038
|
+
features?: string[];
|
|
1039
|
+
};
|
|
1040
|
+
technical: {
|
|
1041
|
+
hosting_preference?: 'managed' | 'self-hosted' | 'no_preference';
|
|
1042
|
+
performance_priority: 'speed' | 'features' | 'balanced';
|
|
1043
|
+
accessibility_level: 'basic' | 'wcag_aa' | 'wcag_aaa';
|
|
1044
|
+
seo_requirements?: string[];
|
|
1045
|
+
};
|
|
1046
|
+
additional: string[];
|
|
1047
|
+
};
|
|
1048
|
+
homepage_layout?: string;
|
|
1049
|
+
/**
|
|
1050
|
+
* Cached AI-enhanced prompt data to avoid re-generating
|
|
1051
|
+
*/
|
|
1052
|
+
enhanced_prompts?: {
|
|
1053
|
+
enhanced_prompt?: string;
|
|
1054
|
+
planning_section?: string;
|
|
1055
|
+
project_instructions_md?: string;
|
|
1056
|
+
generated_at?: string;
|
|
1057
|
+
};
|
|
1058
|
+
/**
|
|
1059
|
+
* AI-generated project overview for Phase 1 → Phase 2 transition
|
|
1060
|
+
* Stores the overview summary and user's content approach choice
|
|
1061
|
+
*/
|
|
1062
|
+
overview?: ProjectOverview;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
interface Phase3Data {
|
|
1066
|
+
generated_prompt: string;
|
|
1067
|
+
json_export: Record<string, unknown>;
|
|
1068
|
+
submitted_at?: string;
|
|
1069
|
+
submitted_by?: string;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Supported AI tools for export generation
|
|
1073
|
+
*/
|
|
1074
|
+
type AIToolType = 'bolt' | 'lovable' | 'v0' | 'cursor' | 'claude' | '10web' | 'windsurf' | 'notion';
|
|
1075
|
+
/**
|
|
1076
|
+
* Export format options
|
|
1077
|
+
*/
|
|
1078
|
+
type ExportFormat = 'long_prompt' | 'short_prompt' | 'markdown_file';
|
|
1079
|
+
/**
|
|
1080
|
+
* AI tool configuration with metadata
|
|
1081
|
+
*/
|
|
1082
|
+
interface AIToolConfig {
|
|
1083
|
+
id: AIToolType;
|
|
1084
|
+
name: string;
|
|
1085
|
+
description: string;
|
|
1086
|
+
icon?: string;
|
|
1087
|
+
supportedFormats: ExportFormat[];
|
|
1088
|
+
promptStyle?: 'detailed' | 'concise' | 'conversational';
|
|
1089
|
+
maxTokens?: number;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Status of a build spec todo item
|
|
1093
|
+
*/
|
|
1094
|
+
type BuildSpecItemStatus = 'pending' | 'in_progress' | 'completed' | 'skipped';
|
|
1095
|
+
/**
|
|
1096
|
+
* A single todo item in the build spec
|
|
1097
|
+
*/
|
|
1098
|
+
interface BuildSpecItem {
|
|
1099
|
+
id: string;
|
|
1100
|
+
title: string;
|
|
1101
|
+
description?: string;
|
|
1102
|
+
status: BuildSpecItemStatus;
|
|
1103
|
+
order: number;
|
|
1104
|
+
pageName?: string;
|
|
1105
|
+
sectionId?: string;
|
|
1106
|
+
content?: {
|
|
1107
|
+
text?: string;
|
|
1108
|
+
images?: {
|
|
1109
|
+
url: string;
|
|
1110
|
+
alt?: string;
|
|
1111
|
+
caption?: string;
|
|
1112
|
+
}[];
|
|
1113
|
+
};
|
|
1114
|
+
createdAt: string;
|
|
1115
|
+
createdBy?: string;
|
|
1116
|
+
updatedAt?: string;
|
|
1117
|
+
updatedBy?: string;
|
|
1118
|
+
completedAt?: string;
|
|
1119
|
+
completedBy?: string;
|
|
1120
|
+
notes?: string;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* A section grouping related build spec items
|
|
1124
|
+
*/
|
|
1125
|
+
interface BuildSpecSection {
|
|
1126
|
+
id: string;
|
|
1127
|
+
title: string;
|
|
1128
|
+
description?: string;
|
|
1129
|
+
order: number;
|
|
1130
|
+
type: 'overview' | 'page' | 'global' | 'technical';
|
|
1131
|
+
pageName?: string;
|
|
1132
|
+
items: BuildSpecItem[];
|
|
1133
|
+
collapsed?: boolean;
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Generated export for an AI tool
|
|
1137
|
+
*/
|
|
1138
|
+
interface BuildSpecExport {
|
|
1139
|
+
id: string;
|
|
1140
|
+
toolType: AIToolType;
|
|
1141
|
+
format: ExportFormat;
|
|
1142
|
+
content: string;
|
|
1143
|
+
generatedAt: string;
|
|
1144
|
+
generatedBy: string;
|
|
1145
|
+
fileName?: string;
|
|
1146
|
+
fileSize?: number;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Build spec phase data stored in project.data.buildSpec
|
|
1150
|
+
*/
|
|
1151
|
+
interface BuildSpecData {
|
|
1152
|
+
sections: BuildSpecSection[];
|
|
1153
|
+
autoGeneratedAt?: string;
|
|
1154
|
+
autoGeneratedFrom?: 'phase1' | 'phase2' | 'both';
|
|
1155
|
+
lastManualEditAt?: string;
|
|
1156
|
+
lastManualEditBy?: string;
|
|
1157
|
+
exports?: BuildSpecExport[];
|
|
1158
|
+
lastExportAt?: string;
|
|
1159
|
+
preferredTool?: AIToolType;
|
|
1160
|
+
editorContent?: string;
|
|
1161
|
+
totalItems?: number;
|
|
1162
|
+
completedItems?: number;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
interface FeedbackRound {
|
|
1166
|
+
id: string;
|
|
1167
|
+
round_number: number;
|
|
1168
|
+
started_at: string;
|
|
1169
|
+
started_by: string;
|
|
1170
|
+
started_by_name: string;
|
|
1171
|
+
ended_at?: string;
|
|
1172
|
+
ended_by?: string;
|
|
1173
|
+
ended_by_name?: string;
|
|
1174
|
+
status: 'active' | 'feedback_complete' | 'closed';
|
|
1175
|
+
feedback_completed_at?: string;
|
|
1176
|
+
feedback_completed_by?: string;
|
|
1177
|
+
feedback_completed_by_name?: string;
|
|
1178
|
+
summary?: FeedbackRoundSummary;
|
|
1179
|
+
screenshot_version?: number;
|
|
1180
|
+
}
|
|
1181
|
+
interface FeedbackRoundSummary {
|
|
1182
|
+
total_items: number;
|
|
1183
|
+
resolved_in_round: number;
|
|
1184
|
+
carried_over: number;
|
|
1185
|
+
unable_to_resolve: number;
|
|
1186
|
+
new_items_added: number;
|
|
1187
|
+
}
|
|
1188
|
+
interface ResolutionImportResult {
|
|
1189
|
+
imported_at: string;
|
|
1190
|
+
imported_by: string;
|
|
1191
|
+
imported_by_name: string;
|
|
1192
|
+
round_number: number;
|
|
1193
|
+
matched_items: number;
|
|
1194
|
+
resolved_count: number;
|
|
1195
|
+
unable_count: number;
|
|
1196
|
+
unmatched_ids: string[];
|
|
1197
|
+
unmatched_notes: string;
|
|
1198
|
+
}
|
|
1199
|
+
type ResolutionStatus = 'resolved' | 'unable_to_resolve' | 'needs_clarification';
|
|
1200
|
+
interface ParsedResolutionItem {
|
|
1201
|
+
feedback_id: string;
|
|
1202
|
+
status: ResolutionStatus;
|
|
1203
|
+
description: string;
|
|
1204
|
+
question?: string;
|
|
1205
|
+
}
|
|
1206
|
+
type ImageStatus = 'pending' | 'approved' | 'changes_requested';
|
|
1207
|
+
interface PageImage {
|
|
1208
|
+
id: string;
|
|
1209
|
+
page_name: string;
|
|
1210
|
+
image_url: string;
|
|
1211
|
+
alt_text?: string;
|
|
1212
|
+
detected_from: 'crawl' | 'manual' | 'upload';
|
|
1213
|
+
dimensions?: {
|
|
1214
|
+
width: number;
|
|
1215
|
+
height: number;
|
|
1216
|
+
};
|
|
1217
|
+
file_size?: number;
|
|
1218
|
+
status: ImageStatus;
|
|
1219
|
+
approved_by?: string;
|
|
1220
|
+
approved_by_name?: string;
|
|
1221
|
+
approved_at?: string;
|
|
1222
|
+
suggested_replacement?: {
|
|
1223
|
+
url: string;
|
|
1224
|
+
uploaded_by: string;
|
|
1225
|
+
uploaded_by_name: string;
|
|
1226
|
+
uploaded_at: string;
|
|
1227
|
+
reason?: string;
|
|
1228
|
+
};
|
|
1229
|
+
comments?: ImageComment[];
|
|
1230
|
+
created_at: string;
|
|
1231
|
+
updated_at: string;
|
|
1232
|
+
}
|
|
1233
|
+
interface ImageComment {
|
|
1234
|
+
id: string;
|
|
1235
|
+
user_id: string;
|
|
1236
|
+
user_name: string;
|
|
1237
|
+
user_role: UserRole;
|
|
1238
|
+
comment: string;
|
|
1239
|
+
created_at: string;
|
|
1240
|
+
edited_at?: string;
|
|
1241
|
+
}
|
|
1242
|
+
type SectionSuggestionStatus = 'pending' | 'approved' | 'rejected';
|
|
1243
|
+
interface SectionSuggestion {
|
|
1244
|
+
id: string;
|
|
1245
|
+
page_name: string;
|
|
1246
|
+
type: string;
|
|
1247
|
+
title: LocalizableString;
|
|
1248
|
+
content: LocalizableString;
|
|
1249
|
+
media_type: 'image' | 'video' | 'illustration' | 'icon' | 'none';
|
|
1250
|
+
media_description?: LocalizableString;
|
|
1251
|
+
notes?: string;
|
|
1252
|
+
suggested_by: string;
|
|
1253
|
+
suggested_by_name: string;
|
|
1254
|
+
suggested_by_role: UserRole;
|
|
1255
|
+
suggested_at: string;
|
|
1256
|
+
status: SectionSuggestionStatus;
|
|
1257
|
+
reviewed_by?: string;
|
|
1258
|
+
reviewed_by_name?: string;
|
|
1259
|
+
reviewed_at?: string;
|
|
1260
|
+
review_notes?: string;
|
|
1261
|
+
}
|
|
1262
|
+
interface ContentBlock {
|
|
1263
|
+
id: string;
|
|
1264
|
+
type: 'heading' | 'text' | 'list';
|
|
1265
|
+
tagName: string;
|
|
1266
|
+
originalContent: string;
|
|
1267
|
+
currentContent: string;
|
|
1268
|
+
order: number;
|
|
1269
|
+
level?: number;
|
|
1270
|
+
items?: string[];
|
|
1271
|
+
currentItems?: string[];
|
|
1272
|
+
}
|
|
1273
|
+
interface ContentSection {
|
|
1274
|
+
id: string;
|
|
1275
|
+
name: string;
|
|
1276
|
+
order: number;
|
|
1277
|
+
blocks: ContentBlock[];
|
|
1278
|
+
collapsed?: boolean;
|
|
1279
|
+
}
|
|
1280
|
+
interface TextEdit {
|
|
1281
|
+
id: string;
|
|
1282
|
+
blockId: string;
|
|
1283
|
+
sectionId: string;
|
|
1284
|
+
previousContent: string;
|
|
1285
|
+
newContent: string;
|
|
1286
|
+
editedAt: string;
|
|
1287
|
+
editedBy: string;
|
|
1288
|
+
editedByName: string;
|
|
1289
|
+
editedByRole: UserRole;
|
|
1290
|
+
editType: 'modify' | 'restore';
|
|
1291
|
+
comment?: string;
|
|
1292
|
+
resolved?: boolean;
|
|
1293
|
+
resolvedAt?: string;
|
|
1294
|
+
resolvedBy?: string;
|
|
1295
|
+
resolvedByName?: string;
|
|
1296
|
+
}
|
|
1297
|
+
interface LanguageContent {
|
|
1298
|
+
language: string;
|
|
1299
|
+
pageTitle?: string;
|
|
1300
|
+
sections: ContentSection[];
|
|
1301
|
+
crawledAt: string;
|
|
1302
|
+
crawledBy: string;
|
|
1303
|
+
editHistory: TextEdit[];
|
|
1304
|
+
}
|
|
1305
|
+
interface PageTextContent {
|
|
1306
|
+
pageUrl: string;
|
|
1307
|
+
languages: Record<string, LanguageContent>;
|
|
1308
|
+
primaryLanguage: string;
|
|
1309
|
+
version: number;
|
|
1310
|
+
}
|
|
1311
|
+
interface CrawledTextElement {
|
|
1312
|
+
id: string;
|
|
1313
|
+
selector: string;
|
|
1314
|
+
tagName: string;
|
|
1315
|
+
elementType: CrawledElementType;
|
|
1316
|
+
originalText: string;
|
|
1317
|
+
currentText: string;
|
|
1318
|
+
order: number;
|
|
1319
|
+
parentSelector?: string;
|
|
1320
|
+
}
|
|
1321
|
+
type CrawledElementType = 'heading' | 'paragraph' | 'link' | 'button' | 'label' | 'list-item' | 'other';
|
|
1322
|
+
interface PageVersion {
|
|
1323
|
+
version_number: number;
|
|
1324
|
+
created_at: string;
|
|
1325
|
+
created_by: string;
|
|
1326
|
+
screenshot_desktop: ScreenshotInfo | null;
|
|
1327
|
+
screenshot_mobile: ScreenshotInfo | null;
|
|
1328
|
+
notes?: string;
|
|
1329
|
+
approved?: boolean;
|
|
1330
|
+
approved_by?: string;
|
|
1331
|
+
approved_by_name?: string;
|
|
1332
|
+
approved_at?: string;
|
|
1333
|
+
round_number?: number;
|
|
1334
|
+
}
|
|
1335
|
+
interface ScreenshotInfo {
|
|
1336
|
+
url: string;
|
|
1337
|
+
uploaded_at: string;
|
|
1338
|
+
uploaded_by: string;
|
|
1339
|
+
file_name: string;
|
|
1340
|
+
file_size: number;
|
|
1341
|
+
}
|
|
1342
|
+
interface AttachmentTranscription {
|
|
1343
|
+
text: string;
|
|
1344
|
+
language?: string;
|
|
1345
|
+
duration?: number;
|
|
1346
|
+
segments?: Array<{
|
|
1347
|
+
start: number;
|
|
1348
|
+
end: number;
|
|
1349
|
+
text: string;
|
|
1350
|
+
}>;
|
|
1351
|
+
}
|
|
1352
|
+
interface CommentAttachment {
|
|
1353
|
+
id: string;
|
|
1354
|
+
file_name: string;
|
|
1355
|
+
file_url: string;
|
|
1356
|
+
file_type: string;
|
|
1357
|
+
file_size: number;
|
|
1358
|
+
uploaded_at: string;
|
|
1359
|
+
transcription?: AttachmentTranscription;
|
|
1360
|
+
}
|
|
1361
|
+
interface PageComment {
|
|
1362
|
+
id: string;
|
|
1363
|
+
user_id: string;
|
|
1364
|
+
user_name: string;
|
|
1365
|
+
user_role: UserRole;
|
|
1366
|
+
version_number: number;
|
|
1367
|
+
screenshot_type: 'desktop' | 'mobile';
|
|
1368
|
+
comment: string;
|
|
1369
|
+
position: {
|
|
1370
|
+
x: number;
|
|
1371
|
+
y: number;
|
|
1372
|
+
};
|
|
1373
|
+
created_at: string;
|
|
1374
|
+
updated_at?: string;
|
|
1375
|
+
edited_at?: string;
|
|
1376
|
+
resolved?: boolean;
|
|
1377
|
+
parent_id?: string;
|
|
1378
|
+
replies?: PageComment[];
|
|
1379
|
+
mentions?: string[];
|
|
1380
|
+
attachments?: CommentAttachment[];
|
|
1381
|
+
metadata?: {
|
|
1382
|
+
reviewType?: 'screenshot' | 'live';
|
|
1383
|
+
viewMode?: 'desktop' | 'mobile';
|
|
1384
|
+
elementMetadata?: unknown;
|
|
1385
|
+
pageUrl?: string;
|
|
1386
|
+
pagePath?: string;
|
|
1387
|
+
cssSelector?: string;
|
|
1388
|
+
source?: 'widget' | 'screenshot' | 'app' | 'content_editor';
|
|
1389
|
+
changeType?: 'modified' | 'added' | 'deleted';
|
|
1390
|
+
originalContent?: string;
|
|
1391
|
+
newContent?: string;
|
|
1392
|
+
paragraphIndex?: number;
|
|
1393
|
+
hasScreenshot?: boolean;
|
|
1394
|
+
screenshotUrl?: string;
|
|
1395
|
+
screenshotType?: 'region' | 'full';
|
|
1396
|
+
annotationsCount?: number;
|
|
1397
|
+
};
|
|
1398
|
+
selector?: string;
|
|
1399
|
+
element_html?: string;
|
|
1400
|
+
element_text?: string;
|
|
1401
|
+
element_type?: string;
|
|
1402
|
+
element_styles?: Record<string, string>;
|
|
1403
|
+
viewport_size?: {
|
|
1404
|
+
width: number;
|
|
1405
|
+
height: number;
|
|
1406
|
+
};
|
|
1407
|
+
created_in_round?: number;
|
|
1408
|
+
resolved_in_round?: number;
|
|
1409
|
+
resolution_status?: ResolutionStatus;
|
|
1410
|
+
resolution_description?: string;
|
|
1411
|
+
needs_clarification?: boolean;
|
|
1412
|
+
clarification_suggestion?: string;
|
|
1413
|
+
}
|
|
1414
|
+
interface Phase4Page {
|
|
1415
|
+
page_name: string;
|
|
1416
|
+
page_url?: string;
|
|
1417
|
+
versions: PageVersion[];
|
|
1418
|
+
comments: PageComment[];
|
|
1419
|
+
textContent?: PageTextContent;
|
|
1420
|
+
is_virtual_view?: boolean;
|
|
1421
|
+
parent_url?: string;
|
|
1422
|
+
}
|
|
1423
|
+
interface Phase4Data {
|
|
1424
|
+
demo_url?: string;
|
|
1425
|
+
pages: Phase4Page[];
|
|
1426
|
+
suggestions?: SectionSuggestion[];
|
|
1427
|
+
rounds?: FeedbackRound[];
|
|
1428
|
+
current_round?: number;
|
|
1429
|
+
import_history?: ResolutionImportResult[];
|
|
1430
|
+
project_approved?: boolean;
|
|
1431
|
+
project_approved_at?: string;
|
|
1432
|
+
project_approved_by?: string;
|
|
1433
|
+
project_approved_by_name?: string;
|
|
1434
|
+
completed_at?: string;
|
|
1435
|
+
completed_by?: string;
|
|
1436
|
+
completed_by_name?: string;
|
|
1437
|
+
onboarding_completed?: boolean;
|
|
1438
|
+
page_images?: PageImage[];
|
|
1439
|
+
}
|
|
1440
|
+
interface BaseFeedItem {
|
|
1441
|
+
id: string;
|
|
1442
|
+
pageName: string;
|
|
1443
|
+
pageUrl?: string;
|
|
1444
|
+
timestamp: string;
|
|
1445
|
+
userId: string;
|
|
1446
|
+
userName: string;
|
|
1447
|
+
userRole: UserRole;
|
|
1448
|
+
}
|
|
1449
|
+
interface FeedbackFeedItem extends BaseFeedItem {
|
|
1450
|
+
type: 'feedback';
|
|
1451
|
+
comment: PageComment;
|
|
1452
|
+
screenshotUrl?: string;
|
|
1453
|
+
versionNumber: number;
|
|
1454
|
+
screenshotType: 'desktop' | 'mobile';
|
|
1455
|
+
position: {
|
|
1456
|
+
x: number;
|
|
1457
|
+
y: number;
|
|
1458
|
+
};
|
|
1459
|
+
createdInRound?: number;
|
|
1460
|
+
resolvedInRound?: number;
|
|
1461
|
+
resolutionStatus?: ResolutionStatus;
|
|
1462
|
+
resolutionDescription?: string;
|
|
1463
|
+
}
|
|
1464
|
+
interface TextEditFeedItem extends BaseFeedItem {
|
|
1465
|
+
type: 'text_edit';
|
|
1466
|
+
edit: TextEdit;
|
|
1467
|
+
language: string;
|
|
1468
|
+
sectionName: string;
|
|
1469
|
+
blockType: 'heading' | 'text' | 'list';
|
|
1470
|
+
tagName: string;
|
|
1471
|
+
originalContent: string;
|
|
1472
|
+
newContent: string;
|
|
1473
|
+
}
|
|
1474
|
+
interface ImageFeedItem extends BaseFeedItem {
|
|
1475
|
+
type: 'image_feedback';
|
|
1476
|
+
imageId: string;
|
|
1477
|
+
imageUrl: string;
|
|
1478
|
+
imageAltText?: string;
|
|
1479
|
+
imageStatus: ImageStatus;
|
|
1480
|
+
comment: ImageComment;
|
|
1481
|
+
usedOnPages: string[];
|
|
1482
|
+
replacementUrl?: string;
|
|
1483
|
+
}
|
|
1484
|
+
type FeedItem = FeedbackFeedItem | TextEditFeedItem | ImageFeedItem;
|
|
1485
|
+
declare const isFeedbackItem: (item: FeedItem) => item is FeedbackFeedItem;
|
|
1486
|
+
declare const isTextEditItem: (item: FeedItem) => item is TextEditFeedItem;
|
|
1487
|
+
declare const isImageFeedItem: (item: FeedItem) => item is ImageFeedItem;
|
|
1488
|
+
interface WidgetSession {
|
|
1489
|
+
id: string;
|
|
1490
|
+
project_id: string;
|
|
1491
|
+
token: string;
|
|
1492
|
+
created_by: string;
|
|
1493
|
+
created_at: string;
|
|
1494
|
+
expires_at: string;
|
|
1495
|
+
last_activity: string;
|
|
1496
|
+
guest_name?: string;
|
|
1497
|
+
page_url?: string;
|
|
1498
|
+
user_agent?: string;
|
|
1499
|
+
is_active: boolean;
|
|
1500
|
+
}
|
|
1501
|
+
interface WidgetSessionCreate {
|
|
1502
|
+
project_id: string;
|
|
1503
|
+
page_url?: string;
|
|
1504
|
+
guest_name?: string;
|
|
1505
|
+
}
|
|
1506
|
+
interface WidgetSessionValidation {
|
|
1507
|
+
valid: boolean;
|
|
1508
|
+
error?: string;
|
|
1509
|
+
session?: {
|
|
1510
|
+
id: string;
|
|
1511
|
+
project_id: string;
|
|
1512
|
+
expires_at: string;
|
|
1513
|
+
guest_name?: string;
|
|
1514
|
+
};
|
|
1515
|
+
project?: {
|
|
1516
|
+
id: string;
|
|
1517
|
+
name: string;
|
|
1518
|
+
status: ProjectStatus;
|
|
1519
|
+
pages: {
|
|
1520
|
+
page_name: string;
|
|
1521
|
+
page_url: string;
|
|
1522
|
+
comment_count: number;
|
|
1523
|
+
has_approved_version: boolean;
|
|
1524
|
+
}[];
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* Categories for maintenance items
|
|
1530
|
+
*/
|
|
1531
|
+
type MaintenanceCategory = 'bug_fix' | 'performance' | 'security' | 'content_update' | 'design_tweak' | 'new_feature' | 'new_section' | 'new_page' | 'campaign' | 'seo' | 'accessibility' | 'technical_debt' | 'other';
|
|
1532
|
+
/**
|
|
1533
|
+
* Priority levels for maintenance items
|
|
1534
|
+
*/
|
|
1535
|
+
type MaintenancePriority = 'critical' | 'high' | 'medium' | 'low';
|
|
1536
|
+
/**
|
|
1537
|
+
* Status workflow for maintenance items
|
|
1538
|
+
* backlog → scheduled → in_progress → review → completed
|
|
1539
|
+
* ↓
|
|
1540
|
+
* wont_fix
|
|
1541
|
+
*/
|
|
1542
|
+
type MaintenanceItemStatus = 'backlog' | 'scheduled' | 'in_progress' | 'review' | 'completed' | 'wont_fix';
|
|
1543
|
+
/**
|
|
1544
|
+
* Configuration for recurring maintenance tasks
|
|
1545
|
+
*/
|
|
1546
|
+
interface RecurringConfig {
|
|
1547
|
+
enabled: boolean;
|
|
1548
|
+
frequency: 'weekly' | 'monthly' | 'quarterly';
|
|
1549
|
+
next_due: string;
|
|
1550
|
+
last_completed?: string;
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Comment on a maintenance item
|
|
1554
|
+
*/
|
|
1555
|
+
interface MaintenanceComment {
|
|
1556
|
+
id: string;
|
|
1557
|
+
user_id: string;
|
|
1558
|
+
user_name: string;
|
|
1559
|
+
user_role?: UserRole;
|
|
1560
|
+
comment: string;
|
|
1561
|
+
created_at: string;
|
|
1562
|
+
edited_at?: string;
|
|
1563
|
+
attachments?: CommentAttachment[];
|
|
1564
|
+
parent_id?: string;
|
|
1565
|
+
replies?: MaintenanceComment[];
|
|
1566
|
+
is_internal?: boolean;
|
|
1567
|
+
mentions?: string[];
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Status transition history for maintenance items
|
|
1571
|
+
*/
|
|
1572
|
+
interface StatusTransition {
|
|
1573
|
+
from_status: MaintenanceItemStatus;
|
|
1574
|
+
to_status: MaintenanceItemStatus;
|
|
1575
|
+
changed_at: string;
|
|
1576
|
+
changed_by: string;
|
|
1577
|
+
changed_by_name: string;
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* A single maintenance item (bug, feature request, improvement, etc.)
|
|
1581
|
+
*/
|
|
1582
|
+
interface MaintenanceItem {
|
|
1583
|
+
id: string;
|
|
1584
|
+
title: string;
|
|
1585
|
+
description: string;
|
|
1586
|
+
category: MaintenanceCategory;
|
|
1587
|
+
priority: MaintenancePriority;
|
|
1588
|
+
status: MaintenanceItemStatus;
|
|
1589
|
+
page_name?: string;
|
|
1590
|
+
page_url?: string;
|
|
1591
|
+
element_selector?: string;
|
|
1592
|
+
screenshot_url?: string;
|
|
1593
|
+
position?: {
|
|
1594
|
+
x: number;
|
|
1595
|
+
y: number;
|
|
1596
|
+
};
|
|
1597
|
+
scheduled_for?: string;
|
|
1598
|
+
due_date?: string;
|
|
1599
|
+
estimated_hours?: number;
|
|
1600
|
+
recurring?: RecurringConfig;
|
|
1601
|
+
source?: 'widget' | 'manual' | string;
|
|
1602
|
+
created_at: string;
|
|
1603
|
+
created_by: string;
|
|
1604
|
+
created_by_name: string;
|
|
1605
|
+
created_by_role?: UserRole;
|
|
1606
|
+
updated_at?: string;
|
|
1607
|
+
resolved_at?: string;
|
|
1608
|
+
resolved_by?: string;
|
|
1609
|
+
resolved_by_name?: string;
|
|
1610
|
+
resolution_notes?: string;
|
|
1611
|
+
comments?: MaintenanceComment[];
|
|
1612
|
+
attachments?: CommentAttachment[];
|
|
1613
|
+
related_items?: string[];
|
|
1614
|
+
blocks?: string[];
|
|
1615
|
+
blocked_by?: string[];
|
|
1616
|
+
status_history?: StatusTransition[];
|
|
1617
|
+
total_time_minutes?: number;
|
|
1618
|
+
metadata?: {
|
|
1619
|
+
type?: 'text-edit' | 'general-feedback' | 'element-feedback';
|
|
1620
|
+
originalContent?: string;
|
|
1621
|
+
newContent?: string;
|
|
1622
|
+
source?: 'widget' | 'manual' | 'phase4';
|
|
1623
|
+
aiValidation?: {
|
|
1624
|
+
clarityScore?: number;
|
|
1625
|
+
conversationThread?: Array<{
|
|
1626
|
+
role: 'user' | 'ai';
|
|
1627
|
+
content: string;
|
|
1628
|
+
timestamp: string;
|
|
1629
|
+
type?: string;
|
|
1630
|
+
}>;
|
|
1631
|
+
summary?: {
|
|
1632
|
+
clarificationQuestions?: string[];
|
|
1633
|
+
finalClarityScore?: number;
|
|
1634
|
+
wasInitiallyClear?: boolean;
|
|
1635
|
+
};
|
|
1636
|
+
};
|
|
1637
|
+
[key: string]: unknown;
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Summary stats for a maintenance cycle
|
|
1642
|
+
*/
|
|
1643
|
+
interface MaintenanceCycleSummary {
|
|
1644
|
+
total_items: number;
|
|
1645
|
+
completed: number;
|
|
1646
|
+
carried_over: number;
|
|
1647
|
+
new_items_added: number;
|
|
1648
|
+
hours_spent?: number;
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* A maintenance cycle (similar to FeedbackRound in Phase 4)
|
|
1652
|
+
*/
|
|
1653
|
+
interface MaintenanceCycle {
|
|
1654
|
+
id: string;
|
|
1655
|
+
cycle_number: number;
|
|
1656
|
+
name: string;
|
|
1657
|
+
type: 'sprint' | 'monthly' | 'quarterly' | 'ad_hoc';
|
|
1658
|
+
started_at: string;
|
|
1659
|
+
started_by: string;
|
|
1660
|
+
started_by_name: string;
|
|
1661
|
+
ended_at?: string;
|
|
1662
|
+
ended_by?: string;
|
|
1663
|
+
ended_by_name?: string;
|
|
1664
|
+
status: 'active' | 'completed' | 'cancelled';
|
|
1665
|
+
summary?: MaintenanceCycleSummary;
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Quick stats cache for Phase 5 dashboard
|
|
1669
|
+
*/
|
|
1670
|
+
interface MaintenanceStats {
|
|
1671
|
+
total_items: number;
|
|
1672
|
+
open_items: number;
|
|
1673
|
+
completed_items: number;
|
|
1674
|
+
critical_count: number;
|
|
1675
|
+
high_count: number;
|
|
1676
|
+
by_category: Record<MaintenanceCategory, number>;
|
|
1677
|
+
last_updated: string;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Credential type for categorization
|
|
1681
|
+
*/
|
|
1682
|
+
type CredentialType = 'hosting' | 'cms' | 'ftp' | 'database' | 'email' | 'api' | 'other';
|
|
1683
|
+
/**
|
|
1684
|
+
* Stored credential for accessing client sites
|
|
1685
|
+
* Used in Phase 5 for maintenance access
|
|
1686
|
+
*/
|
|
1687
|
+
interface StoredCredential {
|
|
1688
|
+
id: string;
|
|
1689
|
+
name: string;
|
|
1690
|
+
type?: CredentialType;
|
|
1691
|
+
url?: string;
|
|
1692
|
+
username?: string;
|
|
1693
|
+
password?: string;
|
|
1694
|
+
notes?: string;
|
|
1695
|
+
created_at: string;
|
|
1696
|
+
created_by: string;
|
|
1697
|
+
created_by_name: string;
|
|
1698
|
+
updated_at?: string;
|
|
1699
|
+
updated_by?: string;
|
|
1700
|
+
updated_by_name?: string;
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Quote status workflow
|
|
1704
|
+
* draft → pending_review → quoted → approved/rejected → in_progress → completed
|
|
1705
|
+
*/
|
|
1706
|
+
type QuoteStatus = 'draft' | 'pending_review' | 'quoted' | 'approved' | 'rejected' | 'in_progress' | 'completed';
|
|
1707
|
+
/**
|
|
1708
|
+
* A quote/estimate for a maintenance item
|
|
1709
|
+
*/
|
|
1710
|
+
interface MaintenanceQuote {
|
|
1711
|
+
id: string;
|
|
1712
|
+
status: QuoteStatus;
|
|
1713
|
+
estimated_hours?: number;
|
|
1714
|
+
hourly_rate?: number;
|
|
1715
|
+
fixed_price?: number;
|
|
1716
|
+
currency: 'EUR' | 'USD' | 'GBP';
|
|
1717
|
+
line_items?: {
|
|
1718
|
+
description: string;
|
|
1719
|
+
hours?: number;
|
|
1720
|
+
amount: number;
|
|
1721
|
+
}[];
|
|
1722
|
+
quote_notes?: string;
|
|
1723
|
+
valid_until?: string;
|
|
1724
|
+
client_response_notes?: string;
|
|
1725
|
+
responded_at?: string;
|
|
1726
|
+
responded_by?: string;
|
|
1727
|
+
responded_by_name?: string;
|
|
1728
|
+
quoted_at?: string;
|
|
1729
|
+
quoted_by?: string;
|
|
1730
|
+
quoted_by_name?: string;
|
|
1731
|
+
revision_number: number;
|
|
1732
|
+
previous_quotes?: MaintenanceQuote[];
|
|
1733
|
+
}
|
|
1734
|
+
/**
|
|
1735
|
+
* Activity log entry for maintenance items
|
|
1736
|
+
*/
|
|
1737
|
+
interface MaintenanceActivity {
|
|
1738
|
+
id: string;
|
|
1739
|
+
item_id: string;
|
|
1740
|
+
type: 'created' | 'status_changed' | 'priority_changed' | 'assigned' | 'comment_added' | 'quote_requested' | 'quote_submitted' | 'quote_approved' | 'quote_rejected' | 'attachment_added' | 'completed';
|
|
1741
|
+
user_id: string;
|
|
1742
|
+
user_name: string;
|
|
1743
|
+
user_role?: UserRole;
|
|
1744
|
+
timestamp: string;
|
|
1745
|
+
details?: {
|
|
1746
|
+
from?: string;
|
|
1747
|
+
to?: string;
|
|
1748
|
+
comment?: string;
|
|
1749
|
+
amount?: number;
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Extended maintenance item with quote support
|
|
1754
|
+
*/
|
|
1755
|
+
interface MaintenanceItemExtended extends MaintenanceItem {
|
|
1756
|
+
quote?: MaintenanceQuote;
|
|
1757
|
+
requires_quote?: boolean;
|
|
1758
|
+
assigned_to?: string;
|
|
1759
|
+
assigned_to_name?: string;
|
|
1760
|
+
activity?: MaintenanceActivity[];
|
|
1761
|
+
is_urgent?: boolean;
|
|
1762
|
+
is_pinned?: boolean;
|
|
1763
|
+
client_visible?: boolean;
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Phase 5: Manage & Maintain data structure
|
|
1767
|
+
* For ongoing post-launch maintenance and feedback
|
|
1768
|
+
*/
|
|
1769
|
+
interface Phase5Data {
|
|
1770
|
+
live_url?: string;
|
|
1771
|
+
staging_url?: string;
|
|
1772
|
+
items: MaintenanceItem[];
|
|
1773
|
+
cycles?: MaintenanceCycle[];
|
|
1774
|
+
current_cycle?: number;
|
|
1775
|
+
stats?: MaintenanceStats;
|
|
1776
|
+
sla?: {
|
|
1777
|
+
critical_response_hours: number;
|
|
1778
|
+
high_response_hours: number;
|
|
1779
|
+
medium_response_hours: number;
|
|
1780
|
+
low_response_hours: number;
|
|
1781
|
+
};
|
|
1782
|
+
credentials?: StoredCredential[];
|
|
1783
|
+
pricing?: {
|
|
1784
|
+
default_hourly_rate: number;
|
|
1785
|
+
currency: 'EUR' | 'USD' | 'GBP';
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Time entry for logging work done on maintenance items
|
|
1790
|
+
*/
|
|
1791
|
+
interface TimeEntry {
|
|
1792
|
+
id: string;
|
|
1793
|
+
project_id: string;
|
|
1794
|
+
maintenance_item_id?: string;
|
|
1795
|
+
user_id: string;
|
|
1796
|
+
agency_id?: string;
|
|
1797
|
+
logged_date: string;
|
|
1798
|
+
duration_minutes: number;
|
|
1799
|
+
description?: string;
|
|
1800
|
+
billable: boolean;
|
|
1801
|
+
user_name?: string;
|
|
1802
|
+
created_at: string;
|
|
1803
|
+
updated_at: string;
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Hour package status
|
|
1807
|
+
*/
|
|
1808
|
+
type HourPackageStatus = 'active' | 'expired' | 'depleted';
|
|
1809
|
+
/**
|
|
1810
|
+
* Hour package (strippenkaart) for a project
|
|
1811
|
+
*/
|
|
1812
|
+
interface HourPackage {
|
|
1813
|
+
id: string;
|
|
1814
|
+
project_id: string;
|
|
1815
|
+
agency_id?: string;
|
|
1816
|
+
name: string;
|
|
1817
|
+
total_minutes: number;
|
|
1818
|
+
used_minutes: number;
|
|
1819
|
+
remaining_minutes: number;
|
|
1820
|
+
purchased_at: string;
|
|
1821
|
+
expires_at?: string;
|
|
1822
|
+
status: HourPackageStatus;
|
|
1823
|
+
price_cents?: number;
|
|
1824
|
+
currency: 'EUR' | 'USD' | 'GBP';
|
|
1825
|
+
stripe_payment_id?: string;
|
|
1826
|
+
notes?: string;
|
|
1827
|
+
created_at: string;
|
|
1828
|
+
updated_at: string;
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Internal note for agency team only
|
|
1832
|
+
*/
|
|
1833
|
+
interface InternalNote {
|
|
1834
|
+
id: string;
|
|
1835
|
+
notable_type: 'project' | 'maintenance_item' | 'meeting';
|
|
1836
|
+
notable_id: string;
|
|
1837
|
+
project_id: string;
|
|
1838
|
+
user_id: string;
|
|
1839
|
+
user_name: string;
|
|
1840
|
+
body: string;
|
|
1841
|
+
is_pinned: boolean;
|
|
1842
|
+
title?: string;
|
|
1843
|
+
meeting_date?: string;
|
|
1844
|
+
content_html?: string;
|
|
1845
|
+
created_at: string;
|
|
1846
|
+
updated_at: string;
|
|
1847
|
+
}
|
|
1848
|
+
/**
|
|
1849
|
+
* Domain monitor check status
|
|
1850
|
+
*/
|
|
1851
|
+
type DomainCheckStatus = 'pending' | 'ok' | 'warning' | 'error';
|
|
1852
|
+
/**
|
|
1853
|
+
* Domain/SSL monitor for a project
|
|
1854
|
+
*/
|
|
1855
|
+
interface DomainMonitor {
|
|
1856
|
+
id: string;
|
|
1857
|
+
project_id: string;
|
|
1858
|
+
agency_id?: string;
|
|
1859
|
+
domain: string;
|
|
1860
|
+
ssl_expiry?: string;
|
|
1861
|
+
domain_expiry?: string;
|
|
1862
|
+
last_checked?: string;
|
|
1863
|
+
check_status: DomainCheckStatus;
|
|
1864
|
+
check_error?: string;
|
|
1865
|
+
alerts_enabled: boolean;
|
|
1866
|
+
alert_days: number[];
|
|
1867
|
+
created_at: string;
|
|
1868
|
+
updated_at: string;
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Uptime monitor for a project
|
|
1872
|
+
*/
|
|
1873
|
+
interface UptimeMonitor {
|
|
1874
|
+
id: string;
|
|
1875
|
+
project_id: string;
|
|
1876
|
+
agency_id?: string;
|
|
1877
|
+
url: string;
|
|
1878
|
+
name?: string;
|
|
1879
|
+
method: 'GET' | 'HEAD';
|
|
1880
|
+
expected_status_code: number;
|
|
1881
|
+
timeout_ms: number;
|
|
1882
|
+
check_interval_minutes: number;
|
|
1883
|
+
is_active: boolean;
|
|
1884
|
+
is_up: boolean;
|
|
1885
|
+
last_status_code?: number;
|
|
1886
|
+
last_response_time_ms?: number;
|
|
1887
|
+
last_checked_at?: string;
|
|
1888
|
+
last_error?: string;
|
|
1889
|
+
consecutive_failures: number;
|
|
1890
|
+
uptime_percentage?: number;
|
|
1891
|
+
avg_response_time_ms?: number;
|
|
1892
|
+
total_checks_30d: number;
|
|
1893
|
+
failed_checks_30d: number;
|
|
1894
|
+
last_down_at?: string;
|
|
1895
|
+
last_up_at?: string;
|
|
1896
|
+
down_since?: string;
|
|
1897
|
+
alerts_enabled: boolean;
|
|
1898
|
+
alert_threshold: number;
|
|
1899
|
+
created_at: string;
|
|
1900
|
+
updated_at: string;
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Individual uptime check result
|
|
1904
|
+
*/
|
|
1905
|
+
interface UptimeCheck {
|
|
1906
|
+
id: string;
|
|
1907
|
+
monitor_id: string;
|
|
1908
|
+
checked_at: string;
|
|
1909
|
+
is_up: boolean;
|
|
1910
|
+
status_code?: number;
|
|
1911
|
+
response_time_ms?: number;
|
|
1912
|
+
error?: string;
|
|
1913
|
+
}
|
|
1914
|
+
/**
|
|
1915
|
+
* Uptime incident (downtime period)
|
|
1916
|
+
*/
|
|
1917
|
+
interface UptimeIncident {
|
|
1918
|
+
id: string;
|
|
1919
|
+
monitor_id: string;
|
|
1920
|
+
project_id: string;
|
|
1921
|
+
started_at: string;
|
|
1922
|
+
ended_at?: string;
|
|
1923
|
+
duration_minutes?: number;
|
|
1924
|
+
error_type?: 'timeout' | 'connection_refused' | 'dns_error' | 'ssl_error' | 'http_error' | 'unknown';
|
|
1925
|
+
last_error?: string;
|
|
1926
|
+
checks_failed: number;
|
|
1927
|
+
is_resolved: boolean;
|
|
1928
|
+
created_at: string;
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Changelog entry category
|
|
1932
|
+
*/
|
|
1933
|
+
type ChangelogCategory = 'bugfix' | 'improvement' | 'feature' | 'content' | 'security';
|
|
1934
|
+
/**
|
|
1935
|
+
* Changelog entry for a project
|
|
1936
|
+
*/
|
|
1937
|
+
interface ChangelogEntry {
|
|
1938
|
+
id: string;
|
|
1939
|
+
project_id: string;
|
|
1940
|
+
maintenance_item_id?: string;
|
|
1941
|
+
title: string;
|
|
1942
|
+
description?: string;
|
|
1943
|
+
category: ChangelogCategory;
|
|
1944
|
+
is_public: boolean;
|
|
1945
|
+
published_at?: string;
|
|
1946
|
+
created_by: string;
|
|
1947
|
+
created_by_name: string;
|
|
1948
|
+
created_at: string;
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Monthly report data structure
|
|
1952
|
+
*/
|
|
1953
|
+
interface MonthlyReportData {
|
|
1954
|
+
period: {
|
|
1955
|
+
start: string;
|
|
1956
|
+
end: string;
|
|
1957
|
+
};
|
|
1958
|
+
summary: {
|
|
1959
|
+
tickets_completed: number;
|
|
1960
|
+
tickets_created: number;
|
|
1961
|
+
hours_logged: number;
|
|
1962
|
+
hours_remaining: number;
|
|
1963
|
+
};
|
|
1964
|
+
tickets_by_category: Record<MaintenanceCategory, number>;
|
|
1965
|
+
time_breakdown: Array<{
|
|
1966
|
+
description: string;
|
|
1967
|
+
minutes: number;
|
|
1968
|
+
user_name?: string;
|
|
1969
|
+
}>;
|
|
1970
|
+
open_items: Array<{
|
|
1971
|
+
title: string;
|
|
1972
|
+
priority: MaintenancePriority;
|
|
1973
|
+
status: MaintenanceItemStatus;
|
|
1974
|
+
category: MaintenanceCategory;
|
|
1975
|
+
}>;
|
|
1976
|
+
changelog: Array<{
|
|
1977
|
+
title: string;
|
|
1978
|
+
category: ChangelogCategory;
|
|
1979
|
+
date: string;
|
|
1980
|
+
}>;
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Monthly report for a project
|
|
1984
|
+
*/
|
|
1985
|
+
interface MonthlyReport {
|
|
1986
|
+
id: string;
|
|
1987
|
+
project_id: string;
|
|
1988
|
+
agency_id?: string;
|
|
1989
|
+
report_month: string;
|
|
1990
|
+
data: MonthlyReportData;
|
|
1991
|
+
pdf_url?: string;
|
|
1992
|
+
sent_to_client: boolean;
|
|
1993
|
+
sent_at?: string;
|
|
1994
|
+
created_at: string;
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* Improvement suggestion category
|
|
1998
|
+
*/
|
|
1999
|
+
type SuggestionCategory = 'performance' | 'ux' | 'seo' | 'design' | 'functionality' | 'security' | 'accessibility';
|
|
2000
|
+
/**
|
|
2001
|
+
* Improvement suggestion impact level
|
|
2002
|
+
*/
|
|
2003
|
+
type SuggestionImpact = 'low' | 'medium' | 'high';
|
|
2004
|
+
/**
|
|
2005
|
+
* Improvement suggestion status
|
|
2006
|
+
*/
|
|
2007
|
+
type SuggestionStatus = 'draft' | 'proposed' | 'accepted' | 'rejected' | 'converted';
|
|
2008
|
+
/**
|
|
2009
|
+
* Improvement suggestion for proactive agency recommendations
|
|
2010
|
+
*/
|
|
2011
|
+
interface ImprovementSuggestion {
|
|
2012
|
+
id: string;
|
|
2013
|
+
project_id: string;
|
|
2014
|
+
title: string;
|
|
2015
|
+
description: string;
|
|
2016
|
+
category: SuggestionCategory;
|
|
2017
|
+
impact: SuggestionImpact;
|
|
2018
|
+
effort_hours?: number;
|
|
2019
|
+
estimated_cost_cents?: number;
|
|
2020
|
+
currency: 'EUR' | 'USD' | 'GBP';
|
|
2021
|
+
status: SuggestionStatus;
|
|
2022
|
+
proposed_at?: string;
|
|
2023
|
+
client_response_at?: string;
|
|
2024
|
+
client_response_notes?: string;
|
|
2025
|
+
converted_item_id?: string;
|
|
2026
|
+
created_by: string;
|
|
2027
|
+
created_by_name: string;
|
|
2028
|
+
created_at: string;
|
|
2029
|
+
updated_at: string;
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Extended Phase 5 notification types
|
|
2033
|
+
*/
|
|
2034
|
+
type Phase5NotificationType = 'maintenance_item_created' | 'maintenance_item_completed' | 'maintenance_priority_alert' | 'maintenance_cycle_started' | 'maintenance_cycle_closed' | 'hour_package_low' | 'time_entry_added' | 'suggestion_proposed' | 'suggestion_accepted' | 'suggestion_rejected' | 'domain_expiry_warning' | 'monthly_report_ready';
|
|
2035
|
+
|
|
2036
|
+
type UserRole = 'super_admin' | 'admin' | 'manager' | 'client';
|
|
2037
|
+
interface User {
|
|
2038
|
+
id: string;
|
|
2039
|
+
email: string;
|
|
2040
|
+
name: string;
|
|
2041
|
+
role: UserRole;
|
|
2042
|
+
agency_id?: string | null;
|
|
2043
|
+
preferred_language?: 'nl' | 'en' | 'es';
|
|
2044
|
+
avatar_url?: string | null;
|
|
2045
|
+
preferences?: UserPreferences | null;
|
|
2046
|
+
created_at?: string;
|
|
2047
|
+
}
|
|
2048
|
+
interface UserPreferences {
|
|
2049
|
+
language: string;
|
|
2050
|
+
email_notifications: {
|
|
2051
|
+
project_updates: boolean;
|
|
2052
|
+
project_status_changes: boolean;
|
|
2053
|
+
comments: boolean;
|
|
2054
|
+
mentions: boolean;
|
|
2055
|
+
weekly_summary: boolean;
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
interface Agency {
|
|
2059
|
+
id: string;
|
|
2060
|
+
name: string;
|
|
2061
|
+
slug: string;
|
|
2062
|
+
project_limit?: number | null;
|
|
2063
|
+
logo_url?: string | null;
|
|
2064
|
+
created_at?: string;
|
|
2065
|
+
created_by?: string | null;
|
|
2066
|
+
is_active?: boolean;
|
|
2067
|
+
plan_type?: PlanType;
|
|
2068
|
+
subscription_status?: SubscriptionStatus;
|
|
2069
|
+
subscription_start_date?: string;
|
|
2070
|
+
subscription_end_date?: string | null;
|
|
2071
|
+
features?: {
|
|
2072
|
+
performance_analysis?: boolean;
|
|
2073
|
+
seo_audit?: boolean;
|
|
2074
|
+
uptime_monitoring?: boolean;
|
|
2075
|
+
[key: string]: boolean | undefined;
|
|
2076
|
+
};
|
|
2077
|
+
seo_credits_limit?: number;
|
|
2078
|
+
seo_credits_used?: number;
|
|
2079
|
+
module_limits?: ModuleLimits;
|
|
2080
|
+
stripe_customer_id?: string | null;
|
|
2081
|
+
stripe_subscription_id?: string | null;
|
|
2082
|
+
stripe_subscription_status?: 'active' | 'past_due' | 'canceled' | 'incomplete' | 'trialing' | null;
|
|
2083
|
+
stripe_current_period_end?: string | null;
|
|
2084
|
+
billing_email?: string | null;
|
|
2085
|
+
}
|
|
2086
|
+
type ProjectStatus = 'draft' | 'submitted' | 'in_development' | 'feedback' | 'in_management' | 'completed' | 'archived';
|
|
2087
|
+
type ProjectType = 'standard' | 'review_only' | 'manage_only';
|
|
2088
|
+
/**
|
|
2089
|
+
* Project-level monitoring feature flags
|
|
2090
|
+
* These can only be enabled if the agency has the feature available
|
|
2091
|
+
*/
|
|
2092
|
+
interface ProjectMonitoringFeatures {
|
|
2093
|
+
seo_enabled?: boolean;
|
|
2094
|
+
performance_enabled?: boolean;
|
|
2095
|
+
uptime_enabled?: boolean;
|
|
2096
|
+
analytics_enabled?: boolean;
|
|
2097
|
+
}
|
|
2098
|
+
interface Project {
|
|
2099
|
+
id: string;
|
|
2100
|
+
agency_id?: string;
|
|
2101
|
+
created_by?: string;
|
|
2102
|
+
user_id?: string;
|
|
2103
|
+
name: string;
|
|
2104
|
+
status?: ProjectStatus;
|
|
2105
|
+
project_type?: ProjectType;
|
|
2106
|
+
source_url?: string | null;
|
|
2107
|
+
current_step?: number;
|
|
2108
|
+
locked_phases?: number[];
|
|
2109
|
+
unlocked_phases?: number[];
|
|
2110
|
+
disabled_phases?: number[];
|
|
2111
|
+
enabled_modules?: ModuleType[];
|
|
2112
|
+
visible_modules?: ModuleType[];
|
|
2113
|
+
data?: ProjectData;
|
|
2114
|
+
created_at?: string;
|
|
2115
|
+
updated_at?: string;
|
|
2116
|
+
enabled_features?: string[];
|
|
2117
|
+
monitoring_features?: ProjectMonitoringFeatures;
|
|
2118
|
+
analytics_enabled?: boolean;
|
|
2119
|
+
agency?: Agency;
|
|
2120
|
+
budget_hours_per_month?: number | null;
|
|
2121
|
+
budget_hourly_rate_cents?: number | null;
|
|
2122
|
+
agency_notes?: string | null;
|
|
2123
|
+
}
|
|
2124
|
+
interface ProjectMember {
|
|
2125
|
+
id: string;
|
|
2126
|
+
project_id: string;
|
|
2127
|
+
user_id: string;
|
|
2128
|
+
role: 'manager' | 'client';
|
|
2129
|
+
created_at?: string;
|
|
2130
|
+
user?: User;
|
|
2131
|
+
}
|
|
2132
|
+
interface ProjectData {
|
|
2133
|
+
phase1?: Phase1Data;
|
|
2134
|
+
phase2?: Phase2Data;
|
|
2135
|
+
phase3?: BuildSpecData;
|
|
2136
|
+
phase4?: Phase4Data;
|
|
2137
|
+
phase5?: Phase5Data;
|
|
2138
|
+
buildSpec?: BuildSpecData;
|
|
2139
|
+
}
|
|
2140
|
+
interface ProjectShare {
|
|
2141
|
+
id: string;
|
|
2142
|
+
project_id: string;
|
|
2143
|
+
share_token: string;
|
|
2144
|
+
created_by: string;
|
|
2145
|
+
expires_at?: string | null;
|
|
2146
|
+
access_level: 'view_only';
|
|
2147
|
+
created_at?: string;
|
|
2148
|
+
updated_at?: string;
|
|
2149
|
+
}
|
|
2150
|
+
interface GeneralComment {
|
|
2151
|
+
id: string;
|
|
2152
|
+
project_id: string;
|
|
2153
|
+
phase?: number | null;
|
|
2154
|
+
page_name?: string | null;
|
|
2155
|
+
section_id?: string | null;
|
|
2156
|
+
author_id?: string | null;
|
|
2157
|
+
guest_name?: string | null;
|
|
2158
|
+
content: string;
|
|
2159
|
+
mentions?: string[];
|
|
2160
|
+
parent_id?: string | null;
|
|
2161
|
+
is_resolved?: boolean;
|
|
2162
|
+
created_at?: string;
|
|
2163
|
+
updated_at?: string;
|
|
2164
|
+
author?: User;
|
|
2165
|
+
replies?: GeneralComment[];
|
|
2166
|
+
}
|
|
2167
|
+
interface PerformanceMetrics {
|
|
2168
|
+
performance: number;
|
|
2169
|
+
accessibility: number;
|
|
2170
|
+
bestPractices: number;
|
|
2171
|
+
seo: number;
|
|
2172
|
+
firstContentfulPaint: number;
|
|
2173
|
+
largestContentfulPaint: number;
|
|
2174
|
+
totalBlockingTime: number;
|
|
2175
|
+
cumulativeLayoutShift: number;
|
|
2176
|
+
speedIndex: number;
|
|
2177
|
+
}
|
|
2178
|
+
interface PerformanceAudit {
|
|
2179
|
+
id: string;
|
|
2180
|
+
title: string;
|
|
2181
|
+
description: string;
|
|
2182
|
+
score: number | null;
|
|
2183
|
+
scoreDisplayMode?: 'binary' | 'numeric' | 'informative' | 'notApplicable';
|
|
2184
|
+
displayValue?: string;
|
|
2185
|
+
numericValue?: number;
|
|
2186
|
+
numericUnit?: string;
|
|
2187
|
+
details?: unknown;
|
|
2188
|
+
}
|
|
2189
|
+
interface PerformanceOpportunity extends PerformanceAudit {
|
|
2190
|
+
overallSavingsMs?: number;
|
|
2191
|
+
overallSavingsBytes?: number;
|
|
2192
|
+
}
|
|
2193
|
+
interface PerformanceReport {
|
|
2194
|
+
id: string;
|
|
2195
|
+
projectId: string;
|
|
2196
|
+
pageName: string;
|
|
2197
|
+
pageUrl: string;
|
|
2198
|
+
strategy: 'mobile' | 'desktop';
|
|
2199
|
+
metrics: PerformanceMetrics;
|
|
2200
|
+
audits: PerformanceAudit[];
|
|
2201
|
+
opportunities: PerformanceOpportunity[];
|
|
2202
|
+
diagnostics: PerformanceAudit[];
|
|
2203
|
+
fetchTime: string;
|
|
2204
|
+
lighthouseVersion: string;
|
|
2205
|
+
rawData?: unknown;
|
|
2206
|
+
createdAt?: string;
|
|
2207
|
+
}
|
|
2208
|
+
interface ProjectPerformanceUsage {
|
|
2209
|
+
projectId: string;
|
|
2210
|
+
checksUsed: number;
|
|
2211
|
+
checksLimit: number;
|
|
2212
|
+
lastCheckAt?: string;
|
|
2213
|
+
reports: PerformanceReport[];
|
|
2214
|
+
}
|
|
2215
|
+
interface ProjectFeature {
|
|
2216
|
+
id: string;
|
|
2217
|
+
projectId: string;
|
|
2218
|
+
featureName: string;
|
|
2219
|
+
enabled: boolean;
|
|
2220
|
+
enabledBy?: string;
|
|
2221
|
+
enabledAt?: string;
|
|
2222
|
+
createdAt?: string;
|
|
2223
|
+
}
|
|
2224
|
+
interface SeoAuditIssue {
|
|
2225
|
+
type: 'error' | 'warning' | 'info';
|
|
2226
|
+
category: string;
|
|
2227
|
+
title: string;
|
|
2228
|
+
description: string;
|
|
2229
|
+
url?: string;
|
|
2230
|
+
selector?: string;
|
|
2231
|
+
impact?: 'critical' | 'serious' | 'moderate' | 'minor';
|
|
2232
|
+
}
|
|
2233
|
+
interface SeoAuditResult {
|
|
2234
|
+
url: string;
|
|
2235
|
+
title?: string;
|
|
2236
|
+
metaDescription?: string;
|
|
2237
|
+
h1?: string[];
|
|
2238
|
+
canonicalUrl?: string;
|
|
2239
|
+
robotsDirectives?: string[];
|
|
2240
|
+
issues: SeoAuditIssue[];
|
|
2241
|
+
scores?: {
|
|
2242
|
+
overall?: number;
|
|
2243
|
+
content?: number;
|
|
2244
|
+
technical?: number;
|
|
2245
|
+
mobile?: number;
|
|
2246
|
+
};
|
|
2247
|
+
pageData?: Record<string, unknown>;
|
|
2248
|
+
}
|
|
2249
|
+
interface SeoReport {
|
|
2250
|
+
id: string;
|
|
2251
|
+
projectId: string;
|
|
2252
|
+
pageName: string;
|
|
2253
|
+
pageUrl: string;
|
|
2254
|
+
apifyRunId: string;
|
|
2255
|
+
apifyDatasetId: string;
|
|
2256
|
+
results: SeoAuditResult[];
|
|
2257
|
+
createdAt: string;
|
|
2258
|
+
createdBy: string;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
interface ElementMetadata {
|
|
2262
|
+
tagName: string;
|
|
2263
|
+
id: string | null;
|
|
2264
|
+
classes: string[];
|
|
2265
|
+
text: string;
|
|
2266
|
+
bbox: {
|
|
2267
|
+
x: number;
|
|
2268
|
+
y: number;
|
|
2269
|
+
width: number;
|
|
2270
|
+
height: number;
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
interface AnnotationBody {
|
|
2274
|
+
type: 'TextualBody';
|
|
2275
|
+
text: string;
|
|
2276
|
+
format: 'text/plain';
|
|
2277
|
+
language: string;
|
|
2278
|
+
}
|
|
2279
|
+
interface AnnotationTarget {
|
|
2280
|
+
type: 'SpecificResource';
|
|
2281
|
+
source: string;
|
|
2282
|
+
selector: {
|
|
2283
|
+
type: 'CssSelector';
|
|
2284
|
+
value: string;
|
|
2285
|
+
}[];
|
|
2286
|
+
}
|
|
2287
|
+
interface Annotation {
|
|
2288
|
+
type: 'Annotation';
|
|
2289
|
+
id?: string;
|
|
2290
|
+
wizardPhase: 4;
|
|
2291
|
+
projectId: string;
|
|
2292
|
+
pageUrl: string;
|
|
2293
|
+
body: AnnotationBody;
|
|
2294
|
+
target: AnnotationTarget;
|
|
2295
|
+
elementMetadata: ElementMetadata;
|
|
2296
|
+
created_at: string;
|
|
2297
|
+
created_by: string;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
/**
|
|
2301
|
+
* Framed API Client
|
|
2302
|
+
*
|
|
2303
|
+
* Handles communication with Framed's AI services (premium features).
|
|
2304
|
+
* Uses the customer's API key for authentication.
|
|
2305
|
+
*/
|
|
2306
|
+
interface FramedApiError {
|
|
2307
|
+
message: string;
|
|
2308
|
+
code?: string;
|
|
2309
|
+
status?: number;
|
|
2310
|
+
}
|
|
2311
|
+
declare class FramedApiClient {
|
|
2312
|
+
private apiKey;
|
|
2313
|
+
constructor(apiKey?: string);
|
|
2314
|
+
/**
|
|
2315
|
+
* Check if the client is configured with an API key.
|
|
2316
|
+
*/
|
|
2317
|
+
get isEnabled(): boolean;
|
|
2318
|
+
/**
|
|
2319
|
+
* Make a POST request to a Framed API endpoint.
|
|
2320
|
+
*
|
|
2321
|
+
* @param endpoint - The endpoint path (e.g., 'sdk-ai-translate')
|
|
2322
|
+
* @param data - The request payload
|
|
2323
|
+
* @returns The response data
|
|
2324
|
+
* @throws Error if API key is not configured or request fails
|
|
2325
|
+
*/
|
|
2326
|
+
post<T>(endpoint: string, data: unknown): Promise<T>;
|
|
2327
|
+
/**
|
|
2328
|
+
* Make a GET request to a Framed API endpoint.
|
|
2329
|
+
*
|
|
2330
|
+
* @param endpoint - The endpoint path
|
|
2331
|
+
* @param params - Optional query parameters
|
|
2332
|
+
* @returns The response data
|
|
2333
|
+
*/
|
|
2334
|
+
get<T>(endpoint: string, params?: Record<string, string>): Promise<T>;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
/**
|
|
2338
|
+
* User Supabase Client Factory
|
|
2339
|
+
*
|
|
2340
|
+
* Creates and manages a Supabase client for the customer's own database.
|
|
2341
|
+
* This is where project data, tasks, and file uploads are stored.
|
|
2342
|
+
*/
|
|
2343
|
+
|
|
2344
|
+
/**
|
|
2345
|
+
* Initialize the user's Supabase client.
|
|
2346
|
+
*
|
|
2347
|
+
* @param url - The customer's Supabase URL (e.g., https://xxx.supabase.co)
|
|
2348
|
+
* @param key - The customer's Supabase anon key
|
|
2349
|
+
* @returns The initialized Supabase client
|
|
2350
|
+
*/
|
|
2351
|
+
declare function initUserSupabase(url: string, key: string): SupabaseClient;
|
|
2352
|
+
/**
|
|
2353
|
+
* Get the current user Supabase client.
|
|
2354
|
+
*
|
|
2355
|
+
* @returns The Supabase client
|
|
2356
|
+
* @throws Error if client has not been initialized
|
|
2357
|
+
*/
|
|
2358
|
+
declare function getUserSupabase(): SupabaseClient;
|
|
2359
|
+
/**
|
|
2360
|
+
* Check if the Supabase client has been initialized.
|
|
2361
|
+
*/
|
|
2362
|
+
declare function isSupabaseInitialized(): boolean;
|
|
2363
|
+
/**
|
|
2364
|
+
* Reset the Supabase client (useful for testing or logout).
|
|
2365
|
+
*/
|
|
2366
|
+
declare function resetUserSupabase(): void;
|
|
2367
|
+
|
|
2368
|
+
/**
|
|
2369
|
+
* Callback Implementations
|
|
2370
|
+
*
|
|
2371
|
+
* These functions implement the callback interfaces used by wizard components.
|
|
2372
|
+
* They use the dual-client architecture:
|
|
2373
|
+
* - File uploads → User's Supabase storage
|
|
2374
|
+
* - AI features → Framed API
|
|
2375
|
+
*/
|
|
2376
|
+
|
|
2377
|
+
/**
|
|
2378
|
+
* Upload a file to the user's Supabase storage.
|
|
2379
|
+
*
|
|
2380
|
+
* @param file - The file to upload
|
|
2381
|
+
* @param bucket - The storage bucket name (default: 'uploads')
|
|
2382
|
+
* @param path - Optional custom path for the file
|
|
2383
|
+
* @returns Upload result with URL and metadata
|
|
2384
|
+
*/
|
|
2385
|
+
declare function uploadFile(file: File, bucket?: string, path?: string): Promise<UploadResult>;
|
|
2386
|
+
/**
|
|
2387
|
+
* Upload a font file to the user's Supabase storage.
|
|
2388
|
+
*
|
|
2389
|
+
* @param file - The font file to upload
|
|
2390
|
+
* @returns Upload result with font-specific metadata
|
|
2391
|
+
*/
|
|
2392
|
+
declare function uploadFont(file: File): Promise<UploadResult>;
|
|
2393
|
+
/**
|
|
2394
|
+
* Upload a logo file to the user's Supabase storage.
|
|
2395
|
+
*
|
|
2396
|
+
* @param file - The logo image file to upload
|
|
2397
|
+
* @returns Upload result with URL
|
|
2398
|
+
*/
|
|
2399
|
+
declare function uploadLogo(file: File): Promise<UploadResult>;
|
|
2400
|
+
/**
|
|
2401
|
+
* Translate content using the Framed AI API.
|
|
2402
|
+
*
|
|
2403
|
+
* @param framedApi - The Framed API client instance
|
|
2404
|
+
* @param value - The content to translate (language code to text mapping)
|
|
2405
|
+
* @param primaryLanguage - The source language code
|
|
2406
|
+
* @param targetLanguages - Array of target language codes
|
|
2407
|
+
* @returns Translation result with translations and any errors
|
|
2408
|
+
*/
|
|
2409
|
+
declare function translateContent(framedApi: FramedApiClient, value: Record<string, string>, primaryLanguage: string, targetLanguages: string[]): Promise<TranslationResult>;
|
|
2410
|
+
/**
|
|
2411
|
+
* Create the complete callbacks object for wizard components.
|
|
2412
|
+
*
|
|
2413
|
+
* @param framedApi - The Framed API client instance
|
|
2414
|
+
* @returns Object with all wizard callback implementations
|
|
2415
|
+
*/
|
|
2416
|
+
declare function createWizardCallbacks(framedApi: FramedApiClient): {
|
|
2417
|
+
onUploadFile: (file: File) => Promise<UploadResult>;
|
|
2418
|
+
onUploadFont: (file: File) => Promise<UploadResult>;
|
|
2419
|
+
onLogoUpload: (file: File) => Promise<void>;
|
|
2420
|
+
onTranslateAll: (value: Record<string, string>, primaryLanguage: string, targetLanguages: string[]) => Promise<TranslationResult>;
|
|
2421
|
+
};
|
|
2422
|
+
|
|
2423
|
+
interface LayoutOption {
|
|
2424
|
+
id: string;
|
|
2425
|
+
name: string;
|
|
2426
|
+
description: string;
|
|
2427
|
+
sections: {
|
|
2428
|
+
type: string;
|
|
2429
|
+
title: string;
|
|
2430
|
+
requiresMedia: boolean;
|
|
2431
|
+
requiresCTA: boolean;
|
|
2432
|
+
}[];
|
|
2433
|
+
}
|
|
2434
|
+
interface PageTypeLayouts {
|
|
2435
|
+
[key: string]: LayoutOption[];
|
|
2436
|
+
}
|
|
2437
|
+
declare const PAGE_LAYOUTS: PageTypeLayouts;
|
|
2438
|
+
declare const getLayoutsForPage: (pageId: string) => LayoutOption[];
|
|
2439
|
+
declare const getPageDisplayName: (pageId: string) => string;
|
|
2440
|
+
|
|
2441
|
+
/**
|
|
2442
|
+
* Date filtering utilities for Phase 4 feedback views
|
|
2443
|
+
*/
|
|
2444
|
+
interface DateRange {
|
|
2445
|
+
startDate: Date | null;
|
|
2446
|
+
endDate: Date | null;
|
|
2447
|
+
}
|
|
2448
|
+
interface DatePreset {
|
|
2449
|
+
id: string;
|
|
2450
|
+
label: string;
|
|
2451
|
+
getRange: () => DateRange;
|
|
2452
|
+
}
|
|
2453
|
+
declare const DATE_PRESETS: DatePreset[];
|
|
2454
|
+
/**
|
|
2455
|
+
* Check if a date string is within the given date range
|
|
2456
|
+
*/
|
|
2457
|
+
declare function isWithinDateRange(dateString: string, range: DateRange): boolean;
|
|
2458
|
+
/**
|
|
2459
|
+
* Format a date range for display in the filter button
|
|
2460
|
+
*/
|
|
2461
|
+
declare function formatDateRangeLabel(range: DateRange): string;
|
|
2462
|
+
/**
|
|
2463
|
+
* Check if a date range filter is active (has any date set)
|
|
2464
|
+
*/
|
|
2465
|
+
declare function isDateRangeActive(range: DateRange): boolean;
|
|
2466
|
+
/**
|
|
2467
|
+
* Get an empty date range
|
|
2468
|
+
*/
|
|
2469
|
+
declare function getEmptyDateRange(): DateRange;
|
|
2470
|
+
|
|
2471
|
+
/**
|
|
2472
|
+
* Permission utilities for multi-tenant SaaS
|
|
2473
|
+
* Source: framed-app/src/utils/permissions.ts
|
|
2474
|
+
*/
|
|
2475
|
+
|
|
2476
|
+
/**
|
|
2477
|
+
* Check if an agency's subscription is currently valid
|
|
2478
|
+
*/
|
|
2479
|
+
declare const isSubscriptionValid: (agency: Agency | null) => boolean;
|
|
2480
|
+
/**
|
|
2481
|
+
* Get the effective project limit based on the agency's plan type
|
|
2482
|
+
*/
|
|
2483
|
+
declare const getEffectiveProjectLimit: (agency: Agency | null) => number | null;
|
|
2484
|
+
declare const canCreateProject: (user: User | null, agency: Agency | null, projectCount: number) => boolean;
|
|
2485
|
+
declare const canViewProject: (user: User | null, project: Project | null, members?: ProjectMember[]) => boolean;
|
|
2486
|
+
declare const canEditProject: (user: User | null, project: Project | null, members?: ProjectMember[]) => boolean;
|
|
2487
|
+
declare const canDeleteProject: (user: User | null, project: Project | null) => boolean;
|
|
2488
|
+
declare const canLockPhase: (user: User | null, project: Project | null) => boolean;
|
|
2489
|
+
/**
|
|
2490
|
+
* Check if user can disable/enable phases (hide from navigation)
|
|
2491
|
+
* Same permissions as phase locking - admins can control phase visibility
|
|
2492
|
+
*/
|
|
2493
|
+
declare const canDisablePhase: (user: User | null, project: Project | null) => boolean;
|
|
2494
|
+
/**
|
|
2495
|
+
* Check if a phase is disabled (hidden from navigation)
|
|
2496
|
+
*/
|
|
2497
|
+
declare const isPhaseDisabled: (phase: number, project: Project | null) => boolean;
|
|
2498
|
+
/**
|
|
2499
|
+
* Check if a phase is soft-locked (automatically disabled during review)
|
|
2500
|
+
* Soft-lock applies to Phase 1 and 2 when project is in Phase 3+ or not in draft status
|
|
2501
|
+
* Admins can override by adding phase to unlocked_phases
|
|
2502
|
+
*/
|
|
2503
|
+
declare const isSoftLocked: (phase: number, project: Project | null) => boolean;
|
|
2504
|
+
/**
|
|
2505
|
+
* Check if user can unlock a soft-locked phase
|
|
2506
|
+
* Same permissions as hard lock
|
|
2507
|
+
*/
|
|
2508
|
+
declare const canUnlockSoftLock: (user: User | null, project: Project | null) => boolean;
|
|
2509
|
+
/**
|
|
2510
|
+
* Check if user can approve/reject section suggestions
|
|
2511
|
+
* Only admins and super_admins can approve suggestions
|
|
2512
|
+
*/
|
|
2513
|
+
declare const canApproveSuggestion: (user: User | null, project: Project | null) => boolean;
|
|
2514
|
+
declare const canInviteUsers: (user: User | null) => boolean;
|
|
2515
|
+
declare const canManageProjectMembers: (user: User | null, project: Project | null) => boolean;
|
|
2516
|
+
declare const canRemoveUser: (actor: User | null, targetUser: User | null) => boolean;
|
|
2517
|
+
declare const canManageAgency: (user: User | null, agencyId: string) => boolean;
|
|
2518
|
+
declare const canCreateAgency: (user: User | null) => boolean;
|
|
2519
|
+
declare const canDeleteAgency: (user: User | null) => boolean;
|
|
2520
|
+
declare const canSetProjectLimit: (user: User | null) => boolean;
|
|
2521
|
+
declare const isSuperAdmin: (user: User | null) => boolean;
|
|
2522
|
+
declare const isAdmin: (user: User | null) => boolean;
|
|
2523
|
+
declare const isManager: (user: User | null) => boolean;
|
|
2524
|
+
declare const isClient: (user: User | null) => boolean;
|
|
2525
|
+
declare const hasRole: (user: User | null, role: User["role"]) => boolean;
|
|
2526
|
+
declare const hasHigherRole: (user: User | null, compareRole: User["role"]) => boolean;
|
|
2527
|
+
declare const hasEqualOrHigherRole: (user: User | null, compareRole: User["role"]) => boolean;
|
|
2528
|
+
declare const getRoleBadgeColor: (role: User["role"]) => string;
|
|
2529
|
+
declare const getRoleDisplayName: (role: User["role"]) => string;
|
|
2530
|
+
declare const getRoleBadge: (role: User["role"]) => string;
|
|
2531
|
+
declare const canManageTeam: (user: User | null) => boolean;
|
|
2532
|
+
/**
|
|
2533
|
+
* Check if user has admin-level privileges (admin or super_admin)
|
|
2534
|
+
* Use this for features that should be available to both admins and super admins
|
|
2535
|
+
* Examples: export functionality, viewing admin-only UI elements
|
|
2536
|
+
*/
|
|
2537
|
+
declare const hasAdminPrivileges: (user: User | null) => boolean;
|
|
2538
|
+
/**
|
|
2539
|
+
* Get display name for plan type
|
|
2540
|
+
*/
|
|
2541
|
+
declare const getPlanDisplayName: (planType: Agency["plan_type"]) => string;
|
|
2542
|
+
/**
|
|
2543
|
+
* Get display name for subscription status
|
|
2544
|
+
*/
|
|
2545
|
+
declare const getSubscriptionStatusDisplayName: (status: Agency["subscription_status"]) => string;
|
|
2546
|
+
/**
|
|
2547
|
+
* Get badge color for subscription status
|
|
2548
|
+
*/
|
|
2549
|
+
declare const getSubscriptionStatusBadgeColor: (status: Agency["subscription_status"]) => string;
|
|
2550
|
+
/**
|
|
2551
|
+
* Get badge color for plan type
|
|
2552
|
+
*/
|
|
2553
|
+
declare const getPlanBadgeColor: (planType: Agency["plan_type"]) => string;
|
|
2554
|
+
/**
|
|
2555
|
+
* Format date for display
|
|
2556
|
+
*/
|
|
2557
|
+
declare const formatSubscriptionDate: (dateString: string | null) => string;
|
|
2558
|
+
/**
|
|
2559
|
+
* Get days remaining until subscription expires
|
|
2560
|
+
*/
|
|
2561
|
+
declare const getDaysRemaining: (endDate: string | null) => number | null;
|
|
2562
|
+
/**
|
|
2563
|
+
* Check if user can configure modules for a project
|
|
2564
|
+
* Only admins and super_admins can change module settings
|
|
2565
|
+
*/
|
|
2566
|
+
declare const canConfigureModules: (user: User | null, project: Project | null) => boolean;
|
|
2567
|
+
/**
|
|
2568
|
+
* Check if user can access a specific phase based on module configuration
|
|
2569
|
+
* Combines module availability with existing project permissions
|
|
2570
|
+
*/
|
|
2571
|
+
declare const canAccessPhase: (user: User | null, project: Project | null, phase: number, members?: ProjectMember[]) => boolean;
|
|
2572
|
+
/**
|
|
2573
|
+
* Check if a module is available for a project (enabled)
|
|
2574
|
+
*/
|
|
2575
|
+
declare const isModuleAvailable: (project: Project | null, module: ModuleType) => boolean;
|
|
2576
|
+
|
|
2577
|
+
/**
|
|
2578
|
+
* Comment utilities - Pure functions for mention handling
|
|
2579
|
+
* Source: framed-app/src/utils/commentUtils.ts
|
|
2580
|
+
*
|
|
2581
|
+
* Note: Upload functions are NOT included here as they require runtime
|
|
2582
|
+
* dependencies (supabase). Only pure utility functions are exported.
|
|
2583
|
+
*
|
|
2584
|
+
* For UploadResult type, use the one from @framed/core types.
|
|
2585
|
+
*/
|
|
2586
|
+
/**
|
|
2587
|
+
* Extract user IDs from @mentions in text
|
|
2588
|
+
* Format: @[userId:userName] or @userName (if we have user list)
|
|
2589
|
+
*/
|
|
2590
|
+
declare function extractMentions(text: string, availableUsers?: Array<{
|
|
2591
|
+
id: string;
|
|
2592
|
+
name: string;
|
|
2593
|
+
}>): string[];
|
|
2594
|
+
/**
|
|
2595
|
+
* Format text with @mentions highlighted
|
|
2596
|
+
* Converts @[userId:userName] to styled mentions
|
|
2597
|
+
*/
|
|
2598
|
+
declare function formatMentions(text: string): string;
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* Localized content utilities
|
|
2602
|
+
* Source: framed-app/src/utils/localizedContent.ts
|
|
2603
|
+
*/
|
|
2604
|
+
|
|
2605
|
+
/**
|
|
2606
|
+
* Get language settings from Phase 1 functionality data
|
|
2607
|
+
*/
|
|
2608
|
+
interface LanguageSettings {
|
|
2609
|
+
isMultilingual: boolean;
|
|
2610
|
+
primaryLanguage: string;
|
|
2611
|
+
additionalLanguages: string[];
|
|
2612
|
+
allLanguages: string[];
|
|
2613
|
+
}
|
|
2614
|
+
declare const getLanguageSettings: (functionality?: {
|
|
2615
|
+
languages?: {
|
|
2616
|
+
is_multilingual: boolean;
|
|
2617
|
+
primary_language: string;
|
|
2618
|
+
additional_languages: string[];
|
|
2619
|
+
};
|
|
2620
|
+
}) => LanguageSettings;
|
|
2621
|
+
/**
|
|
2622
|
+
* Get display value for a LocalizableString
|
|
2623
|
+
* Always returns a string, handling both old (string) and new (LocalizedContent) formats
|
|
2624
|
+
*/
|
|
2625
|
+
declare const getDisplayValue: (value: LocalizableString | undefined, languageSettings: LanguageSettings, displayLanguage?: string) => string;
|
|
2626
|
+
/**
|
|
2627
|
+
* Update a LocalizableString value for a specific language
|
|
2628
|
+
* Handles conversion from string to LocalizedContent if needed
|
|
2629
|
+
*/
|
|
2630
|
+
declare const updateLocalizedValue: (currentValue: LocalizableString | undefined, newValue: string, language: string, languageSettings: LanguageSettings) => LocalizableString;
|
|
2631
|
+
/**
|
|
2632
|
+
* Convert form data to the appropriate format based on language settings
|
|
2633
|
+
* Used when saving data - ensures format matches multilingual setting
|
|
2634
|
+
*/
|
|
2635
|
+
declare const normalizeLocalizedField: (value: LocalizableString | undefined, languageSettings: LanguageSettings) => LocalizableString;
|
|
2636
|
+
/**
|
|
2637
|
+
* Check if a localized field has content in all required languages
|
|
2638
|
+
*/
|
|
2639
|
+
declare const isLocalizedFieldComplete: (value: LocalizableString | undefined, languageSettings: LanguageSettings, requireAllLanguages?: boolean) => boolean;
|
|
2640
|
+
/**
|
|
2641
|
+
* Create initial localized content with empty values for all languages
|
|
2642
|
+
*/
|
|
2643
|
+
declare const createEmptyLocalizedContent: (languageSettings: LanguageSettings) => LocalizedContent;
|
|
2644
|
+
/**
|
|
2645
|
+
* Migrate a single string value to localized content format
|
|
2646
|
+
* Useful for database migrations or data upgrades
|
|
2647
|
+
*/
|
|
2648
|
+
declare const migrateToLocalized: (value: string, sourceLanguage: string, languageSettings: LanguageSettings) => LocalizedContent;
|
|
2649
|
+
|
|
2650
|
+
/**
|
|
2651
|
+
* Format file size for display
|
|
2652
|
+
* Source: framed-app/src/utils/storage.ts (pure function extracted)
|
|
2653
|
+
*/
|
|
2654
|
+
declare const formatFileSize: (bytes: number) => string;
|
|
2655
|
+
|
|
2656
|
+
/**
|
|
2657
|
+
* Storage utilities - Stub implementations
|
|
2658
|
+
*
|
|
2659
|
+
* These are placeholder functions that log warnings.
|
|
2660
|
+
* Actual storage operations should be handled by the parent app
|
|
2661
|
+
* via FramedProvider callbacks (onUploadFile, onDeleteFile).
|
|
2662
|
+
*/
|
|
2663
|
+
interface UploadMediaOptions {
|
|
2664
|
+
file: File;
|
|
2665
|
+
projectId: string;
|
|
2666
|
+
path?: string;
|
|
2667
|
+
}
|
|
2668
|
+
interface UploadMediaResult {
|
|
2669
|
+
url: string;
|
|
2670
|
+
path: string;
|
|
2671
|
+
}
|
|
2672
|
+
/**
|
|
2673
|
+
* Upload media file to storage
|
|
2674
|
+
* Stub - logs warning, actual upload should use FramedProvider callbacks
|
|
2675
|
+
*/
|
|
2676
|
+
declare function uploadMedia(_options: UploadMediaOptions): Promise<UploadMediaResult | null>;
|
|
2677
|
+
/**
|
|
2678
|
+
* Delete media file from storage
|
|
2679
|
+
* Stub - logs warning, actual delete should use FramedProvider callbacks
|
|
2680
|
+
*/
|
|
2681
|
+
declare function deleteMedia(_path: string): Promise<boolean>;
|
|
2682
|
+
|
|
2683
|
+
/**
|
|
2684
|
+
* Feature flag utilities
|
|
2685
|
+
* Source: framed-app/src/utils/featureFlags.ts
|
|
2686
|
+
*/
|
|
2687
|
+
|
|
2688
|
+
/**
|
|
2689
|
+
* Check if a user/project has access to a specific feature
|
|
2690
|
+
*/
|
|
2691
|
+
declare const hasFeature: (user: User | null, project: Project | null, featureName: string) => boolean;
|
|
2692
|
+
/**
|
|
2693
|
+
* Check if agency has a monitoring feature available
|
|
2694
|
+
* This is the "capability" check - can the agency use this feature at all?
|
|
2695
|
+
*/
|
|
2696
|
+
declare const agencyHasMonitoringFeature: (project: Project | null, feature: "seo" | "performance" | "uptime" | "analytics") => boolean;
|
|
2697
|
+
/**
|
|
2698
|
+
* Check if a monitoring feature is enabled for a specific project
|
|
2699
|
+
* Returns true if:
|
|
2700
|
+
* 1. Agency has the feature available AND
|
|
2701
|
+
* 2. Project has the feature enabled (or no explicit setting = enabled by default)
|
|
2702
|
+
*
|
|
2703
|
+
* This allows agencies to selectively enable/disable features per project for billing
|
|
2704
|
+
*/
|
|
2705
|
+
declare const projectHasMonitoringFeature: (user: User | null, project: Project | null, feature: "seo" | "performance" | "uptime" | "analytics") => boolean;
|
|
2706
|
+
/**
|
|
2707
|
+
* Check if performance analysis feature is available
|
|
2708
|
+
* Available to:
|
|
2709
|
+
* - Super admins (always)
|
|
2710
|
+
* - Gold plan agencies (automatically)
|
|
2711
|
+
* - Agencies with feature explicitly enabled
|
|
2712
|
+
*/
|
|
2713
|
+
declare const hasPerformanceAnalysis: (user: User | null, project: Project | null) => boolean;
|
|
2714
|
+
/**
|
|
2715
|
+
* Check if SEO audit feature is available
|
|
2716
|
+
* Available to:
|
|
2717
|
+
* - Super admins (always)
|
|
2718
|
+
* - Gold plan agencies (automatically)
|
|
2719
|
+
* - Agencies with feature explicitly enabled
|
|
2720
|
+
*/
|
|
2721
|
+
declare const hasSeoAudit: (user: User | null, project: Project | null) => boolean;
|
|
2722
|
+
/**
|
|
2723
|
+
* Get SEO audit credits info for an agency
|
|
2724
|
+
*/
|
|
2725
|
+
declare const getSeoCreditsInfo: (project: Project | null) => {
|
|
2726
|
+
used: number;
|
|
2727
|
+
limit: number;
|
|
2728
|
+
remaining: number;
|
|
2729
|
+
};
|
|
2730
|
+
/**
|
|
2731
|
+
* Check if AI content generation feature is available
|
|
2732
|
+
* This includes:
|
|
2733
|
+
* - AI content suggestions for sections
|
|
2734
|
+
* - AI translation for multilingual content
|
|
2735
|
+
* - Auto-generate all content feature
|
|
2736
|
+
*
|
|
2737
|
+
* Available to:
|
|
2738
|
+
* - Super admins (always)
|
|
2739
|
+
* - Gold plan agencies (automatically)
|
|
2740
|
+
* - Silver plan agencies (automatically)
|
|
2741
|
+
* - Agencies with feature explicitly enabled
|
|
2742
|
+
*/
|
|
2743
|
+
declare const hasAIContentGeneration: (user: User | null, project: Project | null) => boolean;
|
|
2744
|
+
/**
|
|
2745
|
+
* Get all available features for a project
|
|
2746
|
+
*/
|
|
2747
|
+
declare const getAvailableFeatures: (user: User | null, project: Project | null) => string[];
|
|
2748
|
+
/**
|
|
2749
|
+
* Feature display names for UI
|
|
2750
|
+
*/
|
|
2751
|
+
declare const FEATURE_NAMES: Record<string, string>;
|
|
2752
|
+
/**
|
|
2753
|
+
* Feature descriptions for UI
|
|
2754
|
+
*/
|
|
2755
|
+
declare const FEATURE_DESCRIPTIONS: Record<string, string>;
|
|
2756
|
+
/**
|
|
2757
|
+
* Monitoring feature display names for Phase 5
|
|
2758
|
+
*/
|
|
2759
|
+
declare const MONITORING_FEATURE_NAMES: Record<'seo' | 'performance' | 'uptime' | 'analytics', string>;
|
|
2760
|
+
/**
|
|
2761
|
+
* Monitoring feature descriptions for Phase 5
|
|
2762
|
+
*/
|
|
2763
|
+
declare const MONITORING_FEATURE_DESCRIPTIONS: Record<'seo' | 'performance' | 'uptime' | 'analytics', string>;
|
|
2764
|
+
|
|
2765
|
+
/**
|
|
2766
|
+
* Shared comment factory utility
|
|
2767
|
+
* Source: framed-app/src/utils/createComment.ts
|
|
2768
|
+
*
|
|
2769
|
+
* Ensures consistent comment structure across all views:
|
|
2770
|
+
* - Page-level feedback (Phase4ReviewPageNew)
|
|
2771
|
+
* - All feedback view (AllFeedbackView)
|
|
2772
|
+
* - Mobile view (Phase4MobileView)
|
|
2773
|
+
*/
|
|
2774
|
+
|
|
2775
|
+
interface CreateCommentOptions {
|
|
2776
|
+
comment: string;
|
|
2777
|
+
userId: string;
|
|
2778
|
+
userName: string;
|
|
2779
|
+
userRole?: UserRole;
|
|
2780
|
+
attachments?: CommentAttachment[];
|
|
2781
|
+
versionNumber?: number;
|
|
2782
|
+
position?: {
|
|
2783
|
+
x: number;
|
|
2784
|
+
y: number;
|
|
2785
|
+
};
|
|
2786
|
+
screenshotType?: 'desktop' | 'mobile';
|
|
2787
|
+
source?: 'app' | 'widget' | 'screenshot' | 'content_editor';
|
|
2788
|
+
currentRound?: number;
|
|
2789
|
+
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Creates a standardized PageComment object with all required fields populated
|
|
2792
|
+
*/
|
|
2793
|
+
declare function createComment(options: CreateCommentOptions): PageComment;
|
|
2794
|
+
|
|
2795
|
+
/**
|
|
2796
|
+
* Backwards Compatibility Utilities
|
|
2797
|
+
* Source: framed-app/src/utils/compatibility.ts
|
|
2798
|
+
*
|
|
2799
|
+
* Helper functions to bridge the old website-only data model with the new
|
|
2800
|
+
* multi-project-type model. These ensure existing projects continue to work
|
|
2801
|
+
* while new projects can use the enhanced features.
|
|
2802
|
+
*/
|
|
2803
|
+
|
|
2804
|
+
/**
|
|
2805
|
+
* Get the project category from Phase1Data, defaulting to 'website' for backwards compatibility
|
|
2806
|
+
*/
|
|
2807
|
+
declare function getProjectCategory(phase1: Phase1Data | undefined): ProjectCategory;
|
|
2808
|
+
/**
|
|
2809
|
+
* Check if a project is e-commerce (supports both old and new data models)
|
|
2810
|
+
*/
|
|
2811
|
+
declare function isEcommerceProject(phase1: Phase1Data | undefined): boolean;
|
|
2812
|
+
/**
|
|
2813
|
+
* Check if a project is a website (includes e-commerce as a website subtype for UI purposes)
|
|
2814
|
+
*/
|
|
2815
|
+
declare function isWebsiteBasedProject(phase1: Phase1Data | undefined): boolean;
|
|
2816
|
+
/**
|
|
2817
|
+
* Check if a project category should show the traditional page/section wizard (Phase 2)
|
|
2818
|
+
*/
|
|
2819
|
+
declare function shouldShowTraditionalWizard(phase1: Phase1Data | undefined): boolean;
|
|
2820
|
+
/**
|
|
2821
|
+
* Get pages from Phase1Data - supports both old (pages array) and new (screens array) formats
|
|
2822
|
+
* Returns an array of page IDs for backwards compatibility
|
|
2823
|
+
*/
|
|
2824
|
+
declare function getPages(phase1: Phase1Data | undefined): string[];
|
|
2825
|
+
/**
|
|
2826
|
+
* Get custom pages from Phase1Data - supports both old and new formats
|
|
2827
|
+
*/
|
|
2828
|
+
declare function getCustomPages(phase1: Phase1Data | undefined): string[];
|
|
2829
|
+
/**
|
|
2830
|
+
* Get all screens from Phase1Data - returns screens array or converts pages to screens
|
|
2831
|
+
*/
|
|
2832
|
+
declare function getScreens(phase1: Phase1Data | undefined): ScreenDefinition[];
|
|
2833
|
+
declare function isDefaultPage(pageId: string): boolean;
|
|
2834
|
+
/**
|
|
2835
|
+
* Get the default display name for a page ID
|
|
2836
|
+
*/
|
|
2837
|
+
declare function getDefaultPageName(pageId: string): string;
|
|
2838
|
+
/**
|
|
2839
|
+
* Get the display name for a screen/page
|
|
2840
|
+
*/
|
|
2841
|
+
declare function getScreenDisplayName(screen: ScreenDefinition | string, phase1?: Phase1Data): string;
|
|
2842
|
+
/**
|
|
2843
|
+
* Get the appropriate screen type label for a project category
|
|
2844
|
+
*/
|
|
2845
|
+
declare function getScreenTypeLabel(category: ProjectCategory, plural?: boolean): string;
|
|
2846
|
+
/**
|
|
2847
|
+
* Get the default screen type for a project category
|
|
2848
|
+
*/
|
|
2849
|
+
declare function getDefaultScreenType(category: ProjectCategory): ScreenType;
|
|
2850
|
+
/**
|
|
2851
|
+
* Migrate Phase1Data from old format to new format
|
|
2852
|
+
* This is a non-destructive operation that adds new fields without removing old ones
|
|
2853
|
+
*/
|
|
2854
|
+
declare function migratePhase1Data(phase1: Phase1Data): Phase1Data;
|
|
2855
|
+
/**
|
|
2856
|
+
* Check if Phase1Data needs migration
|
|
2857
|
+
*/
|
|
2858
|
+
declare function needsMigration(phase1: Phase1Data | undefined): boolean;
|
|
2859
|
+
interface ProjectCategoryInfo {
|
|
2860
|
+
id: ProjectCategory;
|
|
2861
|
+
name: string;
|
|
2862
|
+
description: string;
|
|
2863
|
+
icon: string;
|
|
2864
|
+
examples: string[];
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Get display information for project categories
|
|
2868
|
+
*/
|
|
2869
|
+
declare function getProjectCategoryInfo(category: ProjectCategory): ProjectCategoryInfo;
|
|
2870
|
+
/**
|
|
2871
|
+
* Get all project categories with their display info
|
|
2872
|
+
*/
|
|
2873
|
+
declare function getAllProjectCategories(): ProjectCategoryInfo[];
|
|
2874
|
+
|
|
2875
|
+
/**
|
|
2876
|
+
* Utilities for collecting and filtering unified feed items
|
|
2877
|
+
* Source: framed-app/src/utils/feedUtils.ts
|
|
2878
|
+
*
|
|
2879
|
+
* Combines feedback comments, text edits, and image feedback into a single chronological feed
|
|
2880
|
+
*/
|
|
2881
|
+
|
|
2882
|
+
/**
|
|
2883
|
+
* Get screenshot URL for a comment based on version and screenshot type
|
|
2884
|
+
* For region captures from the widget, the screenshot is stored in comment.metadata.screenshotUrl
|
|
2885
|
+
*/
|
|
2886
|
+
declare function getScreenshotUrl(page: Phase4Page, comment: PageComment): string | undefined;
|
|
2887
|
+
/**
|
|
2888
|
+
* Collect all feed items from Phase 4 pages and images
|
|
2889
|
+
* Combines feedback comments, text edits, and image feedback into a single array
|
|
2890
|
+
*/
|
|
2891
|
+
declare function collectFeedItems(pages: Phase4Page[], pageImages?: PageImage[]): FeedItem[];
|
|
2892
|
+
type FeedTypeFilter = 'all' | 'feedback' | 'text_edits' | 'image_feedback';
|
|
2893
|
+
type FeedStatusFilter = 'all' | 'open' | 'resolved';
|
|
2894
|
+
interface FeedFilters {
|
|
2895
|
+
type: FeedTypeFilter;
|
|
2896
|
+
status: FeedStatusFilter;
|
|
2897
|
+
page?: string;
|
|
2898
|
+
language?: string;
|
|
2899
|
+
round?: number;
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* Filter feed items based on selected filters
|
|
2903
|
+
*/
|
|
2904
|
+
declare function filterFeedItems(items: FeedItem[], filters: FeedFilters): FeedItem[];
|
|
2905
|
+
interface GroupedFeedItems {
|
|
2906
|
+
[pageName: string]: FeedItem[];
|
|
2907
|
+
}
|
|
2908
|
+
/**
|
|
2909
|
+
* Group feed items by page name
|
|
2910
|
+
*/
|
|
2911
|
+
declare function groupFeedItemsByPage(items: FeedItem[]): GroupedFeedItems;
|
|
2912
|
+
interface FeedStats {
|
|
2913
|
+
total: number;
|
|
2914
|
+
feedbackCount: number;
|
|
2915
|
+
textEditCount: number;
|
|
2916
|
+
imageFeedbackCount: number;
|
|
2917
|
+
openFeedback: number;
|
|
2918
|
+
resolvedFeedback: number;
|
|
2919
|
+
openTextEdits: number;
|
|
2920
|
+
resolvedTextEdits: number;
|
|
2921
|
+
openImageFeedback: number;
|
|
2922
|
+
resolvedImageFeedback: number;
|
|
2923
|
+
pagesAffected: number;
|
|
2924
|
+
languagesUsed: string[];
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Calculate statistics for feed items
|
|
2928
|
+
*/
|
|
2929
|
+
declare function calculateFeedStats(items: FeedItem[]): FeedStats;
|
|
2930
|
+
/**
|
|
2931
|
+
* Get available languages from feed items
|
|
2932
|
+
*/
|
|
2933
|
+
declare function getAvailableLanguages(items: FeedItem[]): string[];
|
|
2934
|
+
/**
|
|
2935
|
+
* Get available pages from feed items
|
|
2936
|
+
*/
|
|
2937
|
+
declare function getAvailablePages(items: FeedItem[]): string[];
|
|
2938
|
+
|
|
2939
|
+
/**
|
|
2940
|
+
* Resolution Report Parser
|
|
2941
|
+
* Source: framed-app/src/utils/resolutionParser.ts
|
|
2942
|
+
*
|
|
2943
|
+
* Parses markdown resolution reports from AI agents and applies changes to feedback
|
|
2944
|
+
*
|
|
2945
|
+
* Supports multiple formats:
|
|
2946
|
+
* 1. Checkbox format: **ID:** `feedback-id` with **Status:** [X] DONE / [ ] MANUAL / [ ] SKIPPED
|
|
2947
|
+
* 2. Simple format: ## Resolved Items / ## Unable to Resolve with - [id]: description
|
|
2948
|
+
* 3. Page-grouped format: ### Home Page (X items) with - [id]: description
|
|
2949
|
+
* 4. Mixed format with Notes, Clarification sections, etc.
|
|
2950
|
+
*/
|
|
2951
|
+
|
|
2952
|
+
interface ResolutionParseResult {
|
|
2953
|
+
success: boolean;
|
|
2954
|
+
resolved: ParsedResolutionItem[];
|
|
2955
|
+
unable_to_resolve: ParsedResolutionItem[];
|
|
2956
|
+
needs_clarification: ParsedResolutionItem[];
|
|
2957
|
+
unmatched_ids: string[];
|
|
2958
|
+
total_parsed: number;
|
|
2959
|
+
errors: string[];
|
|
2960
|
+
notes?: string;
|
|
2961
|
+
}
|
|
2962
|
+
interface ApplyResolutionOptions {
|
|
2963
|
+
user: User;
|
|
2964
|
+
roundNumber: number;
|
|
2965
|
+
createNotesForUnmatched?: boolean;
|
|
2966
|
+
}
|
|
2967
|
+
/**
|
|
2968
|
+
* Parse a resolution markdown report
|
|
2969
|
+
* Handles various AI response formats including page-grouped items
|
|
2970
|
+
*/
|
|
2971
|
+
declare function parseResolutionReport(markdown: string, existingIds: string[]): ResolutionParseResult;
|
|
2972
|
+
/**
|
|
2973
|
+
* Apply parsed resolutions to Phase4 data
|
|
2974
|
+
* For "needs_clarification" items, creates a reply asking for clarification
|
|
2975
|
+
*/
|
|
2976
|
+
declare function applyResolutions(phase4Data: Phase4Data, parsed: ResolutionParseResult, options: ApplyResolutionOptions): {
|
|
2977
|
+
updatedData: Phase4Data;
|
|
2978
|
+
importResult: ResolutionImportResult;
|
|
2979
|
+
};
|
|
2980
|
+
/**
|
|
2981
|
+
* Get all feedback IDs from Phase4 data
|
|
2982
|
+
*/
|
|
2983
|
+
declare function getAllFeedbackIds(phase4Data: Phase4Data): string[];
|
|
2984
|
+
/**
|
|
2985
|
+
* Count feedback statistics for a round
|
|
2986
|
+
*/
|
|
2987
|
+
declare function countRoundStats(phase4Data: Phase4Data, roundNumber: number): {
|
|
2988
|
+
total: number;
|
|
2989
|
+
open: number;
|
|
2990
|
+
resolved: number;
|
|
2991
|
+
unable: number;
|
|
2992
|
+
};
|
|
2993
|
+
/**
|
|
2994
|
+
* Calculate summary when closing a round
|
|
2995
|
+
*/
|
|
2996
|
+
declare function calculateRoundSummary(phase4Data: Phase4Data, roundNumber: number): {
|
|
2997
|
+
total_items: number;
|
|
2998
|
+
resolved_in_round: number;
|
|
2999
|
+
carried_over: number;
|
|
3000
|
+
unable_to_resolve: number;
|
|
3001
|
+
new_items_added: number;
|
|
3002
|
+
};
|
|
3003
|
+
/**
|
|
3004
|
+
* Migrate existing comments to Round 1
|
|
3005
|
+
* Called when first round is started on a project with existing comments
|
|
3006
|
+
*/
|
|
3007
|
+
declare function migrateToRounds(phase4Data: Phase4Data, userId: string, userName: string): Phase4Data;
|
|
3008
|
+
|
|
3009
|
+
/**
|
|
3010
|
+
* Prompt Generator Utilities
|
|
3011
|
+
* Source: framed-app/src/utils/promptGenerator.ts
|
|
3012
|
+
*
|
|
3013
|
+
* Generates AI prompts and exports for project data
|
|
3014
|
+
*/
|
|
3015
|
+
|
|
3016
|
+
/**
|
|
3017
|
+
* Generate a natural language prompt for AI website builders
|
|
3018
|
+
*/
|
|
3019
|
+
declare const generateNaturalLanguagePrompt: (data: ProjectData) => string;
|
|
3020
|
+
/**
|
|
3021
|
+
* Generate JSON export for programmatic use
|
|
3022
|
+
*/
|
|
3023
|
+
declare const generateJSONExport: (data: ProjectData) => Record<string, unknown>;
|
|
3024
|
+
/**
|
|
3025
|
+
* Generate a short prompt (max 1000 characters) for AI builders with limited input
|
|
3026
|
+
*/
|
|
3027
|
+
declare const generateShortPrompt: (data: Phase1Data, isNl?: boolean) => string;
|
|
3028
|
+
/**
|
|
3029
|
+
* Collect all media URLs from project
|
|
3030
|
+
*/
|
|
3031
|
+
declare const collectProjectMedia: (data: ProjectData) => string[];
|
|
3032
|
+
/**
|
|
3033
|
+
* Generate planning section for project
|
|
3034
|
+
* Stub - full implementation in framed-app
|
|
3035
|
+
*/
|
|
3036
|
+
declare const generatePlanningSection: (data: Phase1Data, isNl?: boolean) => string;
|
|
3037
|
+
/**
|
|
3038
|
+
* Generate project instructions markdown
|
|
3039
|
+
* Stub - full implementation in framed-app
|
|
3040
|
+
*/
|
|
3041
|
+
declare const generateProjectInstructionsMd: (data: Phase1Data, isNl?: boolean) => string;
|
|
3042
|
+
/**
|
|
3043
|
+
* Enhanced prompt response from AI enhancement
|
|
3044
|
+
*/
|
|
3045
|
+
interface EnhancedPromptResponse {
|
|
3046
|
+
enhanced_prompt: string;
|
|
3047
|
+
planning_section: string;
|
|
3048
|
+
project_instructions_md: string;
|
|
3049
|
+
error?: string;
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
/**
|
|
3053
|
+
* Text diff utilities
|
|
3054
|
+
*
|
|
3055
|
+
* Provides word-level diff computation for text comparison.
|
|
3056
|
+
* Used by CompactDiff component and text editing features.
|
|
3057
|
+
*/
|
|
3058
|
+
interface DiffPart {
|
|
3059
|
+
value: string;
|
|
3060
|
+
added?: boolean;
|
|
3061
|
+
removed?: boolean;
|
|
3062
|
+
}
|
|
3063
|
+
/**
|
|
3064
|
+
* Simple word-level diff implementation
|
|
3065
|
+
* For production, consider using the 'diff' npm package
|
|
3066
|
+
*/
|
|
3067
|
+
declare function computeTextDiff(original: string, current: string): DiffPart[];
|
|
3068
|
+
|
|
3069
|
+
/**
|
|
3070
|
+
* Text content utilities for managing page text edits
|
|
3071
|
+
* Pure functions for content manipulation - no API calls
|
|
3072
|
+
*
|
|
3073
|
+
* Source: framed-app/src/services/textContentService.ts (pure functions only)
|
|
3074
|
+
*/
|
|
3075
|
+
|
|
3076
|
+
declare const LANGUAGE_LABELS: Record<string, string>;
|
|
3077
|
+
interface ExportedChange {
|
|
3078
|
+
sectionName: string;
|
|
3079
|
+
blockType: string;
|
|
3080
|
+
tagName: string;
|
|
3081
|
+
original: string;
|
|
3082
|
+
updated: string;
|
|
3083
|
+
editCount: number;
|
|
3084
|
+
lastEditedBy: string;
|
|
3085
|
+
lastEditedAt: string;
|
|
3086
|
+
}
|
|
3087
|
+
interface TextChangesExport {
|
|
3088
|
+
pageUrl: string;
|
|
3089
|
+
language: string;
|
|
3090
|
+
crawledAt: string;
|
|
3091
|
+
exportedAt: string;
|
|
3092
|
+
totalBlocks: number;
|
|
3093
|
+
changedBlocks: number;
|
|
3094
|
+
changes: ExportedChange[];
|
|
3095
|
+
}
|
|
3096
|
+
/**
|
|
3097
|
+
* Add or update language content in PageTextContent
|
|
3098
|
+
*/
|
|
3099
|
+
declare function addLanguageContent(textContent: PageTextContent | undefined, pageUrl: string, languageContent: LanguageContent): PageTextContent;
|
|
3100
|
+
/**
|
|
3101
|
+
* Apply a text edit to a block and return updated content
|
|
3102
|
+
*/
|
|
3103
|
+
declare function applyBlockEdit(textContent: PageTextContent, language: string, sectionId: string, blockId: string, newContent: string, userId: string, userName: string, userRole: UserRole, comment?: string): PageTextContent;
|
|
3104
|
+
/**
|
|
3105
|
+
* Apply list items edit
|
|
3106
|
+
*/
|
|
3107
|
+
declare function applyListEdit(textContent: PageTextContent, language: string, sectionId: string, blockId: string, newItems: string[], userId: string, userName: string, userRole: UserRole, comment?: string): PageTextContent;
|
|
3108
|
+
/**
|
|
3109
|
+
* Restore block to original content
|
|
3110
|
+
*/
|
|
3111
|
+
declare function restoreBlockToOriginal(textContent: PageTextContent, language: string, sectionId: string, blockId: string, userId: string, userName: string, userRole: UserRole): PageTextContent;
|
|
3112
|
+
/**
|
|
3113
|
+
* Check if block has been modified
|
|
3114
|
+
*/
|
|
3115
|
+
declare function isBlockModified(block: ContentBlock): boolean;
|
|
3116
|
+
/**
|
|
3117
|
+
* Get count of modified blocks in a language
|
|
3118
|
+
*/
|
|
3119
|
+
declare function getModifiedCount(langContent: LanguageContent): number;
|
|
3120
|
+
/**
|
|
3121
|
+
* Get total block count
|
|
3122
|
+
*/
|
|
3123
|
+
declare function getTotalBlockCount(langContent: LanguageContent): number;
|
|
3124
|
+
/**
|
|
3125
|
+
* Get edit history for specific block
|
|
3126
|
+
*/
|
|
3127
|
+
declare function getBlockHistory(langContent: LanguageContent, blockId: string): TextEdit[];
|
|
3128
|
+
/**
|
|
3129
|
+
* Get recent edits across all blocks
|
|
3130
|
+
*/
|
|
3131
|
+
declare function getRecentEdits(langContent: LanguageContent, limit?: number): TextEdit[];
|
|
3132
|
+
/**
|
|
3133
|
+
* Export changes for developer handoff
|
|
3134
|
+
*/
|
|
3135
|
+
declare function exportTextChanges(textContent: PageTextContent, language: string): TextChangesExport | null;
|
|
3136
|
+
/**
|
|
3137
|
+
* Get available languages for a page's text content
|
|
3138
|
+
*/
|
|
3139
|
+
declare function getTextContentLanguages(textContent: PageTextContent | undefined): string[];
|
|
3140
|
+
/**
|
|
3141
|
+
* Get language label for display
|
|
3142
|
+
*/
|
|
3143
|
+
declare function getLanguageLabel(code: string): string;
|
|
3144
|
+
/**
|
|
3145
|
+
* Format relative time (e.g., "2 hours ago")
|
|
3146
|
+
*/
|
|
3147
|
+
declare function formatRelativeTime(dateString: string): string;
|
|
3148
|
+
|
|
3149
|
+
/**
|
|
3150
|
+
* Screenshot/scraping utility functions
|
|
3151
|
+
* Pure functions only - no API calls
|
|
3152
|
+
*
|
|
3153
|
+
* Source: framed-app/src/services/screenshotService.ts (pure functions only)
|
|
3154
|
+
*/
|
|
3155
|
+
/**
|
|
3156
|
+
* Convert URL to friendly page name (fallback when title can't be fetched)
|
|
3157
|
+
* Example: https://example.com/about-us -> About Us
|
|
3158
|
+
*/
|
|
3159
|
+
declare function generatePageName(url: string): string;
|
|
3160
|
+
/**
|
|
3161
|
+
* Parse sitemap XML and extract page URLs
|
|
3162
|
+
* Note: Uses browser DOMParser API
|
|
3163
|
+
*/
|
|
3164
|
+
declare function parseSitemapXML(xmlText: string): string[];
|
|
3165
|
+
/**
|
|
3166
|
+
* Generate minimal Phase 1 data for review-only projects
|
|
3167
|
+
*/
|
|
3168
|
+
declare function generateMinimalPhase1Data(businessName: string, pageNames: string[]): {
|
|
3169
|
+
business_name: string;
|
|
3170
|
+
industry: string;
|
|
3171
|
+
goal: string;
|
|
3172
|
+
audience: string;
|
|
3173
|
+
is_ecommerce: boolean;
|
|
3174
|
+
pages: string[];
|
|
3175
|
+
custom_pages: string[];
|
|
3176
|
+
page_content: {};
|
|
3177
|
+
legal_content_preference: "not_sure";
|
|
3178
|
+
has_logo: boolean;
|
|
3179
|
+
logo_url: null;
|
|
3180
|
+
colors: {
|
|
3181
|
+
primary: null;
|
|
3182
|
+
secondary: null;
|
|
3183
|
+
accent: null;
|
|
3184
|
+
no_idea: boolean;
|
|
3185
|
+
};
|
|
3186
|
+
font: {
|
|
3187
|
+
primary: null;
|
|
3188
|
+
secondary: null;
|
|
3189
|
+
custom_fonts: never[];
|
|
3190
|
+
no_idea: boolean;
|
|
3191
|
+
};
|
|
3192
|
+
style_keywords: never[];
|
|
3193
|
+
references: never[];
|
|
3194
|
+
};
|
|
3195
|
+
|
|
3196
|
+
/**
|
|
3197
|
+
* SEO audit utility functions
|
|
3198
|
+
* Pure functions for parsing and scoring - no API calls
|
|
3199
|
+
*
|
|
3200
|
+
* Source: framed-app/src/services/seoService.ts (pure functions only)
|
|
3201
|
+
*/
|
|
3202
|
+
|
|
3203
|
+
/**
|
|
3204
|
+
* Parse Apify SEO audit results into our format
|
|
3205
|
+
*/
|
|
3206
|
+
declare const parseApifyResults: (apifyResults: any[]) => SeoAuditResult[];
|
|
3207
|
+
/**
|
|
3208
|
+
* Format issue title from camelCase key
|
|
3209
|
+
*/
|
|
3210
|
+
declare const formatIssueTitle: (key: string) => string;
|
|
3211
|
+
/**
|
|
3212
|
+
* Calculate SEO scores based on issues
|
|
3213
|
+
*/
|
|
3214
|
+
declare const calculateScores: (issues: SeoAuditResult["issues"], rawData: any) => SeoAuditResult["scores"];
|
|
3215
|
+
|
|
3216
|
+
/**
|
|
3217
|
+
* Performance analysis utility functions
|
|
3218
|
+
* Pure functions for parsing and formatting - no API calls
|
|
3219
|
+
*
|
|
3220
|
+
* Source: framed-app/src/services/performanceService.ts (pure functions only)
|
|
3221
|
+
*/
|
|
3222
|
+
|
|
3223
|
+
interface PageSpeedResponse {
|
|
3224
|
+
lighthouseResult: {
|
|
3225
|
+
categories: {
|
|
3226
|
+
performance: {
|
|
3227
|
+
score: number;
|
|
3228
|
+
};
|
|
3229
|
+
accessibility: {
|
|
3230
|
+
score: number;
|
|
3231
|
+
};
|
|
3232
|
+
'best-practices': {
|
|
3233
|
+
score: number;
|
|
3234
|
+
};
|
|
3235
|
+
seo: {
|
|
3236
|
+
score: number;
|
|
3237
|
+
};
|
|
3238
|
+
};
|
|
3239
|
+
audits: Record<string, any>;
|
|
3240
|
+
lighthouseVersion: string;
|
|
3241
|
+
};
|
|
3242
|
+
analysisUTCTimestamp: string;
|
|
3243
|
+
}
|
|
3244
|
+
/**
|
|
3245
|
+
* Parse PageSpeed Insights response into our format
|
|
3246
|
+
*/
|
|
3247
|
+
declare const parsePageSpeedResponse: (data: PageSpeedResponse, url: string, strategy: "mobile" | "desktop") => PerformanceReport;
|
|
3248
|
+
/**
|
|
3249
|
+
* Format milliseconds to human-readable time
|
|
3250
|
+
*/
|
|
3251
|
+
declare const formatMs: (ms: number) => string;
|
|
3252
|
+
/**
|
|
3253
|
+
* Format bytes to human-readable size
|
|
3254
|
+
*/
|
|
3255
|
+
declare const formatBytes: (bytes: number) => string;
|
|
3256
|
+
/**
|
|
3257
|
+
* Get color class based on score
|
|
3258
|
+
*/
|
|
3259
|
+
declare const getScoreColor: (score: number) => string;
|
|
3260
|
+
/**
|
|
3261
|
+
* Get background color class based on score
|
|
3262
|
+
*/
|
|
3263
|
+
declare const getScoreBgColor: (score: number) => string;
|
|
3264
|
+
|
|
3265
|
+
/**
|
|
3266
|
+
* Generate instruction text for maintenance items
|
|
3267
|
+
*
|
|
3268
|
+
* Creates concise, AI-friendly instructions that can be copied to clipboard
|
|
3269
|
+
* for use with tools like Claude, Cursor, etc.
|
|
3270
|
+
*/
|
|
3271
|
+
|
|
3272
|
+
interface GenerateInstructionOptions {
|
|
3273
|
+
item: MaintenanceItem & {
|
|
3274
|
+
quote?: MaintenanceQuote;
|
|
3275
|
+
};
|
|
3276
|
+
projectName?: string;
|
|
3277
|
+
liveUrl?: string;
|
|
3278
|
+
}
|
|
3279
|
+
/**
|
|
3280
|
+
* Generate a short, copyable instruction for a maintenance item
|
|
3281
|
+
*/
|
|
3282
|
+
declare function generateItemInstruction({ item, projectName, liveUrl }: GenerateInstructionOptions): string;
|
|
3283
|
+
/**
|
|
3284
|
+
* Generate instruction for a page comment (Phase 4)
|
|
3285
|
+
*/
|
|
3286
|
+
interface PageCommentLike {
|
|
3287
|
+
comment: string;
|
|
3288
|
+
resolved?: boolean;
|
|
3289
|
+
element_text?: string;
|
|
3290
|
+
element_type?: string;
|
|
3291
|
+
user_name?: string;
|
|
3292
|
+
screenshot_type?: string;
|
|
3293
|
+
attachments?: unknown[];
|
|
3294
|
+
metadata?: {
|
|
3295
|
+
source?: string;
|
|
3296
|
+
originalContent?: string;
|
|
3297
|
+
newContent?: string;
|
|
3298
|
+
cssSelector?: string;
|
|
3299
|
+
pageUrl?: string;
|
|
3300
|
+
pagePath?: string;
|
|
3301
|
+
};
|
|
3302
|
+
}
|
|
3303
|
+
interface GenerateCommentInstructionOptions {
|
|
3304
|
+
comment: PageCommentLike;
|
|
3305
|
+
pageName?: string;
|
|
3306
|
+
projectName?: string;
|
|
3307
|
+
demoUrl?: string;
|
|
3308
|
+
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Generate a short, copyable instruction for a page comment (Phase 4)
|
|
3311
|
+
*/
|
|
3312
|
+
declare function generateCommentInstruction({ comment, pageName, projectName, demoUrl }: GenerateCommentInstructionOptions): string;
|
|
3313
|
+
|
|
3314
|
+
export { type AIConfig, type AIConversation, type AIConversationTurn, type AIFeatureResult, type AIQuestion, type AIToolConfig, type AIToolType, type AdditionalContentItem, type AdditionalContentType, type Agency, type Annotation, type AnnotationBody, type AnnotationData, type AnnotationMode, type AnnotationTarget, type ApiBackendDetails, type ApiEndpointConfig, type ApiStyle, type AppScreenConfig, type ApplyResolutionOptions, type Assignment, type Attachment, type AttachmentTranscription, type AuthConfig, type AuthMode, type BaseFeedItem, type BranchingRule, type BuildSpecData, type BuildSpecExport, type BuildSpecItem, type BuildSpecItemStatus, type BuildSpecSection, type CTAInfo, type ChangelogCategory, type ChangelogEntry, type Comment, type CommentAttachment, type ContentBlock, type ContentSection, type CrawledElementType, type CrawledTextElement, type CreateCommentOptions, type CredentialType, DATE_PRESETS, type DataFieldDefinition, type DataModelDefinition, type DataModelReference, type DataRelationship, type DatePreset, type DateRange, type DependencyRule, type DiffPart, type DomainCheckStatus, type DomainMonitor, type ElementHierarchy, type ElementInfo, type ElementMetadata, type EnhancedEcommerceDetails, type EnhancedPromptResponse, type ExportFormat, type ExportedChange, type FAQ, FEATURE_DEFAULTS, FEATURE_DESCRIPTIONS, FEATURE_NAMES, type FeedFilters, type FeedItem, type FeedStats, type FeedStatusFilter, type FeedTypeFilter, type FeedbackComment, type FeedbackFeedItem, type FeedbackInfo, type FeedbackRound, type FeedbackRoundSummary, type FlowStep, FramedApiClient, type FramedApiError, type FramedConfig, type GeneralComment, type GenerateCommentInstructionOptions, type GenerateInstructionOptions, type GlobalElements, type GlobalsSubType, type GroupedFeedItems, type HourPackage, type HourPackageStatus, type ImageComment, type ImageFeedItem, type ImageStatus, type ImportedBlockData, type ImportedContentData, type ImportedImageData, type ImportedPageData, type ImportedSectionData, type ImprovementSuggestion, type InternalNote, LANGUAGE_LABELS, type LanguageContent, type LanguageSettings, type LayoutOption, type LimitStatus, type LocalizableString, type LocalizedContent, MODULES, MODULE_PHASES, MONITORING_FEATURE_DESCRIPTIONS, MONITORING_FEATURE_NAMES, type MaintenanceActivity, type MaintenanceCategory, type MaintenanceComment, type MaintenanceCycle, type MaintenanceCycleSummary, type MaintenanceItem, type MaintenanceItemExtended, type MaintenanceItemStatus, type MaintenancePriority, type MaintenanceQuote, type MaintenanceStats, type MediaInfo, type Mention, type MobileAppDetails, type MobilePlatform, type ModuleInfo, type ModuleLimits, type ModuleType, type ModuleUsageStats, type MonthlyReport, type MonthlyReportData, PAGE_LAYOUTS, PHASE_TO_MODULE, PLAN_LIMITS, type PageComment, type PageCommentLike, type PageContent, type PageDetail, type PageImage, type PageInfo, type PageTextContent, type PageTypeLayouts, type PageVersion, type ParsedResolutionItem, type PendingAttachment, type PerformanceAudit, type PerformanceMetrics, type PerformanceOpportunity, type PerformanceReport, type Phase1Data, type Phase2Data, type Phase2NavigationActions, type Phase2NavigationState, type Phase3Data, type Phase4Data, type Phase4Page, type Phase5Data, type Phase5NotificationType, type PlanConfiguration, type PlanTier, type PlanType, type Position, type PricingTier, type Project, type ProjectCategory, type ProjectCategoryInfo, type ProjectContext, type ProjectContextFile, type ProjectData, type ProjectFeature, type ProjectMember, type ProjectMonitoringFeatures, type ProjectOverview, type ProjectPerformanceUsage, type ProjectShare, type ProjectStatus, type ProjectType, type QuestionCategory, type QuestionOption, type QuestionType, type QuoteStatus, type RecurringConfig, type Reference, type ResolutionImportResult, type ResolutionParseResult, type ResolutionStatus, type SDKConfig, type SaasCategory, type SaasDetails, type ScreenDefinition, type ScreenType, type ScreenshotInfo, type Section, type SectionStatus, type SectionSuggestion, type SectionSuggestionStatus, type SectionTypeData, type SeoAuditIssue, type SeoAuditResult, type SeoReport, type Session, type Stat, type StatusTransition, type StoredCredential, type SubscriptionStatus, type SuggestedPage, type SuggestionCategory, type SuggestionImpact, type SuggestionStatus, type SyncConfig, type SyncResult, type Task, type TaskComment, type TaskInfo, type TaskMeta, type TaskStatus, type TaskType, type TextChangesExport, type TextEdit, type TextEditFeedItem, type TimeEntry, type TranslationResult, type UploadMediaOptions, type UploadMediaResult, type UploadResult, type UptimeCheck, type UptimeIncident, type UptimeMonitor, type UsageLimits, type User, type UserFlowConfig, type UserPreferences, type UserRole, type ValidationRule, type ViewportMode, type WebsitePageConfig, type WidgetConfig, type WidgetDataLayer, type WidgetFeatures, type WidgetSession, type WidgetSessionCreate, type WidgetSessionValidation, type WidgetUIState, type WizardCallbacks, addLanguageContent, agencyHasMonitoringFeature, applyBlockEdit, applyListEdit, applyResolutions, calculateFeedStats, calculateRoundSummary, calculateScores, canAccessPhase, canApproveSuggestion, canConfigureModules, canCreateAgency, canCreateProject, canDeleteAgency, canDeleteProject, canDisablePhase, canEditProject, canInviteUsers, canLockPhase, canManageAgency, canManageProjectMembers, canManageTeam, canRemoveUser, canSetProjectLimit, canSubmitFeedback, canUnlockSoftLock, canUseAI, canViewProject, collectFeedItems, collectProjectMedia, computeTextDiff, countRoundStats, createComment, createEmptyLocalizedContent, createWizardCallbacks, deleteMedia, ensureLocalizedContent, exportTextChanges, extractMentions, filterFeedItems, formatBytes, formatDateRangeLabel, formatFileSize, formatIssueTitle, formatMentions, formatMs, formatRelativeTime, formatSubscriptionDate, generateCommentInstruction, generateItemInstruction, generateJSONExport, generateMinimalPhase1Data, generateNaturalLanguagePrompt, generatePageName, generatePlanningSection, generateProjectInstructionsMd, generateShortPrompt, getAccessiblePhases, getAllFeedbackIds, getAllProjectCategories, getAvailableFeatures, getAvailableLanguages, getAvailablePages, getBlockHistory, getCustomPages, getDaysRemaining, getDefaultModules, getDefaultPageName, getDefaultScreenType, getDisplayValue, getEffectiveProjectLimit, getEmptyDateRange, getFeaturesForTier, getFirstAccessiblePhase, getFirstVisiblePhase, getLanguageLabel, getLanguageSettings, getLayoutsForPage, getLocalizedValue, getModifiedCount, getModuleDescription, getModuleDisplayName, getModuleLimits, getModulePhasesLabel, getPageDisplayName, getPageStatus, getPages, getPlanBadgeColor, getPlanDisplayName, getProjectCategory, getProjectCategoryInfo, getRecentEdits, getRoleBadge, getRoleBadgeColor, getRoleDisplayName, getScoreBgColor, getScoreColor, getScreenDisplayName, getScreenTypeLabel, getScreens, getScreenshotUrl, getSectionStatus, getSeoCreditsInfo, getSubscriptionStatusBadgeColor, getSubscriptionStatusDisplayName, getTextContentLanguages, getTotalBlockCount, getUserSupabase, getVisiblePhases, groupFeedItemsByPage, hasAIContentGeneration, hasAdminPrivileges, hasEqualOrHigherRole, hasFeature, hasHigherRole, hasPerformanceAnalysis, hasRole, hasSeoAudit, initUserSupabase, isAdmin, isBlockModified, isClient, isDateRangeActive, isDefaultPage, isEcommerceProject, isFeedbackItem, isImageFeedItem, isLocalizedContent, isLocalizedFieldComplete, isManager, isModuleAvailable, isModuleEnabled, isModuleUnlimited, isModuleVisible, isPhaseAccessible, isPhaseDisabled, isPhaseVisible, isSoftLocked, isSubscriptionValid, isSupabaseInitialized, isSuperAdmin, isTextEditItem, isWebsiteBasedProject, isWithinDateRange, mergeFeatures, migratePhase1Data, migrateToLocalized, migrateToRounds, needsMigration, normalizeLocalizedField, parseApifyResults, parsePageSpeedResponse, parseResolutionReport, parseSitemapXML, projectHasMonitoringFeature, resetUserSupabase, restoreBlockToOriginal, shouldShowTraditionalWizard, str, toLocalizedContent, translateContent, updateLocalizedValue, uploadFile, uploadFont, uploadLogo, uploadMedia, useTranslation };
|