From 13255f9713f65c808eb164a35a39267aa2d7b651 Mon Sep 17 00:00:00 2001 From: vinix Date: Thu, 11 Dec 2025 17:07:06 +0700 Subject: [PATCH] feat: add getNotificationDetail API function and integrate it into DetailNotification component for enhanced notification handling --- src/api/notification.jsx | 11 +- .../IndexDetailNotification.jsx | 172 ++++++++++++------ .../component/DetailNotification.jsx | 151 +++++++++++---- 3 files changed, 242 insertions(+), 92 deletions(-) diff --git a/src/api/notification.jsx b/src/api/notification.jsx index fe38523..431358f 100644 --- a/src/api/notification.jsx +++ b/src/api/notification.jsx @@ -18,4 +18,13 @@ const getNotificationById = async (id) => { return response.data; }; -export { getAllNotification, getNotificationById }; +const getNotificationDetail = async (id) => { + const response = await SendRequest({ + method: 'get', + prefix: `notification/${id}`, + }); + + return response.data; +}; + +export { getAllNotification, getNotificationById, getNotificationDetail }; diff --git a/src/pages/detailNotification/IndexDetailNotification.jsx b/src/pages/detailNotification/IndexDetailNotification.jsx index c842ce8..128c554 100644 --- a/src/pages/detailNotification/IndexDetailNotification.jsx +++ b/src/pages/detailNotification/IndexDetailNotification.jsx @@ -26,38 +26,46 @@ import { PlusOutlined, UserOutlined, } from '@ant-design/icons'; -// Path disesuaikan karena lokasi file berubah -// import { getNotificationById } from '../../api/notification'; // Dihapus karena belum ada di file API +import { getNotificationDetail } from '../../api/notification'; import UserHistoryModal from '../notification/component/UserHistoryModal'; -import LogHistoryCard from '../notification/component/LogHistoryCard'; // Ganti LogHistoryModal dengan LogHistoryCard +import LogHistoryCard from '../notification/component/LogHistoryCard'; const { Content } = Layout; const { Text, Paragraph, Link } = Typography; -// Menggunakan kembali fungsi transform dari ListNotification untuk konsistensi data -const transformNotificationData = (item) => ({ - id: `notification-${item.notification_error_id || 'dummy'}-0`, - type: item.is_read ? 'resolved' : item.is_delivered ? 'warning' : 'critical', - title: item.device_name || 'Unknown Device', - issue: item.error_code_name || 'Unknown Error', - description: `${item.error_code} - ${item.error_code_name}`, - timestamp: new Date(item.created_at || Date.now()).toLocaleString('id-ID'), - location: item.device_location || 'Location not specified', - details: item.message_error_issue || 'No details available', - link: '#', - subsection: item.solution_name || 'N/A', - isRead: item.is_read || false, - status: item.is_read ? 'Resolved' : item.is_delivered ? 'Delivered' : 'Pending', - tag: item.error_code, - plc: item.plc || 'N/A', -}); +// Transform API response to component format +const transformNotificationData = (apiData) => { + // Extract nested data + const errorCodeData = apiData.error_code; + const solutionData = errorCodeData?.solution?.[0] || {}; -const getDummyNotificationById = (id) => { - console.log("Fetching dummy data for ID:", id); - // Data mentah dummy, seolah-olah dari API - const rawDummyData = { device_name: 'Compressor C-101', error_code_name: 'High Temperature', error_code: 'TEMP-H-303', device_location: 'Gudang Produksi A', message_error_issue: 'Suhu kompresor terdeteksi melebihi ambang batas aman.', is_delivered: true, plc: 'PLC-UTL-01' }; - // Mengolah data mentah dummy menggunakan transform function - return transformNotificationData(rawDummyData); + return { + id: `notification-${apiData.notification_error_id}-0`, + type: apiData.is_read ? 'resolved' : apiData.is_delivered ? 'warning' : 'critical', + title: errorCodeData?.error_code_name || 'Unknown Device', + issue: errorCodeData?.error_code || 'Unknown Error', + description: apiData.message_error_issue || 'No details available', + timestamp: apiData.created_at ? new Date(apiData.created_at).toLocaleString('id-ID', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }) + ' WIB' : 'N/A', + location: solutionData?.solution_name || 'Location not specified', + details: apiData.message_error_issue || 'No details available', + isRead: apiData.is_read || false, + isDelivered: apiData.is_delivered || false, + isSend: apiData.is_send || false, + status: apiData.is_read ? 'Resolved' : apiData.is_delivered ? 'Delivered' : 'Pending', + tag: errorCodeData?.error_code, + plc: 'N/A', // PLC not available in API response + notification_error_id: apiData.notification_error_id, + error_code_id: apiData.error_code_id, + spareparts: errorCodeData?.spareparts || [], + solution: solutionData, // Include the solution data + error_code: errorCodeData, + }; }; const getIconAndColor = (type) => { @@ -116,20 +124,20 @@ const DetailNotificationTab = () => { const fetchDetail = async () => { try { setLoading(true); - // Ganti dengan fungsi API asli Anda - // const response = await getNotificationById(notificationId); - // setNotification(response.data); - - // Menggunakan data dummy untuk sekarang - const dummyData = getDummyNotificationById(notificationId); - if (dummyData) { - setNotification(dummyData); + + // Fetch using the actual API + const response = await getNotificationDetail(notificationId); + + if (response && response.data) { + const transformedData = transformNotificationData(response.data); + setNotification(transformedData); } else { throw new Error('Notification not found'); } } catch (err) { setError(err.message); + console.error('Error fetching notification detail:', err); } finally { setLoading(false); } @@ -210,9 +218,9 @@ const DetailNotificationTab = () => {
Plant Subsection -
{notification.subsection}
+
{notification.location}
Time -
{notification.timestamp}
+
{notification.timestamp.split(' ')[1]} WIB
@@ -240,7 +248,7 @@ const DetailNotificationTab = () => { - + Handling Guideline Spare Part @@ -251,34 +259,80 @@ const DetailNotificationTab = () => { - - Error 303.pdf - lihat disini - - - SOP Kompresor.pdf - lihat disini - + {notification.solution && ( + <> + {notification.solution.path_document ? ( + PDF}> +
+
+ {notification.solution.file_upload_name || 'Solution Document.pdf'} + lihat disini +
+
+
+ ) : null} + {notification.solution.type_solution === 'text' && notification.solution.text_solution ? ( + {notification.solution.type_solution.toUpperCase()}}> + + {notification.issue}: {notification.solution.text_solution} + + + ) : null} + + )} + {!notification.solution && ( +
+ Tidak ada dokumen solusi tersedia +
+ )}
- - - -
- -
- Available - - - Air Filter - Filters incoming air to remove dust. - -
-
+ {notification.spareparts && notification.spareparts.length > 0 ? ( + notification.spareparts.map((sparepart, index) => ( + + + +
+ +
+ + {sparepart.sparepart_stok} + + + + + {sparepart.sparepart_name} + + {sparepart.sparepart_description || 'Deskripsi tidak tersedia'} + +
+ Kode: {sparepart.sparepart_code} | Qty: {sparepart.sparepart_qty} | Unit: {sparepart.sparepart_unit} +
+
+ +
+
+ )) + ) : ( +
+ Tidak ada spare parts terkait +
+ )}
diff --git a/src/pages/notification/component/DetailNotification.jsx b/src/pages/notification/component/DetailNotification.jsx index 54bad25..d86ff09 100644 --- a/src/pages/notification/component/DetailNotification.jsx +++ b/src/pages/notification/component/DetailNotification.jsx @@ -1,12 +1,29 @@ import React, { memo } from 'react'; import { Row, Col, Tag, Card, Button } from 'antd'; -import { CloseCircleFilled, WarningFilled, CheckCircleFilled, InfoCircleFilled } from '@ant-design/icons'; +import { + CloseCircleFilled, + WarningFilled, + CheckCircleFilled, + InfoCircleFilled, +} from '@ant-design/icons'; const DetailNotification = memo(function DetailNotification({ selectedData, onClose }) { if (!selectedData) { return null; } + // Get error code data from the nested structure + const errorCodeData = selectedData.error_code; + const solutionData = errorCodeData?.solution?.[0] || {}; + const sparepartsData = errorCodeData?.spareparts || []; + + // Determine notification type based on is_read status + const getTypeFromStatus = () => { + if (selectedData.is_read === false) return 'critical'; // Not read yet + if (selectedData.is_delivered === false) return 'warning'; // Not delivered + return 'resolved'; // Read and delivered + }; + const getIconAndColor = (type) => { switch (type) { case 'critical': @@ -40,7 +57,8 @@ const DetailNotification = memo(function DetailNotification({ selectedData, onCl } }; - const { IconComponent, color, bgColor, tagColor } = getIconAndColor(selectedData.type); + const notificationType = getTypeFromStatus(); + const { IconComponent, color, bgColor, tagColor } = getIconAndColor(notificationType); return (
- {selectedData.type.toUpperCase()} + {notificationType.toUpperCase()}
- {selectedData.title} + {errorCodeData?.error_code_name || 'N/A'}
@@ -93,18 +111,20 @@ const DetailNotification = memo(function DetailNotification({ selectedData, onCl
- PLC + Kode Error
- {selectedData.plc} + {errorCodeData?.error_code || 'N/A'}
-
Tag
+
+ ID Notifikasi +
- {selectedData.tag} + {selectedData.notification_error_id || 'N/A'}
@@ -114,48 +134,115 @@ const DetailNotification = memo(function DetailNotification({ selectedData, onCl
- Engineer + Solusi
- {selectedData.engineer} + {solutionData?.solution_name || 'N/A'}
- Waktu + Waktu Dibuat
- {selectedData.time} + {selectedData.created_at + ? new Date(selectedData.created_at).toLocaleString('id-ID', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }) + ' WIB' + : 'N/A'}
- {/* Status */} -
-
Status
- - {selectedData.isRead ? 'Sudah Dibaca' : 'Belum Dibaca'} - -
+ {/* Status Information */} + + +
+
+ Status Kirim +
+ + {selectedData.is_send ? 'Terkirim' : 'Belum Terkirim'} + +
+ + +
+
+ Status Terkirim +
+ + {selectedData.is_delivered ? 'Terkirim' : 'Belum Terkirim'} + +
+ + +
+
+ Status Baca +
+ + {selectedData.is_read ? 'Dibaca' : 'Belum Dibaca'} + +
+ +
- {/* Additional Info */} -
-
- Catatan: Notifikasi ini telah dikirim ke engineer yang bersangkutan - untuk ditindaklanjuti sesuai dengan prosedur yang berlaku. + {/* Description */} +
+
+ Deskripsi Error +
+
+ {selectedData.message_error_issue || 'N/A'}
+ + {/* Spareparts Information */} + {sparepartsData.length > 0 && ( +
+
+ Spareparts Terkait +
+ {sparepartsData.map((sparepart, index) => ( +
+
+ {sparepart.sparepart_name} +
+
+ Kode: {sparepart.sparepart_code} | Stok:{' '} + {sparepart.sparepart_stok} +
+
+ ))} +
+ )}
);