import React, { memo, useState, useEffect } from 'react'; import { Button, Row, Col, Card, Badge, Input, Typography, Space, Divider, Modal, Tag, message } from 'antd'; import { CloseCircleFilled, WarningFilled, CheckCircleFilled, InfoCircleFilled, ClockCircleOutlined, EnvironmentOutlined, LinkOutlined, SendOutlined, MailOutlined, UserOutlined, HistoryOutlined, EyeOutlined, MobileOutlined, CloseOutlined, BookOutlined, ToolOutlined, FilePdfOutlined, PlusOutlined, ExclamationCircleOutlined, } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; const { Text, Paragraph, Link } = Typography; // Dummy data untuk notifikasi device const initialDeviceNotifications = [ { id: 1, type: 'critical', title: 'Compressor Unit A', issue: 'Overheat detected (85°C)', description: '⚠️ Compressor Unit A - Overheat Detected (85°C) 🚨', timestamp: '04-11-2025 11.39 WIB', location: 'Lantai 2, Area Produksi A, Zona 3', details: 'Terjadi kenaikan suhu melebihi ambang batas pada Compressor Unit A. Pengecekan potensi kerusakan dibutuhkan.', link: 'https://tinyurl.com/compA85', subsection: 'Air Dryer A', value: '85° C', threshold: '≤75° C', isRead: false, plc: 'PLC-001', status: 'Butuh Info lebih', tag: 'A1-TEMP', }, { id: 2, type: 'warning', title: 'Compressor Unit C', issue: 'Pressure slightly high (7.2 bar)', description: '🔧 Compressor Unit C - Pressure High (7.2 bar)', timestamp: '04-11-2025 11.30 WIB', location: 'Lantai 1, Area Produksi C, Zona 1', details: 'Tekanan mendekati ambang batas atas. Perlu monitoring lebih lanjut oleh engineer.', link: 'https://tinyurl.com/compC72', subsection: 'Main Compressor', value: '7.2 bar', threshold: '<7.5 bar', isRead: false, plc: 'PLC-002', status: 'Monitoring', tag: 'C1-PRESSURE', }, { id: 3, type: 'resolved', title: 'Compressor Unit B', issue: 'Vibration issue resolved', description: '✅ Compressor Unit B - Vibration Resolved', timestamp: '04-11-2025 10.05 WIB', location: 'Lantai 2, Area Produksi B, Zona 2', details: 'Getaran pada Unit B telah kembali normal setelah perbaikan.', link: 'https://tinyurl.com/compBresolved', subsection: 'Motor Bearing', value: 'Normal', threshold: 'N/A', isRead: true, plc: 'PLC-003', status: 'Resolved', tag: 'B1-VIBRATION', }, ]; // Dummy data untuk user history const userHistoryData = [ { id: 1, name: 'John Doe', phone: '081234567890', status: 'Delivered', timestamp: '04-11-2025 11:40 WIB' }, { id: 2, name: 'Jane Smith', phone: '087654321098', status: 'Delivered', timestamp: '04-11-2025 11:41 WIB' }, { id: 3, name: 'Peter Jones', phone: '082345678901', status: 'Delivered', timestamp: '04-11-2025 11:42 WIB' }, ]; // Dummy data untuk log history const logHistoryData = [ { id: 1, timestamp: '04-11-2025 11:55 WIB', addedBy: { name: 'Budi Santoso', phone: '081122334455' }, description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.' }, { id: 2, timestamp: '04-11-2025 11:45 WIB', addedBy: { name: 'John Doe', phone: '081234567890' }, description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.', }, { id: 3, timestamp: '04-11-2025 11:40 WIB', addedBy: { name: 'Jane Smith', phone: '087654321098' }, description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.', } ]; const ListNotification = memo(function ListNotification(props) { const [notifications, setNotifications] = useState(initialDeviceNotifications); const [activeTab, setActiveTab] = useState('all'); const [searchTerm, setSearchTerm] = useState(''); const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null const [isAddingLog, setIsAddingLog] = useState(false); const [selectedNotification, setSelectedNotification] = useState(null); const navigate = useNavigate(); useEffect(() => { const token = localStorage.getItem('token'); if (!token) { navigate('/signin'); } }, [navigate]); const getIconAndColor = (type) => { switch (type) { case 'critical': return { IconComponent: CloseCircleFilled, color: '#ff4d4f', bgColor: '#fff1f0' }; case 'warning': return { IconComponent: WarningFilled, color: '#faad14', bgColor: '#fffbe6' }; case 'resolved': return { IconComponent: CheckCircleFilled, color: '#52c41a', bgColor: '#f6ffed' }; default: return { IconComponent: InfoCircleFilled, color: '#1890ff', bgColor: '#e6f7ff' }; } }; const handleResend = (notification) => { Modal.confirm({ title: 'Confirm Resend', icon: , content: `Are you sure you want to resend the notification for "${notification.title}"?`, okText: 'Resend', cancelText: 'Cancel', onOk() { console.log('Resending notification:', notification.id); // Di sini Anda bisa menambahkan logika pemanggilan API message.success(`Notification for "${notification.title}" has been resent successfully.`); }, onCancel() { console.log('Resend cancelled'); }, }); }; const handleMarkAsRead = (id) => { setNotifications((prev) => prev.map((n) => (n.id === id ? { ...n, isRead: true } : n)) ); }; const filteredNotifications = notifications .filter(n => (activeTab === 'all' || (activeTab === 'unread' && !n.isRead) || (activeTab === 'read' && n.isRead))) .filter(n => { if (!searchTerm) return true; const searchableText = `${n.title} ${n.issue} ${n.description} ${n.location} ${n.details}`.toLowerCase(); return searchableText.includes(searchTerm.toLowerCase()); }); const getUnreadCount = () => notifications.filter((n) => !n.isRead).length; const tabButtonStyle = (isActive) => ({ padding: '12px 16px', border: 'none', background: 'none', cursor: 'pointer', fontSize: '14px', fontWeight: 500, color: isActive ? '#FF6B35' : '#595959', borderBottom: isActive ? '2px solid #FF6B35' : '2px solid transparent', marginBottom: '-1px', transition: 'all 0.3s', }); const renderDeviceNotifications = () => ( {filteredNotifications.length === 0 ? (
Tidak ada notifikasi
) : ( filteredNotifications.map((notification) => { const { IconComponent, color, bgColor } = getIconAndColor(notification.type); return ( handleMarkAsRead(notification.id)} >
{notification.title}
{notification.issue}
{!notification.isRead && }
{notification.description}
{notification.details}
{notification.timestamp} {notification.location} {notification.link}
); }) )}
); const renderUserHistory = () => ( <> {userHistoryData.map(user => ( {user.name} | {user.phone} | Success Delivered at {user.timestamp} ))} ); const renderLogHistory = () => ( <>
{/* Garis vertikal yang menyambung */}
{logHistoryData.map((log, index) => ( {/* Kolom Kiri: Branch/Timeline */}
{/* Kolom Kanan: Card */} Added at {log.timestamp}
Added by: {log.addedBy.name} {log.addedBy.phone}
{log.description}
))}
); const renderDetailsNotification = () => { if (!selectedNotification) return null; const { IconComponent, color } = getIconAndColor(selectedNotification.type); return ( {/* Kolom Kiri: Data Kompresor */}
{selectedNotification.title}
{selectedNotification.issue}
Plant Subsection
{selectedNotification.subsection}
Time
{selectedNotification.timestamp.split(' ')[1]} WIB
Value
{selectedNotification.value.includes('°') ? selectedNotification.value : `${selectedNotification.value}° C`}
Treshold
{selectedNotification.threshold.includes('°') ? selectedNotification.threshold : `${selectedNotification.threshold}° C`}
{/* Kolom Kanan: Informasi Teknis */}
PLC
{selectedNotification.plc}
Status
{selectedNotification.status}
Tag
{selectedNotification.tag}
Handling Guideline Spare Part setModalContent('log')}> Log Activity PDF} >
Error 303.pdf lihat disini
PDF} >
Error 303.pdf lihat disini
PDF} >
Error 303.pdf lihat disini
Text} > Error 303: Sensor suhu tidak merespon. Lakukan reset manual pada panel kontrol.
Available Air Filter Filters incoming air to remove dust and impurities before compression.
Part No: AF-2024-X2 | Condition: New | Compatible with Model XR-60
Not Available Compressor Oil Special synthetic oil to lubricate and cool down the compressor unit.
Part No: OL-SYN-550 | Condition: New | Compatible with Model XR-60
{isAddingLog && ( <> Add New Log / Update Progress )} {logHistoryData.slice(0, 2).map(log => ( // Menampilkan 2 log terbaru sebagai pratinjau {log.addedBy.name}: {log.description} {log.timestamp} ))}
); }; return (

Notification

Riwayat notifikasi yang dikirim ke engineer

setSearchTerm(e.target.value)} style={{ width: 300 }} />
{renderDeviceNotifications()}
{modalContent === 'details' ? (
Error Notification Detail
) : ( {modalContent === 'user' && 'User History Notification'} {modalContent === 'log' && 'Log History Notification'} )} } open={modalContent !== null} onCancel={() => { setModalContent(null); // Reset state isAddingLog saat modal ditutup if (modalContent === 'details') { setIsAddingLog(false); } setSelectedNotification(null); }} closable={false} // Menghilangkan tombol 'x' di pojok kanan atas width={modalContent === 'details' ? 900 : 700} footer={
} > {modalContent === 'user' && renderUserHistory()} {modalContent === 'log' && renderLogHistory()} {modalContent === 'details' && renderDetailsNotification()}
); }); export default ListNotification;