Files
smoothschedule/frontend/src/hooks/useResources.ts
poduck 4cd6610f2a Fix double /api/ prefix in API endpoint calls
When VITE_API_URL=/api, axios baseURL is already set to /api. However, all endpoint calls included the /api/ prefix, creating double paths like /api/api/auth/login/.

Removed /api/ prefix from 81 API endpoint calls across 22 files:
- src/api/auth.ts - Fixed login, logout, me, refresh, hijack endpoints
- src/api/client.ts - Fixed token refresh endpoint
- src/api/profile.ts - Fixed all profile, email, password, MFA, sessions endpoints
- src/hooks/*.ts - Fixed all remaining API calls (users, appointments, resources, etc)
- src/pages/*.tsx - Fixed signup and email verification endpoints

This ensures API requests use the correct path: /api/auth/login/ instead of /api/api/auth/login/

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 15:27:57 -05:00

129 lines
3.5 KiB
TypeScript

/**
* Resource Management Hooks
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import apiClient from '../api/client';
import { Resource, ResourceType } from '../types';
interface ResourceFilters {
type?: ResourceType;
}
/**
* Hook to fetch resources with optional type filter
*/
export const useResources = (filters?: ResourceFilters) => {
return useQuery<Resource[]>({
queryKey: ['resources', filters],
queryFn: async () => {
const params = new URLSearchParams();
if (filters?.type) params.append('type', filters.type);
const { data } = await apiClient.get(`/resources/?${params}`);
// Transform backend format to frontend format
return data.map((r: any) => ({
id: String(r.id),
name: r.name,
type: r.type as ResourceType,
userId: r.user_id ? String(r.user_id) : undefined,
maxConcurrentEvents: r.max_concurrent_events ?? 1,
savedLaneCount: r.saved_lane_count,
}));
},
});
};
/**
* Hook to get a single resource
*/
export const useResource = (id: string) => {
return useQuery<Resource>({
queryKey: ['resources', id],
queryFn: async () => {
const { data } = await apiClient.get(`/resources/${id}/`);
return {
id: String(data.id),
name: data.name,
type: data.type as ResourceType,
userId: data.user_id ? String(data.user_id) : undefined,
maxConcurrentEvents: data.max_concurrent_events ?? 1,
savedLaneCount: data.saved_lane_count,
};
},
enabled: !!id,
});
};
/**
* Hook to create a resource
*/
export const useCreateResource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (resourceData: Omit<Resource, 'id'>) => {
const backendData = {
name: resourceData.name,
type: resourceData.type,
user: resourceData.userId ? parseInt(resourceData.userId) : null,
timezone: 'UTC', // Default timezone
};
const { data } = await apiClient.post('/resources/', backendData);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['resources'] });
},
});
};
/**
* Hook to update a resource
*/
export const useUpdateResource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ id, updates }: { id: string; updates: Partial<Resource> }) => {
const backendData: any = {};
if (updates.name) backendData.name = updates.name;
if (updates.type) backendData.type = updates.type;
if (updates.userId !== undefined) {
backendData.user = updates.userId ? parseInt(updates.userId) : null;
}
if (updates.maxConcurrentEvents !== undefined) {
backendData.max_concurrent_events = updates.maxConcurrentEvents;
}
if (updates.savedLaneCount !== undefined) {
backendData.saved_lane_count = updates.savedLaneCount;
}
const { data } = await apiClient.patch(`/resources/${id}/`, backendData);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['resources'] });
},
});
};
/**
* Hook to delete a resource
*/
export const useDeleteResource = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (id: string) => {
await apiClient.delete(`/resources/${id}/`);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['resources'] });
},
});
};