update history trending
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import React, { memo, useEffect } from 'react';
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||
import { Typography } from 'antd';
|
||||
import { Typography, Select, DatePicker, Button, Row, Col, Card, Statistic } from 'antd';
|
||||
import { ResponsiveLine } from '@nivo/line';
|
||||
import { ResponsivePie } from '@nivo/pie';
|
||||
import { FileTextOutlined, ToolOutlined, CheckCircleOutlined, ClockCircleOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import './trending.css';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -9,22 +14,374 @@ 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('Bulanan');
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
setBreadcrumbItems([
|
||||
{ title: <Text strong style={{ fontSize: '14px' }}>• History</Text> },
|
||||
{ title: <Text strong style={{ fontSize: '14px' }}>Trending</Text> }
|
||||
{ title: <Text strong style={{ fontSize: '14px' }}>Trending</Text> },
|
||||
]);
|
||||
} else {
|
||||
navigate('/signin');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const lineChartData = [
|
||||
{
|
||||
id: 'Compressor Section 1',
|
||||
color: '#FF6B4A',
|
||||
data: [
|
||||
{ x: 'Jan', y: 15 },
|
||||
{ x: 'Feb', y: 18 },
|
||||
{ x: 'Mar', y: 17 },
|
||||
{ x: 'Apr', y: 24 },
|
||||
{ x: 'Mei', y: 21 },
|
||||
{ x: 'Jun', y: 19 },
|
||||
{ x: 'Jul', y: 28 },
|
||||
{ x: 'Agu', y: 26 },
|
||||
{ x: 'Sep', y: 22 },
|
||||
{ x: 'Okt', y: 25 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'Compressor Section 2',
|
||||
color: '#4ECDC4',
|
||||
data: [
|
||||
{ x: 'Jan', y: 12 },
|
||||
{ x: 'Feb', y: 14 },
|
||||
{ x: 'Mar', y: 19 },
|
||||
{ x: 'Apr', y: 21 },
|
||||
{ x: 'Mei', y: 22 },
|
||||
{ x: 'Jun', y: 20 },
|
||||
{ x: 'Jul', y: 19 },
|
||||
{ x: 'Agu', y: 21 },
|
||||
{ x: 'Sep', y: 18 },
|
||||
{ x: 'Okt', y: 20 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'Compressor Section 3',
|
||||
color: '#FFE66D',
|
||||
data: [
|
||||
{ x: 'Jan', y: 8 },
|
||||
{ x: 'Feb', y: 10 },
|
||||
{ x: 'Mar', y: 12 },
|
||||
{ x: 'Apr', y: 15 },
|
||||
{ x: 'Mei', y: 18 },
|
||||
{ x: 'Jun', y: 20 },
|
||||
{ x: 'Jul', y: 22 },
|
||||
{ x: 'Agu', y: 21 },
|
||||
{ x: 'Sep', y: 19 },
|
||||
{ x: 'Okt', y: 26 },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const donutChartData = [
|
||||
{ id: 'Section 1', label: 'Section 1', value: 35, color: '#FF6B4A' },
|
||||
{ id: 'Section 2', label: 'Section 2', value: 25, color: '#4ECDC4' },
|
||||
{ id: 'Section 3', label: 'Section 3', value: 15, color: '#FFE66D' },
|
||||
{ id: 'Section 4', label: 'Section 4', value: 12, color: '#95E1D3' },
|
||||
{ id: 'Section 5', label: 'Section 5', value: 8, color: '#F38BA0' },
|
||||
{ id: 'Section 6', label: 'Section 6', value: 5, color: '#A78BFA' },
|
||||
];
|
||||
|
||||
const barChartData = [
|
||||
{ label: 'Overheat', value: 65 },
|
||||
{ label: 'Low Pressure', value: 48 },
|
||||
{ label: 'High Vibration', value: 42 },
|
||||
{ label: 'Oil Leak', value: 35 },
|
||||
{ label: 'Sensor Error', value: 28 },
|
||||
];
|
||||
|
||||
const handleReset = () => {
|
||||
setPlantSubSection('Semua Plant');
|
||||
setStartDate(dayjs('2025-09-30'));
|
||||
setEndDate(dayjs('2025-10-09'));
|
||||
setPeriode('Bulanan');
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Trending Page</h1>
|
||||
<React.Fragment>
|
||||
<div className="trending-container">
|
||||
{/* Filter Section */}
|
||||
<Card className="filter-card">
|
||||
<div className="filter-header">
|
||||
<Text strong style={{ fontSize: '14px' }}>☰ Filter Data</Text>
|
||||
</div>
|
||||
<Row gutter={16} style={{ marginTop: '16px' }}>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<div className="filter-item">
|
||||
<Text style={{ fontSize: '12px', color: '#666' }}>Plant Sub Section</Text>
|
||||
<Select
|
||||
value={plantSubSection}
|
||||
onChange={setPlantSubSection}
|
||||
style={{ width: '100%', marginTop: '4px' }}
|
||||
options={[
|
||||
{ value: 'Semua Plant', label: 'Semua Plant' },
|
||||
{ value: 'Plant 1', label: 'Plant 1' },
|
||||
{ value: 'Plant 2', label: 'Plant 2' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<div className="filter-item">
|
||||
<Text style={{ fontSize: '12px', color: '#666' }}>Tanggal Mulai</Text>
|
||||
<DatePicker
|
||||
value={startDate}
|
||||
onChange={setStartDate}
|
||||
format="DD/MM/YYYY"
|
||||
style={{ width: '100%', marginTop: '4px' }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<div className="filter-item">
|
||||
<Text style={{ fontSize: '12px', color: '#666' }}>Tanggal Akhir</Text>
|
||||
<DatePicker
|
||||
value={endDate}
|
||||
onChange={setEndDate}
|
||||
format="DD/MM/YYYY"
|
||||
style={{ width: '100%', marginTop: '4px' }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<div className="filter-item">
|
||||
<Text style={{ fontSize: '12px', color: '#666' }}>Periode</Text>
|
||||
<Select
|
||||
value={periode}
|
||||
onChange={setPeriode}
|
||||
style={{ width: '100%', marginTop: '4px' }}
|
||||
options={[
|
||||
{ value: 'Harian', label: 'Harian' },
|
||||
{ value: 'Mingguan', label: 'Mingguan' },
|
||||
{ value: 'Bulanan', label: 'Bulanan' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={8} style={{ marginTop: '16px' }}>
|
||||
<Col>
|
||||
<Button type="primary" danger icon={<FileTextOutlined />}>
|
||||
Tampilkan
|
||||
</Button>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button onClick={handleReset} style={{ backgroundColor: '#6c757d', color: 'white' }}>
|
||||
Reset
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* Statistics Cards */}
|
||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card className="stat-card stat-card-red">
|
||||
<div className="stat-icon">
|
||||
<FileTextOutlined style={{ fontSize: '24px' }} />
|
||||
</div>
|
||||
<Statistic
|
||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Total Error</Text>}
|
||||
value={245}
|
||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card className="stat-card stat-card-orange">
|
||||
<div className="stat-icon">
|
||||
<ToolOutlined style={{ fontSize: '24px' }} />
|
||||
</div>
|
||||
<Statistic
|
||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Sedang Maintenance</Text>}
|
||||
value={12}
|
||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card className="stat-card stat-card-green">
|
||||
<div className="stat-icon">
|
||||
<CheckCircleOutlined style={{ fontSize: '24px' }} />
|
||||
</div>
|
||||
<Statistic
|
||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Selesai Diperbaiki</Text>}
|
||||
value={233}
|
||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card className="stat-card stat-card-blue">
|
||||
<div className="stat-icon">
|
||||
<ClockCircleOutlined style={{ fontSize: '24px' }} />
|
||||
</div>
|
||||
<Statistic
|
||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Rata-rata Waktu Perbaikan</Text>}
|
||||
value="2.5 jam"
|
||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* Charts Section */}
|
||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||
{/* Line Chart */}
|
||||
<Col xs={24} lg={12}>
|
||||
<Card className="chart-card">
|
||||
<div className="chart-header">
|
||||
<Text strong style={{ fontSize: '14px' }}>☰ Trending Error per Plant Sub Section</Text>
|
||||
</div>
|
||||
<div style={{ height: '300px', marginTop: '16px' }}>
|
||||
<ResponsiveLine
|
||||
data={lineChartData}
|
||||
margin={{ top: 20, right: 20, bottom: 50, left: 50 }}
|
||||
xScale={{ type: 'point' }}
|
||||
yScale={{ type: 'linear', min: 0, max: 35 }}
|
||||
curve="natural"
|
||||
axisBottom={{
|
||||
tickSize: 5,
|
||||
tickPadding: 5,
|
||||
tickRotation: 0
|
||||
}}
|
||||
axisLeft={{
|
||||
tickSize: 5,
|
||||
tickPadding: 5,
|
||||
tickRotation: 0
|
||||
}}
|
||||
colors={{ datum: 'color' }}
|
||||
pointSize={6}
|
||||
pointColor={{ theme: 'background' }}
|
||||
pointBorderWidth={2}
|
||||
pointBorderColor={{ from: 'serieColor' }}
|
||||
pointLabelYOffset={-12}
|
||||
useMesh={true}
|
||||
legends={[
|
||||
{
|
||||
anchor: 'bottom',
|
||||
direction: 'row',
|
||||
justify: false,
|
||||
translateX: 0,
|
||||
translateY: 50,
|
||||
itemsSpacing: 10,
|
||||
itemDirection: 'left-to-right',
|
||||
itemWidth: 140,
|
||||
itemHeight: 20,
|
||||
itemOpacity: 0.75,
|
||||
symbolSize: 12,
|
||||
symbolShape: 'circle'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{/* Donut Chart */}
|
||||
<Col xs={24} lg={12}>
|
||||
<Card className="chart-card">
|
||||
<div className="chart-header">
|
||||
<Text strong style={{ fontSize: '14px' }}>☰ Distribusi Error per Plant</Text>
|
||||
</div>
|
||||
<div style={{ height: '300px', marginTop: '16px' }}>
|
||||
<ResponsivePie
|
||||
data={donutChartData}
|
||||
margin={{ top: 20, right: 80, bottom: 80, left: 80 }}
|
||||
innerRadius={0.6}
|
||||
padAngle={1}
|
||||
cornerRadius={3}
|
||||
activeOuterRadiusOffset={8}
|
||||
colors={{ datum: 'data.color' }}
|
||||
borderWidth={1}
|
||||
borderColor={{ from: 'color', modifiers: [['darker', 0.2]] }}
|
||||
arcLinkLabelsSkipAngle={10}
|
||||
arcLinkLabelsTextColor="#333333"
|
||||
arcLinkLabelsThickness={2}
|
||||
arcLinkLabelsColor={{ from: 'color' }}
|
||||
arcLabelsSkipAngle={10}
|
||||
arcLabelsTextColor={{ from: 'color', modifiers: [['darker', 2]] }}
|
||||
legends={[
|
||||
{
|
||||
anchor: 'bottom',
|
||||
direction: 'row',
|
||||
justify: false,
|
||||
translateX: 0,
|
||||
translateY: 56,
|
||||
itemsSpacing: 8,
|
||||
itemWidth: 80,
|
||||
itemHeight: 18,
|
||||
itemTextColor: '#999',
|
||||
itemDirection: 'left-to-right',
|
||||
itemOpacity: 1,
|
||||
symbolSize: 12,
|
||||
symbolShape: 'circle'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* Bar Chart and Bottom Section */}
|
||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||
{/* Bar Chart */}
|
||||
<Col xs={24} lg={12}>
|
||||
<Card className="chart-card">
|
||||
<div className="chart-header">
|
||||
<Text strong style={{ fontSize: '14px' }}>☰ Jenis Error Terbanyak</Text>
|
||||
</div>
|
||||
<div style={{ marginTop: '24px', padding: '0 20px' }}>
|
||||
{barChartData.map((item, index) => (
|
||||
<div key={index} style={{ marginBottom: '20px' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
|
||||
<Text style={{ fontSize: '12px' }}>{item.label}</Text>
|
||||
<Text strong style={{ fontSize: '12px' }}>{item.value}</Text>
|
||||
</div>
|
||||
<div style={{
|
||||
width: '100%',
|
||||
height: '24px',
|
||||
backgroundColor: '#f0f0f0',
|
||||
borderRadius: '4px',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<div style={{
|
||||
width: `${(item.value / 70) * 100}%`,
|
||||
height: '100%',
|
||||
backgroundColor: '#FF6B4A',
|
||||
transition: 'width 0.3s ease'
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{/* Perbandingan Error Section */}
|
||||
<Col xs={24} lg={12}>
|
||||
<Card className="chart-card">
|
||||
<div className="chart-header">
|
||||
<Text strong style={{ fontSize: '14px' }}>☰ Perbandingan Error Bulan Ini vs Bulan Lalu</Text>
|
||||
</div>
|
||||
<div style={{ marginTop: '24px', padding: '20px', textAlign: 'center' }}>
|
||||
<Text style={{ color: '#999' }}>Data akan ditampilkan di sini</Text>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
118
src/pages/history/trending/trending.css
Normal file
118
src/pages/history/trending/trending.css
Normal file
@@ -0,0 +1,118 @@
|
||||
.trending-container {
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Filter Card */
|
||||
.filter-card {
|
||||
margin-bottom: 24px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.filter-header {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Statistic Cards */
|
||||
.stat-card {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.stat-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.stat-card-red::before {
|
||||
background-color: #ff4d4f;
|
||||
}
|
||||
|
||||
.stat-card-orange::before {
|
||||
background-color: #ff9f43;
|
||||
}
|
||||
|
||||
.stat-card-green::before {
|
||||
background-color: #52c41a;
|
||||
}
|
||||
|
||||
.stat-card-blue::before {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.stat-card-red .stat-icon {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.stat-card-orange .stat-icon {
|
||||
color: #ff9f43;
|
||||
}
|
||||
|
||||
.stat-card-green .stat-icon {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.stat-card-blue .stat-icon {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
/* Chart Cards */
|
||||
.chart-card {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.trending-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Ant Design overrides */
|
||||
.trending-container .ant-statistic-title {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.trending-container .ant-statistic-content {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.trending-container .ant-card-body {
|
||||
padding: 20px;
|
||||
}
|
||||
Reference in New Issue
Block a user