Fix build errors

This commit is contained in:
Dries Augustyns
2025-12-04 11:42:16 +01:00
parent 6fe3779fcb
commit fde00ebda3
10 changed files with 177 additions and 193 deletions
@@ -35,7 +35,6 @@ interface EmailEditorProps {
value: string; value: string;
onChange: (value: string) => void; onChange: (value: string) => void;
placeholder?: string; placeholder?: string;
canUploadImages?: boolean;
// Optional props for preview header // Optional props for preview header
subject?: string; subject?: string;
from?: string; from?: string;
@@ -119,6 +119,44 @@ const FilterRow = memo(function FilterRow({filter, onChange, onRemove, available
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
// Helper to get default value based on field type
const getDefaultValueForType = useCallback((type: string) => {
switch (type) {
case 'boolean':
return true;
case 'number':
return 0;
case 'date':
return '';
default:
return '';
}
}, []);
// Helper to get valid operators for a field type
const getOperatorsForType = useCallback((type: string, isEvent: boolean) => {
if (isEvent) {
return EVENT_OPERATORS;
}
if (type === 'boolean') {
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'exists', 'notExists'].includes(op.value)
);
}
if (type === 'number' || type === 'date') {
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual', 'exists', 'notExists', 'within'].includes(op.value)
);
}
// String type - no within operator, no comparison operators
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'contains', 'notContains', 'exists', 'notExists'].includes(op.value)
);
}, []);
const needsValue = !['exists', 'notExists', 'triggered', 'notTriggered'].includes(filter.operator); const needsValue = !['exists', 'notExists', 'triggered', 'notTriggered'].includes(filter.operator);
const needsUnit = ['within', 'triggeredWithin'].includes(filter.operator); const needsUnit = ['within', 'triggeredWithin'].includes(filter.operator);
@@ -208,45 +246,7 @@ const FilterRow = memo(function FilterRow({filter, onChange, onRemove, available
setOpen(false); setOpen(false);
setSearch(''); setSearch('');
}, [availableFields, filter.operator, fieldType, onChange]); }, [availableFields, filter.operator, fieldType, onChange, getDefaultValueForType, getOperatorsForType]);
// Helper to get default value based on field type
const getDefaultValueForType = useCallback((type: string) => {
switch (type) {
case 'boolean':
return true;
case 'number':
return 0;
case 'date':
return '';
default:
return '';
}
}, []);
// Helper to get valid operators for a field type
const getOperatorsForType = useCallback((type: string, isEvent: boolean) => {
if (isEvent) {
return EVENT_OPERATORS;
}
if (type === 'boolean') {
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'exists', 'notExists'].includes(op.value)
);
}
if (type === 'number' || type === 'date') {
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual', 'exists', 'notExists', 'within'].includes(op.value)
);
}
// String type - no within operator, no comparison operators
return STANDARD_OPERATORS.filter(op =>
['equals', 'notEquals', 'contains', 'notContains', 'exists', 'notExists'].includes(op.value)
);
}, []);
// Get label for selected field // Get label for selected field
const getFieldLabel = useCallback(() => { const getFieldLabel = useCallback(() => {
+12 -11
View File
@@ -334,6 +334,18 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const [stepToDelete, setStepToDelete] = useState<string | null>(null); const [stepToDelete, setStepToDelete] = useState<string | null>(null);
// Define handlers before they are used in useMemo
const handleEditStep = useCallback((stepId: string) => {
// This will be handled by the parent component
const event = new CustomEvent('workflow-edit-step', {detail: {stepId}});
window.dispatchEvent(event);
}, []);
const handleDeleteStepClick = useCallback((stepId: string) => {
setStepToDelete(stepId);
setShowDeleteDialog(true);
}, []);
// Convert workflow steps to React Flow nodes // Convert workflow steps to React Flow nodes
const rawNodes: Node[] = useMemo(() => { const rawNodes: Node[] = useMemo(() => {
@@ -622,17 +634,6 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
[addStepContext, workflowId, onUpdate], [addStepContext, workflowId, onUpdate],
); );
const handleEditStep = useCallback((stepId: string) => {
// This will be handled by the parent component
const event = new CustomEvent('workflow-edit-step', {detail: {stepId}});
window.dispatchEvent(event);
}, []);
const handleDeleteStepClick = useCallback((stepId: string) => {
setStepToDelete(stepId);
setShowDeleteDialog(true);
}, []);
// Get all steps that will be affected by deleting a step (the step itself + all downstream steps) // Get all steps that will be affected by deleting a step (the step itself + all downstream steps)
const getAffectedSteps = useCallback( const getAffectedSteps = useCallback(
(stepId: string): typeof steps => { (stepId: string): typeof steps => {
-4
View File
@@ -546,10 +546,6 @@ export default function CampaignDetailsPage() {
setHasChanges(true); setHasChanges(true);
}} }}
placeholder="<h1>Welcome!</h1><p>Your email content here...</p>" placeholder="<h1>Welcome!</h1><p>Your email content here...</p>"
canUploadImages={true}
subject={editedCampaign.subject}
from={editedCampaign.from}
replyTo={editedCampaign.replyTo || undefined}
/> />
</CardContent> </CardContent>
</Card> </Card>
-4
View File
@@ -195,10 +195,6 @@ export default function CreateCampaignPage() {
value={body} value={body}
onChange={setBody} onChange={setBody}
placeholder="<h1>Welcome!</h1><p>Your email content here...</p>" placeholder="<h1>Welcome!</h1><p>Your email content here...</p>"
canUploadImages={true}
subject={subject}
from={from}
replyTo={replyTo}
/> />
</div> </div>
</CardContent> </CardContent>
-4
View File
@@ -270,10 +270,6 @@ export default function TemplateEditorPage() {
value={editedTemplate.body || ''} value={editedTemplate.body || ''}
onChange={body => setEditedTemplate({...editedTemplate, body})} onChange={body => setEditedTemplate({...editedTemplate, body})}
placeholder="<h1>Welcome!</h1><p>Thanks for subscribing to our newsletter.</p>" placeholder="<h1>Welcome!</h1><p>Thanks for subscribing to our newsletter.</p>"
canUploadImages={true}
subject={editedTemplate.subject}
from={editedTemplate.from}
replyTo={editedTemplate.replyTo || undefined}
/> />
</CardContent> </CardContent>
</Card> </Card>
-4
View File
@@ -179,10 +179,6 @@ export default function CreateTemplatePage() {
value={body} value={body}
onChange={setBody} onChange={setBody}
placeholder="<h1>Welcome!</h1><p>Thanks for subscribing to our newsletter.</p>" placeholder="<h1>Welcome!</h1><p>Thanks for subscribing to our newsletter.</p>"
canUploadImages={true}
subject={subject}
from={from}
replyTo={replyTo}
/> />
</CardContent> </CardContent>
</Card> </Card>
+1 -1
View File
@@ -1,6 +1,6 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts"; import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+3 -3
View File
@@ -36,14 +36,14 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-neutral-200 bg-white p-4 sm:p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg max-h-[90vh] overflow-y-auto mx-4 sm:mx-0', 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-neutral-200 bg-white p-4 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg max-h-[90vh] overflow-y-auto',
className, className,
)} )}
{...props} {...props}
> >
{children} {children}
<DialogPrimitive.Close className="absolute right-3 top-3 sm:right-4 sm:top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 p-1 sm:p-0"> <DialogPrimitive.Close className="absolute right-2.5 top-2.5 sm:right-4 sm:top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 p-1 sm:p-1.5">
<X className="h-5 w-5 sm:h-4 sm:w-4" /> <X className="h-5 w-5 sm:h-5 sm:w-5" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>
</DialogPrimitive.Content> </DialogPrimitive.Content>