From 3206db6010e4c0ab98cedd8d45466e391dc96c7d Mon Sep 17 00:00:00 2001 From: "MOCH. PASHA ARDYAN PUTRA" Date: Mon, 7 Jul 2025 15:08:43 +0000 Subject: [PATCH] ok --- src/App.js | 22 +----- src/Dashboard.js | 93 ++++++++++++++--------- src/Dashboard.module.css | 156 ++++++++++++++++++++++++++++++++++++++ src/KTPScanner.js | 79 +++++++++++++------ src/ProfileTab.module.css | 1 - 5 files changed, 270 insertions(+), 81 deletions(-) diff --git a/src/App.js b/src/App.js index b04db33..fa71345 100644 --- a/src/App.js +++ b/src/App.js @@ -13,26 +13,6 @@ const ProtectedRoute = ({ element }) => { return token ? element : ; }; -// Komponen redirect berdasarkan sessionStorage -const HomeRedirect = () => { - const token = localStorage.getItem("token"); - const hasOpen = sessionStorage.getItem("hasOpen"); - - if (!token) { - return ; - } - - // Jika tidak ada sessionId (anggap sebagai session baru) - if (!hasOpen) { - sessionStorage.setItem("hasOpen", true); - - return ; - } - - // Jika sudah ada sessionId - return ; -}; - function App() { return (
@@ -43,11 +23,11 @@ function App() { path="/dashboard" element={} />} /> + } />} /> } />} /> - } /> } />
diff --git a/src/Dashboard.js b/src/Dashboard.js index 9172433..6f3845c 100644 --- a/src/Dashboard.js +++ b/src/Dashboard.js @@ -70,27 +70,28 @@ const Dashboard = () => { verifyTokenAndFetchData(); }, []); + // Memisahkan fungsi fetchOfficers agar dapat dipanggil ulang + const fetchOfficers = async () => { + const token = localStorage.getItem("token"); + try { + const response = await fetch( + "https://bot.kediritechnopark.com/webhook/list-user/psi", + { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + const data = await response.json(); + setOfficers(data); + } catch (error) { + console.error("Gagal memuat daftar officer:", error.message); + } + }; + useEffect(() => { - const fetchOfficers = async () => { - const token = localStorage.getItem("token"); - try { - const response = await fetch( - "https://bot.kediritechnopark.com/webhook/list-user/psi", - { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); - - const data = await response.json(); - setOfficers(data); - } catch (error) { - console.error("Gagal memuat daftar officer:", error.message); - } - }; - if (user.role == "admin") { fetchOfficers(); } @@ -133,6 +134,9 @@ const Dashboard = () => { setUsername(""); setPassword(""); setErrorMessage(""); + + // Refresh daftar officer setelah berhasil menambahkan + await fetchOfficers(); } catch (error) { setErrorMessage(error.message || "Gagal menambahkan officer"); setSuccessMessage(""); @@ -148,6 +152,7 @@ const Dashboard = () => { document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); + const handleDeleteOfficer = async (id) => { const confirmDelete = window.confirm( "Apakah Anda yakin ingin menghapus petugas ini?" @@ -268,21 +273,39 @@ const Dashboard = () => { {user.role === "admin" && (

Daftar Petugas

-
    - {officers.map((officer) => ( -
  • - 👤 {officer.username} —{" "} - {officer.role} - -
  • - ))} -
+
+
+ {officers.length > 0 ? ( + officers.map((officer) => ( +
+
+ 👤 +
+ + {officer.username} + + + {officer.role} + +
+
+ +
+ )) + ) : ( +
+ 📋 +

Belum ada petugas terdaftar

+
+ )} +
+

Tambah Petugas Baru

diff --git a/src/Dashboard.module.css b/src/Dashboard.module.css index 7db97ca..728a5fd 100644 --- a/src/Dashboard.module.css +++ b/src/Dashboard.module.css @@ -442,3 +442,159 @@ body { grid-column: 1 / -1; } } + +/* CSS untuk styling daftar petugas */ + +.officerListContainer { + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 8px; + padding: 16px; + margin-bottom: 20px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.officerList { + max-height: 300px; + overflow-y: auto; + padding: 0; + margin: 0; + list-style: none; + border-radius: 6px; + background: white; + border: 1px solid #e9ecef; +} + +.officerItem { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + border-bottom: 1px solid #e9ecef; + transition: background-color 0.2s ease; +} + +.officerItem:last-child { + border-bottom: none; +} + +.officerItem:hover { + background-color: #f8f9fa; +} + +.officerInfo { + display: flex; + align-items: center; + gap: 12px; + flex: 1; +} + +.officerIcon { + font-size: 20px; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; +} + +.officerDetails { + display: flex; + flex-direction: column; + gap: 2px; +} + +.officerName { + font-weight: 600; + color: #2c3e50; + font-size: 14px; +} + +.officerRole { + font-size: 12px; + color: #6c757d; + font-style: italic; + text-transform: capitalize; +} + +.deleteButton { + background: none; + border: none; + cursor: pointer; + font-size: 12px; + padding: 4px 8px; + border-radius: 4px; + transition: background-color 0.2s ease; + opacity: 0.7; +} + +.deleteButton:hover { + background-color: #fee; + opacity: 1; +} + +.deleteButton:focus { + outline: 2px solid #dc3545; + outline-offset: 2px; +} + +.emptyState { + text-align: center; + padding: 40px 20px; + color: #6c757d; +} + +.emptyState span { + font-size: 32px; + display: block; + margin-bottom: 8px; +} + +.emptyState p { + margin: 0; + font-size: 14px; +} + +.separator { + border: none; + border-top: 1px solid #dee2e6; + margin: 24px 0; +} + +/* Custom scrollbar untuk daftar petugas */ +.officerList::-webkit-scrollbar { + width: 8px; +} + +.officerList::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; +} + +.officerList::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 4px; +} + +.officerList::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} + +/* Responsive design */ +@media (max-width: 768px) { + .officerItem { + padding: 10px 12px; + } + + .officerInfo { + gap: 8px; + } + + .officerName { + font-size: 13px; + } + + .officerRole { + font-size: 11px; + } +} diff --git a/src/KTPScanner.js b/src/KTPScanner.js index e17a3d8..defdc53 100644 --- a/src/KTPScanner.js +++ b/src/KTPScanner.js @@ -1,4 +1,6 @@ import React, { useEffect, useRef, useState } from "react"; +import styless from "./Dashboard.module.css"; + import { useNavigate } from "react-router-dom"; import Modal from "./Modal"; @@ -7,6 +9,8 @@ import PaginatedFormEditable from "./PaginatedFormEditable"; const STORAGE_KEY = "camera_canvas_gallery"; const CameraCanvas = () => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + const menuRef = useRef(null); const navigate = useNavigate(); const videoRef = useRef(null); @@ -489,30 +493,57 @@ const CameraCanvas = () => { return (
-
- -
Scan KTP atau unggah
+
+
+ Bot Avatar +

Kawal PSI Dashboard

+
+ +
+ + {isMenuOpen && ( +
+ + +
+ )} +