lavoce #27

Merged
bragaz_rexita merged 42 commits from lavoce into main 2025-12-22 09:28:35 +00:00
2 changed files with 141 additions and 48 deletions
Showing only changes of commit bee196e299 - Show all commits

View File

@@ -27,4 +27,29 @@ const getNotificationDetail = async (id) => {
return response.data; return response.data;
}; };
export { getAllNotification, getNotificationById, getNotificationDetail }; // Create new notification log
const createNotificationLog = async (data) => {
const response = await SendRequest({
method: 'post',
prefix: 'notification-log',
params: data,
});
return response.data;
};
// Get notification logs by notification_error_id
const getNotificationLogByNotificationId = async (notificationId) => {
const response = await SendRequest({
method: 'get',
prefix: `notification-log/notification_error/${notificationId}`,
});
return response.data;
};
export {
getAllNotification,
getNotificationById,
getNotificationDetail,
createNotificationLog,
getNotificationLogByNotificationId
};

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom'; import { useParams, useNavigate } from 'react-router-dom';
import { Layout, Card, Row, Col, Typography, Space, Button, Spin, Result, Input } from 'antd'; import { Layout, Card, Row, Col, Typography, Space, Button, Spin, Result, Input, message } from 'antd';
import { import {
ArrowLeftOutlined, ArrowLeftOutlined,
CloseCircleFilled, CloseCircleFilled,
@@ -14,8 +14,9 @@ import {
FilePdfOutlined, FilePdfOutlined,
PlusOutlined, PlusOutlined,
UserOutlined, UserOutlined,
LoadingOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { getNotificationDetail } from '../../api/notification'; import { getNotificationDetail, createNotificationLog, getNotificationLogByNotificationId } from '../../api/notification';
import UserHistoryModal from '../notification/component/UserHistoryModal'; import UserHistoryModal from '../notification/component/UserHistoryModal';
import LogHistoryCard from '../notification/component/LogHistoryCard'; import LogHistoryCard from '../notification/component/LogHistoryCard';
@@ -38,12 +39,12 @@ const transformNotificationData = (apiData) => {
description: apiData.message_error_issue || 'No details available', description: apiData.message_error_issue || 'No details available',
timestamp: apiData.created_at timestamp: apiData.created_at
? new Date(apiData.created_at).toLocaleString('id-ID', { ? new Date(apiData.created_at).toLocaleString('id-ID', {
day: '2-digit', day: '2-digit',
month: '2-digit', month: '2-digit',
year: 'numeric', year: 'numeric',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
}) + ' WIB' }) + ' WIB'
: 'N/A', : 'N/A',
location: apiData.plant_sub_section_name || 'Location not specified', location: apiData.plant_sub_section_name || 'Location not specified',
details: apiData.message_error_issue || 'No details available', details: apiData.message_error_issue || 'No details available',
@@ -61,9 +62,9 @@ const transformNotificationData = (apiData) => {
...activeSolution, ...activeSolution,
path_document: activeSolution.path_document path_document: activeSolution.path_document
? activeSolution.path_document.replace( ? activeSolution.path_document.replace(
'/detail-notification/pdf/', '/detail-notification/pdf/',
'/notification-detail/pdf/' '/notification-detail/pdf/'
) )
: activeSolution.path_document, : activeSolution.path_document,
}, // Include the active solution data with fixed URL }, // Include the active solution data with fixed URL
error_code: errorCodeData, error_code: errorCodeData,
@@ -98,35 +99,77 @@ const NotificationDetailTab = () => {
const [modalContent, setModalContent] = useState(null); // 'user', atau null const [modalContent, setModalContent] = useState(null); // 'user', atau null
const [isAddingLog, setIsAddingLog] = useState(false); const [isAddingLog, setIsAddingLog] = useState(false);
const logHistoryData = [ // Log history states
{ const [logHistoryData, setLogHistoryData] = useState([]);
id: 1, const [logLoading, setLogLoading] = useState(false);
timestamp: '04-11-2025 11:55 WIB', const [newLogDescription, setNewLogDescription] = useState('');
addedBy: { const [submitLoading, setSubmitLoading] = useState(false);
name: 'Budi Santoso',
phone: '081122334455', // Fetch log history from API
}, const fetchLogHistory = async (notifId) => {
description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.', try {
}, setLogLoading(true);
{ const response = await getNotificationLogByNotificationId(notifId);
id: 2, if (response && response.data) {
timestamp: '04-11-2025 11:45 WIB', // Transform API data to component format
addedBy: { const transformedLogs = response.data.map((log) => ({
name: 'John Doe', id: log.notification_error_log_id,
phone: '081234567890', timestamp: log.created_at
}, ? new Date(log.created_at).toLocaleString('id-ID', {
description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.', day: '2-digit',
}, month: '2-digit',
{ year: 'numeric',
id: 3, hour: '2-digit',
timestamp: '04-11-2025 11:40 WIB', minute: '2-digit',
addedBy: { }) + ' WIB'
name: 'Jane Smith', : 'N/A',
phone: '087654321098', addedBy: {
}, name: log.contact_name || 'Unknown',
description: 'Suhu sudah coba diturunkan, namun masih belum mencapai treshold aman.', phone: log.contact_phone || '',
}, },
]; description: log.notification_error_log_description || '',
}));
setLogHistoryData(transformedLogs);
}
} catch (err) {
console.error('Error fetching log history:', err);
} finally {
setLogLoading(false);
}
};
// Handle submit new log
const handleSubmitLog = async () => {
if (!newLogDescription.trim()) {
message.warning('Mohon isi deskripsi log terlebih dahulu');
return;
}
try {
setSubmitLoading(true);
const payload = {
notification_error_id: parseInt(notificationId),
notification_error_log_description: newLogDescription.trim(),
};
const response = await createNotificationLog(payload);
if (response && response.statusCode === 200) {
message.success('Log berhasil ditambahkan');
setNewLogDescription('');
setIsAddingLog(false);
// Refresh log history
fetchLogHistory(notificationId);
} else {
throw new Error(response?.message || 'Gagal menambahkan log');
}
} catch (err) {
console.error('Error submitting log:', err);
message.error(err.message || 'Gagal menambahkan log');
} finally {
setSubmitLoading(false);
}
};
useEffect(() => { useEffect(() => {
const fetchDetail = async () => { const fetchDetail = async () => {
@@ -139,6 +182,9 @@ const NotificationDetailTab = () => {
if (response && response.data) { if (response && response.data) {
const transformedData = transformNotificationData(response.data); const transformedData = transformNotificationData(response.data);
setNotification(transformedData); setNotification(transformedData);
// Fetch log history
fetchLogHistory(notificationId);
} else { } else {
throw new Error('Notification not found'); throw new Error('Notification not found');
} }
@@ -343,7 +389,11 @@ const NotificationDetailTab = () => {
{/* Kolom Kanan: Log History */} {/* Kolom Kanan: Log History */}
<Col xs={24} lg={8}> <Col xs={24} lg={8}>
<LogHistoryCard notificationData={notification} /> <LogHistoryCard
notificationData={notification}
logData={logHistoryData}
loading={logLoading}
/>
</Col> </Col>
</Row> </Row>
@@ -408,7 +458,7 @@ const NotificationDetailTab = () => {
style={{ width: '100%' }} style={{ width: '100%' }}
> >
{notification.error_code?.solution && {notification.error_code?.solution &&
notification.error_code.solution.length > 0 ? ( notification.error_code.solution.length > 0 ? (
<> <>
{notification.error_code.solution {notification.error_code.solution
.filter((sol) => sol.is_active) // Hanya tampilkan solusi yang aktif .filter((sol) => sol.is_active) // Hanya tampilkan solusi yang aktif
@@ -482,7 +532,7 @@ const NotificationDetailTab = () => {
</Card> </Card>
) : null} ) : null}
{sol.type_solution === 'text' && {sol.type_solution === 'text' &&
sol.text_solution ? ( sol.text_solution ? (
<Card <Card
size="small" size="small"
bodyStyle={{ bodyStyle={{
@@ -543,7 +593,7 @@ const NotificationDetailTab = () => {
style={{ width: '100%' }} style={{ width: '100%' }}
> >
{notification.spareparts && {notification.spareparts &&
notification.spareparts.length > 0 ? ( notification.spareparts.length > 0 ? (
notification.spareparts.map((sparepart, index) => ( notification.spareparts.map((sparepart, index) => (
<Card <Card
size="small" size="small"
@@ -581,7 +631,7 @@ const NotificationDetailTab = () => {
color: color:
sparepart.sparepart_stok === sparepart.sparepart_stok ===
'Available' || 'Available' ||
sparepart.sparepart_stok === sparepart.sparepart_stok ===
'available' 'available'
? '#52c41a' ? '#52c41a'
: '#ff4d4f', : '#ff4d4f',
@@ -671,6 +721,9 @@ const NotificationDetailTab = () => {
<Input.TextArea <Input.TextArea
rows={2} rows={2}
placeholder="Tuliskan update penanganan di sini..." placeholder="Tuliskan update penanganan di sini..."
value={newLogDescription}
onChange={(e) => setNewLogDescription(e.target.value)}
disabled={submitLoading}
/> />
</> </>
)} )}
@@ -678,11 +731,26 @@ const NotificationDetailTab = () => {
type={isAddingLog ? 'primary' : 'dashed'} type={isAddingLog ? 'primary' : 'dashed'}
size="small" size="small"
block block
icon={!isAddingLog && <PlusOutlined />} icon={submitLoading ? <LoadingOutlined /> : (!isAddingLog && <PlusOutlined />)}
onClick={() => setIsAddingLog(!isAddingLog)} onClick={isAddingLog ? handleSubmitLog : () => setIsAddingLog(true)}
loading={submitLoading}
disabled={submitLoading}
> >
{isAddingLog ? 'Submit Log' : 'Add Log'} {isAddingLog ? 'Submit Log' : 'Add Log'}
</Button> </Button>
{isAddingLog && (
<Button
size="small"
block
onClick={() => {
setIsAddingLog(false);
setNewLogDescription('');
}}
disabled={submitLoading}
>
Cancel
</Button>
)}
</Space> </Space>
</Card> </Card>
{logHistoryData.map((log) => ( {logHistoryData.map((log) => (