lavoce #40
@@ -10,7 +10,8 @@ const topics = [
|
|||||||
'PIU_COD/COMPRESSOR/OVERVIEW',
|
'PIU_COD/COMPRESSOR/OVERVIEW',
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_A',
|
'PIU_COD/COMPRESSOR/COMPRESSOR_A',
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_B',
|
'PIU_COD/COMPRESSOR/COMPRESSOR_B',
|
||||||
'PIU_COD/COMPRESSOR/COMPRESSOR_C'
|
'PIU_COD/COMPRESSOR/COMPRESSOR_C',
|
||||||
|
'PIU_COD/ERROR_CODE/SIM',
|
||||||
];
|
];
|
||||||
const options = {
|
const options = {
|
||||||
keepalive: 30,
|
keepalive: 30,
|
||||||
@@ -98,4 +99,22 @@ const setValSvg = (listenTopic, svg) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export { publishMessage, listenMessage, setValSvg };
|
// === NOTIFICATION LISTENER ===
|
||||||
|
const notifListeners = [];
|
||||||
|
|
||||||
|
const onNotifUpdate = (callback) => {
|
||||||
|
notifListeners.push(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
client.on('message', (topic, message) => {
|
||||||
|
if (topic === import.meta.env.VITE_MQTT_TOPIC_COD) {
|
||||||
|
try {
|
||||||
|
const payload = JSON.parse(message.toString());
|
||||||
|
notifListeners.forEach((cb) => cb(payload));
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Invalid notif payload', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { publishMessage, listenMessage, setValSvg, onNotifUpdate };
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import {
|
|||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
ExclamationCircleOutlined,
|
ExclamationCircleOutlined,
|
||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
MailFilled,
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { useNavigate, Link as RouterLink } from 'react-router-dom';
|
import { useNavigate, Link as RouterLink } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
@@ -47,9 +46,20 @@ import {
|
|||||||
resendChatAllUser,
|
resendChatAllUser,
|
||||||
searchData,
|
searchData,
|
||||||
} from '../../../api/notification';
|
} from '../../../api/notification';
|
||||||
|
import { onNotifUpdate } from '../../../components/Global/MqttConnection';
|
||||||
|
|
||||||
const { Text, Paragraph, Link: AntdLink } = Typography;
|
const { Text, Paragraph, Link: AntdLink } = Typography;
|
||||||
|
const OpenMail = ({ size = 22, color = 'black' }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 640 640"
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
fill={color}
|
||||||
|
>
|
||||||
|
<path d="M576 480C576 515.3 547.5 544 512.1 544L128 544C92.6 544 64 515.3 64 480L64 228C64.1 212.5 71.8 198 84.5 189.2L270 61.3C300.1 40.6 339.8 40.6 369.9 61.3L555.5 189.2C568.3 198 575.9 212.5 576 228L576 480zM128 496L512.1 496C520.9 496 528 488.9 528 480L528 288.3L373.2 405.7C341.8 429.6 298.3 429.6 266.8 405.7L112 288.3L112 480C112 488.9 119.2 496 128 496zM527.6 228.4L342.7 100.8C329 91.4 311 91.4 297.3 100.8L112.4 228.4L295.8 367.5C310.1 378.3 329.9 378.3 344.2 367.5L527.6 228.4z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
// Transform API response to component format
|
// Transform API response to component format
|
||||||
const transformNotificationData = (apiData) => {
|
const transformNotificationData = (apiData) => {
|
||||||
return apiData.map((item, index) => ({
|
return apiData.map((item, index) => ({
|
||||||
@@ -92,6 +102,7 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
const [activeTab, setActiveTab] = useState('all');
|
const [activeTab, setActiveTab] = useState('all');
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
const [notifTrigger, setNotifTrigger] = useState(0);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
|
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
|
||||||
const [isAddingLog, setIsAddingLog] = useState(false);
|
const [isAddingLog, setIsAddingLog] = useState(false);
|
||||||
@@ -169,6 +180,12 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
fetchNotifications(page, pageSize, isReadFilter);
|
fetchNotifications(page, pageSize, isReadFilter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onNotifUpdate(() => {
|
||||||
|
setNotifTrigger((prev) => prev + 1);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -179,18 +196,18 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
// Fetch notifications on component mount and when tab changes
|
// Fetch notifications on component mount and when tab changes
|
||||||
const isReadFilter = activeTab === 'read' ? 1 : activeTab === 'unread' ? 0 : null;
|
const isReadFilter = activeTab === 'read' ? 1 : activeTab === 'unread' ? 0 : null;
|
||||||
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
|
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
|
||||||
}, [activeTab]);
|
}, [activeTab, notifTrigger]);
|
||||||
|
|
||||||
const getIconAndColor = (type) => {
|
const getIconAndColor = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'critical':
|
case 'critical':
|
||||||
return { IconComponent: MailFilled, color: '#faad14', bgColor: '#fff1f0' };
|
return { IconComponent: MailOutlined, color: '#faad14', bgColor: '#fff1f0' };
|
||||||
case 'warning':
|
case 'warning':
|
||||||
return { IconComponent: MailFilled, color: '#1890ff', bgColor: '#fffbe6' };
|
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#fffbe6' };
|
||||||
case 'resolved':
|
case 'resolved':
|
||||||
return { IconComponent: MailFilled, color: '#52c41a', bgColor: '#f6ffed' };
|
return { IconComponent: MailOutlined, color: '#52c41a', bgColor: '#f6ffed' };
|
||||||
default:
|
default:
|
||||||
return { IconComponent: MailFilled, color: '#1890ff', bgColor: '#e6f7ff' };
|
return { IconComponent: MailOutlined, color: '#1890ff', bgColor: '#e6f7ff' };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -407,7 +424,11 @@ const ListNotification = memo(function ListNotification(props) {
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{notification.type === 'resolved' ? (
|
||||||
|
<OpenMail size={28.5} color={color} />
|
||||||
|
) : (
|
||||||
<IconComponent style={{ fontSize: '22px' }} />
|
<IconComponent style={{ fontSize: '22px' }} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Row align="top">
|
<Row align="top">
|
||||||
|
|||||||
Reference in New Issue
Block a user