From 034cf636f903533c8e2b80898fcfa87d387e2059 Mon Sep 17 00:00:00 2001 From: Fachba Date: Thu, 23 Oct 2025 15:57:26 +0700 Subject: [PATCH] Slicing menu history alarm and event alarm --- src/App.jsx | 11 +- src/pages/eventAlarm/IndexEventAlarm.jsx | 72 ----- .../eventAlarm/component/DetailEventAlarm.jsx | 58 ---- src/pages/history/alarm/IndexHistoryAlarm.jsx | 38 +++ .../alarm/component/ListHistoryAlarm.jsx | 128 ++++++++ src/pages/history/event/IndexHistoryEvent.jsx | 38 +++ .../event/component/ListHistoryEvent.jsx} | 130 ++------ src/pages/history/report/IndexReport.jsx | 275 ---------------- src/pages/history/trending/IndexTrending.jsx | 297 ------------------ src/pages/report/report/IndexReport.jsx | 38 +++ .../report/report/component/ListReport.jsx | 163 ++++++++++ src/pages/report/trending/IndexTrending.jsx | 38 +++ src/pages/report/trending/ReportTrending.jsx | 222 +++++++++++++ .../{history => report}/trending/trending.css | 0 14 files changed, 692 insertions(+), 816 deletions(-) delete mode 100644 src/pages/eventAlarm/IndexEventAlarm.jsx delete mode 100644 src/pages/eventAlarm/component/DetailEventAlarm.jsx create mode 100644 src/pages/history/alarm/IndexHistoryAlarm.jsx create mode 100644 src/pages/history/alarm/component/ListHistoryAlarm.jsx create mode 100644 src/pages/history/event/IndexHistoryEvent.jsx rename src/pages/{eventAlarm/component/ListEventAlarm.jsx => history/event/component/ListHistoryEvent.jsx} (51%) delete mode 100644 src/pages/history/report/IndexReport.jsx delete mode 100644 src/pages/history/trending/IndexTrending.jsx create mode 100644 src/pages/report/report/IndexReport.jsx create mode 100644 src/pages/report/report/component/ListReport.jsx create mode 100644 src/pages/report/trending/IndexTrending.jsx create mode 100644 src/pages/report/trending/ReportTrending.jsx rename src/pages/{history => report}/trending/trending.css (100%) diff --git a/src/App.jsx b/src/App.jsx index 7be1e99..ae251bd 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -23,12 +23,11 @@ import IndexShift from './pages/master/shift/IndexShift'; import IndexJadwalShift from './pages/jadwalShift/IndexJadwalShift'; // History -import IndexTrending from './pages/history/trending/IndexTrending'; -import IndexReport from './pages/history/report/IndexReport'; +import IndexTrending from './pages/report/trending/IndexTrending'; +import IndexReport from './pages/report/report/IndexReport'; // Other Pages import IndexNotification from './pages/notification/IndexNotification'; -import IndexEventAlarm from './pages/eventAlarm/IndexEventAlarm'; import IndexRole from './pages/role/IndexRole'; import IndexUser from './pages/user/IndexUser'; @@ -40,6 +39,8 @@ import SvgCompressorC from './pages/home/SvgCompressorC'; import SvgAirDryerA from './pages/home/SvgAirDryerA'; import SvgAirDryerB from './pages/home/SvgAirDryerB'; import SvgAirDryerC from './pages/home/SvgAirDryerC'; +import IndexHistoryAlarm from './pages/history/alarm/IndexHistoryAlarm'; +import IndexHistoryEvent from './pages/history/event/IndexHistoryEvent'; const App = () => { return ( @@ -84,8 +85,8 @@ const App = () => { }> - } /> - } /> + } /> + } /> }> diff --git a/src/pages/eventAlarm/IndexEventAlarm.jsx b/src/pages/eventAlarm/IndexEventAlarm.jsx deleted file mode 100644 index c33939a..0000000 --- a/src/pages/eventAlarm/IndexEventAlarm.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { memo, useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useBreadcrumb } from '../../layout/LayoutBreadcrumb'; -import { Form, Typography } from 'antd'; -import ListEventAlarm from './component/ListEventAlarm'; -import DetailEventAlarm from './component/DetailEventAlarm'; - -const { Text } = Typography; - -const IndexEventAlarm = memo(function IndexEventAlarm() { - const navigate = useNavigate(); - const { setBreadcrumbItems } = useBreadcrumb(); - const [form] = Form.useForm(); - - const [actionMode, setActionMode] = useState('list'); - const [selectedData, setSelectedData] = useState(null); - const [isModalVisible, setIsModalVisible] = useState(false); - - useEffect(() => { - const token = localStorage.getItem('token'); - if (token) { - setBreadcrumbItems([ - { - title: ( - - • Event Alarm - - ), - }, - ]); - } else { - navigate('/signin'); - } - }, [navigate, setBreadcrumbItems]); - - useEffect(() => { - if (actionMode === 'preview') { - setIsModalVisible(true); - if (selectedData) { - form.setFieldsValue(selectedData); - } - } else { - setIsModalVisible(false); - form.resetFields(); - } - }, [actionMode, selectedData, form]); - - const handleCancel = () => { - setActionMode('list'); - setSelectedData(null); - form.resetFields(); - }; - - return ( - - - - - ); -}); - -export default IndexEventAlarm; diff --git a/src/pages/eventAlarm/component/DetailEventAlarm.jsx b/src/pages/eventAlarm/component/DetailEventAlarm.jsx deleted file mode 100644 index 0a0b487..0000000 --- a/src/pages/eventAlarm/component/DetailEventAlarm.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { memo } from 'react'; -import { Modal, Divider, Descriptions } from 'antd'; - -const DetailEventAlarm = memo(function DetailEventAlarm({ visible, onCancel, selectedData }) { - return ( - - {selectedData && ( -
- - - {selectedData.tanggal} - - - {selectedData.plant_sub_section} - - - {selectedData.device} - - - {selectedData.tag} - - - {selectedData.engineer} - - - - - - {/* Additional Info */} -
-
- Catatan: Event alarm ini telah tercatat dalam sistem untuk - monitoring dan analisis lebih lanjut. -
-
-
- )} -
- ); -}); - -export default DetailEventAlarm; diff --git a/src/pages/history/alarm/IndexHistoryAlarm.jsx b/src/pages/history/alarm/IndexHistoryAlarm.jsx new file mode 100644 index 0000000..1fca140 --- /dev/null +++ b/src/pages/history/alarm/IndexHistoryAlarm.jsx @@ -0,0 +1,38 @@ +import React, { memo, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; +import { Typography } from 'antd'; +import ListHistoryAlarm from './component/ListHistoryAlarm'; + +const { Text } = Typography; + +const IndexHistoryAlarm = memo(function IndexHistoryAlarm() { + const navigate = useNavigate(); + const { setBreadcrumbItems } = useBreadcrumb(); + const [selectedData, setSelectedData] = useState(null); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (token) { + setBreadcrumbItems([ + { + title: ( + + • History Event + + ), + }, + ]); + } else { + navigate('/signin'); + } + }, [navigate, setBreadcrumbItems]); + + return ( + + + + ); +}); + +export default IndexHistoryAlarm; diff --git a/src/pages/history/alarm/component/ListHistoryAlarm.jsx b/src/pages/history/alarm/component/ListHistoryAlarm.jsx new file mode 100644 index 0000000..e11124a --- /dev/null +++ b/src/pages/history/alarm/component/ListHistoryAlarm.jsx @@ -0,0 +1,128 @@ +import React, { memo, useState, useEffect } from 'react'; +import { Button, Row, Col, Card, Input } from 'antd'; +import { SearchOutlined } from '@ant-design/icons'; +import TableList from '../../../../components/Global/TableList'; + +const ListHistoryAlarm = memo(function ListHistoryAlarm(props) { + const columns = [ + { + title: 'No', + key: 'no', + width: '5%', + align: 'center', + render: (_, __, index) => index + 1, + }, + { + title: 'Datetime', + dataIndex: 'datetime', + key: 'datetime', + width: '10%', + }, + { + title: 'Tag Name', + dataIndex: 'tag_name', + key: 'tag_name', + width: '40%', + }, + { + title: 'Value', + dataIndex: 'stat', + key: 'stat', + width: '10%', + }, + { + title: 'Threshold', + dataIndex: 'threshold', + key: 'threshold', + width: '10%', + }, + { + title: 'Condition', + dataIndex: 'condition', + key: 'condition', + width: '20%', + }, + { + title: 'Stat', + dataIndex: 'stat', + key: 'stat', + width: '5%', + }, + ]; + + const [trigerFilter, setTrigerFilter] = useState(false); + + const defaultFilter = { search: '' }; + const [formDataFilter, setFormDataFilter] = useState(defaultFilter); + const [searchValue, setSearchValue] = useState(''); + + const getAllEventAlarm = async (params) => { + return { + data: [], + }; + }; + + const handleSearch = () => { + setFormDataFilter({ search: searchValue }); + setTrigerFilter((prev) => !prev); + }; + + const handleSearchClear = () => { + setSearchValue(''); + setFormDataFilter({ search: '' }); + setTrigerFilter((prev) => !prev); + }; + + return ( + + + + + + + { + const value = e.target.value; + setSearchValue(value); + if (value === '') { + handleSearchClear(); + } + }} + onSearch={handleSearch} + allowClear={{ + clearIcon: , + }} + enterButton={ + + } + size="large" + /> + + + + + + + + + + ); +}); + +export default ListHistoryAlarm; diff --git a/src/pages/history/event/IndexHistoryEvent.jsx b/src/pages/history/event/IndexHistoryEvent.jsx new file mode 100644 index 0000000..8a734d4 --- /dev/null +++ b/src/pages/history/event/IndexHistoryEvent.jsx @@ -0,0 +1,38 @@ +import React, { memo, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; +import { Typography } from 'antd'; +import ListHistoryEvent from './component/ListHistoryEvent'; + +const { Text } = Typography; + +const IndexHistoryEvent = memo(function IndexHistoryEvent() { + const navigate = useNavigate(); + const { setBreadcrumbItems } = useBreadcrumb(); + const [selectedData, setSelectedData] = useState(null); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (token) { + setBreadcrumbItems([ + { + title: ( + + • History Event + + ), + }, + ]); + } else { + navigate('/signin'); + } + }, [navigate, setBreadcrumbItems]); + + return ( + + + + ); +}); + +export default IndexHistoryEvent; diff --git a/src/pages/eventAlarm/component/ListEventAlarm.jsx b/src/pages/history/event/component/ListHistoryEvent.jsx similarity index 51% rename from src/pages/eventAlarm/component/ListEventAlarm.jsx rename to src/pages/history/event/component/ListHistoryEvent.jsx index 394ca63..45f60a4 100644 --- a/src/pages/eventAlarm/component/ListEventAlarm.jsx +++ b/src/pages/history/event/component/ListHistoryEvent.jsx @@ -1,70 +1,9 @@ import React, { memo, useState, useEffect } from 'react'; import { Button, Row, Col, Card, Input } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; -import { useNavigate } from 'react-router-dom'; -import TableList from '../../../components/Global/TableList'; +import TableList from '../../../../components/Global/TableList'; -// Dummy data untuk riwayat alarm -const initialAlarmsData = [ - { - alarm_id: 1, - tanggal: '2025-01-15 08:30:00', - plant_sub_section: 'Plant A - Section 1', - device: 'Device 001', - tag: 'TEMP-001', - engineer: 'Pras', - }, - { - alarm_id: 2, - tanggal: '2025-01-15 09:15:00', - plant_sub_section: 'Plant B - Section 2', - device: 'Device 002', - tag: 'PRESS-002', - engineer: 'Bagus', - }, - { - alarm_id: 3, - tanggal: '2025-01-15 10:00:00', - plant_sub_section: 'Plant A - Section 3', - device: 'Device 003', - tag: 'FLOW-003', - engineer: 'iqbal', - }, - { - alarm_id: 4, - tanggal: '2025-01-15 11:45:00', - plant_sub_section: 'Plant C - Section 1', - device: 'Device 004', - tag: 'LEVEL-004', - engineer: 'riski', - }, - { - alarm_id: 5, - tanggal: '2025-01-15 13:20:00', - plant_sub_section: 'Plant B - Section 3', - device: 'Device 005', - tag: 'TEMP-005', - engineer: 'anton', - }, - { - alarm_id: 6, - tanggal: '2025-01-15 14:00:00', - plant_sub_section: 'Plant A - Section 2', - device: 'Device 006', - tag: 'PRESS-006', - engineer: 'kurniawan', - }, - { - alarm_id: 7, - tanggal: '2025-01-15 15:30:00', - plant_sub_section: 'Plant C - Section 2', - device: 'Device 007', - tag: 'FLOW-007', - engineer: 'wawan', - }, -]; - -const ListEventAlarm = memo(function ListEventAlarm(props) { +const ListHistoryEvent = memo(function ListHistoryEvent(props) { const columns = [ { title: 'No', @@ -74,33 +13,27 @@ const ListEventAlarm = memo(function ListEventAlarm(props) { render: (_, __, index) => index + 1, }, { - title: 'Tanggal', - dataIndex: 'tanggal', - key: 'tanggal', - width: '15%', + title: 'Datetime', + dataIndex: 'datetime', + key: 'datetime', + width: '10%', }, { - title: 'Plant Sub Section', - dataIndex: 'plant_sub_section', - key: 'plant_sub_section', - width: '25%', + title: 'Tag Name', + dataIndex: 'tag_name', + key: 'tag_name', + width: '40%', }, { - title: 'Device', - dataIndex: 'device', - key: 'device', - width: '15%', + title: 'Stat', + dataIndex: 'stat', + key: 'stat', + width: '5%', }, { - title: 'Tag', - dataIndex: 'tag', - key: 'tag', - width: '15%', - }, - { - title: 'Engineer', - dataIndex: 'engineer', - key: 'engineer', + title: 'Description', + dataIndex: 'description', + key: 'description', width: '15%', }, ]; @@ -111,31 +44,12 @@ const ListEventAlarm = memo(function ListEventAlarm(props) { const [formDataFilter, setFormDataFilter] = useState(defaultFilter); const [searchValue, setSearchValue] = useState(''); - const navigate = useNavigate(); - - // Dummy data function to simulate API call const getAllEventAlarm = async (params) => { return { - data: initialAlarmsData, + data: [], }; }; - useEffect(() => { - const token = localStorage.getItem('token'); - if (token) { - if (props.actionMode == 'list') { - setFormDataFilter(defaultFilter); - doFilter(); - } - } else { - navigate('/signin'); - } - }, [props.actionMode]); - - const doFilter = () => { - setTrigerFilter((prev) => !prev); - }; - const handleSearch = () => { setFormDataFilter({ search: searchValue }); setTrigerFilter((prev) => !prev); @@ -155,15 +69,13 @@ const ListEventAlarm = memo(function ListEventAlarm(props) { { const value = e.target.value; setSearchValue(value); - // Auto search when clearing by backspace/delete if (value === '') { - setFormDataFilter({ search: '' }); - setTrigerFilter((prev) => !prev); + handleSearchClear(); } }} onSearch={handleSearch} @@ -201,4 +113,4 @@ const ListEventAlarm = memo(function ListEventAlarm(props) { ); }); -export default ListEventAlarm; +export default ListHistoryEvent; diff --git a/src/pages/history/report/IndexReport.jsx b/src/pages/history/report/IndexReport.jsx deleted file mode 100644 index 00a4149..0000000 --- a/src/pages/history/report/IndexReport.jsx +++ /dev/null @@ -1,275 +0,0 @@ -import React, { memo, useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; -import { Typography, Table, Card, Select, DatePicker, Button, Row, Col } from 'antd'; -import { FileTextOutlined } from '@ant-design/icons'; -import { decryptData } from '../../../components/Global/Formatter'; -import dayjs from 'dayjs'; - -const { Text } = Typography; - -// New data structure for tag history -const tagHistoryData = [ - { - tag: 'TEMP_SENSOR_1', - color: '#FF6B4A', - history: [ - { timestamp: '2025-10-09 08:00', value: 75 }, - { timestamp: '2025-10-09 08:05', value: 76 }, - { timestamp: '2025-10-09 08:10', value: 75 }, - ], - }, - { - tag: 'GAS_LEAK_SENSOR_1', - color: '#4ECDC4', - history: [ - { timestamp: '2025-10-09 08:00', value: 10 }, - { timestamp: '2025-10-09 08:05', value: 150 }, - { timestamp: '2025-10-09 08:10', value: 12 }, - ], - }, - { - tag: 'PRESSURE_SENSOR_1', - color: '#FFE66D', - history: [ - { timestamp: '2025-10-09 08:00', value: 1.2 }, - { timestamp: '2025-10-09 08:05', value: 1.3 }, - { timestamp: '2025-10-09 08:10', value: 1.2 }, - ], - }, -]; - -const IndexReport = memo(function IndexReport() { - const navigate = useNavigate(); - const { setBreadcrumbItems } = useBreadcrumb(); - - const [plantSubSection, setPlantSubSection] = useState('Semua Plant'); - const [startDate, setStartDate] = useState(dayjs('2025-09-30')); - const [endDate, setEndDate] = useState(dayjs('2025-10-09')); - const [periode, setPeriode] = useState('30 Menit'); - const [userRole, setUserRole] = useState(null); - const [roleLevel, setRoleLevel] = useState(null); - - useEffect(() => { - const token = localStorage.getItem('token'); - if (token) { - // Get user data and role - let userData = null; - const sessionData = localStorage.getItem('session'); - if (sessionData) { - userData = decryptData(sessionData); - } else { - const userRaw = localStorage.getItem('user'); - if (userRaw) { - try { - userData = { user: JSON.parse(userRaw) }; - } catch (e) { - console.error('Error parsing user data:', e); - } - } - } - - if (userData?.user) { - setUserRole(userData.user.role_name); - setRoleLevel(userData.user.role_level); - } - - setBreadcrumbItems([ - { - title: ( - - • History - - ), - }, - { - title: ( - - Report - - ), - }, - ]); - } else { - navigate('/signin'); - } - }, []); - - const handleReset = () => { - setPlantSubSection('Semua Plant'); - setStartDate(dayjs('2025-09-30')); - setEndDate(dayjs('2025-10-09')); - setPeriode('30 Menit'); - }; - - // Check if user has permission to view data (all except guest) - const canViewData = userRole && userRole !== 'guest'; - - // Convert tag history data to table format - const convertToTableData = () => { - const timestamps = {}; // Use an object to collect data per timestamp - - tagHistoryData.forEach((tagData) => { - tagData.history.forEach((point) => { - if (!timestamps[point.timestamp]) { - timestamps[point.timestamp] = { - key: point.timestamp, - 'Date and Time': point.timestamp, - }; - } - timestamps[point.timestamp][tagData.tag] = point.value; - }); - }); - - // Convert the object to an array - return Object.values(timestamps); - }; - - const tableData = convertToTableData(); - - // Create dynamic columns based on tags - const tags = tagHistoryData.map((tagData) => tagData.tag); - - const columns = [ - { - title: 'Date and Time', - dataIndex: 'Date and Time', - key: 'Date and Time', - fixed: 'left', - width: 180, - render: (text) => {text}, - }, - ...tags.map((tag) => ({ - title: tag, - dataIndex: tag, - key: tag, - align: 'center', - width: 150, - render: (value) => {value !== undefined ? value : '-'}, - })), - ]; - - return ( - -
- {/* Filter Section */} - -
- - ☰ Filter Data - -
- - -
- - Plant Sub Section - - -
- -
- - - - - - - - -
- {/* Table Section */} - {/* {!canViewData ? ( - - - Anda tidak memiliki akses untuk melihat data report. -
- Silakan hubungi administrator untuk mendapatkan akses. -
-
- ) : ( */} - -
- - ☰ History Report - -
- - - {/* )} */} - - - ); -}); - -export default IndexReport; diff --git a/src/pages/history/trending/IndexTrending.jsx b/src/pages/history/trending/IndexTrending.jsx deleted file mode 100644 index 83e1cb0..0000000 --- a/src/pages/history/trending/IndexTrending.jsx +++ /dev/null @@ -1,297 +0,0 @@ -import React, { memo, useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; -import { Typography, Select, DatePicker, Button, Row, Col, Card } from 'antd'; -import { ResponsiveLine } from '@nivo/line'; -import { FileTextOutlined } from '@ant-design/icons'; -import { decryptData } from '../../../components/Global/Formatter'; -import dayjs from 'dayjs'; -import './trending.css'; - -const { Text } = Typography; - -const IndexTrending = memo(function IndexTrending() { - const navigate = useNavigate(); - const { setBreadcrumbItems } = useBreadcrumb(); - - const [plantSubSection, setPlantSubSection] = useState('Semua Plant'); - const [startDate, setStartDate] = useState(dayjs('2025-09-30')); - const [endDate, setEndDate] = useState(dayjs('2025-10-09')); - const [periode, setPeriode] = useState('10 Menit'); - const [userRole, setUserRole] = useState(null); - const [roleLevel, setRoleLevel] = useState(null); - - useEffect(() => { - const token = localStorage.getItem('token'); - if (token) { - // Get user data and role - let userData = null; - const sessionData = localStorage.getItem('session'); - if (sessionData) { - userData = decryptData(sessionData); - } else { - const userRaw = localStorage.getItem('user'); - if (userRaw) { - try { - userData = { user: JSON.parse(userRaw) }; - } catch (e) { - console.error('Error parsing user data:', e); - } - } - } - - if (userData?.user) { - setUserRole(userData.user.role_name); - setRoleLevel(userData.user.role_level); - } - - setBreadcrumbItems([ - { - title: ( - - • History - - ), - }, - { - title: ( - - Trending - - ), - }, - ]); - } else { - navigate('/signin'); - } - }, []); - - const tagTrendingData = [ - { - id: 'TEMP_SENSOR_1', - color: '#FF6B4A', - data: [ - { y: '08:00', x: 75 }, - { y: '08:05', x: 76 }, - { y: '08:10', x: 75 }, - { y: '08:15', x: 77 }, - { y: '08:20', x: 76 }, - { y: '08:25', x: 78 }, - { y: '08:30', x: 79 }, - ], - }, - { - id: 'GAS_LEAK_SENSOR_1', - color: '#4ECDC4', - data: [ - { y: '08:00', x: 10 }, - { y: '08:05', x: 150 }, - { y: '08:10', x: 40 }, - { y: '08:15', x: 20 }, - { y: '08:20', x: 15 }, - { y: '08:25', x: 18 }, - { y: '08:30', x: 25 }, - ], - }, - { - id: 'PRESSURE_SENSOR_1', - color: '#FFE66D', - data: [ - { y: '08:00', x: 1.2 }, - { y: '08:05', x: 1.3 }, - { y: '08:10', x: 1.2 }, - { y: '08:15', x: 1.4 }, - { y: '08:20', x: 1.5 }, - { y: '08:25', x: 1.3 }, - { y: '08:30', x: 1.2 }, - ], - }, - ]; - - const handleReset = () => { - setPlantSubSection('Semua Plant'); - setStartDate(dayjs('2025-09-30')); - setEndDate(dayjs('2025-10-09')); - setPeriode('10 Menit'); - }; - - // Check if user has permission to view data (all except guest) - const canViewData = userRole && userRole !== 'guest'; - - // Check if user can export/filter (administrator, engineer) - const canExportData = userRole && (userRole === 'administrator' || userRole === 'engineer'); - - return ( - - {/* Filter Section */} - -
- - ☰ Filter Data - -
- -
-
- - Plant Sub Section - - -
- - - - - - - - - - - - {/* Charts Section */} - {/* {!canViewData ? ( - - - Anda tidak memiliki akses untuk melihat data trending. -
- Silakan hubungi administrator untuk mendapatkan akses. -
-
- ) : ( */} - <> - - {/* Line Chart */} - - -
- - ☰ Tag Value Trending - -
-
- -
-
- - - - {/* )} */} - - ); -}); - -export default IndexTrending; diff --git a/src/pages/report/report/IndexReport.jsx b/src/pages/report/report/IndexReport.jsx new file mode 100644 index 0000000..d849260 --- /dev/null +++ b/src/pages/report/report/IndexReport.jsx @@ -0,0 +1,38 @@ +import React, { memo, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; +import { Typography } from 'antd'; +import ListReport from './component/ListReport'; + +const { Text } = Typography; + +const IndexReport = memo(function IndexReport() { + const navigate = useNavigate(); + const { setBreadcrumbItems } = useBreadcrumb(); + const [selectedData, setSelectedData] = useState(null); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (token) { + setBreadcrumbItems([ + { + title: ( + + • Report + + ), + }, + ]); + } else { + navigate('/signin'); + } + }, [navigate, setBreadcrumbItems]); + + return ( + + + + ); +}); + +export default IndexReport; diff --git a/src/pages/report/report/component/ListReport.jsx b/src/pages/report/report/component/ListReport.jsx new file mode 100644 index 0000000..974af15 --- /dev/null +++ b/src/pages/report/report/component/ListReport.jsx @@ -0,0 +1,163 @@ +import React, { memo, useState, useEffect } from 'react'; +import { Button, Row, Col, Card, Input, DatePicker, Select, Typography } from 'antd'; +import TableList from '../../../../components/Global/TableList'; +import dayjs from 'dayjs'; +import { FileTextOutlined } from '@ant-design/icons'; + +const { Text } = Typography; + +const ListReport = memo(function ListReport(props) { + const columns = [ + { + title: 'No', + key: 'no', + width: '5%', + align: 'center', + render: (_, __, index) => index + 1, + }, + { + title: 'Datetime', + dataIndex: 'datetime', + key: 'datetime', + width: '10%', + }, + { + title: 'Tag Name', + dataIndex: 'tag_name', + key: 'tag_name', + width: '70%', + }, + { + title: 'Value', + dataIndex: 'val', + key: 'val', + width: '10%', + }, + { + title: 'Stat', + dataIndex: 'stat', + key: 'stat', + width: '10%', + }, + ]; + + const [trigerFilter, setTrigerFilter] = useState(false); + + const defaultFilter = { search: '' }; + const [formDataFilter, setFormDataFilter] = useState(defaultFilter); + + const [plantSubSection, setPlantSubSection] = useState('Semua Plant'); + const [startDate, setStartDate] = useState(dayjs('2025-09-30')); + const [endDate, setEndDate] = useState(dayjs('2025-10-09')); + const [periode, setPeriode] = useState('10 Menit'); + + const getAllReport = async (params) => { + return { + data: [], + }; + }; + + const handleReset = () => { + setPlantSubSection('Semua Plant'); + setStartDate(dayjs('2025-09-30')); + setEndDate(dayjs('2025-10-09')); + setPeriode('10 Menit'); + }; + + return ( + + + + + + +
+ + Plant Sub Section + + +
+ + + + + + + + + + + + + + + + + + ); +}); + +export default ListReport; diff --git a/src/pages/report/trending/IndexTrending.jsx b/src/pages/report/trending/IndexTrending.jsx new file mode 100644 index 0000000..73540e7 --- /dev/null +++ b/src/pages/report/trending/IndexTrending.jsx @@ -0,0 +1,38 @@ +import React, { memo, useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; +import { Typography } from 'antd'; +import ReportTrending from './ReportTrending'; + +const { Text } = Typography; + +const IndexTrending = memo(function IndexTrending() { + const navigate = useNavigate(); + const { setBreadcrumbItems } = useBreadcrumb(); + const [selectedData, setSelectedData] = useState(null); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (token) { + setBreadcrumbItems([ + { + title: ( + + • Trending + + ), + }, + ]); + } else { + navigate('/signin'); + } + }, [navigate, setBreadcrumbItems]); + + return ( + + + + ); +}); + +export default IndexTrending; diff --git a/src/pages/report/trending/ReportTrending.jsx b/src/pages/report/trending/ReportTrending.jsx new file mode 100644 index 0000000..04a1eb5 --- /dev/null +++ b/src/pages/report/trending/ReportTrending.jsx @@ -0,0 +1,222 @@ +import React, { memo, useState, useEffect } from 'react'; +import { Button, Row, Col, Card, Input, DatePicker, Select, Typography } from 'antd'; +import dayjs from 'dayjs'; +import { FileTextOutlined } from '@ant-design/icons'; +import { ResponsiveLine } from '@nivo/line'; +import './trending.css'; + +const { Text } = Typography; + +const tagTrendingData = [ + { + id: 'TEMP_SENSOR_1', + color: '#FF6B4A', + data: [ + { y: '08:00', x: 75 }, + { y: '08:05', x: 76 }, + { y: '08:10', x: 75 }, + { y: '08:15', x: 77 }, + { y: '08:20', x: 76 }, + { y: '08:25', x: 78 }, + { y: '08:30', x: 79 }, + ], + }, + { + id: 'GAS_LEAK_SENSOR_1', + color: '#4ECDC4', + data: [ + { y: '08:00', x: 10 }, + { y: '08:05', x: 150 }, + { y: '08:10', x: 40 }, + { y: '08:15', x: 20 }, + { y: '08:20', x: 15 }, + { y: '08:25', x: 18 }, + { y: '08:30', x: 25 }, + ], + }, + { + id: 'PRESSURE_SENSOR_1', + color: '#FFE66D', + data: [ + { y: '08:00', x: 1.2 }, + { y: '08:05', x: 1.3 }, + { y: '08:10', x: 1.2 }, + { y: '08:15', x: 1.4 }, + { y: '08:20', x: 1.5 }, + { y: '08:25', x: 1.3 }, + { y: '08:30', x: 1.2 }, + ], + }, +]; + +const ReportTrending = memo(function ReportTrending(props) { + const [trigerFilter, setTrigerFilter] = useState(false); + + const defaultFilter = { search: '' }; + const [formDataFilter, setFormDataFilter] = useState(defaultFilter); + + const [plantSubSection, setPlantSubSection] = useState('Semua Plant'); + const [startDate, setStartDate] = useState(dayjs('2025-09-30')); + const [endDate, setEndDate] = useState(dayjs('2025-10-09')); + const [periode, setPeriode] = useState('10 Menit'); + + const getAllReport = async (params) => { + return { + data: [], + }; + }; + + const handleReset = () => { + setPlantSubSection('Semua Plant'); + setStartDate(dayjs('2025-09-30')); + setEndDate(dayjs('2025-10-09')); + setPeriode('10 Menit'); + }; + + return ( + + + + + + +
+ + Plant Sub Section + + +
+ + + + + + + + + + + + +
+ +
+ + + + + ); +}); + +export default ReportTrending; diff --git a/src/pages/history/trending/trending.css b/src/pages/report/trending/trending.css similarity index 100% rename from src/pages/history/trending/trending.css rename to src/pages/report/trending/trending.css