From 4bd0348a2ab95da232dd3e610d658017e5a01c08 Mon Sep 17 00:00:00 2001 From: Fachba Date: Tue, 21 Oct 2025 20:26:05 +0700 Subject: [PATCH] clean code master plant sub section and master device --- .env.example | 3 +- src/Utils/validate.js | 71 +++ src/api/dashboard-home.jsx | 48 -- src/api/jadwal-shift.jsx | 70 ++- src/api/master-apd.jsx | 45 -- src/api/master-brand.jsx | 117 +---- src/api/master-device.jsx | 147 +----- src/api/master-plant-section.jsx | 171 +------ src/api/master-shift.jsx | 153 +----- src/api/master-status.jsx | 148 +----- src/api/master-tag.jsx | 154 +----- src/api/master-unit.jsx | 177 +------ src/api/role.jsx | 164 +------ src/api/user-admin.jsx | 51 +- src/api/user.jsx | 169 ++----- src/components/Global/ApiRequest.jsx | 271 +++++----- src/components/Global/CardList.jsx | 2 +- src/components/Global/TableList.jsx | 79 +-- src/components/Global/ToastNotif.jsx | 1 + src/pages/auth/Registration.jsx | 461 ------------------ src/pages/auth/SignIn.jsx | 9 +- .../brandDevice/component/ListBrandDevice.jsx | 52 +- .../master/device/component/DetailDevice.jsx | 278 ++--------- .../component/DetailPlantSection.jsx | 140 ++---- 24 files changed, 521 insertions(+), 2460 deletions(-) create mode 100644 src/Utils/validate.js delete mode 100644 src/api/dashboard-home.jsx delete mode 100644 src/api/master-apd.jsx delete mode 100644 src/pages/auth/Registration.jsx diff --git a/.env.example b/.env.example index 62bd0b8..914aa0c 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ -VITE_API_SERVER=http://36.66.16.49:9528/api +VITE_API_SERVER=http://localhost:9530/api +# VITE_API_SERVER=https://117.102.231.130:9528/api VITE_MQTT_SERVER=ws://localhost:1884 VITE_MQTT_USERNAME= VITE_MQTT_PASSWORD= diff --git a/src/Utils/validate.js b/src/Utils/validate.js new file mode 100644 index 0000000..8e6012f --- /dev/null +++ b/src/Utils/validate.js @@ -0,0 +1,71 @@ +// utils/validate.js + +// Daftar aturan validasi +const validationRules = [ + { field: 'name', label: 'Nama', required: true }, + { + field: 'email', + label: 'Email', + required: true, + pattern: /\S+@\S+\.\S+/, + patternMessage: 'Format email tidak valid', + }, + { + field: 'age', + label: 'Umur', + required: true, + validator: (v) => !isNaN(v) && Number(v) >= 18, + message: 'Umur harus angka dan minimal 18 tahun', + }, +]; + +/** + * Fungsi validasi dinamis berbasis array objek aturan. + * @param {Object} data - data form (misal { name: '', email: '' }) + * @param {Array} rules - array aturan validasi + * @returns {Object} errors - object berisi pesan error per field + */ + +export const validateRun = (data, rules, onError) => { + const errors = {}; + const messages = []; + + const ipRegex = /^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/; + + rules.forEach((rule) => { + const value = data[rule.field]?.toString().trim(); + const fieldErrors = []; + + if (rule.required && !value) { + fieldErrors.push(`${rule.label} wajib diisi`); + } + + // ✅ IP Address check + if (rule.ip && value && !ipRegex.test(value)) { + fieldErrors.push(`${rule.label} harus berupa alamat IP yang valid`); + } + + if (rule.pattern && value && !rule.pattern.test(value)) { + fieldErrors.push(rule.patternMessage || `${rule.label} tidak valid`); + } + + if (rule.validator && value && !rule.validator(value)) { + fieldErrors.push(rule.message || `${rule.label} tidak valid`); + } + + // Gabungkan error satu field jadi satu string (pisah baris) + if (fieldErrors.length > 0) { + errors[rule.field] = fieldErrors.join("\n"); + messages.push(...fieldErrors); + } + }); + + // Jika ada error total, tampilkan callback dan return false + + if (messages.length > 0) { + if (onError) onError(messages.join("\n")); + return true; + } + return false + +}; \ No newline at end of file diff --git a/src/api/dashboard-home.jsx b/src/api/dashboard-home.jsx deleted file mode 100644 index 6f14ea0..0000000 --- a/src/api/dashboard-home.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { SendRequest } from '../components/Global/ApiRequest'; - -const getTotal = async (query = '') => { - const prefix = `${query ? `?${query}` : ''}`; - const fullUrl = `${import.meta.env.VITE_API_SERVER}/dashboard/${prefix}`; - try { - const response = await SendRequest({ - method: 'get', - prefix: `dashboard/${prefix}`, - }); - return response; - } catch (error) { - console.error(`[API Call] Failed: GET ${fullUrl}`, error); - throw error; - } -}; - -const getTotalPermit = async (query = '') => { - const prefix = `dashboard/permit-total${query ? `?${query}` : ''}`; - const fullUrl = `${import.meta.env.VITE_API_SERVER}/${prefix}`; - try { - const response = await SendRequest({ - method: 'get', - prefix, - }); - return response; - } catch (error) { - console.error(`[API Call] Failed: GET ${fullUrl}`, error); - throw error; - } -}; - -const getTotalPermitPerYear = async (query = '') => { - const prefix = `dashboard/permit-breakdown${query ? `?${query}` : ''}`; - const fullUrl = `${import.meta.env.VITE_API_SERVER}/${prefix}`; - try { - const response = await SendRequest({ - method: 'get', - prefix, - }); - return response; - } catch (error) { - console.error(`[API Call] Failed: GET ${fullUrl}`, error); - throw error; - } -}; - -export { getTotal, getTotalPermit, getTotalPermitPerYear }; \ No newline at end of file diff --git a/src/api/jadwal-shift.jsx b/src/api/jadwal-shift.jsx index 2ae403a..ce221b3 100644 --- a/src/api/jadwal-shift.jsx +++ b/src/api/jadwal-shift.jsx @@ -1,55 +1,41 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllJadwalShift = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `jadwal-shift?${queryParams.toString()}`, - }); - return response; - } catch (error) { - console.error('getAllJadwalShift error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + const response = await SendRequest({ + method: 'get', + prefix: `jadwal-shift?${queryParams.toString()}`, + }); + + return response.data; +}; + +const getJadwalShiftById = async (id) => { + const response = await SendRequest({ + method: 'get', + prefix: `jadwal-shift/${id}`, + }); + + return response.data; }; const createJadwalShift = async (queryParams) => { const response = await SendRequest({ method: 'post', prefix: `jadwal-shift`, - data: queryParams, + params: queryParams, }); - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const updateJadwalShift = async (id, queryParams) => { const response = await SendRequest({ method: 'put', prefix: `jadwal-shift/${id}`, - data: queryParams, + params: queryParams, }); - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const deleteJadwalShift = async (id) => { @@ -57,11 +43,13 @@ const deleteJadwalShift = async (id) => { method: 'delete', prefix: `jadwal-shift/${id}`, }); - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + return response.data; }; -export { getAllJadwalShift, createJadwalShift, updateJadwalShift, deleteJadwalShift }; +export { + getAllJadwalShift, + getJadwalShiftById, + createJadwalShift, + updateJadwalShift, + deleteJadwalShift, +}; diff --git a/src/api/master-apd.jsx b/src/api/master-apd.jsx deleted file mode 100644 index c39c14a..0000000 --- a/src/api/master-apd.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { SendRequest } from '../components/Global/ApiRequest'; - -const getAllApd = async (queryParams) => { - const response = await SendRequest({ - method: 'get', - prefix: `apd?${queryParams.toString()}`, - }); - return response; -}; - -const createApd = async (queryParams) => { - const response = await SendRequest({ - method: 'post', - prefix: `apd`, - params: queryParams, - }); - return response.data; -}; - -const updateApd = async (vendor_id, queryParams) => { - const response = await SendRequest({ - method: 'put', - prefix: `apd/${vendor_id}`, - params: queryParams, - }); - return response.data; -}; - -const deleteApd = async (queryParams) => { - const response = await SendRequest({ - method: 'delete', - prefix: `apd/${queryParams}`, - }); - return response.data; -}; - -const getJenisPermit = async () => { - const response = await SendRequest({ - method: 'get', - prefix: `apd/jenis-permit`, - }); - return response.data; -}; - -export { getAllApd, createApd, updateApd, deleteApd, getJenisPermit }; diff --git a/src/api/master-brand.jsx b/src/api/master-brand.jsx index e68b2bb..942e4e3 100644 --- a/src/api/master-brand.jsx +++ b/src/api/master-brand.jsx @@ -1,70 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllBrands = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `brand?${queryParams.toString()}`, - }); - if (response.paging) { - const totalData = response.data?.[0]?.total_data || response.rows || response.data?.length || 0; + const response = await SendRequest({ + method: 'get', + prefix: `brand?${queryParams.toString()}`, + }); - 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 - } - }; - } - - 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; - - 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('getAllBrands error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getBrandById = async (id) => { @@ -72,6 +14,7 @@ const getBrandById = async (id) => { method: 'get', prefix: `brand/${id}`, }); + return response.data; }; @@ -81,55 +24,27 @@ const createBrand = async (queryParams) => { prefix: `brand`, params: queryParams, }); - if (Array.isArray(response) && response.length === 0) { - return { - statusCode: 500, - data: null, - message: 'Request failed', - rows: 0 - }; - } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + + return response.data; }; -const updateBrand = async (brand_id, queryParams) => { +const updateBrand = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `brand/${brand_id}`, + prefix: `brand/${id}`, params: queryParams, }); - if (Array.isArray(response) && response.length === 0) { - return { - statusCode: 500, - data: null, - message: 'Request failed', - rows: 0 - }; - } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + + return response.data; }; -const deleteBrand = async (queryParams) => { +const deleteBrand = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `brand/${queryParams}`, + prefix: `brand/${id}`, }); - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message, - rows: response.rows - }; + + return response.data; }; export { getAllBrands, getBrandById, createBrand, updateBrand, deleteBrand }; diff --git a/src/api/master-device.jsx b/src/api/master-device.jsx index 9493cc8..e1b7315 100644 --- a/src/api/master-device.jsx +++ b/src/api/master-device.jsx @@ -1,88 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllDevice = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `device?${queryParams.toString()}`, - }); - console.log('getAllDevice response:', response); - console.log('Query params:', queryParams.toString()); + const response = await SendRequest({ + method: 'get', + prefix: `device?${queryParams.toString()}`, + }); - // Backend response structure: - // { - // statusCode: 200, - // data: [...devices], - // 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('getAllDevice error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getDeviceById = async (id) => { @@ -90,6 +14,7 @@ const getDeviceById = async (id) => { method: 'get', prefix: `device/${id}`, }); + return response.data; }; @@ -99,71 +24,27 @@ const createDevice = async (queryParams) => { prefix: `device`, params: queryParams, }); - console.log('createDevice full response:', response); - 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?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const updateDevice = async (device_id, queryParams) => { +const updateDevice = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `device/${device_id}`, + prefix: `device/${id}`, params: queryParams, }); - console.log('updateDevice full response:', response); - 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?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const deleteDevice = async (queryParams) => { +const deleteDevice = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `device/${queryParams}`, + prefix: `device/${id}`, }); - console.log('deleteDevice full response:', response); - // Backend returns: { statusCode, message, rows: null, data: true } - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message, - rows: response.rows - }; + + return response.data; }; export { getAllDevice, getDeviceById, createDevice, updateDevice, deleteDevice }; diff --git a/src/api/master-plant-section.jsx b/src/api/master-plant-section.jsx index 594723b..790cf89 100644 --- a/src/api/master-plant-section.jsx +++ b/src/api/master-plant-section.jsx @@ -1,97 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllPlantSection = async (queryParams) => { - try { - // Ensure queryParams is URLSearchParams object - const params = queryParams instanceof URLSearchParams ? queryParams : new URLSearchParams(queryParams); + const response = await SendRequest({ + method: 'get', + prefix: `plant-sub-section?${queryParams.toString()}`, + }); - const response = await SendRequest({ - method: 'get', - prefix: `plant-sub-section?${params.toString()}`, - }); - console.log('getAllPlantSection response:', response); - console.log('Query params:', params.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) { - // Extract total_data from first record, or fallback to total_limit or rows - const totalData = response.data?.[0]?.total_data || response.paging.total_limit || response.rows || response.data?.length || 0; - - // Use total_limit as total count, handle 0 values for page/limit - const currentPage = response.paging.current_page || 1; - const currentLimit = response.paging.current_limit || 10; - const totalPages = response.paging.total_page || Math.ceil(totalData / currentLimit); - - return { - status: response.statusCode || 200, - data: { - data: response.data || [], - paging: { - page: currentPage, - limit: currentLimit, - total: totalData, - page_total: totalPages - }, - total: totalData - } - }; - } - - // Fallback: If backend returns all data without pagination (old behavior) - const parsedParams = Object.fromEntries(params); - const currentPage = parseInt(parsedParams.page) || 1; - const currentLimit = parseInt(parsedParams.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 - }; - } + return response.data; }; const getPlantSectionById = async (id) => { @@ -99,6 +14,7 @@ const getPlantSectionById = async (id) => { method: 'get', prefix: `plant-sub-section/${id}`, }); + return response.data; }; @@ -108,80 +24,33 @@ const createPlantSection = async (queryParams) => { 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 - }; + return response.data; }; -const updatePlantSection = async (plant_section_id, queryParams) => { +const updatePlantSection = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `plant-sub-section/${plant_section_id}`, + prefix: `plant-sub-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 - }; + return response.data; }; -const deletePlantSection = async (queryParams) => { +const deletePlantSection = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `plant-sub-section/${queryParams}`, + prefix: `plant-sub-section/${id}`, }); - 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 - }; + return response.data; }; -export { getAllPlantSection, getPlantSectionById, createPlantSection, updatePlantSection, deletePlantSection }; +export { + getAllPlantSection, + getPlantSectionById, + createPlantSection, + updatePlantSection, + deletePlantSection, +}; diff --git a/src/api/master-shift.jsx b/src/api/master-shift.jsx index a4d7fee..9807dc5 100644 --- a/src/api/master-shift.jsx +++ b/src/api/master-shift.jsx @@ -1,95 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllShift = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `shift?${queryParams.toString()}`, - }); - console.log('getAllShift response:', response); - console.log('Query params:', queryParams.toString()); + const response = await SendRequest({ + method: 'get', + prefix: `shift?${queryParams.toString()}`, + }); - // Check if response has error - if (response.error) { - console.error('getAllShift 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 - 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('getAllShift catch error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getShiftById = async (id) => { @@ -97,6 +14,7 @@ const getShiftById = async (id) => { method: 'get', prefix: `shift/${id}`, }); + return response.data; }; @@ -106,26 +24,8 @@ const createShift = async (queryParams) => { prefix: `shift`, params: queryParams, }); - console.log('createShift full response:', response); - console.log('createShift 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: [shift_object] } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; const updateShift = async (id, queryParams) => { @@ -134,26 +34,8 @@ const updateShift = async (id, queryParams) => { prefix: `shift/${id}`, params: queryParams, }); - console.log('updateShift full response:', response); - console.log('updateShift 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: [shift_object] } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; const deleteShift = async (id) => { @@ -161,25 +43,8 @@ const deleteShift = async (id) => { method: 'delete', prefix: `shift/${id}`, }); - console.log('deleteShift 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 - }; + return response.data; }; export { getAllShift, getShiftById, createShift, updateShift, deleteShift }; diff --git a/src/api/master-status.jsx b/src/api/master-status.jsx index d5ed80d..4b53e96 100644 --- a/src/api/master-status.jsx +++ b/src/api/master-status.jsx @@ -1,89 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; -const getAllStatus = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `status?${queryParams.toString()}`, - }); +const getAllStatuss = async (queryParams) => { + const response = await SendRequest({ + method: 'get', + prefix: `status?${queryParams.toString()}`, + }); - if (response.error) { - console.error('getAllStatus 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 - }; - } - - 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 - } - }; - } - - 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; - - 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('getAllStatus catch error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getStatusById = async (id) => { @@ -91,6 +14,7 @@ const getStatusById = async (id) => { method: 'get', prefix: `status/${id}`, }); + return response.data; }; @@ -101,68 +25,26 @@ const createStatus = async (queryParams) => { params: queryParams, }); - if (response.error) { - return { - statusCode: response.statusCode || 500, - data: null, - message: response.message || 'Request failed', - rows: 0 - }; - } - - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const updateStatus = async (status_id, queryParams) => { +const updateStatus = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `status/${status_id}`, + prefix: `status/${id}`, params: queryParams, }); - if (response.error) { - return { - statusCode: response.statusCode || 500, - data: null, - message: response.message || 'Request failed', - rows: 0 - }; - } - - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const deleteStatus = async (queryParams) => { +const deleteStatus = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `status/${queryParams}`, + prefix: `status/${id}`, }); - if (response.error) { - return { - statusCode: response.statusCode || 500, - data: null, - message: response.message || 'Request failed', - rows: 0 - }; - } - - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -export { getAllStatus, getStatusById, createStatus, updateStatus, deleteStatus }; \ No newline at end of file +export { getAllStatuss, getStatusById, createStatus, updateStatus, deleteStatus }; diff --git a/src/api/master-tag.jsx b/src/api/master-tag.jsx index f6a8eca..ba5a55e 100644 --- a/src/api/master-tag.jsx +++ b/src/api/master-tag.jsx @@ -1,93 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllTag = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `tags?${queryParams.toString()}`, - }); + const response = await SendRequest({ + method: 'get', + prefix: `tags?${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 - }; - } + return response.data; }; const getTagById = async (id) => { @@ -95,6 +14,7 @@ const getTagById = async (id) => { method: 'get', prefix: `tags/${id}`, }); + return response.data; }; @@ -105,74 +25,26 @@ const createTag = async (queryParams) => { params: 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 - }; + return response.data; }; -const updateTag = async (tag_id, queryParams) => { +const updateTag = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `tags/${tag_id}`, + prefix: `tags/${id}`, params: 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 - }; + return response.data; }; -const deleteTag = async (queryParams) => { +const deleteTag = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `tags/${queryParams}`, + prefix: `tags/${id}`, }); - // 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 - }; + return response.data; }; export { getAllTag, getTagById, createTag, updateTag, deleteTag }; diff --git a/src/api/master-unit.jsx b/src/api/master-unit.jsx index b03c91a..0130502 100644 --- a/src/api/master-unit.jsx +++ b/src/api/master-unit.jsx @@ -1,95 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllUnit = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `unit?${queryParams.toString()}`, - }); - console.log('getAllUnit response:', response); - console.log('Query params:', queryParams.toString()); + const response = await SendRequest({ + method: 'get', + prefix: `unit?${queryParams.toString()}`, + }); - // Check if response has error - if (response.error) { - console.error('getAllUnit 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 - 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('getAllUnit catch error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getUnitById = async (id) => { @@ -97,101 +14,37 @@ const getUnitById = async (id) => { method: 'get', prefix: `unit/${id}`, }); + return response.data; }; const createUnit = async (queryParams) => { - // Map frontend fields to backend fields - const backendParams = { - unit_name: queryParams.name, - is_active: queryParams.is_active, - }; - const response = await SendRequest({ method: 'post', prefix: `unit`, - params: backendParams, + params: queryParams, }); - console.log('createUnit full response:', response); - console.log('createUnit payload sent:', backendParams); - // 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: [unit_object] } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const updateUnit = async (unit_id, queryParams) => { - // Map frontend fields to backend fields - const backendParams = { - unit_name: queryParams.name, - is_active: queryParams.is_active, - }; - +const updateUnit = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `unit/${unit_id}`, - params: backendParams, + prefix: `unit/${id}`, + params: queryParams, }); - console.log('updateUnit full response:', response); - console.log('updateUnit payload sent:', backendParams); - // 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: [unit_object] } - return { - statusCode: response.statusCode || 200, - data: response.data?.[0] || response.data, - message: response.message, - rows: response.rows - }; + return response.data; }; -const deleteUnit = async (queryParams) => { +const deleteUnit = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `unit/${queryParams}`, + prefix: `unit/${id}`, }); - console.log('deleteUnit 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 - }; + return response.data; }; export { getAllUnit, getUnitById, createUnit, updateUnit, deleteUnit }; diff --git a/src/api/role.jsx b/src/api/role.jsx index 5a0b62f..44e5480 100644 --- a/src/api/role.jsx +++ b/src/api/role.jsx @@ -1,70 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllRole = async (queryParams) => { - try { - const response = await SendRequest({ - method: 'get', - prefix: `roles?${queryParams.toString()}`, - }); + const response = await SendRequest({ + method: 'get', + prefix: `roles?${queryParams.toString()}`, + }); - console.log('Role API Response:', response); - - // Check if backend returns paginated data - if (response.paging) { - // Backend already provides pagination info - return { - status: response.statusCode || 200, - data: { - data: response.data || [], - paging: response.paging, - total: response.paging.total || 0 - } - }; - } - - // Fallback: If backend returns all data without pagination - 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('getAllRole error:', error); - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getRoleById = async (id) => { @@ -72,6 +14,7 @@ const getRoleById = async (id) => { method: 'get', prefix: `roles/${id}`, }); + return response.data; }; @@ -82,107 +25,26 @@ const createRole = async (queryParams) => { params: queryParams, }); - console.log('Create Role API Response:', response); - - // Check for error status (not 200, 201, or success) - const isSuccess = - response.statusCode === 200 || response.statusCode === 201 || response.status === 'success'; - - if (!isSuccess && response.statusCode >= 400) { - let errorMessage = response.message || 'Gagal menambahkan role'; - - // Handle SQL unique constraint violation - if ( - errorMessage.includes('UNIQUE KEY constraint') || - errorMessage.includes('duplicate key') - ) { - errorMessage = `Role dengan nama "${queryParams.role_name}" sudah ada. Silakan gunakan nama lain.`; - } - - return { - statusCode: response.statusCode, - data: response.data, - message: errorMessage, - }; - } - - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message || 'Berhasil menambahkan role', - }; + return response.data; }; -const updateRole = async (role_id, queryParams) => { +const updateRole = async (id, queryParams) => { const response = await SendRequest({ method: 'put', - prefix: `roles/${role_id}`, + prefix: `roles/${id}`, params: queryParams, }); - console.log('Update Role API Response:', response); - - // Check for error status (not 200, 201, or success) - const isSuccess = - response.statusCode === 200 || response.statusCode === 201 || response.status === 'success'; - - if (!isSuccess && response.statusCode >= 400) { - let errorMessage = response.message || 'Gagal mengubah role'; - - // Handle SQL unique constraint violation - if ( - errorMessage.includes('UNIQUE KEY constraint') || - errorMessage.includes('duplicate key') - ) { - errorMessage = `Role dengan nama "${queryParams.role_name}" sudah ada. Silakan gunakan nama lain.`; - } - - return { - statusCode: response.statusCode, - data: response.data, - message: errorMessage, - }; - } - - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message || 'Berhasil mengubah role', - }; + return response.data; }; -const deleteRole = async (queryParams) => { +const deleteRole = async (id) => { const response = await SendRequest({ method: 'delete', - prefix: `roles/${queryParams}`, + prefix: `roles/${id}`, }); - console.log('Delete API Response:', response); - - // Check for errors - if (response.statusCode !== 200) { - let errorMessage = response.message || 'Gagal menghapus role'; - - // Handle foreign key constraint - if (errorMessage.includes('REFERENCE constraint') || errorMessage.includes('foreign key')) { - errorMessage = 'Role tidak dapat dihapus karena masih digunakan oleh user.'; - } - - return { - statusCode: response.statusCode, - data: response.data, - message: errorMessage, - }; - } - - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message, - }; + return response.data; }; export { getAllRole, getRoleById, createRole, updateRole, deleteRole }; diff --git a/src/api/user-admin.jsx b/src/api/user-admin.jsx index 72dba82..a1eeef5 100644 --- a/src/api/user-admin.jsx +++ b/src/api/user-admin.jsx @@ -1,15 +1,11 @@ -// user-admin.jsx -import axios from 'axios'; import { SendRequest } from '../components/Global/ApiRequest'; -const baseURL = import.meta.env.VITE_API_SERVER; - const getAllUser = async (queryParams) => { const response = await SendRequest({ method: 'get', prefix: `admin-user?${queryParams.toString()}`, }); - return response; + return response.data; }; const getUserDetail = async (id) => { @@ -17,7 +13,7 @@ const getUserDetail = async (id) => { method: 'get', prefix: `admin-user/${id}`, }); - return response; + return response.data; }; const updateUser = async (id, data) => { @@ -26,7 +22,7 @@ const updateUser = async (id, data) => { prefix: `admin-user/${id}`, params: data, }); - return response; + return response.data; }; const deleteUser = async (id) => { @@ -34,7 +30,7 @@ const deleteUser = async (id) => { method: 'delete', prefix: `admin-user/${id}`, }); - return response; + return response.data; }; const approvalUser = async (id, queryParams) => { @@ -43,42 +39,7 @@ const approvalUser = async (id, queryParams) => { prefix: `admin-user/approve/${id}`, params: queryParams, }); - return response; + return response.data; }; -const uploadFile = async (formData) => { - try { - const token = localStorage.getItem('token')?.replace(/"/g, '') || ''; - const url = `${baseURL}/file-upload`; - - const response = await axios.post(url, formData, { - headers: { - Authorization: `Bearer ${token}`, - 'Accept-Language': 'en_US', - 'Content-Type': 'multipart/form-data', - }, - }); - - return { - statusCode: response.data?.statusCode ?? 0, - message: response.data?.message ?? '', - data: response.data?.data ?? {}, - }; - } catch (error) { - console.error('❌ ERROR di uploadFile:', error); - return { - statusCode: error?.response?.status || 500, - message: error?.response?.data?.message || 'Upload gagal', - data: {}, - }; - } -}; - - - - - - - - -export { getAllUser, getUserDetail, updateUser, deleteUser, approvalUser, uploadFile }; \ No newline at end of file +export { getAllUser, getUserDetail, updateUser, deleteUser, approvalUser }; diff --git a/src/api/user.jsx b/src/api/user.jsx index 208f5ba..7c206e5 100644 --- a/src/api/user.jsx +++ b/src/api/user.jsx @@ -1,97 +1,12 @@ import { SendRequest } from '../components/Global/ApiRequest'; const getAllUser = async (queryParams) => { - try { - console.log('getAllUser queryParams:', queryParams.toString()); + const response = await SendRequest({ + method: 'get', + prefix: `user?${queryParams.toString()}`, + }); - const response = await SendRequest({ - method: 'get', - prefix: `user?${queryParams.toString()}`, - }); - - console.log('getAllUser response:', response); - - // Backend now handles pagination, just return the response - // Expected backend response structure: - // { - // statusCode: 200, - // data: [...users], - // paging: { page, limit, total, page_total } - // } - - // Check if backend returns paginated data - if (response.paging) { - // Filter out super admin users (is_sa = true) - const allData = response.data || []; - const filteredData = allData.filter(user => user.is_sa !== true && user.is_sa !== 1); - - // Recalculate pagination info after filtering - const totalAfterFilter = filteredData.length; - const currentPage = response.paging.page || 1; - const currentLimit = response.paging.limit || 10; - - return { - status: response.statusCode || 200, - data: { - data: filteredData, - paging: { - page: currentPage, - limit: currentLimit, - total: totalAfterFilter, - page_total: Math.ceil(totalAfterFilter / currentLimit) - }, - total: totalAfterFilter - } - }; - } - - // 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 || []; - - // Filter out users with is_sa = true or 1 (client-side filtering) - const filteredData = allData.filter(user => user.is_sa !== true && user.is_sa !== 1); - const totalData = filteredData.length; - - // Client-side pagination - const startIndex = (currentPage - 1) * currentLimit; - const endIndex = startIndex + currentLimit; - const paginatedData = filteredData.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('getAllUser error:', error); - // Return empty data on error to prevent app crash - return { - status: 500, - data: { - data: [], - paging: { - page: 1, - limit: 10, - total: 0, - page_total: 0 - }, - total: 0 - }, - error: error.message - }; - } + return response.data; }; const getUserById = async (id) => { @@ -99,6 +14,7 @@ const getUserById = async (id) => { method: 'get', prefix: `user/${id}`, }); + return response.data; }; @@ -108,12 +24,8 @@ const createUser = async (queryParams) => { prefix: `user`, params: queryParams, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const updateUser = async (user_id, queryParams) => { @@ -122,12 +34,8 @@ const updateUser = async (user_id, queryParams) => { prefix: `user/${user_id}`, params: queryParams, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const deleteUser = async (queryParams) => { @@ -135,12 +43,8 @@ const deleteUser = async (queryParams) => { method: 'delete', prefix: `user/${queryParams}`, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const approveUser = async (user_id) => { @@ -148,12 +52,8 @@ const approveUser = async (user_id) => { method: 'put', prefix: `user/${user_id}/approve`, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const rejectUser = async (user_id) => { @@ -161,12 +61,8 @@ const rejectUser = async (user_id) => { method: 'put', prefix: `user/${user_id}/reject`, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const toggleActiveUser = async (user_id, is_active) => { @@ -174,15 +70,11 @@ const toggleActiveUser = async (user_id, is_active) => { method: 'put', prefix: `user/${user_id}`, params: { - is_active: is_active + is_active: is_active, }, }); - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message - }; + + return response.data; }; const changePassword = async (user_id, new_password) => { @@ -190,18 +82,21 @@ const changePassword = async (user_id, new_password) => { method: 'put', prefix: `user/change-password/${user_id}`, params: { - new_password: new_password + new_password: new_password, }, }); - console.log('Change Password Response:', response); - - // Return full response with statusCode - return { - statusCode: response.statusCode || 200, - data: response.data, - message: response.message || 'Password berhasil diubah' - }; + return response.data; }; -export { getAllUser, getUserById, createUser, updateUser, deleteUser, approveUser, rejectUser, toggleActiveUser, changePassword }; \ No newline at end of file +export { + getAllUser, + getUserById, + createUser, + updateUser, + deleteUser, + approveUser, + rejectUser, + toggleActiveUser, + changePassword, +}; diff --git a/src/components/Global/ApiRequest.jsx b/src/components/Global/ApiRequest.jsx index 78441e9..cf166cf 100644 --- a/src/components/Global/ApiRequest.jsx +++ b/src/components/Global/ApiRequest.jsx @@ -1,170 +1,171 @@ -import axios from "axios"; -import Swal from "sweetalert2"; +import axios from 'axios'; +import Swal from 'sweetalert2'; const baseURL = import.meta.env.VITE_API_SERVER; const instance = axios.create({ - baseURL, - withCredentials: true, + baseURL, + withCredentials: true, }); // axios khusus refresh const refreshApi = axios.create({ - baseURL, - withCredentials: true, + baseURL, + withCredentials: true, }); - instance.interceptors.response.use( - (response) => response, - async (error) => { - const originalRequest = error.config; + (response) => response, + 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 - }); + 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; + if (error.response?.status === 401 && !originalRequest._retry) { + originalRequest._retry = true; - try { - console.log("🔄 Refresh token dipanggil..."); - const refreshRes = await refreshApi.post("/auth/refresh-token"); + try { + console.log('🔄 Refresh token dipanggil...'); + const refreshRes = await refreshApi.post('/auth/refresh-token'); - const newAccessToken = refreshRes.data.data.accessToken; - localStorage.setItem("token", newAccessToken); - console.log("✅ Token refreshed successfully"); + 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}`; + // 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.response?.data || refreshError.message); - localStorage.clear(); - window.location.href = "/signin"; - } + console.log('🔁 Retrying original request...'); + return instance(originalRequest); + } catch (refreshError) { + console.error( + '❌ Refresh token gagal:', + refreshError.response?.data || refreshError.message + ); + localStorage.clear(); + window.location.href = '/signin'; + } + } + + return Promise.reject(error); } - - return Promise.reject(error); - } ); -async function ApiRequest({ - method = "GET", - params = {}, - prefix = "/", - token = true, -} = {}) { - const isFormData = params instanceof FormData; +async function ApiRequest({ method = 'GET', params = {}, prefix = '/', token = true } = {}) { + const isFormData = params instanceof FormData; - const request = { - method, - url: prefix, - data: params, - headers: { - "Accept-Language": "en_US", - ...(isFormData ? {} : { "Content-Type": "application/json" }), - }, - }; + const request = { + method, + url: prefix, + data: params, + headers: { + 'Accept-Language': 'en_US', + ...(isFormData ? {} : { 'Content-Type': 'application/json' }), + }, + }; - const rawToken = localStorage.getItem("token"); - if (token && rawToken) { - 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); + const rawToken = localStorage.getItem('token'); + if (token && rawToken) { + 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'); } - return { ...error.response, error: true }; - } + 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); + } + + return { ...error.response, error: true }; + } } -async function cekError(status, message = "") { - if (status === 403) { - await Swal.fire({ - icon: "warning", - title: "Forbidden", - text: message, - }); - } else if (status >= 500) { - await Swal.fire({ - icon: "error", - title: "Server Error", - text: message, - }); - } else { - await Swal.fire({ - icon: "warning", - title: "Peringatan", - text: message, - }); - } +async function cekError(status, message = '') { + if (status === 403) { + await Swal.fire({ + icon: 'warning', + title: 'Forbidden', + text: message, + }); + } else if (status >= 500) { + await Swal.fire({ + icon: 'error', + title: 'Server Error', + text: message, + }); + } else { + await Swal.fire({ + icon: 'warning', + title: 'Peringatan', + text: message, + }); + } } const SendRequest = async (queryParams) => { - try { - const response = await ApiRequest(queryParams); - console.log("📦 SendRequest response:", { - hasError: response.error, - status: response.status, - statusCode: response.data?.statusCode, - data: response.data - }); + try { + const response = await ApiRequest(queryParams); + console.log('📦 SendRequest response:', { + hasError: response.error, + status: response.status, + statusCode: response.data?.statusCode, + data: response.data, + }); - // 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); + // 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 consistent error structure instead of empty array + return { + statusCode: response.status || 500, + message: errorMsg, + data: null, + error: true, + }; + } + + return response || { 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, + }; } - - 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 - }; - } }; export { ApiRequest, SendRequest }; diff --git a/src/components/Global/CardList.jsx b/src/components/Global/CardList.jsx index 746e7c5..ee9cc9e 100644 --- a/src/components/Global/CardList.jsx +++ b/src/components/Global/CardList.jsx @@ -37,7 +37,7 @@ const CardList = ({ return ( {data.map((item) => ( - + { - filter(1, 10); + filter(1, pagination.current_limit); }, [triger]); const filter = async (currentPage, pageSize) => { setGridLoading(true); const paging = { - page: currentPage, - limit: pageSize, + page: Number(currentPage), + limit: Number(pageSize), }; const param = new URLSearchParams({ ...paging, ...queryParams }); const resData = await getData(param); + setData(resData?.data ?? []); + + const pagingData = resData?.paging; + + if (pagingData) { + setPagination((prev) => ({ + ...prev, + current_page: pagingData.current_page || 1, + current_limit: pagingData.current_limit || 10, + total_limit: pagingData.total_limit || 0, + total_page: pagingData.total_page || 1, + })); + } + if (resData) { setTimeout(() => { setGridLoading(false); @@ -72,29 +70,6 @@ const TableList = memo(function TableList({ setGridLoading(false); return; } - - const dataToSet = resData.data?.data ?? resData.data ?? []; - setData(dataToSet); - setFilterData(dataToSet); - - if (resData.status == 200) { - const pagingData = resData.data?.paging; - - if (pagingData) { - setPagingResponse({ - totalData: pagingData.total || 0, - perPage: pagingData.limit || 0, - totalPage: pagingData.page_total || 0, - }); - - setPagination((prev) => ({ - ...prev, - current: pagingData.page || 1, - limit: pagingData.limit || 10, - total: pagingData.total || 0, - })); - } - } }; const handlePaginationChange = (page, pageSize) => { @@ -146,8 +121,8 @@ const TableList = memo(function TableList({
- Menampilkan {pagingResponse.totalData} Data dari {pagingResponse.totalPage}{' '} - Halaman + Menampilkan {pagination.current_limit} data halaman{' '} + {pagination.current_page} dari total {pagination.total_limit} data
@@ -155,9 +130,9 @@ const TableList = memo(function TableList({ showSizeChanger onChange={handlePaginationChange} onShowSizeChange={handlePaginationChange} - current={pagination.current} - pageSize={pagination.limit} - total={pagination.total} + current={pagination.current_page} + pageSize={pagination.current_limit} + total={pagination.total_limit} />
diff --git a/src/components/Global/ToastNotif.jsx b/src/components/Global/ToastNotif.jsx index cf9d8ad..2cdeaf9 100644 --- a/src/components/Global/ToastNotif.jsx +++ b/src/components/Global/ToastNotif.jsx @@ -16,6 +16,7 @@ const NotifOk = ({ icon, title, message }) => { icon: icon, title: title, text: message, + html: message.replace(/\n/g, '
'), }); }; diff --git a/src/pages/auth/Registration.jsx b/src/pages/auth/Registration.jsx deleted file mode 100644 index a836ffd..0000000 --- a/src/pages/auth/Registration.jsx +++ /dev/null @@ -1,461 +0,0 @@ -// import React, { useState } from 'react'; -// import { -// Flex, -// Input, -// InputNumber, -// Form, -// Button, -// Card, -// Space, -// Upload, -// Divider, -// Tooltip, -// message, -// Select, -// } from 'antd'; -// import { -// UploadOutlined, -// UserOutlined, -// IdcardOutlined, -// PhoneOutlined, -// LockOutlined, -// InfoCircleOutlined, -// MailOutlined, -// } from '@ant-design/icons'; -// const { Item } = Form; -// const { Option } = Select; -// import sypiu_ggcp from 'assets/sypiu_ggcp.jpg'; -// import { useNavigate } from 'react-router-dom'; -// import { register, uploadFile, checkUsername } from '../../api/auth'; -// import { NotifAlert } from '../../components/Global/ToastNotif'; - -// const Registration = () => { -// const [form] = Form.useForm(); -// const navigate = useNavigate(); -// const [loading, setLoading] = useState(false); -// const [fileListKontrak, setFileListKontrak] = useState([]); -// const [fileListHsse, setFileListHsse] = useState([]); -// const [fileListIcon, setFileListIcon] = useState([]); - -// // Daftar jenis vendor -// const vendorTypes = [ -// { vendor_type: 1, vendor_type_name: 'One-Time' }, -// { vendor_type: 2, vendor_type_name: 'Rutin' }, -// ]; - -// const onFinish = async (values) => { -// setLoading(true); -// try { -// if (!fileListKontrak.length || !fileListHsse.length) { -// message.error('Harap unggah Lampiran Kontrak Kerja dan HSSE Plan!'); -// setLoading(false); -// return; -// } - -// const formData = new FormData(); -// formData.append('path_kontrak', fileListKontrak[0].originFileObj); -// formData.append('path_hse_plant', fileListHsse[0].originFileObj); -// if (fileListIcon.length) { -// formData.append('path_icon', fileListIcon[0].originFileObj); -// } - -// const uploadResponse = await uploadFile(formData); - -// if (!uploadResponse.data?.pathKontrak && !uploadResponse.data?.pathHsePlant) { -// message.error(uploadResponse.message || 'Gagal mengunggah file.'); -// setLoading(false); -// return; -// } - -// const params = new URLSearchParams({ username: values.username }); -// const usernameCheck = await checkUsername(params); -// if (usernameCheck.data.data && usernameCheck.data.data.available === false) { -// NotifAlert({ -// icon: 'error', -// title: 'Gagal', -// message: usernameCheck.data.message || 'Terjadi kesalahan, silakan coba lagi', -// }); -// setLoading(false); -// return; -// } - -// const registerData = { -// nama_perusahaan: values.namaPerusahaan, -// no_kontak_wo: values.noKontakWo, -// path_kontrak: uploadResponse.data.pathKontrak || '', -// durasi: values.durasiPekerjaan, -// nilai_csms: values.nilaiCsms.toString(), -// vendor_type: values.jenisVendor, // Tambahkan jenis vendor ke registerData -// path_hse_plant: uploadResponse.data.pathHsePlant || '', -// nama_leader: values.penanggungJawab, -// no_identitas: values.noIdentitas, -// no_hp: values.noHandphone, -// email_register: values.username, -// password_register: values.password, -// }; - -// const response = await register(registerData); - -// if (response.data?.id_register) { -// message.success('Data berhasil disimpan!'); - -// try { -// form.resetFields(); -// setFileListKontrak([]); -// setFileListHsse([]); -// setFileListIcon([]); - -// navigate('/registration-submitted'); -// } catch (postSuccessError) { -// message.warning( -// 'Registrasi berhasil, tetapi ada masalah setelahnya. Silakan ke halaman login secara manual.' -// ); -// } -// } else { -// message.error(response.message || 'Pendaftaran gagal, silakan coba lagi.'); -// } -// } catch (error) { -// console.error('Error saat registrasi:', error); -// NotifAlert({ -// icon: 'error', -// title: 'Gagal', -// message: error.message || 'Terjadi kesalahan, silakan coba lagi', -// }); -// } finally { -// setLoading(false); -// } -// }; - -// const onCancel = () => { -// form.resetFields(); -// setFileListKontrak([]); -// setFileListHsse([]); -// setFileListIcon([]); -// navigate('/signin'); -// }; - -// const handleChangeKontrak = ({ fileList }) => { -// setFileListKontrak(fileList); -// }; - -// const handleChangeHsse = ({ fileList }) => { -// setFileListHsse(fileList); -// }; - -// const handleChangeIcon = ({ fileList }) => { -// setFileListIcon(fileList); -// }; - -// const beforeUpload = (file, fieldname) => { -// const isValidType = [ -// 'image/jpeg', -// 'image/jpg', -// 'image/png', -// fieldname !== 'path_icon' ? 'application/pdf' : null, -// ] -// .filter(Boolean) -// .includes(file.type); -// const isNotEmpty = file.size > 0; -// const isSizeValid = file.size / 1024 / 1024 < 10; - -// if (!isValidType) { -// message.error( -// `Hanya file ${ -// fieldname === 'path_icon' ? 'JPG/PNG' : 'PDF/JPG/PNG' -// } yang diperbolehkan!` -// ); -// return false; -// } -// if (!isNotEmpty) { -// message.error('File tidak boleh kosong!'); -// return false; -// } -// if (!isSizeValid) { -// message.error('Ukuran file maksimal 10MB!'); -// return false; -// } -// return true; -// }; - -// return ( -// -// -//

Formulir Pendaftaran

-// -//
-// } -// > -//
-// {/* Informasi Perusahaan */} -// -// Informasi Perusahaan -// -// -// } -// placeholder="Masukkan Nama Perusahaan" -// size="large" -// /> -// -// -// -// -// -// -// -// -// beforeUpload(file, 'path_kontrak')} -// fileList={fileListKontrak} -// onChange={handleChangeKontrak} -// maxCount={1} -// > -// -// -// -// -// beforeUpload(file, 'path_hse_plant')} -// fileList={fileListHsse} -// onChange={handleChangeHsse} -// maxCount={1} -// > -// -// -// -// -// -// -// -// -// - -// {/* Informasi Penanggung Jawab */} -// -// Informasi Penanggung Jawab -// -// -// } -// placeholder="Masukkan Nama Penanggung Jawab" -// size="large" -// /> -// -// -// } -// placeholder="Masukkan No Handphone (+62)" -// size="large" -// /> -// -// -// } -// placeholder="Masukkan No Identitas" -// size="large" -// /> -// - -// {/* Akun Pengguna */} -// -// Akun Pengguna (digunakan sebagai user login SYPIU) -// -// -// } -// placeholder="Masukkan Email" -// size="large" -// /> -// -// -// } -// placeholder="Masukkan Password" -// size="large" -// /> -// - -// {/* Tombol */} -// -// -// -// -// -// -//
-//
-// -// ); -// }; - -// export default Registration; diff --git a/src/pages/auth/SignIn.jsx b/src/pages/auth/SignIn.jsx index f63ea0d..3e95747 100644 --- a/src/pages/auth/SignIn.jsx +++ b/src/pages/auth/SignIn.jsx @@ -31,8 +31,9 @@ const SignIn = () => { prefix: 'auth/generate-captcha', token: false, }); - setCaptchaSvg(res.data.svg || ''); - setCaptchaText(res.data.text || ''); + + setCaptchaSvg(res.data?.data?.svg || ''); + setCaptchaText(res.data?.data?.text || ''); } catch (err) { console.error('Error fetching captcha:', err); } @@ -57,8 +58,8 @@ const SignIn = () => { withCredentials: true, }); - const user = res?.data?.user || res?.user; - const accessToken = res?.data?.accessToken || res?.tokens?.accessToken; + const user = res?.data?.data?.user || res?.user; + const accessToken = res?.data?.data?.accessToken || res?.tokens?.accessToken; if (user && accessToken) { localStorage.setItem('token', accessToken); diff --git a/src/pages/master/brandDevice/component/ListBrandDevice.jsx b/src/pages/master/brandDevice/component/ListBrandDevice.jsx index 9b1d740..cd9b654 100644 --- a/src/pages/master/brandDevice/component/ListBrandDevice.jsx +++ b/src/pages/master/brandDevice/component/ListBrandDevice.jsx @@ -10,6 +10,7 @@ import { import { NotifAlert, NotifConfirmDialog } from '../../../../components/Global/ToastNotif'; import { useNavigate } from 'react-router-dom'; import TableList from '../../../../components/Global/TableList'; +import { getAllBrands } from '../../../../api/master-brand'; // Dummy data const initialBrandDeviceData = [ @@ -145,55 +146,6 @@ const ListBrandDevice = memo(function ListBrandDevice(props) { const navigate = useNavigate(); - // Dummy data function to simulate API call - now uses state - const getAllBrandDevice = async (params) => { - // Simulate API delay - await new Promise((resolve) => setTimeout(resolve, 300)); - - // Extract URLSearchParams - TableList sends URLSearchParams object - const searchParam = params.get('search') || ''; - const page = parseInt(params.get('page')) || 1; - const limit = parseInt(params.get('limit')) || 10; - - console.log('getAllBrandDevice called with:', { searchParam, page, limit }); - - // Filter by search - let filteredBrandDevices = brandDeviceData; - if (searchParam) { - const searchLower = searchParam.toLowerCase(); - filteredBrandDevices = brandDeviceData.filter( - (brand) => - brand.brandName.toLowerCase().includes(searchLower) || - brand.brandType.toLowerCase().includes(searchLower) || - brand.manufacturer.toLowerCase().includes(searchLower) || - brand.model.toLowerCase().includes(searchLower) - ); - } - - // Pagination logic - const totalData = filteredBrandDevices.length; - const totalPages = Math.ceil(totalData / limit); - const startIndex = (page - 1) * limit; - const endIndex = startIndex + limit; - const paginatedData = filteredBrandDevices.slice(startIndex, endIndex); - - // Return structure that matches TableList expectation - return { - status: 200, - statusCode: 200, - data: { - data: paginatedData, - total: totalData, - paging: { - page: page, - limit: limit, - total: totalData, - page_total: totalPages, - }, - }, - }; - }; - useEffect(() => { const token = localStorage.getItem('token'); if (token) { @@ -333,7 +285,7 @@ const ListBrandDevice = memo(function ListBrandDevice(props) { showPreviewModal={showPreviewModal} showEditModal={showEditModal} showDeleteDialog={showDeleteDialog} - getData={getAllBrandDevice} + getData={getAllBrands} queryParams={formDataFilter} columns={columns(showPreviewModal, showEditModal, showDeleteDialog)} triger={trigerFilter} diff --git a/src/pages/master/device/component/DetailDevice.jsx b/src/pages/master/device/component/DetailDevice.jsx index c49a273..a0d951a 100644 --- a/src/pages/master/device/component/DetailDevice.jsx +++ b/src/pages/master/device/component/DetailDevice.jsx @@ -1,20 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { - Modal, - Input, - Divider, - Typography, - Switch, - Button, - ConfigProvider, - Radio, - Select, -} from 'antd'; +import { Modal, Input, Divider, Typography, Switch, Button, ConfigProvider } from 'antd'; import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif'; -import { createApd, getJenisPermit, updateApd } from '../../../../api/master-apd'; -import { createDevice, updateDevice, getAllDevice } from '../../../../api/master-device'; -import { Checkbox } from 'antd'; -const CheckboxGroup = Checkbox.Group; +import { createDevice, updateDevice } from '../../../../api/master-device'; +import { validateRun } from '../../../../Utils/validate'; const { Text } = Typography; const { TextArea } = Input; @@ -27,156 +15,60 @@ const DetailDevice = (props) => { device_code: '', device_name: '', is_active: true, - device_location: 'Building A', + device_location: '', device_description: '', ip_address: '', }; - const [FormData, setFormData] = useState(defaultData); - const [nextDeviceCode, setNextDeviceCode] = useState('Auto-fill'); - - const [jenisPermit, setJenisPermit] = useState([]); - const [checkedList, setCheckedList] = useState([]); - - const onChange = (list) => { - setCheckedList(list); - }; - - const onChangeRadio = (e) => { - setFormData({ - ...FormData, - type_input: e.target.value, - }); - }; - - const getDataJenisPermit = async () => { - setCheckedList([]); - const result = await getJenisPermit(); - const data = result.data ?? []; - const names = data.map((item) => ({ - value: item.id_jenis_permit, - label: item.nama_jenis_permit, - })); - setJenisPermit(names); - }; + const [formData, setFormData] = useState(defaultData); const handleCancel = () => { props.setSelectedData(null); props.setActionMode('list'); }; - const validateIPAddress = (ip) => { - const ipRegex = - /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; - return ipRegex.test(ip); - }; - const handleSave = async () => { setConfirmLoading(true); - // Validasi required fields - // if (!FormData.device_code) { - // NotifOk({ - // icon: 'warning', - // title: 'Peringatan', - // message: 'Kolom Device Code Tidak Boleh Kosong', - // }); - // setConfirmLoading(false); - // return; - // } + // Daftar aturan validasi + const validationRules = [ + { field: 'device_name', label: 'Device Name', required: true }, + { field: 'ip_address', label: 'Ip Address', required: true, ip: true }, + ]; - if (!FormData.device_name) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom Device Name Tidak Boleh Kosong', - }); - setConfirmLoading(false); + if ( + validateRun(formData, validationRules, (errorMessages) => { + NotifOk({ + icon: 'warning', + title: 'Peringatan', + message: errorMessages, + }); + setConfirmLoading(false); + }) + ) return; - } - - if (!FormData.device_location) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom Device Location Tidak Boleh Kosong', - }); - setConfirmLoading(false); - return; - } - - if (!FormData.ip_address) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom IP Address Tidak Boleh Kosong', - }); - setConfirmLoading(false); - return; - } - - // Validasi format IP - if (!validateIPAddress(FormData.ip_address)) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Format IP Address Tidak Valid', - }); - setConfirmLoading(false); - return; - } - - if (props.permitDefault && checkedList.length === 0) { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: 'Kolom Jenis Permit Tidak Boleh Kosong', - }); - - setConfirmLoading(false); - return; - } - - // Backend validation schema doesn't include device_code - const payload = { - device_name: FormData.device_name, - is_active: FormData.is_active, - device_location: FormData.device_location, - ip_address: FormData.ip_address, - }; - - // For CREATE: device_description is required (cannot be empty) - // For UPDATE: device_description is optional - if (!FormData.device_id) { - // Creating - ensure description is not empty - payload.device_description = FormData.device_description || '-'; - } else { - // Updating - include description as-is - payload.device_description = FormData.device_description; - } - - console.log('Payload to send:', payload); try { - let response; - if (!FormData.device_id) { - response = await createDevice(payload); - } else { - response = await updateDevice(FormData.device_id, payload); - } + const payload = { + device_name: formData.device_name, + is_active: formData.is_active, + device_location: formData.device_location, + ip_address: formData.ip_address, + }; - console.log('Save Device Response:', response); + const response = !formData.device_id + ? await updateDevice(formData.device_id, payload) + : await createDevice(payload); // Check if response is successful if (response && (response.statusCode === 200 || response.statusCode === 201)) { - // Response.data is now a single object (already extracted from array) - const deviceName = response.data?.device_name || FormData.device_name; + const deviceName = response.data?.device_name || formData.device_name; NotifOk({ icon: 'success', title: 'Berhasil', message: `Data Device "${deviceName}" berhasil ${ - FormData.device_id ? 'diubah' : 'ditambahkan' + formData.device_id ? 'diubah' : 'ditambahkan' }.`, }); @@ -203,7 +95,7 @@ const DetailDevice = (props) => { const handleInputChange = (e) => { const { name, value } = e.target; setFormData({ - ...FormData, + ...formData, [name]: value, }); }; @@ -211,78 +103,22 @@ const DetailDevice = (props) => { const handleStatusToggle = (event) => { const isChecked = event; setFormData({ - ...FormData, + ...formData, is_active: isChecked ? true : false, }); }; - const generateNextDeviceCode = async () => { - try { - const params = new URLSearchParams({ limit: 10000 }); - const response = await getAllDevice(params); - - if (response && response.data && response.data.data) { - const devices = response.data.data; - - if (devices.length === 0) { - setNextDeviceCode('DVC001'); - return; - } - - // Extract numeric part from device codes and find the maximum - const deviceNumbers = devices - .map((device) => { - const match = device.device_code?.match(/dvc(\d+)/i); - return match ? parseInt(match[1], 10) : 0; - }) - .filter((num) => !isNaN(num)); - - const maxNumber = deviceNumbers.length > 0 ? Math.max(...deviceNumbers) : 0; - const nextNumber = maxNumber + 1; - - // Format with leading zeros (DVC001, DVC002, etc.) - const nextCode = `DVC${String(nextNumber).padStart(3, '0')}`; - setNextDeviceCode(nextCode); - } else { - setNextDeviceCode('DVC001'); - } - } catch (error) { - console.error('Error generating next device code:', error); - setNextDeviceCode('Auto-fill'); - } - }; - useEffect(() => { - const token = localStorage.getItem('token'); - if (token) { - if (props.showModal) { - // Only call getDataJenisPermit if permitDefault is enabled - if (props.permitDefault) { - getDataJenisPermit(); - } - - // Generate next device code only for add mode - if (props.actionMode === 'add' && !props.selectedData) { - generateNextDeviceCode(); - } - } - - if (props.selectedData != null) { - setFormData(props.selectedData); - if (props.permitDefault && props.selectedData.jenis_permit_default_arr) { - setCheckedList(props.selectedData.jenis_permit_default_arr); - } - } else { - setFormData(defaultData); - } + if (props.selectedData) { + setFormData(props.selectedData); } else { - // navigate('/signin'); // Uncomment if useNavigate is imported + setFormData(defaultData); } - }, [props.showModal, props.actionMode]); + }, [props.showModal, props.selectedData, props.actionMode]); return ( { , ]} > - {FormData && ( + {formData && (
@@ -355,14 +191,14 @@ const DetailDevice = (props) => { disabled={props.readOnly} style={{ backgroundColor: - FormData.is_active === true ? '#23A55A' : '#bfbfbf', + formData.is_active === true ? '#23A55A' : '#bfbfbf', }} - checked={FormData.is_active === true} + checked={formData.is_active === true} onChange={handleStatusToggle} />
- {FormData.is_active === true ? 'Running' : 'Offline'} + {formData.is_active === true ? 'Running' : 'Offline'}
@@ -371,7 +207,7 @@ const DetailDevice = (props) => { Device ID @@ -381,13 +217,13 @@ const DetailDevice = (props) => { Device Code @@ -396,7 +232,7 @@ const DetailDevice = (props) => { * {
Device Location - * { * { Device Description