Boisson SolutionX
The client needed a site they could update on their own (hero, product cards, retailer and distributor calls to action) without the speed and theme limits of a classic WordPress build.
I built a headless setup. WordPress + ACF stays the editing tool, and a React/TypeScript single-page app pulls page content through WPGraphQL. The contact form uses a custom GraphQL mutation (createContactMessage, registered in functions.php) that cleans each input with sanitize_text_field and saves the message as a WordPress post.
Architecture: a layered client. Components call custom hooks (useHomePageData, useContactFormQuery), hooks call a service layer (homePageService) that uses one shared Axios instance, and GraphQL queries live in their own module. TanStack Query (useQuery/useMutation) manages server state, with a retry rule that never retries validation errors and retries network errors up to 3 times.
Best practices: strict TypeScript models for the GraphQL responses; typed error classes (GraphQLServiceError, NetworkError, ValidationError) that turn transport failures into clear outcomes; client-side form validation before sending, with loading and success/error states; ESLint with typescript-eslint, and Tailwind v4 through the Vite plugin.
Stack
- React
- TypeScript
- Vite
- Tailwind CSS
- TanStack Query
- Headless WordPress
- WPGraphQL
- ACF