rate limiting
This commit is contained in:
@@ -23,6 +23,7 @@ const Applications = () => {
|
|||||||
const [nozzles, setNozzles] = useState([]);
|
const [nozzles, setNozzles] = useState([]);
|
||||||
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
||||||
const [editingPlan, setEditingPlan] = useState(null);
|
const [editingPlan, setEditingPlan] = useState(null);
|
||||||
|
const [propertyCache, setPropertyCache] = useState({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchApplications();
|
fetchApplications();
|
||||||
@@ -76,9 +77,18 @@ const Applications = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchPropertyDetails = async (propertyId) => {
|
const fetchPropertyDetails = async (propertyId) => {
|
||||||
|
// Check cache first
|
||||||
|
if (propertyCache[propertyId]) {
|
||||||
|
setSelectedPropertyDetails(propertyCache[propertyId]);
|
||||||
|
return propertyCache[propertyId];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await propertiesAPI.getById(parseInt(propertyId));
|
const response = await propertiesAPI.getById(parseInt(propertyId));
|
||||||
const property = response.data.data.property;
|
const property = response.data.data.property;
|
||||||
|
|
||||||
|
// Cache the result
|
||||||
|
setPropertyCache(prev => ({ ...prev, [propertyId]: property }));
|
||||||
setSelectedPropertyDetails(property);
|
setSelectedPropertyDetails(property);
|
||||||
return property;
|
return property;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -385,11 +395,8 @@ const ApplicationPlanModal = ({
|
|||||||
|
|
||||||
// Initialize form with editing data
|
// Initialize form with editing data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editingPlan) {
|
if (editingPlan && products.length > 0) {
|
||||||
const propertyId = editingPlan.section?.propertyId || editingPlan.property?.id;
|
const propertyId = editingPlan.section?.propertyId || editingPlan.property?.id;
|
||||||
if (propertyId && propertyId !== planData.propertyId) {
|
|
||||||
onPropertySelect(propertyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the product from the plans products array
|
// Find the product from the plans products array
|
||||||
const planProduct = editingPlan.products?.[0];
|
const planProduct = editingPlan.products?.[0];
|
||||||
@@ -413,12 +420,17 @@ const ApplicationPlanModal = ({
|
|||||||
plannedDate: editingPlan.plannedDate ? new Date(editingPlan.plannedDate).toISOString().split('T')[0] : '',
|
plannedDate: editingPlan.plannedDate ? new Date(editingPlan.plannedDate).toISOString().split('T')[0] : '',
|
||||||
notes: editingPlan.notes || ''
|
notes: editingPlan.notes || ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Only fetch property details if we don't already have them
|
||||||
|
if (propertyId && (!selectedPropertyDetails || selectedPropertyDetails.id !== propertyId)) {
|
||||||
|
onPropertySelect(propertyId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [editingPlan, products, onPropertySelect]);
|
}, [editingPlan, products]);
|
||||||
|
|
||||||
const handlePropertyChange = async (propertyId) => {
|
const handlePropertyChange = async (propertyId) => {
|
||||||
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
||||||
if (propertyId) {
|
if (propertyId && propertyId !== selectedPropertyDetails?.id?.toString()) {
|
||||||
setLoadingProperty(true);
|
setLoadingProperty(true);
|
||||||
await onPropertySelect(propertyId);
|
await onPropertySelect(propertyId);
|
||||||
setLoadingProperty(false);
|
setLoadingProperty(false);
|
||||||
|
|||||||
@@ -13,6 +13,24 @@ const apiClient = axios.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Rate limiting - simple queue to prevent excessive requests
|
||||||
|
let lastRequestTime = 0;
|
||||||
|
const MIN_REQUEST_INTERVAL = 100; // 100ms between requests
|
||||||
|
|
||||||
|
// Add rate limiting interceptor
|
||||||
|
apiClient.interceptors.request.use(async (config) => {
|
||||||
|
const now = Date.now();
|
||||||
|
const timeSinceLastRequest = now - lastRequestTime;
|
||||||
|
|
||||||
|
if (timeSinceLastRequest < MIN_REQUEST_INTERVAL) {
|
||||||
|
const delay = MIN_REQUEST_INTERVAL - timeSinceLastRequest;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastRequestTime = Date.now();
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
// Request interceptor to add auth token
|
// Request interceptor to add auth token
|
||||||
apiClient.interceptors.request.use(
|
apiClient.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user