diff --git a/.gemini/hooks/telegram-notify.ts b/.gemini/hooks/telegram-notify.ts index fc99ca9..063d337 100755 --- a/.gemini/hooks/telegram-notify.ts +++ b/.gemini/hooks/telegram-notify.ts @@ -1,62 +1,65 @@ #!/usr/bin/env bun -import { readFileSync } from "fs"; +import { readFileSync } from "node:fs"; // Fungsi untuk mencari string terpanjang dalam objek (biasanya balasan AI) function findLongestString(obj: any): string { - let longest = ""; - const search = (item: any) => { - if (typeof item === "string") { - if (item.length > longest.length) longest = item; - } else if (Array.isArray(item)) { - item.forEach(search); - } else if (item && typeof item === "object") { - Object.values(item).forEach(search); - } - }; - search(obj); - return longest; + let longest = ""; + const search = (item: any) => { + if (typeof item === "string") { + if (item.length > longest.length) longest = item; + } else if (Array.isArray(item)) { + item.forEach(search); + } else if (item && typeof item === "object") { + Object.values(item).forEach(search); + } + }; + search(obj); + return longest; } async function run() { - try { - const inputRaw = readFileSync(0, "utf-8"); - if (!inputRaw) return; - const input = JSON.parse(inputRaw); + try { + const inputRaw = readFileSync(0, "utf-8"); + if (!inputRaw) return; + const input = JSON.parse(inputRaw); - // DEBUG: Lihat struktur asli di console terminal (stderr) - console.error("DEBUG KEYS:", Object.keys(input)); + // DEBUG: Lihat struktur asli di console terminal (stderr) + console.error("DEBUG KEYS:", Object.keys(input)); - const BOT_TOKEN = process.env.BOT_TOKEN; - const CHAT_ID = process.env.CHAT_ID; + const BOT_TOKEN = process.env.BOT_TOKEN; + const CHAT_ID = process.env.CHAT_ID; - const sessionId = input.session_id || "unknown"; - - // Cari teks secara otomatis di seluruh objek JSON - let finalText = findLongestString(input.response || input); + const sessionId = input.session_id || "unknown"; - if (!finalText || finalText.length < 5) { - finalText = "Teks masih gagal diekstraksi. Struktur: " + Object.keys(input).join(", "); - } + // Cari teks secara otomatis di seluruh objek JSON + let finalText = findLongestString(input.response || input); - const message = `✅ *Gemini Task Selesai*\n\n` + - `🆔 Session: \`${sessionId}\` \n\n` + - `🧠 Output:\n${finalText.substring(0, 3500)}`; + if (!finalText || finalText.length < 5) { + finalText = + "Teks masih gagal diekstraksi. Struktur: " + + Object.keys(input).join(", "); + } - await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - chat_id: CHAT_ID, - text: message, - parse_mode: "Markdown", - }), - }); + const message = + `✅ *Gemini Task Selesai*\n\n` + + `🆔 Session: \`${sessionId}\` \n\n` + + `🧠 Output:\n${finalText.substring(0, 3500)}`; - process.stdout.write(JSON.stringify({ status: "continue" })); - } catch (err) { - console.error("Hook Error:", err); - process.stdout.write(JSON.stringify({ status: "continue" })); - } + await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + chat_id: CHAT_ID, + text: message, + parse_mode: "Markdown", + }), + }); + + process.stdout.write(JSON.stringify({ status: "continue" })); + } catch (err) { + console.error("Hook Error:", err); + process.stdout.write(JSON.stringify({ status: "continue" })); + } } -run(); \ No newline at end of file +run(); diff --git a/.gemini/settings.json b/.gemini/settings.json index fe2af0f..ed73635 100644 --- a/.gemini/settings.json +++ b/.gemini/settings.json @@ -1,17 +1,17 @@ { - "hooks": { - "AfterAgent": [ - { - "matcher": "*", - "hooks": [ - { - "name": "telegram-notify", - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/.gemini/hooks/telegram-notify.ts", - "timeout": 10000 - } - ] - } - ] - } -} \ No newline at end of file + "hooks": { + "AfterAgent": [ + { + "matcher": "*", + "hooks": [ + { + "name": "telegram-notify", + "type": "command", + "command": "bun $GEMINI_PROJECT_DIR/.gemini/hooks/telegram-notify.ts", + "timeout": 10000 + } + ] + } + ] + } +} diff --git a/DASHBOARD_DESIGN.md b/DASHBOARD_DESIGN.md new file mode 100644 index 0000000..f368c1c --- /dev/null +++ b/DASHBOARD_DESIGN.md @@ -0,0 +1,270 @@ +# Dashboard Design Specification + +Dokumen ini mendeskripsikan desain dashboard berdasarkan **Screenshot 2026-02-02 at 14.12.36.png**. Tujuannya sebagai acuan implementasi UI untuk `src/routes/noc/dashboard/route.tsx`. + +--- + +## 1. Gambaran Umum + +Dashboard merepresentasikan **Sistem Informasi Desa (DESA+)** dengan fokus pada: + +* Monitoring layanan administrasi desa +* Statistik surat & pengaduan +* Tingkat kepuasan warga +* Aktivitas divisi & agenda desa + +Gaya visual: **modern, clean, administratif**, dengan nuansa **biru pemerintah** dan kartu (card-based layout). + +--- + +## 2. Struktur Layout + +### 2.1 Layout Global + +``` ++--------------------------------------------------+ +| Topbar / Header | ++-----------+--------------------------------------+ +| Sidebar | Main Content (Dashboard) | +| | - KPI Cards | +| | - Charts | +| | - Activity & Calendar | ++-----------+--------------------------------------+ +``` + +* **Sidebar**: fixed / sticky di kiri +* **Header**: fixed di atas konten utama +* **Main Content**: scrollable + +--- + +## 3. Header (Topbar) + +### Komponen + +* Nama desa: `Desa Darmasaba` +* User info: + + * Nama: `I. B. Surya Prabhawa M.` + * Role: `Kepala Desa` +* Ikon: + + * Notification (badge angka) + * Theme / setting (opsional) + * Avatar user (circle) + +### Style + +* Background: **Navy / Dark Blue** +* Text: putih +* Height: ±64px +* Shadow tipis ke bawah + +--- + +## 4. Sidebar Navigation + +### Elemen + +* Logo **DESA+** di atas +* Search input: `cari apa saja` +* Menu navigasi: + + * Beranda (active) + * Kinerja Divisi + * Pengaduan & Layanan Publik + * Jenna Analytic + * Demografi & Kependudukan + * Keuangan & Anggaran + * Bumdes & UMKM Desa + * Sosial + * Keamanan + * Bantuan + * Pengaturan + +### Style + +* Background: putih +* Active state: + + * Background: biru muda + * Text: biru tua +* Icon (opsional, outline style) +* Spacing antar menu: ±12–16px + +--- + +## 5. KPI / Summary Cards (Row 1) + +### Cards + +1. **Surat Minggu Ini** + + * Value: `99` + * Delta: `+12%` +2. **Pengaduan Aktif** + + * Value: `28` + * Sub: `14 baru, 14 diproses` +3. **Layanan Selesai** + + * Value: `156` + * Sub: `bulan ini` + * Delta: `+8%` +4. **Kepuasan Warga** + + * Value: `87.2%` + * Circular indicator + +### Style + +* Card background: putih +* Border radius: 12–16px +* Shadow: soft +* Icon di kanan atas card +* Grid: 4 kolom (desktop) + +--- + +## 6. Statistik Pengajuan Surat (Bar Chart) + +### Deskripsi + +* Judul: `Statistik Pengajuan Surat` +* Subjudul: `Trend pengajuan surat 6 bulan terakhir` +* X-axis: Jan – Jun +* Y-axis: jumlah surat + +### Style + +* Bar color: navy / dark blue +* Background card: putih +* Axis minimal & clean + +### Data Expectation + +```ts +{ + month: string; + total: number; +} +``` + +--- + +## 7. Tingkat Kepuasan (Donut Chart) + +### Kategori + +* Sangat Puas (hijau) +* Puas (biru) +* Cukup (kuning) +* Kurang (merah) + +### Style + +* Donut chart +* Legend di bawah +* Persentase di tengah (opsional) + +--- + +## 8. Divisi Teraktif (Progress List) + +### Item + +* Kesejahteraan – 37 kegiatan +* Pemerintahan – 26 kegiatan +* Keuangan – 17 kegiatan +* Sekretaris Desa – 15 kegiatan + +### Style + +* Horizontal progress bar +* Warna bar: navy +* Background bar: abu-abu terang + +--- + +## 9. Kalender & Kegiatan Mendatang + +### Item + +* 1 Oktober 2025 – Hari Kesaktian Pancasila +* 15 Oktober 2025 – Davest +* 19 Oktober 2025 – Rapat Koordinasi + +### Style + +* Card list +* Date kecil, title tebal + +--- + +## 10. Warna & Tema + +### Color Palette (Approx) + +* Primary: `#1E3A5F` (navy) +* Secondary: `#3B82F6` +* Success: `#22C55E` +* Warning: `#FACC15` +* Danger: `#EF4444` +* Background: `#F5F8FB` + +--- + +## 11. Typography + +* Font utama: **Inter / Poppins / system-ui** +* Heading: semi-bold +* Body: regular +* Angka KPI: bold, besar + +--- + +## 12. Responsiveness + +* Desktop (>=1280px): layout penuh +* Tablet: + + * Sidebar collapsible + * KPI cards jadi 2 kolom +* Mobile: + + * Sidebar drawer + * KPI cards 1 kolom + * Charts stack vertical + +--- + +## 13. Interaksi & Behavior + +* Sidebar menu: active state +* Hover card: shadow naik +* Chart: tooltip on hover +* Notification: clickable +* Data: async (API driven) + +--- + +## 14. Catatan Implementasi + +* Cocok untuk: + + * React + Vite + * Mantine / Shadcn / MUI + * ChartJS / Recharts / ECharts +* Gunakan layout berbasis **CSS Grid / Flexbox** + +--- + +## 15. Scope Selanjutnya + +* Dark mode +* Export laporan (PDF/Excel) +* Filter tanggal & divisi + +--- + +> Dokumen ini menjadi acuan desain UI. Perubahan visual harus tetap konsisten dengan struktur ini. diff --git a/GEMINI.md b/GEMINI.md index 41f1b19..09fe316 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -1,11 +1,11 @@ # GEMINI.md -This project is **makuro-base-template**, a high-performance, full-stack React development template leveraging the Bun runtime. It is designed for a seamless developer experience with a unified "single-port" architecture and a Contract-First API design. +This project is **darmasaba-dashboard-noc**, a high-performance, full-stack React development template leveraging the Bun runtime. It is designed for a seamless developer experience with a unified "single-port" architecture and a Contract-First API design. ## Project Overview * **Runtime**: [Bun](https://bun.sh/) -* **Architecture**: "Single Port" (default: 3000). [ElysiaJS](https://elysiajs.com/) serves as the main HTTP server, integrating [Vite](https://vitejs.dev/) in **middleware mode** during development to provide HMR and React Dev Inspector support. +* **Architecture**: "Single Port" (default: 3000). [ElysiaJS](https://elysiajs.com/) serves as the main HTTP server. During development, it integrates [Vite](https://vitejs.dev/) in **middleware mode** for HMR and React Dev Inspector support. In production, `@elysiajs/static` is used to efficiently serve pre-built frontend assets. * **API Design**: **Contract-First (OpenAPI)**. The frontend uses `openapi-fetch` with types generated from the backend's OpenAPI schema, ensuring a decoupled but type-safe connection. * **Mobile Readiness**: **PWA (Progressive Web App)** & **TWA (Trusted Web Activity)**. Built-in support for offline caching and Android app packaging. * **Frontend**: React 19 with [TanStack React Router](https://tanstack.com/router/latest) for type-safe, file-based routing. @@ -60,7 +60,7 @@ The project uses two main categories for testing, consolidated in the `__tests__ * **Manifest**: Metadata is located in `src/manifest.json`. * **Service Worker**: Offline logic is in `src/sw.js`. It uses a "Cache First" strategy. * **TWA Verification**: The Android ownership file is at `src/.well-known/assetlinks.json`. -* **Server Logic**: Elysia is configured to remove `Vary: *` headers for these static assets to ensure Cache Storage API compatibility. +* **Server Logic**: In production, `@elysiajs/static` handles serving static assets, including PWA/TWA files, ensuring proper caching headers. ### Backend/API * **Prefix**: All backend API routes are prefixed with `/api`. diff --git a/README.md b/README.md index 10392c8..7773ce3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# Makuro Base Template 🚀 +# Darmasaba Dashboard Noc 🚀 [![Bun](https://img.shields.io/badge/Bun-%23000000.svg?style=for-the-badge&logo=bun&logoColor=white)](https://bun.sh/) [![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)](https://react.dev/) [![Mantine](https://img.shields.io/badge/Mantine-blue?style=for-the-badge&logo=mantine&logoColor=white)](https://mantine.dev/) [![Biome](https://img.shields.io/badge/Biome-60a5fa?style=for-the-badge&logo=biome&logoColor=white)](https://biomejs.dev/) -**Makuro Base Template** is a high-performance, full-stack React development template leveraging the **Bun** runtime. It offers a unique "Single Port" architecture, combining a Bun/Elysia backend with a React frontend for an incredibly smooth developer experience. +**Darmasaba Dashboard Noc** is a high-performance, full-stack React development template leveraging the **Bun** runtime. It offers a unique "Single Port" architecture, combining a Bun/Elysia backend with a React frontend for an incredibly smooth developer experience. ## ✨ Key Features diff --git a/__tests__/api/features.test.ts b/__tests__/api/features.test.ts index a2e2bf0..9d8f1d2 100644 --- a/__tests__/api/features.test.ts +++ b/__tests__/api/features.test.ts @@ -10,7 +10,7 @@ describe("Feature Utilities", () => { it("should return value from process.env if available", () => { // Mock process.env - const originalEnv = { ...process.env }; + const _originalEnv = { ...process.env }; process.env.TEST_ENV_KEY = "test-value"; const val = getEnv("TEST_ENV_KEY"); diff --git a/bun.lock b/bun.lock index 2e61824..bc48f7c 100644 --- a/bun.lock +++ b/bun.lock @@ -47,15 +47,28 @@ "@tailwindcss/vite": "^4.1.18", "@tanstack/react-router": "^1.158.1", "better-auth": "^1.4.18", + "class-variance-authority": "^0.7.1", + "cmdk": "^1.0.1", "dayjs": "^1.11.19", "elysia": "^1.4.22", + "embla-carousel-react": "^8.1.1", + "input-otp": "^1.2.1", + "lucide-react": "^0.563.0", + "next-themes": "^0.4.6", "openapi-fetch": "^0.15.0", "pino": "^10.3.0", "pino-pretty": "^13.1.3", "react": "^19", + "react-day-picker": "^8.10.1", "react-dom": "^19", - "tailwindcss": "^4.1.18", + "react-hook-form": "^7.52.1", + "react-resizable-panels": "^2.0.22", + "recharts": "^3.7.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.4.0", + "ulid": "^3.0.2", "valtio": "^2.3.0", + "vaul": "^0.9.1", }, "devDependencies": { "@babel/core": "^7.29.0", @@ -63,12 +76,14 @@ "@biomejs/biome": "2.3.14", "@playwright/test": "^1.58.2", "@react-dev-inspector/vite-plugin": "^2.0.1", + "@tailwindcss/postcss": "^4.1.18", "@tanstack/react-router-devtools": "^1.158.1", "@tanstack/router-vite-plugin": "^1.158.1", "@types/bun": "latest", "@types/react": "^19", "@types/react-dom": "^19", "@vitejs/plugin-react": "^5.1.3", + "autoprefixer": "^10.4.24", "openapi-typescript": "^7.10.1", "postcss": "^8.5.6", "postcss-preset-mantine": "^1.18.0", @@ -82,6 +97,8 @@ "packages": { "@acemir/cssom": ["@acemir/cssom@0.9.31", "", {}, "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@asamuzakjp/css-color": ["@asamuzakjp/css-color@4.1.2", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "lru-cache": "^11.2.5" } }, "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg=="], "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.7.8", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.5" } }, "sha512-stisC1nULNc9oH5lakAj8MH88ZxeGxzyWNDfbdCxvJSJIvDsHNZqYvscGTgy/ysgXWLJPt6K/4t0/GjvtKcFJQ=="], @@ -468,6 +485,8 @@ "@redocly/openapi-core": ["@redocly/openapi-core@1.34.6", "", { "dependencies": { "@redocly/ajv": "^8.11.2", "@redocly/config": "^0.22.0", "colorette": "^1.2.0", "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "minimatch": "^5.0.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" } }, "sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw=="], + "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.2", "", {}, "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], @@ -530,6 +549,8 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], + "@tabler/icons": ["@tabler/icons@3.36.1", "", {}, "sha512-f4Jg3Fof/Vru5ioix/UO4GX+sdDsF9wQo47FbtvG+utIYYVQ/QVAC0QYgcBbAjQGfbdOh2CCf0BgiFOF9Ixtjw=="], "@tabler/icons-react": ["@tabler/icons-react@3.36.1", "", { "dependencies": { "@tabler/icons": "" }, "peerDependencies": { "react": ">= 16" } }, "sha512-/8nOXeNeMoze9xY/QyEKG65wuvRhkT3q9aytaur6Gj8bYU2A98YVJyLc9MRmc5nVvpy+bRlrrwK/Ykr8WGyUWg=="], @@ -562,6 +583,8 @@ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="], + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="], "@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="], @@ -604,6 +627,24 @@ "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], @@ -626,6 +667,8 @@ "@types/react-reconciler": ["@types/react-reconciler@0.33.0", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HZOXsKT0tGI9LlUw2LuedXsVeB88wFa536vVL0M6vE8zN63nI+sSr1ByxmPToP5K5bukaVscyeCJcF9guVNJ1g=="], + "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], + "@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.3", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.2", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg=="], @@ -718,6 +761,8 @@ "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "autoprefixer": ["autoprefixer@10.4.24", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001766", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw=="], + "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -778,8 +823,12 @@ "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -812,8 +861,32 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + "data-urls": ["data-urls@7.0.0", "", { "dependencies": { "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.0" } }, "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA=="], + "date-fns": ["date-fns@3.6.0", "", {}, "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww=="], + "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="], @@ -822,6 +895,8 @@ "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], @@ -862,6 +937,12 @@ "elysia": ["elysia@1.4.22", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.6", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Q90VCb1RVFxnFaRV0FDoSylESQQLWgLHFmWciQJdX9h3b2cSasji9KWEUvaJuy/L9ciAGg4RAhUVfsXHg5K2RQ=="], + "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], + + "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], + + "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], + "empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="], "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], @@ -874,6 +955,8 @@ "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + "es-toolkit": ["es-toolkit@1.44.0", "", {}, "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg=="], + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -890,6 +973,8 @@ "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="], @@ -936,6 +1021,8 @@ "fork-ts-checker-webpack-plugin": ["fork-ts-checker-webpack-plugin@6.5.3", "", { "dependencies": { "@babel/code-frame": "^7.8.3", "@types/json-schema": "^7.0.5", "chalk": "^4.1.0", "chokidar": "^3.4.2", "cosmiconfig": "^6.0.0", "deepmerge": "^4.2.2", "fs-extra": "^9.0.0", "glob": "^7.1.6", "memfs": "^3.1.2", "minimatch": "^3.0.4", "schema-utils": "2.7.0", "semver": "^7.3.2", "tapable": "^1.0.0" }, "peerDependencies": { "eslint": ">= 6", "typescript": ">= 2.7", "vue-template-compiler": "*", "webpack": ">= 4" }, "optionalPeers": ["eslint", "vue-template-compiler"] }, "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], "fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], @@ -992,7 +1079,7 @@ "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "immer": ["immer@9.0.21", "", {}, "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="], + "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], @@ -1004,6 +1091,10 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], + + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], @@ -1100,6 +1191,8 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="], @@ -1138,6 +1231,8 @@ "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="], "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], @@ -1242,6 +1337,8 @@ "postcss-simple-vars": ["postcss-simple-vars@7.0.1", "", { "peerDependencies": { "postcss": "^8.2.1" } }, "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A=="], + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + "postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="], "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], @@ -1280,6 +1377,8 @@ "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + "react-day-picker": ["react-day-picker@8.10.1", "", { "peerDependencies": { "date-fns": "^2.28.0 || ^3.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA=="], + "react-dev-inspector": ["react-dev-inspector@2.0.1", "", { "dependencies": { "@react-dev-inspector/babel-plugin": "2.0.1", "@react-dev-inspector/middleware": "2.0.1", "@react-dev-inspector/umi3-plugin": "2.0.1", "@react-dev-inspector/umi4-plugin": "2.0.1", "@react-dev-inspector/vite-plugin": "2.0.1", "@types/react-reconciler": ">=0.26.6", "hotkeys-js": "^3.8.1", "picocolors": "1.0.0", "react-dev-utils": "12.0.1" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-b8PAmbwGFrWcxeaX8wYveqO+VTwTXGJaz/yl9RO31LK1zeLKJVlkkbeLExLnJ6IvhXY1TwL8Q4+gR2GKJ8BI6Q=="], "react-dev-utils": ["react-dev-utils@12.0.1", "", { "dependencies": { "@babel/code-frame": "^7.16.0", "address": "^1.1.2", "browserslist": "^4.18.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "detect-port-alt": "^1.1.6", "escape-string-regexp": "^4.0.0", "filesize": "^8.0.6", "find-up": "^5.0.0", "fork-ts-checker-webpack-plugin": "^6.5.0", "global-modules": "^2.0.0", "globby": "^11.0.4", "gzip-size": "^6.0.0", "immer": "^9.0.7", "is-root": "^2.1.0", "loader-utils": "^3.2.0", "open": "^8.4.0", "pkg-up": "^3.1.0", "prompts": "^2.4.2", "react-error-overlay": "^6.0.11", "recursive-readdir": "^2.2.2", "shell-quote": "^1.7.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" } }, "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ=="], @@ -1288,14 +1387,22 @@ "react-error-overlay": ["react-error-overlay@6.1.0", "", {}, "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ=="], + "react-hook-form": ["react-hook-form@7.71.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w=="], + + "react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="], + "react-number-format": ["react-number-format@5.4.4", "", { "peerDependencies": { "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-wOmoNZoOpvMminhifQYiYSTCLUDOiUbBunrMrMjA+dV52sY+vck1S4UhR6PkgnoCquvvMSeJjErXZ4qSaWCliA=="], + "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + "react-resizable-panels": ["react-resizable-panels@2.1.9", "", { "peerDependencies": { "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ=="], + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], "react-textarea-autosize": ["react-textarea-autosize@8.5.9", "", { "dependencies": { "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A=="], @@ -1308,12 +1415,20 @@ "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], + "recharts": ["recharts@3.7.0", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew=="], + "recursive-readdir": ["recursive-readdir@2.2.3", "", { "dependencies": { "minimatch": "^3.0.5" } }, "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA=="], + "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], + + "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], + "regexp-to-ast": ["regexp-to-ast@0.5.0", "", {}, "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], @@ -1370,6 +1485,8 @@ "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], + "sonner": ["sonner@1.7.4", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -1398,6 +1515,8 @@ "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="], + "tailwind-merge": ["tailwind-merge@2.6.1", "", {}, "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ=="], + "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], @@ -1454,6 +1573,8 @@ "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + "ulid": ["ulid@3.0.2", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w=="], + "undici": ["undici@7.21.0", "", {}, "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], @@ -1482,6 +1603,10 @@ "valtio": ["valtio@2.3.0", "", { "dependencies": { "proxy-compare": "^3.0.1" }, "peerDependencies": { "@types/react": ">=18.0.0", "react": ">=18.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-1MfKNcmOIdBSatiJsYgw420n6jnD+jeoI0V+RkOQbCB0ElLh6GKUfPr0hc9uq/KBGeghivDEarRsKFFdSQQnKw=="], + "vaul": ["vaul@0.9.9", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0", "react-dom": "^16.8 || ^17.0 || ^18.0" } }, "sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ=="], + + "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], + "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], "vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="], @@ -1582,6 +1707,8 @@ "@redocly/openapi-core/colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], + "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], + "@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], @@ -1614,6 +1741,8 @@ "c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "cmdk/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], "cssstyle/lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], @@ -1664,6 +1793,8 @@ "react-dev-utils/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "react-dev-utils/immer": ["immer@9.0.21", "", {}, "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="], + "react-dev-utils/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], diff --git a/dashboard.png b/dashboard.png new file mode 100644 index 0000000..f419ba0 Binary files /dev/null and b/dashboard.png differ diff --git a/package.json b/package.json index d745490..4ed4248 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "makuro-base-template", + "name": "darmasaba-dashboard-noc", "version": "0.1.0-pre.2", "private": true, "type": "module", @@ -13,7 +13,8 @@ "test:ui": "bun test --ui __tests__/api", "test:e2e": "bun run build && playwright test", "build": "bun build ./src/index.html --outdir=dist --sourcemap --target=browser --minify --define:process.env.NODE_ENV='\"production\"' --env='VITE_*'", - "start": "NODE_ENV=production bun src/index.ts" + "start": "NODE_ENV=production bun src/index.ts", + "seed": "bun prisma/seed.ts" }, "dependencies": { "@better-auth/cli": "^1.4.18", @@ -58,15 +59,28 @@ "@tailwindcss/vite": "^4.1.18", "@tanstack/react-router": "^1.158.1", "better-auth": "^1.4.18", + "class-variance-authority": "^0.7.1", + "cmdk": "^1.0.1", "dayjs": "^1.11.19", "elysia": "^1.4.22", + "embla-carousel-react": "^8.1.1", + "input-otp": "^1.2.1", + "lucide-react": "^0.563.0", + "next-themes": "^0.4.6", "openapi-fetch": "^0.15.0", "pino": "^10.3.0", "pino-pretty": "^13.1.3", "react": "^19", + "react-day-picker": "^8.10.1", "react-dom": "^19", - "tailwindcss": "^4.1.18", - "valtio": "^2.3.0" + "react-hook-form": "^7.52.1", + "react-resizable-panels": "^2.0.22", + "recharts": "^3.7.0", + "sonner": "^1.5.0", + "tailwind-merge": "^2.4.0", + "ulid": "^3.0.2", + "valtio": "^2.3.0", + "vaul": "^0.9.1" }, "devDependencies": { "@babel/core": "^7.29.0", @@ -74,12 +88,14 @@ "@biomejs/biome": "2.3.14", "@playwright/test": "^1.58.2", "@react-dev-inspector/vite-plugin": "^2.0.1", + "@tailwindcss/postcss": "^4.1.18", "@tanstack/react-router-devtools": "^1.158.1", "@tanstack/router-vite-plugin": "^1.158.1", "@types/bun": "latest", "@types/react": "^19", "@types/react-dom": "^19", "@vitejs/plugin-react": "^5.1.3", + "autoprefixer": "^10.4.24", "openapi-typescript": "^7.10.1", "postcss": "^8.5.6", "postcss-preset-mantine": "^1.18.0", diff --git a/postcss.config.cjs b/postcss.config.cjs index 8c0c4d4..4b20477 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -1,5 +1,7 @@ module.exports = { plugins: { + "@tailwindcss/postcss": {}, + autoprefixer: {}, "postcss-preset-mantine": {}, "postcss-simple-vars": { variables: { diff --git a/prisma/seed.ts b/prisma/seed.ts index e641e5a..f97f357 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,3 +1,4 @@ +import "dotenv/config"; import { prisma } from "@/utils/db"; async function seedAdminUser() { diff --git a/src/components/ColorSchemeToggle.tsx b/src/components/ColorSchemeToggle.tsx index f246a0f..3abda18 100644 --- a/src/components/ColorSchemeToggle.tsx +++ b/src/components/ColorSchemeToggle.tsx @@ -1,34 +1,10 @@ -import { - ActionIcon, - Group, - rem, - useComputedColorScheme, - useMantineColorScheme, -} from "@mantine/core"; -import { IconMoon, IconSun } from "@tabler/icons-react"; +import React from "react"; export function ColorSchemeToggle() { - const { setColorScheme } = useMantineColorScheme(); - const computedColorScheme = useComputedColorScheme("light", { - getInitialValueInEffect: true, - }); - - return ( - - - setColorScheme(computedColorScheme === "light" ? "dark" : "light") - } - variant="default" - size="lg" - aria-label="Toggle color scheme" - > - {computedColorScheme === "light" ? ( - - ) : ( - - )} - - - ); + return ( +
+ {/* Placeholder for Color Scheme Toggle */} + Color Scheme Toggle +
+ ); } diff --git a/src/components/DashboardHeader.tsx b/src/components/DashboardHeader.tsx new file mode 100644 index 0000000..72e4728 --- /dev/null +++ b/src/components/DashboardHeader.tsx @@ -0,0 +1,15 @@ +import React from "react"; + +interface DashboardHeaderProps { + toggleSidebar: () => void; + sidebarOpened: boolean; +} + +export function DashboardHeader({ toggleSidebar, sidebarOpened }: DashboardHeaderProps) { + return ( +
+ {/* Placeholder for Dashboard Header content */} + Dashboard Header +
+ ); +} diff --git a/src/components/DashboardSidebar.tsx b/src/components/DashboardSidebar.tsx new file mode 100644 index 0000000..bd76d6d --- /dev/null +++ b/src/components/DashboardSidebar.tsx @@ -0,0 +1,84 @@ +import { Link, useLocation } from "@tanstack/react-router"; +import { Search } from "lucide-react"; +import { cn } from "./ui/utils"; + +interface SidebarProps { + className?: string; + sidebarOpened: boolean; + closeSidebar: () => void; +} + +export function DashboardSidebar({ className, sidebarOpened, closeSidebar }: SidebarProps) { + const location = useLocation(); + + // Define menu items with their paths + const menuItems = [ + { name: "Beranda", path: "/" }, + { name: "Kinerja Divisi", path: "/kinerja-divisi" }, + { name: "Pengaduan & Layanan Publik", path: "/pengaduan" }, + { name: "Jenna Analytic", path: "/analytic" }, + { name: "Demografi & Kependudukan", path: "/demografi" }, + { name: "Keuangan & Anggaran", path: "/keuangan" }, + { name: "Bumdes & UMKM Desa", path: "/bumdes" }, + { name: "Sosial", path: "/sosial" }, + { name: "Keamanan", path: "/keamanan" }, + { name: "Bantuan", path: "/bantuan" }, + { name: "Pengaturan", path: "/pengaturan" }, + ]; + + return ( +
+ {/* Logo */} +
+
+
+ DESA +
+
+ + +
+
+

+ Digitalisasi Desa Transparansi Kerja +

+
+ + {/* Search */} +
+
+ + +
+
+ + {/* Menu Items */} + +
+ ); +} diff --git a/src/components/RadixSample.tsx b/src/components/RadixSample.tsx deleted file mode 100644 index 6bd37bc..0000000 --- a/src/components/RadixSample.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import { IconChevronRight, IconUser, IconSettings, IconLogout } from '@tabler/icons-react'; - -export function RadixSample() { - return ( -
- - - - - - - - - - Profil Saya -
⌘P
-
- - - - Pengaturan -
⌘S
-
- - - - - - Keluar - - - -
-
-
-
- ); -} diff --git a/src/components/dashboard-card.tsx b/src/components/dashboard-card.tsx new file mode 100644 index 0000000..b60ddaa --- /dev/null +++ b/src/components/dashboard-card.tsx @@ -0,0 +1,43 @@ +import type { ReactNode } from "react"; +import { Card } from "./ui/card"; + +interface DashboardCardProps { + title: string; + value: string | number; + subtitle?: string; + change?: string; + icon: ReactNode; + badge?: string; +} + +export function DashboardCard({ + title, + value, + subtitle, + change, + icon, + badge, +}: DashboardCardProps) { + return ( + +
+
+

{title}

+
+

{value}

+ {badge && ( +
+ {badge} +
+ )} +
+ {subtitle &&

{subtitle}

} + {change &&

↗ {change}

} +
+
+ {icon} +
+
+
+ ); +} diff --git a/src/components/dashboard-content.tsx b/src/components/dashboard-content.tsx new file mode 100644 index 0000000..3d563fb --- /dev/null +++ b/src/components/dashboard-content.tsx @@ -0,0 +1,286 @@ +import { + Calendar, + CheckCircle, + FileText, + MessageCircle, + Users, +} from "lucide-react"; +import { + Bar, + BarChart, + CartesianGrid, + Cell, + Pie, + PieChart, + ResponsiveContainer, + XAxis, + YAxis, +} from "recharts"; +import { ulid } from "ulid"; // Import ulid +import { DashboardCard } from "./dashboard-card"; +import { Card } from "./ui/card"; + +const barChartData = [ + { id: ulid(), month: "Jan", value: 145 }, + { id: ulid(), month: "Feb", value: 165 }, + { id: ulid(), month: "Mar", value: 195 }, + { id: ulid(), month: "Apr", value: 155 }, + { id: ulid(), month: "Mei", value: 205 }, + { id: ulid(), month: "Jun", value: 185 }, +]; + +const pieChartData = [ + { id: ulid(), name: "Puas", value: 25 }, + { id: ulid(), name: "Cukup", value: 25 }, + { id: ulid(), name: "Kurang", value: 25 }, + { id: ulid(), name: "Sangat puas", value: 25 }, +]; + +const COLORS = ["#4E5BA6", "#F4C542", "#8CC63F", "#E57373"]; + +const divisiData = [ + { id: ulid(), name: "Kesejahteraan", value: 37 }, + { id: ulid(), name: "Pemerintahan", value: 26 }, + { id: ulid(), name: "Keuangan", value: 17 }, + { id: ulid(), name: "Sekretaris Desa", value: 15 }, +]; + +const eventData = [ + { id: ulid(), date: "1 Oktober 2025", title: "Hari Kesaktian Pancasila" }, + { id: ulid(), date: "15 Oktober 2025", title: "Davest" }, + { id: ulid(), date: "19 Oktober 2025", title: "Rapat Koordinasi" }, +]; + +export function DashboardContent() { + return ( +
+ {/* Stats Cards */} +
+ } + /> + } + /> + } + /> + } + badge="87%" + /> +
+ + {/* Charts Section */} +
+ {/* Bar Chart */} + +
+
+

