diff --git a/src/Dashboard.js b/src/Dashboard.js index ee76d3a..1ee3ad1 100644 --- a/src/Dashboard.js +++ b/src/Dashboard.js @@ -144,10 +144,23 @@ const Dashboard = () => { {isMenuOpen && (
@@ -155,7 +168,7 @@ const Dashboard = () => { onClick={() => { navigate("/profile"); setIsMenuOpen(false); - }} /* Tutup menu setelah klik */ + }} className={styles.dropdownItem} > Profile @@ -164,7 +177,7 @@ const Dashboard = () => { onClick={() => { navigate("/scan"); setIsMenuOpen(false); - }} /* Tutup menu setelah klik */ + }} className={styles.dropdownItem} > Scan @@ -173,7 +186,7 @@ const Dashboard = () => { onClick={() => { handleLogout(); setIsMenuOpen(false); - }} /* Tutup menu setelah klik */ + }} className={styles.dropdownItem} > Logout @@ -187,45 +200,47 @@ const Dashboard = () => { {/* Summary Cards */}
-

Total Hari Ini

-

{totalFilesSentToday}

+

Hari Ini

+

{totalFilesSentToday.toLocaleString()}

-

Total Bulan Ini

-

{totalFilesSentMonth}

+

Bulan Ini

+

{totalFilesSentMonth.toLocaleString()}

Total Keseluruhan

-

{totalFilesSentOverall}

+

{totalFilesSentOverall.toLocaleString()}

{/* Grid for Form (Admin) and Chart (Admin & Officer) */}
- {user.role === "admin" /* Render form hanya jika admin */ && ( + {user.role === "admin" && (

Tambah Officer Baru

@@ -238,7 +253,7 @@ const Dashboard = () => { {/* Chart Section - Visible to both Admin and Officer */}
-

Performa Pengiriman File Petugas

+

Performa Pengiriman File

{officerPerformanceData.length > 0 ? ( // Contoh implementasi Recharts: /* @@ -249,25 +264,28 @@ const Dashboard = () => { */
- Grafik performa petugas akan ditampilkan di sini. (Integrasikan - library grafik seperti Recharts/Chart.js) + 📊 Grafik performa akan ditampilkan di sini +
+ Integrasikan dengan Recharts atau Chart.js
) : ( -

- Tidak ada data performa petugas untuk ditampilkan. -

+
+ 📋 Belum ada data performa untuk ditampilkan +
)}
-
© 2025 Kediri Technopark
+
+ © 2025 Kediri Technopark • Dashboard PSI +
); }; diff --git a/src/Dashboard.module.css b/src/Dashboard.module.css index 6fdc63a..0667e94 100644 --- a/src/Dashboard.module.css +++ b/src/Dashboard.module.css @@ -1,31 +1,48 @@ -/* Variabel Warna */ +/* Modern Color Palette */ :root { - --primary-red: #e53935; - --secondary-red: #ef5350; - --dark-red: #c62828; - --light-gray: #eeeeee; - --dark-gray: #424242; + --primary-blue: #3b82f6; + --secondary-blue: #60a5fa; + --dark-blue: #1e40af; + --neutral-50: #fafafa; + --neutral-100: #f5f5f5; + --neutral-200: #e5e5e5; + --neutral-300: #d4d4d4; + --neutral-500: #737373; + --neutral-700: #404040; + --neutral-800: #262626; + --neutral-900: #171717; --white: #ffffff; - --success-green: #4caf50; - --warning-yellow: #ffc107; - --text-color-light: #f5f5f5; /* Teks terang di latar belakang gelap */ - --text-color-dark: #212121; /* Teks gelap di latar belakang terang */ + --success-green: #10b981; + --warning-amber: #f59e0b; + --error-red: #ef4444; + --text-primary: #0f172a; + --text-secondary: #64748b; + --text-light: #ffffff; + --border-light: #e2e8f0; + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), + 0 4px 6px -4px rgb(0 0 0 / 0.1); } /* Base Styles & Reset */ * { - box-sizing: border-box; /* Pastikan padding dan border tidak menambah lebar elemen */ + box-sizing: border-box; } body { margin: 0; - font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; /* Font lebih modern */ - line-height: 1.6; - color: var(--text-color-dark); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + "Helvetica Neue", Arial, sans-serif; + line-height: 1.5; + color: var(--text-primary); + background-color: var(--neutral-50); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .dashboardContainer { - background-color: var(--light-gray); + background-color: var(--neutral-50); min-height: 100vh; display: flex; flex-direction: column; @@ -33,33 +50,40 @@ body { /* --- Header --- */ .dashboardHeader { - background-color: var(--primary-red); - color: var(--text-color-light); - padding: 1rem; /* Menggunakan rem */ + background-color: var(--white); + color: var(--text-primary); + padding: 1rem 1.5rem; display: flex; justify-content: space-between; align-items: center; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + box-shadow: var(--shadow-sm); + border-bottom: 3px solid #ef4444; + position: sticky; + top: 0; + z-index: 50; + backdrop-filter: blur(8px); } .logoAndTitle { display: flex; align-items: center; - flex-shrink: 0; /* Mencegah logo dan judul mengecil terlalu banyak */ + flex-shrink: 0; } .logoAndTitle img { - width: 2.5rem; /* Ukuran rem */ + width: 2.5rem; height: 2.5rem; - border-radius: 50%; - margin-right: 0.8rem; + border-radius: 0.75rem; + margin-right: 0.75rem; + object-fit: cover; } .dashboardHeader .h1 { margin: 0; - font-size: 1.5rem; /* Ukuran rem untuk mobile */ - font-weight: bold; - white-space: nowrap; /* Mencegah judul patah baris */ + font-size: 1.5rem; + font-weight: 700; + color: #ed4344; + letter-spacing: -0.025em; } /* Dropdown Menu */ @@ -67,238 +91,262 @@ body { position: relative; display: flex; align-items: center; - gap: 0.8rem; - flex-shrink: 0; /* Mencegah mengecil */ + gap: 0.75rem; + flex-shrink: 0; } .userDisplayName { - color: var(--text-color-light); - font-weight: bold; - font-size: 0.9rem; - white-space: nowrap; /* Pastikan nama pengguna tidak patah baris */ + color: var(--text-secondary); + font-weight: 500; + font-size: 0.875rem; } .dropdownToggle { - background-color: var(--dark-red); - color: var(--text-color-light); - border: none; - padding: 0.5rem 0.75rem; /* Padding rem */ - border-radius: 0.3rem; + background-color: var(--neutral-100); + color: var(--text-primary); + border: 1px solid var(--border-light); + padding: 0.5rem; + border-radius: 0.5rem; cursor: pointer; font-size: 1rem; - transition: background-color 0.3s ease; - min-width: 3rem; /* Pastikan tombol tidak terlalu kecil */ + transition: all 0.2s ease; + min-width: 2.5rem; + height: 2.5rem; + display: flex; + align-items: center; + justify-content: center; } .dropdownToggle:hover { - background-color: var(--secondary-red); + background-color: var(--neutral-200); + border-color: var(--neutral-300); } .dropdownMenu { position: absolute; - top: calc(100% + 0.5rem); /* Posisikan di bawah tombol dengan jarak */ + top: calc(100% + 0.5rem); right: 0; background-color: var(--white); - border-radius: 0.3rem; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + border-radius: 0.75rem; + box-shadow: var(--shadow-lg); + border: 1px solid var(--border-light); z-index: 10; display: flex; flex-direction: column; - min-width: 8rem; /* Lebar minimum */ - overflow: hidden; /* Pastikan item tidak keluar */ + min-width: 10rem; + overflow: hidden; + padding: 0.5rem; } .dropdownItem { background: none; border: none; - padding: 0.6rem 0.8rem; + padding: 0.75rem 1rem; text-align: left; cursor: pointer; - color: var(--text-color-dark); - transition: background-color 0.3s ease; - font-size: 0.9rem; - white-space: nowrap; /* Mencegah item menu patah baris */ + color: var(--text-primary); + transition: background-color 0.2s ease; + font-size: 0.875rem; + font-weight: 500; + border-radius: 0.5rem; + margin-bottom: 0.125rem; } .dropdownItem:hover { - background-color: var(--light-gray); + background-color: var(--neutral-100); +} + +.dropdownItem:last-child { + margin-bottom: 0; } /* --- Main Content --- */ .mainContent { flex-grow: 1; - padding: 1.25rem; /* Padding rem */ + padding: 2rem 1.5rem; display: flex; flex-direction: column; - gap: 1.5rem; /* Jarak antar bagian utama */ + gap: 2rem; + max-width: 1400px; + margin: 0 auto; + width: 100%; } /* Summary Cards Container */ .summaryCardsContainer { - display: flex; - flex-wrap: wrap; /* Mengizinkan kartu melipat */ - gap: 1rem; /* Jarak antar kartu */ - justify-content: center; /* Tengahkan kartu di mobile */ - padding: 1rem; - background-color: var(--white); - border-radius: 0.6rem; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; } .summaryCard { - background-color: var(--light-gray); - color: var(--text-color-dark); - padding: 1rem; - border-radius: 0.5rem; - border: 1px solid var(--secondary-red); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - text-align: center; - flex: 1 1 calc(50% - 0.75rem); /* Di layar mobile, 2 kartu per baris */ - min-width: 120px; /* Batasan agar tidak terlalu kecil */ - max-width: 250px; /* Batasan agar tidak terlalu lebar di mobile */ + background-color: var(--white); + padding: 1.5rem; + border-radius: 1rem; + border: 1px solid var(--border-light); + box-shadow: var(--shadow-sm); + transition: all 0.2s ease; +} + +.summaryCard:hover { + box-shadow: var(--shadow-md); + transform: translateY(-1px); } .summaryCard h3 { - margin-top: 0; - font-size: 0.9rem; - color: var(--dark-red); + margin: 0 0 0.5rem 0; + font-size: 0.875rem; + color: var(--text-secondary); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; } .summaryCard p { - font-size: 1.6rem; - font-weight: bold; - color: var(--dark-gray); - margin-bottom: 0; + font-size: 2rem; + font-weight: 700; + color: #ef4444; + margin: 0; + line-height: 1; } /* Dashboard Grid for Form and Chart */ .dashboardGrid { display: grid; - grid-template-columns: 1fr; /* Default: satu kolom untuk mobile */ - gap: 1.5rem; /* Jarak antar bagian */ - flex-grow: 1; /* Agar grid bisa membesar mengisi sisa ruang */ + grid-template-columns: 1fr; + gap: 2rem; + flex-grow: 1; } .formSection, .chartSection { background-color: var(--white); - padding: 1.5rem; /* Padding rem */ - border-radius: 0.6rem; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + padding: 2rem; + border-radius: 1rem; + border: 1px solid var(--border-light); + box-shadow: var(--shadow-sm); } .formSection h2, .chartSection h2 { - color: var(--dark-red); - margin-top: 0; - margin-bottom: 1.25rem; - text-align: center; - font-size: 1.4rem; + color: var(--text-primary); + margin: 0 0 1.5rem 0; + font-size: 1.25rem; + font-weight: 600; + letter-spacing: -0.025em; } .form label { display: block; - margin-bottom: 0.8rem; - color: var(--text-color-dark); - font-weight: bold; - font-size: 0.95rem; + margin-bottom: 1rem; + color: var(--text-primary); + font-weight: 500; + font-size: 0.875rem; } .form input[type="text"], .form input[type="password"], .form select { width: 100%; - padding: 0.75rem; - margin-top: 0.3rem; - border: 1px solid var(--light-gray); - border-radius: 0.3rem; - font-size: 1rem; - transition: border-color 0.3s ease, box-shadow 0.3s ease; + padding: 0.75rem 1rem; + margin-top: 0.375rem; + border: 1px solid var(--border-light); + border-radius: 0.5rem; + font-size: 0.875rem; + transition: all 0.2s ease; + background-color: var(--white); + color: var(--text-primary); } .form input[type="text"]:focus, .form input[type="password"]:focus, .form select:focus { - border-color: var(--primary-red); - box-shadow: 0 0 0 3px rgba(229, 57, 53, 0.2); /* Ring focus */ + border-color: var(--primary-blue); + box-shadow: 0 0 0 3px rgb(59 130 246 / 0.1); outline: none; } .submitButton { - background-color: var(--primary-red); - color: var(--white); + background-color: var(--primary-blue); + color: var(--text-light); border: none; - padding: 0.8rem 1.5rem; + padding: 0.75rem 1.5rem; border-radius: 0.5rem; cursor: pointer; - font-size: 1rem; - font-weight: bold; - margin-top: 1.25rem; + font-size: 0.875rem; + font-weight: 600; + margin-top: 1rem; width: 100%; - transition: background-color 0.3s ease, transform 0.2s ease; + transition: all 0.2s ease; + letter-spacing: 0.025em; } .submitButton:hover { - background-color: var(--secondary-red); - transform: translateY(-2px); /* Efek sedikit naik */ + background-color: var(--dark-blue); + transform: translateY(-1px); + box-shadow: var(--shadow-md); +} + +.submitButton:active { + transform: translateY(0); } /* Messages */ .success { - background-color: #e6ffe6; + background-color: rgb(16 185 129 / 0.1); color: var(--success-green); - border: 1px solid var(--success-green); - padding: 0.8rem; - border-radius: 0.3rem; + border: 1px solid rgb(16 185 129 / 0.2); + padding: 0.75rem 1rem; + border-radius: 0.5rem; margin-top: 1rem; - text-align: center; - font-size: 0.9rem; + font-size: 0.875rem; + font-weight: 500; } .error { - background-color: #ffe6e6; - color: var(--primary-red); - border: 1px solid var(--primary-red); - padding: 0.8rem; - border-radius: 0.3rem; + background-color: rgb(239 68 68 / 0.1); + color: var(--error-red); + border: 1px solid rgb(239 68 68 / 0.2); + padding: 0.75rem 1rem; + border-radius: 0.5rem; margin-top: 1rem; - text-align: center; - font-size: 0.9rem; + font-size: 0.875rem; + font-weight: 500; } .warning { - background-color: #fffbe6; - color: var(--warning-yellow); - border: 1px solid var(--warning-yellow); + background-color: rgb(245 158 11 / 0.1); + color: var(--warning-amber); + border: 1px solid rgb(245 158 11 / 0.2); padding: 1rem; - border-radius: 0.3rem; - margin-top: 1.25rem; - text-align: center; - font-weight: bold; - font-size: 1rem; + border-radius: 0.5rem; + margin-top: 1rem; + font-weight: 500; + font-size: 0.875rem; } /* Footer */ .footer { - background-color: var(--dark-red); - color: var(--text-color-light); + background-color: var(--white); + color: var(--text-secondary); text-align: center; - padding: 0.75rem; + padding: 1rem; margin-top: auto; - font-size: 0.85rem; + font-size: 0.75rem; + border-top: 1px solid var(--border-light); } .chartPlaceholder { - background-color: var(--light-gray); - height: 20rem; /* Menggunakan rem */ + background-color: var(--neutral-50); + height: 20rem; display: flex; justify-content: center; align-items: center; - color: var(--dark-gray); + color: var(--text-secondary); font-style: italic; - border-radius: 0.6rem; - border: 1px dashed var(--secondary-red); - font-size: 1rem; + border-radius: 0.75rem; + border: 2px dashed var(--border-light); + font-size: 0.875rem; } /* --- Media Queries for Tablets and Desktops --- */ @@ -315,119 +363,24 @@ body { } .dashboardHeader .h1 { - font-size: 1.8rem; + font-size: 1.75rem; } .userDisplayName { - font-size: 1rem; - } - - .dropdownToggle { - padding: 0.6rem 1rem; - font-size: 1rem; - } - - .dropdownMenu { - min-width: 10rem; - } - - .dropdownItem { - font-size: 1rem; + font-size: 0.875rem; } .mainContent { - padding: 1.5rem 2.5rem; /* Padding lebih besar di tablet/desktop */ - gap: 2rem; - } - - .summaryCardsContainer { - justify-content: flex-start; /* Sejajarkan ke kiri di tablet/desktop */ - padding: 1.5rem; - } - - .summaryCard { - flex: 1 1 calc(33.33% - 1rem); /* 3 kartu per baris di tablet */ - max-width: 200px; /* Batasi lebar kartu agar tetap rapi */ - } - - .summaryCard h3 { - font-size: 1rem; - } - - .summaryCard p { - font-size: 2rem; - } - - .dashboardGrid { - grid-template-columns: 1fr 2fr; /* Dua kolom: form (1/3), chart (2/3) */ - gap: 2rem; - } - - .formSection, - .chartSection { - padding: 2rem; - } - - .formSection h2, - .chartSection h2 { - font-size: 1.6rem; - } - - .form label { - font-size: 1rem; - } - - .form input[type="text"], - .form input[type="password"], - .form select { - padding: 0.8rem; - font-size: 1rem; - } - - .submitButton { - padding: 1rem 1.8rem; - font-size: 1.1rem; - } - - .warning { - font-size: 1rem; - } - - .chartPlaceholder { - height: 25rem; /* Tinggi placeholder lebih besar di tablet/desktop */ - } -} - -/* Desktop-sized screens and up */ -@media (min-width: 1024px) { - .dashboardHeader { - padding: 1.5rem 3rem; - } - - .logoAndTitle img { - width: 3.5rem; - height: 3.5rem; - } - - .dashboardHeader .h1 { - font-size: 2.2rem; - } - - .mainContent { - padding: 2rem 4rem; + padding: 2.5rem 2rem; gap: 2.5rem; } .summaryCardsContainer { - padding: 2rem; - } - - .summaryCard { - flex: 0 0 auto; /* Ukuran tetap di desktop */ - min-width: 180px; + grid-template-columns: repeat(3, 1fr); } .dashboardGrid { + grid-template-columns: 1fr 2fr; gap: 2.5rem; } @@ -438,11 +391,41 @@ body { .formSection h2, .chartSection h2 { - font-size: 1.8rem; + font-size: 1.5rem; } - .submitButton { - padding: 1.1rem 2rem; + .chartPlaceholder { + height: 25rem; + } +} + +/* Desktop-sized screens and up */ +@media (min-width: 1024px) { + .dashboardHeader { + padding: 1.25rem 3rem; + } + + .logoAndTitle img { + width: 3.5rem; + height: 3.5rem; + } + + .dashboardHeader .h1 { + font-size: 2rem; + } + + .mainContent { + padding: 3rem 2.5rem; + gap: 3rem; + } + + .dashboardGrid { + gap: 3rem; + } + + .formSection, + .chartSection { + padding: 3rem; } .chartPlaceholder { @@ -450,11 +433,9 @@ body { } } -/* Jika hanya officer, pastikan chart mengambil seluruh lebar kolom */ -/* Ini sebenarnya sudah ditangani oleh grid secara default, tapi bisa diperjelas */ +/* Single column layout when only one section is present */ @media (min-width: 768px) { .dashboardGrid > *:only-child { - /* Jika hanya ada satu anak elemen di dalam dashboardGrid */ - grid-column: 1 / -1; /* Ambil seluruh lebar dari kolom pertama hingga terakhir */ + grid-column: 1 / -1; } } diff --git a/src/KTPScanner.js b/src/KTPScanner.js index 7bd1a38..87fb74b 100644 --- a/src/KTPScanner.js +++ b/src/KTPScanner.js @@ -267,12 +267,16 @@ const CameraCanvas = () => { const ReadImage = async (capturedImage) => { try { setLoading(true); + const token = localStorage.getItem("token"); let res = await fetch( "https://bot.kediritechnopark.com/webhook/mastersnapper/read", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, body: JSON.stringify({ image: capturedImage }), } ); diff --git a/src/Login.js b/src/Login.js index c9f045c..f30f286 100644 --- a/src/Login.js +++ b/src/Login.js @@ -35,7 +35,7 @@ const Login = () => { if (loginData?.success && loginData?.token) { localStorage.setItem("token", loginData.token); - window.location.href = "/dashboard"; + window.location.href = "/"; } else { setError(loginData?.message || "Username atau password salah"); } @@ -48,7 +48,7 @@ const Login = () => { return (
- Logo + Logo

PSI Admin Login

Silakan masuk untuk melanjutkan ke dashboard diff --git a/src/Login.module.css b/src/Login.module.css index a744827..09cfcf7 100644 --- a/src/Login.module.css +++ b/src/Login.module.css @@ -13,7 +13,8 @@ border-radius: 16px; padding: 40px; box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.05); - width: 300px; + width: 100%; + max-width: 400px; text-align: center; } @@ -27,7 +28,7 @@ font-size: 28px; font-weight: 700; margin-bottom: 10px; - color: #d22129; /* 🔴 Warna merah PSI */ + color: #ef4444; /* 🔴 Warna merah PSI */ } .subtitle { @@ -55,7 +56,7 @@ } .button { - background-color: #d22129; /* 🔴 Warna merah PSI */ + background-color: #ef4444; /* 🔴 Warna merah PSI */ color: #ffffff; padding: 12px 24px; border-radius: 24px; diff --git a/src/PSI.png b/src/PSI.png new file mode 100644 index 0000000..f7075fb Binary files /dev/null and b/src/PSI.png differ