role-based access control
This commit is contained in:
@@ -5,6 +5,7 @@ import { Typography, Select, DatePicker, Button, Row, Col, Card, Statistic } fro
|
|||||||
import { ResponsiveLine } from '@nivo/line';
|
import { ResponsiveLine } from '@nivo/line';
|
||||||
import { ResponsivePie } from '@nivo/pie';
|
import { ResponsivePie } from '@nivo/pie';
|
||||||
import { FileTextOutlined, ToolOutlined, CheckCircleOutlined, ClockCircleOutlined } from '@ant-design/icons';
|
import { FileTextOutlined, ToolOutlined, CheckCircleOutlined, ClockCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { decryptData } from '../../../components/Global/Formatter';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import './trending.css';
|
import './trending.css';
|
||||||
|
|
||||||
@@ -18,10 +19,33 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
||||||
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
||||||
const [periode, setPeriode] = useState('Bulanan');
|
const [periode, setPeriode] = useState('Bulanan');
|
||||||
|
const [userRole, setUserRole] = useState(null);
|
||||||
|
const [roleLevel, setRoleLevel] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (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([
|
setBreadcrumbItems([
|
||||||
{ title: <Text strong style={{ fontSize: '14px' }}>• History</Text> },
|
{ title: <Text strong style={{ fontSize: '14px' }}>• History</Text> },
|
||||||
{ title: <Text strong style={{ fontSize: '14px' }}>Trending</Text> },
|
{ title: <Text strong style={{ fontSize: '14px' }}>Trending</Text> },
|
||||||
@@ -106,6 +130,12 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
setPeriode('Bulanan');
|
setPeriode('Bulanan');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="trending-container">
|
<div className="trending-container">
|
||||||
@@ -170,12 +200,21 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
</Row>
|
</Row>
|
||||||
<Row gutter={8} style={{ marginTop: '16px' }}>
|
<Row gutter={8} style={{ marginTop: '16px' }}>
|
||||||
<Col>
|
<Col>
|
||||||
<Button type="primary" danger icon={<FileTextOutlined />}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
danger
|
||||||
|
icon={<FileTextOutlined />}
|
||||||
|
disabled={!canViewData}
|
||||||
|
>
|
||||||
Tampilkan
|
Tampilkan
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<Button onClick={handleReset} style={{ backgroundColor: '#6c757d', color: 'white' }}>
|
<Button
|
||||||
|
onClick={handleReset}
|
||||||
|
style={{ backgroundColor: '#6c757d', color: 'white' }}
|
||||||
|
disabled={!canViewData}
|
||||||
|
>
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -183,56 +222,66 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Statistics Cards */}
|
{/* Statistics Cards */}
|
||||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
{!canViewData ? (
|
||||||
<Col xs={24} sm={12} md={6}>
|
<Card style={{ marginTop: '24px', textAlign: 'center', padding: '40px' }}>
|
||||||
<Card className="stat-card stat-card-red">
|
<Text style={{ fontSize: '16px', color: '#999' }}>
|
||||||
<div className="stat-icon">
|
Anda tidak memiliki akses untuk melihat data trending.
|
||||||
<FileTextOutlined style={{ fontSize: '24px' }} />
|
<br />
|
||||||
</div>
|
Silakan hubungi administrator untuk mendapatkan akses.
|
||||||
<Statistic
|
</Text>
|
||||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Total Error</Text>}
|
</Card>
|
||||||
value={245}
|
) : (
|
||||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
<>
|
||||||
/>
|
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||||
</Card>
|
<Col xs={24} sm={12} md={6}>
|
||||||
</Col>
|
<Card className="stat-card stat-card-red">
|
||||||
<Col xs={24} sm={12} md={6}>
|
<div className="stat-icon">
|
||||||
<Card className="stat-card stat-card-orange">
|
<FileTextOutlined style={{ fontSize: '24px' }} />
|
||||||
<div className="stat-icon">
|
</div>
|
||||||
<ToolOutlined style={{ fontSize: '24px' }} />
|
<Statistic
|
||||||
</div>
|
title={<Text style={{ fontSize: '12px', color: '#666' }}>Total Error</Text>}
|
||||||
<Statistic
|
value={245}
|
||||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Sedang Maintenance</Text>}
|
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||||
value={12}
|
/>
|
||||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
</Card>
|
||||||
/>
|
</Col>
|
||||||
</Card>
|
<Col xs={24} sm={12} md={6}>
|
||||||
</Col>
|
<Card className="stat-card stat-card-orange">
|
||||||
<Col xs={24} sm={12} md={6}>
|
<div className="stat-icon">
|
||||||
<Card className="stat-card stat-card-green">
|
<ToolOutlined style={{ fontSize: '24px' }} />
|
||||||
<div className="stat-icon">
|
</div>
|
||||||
<CheckCircleOutlined style={{ fontSize: '24px' }} />
|
<Statistic
|
||||||
</div>
|
title={<Text style={{ fontSize: '12px', color: '#666' }}>Sedang Maintenance</Text>}
|
||||||
<Statistic
|
value={12}
|
||||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Selesai Diperbaiki</Text>}
|
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||||
value={233}
|
/>
|
||||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
</Card>
|
||||||
/>
|
</Col>
|
||||||
</Card>
|
<Col xs={24} sm={12} md={6}>
|
||||||
</Col>
|
<Card className="stat-card stat-card-green">
|
||||||
<Col xs={24} sm={12} md={6}>
|
<div className="stat-icon">
|
||||||
<Card className="stat-card stat-card-blue">
|
<CheckCircleOutlined style={{ fontSize: '24px' }} />
|
||||||
<div className="stat-icon">
|
</div>
|
||||||
<ClockCircleOutlined style={{ fontSize: '24px' }} />
|
<Statistic
|
||||||
</div>
|
title={<Text style={{ fontSize: '12px', color: '#666' }}>Selesai Diperbaiki</Text>}
|
||||||
<Statistic
|
value={233}
|
||||||
title={<Text style={{ fontSize: '12px', color: '#666' }}>Rata-rata Waktu Perbaikan</Text>}
|
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
||||||
value="2.5 jam"
|
/>
|
||||||
valueStyle={{ fontSize: '24px', fontWeight: 'bold', color: '#333' }}
|
</Card>
|
||||||
/>
|
</Col>
|
||||||
</Card>
|
<Col xs={24} sm={12} md={6}>
|
||||||
</Col>
|
<Card className="stat-card stat-card-blue">
|
||||||
</Row>
|
<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 */}
|
{/* Charts Section */}
|
||||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||||
@@ -380,6 +429,8 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user