+ Statistik Pengajuan Surat +

+

+ Trend pengajuan surat 6 bulan terakhir +

+
+ +
+ + + + + + + + +
+ + {/* Pie Chart */} + +

Tingkat Kepuasan

+

Tingkat kepuasan layanan

+ + + + {pieChartData.map((_entry, index) => ( + + ))} + + + +
+
+
+ Sangat puas (0%) +
+
+
+ Puas (0%) +
+
+
+ Cukup (0%) +
+
+
+ Kurang (0%) +
+
+
+
+ + {/* Bottom Section */} +
+ {/* Divisi Teraktif */} + +
+ + Divisi Teraktif Icon + + + + + +

Divisi Teraktif

+
+
+ {divisiData.map((divisi) => ( +
+
+ {divisi.name} + + {divisi.value} Kegiatan + +
+
+
+
+
+ ))} +
+ + + {/* Kalender */} + +
+ +

+ Kalender & Kegiatan Mendatang +

+
+
+ {eventData.map((event) => ( +
+

{event.date}

+

{event.title}

+
+ ))} +
+
+
+ + {/* APBDes Chart */} + +

Grafik APBDes

+
+
+ Belanja +
+
+
+
+
+ ); +} diff --git a/src/components/figma/ImageWithFallback.tsx b/src/components/figma/ImageWithFallback.tsx new file mode 100644 index 0000000..f23274b --- /dev/null +++ b/src/components/figma/ImageWithFallback.tsx @@ -0,0 +1,42 @@ +import type React from "react"; +import { useState } from "react"; + +const ERROR_IMG_SRC = + "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg=="; + +export function ImageWithFallback( + props: React.ImgHTMLAttributes, +) { + const [didError, setDidError] = useState(false); + + const handleError = () => { + setDidError(true); + }; + + const { src, alt, style, className, ...rest } = props; + + return didError ? ( +
+
+ Failed to load +
+
+ ) : ( + {alt} + ); +} diff --git a/src/components/kinerja-divisi.tsx b/src/components/kinerja-divisi.tsx new file mode 100644 index 0000000..8c81a1c --- /dev/null +++ b/src/components/kinerja-divisi.tsx @@ -0,0 +1,279 @@ +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; // Correct import for Button +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +const KinerjaDivisi = () => { + // Sample data for division performance + const divisions = [ + { + id: 1, + name: "Divisi Teknologi", + target: 95, + achievement: 87, + status: "On Track", + projects: 12, + budget: "Rp 2.5M", + lastUpdate: "2 days ago", + }, + { + id: 2, + name: "Divisi Keuangan", + target: 90, + achievement: 92, + status: "Above Target", + projects: 8, + budget: "Rp 1.8M", + lastUpdate: "1 day ago", + }, + { + id: 3, + name: "Divisi SDM", + target: 85, + achievement: 78, + status: "Needs Attention", + projects: 6, + budget: "Rp 1.2M", + lastUpdate: "3 days ago", + }, + { + id: 4, + name: "Divisi Operasional", + target: 92, + achievement: 89, + status: "On Track", + projects: 15, + budget: "Rp 3.2M", + lastUpdate: "5 hours ago", + }, + { + id: 5, + name: "Divisi Pemasaran", + target: 88, + achievement: 91, + status: "Above Target", + projects: 10, + budget: "Rp 2.1M", + lastUpdate: "1 day ago", + }, + ]; + + return ( +
+
+

