236 lines
9.8 KiB
JavaScript
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; |