Files
smoothschedule/frontend/src/hooks/useSites.ts
poduck 29bcb27e76 Add Puck site builder with preview and draft functionality
Frontend:
- Add comprehensive Puck component library (Layout, Content, Booking, Contact)
- Add Services component with usePublicServices hook integration
- Add 150+ icons to IconList component organized by category
- Add preview modal with viewport toggles (desktop/tablet/mobile)
- Add draft save/discard functionality with localStorage persistence
- Add draft status indicator in PageEditor toolbar
- Fix useSites hooks to use correct API URLs (/pages/{id}/)

Backend:
- Add SiteConfig model for theme, header, footer configuration
- Add Page SEO fields (meta_title, meta_description, og_image, etc.)
- Add puck_data validation for component structure
- Add create_missing_sites management command
- Fix PageViewSet to use EntitlementService for permissions
- Add comprehensive tests for site builder functionality

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 01:32:11 -05:00

122 lines
3.0 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import api from '../api/client';
export const useSite = () => {
return useQuery({
queryKey: ['site'],
queryFn: async () => {
const response = await api.get('/sites/me/');
return response.data;
},
});
};
export const usePages = () => {
return useQuery({
queryKey: ['pages'],
queryFn: async () => {
const response = await api.get('/sites/me/pages/');
return response.data;
},
});
};
export const usePage = (pageId: string) => {
return useQuery({
queryKey: ['page', pageId],
queryFn: async () => {
const response = await api.get(`/pages/${pageId}/`);
return response.data;
},
enabled: !!pageId,
});
};
export const useUpdatePage = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id, data }: { id: string; data: any }) => {
const response = await api.patch(`/pages/${id}/`, data);
return response.data;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({ queryKey: ['page', variables.id] });
queryClient.invalidateQueries({ queryKey: ['pages'] });
},
});
};
export const useCreatePage = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (data: { title: string; slug?: string; is_home?: boolean }) => {
const response = await api.post('/sites/me/pages/', data);
return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pages'] });
},
});
};
export const useDeletePage = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (id: string) => {
await api.delete(`/pages/${id}/`);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pages'] });
},
});
};
export const usePublicPage = () => {
return useQuery({
queryKey: ['publicPage'],
queryFn: async () => {
const response = await api.get('/public/page/');
return response.data;
},
retry: false,
});
};
export const useSiteConfig = () => {
return useQuery({
queryKey: ['siteConfig'],
queryFn: async () => {
const response = await api.get('/sites/me/config/');
return response.data;
},
});
};
export const useUpdateSiteConfig = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (data: {
theme?: Record<string, unknown>;
header?: Record<string, unknown>;
footer?: Record<string, unknown>;
}) => {
const response = await api.patch('/sites/me/config/', data);
return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['siteConfig'] });
},
});
};
export const usePublicSiteConfig = () => {
return useQuery({
queryKey: ['publicSiteConfig'],
queryFn: async () => {
const response = await api.get('/public/site-config/');
return response.data;
},
retry: false,
});
};