- Introduced a new service `igny8_site_builder` in `docker-compose.app.yml` for site building functionality, including environment variables and volume mappings. - Deleted several outdated scripts: `create_test_users.py`, `test_image_write_access.py`, `update_free_plan.py`, and the database file `db.sqlite3` to clean up the backend. - Updated Django settings and URL configurations to integrate the new site builder module.
157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
import { create } from 'zustand';
|
|
import { builderApi } from '../api/builder.api';
|
|
import type {
|
|
BuilderFormData,
|
|
PageBlueprint,
|
|
SiteBlueprint,
|
|
StylePreferences,
|
|
} from '../types/siteBuilder';
|
|
import { useSiteDefinitionStore } from './siteDefinitionStore';
|
|
|
|
const defaultStyle: StylePreferences = {
|
|
palette: 'Vibrant modern palette with rich accent color',
|
|
typography: 'Sans-serif display for headings, humanist body font',
|
|
personality: 'Confident, energetic, optimistic',
|
|
heroImagery: 'Real people interacting with the product/service',
|
|
};
|
|
|
|
const defaultForm: BuilderFormData = {
|
|
siteId: null,
|
|
sectorId: null,
|
|
siteName: '',
|
|
businessType: '',
|
|
industry: '',
|
|
targetAudience: '',
|
|
hostingType: 'igny8_sites',
|
|
businessBrief: '',
|
|
objectives: ['Launch a conversion-focused marketing site'],
|
|
style: defaultStyle,
|
|
};
|
|
|
|
interface BuilderState {
|
|
form: BuilderFormData;
|
|
currentStep: number;
|
|
isSubmitting: boolean;
|
|
error?: string;
|
|
activeBlueprint?: SiteBlueprint;
|
|
pages: PageBlueprint[];
|
|
setField: <K extends keyof BuilderFormData>(key: K, value: BuilderFormData[K]) => void;
|
|
updateStyle: (partial: Partial<StylePreferences>) => void;
|
|
addObjective: (value: string) => void;
|
|
removeObjective: (index: number) => void;
|
|
setStep: (step: number) => void;
|
|
nextStep: () => void;
|
|
previousStep: () => void;
|
|
reset: () => void;
|
|
submitWizard: () => Promise<void>;
|
|
refreshPages: (blueprintId: number) => Promise<void>;
|
|
}
|
|
|
|
export const useBuilderStore = create<BuilderState>((set, get) => ({
|
|
form: defaultForm,
|
|
currentStep: 0,
|
|
isSubmitting: false,
|
|
pages: [],
|
|
|
|
setField: (key, value) =>
|
|
set((state) => ({
|
|
form: { ...state.form, [key]: value },
|
|
})),
|
|
|
|
updateStyle: (partial) =>
|
|
set((state) => ({
|
|
form: { ...state.form, style: { ...state.form.style, ...partial } },
|
|
})),
|
|
|
|
addObjective: (value) =>
|
|
set((state) => ({
|
|
form: { ...state.form, objectives: [...state.form.objectives, value] },
|
|
})),
|
|
|
|
removeObjective: (index) =>
|
|
set((state) => ({
|
|
form: {
|
|
...state.form,
|
|
objectives: state.form.objectives.filter((_, idx) => idx !== index),
|
|
},
|
|
})),
|
|
|
|
setStep: (step) => set({ currentStep: step }),
|
|
|
|
nextStep: () =>
|
|
set((state) => ({
|
|
currentStep: Math.min(state.currentStep + 1, 3),
|
|
})),
|
|
|
|
previousStep: () =>
|
|
set((state) => ({
|
|
currentStep: Math.max(state.currentStep - 1, 0),
|
|
})),
|
|
|
|
reset: () =>
|
|
set({
|
|
form: defaultForm,
|
|
currentStep: 0,
|
|
isSubmitting: false,
|
|
error: undefined,
|
|
activeBlueprint: undefined,
|
|
pages: [],
|
|
}),
|
|
|
|
submitWizard: async () => {
|
|
const { form } = get();
|
|
if (!form.siteId || !form.sectorId) {
|
|
set({ error: 'Site and sector are required to generate a blueprint.' });
|
|
return;
|
|
}
|
|
|
|
set({ isSubmitting: true, error: undefined });
|
|
try {
|
|
const payload = {
|
|
name: form.siteName || `Site Blueprint (${form.industry || 'New'})`,
|
|
description: `${form.businessType} for ${form.targetAudience}`,
|
|
site_id: form.siteId,
|
|
sector_id: form.sectorId,
|
|
hosting_type: form.hostingType,
|
|
config_json: {
|
|
business_type: form.businessType,
|
|
industry: form.industry,
|
|
target_audience: form.targetAudience,
|
|
},
|
|
};
|
|
|
|
const blueprint = await builderApi.createBlueprint(payload);
|
|
set({ activeBlueprint: blueprint });
|
|
|
|
const generation = await builderApi.generateStructure(blueprint.id, {
|
|
business_brief: form.businessBrief,
|
|
objectives: form.objectives,
|
|
style: form.style,
|
|
metadata: { targetAudience: form.targetAudience },
|
|
});
|
|
|
|
if (generation?.structure) {
|
|
useSiteDefinitionStore.getState().setStructure(generation.structure);
|
|
}
|
|
|
|
await get().refreshPages(blueprint.id);
|
|
} catch (error) {
|
|
set({ error: error instanceof Error ? error.message : 'Unexpected error' });
|
|
} finally {
|
|
set({ isSubmitting: false });
|
|
}
|
|
},
|
|
|
|
refreshPages: async (blueprintId: number) => {
|
|
try {
|
|
const pages = await builderApi.listPages(blueprintId);
|
|
set({ pages });
|
|
useSiteDefinitionStore.getState().setPages(pages);
|
|
} catch (error) {
|
|
set({ error: error instanceof Error ? error.message : 'Unable to load pages' });
|
|
}
|
|
},
|
|
}));
|
|
|
|
|