State & Query Management
State & Query Management
The Japanese ATS leverages a modern state management architecture to ensure data integrity, responsive UI updates, and efficient server synchronization. The system separates concerns between Server State (managed by TanStack Query) and Form State (managed by React Hook Form).
Server State with TanStack Query
The application utilizes TanStack Query (React Query) to handle asynchronous data fetching, caching, and synchronization with the Supabase backend. This approach reduces boilerplate code and provides built-in support for loading states and error handling.
Global Configuration
The QueryClient is initialized at the root level in App.tsx, providing a centralized cache for all application data.
// src/App.tsx
const queryClient = new QueryClient();
const App = () => (
<QueryClientProvider client={queryClient}>
{/* Application Routes */}
</QueryClientProvider>
);
Usage in Admin Modules
Admin pages, such as the Dashboard and Applicant Details, interact with the Supabase client to retrieve records. While some components utilize standard React lifecycle hooks, the architecture is designed to support query-based fetching for optimized performance and automatic background refetching.
Form Management & Client-Side Validation
For complex data entry, such as the applicant submission form, the project uses React Hook Form paired with Zod for schema-based validation. This ensures that only valid data is sent to the database.
Applicant Form Schema
The validation logic is centralized in a Zod schema, defining strict rules for user input, including file size constraints for resume uploads.
| Field | Validation Rule |
| :--- | :--- |
| fullName | String, 2-100 characters |
| email | Valid email format, max 255 characters |
| yearsOfExperience | Number, range 0 to 50 |
| highestDegree | Required selection |
| preferredCourse | Required selection |
| cvFile | PDF format only, maximum 5MB |
Implementation Example
The Index.tsx page implements the application form using the useForm hook. It handles both the structured text data and the binary file upload to Supabase Storage.
const formSchema = z.object({
fullName: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email address"),
// ... other fields
});
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
const onSubmit = async (data: FormData) => {
// Logic for CV upload and Database insertion
};
Persistence and Type Safety
The application's state is strictly typed using generated Supabase types, ensuring that the frontend state always aligns with the database schema.
- Type Definitions: Located in
src/integrations/supabase/types.ts. - Database Interactions: The
supabaseclient is used directly within hooks and components to perform CRUD operations, ensuring that the application remains lightweight without the need for a heavy global state library like Redux.
User Feedback (Toasts)
State transitions (such as "Submitting", "Success", or "Error") are communicated to the user through the sonner and shadcn-ui/toaster libraries. These are triggered during the mutation lifecycle to provide real-time feedback.
try {
// perform action
toast.success("Application submitted successfully!");
} catch (error) {
toast.error("Failed to submit application");
}