role-based access control

This commit is contained in:
2025-10-10 11:40:33 +07:00
parent a6e8c39ed8
commit 27c901d08f

View File

@@ -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>
); );