Files
turftracker/frontend/src/services/api.js
Jake Kasper dadc61209a disable rate
2025-08-26 06:42:41 -05:00

236 lines
9.8 KiB
JavaScript

import axios from 'axios';
import toast from 'react-hot-toast';
// Base API configuration
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';
// Create axios instance
const apiClient = axios.create({
baseURL: API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// Rate limiting disabled - unlimited requests
// let lastRequestTime = 0;
// const MIN_REQUEST_INTERVAL = 0; // No delay between requests
// Rate limiting interceptor disabled for unlimited requests
// apiClient.interceptors.request.use(async (config) => {
// return config;
// });
// Request interceptor to add auth token
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
console.log('Token from localStorage:', token);
if (token && token !== 'undefined' && token !== 'null') {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor for error handling
apiClient.interceptors.response.use(
(response) => response,
(error) => {
// Handle specific error codes
if (error.response?.status === 401 || error.response?.status === 403) {
// Unauthorized or malformed token - clear token and redirect to login
console.log('Clearing invalid token due to auth error:', error.response?.status);
localStorage.removeItem('authToken');
// Use React Router navigation instead of hard redirect
if (window.location.pathname !== '/login' && window.location.pathname !== '/register') {
window.location.href = '/login';
}
} else if (error.response?.status >= 500) {
// Server error
toast.error('Server error. Please try again later.');
} else if (error.code === 'ECONNABORTED') {
// Timeout
toast.error('Request timeout. Please check your connection.');
} else if (!error.response) {
// Network error
toast.error('Network error. Please check your connection.');
}
return Promise.reject(error);
}
);
// Auth API endpoints
export const authAPI = {
login: (credentials) => apiClient.post('/auth/login', credentials),
register: (userData) => apiClient.post('/auth/register', userData),
getCurrentUser: () => apiClient.get('/auth/me'),
changePassword: (passwordData) => apiClient.post('/auth/change-password', passwordData),
forgotPassword: (email) => apiClient.post('/auth/forgot-password', { email }),
};
// Users API endpoints
export const usersAPI = {
getProfile: () => apiClient.get('/users/profile'),
updateProfile: (userData) => apiClient.put('/users/profile', userData),
deleteAccount: () => apiClient.delete('/users/account'),
getStats: () => apiClient.get('/users/stats'),
};
// Properties API endpoints
export const propertiesAPI = {
getAll: () => apiClient.get('/properties'),
getById: (id) => apiClient.get(`/properties/${id}`),
create: (propertyData) => apiClient.post('/properties', propertyData),
update: (id, propertyData) => apiClient.put(`/properties/${id}`, propertyData),
delete: (id) => apiClient.delete(`/properties/${id}`),
// Lawn sections
createSection: (propertyId, sectionData) =>
apiClient.post(`/properties/${propertyId}/sections`, sectionData),
updateSection: (propertyId, sectionId, sectionData) =>
apiClient.put(`/properties/${propertyId}/sections/${sectionId}`, sectionData),
deleteSection: (propertyId, sectionId) =>
apiClient.delete(`/properties/${propertyId}/sections/${sectionId}`),
};
// Equipment API endpoints
export const equipmentAPI = {
getAll: (params) => apiClient.get('/equipment', { params }),
getById: (id) => apiClient.get(`/equipment/${id}`),
create: (equipmentData) => apiClient.post('/equipment', equipmentData),
update: (id, equipmentData) => apiClient.put(`/equipment/${id}`, equipmentData),
delete: (id) => apiClient.delete(`/equipment/${id}`),
getCategories: () => apiClient.get('/equipment/categories'),
getTypes: (params) => apiClient.get('/equipment/types', { params }),
getSpreaders: () => apiClient.get('/equipment/spreaders'), // Get user's spreader equipment
getCalculations: (id, params) => apiClient.get(`/equipment/${id}/calculations`, { params }),
};
// Nozzles API endpoints
export const nozzlesAPI = {
getAll: () => apiClient.get('/nozzles'),
getById: (id) => apiClient.get(`/nozzles/${id}`),
create: (nozzleData) => apiClient.post('/nozzles', nozzleData),
update: (id, nozzleData) => apiClient.put(`/nozzles/${id}`, nozzleData),
delete: (id) => apiClient.delete(`/nozzles/${id}`),
getNozzleTypes: () => apiClient.get('/nozzles/types'),
getUserNozzles: () => apiClient.get('/nozzles/user'),
calculateFlowRate: (nozzleId, pressure) => apiClient.get(`/nozzles/${nozzleId}/flow-rate`, { params: { pressure } }),
// Pump assignments
getPumpAssignments: (sprayerId) => apiClient.get(`/nozzles/sprayer/${sprayerId}/pump-assignments`),
assignPump: (sprayerId, pumpId) => apiClient.post(`/nozzles/sprayer/${sprayerId}/pump-assignments`, { pumpId }),
unassignPump: (assignmentId) => apiClient.delete(`/nozzles/pump-assignments/${assignmentId}`),
// Nozzle configurations
getNozzleConfigurations: (sprayerId) => apiClient.get(`/nozzles/sprayer/${sprayerId}/nozzle-configurations`),
addNozzleConfiguration: (sprayerId, configData) => apiClient.post(`/nozzles/sprayer/${sprayerId}/nozzle-configurations`, configData),
removeNozzleConfiguration: (configId) => apiClient.delete(`/nozzles/nozzle-configurations/${configId}`),
// Legacy endpoints for compatibility
getTypes: (params) => apiClient.get('/nozzles/types', { params }),
getAssignments: (equipmentId) => apiClient.get(`/nozzles/equipment/${equipmentId}/assignments`),
assignToEquipment: (equipmentId, assignmentData) => apiClient.post(`/nozzles/equipment/${equipmentId}/assignments`, assignmentData),
removeAssignment: (assignmentId) => apiClient.delete(`/nozzles/assignments/${assignmentId}`),
};
// Products API endpoints
export const productsAPI = {
getAll: (params) => apiClient.get('/products', { params }),
getById: (id) => apiClient.get(`/products/${id}`),
search: (params) => apiClient.get('/products/search', { params }),
getCategories: () => apiClient.get('/products/categories'),
// User products
getUserProducts: () => apiClient.get('/products/user'),
createUserProduct: (productData) => apiClient.post('/products/user', productData),
getUserProduct: (id) => apiClient.get(`/products/user/${id}`),
updateUserProduct: (id, productData) => apiClient.put(`/products/user/${id}`, productData),
deleteUserProduct: (id) => apiClient.delete(`/products/user/${id}`),
};
// Applications API endpoints
export const applicationsAPI = {
// Plans
getPlans: (params) => apiClient.get('/applications/plans', { params }),
getPlan: (id) => apiClient.get(`/applications/plans/${id}`),
createPlan: (planData) => apiClient.post('/applications/plans', planData),
updatePlan: (id, planData) => apiClient.put(`/applications/plans/${id}`, planData),
deletePlan: (id) => apiClient.delete(`/applications/plans/${id}`),
updatePlanStatus: (id, status) => apiClient.put(`/applications/plans/${id}/status`, { status }),
// Logs
getLogs: (params) => apiClient.get('/applications/logs', { params }),
createLog: (logData) => apiClient.post('/applications/logs', logData),
// Stats
getStats: (params) => apiClient.get('/applications/stats', { params }),
};
// Spreader Settings API endpoints
export const spreaderSettingsAPI = {
getAll: () => apiClient.get('/spreader-settings'),
getBrands: () => apiClient.get('/spreader-settings/brands'),
getByBrand: (brand) => apiClient.get(`/spreader-settings/${brand}`),
};
// Product Spreader Settings API endpoints
export const productSpreaderSettingsAPI = {
getByProduct: (productId) => apiClient.get(`/product-spreader-settings/product/${productId}`),
getByUserProduct: (userProductId) => apiClient.get(`/product-spreader-settings/user-product/${userProductId}`),
create: (settingData) => apiClient.post('/product-spreader-settings', settingData),
update: (id, settingData) => apiClient.put(`/product-spreader-settings/${id}`, settingData),
delete: (id) => apiClient.delete(`/product-spreader-settings/${id}`),
};
// Weather API endpoints
export const weatherAPI = {
getCurrent: (propertyId) => apiClient.get(`/weather/${propertyId}`),
getForecast: (propertyId) => apiClient.get(`/weather/${propertyId}/forecast`),
getHistory: (propertyId, params) => apiClient.get(`/weather/${propertyId}/history`, { params }),
checkSuitability: (propertyId, params) =>
apiClient.get(`/weather/conditions/suitable/${propertyId}`, { params }),
};
// Admin API endpoints
export const adminAPI = {
getDashboard: () => apiClient.get('/admin/dashboard'),
// Users management
getUsers: (params) => apiClient.get('/admin/users', { params }),
updateUserRole: (id, role) => apiClient.put(`/admin/users/${id}/role`, { role }),
deleteUser: (id) => apiClient.delete(`/admin/users/${id}`),
// Products management
getProducts: (params) => apiClient.get('/admin/products', { params }),
createProduct: (productData) => apiClient.post('/admin/products', productData),
updateProduct: (id, productData) => apiClient.put(`/admin/products/${id}`, productData),
deleteProduct: (id) => apiClient.delete(`/admin/products/${id}`),
// System health
getSystemHealth: () => apiClient.get('/admin/system/health'),
};
// Utility functions
export const handleApiError = (error, defaultMessage = 'An error occurred') => {
if (error.response?.data?.message) {
return error.response.data.message;
}
if (error.message) {
return error.message;
}
return defaultMessage;
};
export const formatApiResponse = (response) => {
return response.data;
};
// Export the configured axios instance for custom requests
export default apiClient;