Enhance Site Builder Functionality and UI Components

- Added a new method to fetch blueprints from the API, improving data retrieval for site structures.
- Updated the WizardPage component to include a progress modal for better user feedback during site structure generation.
- Refactored state management in builderStore to track structure generation tasks, enhancing the overall user experience.
- Replaced SyncIcon with RefreshCw in integration components for a more consistent iconography.
- Improved the site structure generation prompt in utils.py to provide clearer instructions for AI-driven site architecture.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-18 15:25:34 +00:00
parent 040ba79621
commit 1ceeabed67
10 changed files with 302 additions and 14 deletions

View File

@@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Loader2, PlayCircle, RefreshCw } from 'lucide-react';
import { useBuilderStore } from '../../state/builderStore';
import { useSiteDefinitionStore } from '../../state/siteDefinitionStore';
@@ -7,6 +7,9 @@ import { BriefStep } from './steps/BriefStep';
import { ObjectivesStep } from './steps/ObjectivesStep';
import { StyleStep } from './steps/StyleStep';
import { Card } from '../../components/common/Card';
import { ProgressModal } from '../../components/common/ProgressModal';
import { useTaskProgress } from '../../hooks/useTaskProgress';
import { builderApi } from '../../api/builder.api';
const stepTitles = ['Business', 'Brief', 'Objectives', 'Style'];
@@ -26,8 +29,54 @@ export function WizardPage() {
error,
activeBlueprint,
refreshPages,
structureTaskId,
setStructureTaskId,
} = useBuilderStore();
const { structure } = useSiteDefinitionStore();
const structure = useSiteDefinitionStore((state) => state.structure);
const setStructure = useSiteDefinitionStore((state) => state.setStructure);
const [showProgressModal, setShowProgressModal] = useState(false);
const [progressMessage, setProgressMessage] = useState('Initializing Site Builder AI…');
const syncLatestStructure = useCallback(async () => {
if (!activeBlueprint) return;
try {
const latestBlueprint = await builderApi.getBlueprint(activeBlueprint.id);
if (latestBlueprint.structure_json) {
setStructure(latestBlueprint.structure_json);
}
await refreshPages(activeBlueprint.id);
} catch (syncError) {
const message = syncError instanceof Error ? syncError.message : 'Unable to sync blueprint';
useBuilderStore.setState({ error: message });
} finally {
setStructureTaskId(null);
}
}, [activeBlueprint, refreshPages, setStructure, setStructureTaskId]);
const taskProgress = useTaskProgress(structureTaskId, {
onUpdate: (meta) => {
if (meta?.message) {
setProgressMessage(meta.message);
}
},
onComplete: async () => {
setProgressMessage('Site structure ready!');
await syncLatestStructure();
setTimeout(() => setShowProgressModal(false), 500);
},
onError: (message) => {
useBuilderStore.setState({ error: message });
setShowProgressModal(false);
setStructureTaskId(null);
},
});
useEffect(() => {
if (structureTaskId) {
setShowProgressModal(true);
setProgressMessage('Sending request to Site Builder AI…');
}
}, [structureTaskId]);
const stepComponents = useMemo(
() => [
@@ -112,6 +161,23 @@ export function WizardPage() {
</div>
</Card>
)}
<ProgressModal
isOpen={showProgressModal}
onClose={() => {
if (taskProgress.status === 'processing') {
return;
}
setShowProgressModal(false);
setStructureTaskId(null);
}}
title="Generating site structure"
message={progressMessage}
progress={{
current: Math.round(taskProgress.percentage),
total: 100,
}}
taskId={structureTaskId || undefined}
/>
</div>
);
}

View File

@@ -17,6 +17,9 @@ describe('WizardPage', () => {
const mockAddObjective = vi.fn();
const mockRemoveObjective = vi.fn();
const mockSubmitWizard = vi.fn();
const mockSetStructureTaskId = vi.fn();
const mockRefreshPages = vi.fn();
const mockSetStructure = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
@@ -37,6 +40,7 @@ describe('WizardPage', () => {
isSubmitting: false,
error: undefined,
activeBlueprint: undefined,
structureTaskId: null,
setField: mockSetField,
nextStep: mockNextStep,
previousStep: mockPreviousStep,
@@ -45,10 +49,15 @@ describe('WizardPage', () => {
addObjective: mockAddObjective,
removeObjective: mockRemoveObjective,
submitWizard: mockSubmitWizard,
refreshPages: vi.fn(),
refreshPages: mockRefreshPages,
setStructureTaskId: mockSetStructureTaskId,
});
(useSiteDefinitionStore as any).mockReturnValue({
structure: undefined,
(useSiteDefinitionStore as any).mockImplementation((selector?: (state: any) => any) => {
const state = {
structure: undefined,
setStructure: mockSetStructure,
};
return selector ? selector(state) : state;
});
});
@@ -85,6 +94,7 @@ describe('WizardPage', () => {
isSubmitting: false,
error: undefined,
activeBlueprint: undefined,
structureTaskId: null,
setField: mockSetField,
nextStep: mockNextStep,
previousStep: mockPreviousStep,
@@ -93,7 +103,8 @@ describe('WizardPage', () => {
addObjective: mockAddObjective,
removeObjective: mockRemoveObjective,
submitWizard: mockSubmitWizard,
refreshPages: vi.fn(),
refreshPages: mockRefreshPages,
setStructureTaskId: mockSetStructureTaskId,
});
render(<WizardPage />);
@@ -112,6 +123,7 @@ describe('WizardPage', () => {
isSubmitting: false,
error: 'Test error message',
activeBlueprint: undefined,
structureTaskId: null,
setField: mockSetField,
nextStep: mockNextStep,
previousStep: mockPreviousStep,
@@ -120,7 +132,8 @@ describe('WizardPage', () => {
addObjective: mockAddObjective,
removeObjective: mockRemoveObjective,
submitWizard: mockSubmitWizard,
refreshPages: vi.fn(),
refreshPages: mockRefreshPages,
setStructureTaskId: mockSetStructureTaskId,
});
render(<WizardPage />);
@@ -151,6 +164,7 @@ describe('WizardPage', () => {
isSubmitting: true,
error: undefined,
activeBlueprint: undefined,
structureTaskId: null,
setField: mockSetField,
nextStep: mockNextStep,
previousStep: mockPreviousStep,
@@ -159,7 +173,8 @@ describe('WizardPage', () => {
addObjective: mockAddObjective,
removeObjective: mockRemoveObjective,
submitWizard: mockSubmitWizard,
refreshPages: vi.fn(),
refreshPages: mockRefreshPages,
setStructureTaskId: mockSetStructureTaskId,
});
render(<WizardPage />);