+ Kinerja Divisi +

+
+ + +
+
+ +
+ + + Total Divisi +
+ + Total Divisi Icon + + +
+
+ +
5
+

Jumlah divisi aktif

+
+
+ + + + + Rata-rata Pencapaian + +
+ + + Rata-rata Pencapaian Icon + + + +
+
+ +
87.4%
+

Target tercapai

+
+
+ + + + + Divisi Melebihi Target + +
+ + + Divisi Melebihi Target Icon + + + +
+
+ +
2
+

Dari total 5 divisi

+
+
+
+ + + + Detail Kinerja Divisi + + + + + + Nama Divisi + Target (%) + Pencapaian (%) + Status + Proyek Aktif + Anggaran + Terakhir Diperbarui + + + + {divisions.map((division) => ( + + + {division.name} + + + {division.target}% + + + {division.achievement}% + + +
+ + + {division.status} + +
+
+ + {division.projects} + + + {division.budget} + + + {division.lastUpdate} + +
+ ))} +
+
+
+
+ +
+ + + Grafik Pencapaian Divisi + + +
+

+ Grafik pencapaian akan ditampilkan di sini +

+
+
+
+ + + + Distribusi Anggaran Divisi + + +
+

+ Diagram distribusi anggaran akan ditampilkan di sini +

