refactor: enhance error handling and logging in API requests
This commit is contained in:
@@ -100,11 +100,25 @@ const createDevice = async (queryParams) => {
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('createDevice full response:', response);
|
||||
// Return full response with statusCode
|
||||
console.log('createDevice payload sent:', queryParams);
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [device_object] }
|
||||
// Check if response is empty array (error from SendRequest)
|
||||
if (Array.isArray(response) && response.length === 0) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
data: null,
|
||||
message: 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Extract first item from data array
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data,
|
||||
message: response.message
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
@@ -115,11 +129,25 @@ const updateDevice = async (device_id, queryParams) => {
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('updateDevice full response:', response);
|
||||
// Return full response with statusCode
|
||||
console.log('updateDevice payload sent:', queryParams);
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [device_object] }
|
||||
// Check if response is empty array (error from SendRequest)
|
||||
if (Array.isArray(response) && response.length === 0) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
data: null,
|
||||
message: 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Extract first item from data array
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data,
|
||||
message: response.message
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
@@ -129,11 +157,12 @@ const deleteDevice = async (queryParams) => {
|
||||
prefix: `device/${queryParams}`,
|
||||
});
|
||||
console.log('deleteDevice full response:', response);
|
||||
// Return full response with statusCode
|
||||
// Backend returns: { statusCode, message, rows: null, data: true }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data,
|
||||
message: response.message
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
178
src/api/master-plant-section.jsx
Normal file
178
src/api/master-plant-section.jsx
Normal file
@@ -0,0 +1,178 @@
|
||||
import { SendRequest } from '../components/Global/ApiRequest';
|
||||
|
||||
const getAllPlantSection = async (queryParams) => {
|
||||
try {
|
||||
const response = await SendRequest({
|
||||
method: 'get',
|
||||
prefix: `plant-sub-section?${queryParams.toString()}`,
|
||||
});
|
||||
console.log('getAllPlantSection response:', response);
|
||||
console.log('Query params:', queryParams.toString());
|
||||
|
||||
// Backend response structure:
|
||||
// {
|
||||
// statusCode: 200,
|
||||
// data: [...plantSections],
|
||||
// paging: {
|
||||
// current_page: 1,
|
||||
// current_limit: 10,
|
||||
// total_limit: 50,
|
||||
// total_page: 5
|
||||
// }
|
||||
// }
|
||||
|
||||
// Check if backend returns paginated data
|
||||
if (response.paging) {
|
||||
const totalData = response.data?.[0]?.total_data || response.rows || response.data?.length || 0;
|
||||
|
||||
return {
|
||||
status: response.statusCode || 200,
|
||||
data: {
|
||||
data: response.data || [],
|
||||
paging: {
|
||||
page: response.paging.current_page || 1,
|
||||
limit: response.paging.current_limit || 10,
|
||||
total: totalData,
|
||||
page_total: response.paging.total_page || Math.ceil(totalData / (response.paging.current_limit || 10))
|
||||
},
|
||||
total: totalData
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback: If backend returns all data without pagination (old behavior)
|
||||
const params = Object.fromEntries(queryParams);
|
||||
const currentPage = parseInt(params.page) || 1;
|
||||
const currentLimit = parseInt(params.limit) || 10;
|
||||
|
||||
const allData = response.data || [];
|
||||
const totalData = allData.length;
|
||||
|
||||
// Client-side pagination
|
||||
const startIndex = (currentPage - 1) * currentLimit;
|
||||
const endIndex = startIndex + currentLimit;
|
||||
const paginatedData = allData.slice(startIndex, endIndex);
|
||||
|
||||
return {
|
||||
status: response.statusCode || 200,
|
||||
data: {
|
||||
data: paginatedData,
|
||||
paging: {
|
||||
page: currentPage,
|
||||
limit: currentLimit,
|
||||
total: totalData,
|
||||
page_total: Math.ceil(totalData / currentLimit)
|
||||
},
|
||||
total: totalData
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('getAllPlantSection error:', error);
|
||||
return {
|
||||
status: 500,
|
||||
data: {
|
||||
data: [],
|
||||
paging: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
page_total: 0
|
||||
},
|
||||
total: 0
|
||||
},
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getPlantSectionById = async (id) => {
|
||||
const response = await SendRequest({
|
||||
method: 'get',
|
||||
prefix: `plant-sub-section/${id}`,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const createPlantSection = async (queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'post',
|
||||
prefix: `plant-sub-section`,
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('createPlantSection full response:', response);
|
||||
console.log('createPlantSection payload sent:', queryParams);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [plantSection_object] }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
const updatePlantSection = async (plant_section_id, queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'put',
|
||||
prefix: `plant-sub-section/${plant_section_id}`,
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('updatePlantSection full response:', response);
|
||||
console.log('updatePlantSection payload sent:', queryParams);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [plantSection_object] }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
const deletePlantSection = async (queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'delete',
|
||||
prefix: `plant-sub-section/${queryParams}`,
|
||||
});
|
||||
console.log('deletePlantSection full response:', response);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows: null, data: true }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
export { getAllPlantSection, getPlantSectionById, createPlantSection, updatePlantSection, deletePlantSection };
|
||||
185
src/api/master-tag.jsx
Normal file
185
src/api/master-tag.jsx
Normal file
@@ -0,0 +1,185 @@
|
||||
import { SendRequest } from '../components/Global/ApiRequest';
|
||||
|
||||
const getAllTag = async (queryParams) => {
|
||||
try {
|
||||
const response = await SendRequest({
|
||||
method: 'get',
|
||||
prefix: `tags?${queryParams.toString()}`,
|
||||
});
|
||||
console.log('getAllTag response:', response);
|
||||
console.log('Query params:', queryParams.toString());
|
||||
|
||||
// Check if response has error
|
||||
if (response.error) {
|
||||
console.error('getAllTag error response:', response);
|
||||
return {
|
||||
status: response.statusCode || 500,
|
||||
data: {
|
||||
data: [],
|
||||
paging: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
page_total: 0
|
||||
},
|
||||
total: 0
|
||||
},
|
||||
error: response.message
|
||||
};
|
||||
}
|
||||
|
||||
// Check if backend returns paginated data
|
||||
if (response.paging) {
|
||||
const totalData = response.data?.[0]?.total_data || response.rows || response.data?.length || 0;
|
||||
|
||||
return {
|
||||
status: response.statusCode || 200,
|
||||
data: {
|
||||
data: response.data || [],
|
||||
paging: {
|
||||
page: response.paging.current_page || 1,
|
||||
limit: response.paging.current_limit || 10,
|
||||
total: totalData,
|
||||
page_total: response.paging.total_page || Math.ceil(totalData / (response.paging.current_limit || 10))
|
||||
},
|
||||
total: totalData
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback: If backend returns all data without pagination (old behavior)
|
||||
const params = Object.fromEntries(queryParams);
|
||||
const currentPage = parseInt(params.page) || 1;
|
||||
const currentLimit = parseInt(params.limit) || 10;
|
||||
|
||||
const allData = response.data || [];
|
||||
const totalData = allData.length;
|
||||
|
||||
// Client-side pagination
|
||||
const startIndex = (currentPage - 1) * currentLimit;
|
||||
const endIndex = startIndex + currentLimit;
|
||||
const paginatedData = allData.slice(startIndex, endIndex);
|
||||
|
||||
return {
|
||||
status: response.statusCode || 200,
|
||||
data: {
|
||||
data: paginatedData,
|
||||
paging: {
|
||||
page: currentPage,
|
||||
limit: currentLimit,
|
||||
total: totalData,
|
||||
page_total: Math.ceil(totalData / currentLimit)
|
||||
},
|
||||
total: totalData
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('getAllTag catch error:', error);
|
||||
return {
|
||||
status: 500,
|
||||
data: {
|
||||
data: [],
|
||||
paging: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
page_total: 0
|
||||
},
|
||||
total: 0
|
||||
},
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getTagById = async (id) => {
|
||||
const response = await SendRequest({
|
||||
method: 'get',
|
||||
prefix: `tags/${id}`,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const createTag = async (queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'post',
|
||||
prefix: `tags`,
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('createTag full response:', response);
|
||||
console.log('createTag payload sent:', queryParams);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [tag_object] }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
const updateTag = async (tag_id, queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'put',
|
||||
prefix: `tags/${tag_id}`,
|
||||
params: queryParams,
|
||||
});
|
||||
console.log('updateTag full response:', response);
|
||||
console.log('updateTag payload sent:', queryParams);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows, data: [tag_object] }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data?.[0] || response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
const deleteTag = async (queryParams) => {
|
||||
const response = await SendRequest({
|
||||
method: 'delete',
|
||||
prefix: `tags/${queryParams}`,
|
||||
});
|
||||
console.log('deleteTag full response:', response);
|
||||
|
||||
// Check if response has error flag
|
||||
if (response.error) {
|
||||
return {
|
||||
statusCode: response.statusCode || 500,
|
||||
data: null,
|
||||
message: response.message || 'Request failed',
|
||||
rows: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Backend returns: { statusCode, message, rows: null, data: true }
|
||||
return {
|
||||
statusCode: response.statusCode || 200,
|
||||
data: response.data,
|
||||
message: response.message,
|
||||
rows: response.rows
|
||||
};
|
||||
};
|
||||
|
||||
export { getAllTag, getTagById, createTag, updateTag, deleteTag };
|
||||
@@ -20,6 +20,13 @@ instance.interceptors.response.use(
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
|
||||
console.error("🚨 Response Error Interceptor:", {
|
||||
status: error.response?.status,
|
||||
url: originalRequest.url,
|
||||
message: error.response?.data?.message,
|
||||
hasRetried: originalRequest._retry
|
||||
});
|
||||
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
@@ -29,14 +36,16 @@ instance.interceptors.response.use(
|
||||
|
||||
const newAccessToken = refreshRes.data.data.accessToken;
|
||||
localStorage.setItem("token", newAccessToken);
|
||||
console.log("✅ Token refreshed successfully");
|
||||
|
||||
// update token di header
|
||||
instance.defaults.headers.common["Authorization"] = `Bearer ${newAccessToken}`;
|
||||
originalRequest.headers["Authorization"] = `Bearer ${newAccessToken}`;
|
||||
|
||||
console.log("🔁 Retrying original request...");
|
||||
return instance(originalRequest);
|
||||
} catch (refreshError) {
|
||||
console.error("Refresh token gagal:", refreshError);
|
||||
console.error("❌ Refresh token gagal:", refreshError.response?.data || refreshError.message);
|
||||
localStorage.clear();
|
||||
window.location.href = "/signin";
|
||||
}
|
||||
@@ -66,15 +75,28 @@ async function ApiRequest({
|
||||
|
||||
const rawToken = localStorage.getItem("token");
|
||||
if (token && rawToken) {
|
||||
request.headers["Authorization"] = `Bearer ${rawToken.replace(/"/g, "")}`;
|
||||
const cleanToken = rawToken.replace(/"/g, "");
|
||||
request.headers["Authorization"] = `Bearer ${cleanToken}`;
|
||||
console.log("🔐 Sending request with token:", cleanToken.substring(0, 20) + "...");
|
||||
} else {
|
||||
console.warn("⚠️ No token found in localStorage");
|
||||
}
|
||||
|
||||
console.log("📤 API Request:", { method, url: prefix, hasToken: !!rawToken });
|
||||
|
||||
try {
|
||||
const response = await instance(request);
|
||||
console.log("✅ API Response:", { url: prefix, status: response.status, statusCode: response.data?.statusCode });
|
||||
return { ...response, error: false };
|
||||
} catch (error) {
|
||||
const status = error?.response?.status || 500;
|
||||
const message = error?.response?.data?.message || error.message || "Something Wrong";
|
||||
console.error("❌ API Error:", {
|
||||
url: prefix,
|
||||
status,
|
||||
message,
|
||||
fullError: error?.response?.data
|
||||
});
|
||||
|
||||
if (status !== 401) {
|
||||
await cekError(status, message);
|
||||
@@ -109,14 +131,39 @@ async function cekError(status, message = "") {
|
||||
const SendRequest = async (queryParams) => {
|
||||
try {
|
||||
const response = await ApiRequest(queryParams);
|
||||
return response?.data || [];
|
||||
} catch (error) {
|
||||
console.error("Request error:", error);
|
||||
await Swal.fire({
|
||||
icon: "error",
|
||||
text: error.message || "Something went wrong",
|
||||
console.log("📦 SendRequest response:", {
|
||||
hasError: response.error,
|
||||
status: response.status,
|
||||
statusCode: response.data?.statusCode,
|
||||
data: response.data
|
||||
});
|
||||
return [];
|
||||
|
||||
// If ApiRequest returned error flag, return error structure
|
||||
if (response.error) {
|
||||
const errorMsg = response.data?.message || response.statusText || "Request failed";
|
||||
console.error("❌ SendRequest error response:", errorMsg);
|
||||
|
||||
// Return consistent error structure instead of empty array
|
||||
return {
|
||||
statusCode: response.status || 500,
|
||||
message: errorMsg,
|
||||
data: null,
|
||||
error: true
|
||||
};
|
||||
}
|
||||
|
||||
return response?.data || { statusCode: 200, data: [], message: "Success" };
|
||||
} catch (error) {
|
||||
console.error("❌ SendRequest catch error:", error);
|
||||
|
||||
// Don't show Swal here, let the calling code handle it
|
||||
// This allows better error handling in each API call
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: error.message || "Something went wrong",
|
||||
data: null,
|
||||
error: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user