Skip to content

Mutations & Queries

PinTeach uses TanStack Query 5 for all server state management. The API client is a thin fetch wrapper in apps/app/src/lib/api.ts.

export const api = {
get: <T>(path: string) => apiRequest<T>(path),
post: <T>(path: string, body: unknown) =>
apiRequest<T>(path, { method: 'POST', body: JSON.stringify(body) }),
patch: <T>(path: string, body: unknown) =>
apiRequest<T>(path, { method: 'PATCH', body: JSON.stringify(body) }),
put: <T>(path: string, body: unknown) =>
apiRequest<T>(path, { method: 'PUT', body: JSON.stringify(body) }),
delete: <T>(path: string) =>
apiRequest<T>(path, { method: 'DELETE' }),
};
const { data, isLoading } = useQuery({
queryKey: ['teacher-sessions', teacherId],
queryFn: () => api.get<Session[]>('/teacher/sessions'),
});
Key Pattern Data
['teacher-sessions'] Session list
['teacher-calendar', start, end] Calendar events
['teacher-students'] Student list
['teacher-services'] Service list
['teacher-reviews'] Review list
['teacher-dashboard'] Dashboard KPIs
['teacher-payments'] Payment history
const mutation = useMutation({
mutationFn: (input: CreateInput) =>
api.post('/teacher/sessions', input),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['teacher-sessions'] });
toast.success(t('sessions.created'));
},
onError: () => toast.error(t('common.error')),
});

For frequent, low-risk actions, use useOptimisticMutation from hooks/mutations/:

import { useOptimisticMutation } from '@/hooks/mutations';
const mutation = useOptimisticMutation({
mutationFn: (id: string) =>
api.post(`/teacher/sessions/${id}/complete`),
queryKeys: [['teacher-sessions'], ['teacher-calendar']],
onOptimisticUpdate: ({ queryClient, snapshot }) => {
// Update cache immediately
},
});
  1. Cancel in-flight queries
  2. Create snapshot (createSnapshot)
  3. Apply optimistic cache update
  4. On error: rollback via restoreSnapshot
  5. On settle: invalidate all queryKeys
  • Complete session
  • Mark no-show
  • Toggle favorite
  • Move items (materials)
  • Reorder tags
  • Reorder categories
  • Submit mood
  • Read notification
  • Update review status
  • Bulk delete materials
  • Bulk tag materials

updateCalendarEvent prefix-matches ['teacher-calendar', ...] across date ranges for optimistic calendar updates.

Helper Purpose
createSnapshot(queryClient, queryKeys) Save current cache state
restoreSnapshot(queryClient, snapshot) Rollback to saved state
updateCalendarEvent(queryClient, ...) Update calendar cache entries