+
+
+
+
+
+ ); +}; + +export default KinerjaDivisi; diff --git a/src/components/pengaduan-layanan-publik.tsx b/src/components/pengaduan-layanan-publik.tsx new file mode 100644 index 0000000..47d0a8d --- /dev/null +++ b/src/components/pengaduan-layanan-publik.tsx @@ -0,0 +1,412 @@ +import type React from "react"; +import { useState } from "react"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Select } from "@/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Textarea } from "@/components/ui/textarea"; + +const PengaduanLayananPublik = () => { + const [activeTab, setActiveTab] = useState<"complaints" | "services">( + "complaints", + ); + const [newComplaint, setNewComplaint] = useState({ + title: "", + category: "", + description: "", + }); + + // Sample data for complaints + const complaints = [ + { + id: 1, + title: "Jalan Rusak di Jalan Raya", + category: "Infrastruktur", + status: "Pending", + priority: "High", + date: "2024-02-01", + reporter: "Bapak Ahmad", + }, + { + id: 2, + title: "Pemadaman Listrik Berkelanjutan", + category: "Utilitas", + status: "In Progress", + priority: "Medium", + date: "2024-02-03", + reporter: "Ibu Sari", + }, + { + id: 3, + title: "Pelayanan Administrasi Lambat", + category: "Administrasi", + status: "Resolved", + priority: "Low", + date: "2024-01-28", + reporter: "Pak Joko", + }, + { + id: 4, + title: "Kebersihan Lingkungan", + category: "Sanitasi", + status: "Pending", + priority: "Medium", + date: "2024-02-05", + reporter: "Bu Dewi", + }, + ]; + + // Sample data for public services + const services = [ + { + id: 1, + name: "Pembuatan KTP", + description: + "Pelayanan pembuatan Kartu Tanda Penduduk baru atau perpanjangan", + status: "Available", + category: "Administrasi", + lastUpdated: "2024-02-01", + }, + { + id: 2, + name: "Pembuatan Surat Keterangan Usaha", + description: "Surat keterangan untuk keperluan usaha atau perizinan", + status: "Available", + category: "Administrasi", + lastUpdated: "2024-02-02", + }, + { + id: 3, + name: "Pelayanan Kesehatan", + description: "Pelayanan kesehatan dasar di puskesmas desa", + status: "Available", + category: "Kesehatan", + lastUpdated: "2024-01-30", + }, + { + id: 4, + name: "Program Bantuan Sosial", + description: + "Informasi dan pendaftaran program bantuan sosial dari pemerintah", + status: "Limited", + category: "Sosial", + lastUpdated: "2024-02-04", + }, + ]; + + const handleInputChange = ( + e: React.ChangeEvent, + ) => { + const { name, value } = e.target; + setNewComplaint((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const handleSelectChange = (value: string | null) => { + setNewComplaint((prev) => ({ + ...prev, + category: value ?? "", // Handle null case, assign empty string if null + })); + }; + + const handleSubmitComplaint = (e: React.FormEvent) => { + e.preventDefault(); + console.log("Submitting complaint:", newComplaint); + // Here you would typically send the complaint to your backend + alert("Pengaduan berhasil dikirim!"); + setNewComplaint({ title: "", category: "", description: "" }); + }; + + return ( +
+
+

+ Pengaduan & Layanan Publik +

+
+ + +
+
+ + {activeTab === "complaints" ? ( +
+ {/* Complaint Submission Form */} +
+ + + + Ajukan Pengaduan + + + +
+
+ + +
+ +
+ +