From a014d6b3709897bab94c8b450677fc37acb6f404 Mon Sep 17 00:00:00 2001 From: Iqbal Rizqi Kurniawan Date: Tue, 9 Dec 2025 13:32:53 +0700 Subject: [PATCH] feat: replace LogHistoryModal with LogHistoryCard and update DetailNotification for improved log history display --- .../IndexDetailNotification.jsx | 22 +- src/pages/notification/IndexNotification.jsx | 52 ++-- .../component/DetailNotification.jsx | 226 +++++++++--------- .../notification/component/LogHistoryCard.jsx | 90 +++++++ 4 files changed, 238 insertions(+), 152 deletions(-) create mode 100644 src/pages/notification/component/LogHistoryCard.jsx diff --git a/src/pages/detailNotification/IndexDetailNotification.jsx b/src/pages/detailNotification/IndexDetailNotification.jsx index 66f177b..c842ce8 100644 --- a/src/pages/detailNotification/IndexDetailNotification.jsx +++ b/src/pages/detailNotification/IndexDetailNotification.jsx @@ -29,7 +29,7 @@ import { // Path disesuaikan karena lokasi file berubah // import { getNotificationById } from '../../api/notification'; // Dihapus karena belum ada di file API import UserHistoryModal from '../notification/component/UserHistoryModal'; -import LogHistoryModal from '../notification/component/LogHistoryModal'; +import LogHistoryCard from '../notification/component/LogHistoryCard'; // Ganti LogHistoryModal dengan LogHistoryCard const { Content } = Layout; const { Text, Paragraph, Link } = Typography; @@ -79,7 +79,7 @@ const DetailNotificationTab = () => { const [notification, setNotification] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [modalContent, setModalContent] = useState(null); // 'user', 'log', atau null + const [modalContent, setModalContent] = useState(null); // 'user', atau null const [isAddingLog, setIsAddingLog] = useState(false); const logHistoryData = [ @@ -196,7 +196,7 @@ const DetailNotificationTab = () => { {/* Kolom Kiri: Data Kompresor */} - + @@ -224,8 +224,8 @@ const DetailNotificationTab = () => { - {/* Kolom Kanan: Informasi Teknis */} - + {/* Kolom Tengah: Informasi Teknis */} +
PLC
{notification.plc || 'N/A'}
@@ -234,12 +234,17 @@ const DetailNotificationTab = () => {
+ + {/* Kolom Kanan: Log History */} + + +
Handling Guideline Spare Part - setModalContent('log')} style={{ cursor: 'pointer' }}>Log Activity + Log Activity @@ -345,11 +350,6 @@ const DetailNotificationTab = () => { onCancel={() => setModalContent(null)} notificationData={notification} /> - setModalContent(null)} - notificationData={notification} - /> ); }; diff --git a/src/pages/notification/IndexNotification.jsx b/src/pages/notification/IndexNotification.jsx index 664cd45..1f83490 100644 --- a/src/pages/notification/IndexNotification.jsx +++ b/src/pages/notification/IndexNotification.jsx @@ -1,7 +1,7 @@ import React, { memo, useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useBreadcrumb } from '../../layout/LayoutBreadcrumb'; -import { Typography } from 'antd'; +import { Typography, Row, Col } from 'antd'; import ListNotification from './component/ListNotification'; import DetailNotification from './component/DetailNotification'; @@ -10,10 +10,7 @@ const { Text } = Typography; const IndexNotification = memo(function IndexNotification() { const navigate = useNavigate(); const { setBreadcrumbItems } = useBreadcrumb(); - - const [actionMode, setActionMode] = useState('list'); const [selectedData, setSelectedData] = useState(null); - const [isModalVisible, setIsModalVisible] = useState(false); useEffect(() => { const token = localStorage.getItem('token'); @@ -32,33 +29,34 @@ const IndexNotification = memo(function IndexNotification() { } }, [navigate, setBreadcrumbItems]); - useEffect(() => { - if (actionMode === 'preview') { - setIsModalVisible(true); - } else { - setIsModalVisible(false); - } - }, [actionMode]); - - const handleCancel = () => { - setActionMode('list'); + const handleCloseDetail = () => { setSelectedData(null); }; + // This handler will be passed to ListNotification to update the selected item + const handleSelectNotification = (data) => { + setSelectedData(data); + }; + return ( - - - - + + + {}} // Keep prop for safety, but can be empty + setSelectedData={handleSelectNotification} + /> + + {selectedData && ( + + + + )} + ); }); diff --git a/src/pages/notification/component/DetailNotification.jsx b/src/pages/notification/component/DetailNotification.jsx index 2f19a7e..3ec4c77 100644 --- a/src/pages/notification/component/DetailNotification.jsx +++ b/src/pages/notification/component/DetailNotification.jsx @@ -1,8 +1,12 @@ import React, { memo } from 'react'; -import { Modal, Row, Col, Tag, Divider } from 'antd'; +import { Row, Col, Tag, Divider, Card, Button } from 'antd'; import { CloseCircleFilled, WarningFilled, CheckCircleFilled, InfoCircleFilled } from '@ant-design/icons'; -const DetailNotification = memo(function DetailNotification({ visible, onCancel, form, selectedData }) { +const DetailNotification = memo(function DetailNotification({ selectedData, onClose }) { + if (!selectedData) { + return null; + } + const getIconAndColor = (type) => { switch (type) { case 'critical': @@ -36,133 +40,127 @@ const DetailNotification = memo(function DetailNotification({ visible, onCancel, } }; - const { IconComponent, color, bgColor, tagColor } = selectedData ? getIconAndColor(selectedData.type) : {}; + const { IconComponent, color, bgColor, tagColor } = getIconAndColor(selectedData.type); return ( - Tutup} + style={{ height: '100%' }} > - {selectedData && ( -
- {/* Header with Icon and Status */} +
+ {/* Header with Icon and Status */} +
-
- {IconComponent && } -
-
- - {selectedData.type.toUpperCase()} - -
- {selectedData.title} -
-
+ {IconComponent && }
- - - - {/* Information Grid */} - - -
-
- PLC -
-
- {selectedData.plc} -
-
- - -
-
Tag
-
- {selectedData.tag} -
-
- -
- - - -
-
- Engineer -
-
- {selectedData.engineer} -
-
- - -
-
- Waktu -
-
- {selectedData.time} -
-
- -
- - - - {/* Status */} -
-
Status
- - {selectedData.isRead ? 'Sudah Dibaca' : 'Belum Dibaca'} +
+ + {selectedData.type.toUpperCase()} -
- - {/* Additional Info */} -
-
- Catatan: Notifikasi ini telah dikirim ke engineer yang bersangkutan - untuk ditindaklanjuti sesuai dengan prosedur yang berlaku. +
+ {selectedData.title}
- )} - + + + + {/* Information Grid */} + + +
+
+ PLC +
+
+ {selectedData.plc} +
+
+ + +
+
Tag
+
+ {selectedData.tag} +
+
+ +
+ + + +
+
+ Engineer +
+
+ {selectedData.engineer} +
+
+ + +
+
+ Waktu +
+
+ {selectedData.time} +
+
+ +
+ + + + {/* Status */} +
+
Status
+ + {selectedData.isRead ? 'Sudah Dibaca' : 'Belum Dibaca'} + +
+ + {/* Additional Info */} +
+
+ Catatan: Notifikasi ini telah dikirim ke engineer yang bersangkutan + untuk ditindaklanjuti sesuai dengan prosedur yang berlaku. +
+
+
+ ); }); diff --git a/src/pages/notification/component/LogHistoryCard.jsx b/src/pages/notification/component/LogHistoryCard.jsx new file mode 100644 index 0000000..0be9a09 --- /dev/null +++ b/src/pages/notification/component/LogHistoryCard.jsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { Card, Table, Tag, Typography } from 'antd'; +import { ClockCircleOutlined } from '@ant-design/icons'; +import dayjs from 'dayjs'; + +const { Text } = Typography; + +const getDummyLogHistory = (notification) => { + if (!notification) return []; + return [ + { + key: '1', + timestamp: dayjs().subtract(2, 'hour').format('DD-MM-YYYY HH:mm:ss'), + activity: 'Notification Created', + details: `System generated a ${notification.type} notification for: ${notification.issue}`, + }, + { + key: '2', + timestamp: dayjs().subtract(1, 'hour').format('DD-MM-YYYY HH:mm:ss'), + activity: 'Notification Sent', + details: 'Sent to 2 engineers', + }, + { + key: '3', + timestamp: dayjs().subtract(30, 'minute').format('DD-MM-YYYY HH:mm:ss'), + activity: 'Notification Read', + details: 'Read by Engineer A', + }, + { + key: '4', + timestamp: dayjs().subtract(5, 'minute').format('DD-MM-YYYY HH:mm:ss'), + activity: 'Resend Triggered', + details: 'Notification resent by Admin', + }, + ]; +}; + +const columns = [ + { + title: 'Timestamp', + dataIndex: 'timestamp', + key: 'timestamp', + render: (text) => ( + + + {text} + + ), + }, + { + title: 'Activity', + dataIndex: 'activity', + key: 'activity', + render: (text) => { + let color = 'blue'; + if (text.includes('Created')) { + color = 'geekblue'; + } else if (text.includes('Sent')) { + color = 'purple'; + } else if (text.includes('Read')) { + color = 'green'; + } else if (text.includes('Triggered')) { + color = 'orange'; + } + return {text.toUpperCase()}; + }, + }, + { + title: 'Details', + dataIndex: 'details', + key: 'details', + }, +]; + +const LogHistoryCard = ({ notificationData }) => { + const logHistoryData = getDummyLogHistory(notificationData); + + return ( + + + + ); +}; + +export default LogHistoryCard;