@rozaqi02/reusable-dashboard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.js","../src/config/cidikaWidgetConfig.js","../src/config/dummyUmkmWidgetConfig.js","../src/config/tokoSepatuWidgetConfig.js","../src/utils/formatters.js","../src/utils/adapterHelpers.js","../src/data-adapter/cidikaDashboardAdapter.js","../src/data-adapter/dummyUmkmDashboardAdapter.js","../src/data-adapter/tokoSepatuDashboardAdapter.js","../src/data-source/cidikaSupabaseSource.js","../src/data-source/tokoSepatuSupabaseSource.js","../src/hooks/useReusableDashboard.js","../src/utils/dateRange.js","../src/hooks/useRealtimeUpdate.js","../src/presentation/atoms/Button.jsx","../src/presentation/atoms/Input.jsx","../src/presentation/atoms/Icon.jsx","../src/presentation/atoms/Typography.jsx","../src/presentation/atoms/Badge.jsx","../src/presentation/atoms/SkeletonLoader.jsx","../src/presentation/molecules/StatCard.jsx","../src/presentation/molecules/SearchBar.jsx","../src/presentation/molecules/DateRangeFilter.jsx","../src/presentation/molecules/ChartHeader.jsx","../src/presentation/organisms/DataTable.jsx","../src/presentation/organisms/ChartCard.jsx","../src/presentation/organisms/FilterPanel.jsx","../src/presentation/organisms/SidebarNavigation.jsx","../src/presentation/organisms/TopbarHeader.jsx","../src/presentation/templates/DashboardLayout.jsx","../src/presentation/ReusableDashboardView.jsx","../src/utils/labels.js"],"sourcesContent":["// ──────────────────────────────────────────────────────────────────────────────\n// Config\n// ──────────────────────────────────────────────────────────────────────────────\nexport { cidikaWidgetConfig } from \"./config/cidikaWidgetConfig.js\";\nexport { dummyUmkmWidgetConfig } from \"./config/dummyUmkmWidgetConfig.js\";\nexport { tokoSepatuWidgetConfig } from \"./config/tokoSepatuWidgetConfig.js\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Data Adapter\n// ──────────────────────────────────────────────────────────────────────────────\nexport {\n adaptCidikaDashboardData,\n createEmptyDashboardData,\n} from \"./data-adapter/cidikaDashboardAdapter.js\";\nexport {\n adaptDummyUmkmData,\n createEmptyDummyUmkmData,\n} from \"./data-adapter/dummyUmkmDashboardAdapter.js\";\nexport {\n adaptTokoSepatuData,\n createEmptyTokoSepatuData,\n} from \"./data-adapter/tokoSepatuDashboardAdapter.js\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Data Source\n// ──────────────────────────────────────────────────────────────────────────────\nexport { createCidikaSupabaseSource } from \"./data-source/cidikaSupabaseSource.js\";\nexport { createTokoSepatuSupabaseSource } from \"./data-source/tokoSepatuSupabaseSource.js\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Hook\n// ──────────────────────────────────────────────────────────────────────────────\nexport { useReusableDashboard } from \"./hooks/useReusableDashboard.js\";\nexport { useRealtimeUpdate } from \"./hooks/useRealtimeUpdate.js\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Presentation — Atoms\n// ──────────────────────────────────────────────────────────────────────────────\nexport { default as Button } from \"./presentation/atoms/Button.jsx\";\nexport { default as Input } from \"./presentation/atoms/Input.jsx\";\nexport { default as Icon, resolveIcon } from \"./presentation/atoms/Icon.jsx\";\nexport { default as Typography } from \"./presentation/atoms/Typography.jsx\";\nexport { default as Badge } from \"./presentation/atoms/Badge.jsx\";\nexport { default as SkeletonLoader } from \"./presentation/atoms/SkeletonLoader.jsx\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Presentation — Molecules\n// ──────────────────────────────────────────────────────────────────────────────\nexport { default as StatCard } from \"./presentation/molecules/StatCard.jsx\";\nexport { default as SearchBar } from \"./presentation/molecules/SearchBar.jsx\";\nexport { default as DateRangeFilter } from \"./presentation/molecules/DateRangeFilter.jsx\";\nexport { default as ChartHeader } from \"./presentation/molecules/ChartHeader.jsx\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Presentation — Organisms\n// ──────────────────────────────────────────────────────────────────────────────\nexport { default as DataTable } from \"./presentation/organisms/DataTable.jsx\";\nexport { default as ChartCard } from \"./presentation/organisms/ChartCard.jsx\";\nexport { default as FilterPanel } from \"./presentation/organisms/FilterPanel.jsx\";\nexport { default as SidebarNavigation } from \"./presentation/organisms/SidebarNavigation.jsx\";\nexport { default as TopbarHeader } from \"./presentation/organisms/TopbarHeader.jsx\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Presentation — Templates\n// ──────────────────────────────────────────────────────────────────────────────\nexport { default as DashboardLayout } from \"./presentation/templates/DashboardLayout.jsx\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Presentation — Page-Level View\n// ──────────────────────────────────────────────────────────────────────────────\nexport { ReusableDashboardView } from \"./presentation/ReusableDashboardView.jsx\";\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Utils\n// ──────────────────────────────────────────────────────────────────────────────\nexport { createDashboardLabels } from \"./utils/labels.js\";\nexport {\n createDefaultFilters,\n formatYYYYMMDD,\n resolveDateRange,\n} from \"./utils/dateRange.js\";\nexport { formatDate, formatIDR, shortId } from \"./utils/formatters.js\";\nexport {\n toNumber,\n buildDayBuckets,\n sortMapEntries,\n} from \"./utils/adapterHelpers.js\";\n\n","export const cidikaWidgetConfig = {\n id: \"cidika.travel.dashboard\",\n defaultFilters: {\n statusScope: \"confirmed\",\n includePendingOverlay: false,\n audience: \"\",\n daysPreset: 30,\n sortPkgBy: \"bookings\",\n sortPkgDir: \"desc\",\n },\n widgets: {\n stats: [\n {\n id: \"bookingsConfirm\",\n label: \"confirmedBookings\",\n icon: \"TrendingUp\",\n valueKey: \"bookingsConfirm\",\n format: \"number\",\n },\n {\n id: \"revenueConfirm\",\n label: \"confirmedRevenue\",\n icon: \"DollarSign\",\n valueKey: \"revenueConfirm\",\n format: \"currency\",\n },\n {\n id: \"avgRevenue\",\n label: \"avgRevenue\",\n icon: \"Users\",\n valueKey: \"avgRevenue\",\n format: \"currency\",\n },\n {\n id: \"conversionRate\",\n label: \"conversionRate\",\n icon: \"PieChart\",\n valueKey: \"conversionRate\",\n format: \"percent\",\n },\n ],\n charts: [\n {\n id: \"dailyTrends\",\n type: \"dailyArea\",\n label: \"dailyTrends\",\n icon: \"BarChart3\",\n },\n {\n id: \"statusDistribution\",\n type: \"statusPie\",\n label: \"statusDistribution\",\n icon: \"PieChart\",\n },\n {\n id: \"audienceDistribution\",\n type: \"audiencePie\",\n label: \"audienceDistribution\",\n icon: \"Users\",\n },\n {\n id: \"topPackages\",\n type: \"topPackagesBar\",\n label: \"topPackages\",\n icon: \"TrendingUp\",\n },\n ],\n table: {\n id: \"recentBookings\",\n label: \"recentBookings\",\n icon: \"Calendar\",\n emptyLabel: \"noRecentBookings\",\n columns: [\n { id: \"date\", label: \"date\", accessor: \"createdAt\", type: \"date\" },\n { id: \"customer\", label: \"customer\", accessor: \"customerName\" },\n { id: \"package\", label: \"package\", accessor: \"packageName\" },\n { id: \"audience\", label: \"audience\", accessor: \"audienceLabel\" },\n { id: \"total\", label: \"total\", accessor: \"totalIDR\", type: \"currency\" },\n {\n id: \"status\",\n label: \"status\",\n accessor: \"statusLabel\",\n type: \"statusBadge\",\n statusAccessor: \"status\",\n },\n ],\n },\n },\n};\n","export const dummyUmkmWidgetConfig = {\n id: \"dummy.umkm.dashboard\",\n defaultFilters: {\n statusScope: \"all\",\n includePendingOverlay: false,\n audience: \"\",\n daysPreset: 30,\n sortPkgBy: \"revenue\",\n sortPkgDir: \"desc\",\n },\n widgets: {\n stats: [\n {\n id: \"orders\",\n label: \"confirmedBookings\",\n icon: \"TrendingUp\",\n valueKey: \"bookingsConfirm\",\n format: \"number\",\n },\n {\n id: \"revenue\",\n label: \"confirmedRevenue\",\n icon: \"DollarSign\",\n valueKey: \"revenueConfirm\",\n format: \"currency\",\n },\n ],\n charts: [\n {\n id: \"revenueTrend\",\n type: \"dailyArea\",\n label: \"dailyTrends\",\n icon: \"BarChart3\",\n },\n {\n id: \"recentOrderStatus\",\n type: \"statusPie\",\n label: \"statusDistribution\",\n icon: \"PieChart\",\n },\n ],\n table: {\n id: \"recentOrders\",\n label: \"recentBookings\",\n icon: \"Calendar\",\n emptyLabel: \"noRecentBookings\",\n columns: [\n { id: \"date\", label: \"date\", accessor: \"createdAt\", type: \"date\" },\n { id: \"customer\", label: \"customer\", accessor: \"customerName\" },\n { id: \"total\", label: \"total\", accessor: \"totalIDR\", type: \"currency\" },\n ],\n },\n },\n};\n","/**\r\n * Widget Configuration — Toko Sepatu Online (Studi Kasus Dummy UMKM Non-Travel)\r\n *\r\n * Konfigurasi ini membuktikan bahwa modul reusable dashboard dapat digunakan\r\n * pada domain bisnis yang berbeda (retail sepatu) hanya dengan mendefinisikan\r\n * konfigurasi baru tanpa mengubah komponen inti.\r\n *\r\n * Perbedaan dengan cidikaWidgetConfig:\r\n * - 4 stat cards (orders, revenue, avg order, products)\r\n * - 2 charts (daily trends, status distribution)\r\n * - 1 tabel (recent orders) dengan 5 kolom\r\n * - Filter lebih sederhana (tanpa audience, tanpa pending overlay)\r\n */\r\nexport const tokoSepatuWidgetConfig = {\r\n id: \"toko.sepatu.dashboard\",\r\n defaultFilters: {\r\n statusScope: \"all\",\r\n includePendingOverlay: false,\r\n audience: \"\",\r\n daysPreset: 30,\r\n sortPkgBy: \"revenue\",\r\n sortPkgDir: \"desc\",\r\n },\r\n widgets: {\r\n stats: [\r\n {\r\n id: \"totalOrders\",\r\n label: \"confirmedBookings\",\r\n icon: \"TrendingUp\",\r\n valueKey: \"bookingsConfirm\",\r\n format: \"number\",\r\n },\r\n {\r\n id: \"totalRevenue\",\r\n label: \"confirmedRevenue\",\r\n icon: \"DollarSign\",\r\n valueKey: \"revenueConfirm\",\r\n format: \"currency\",\r\n },\r\n {\r\n id: \"avgOrderValue\",\r\n label: \"avgRevenue\",\r\n icon: \"BarChart3\",\r\n valueKey: \"avgRevenue\",\r\n format: \"currency\",\r\n },\r\n {\r\n id: \"totalProducts\",\r\n label: \"totalProducts\",\r\n icon: \"PieChart\",\r\n valueKey: \"packages\",\r\n format: \"number\",\r\n },\r\n ],\r\n charts: [\r\n {\r\n id: \"dailyOrderTrends\",\r\n type: \"dailyArea\",\r\n label: \"dailyTrends\",\r\n icon: \"BarChart3\",\r\n },\r\n {\r\n id: \"orderStatusDistribution\",\r\n type: \"statusPie\",\r\n label: \"statusDistribution\",\r\n icon: \"PieChart\",\r\n },\r\n {\r\n id: \"topProducts\",\r\n type: \"topPackagesBar\",\r\n label: \"topPackages\",\r\n icon: \"TrendingUp\",\r\n },\r\n ],\r\n table: {\r\n id: \"recentOrders\",\r\n label: \"recentBookings\",\r\n icon: \"Calendar\",\r\n emptyLabel: \"noRecentBookings\",\r\n columns: [\r\n { id: \"date\", label: \"date\", accessor: \"createdAt\", type: \"date\" },\r\n { id: \"customer\", label: \"customer\", accessor: \"customerName\" },\r\n { id: \"product\", label: \"package\", accessor: \"packageName\" },\r\n { id: \"total\", label: \"total\", accessor: \"totalIDR\", type: \"currency\" },\r\n {\r\n id: \"status\",\r\n label: \"status\",\r\n accessor: \"statusLabel\",\r\n type: \"statusBadge\",\r\n statusAccessor: \"status\",\r\n },\r\n ],\r\n },\r\n },\r\n};\r\n","export function formatIDR(value) {\n try {\n return (Number(value) || 0).toLocaleString(\"id-ID\");\n } catch (_error) {\n return String(value ?? 0);\n }\n}\n\nexport function shortId(value, length = 8) {\n if (!value) return \"-\";\n return String(value).slice(0, length);\n}\n\nexport function formatDate(value, locale) {\n if (!value) return \"-\";\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return \"-\";\n return date.toLocaleDateString(locale);\n}\n","/**\n * adapterHelpers — Fungsi utilitas bersama yang digunakan oleh semua data-adapter.\n * Diekstrak dari adapter individu untuk menghindari duplikasi kode (prinsip DRY).\n */\n\n/**\n * Mengkonversi nilai apapun ke angka yang valid.\n * Mengembalikan 0 jika nilai tidak valid atau bukan angka finite.\n *\n * @param {*} value - Nilai yang akan dikonversi.\n * @returns {number} Angka finite, atau 0 jika tidak valid.\n */\nexport function toNumber(value) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\n/**\n * Membangun array bucket harian untuk chart tren.\n * Setiap bucket berisi dateKey, label terformat, dan counter awal (0).\n *\n * @param {number} daysWindow - Jumlah hari dalam rentang.\n * @param {string} fromISO - Tanggal awal dalam format ISO.\n * @param {string} dateLocale - Locale untuk format tanggal (misal: \"id-ID\").\n * @returns {Array<{dateKey: string, label: string, count: number, revenue: number, pendingCount: number}>}\n */\nexport function buildDayBuckets(daysWindow, fromISO, dateLocale) {\n const start = new Date(fromISO);\n return Array.from({ length: daysWindow }).map((_, index) => {\n const day = new Date(start);\n day.setDate(start.getDate() + index);\n return {\n dateKey: day.toISOString().slice(0, 10),\n label: day.toLocaleDateString(dateLocale, {\n day: \"2-digit\",\n month: \"short\",\n }),\n count: 0,\n revenue: 0,\n pendingCount: 0,\n };\n });\n}\n\n/**\n * Mengurutkan entri Map berdasarkan nilai numerik.\n *\n * @param {Map} map - Map yang akan diurutkan.\n * @param {\"asc\"|\"desc\"} direction - Arah pengurutan.\n * @returns {Array<[string, number]>} Array entri terurut.\n */\nexport function sortMapEntries(map, direction) {\n return Array.from(map.entries()).sort((a, b) =>\n direction === \"asc\" ? a[1] - b[1] : b[1] - a[1]\n );\n}\n","import { shortId } from \"../utils/formatters.js\";\nimport { toNumber, buildDayBuckets, sortMapEntries } from \"../utils/adapterHelpers.js\";\n\nfunction createPackageTitleResolver(packageLocales, languageCode) {\n const byPackage = new Map();\n\n packageLocales.forEach((row) => {\n if (!row.package_id) return;\n const current = byPackage.get(row.package_id) || {};\n byPackage.set(row.package_id, {\n ...current,\n [row.lang]: row.title,\n });\n });\n\n return (packageId) => {\n if (!packageId) return \"-\";\n const labels = byPackage.get(packageId);\n if (!labels) return shortId(packageId, 6);\n return (\n labels[languageCode] ||\n labels.en ||\n labels.id ||\n Object.values(labels).find(Boolean) ||\n shortId(packageId, 6)\n );\n };\n}\n\nexport function createEmptyDashboardData() {\n return {\n stats: {\n bookingsConfirm: 0,\n bookingsPending: 0,\n revenueConfirm: 0,\n packages: 0,\n sections: 0,\n avgRevenue: 0,\n conversionRate: 0,\n },\n charts: {\n dailyTrends: [],\n statusDistribution: [],\n audienceDistribution: [],\n topPackages: [],\n },\n table: {\n recentBookings: [],\n },\n };\n}\n\nexport function adaptCidikaDashboardData({\n raw,\n filters,\n range,\n dateLocale,\n languageCode,\n labels,\n}) {\n if (!raw) return createEmptyDashboardData();\n\n const dailyBuckets = buildDayBuckets(range.daysWindow, range.fromISO, dateLocale);\n const dayLookup = new Map(\n dailyBuckets.map((bucket) => [bucket.dateKey, bucket])\n );\n\n const statusMap = new Map();\n const audienceMap = new Map();\n const packageCountMap = new Map();\n const packageRevenueMap = new Map();\n const getPackageTitle = createPackageTitleResolver(\n raw.packageLocales || [],\n languageCode\n );\n\n let bookingsConfirm = 0;\n let bookingsPending = 0;\n let revenueConfirm = 0;\n\n (raw.bookings || []).forEach((row) => {\n const dayKey = String(row.created_at || \"\").slice(0, 10);\n const status = String(row.status || \"pending\").toLowerCase();\n const total = toNumber(row.total_idr);\n const audience = row.audience || \"unknown\";\n\n statusMap.set(status, (statusMap.get(status) || 0) + 1);\n audienceMap.set(audience, (audienceMap.get(audience) || 0) + 1);\n\n const bucket = dayLookup.get(dayKey);\n if (bucket) {\n if (status === \"confirmed\") {\n bucket.count += 1;\n bucket.revenue += total;\n }\n if (status === \"pending\") {\n bucket.pendingCount += 1;\n }\n }\n\n if (status === \"confirmed\") {\n bookingsConfirm += 1;\n revenueConfirm += total;\n packageCountMap.set(\n row.package_id,\n (packageCountMap.get(row.package_id) || 0) + 1\n );\n packageRevenueMap.set(\n row.package_id,\n (packageRevenueMap.get(row.package_id) || 0) + total\n );\n } else if (status === \"pending\") {\n bookingsPending += 1;\n }\n });\n\n const statusDistribution = sortMapEntries(statusMap, \"desc\").map(\n ([status, count]) => ({\n status,\n label: labels.formatStatusLabel(status),\n count,\n })\n );\n\n const audienceDistribution = sortMapEntries(audienceMap, \"desc\").map(\n ([audience, count]) => ({\n audience,\n label: labels.formatAudienceLabel(audience),\n count,\n })\n );\n\n const metricMap =\n filters.sortPkgBy === \"revenue\" ? packageRevenueMap : packageCountMap;\n\n const topPackages = sortMapEntries(metricMap, filters.sortPkgDir)\n .slice(0, 5)\n .map(([packageId, value]) => ({\n packageId,\n name: getPackageTitle(packageId),\n value: toNumber(value),\n }));\n\n const recentBookings = (raw.recent || []).map((row) => {\n const status = String(row.status || \"pending\").toLowerCase();\n return {\n id: row.id,\n createdAt: row.created_at,\n customerName: row.customer_name || \"-\",\n packageName: getPackageTitle(row.package_id),\n audienceLabel: labels.formatAudienceLabel(row.audience),\n totalIDR: toNumber(row.total_idr),\n status,\n statusLabel: labels.formatStatusLabel(status),\n };\n });\n\n const avgRevenue =\n bookingsConfirm > 0 ? Math.round(revenueConfirm / bookingsConfirm) : 0;\n const conversionRate =\n bookingsConfirm + bookingsPending > 0\n ? Math.round((bookingsConfirm / (bookingsConfirm + bookingsPending)) * 100)\n : 0;\n\n return {\n stats: {\n bookingsConfirm,\n bookingsPending,\n revenueConfirm,\n packages: toNumber(raw.staticCounts?.packages),\n sections: toNumber(raw.staticCounts?.sections),\n avgRevenue,\n conversionRate,\n },\n charts: {\n dailyTrends: dailyBuckets,\n statusDistribution,\n audienceDistribution,\n topPackages,\n },\n table: {\n recentBookings,\n },\n };\n}\n","/**\n * dummyUmkmDashboardAdapter — Data-adapter layer untuk studi kasus\n * aplikasi dummy UMKM non-travel (penjualan produk).\n *\n * Adapter ini membuktikan bahwa modul reusable dashboard dapat digunakan\n * pada domain bisnis yang berbeda dari Cidika Travel hanya dengan\n * mengganti adapter, tanpa mengubah komponen inti.\n *\n * Struktur data Supabase dummy UMKM yang diharapkan:\n * - Tabel `orders` : id, created_at, total_amount, status, customer_name, product_id\n * - Tabel `products` : id, name\n * - Tabel `customers`: id, name\n */\n\nimport { toNumber, buildDayBuckets } from \"../utils/adapterHelpers.js\";\n\n/**\n * Membuat state kosong yang sesuai dengan kontrak data dummy UMKM.\n * Dipanggil oleh useReusableDashboard sebagai initial state dan saat error.\n *\n * @returns {object} Empty dashboard data object.\n */\nexport function createEmptyDummyUmkmData() {\n return {\n stats: {\n bookingsConfirm: 0,\n revenueConfirm: 0,\n totalProducts: 0,\n totalCustomers: 0,\n },\n charts: {\n dailyTrends: [],\n statusDistribution: [],\n audienceDistribution: [],\n topPackages: [],\n },\n table: {\n recentBookings: [],\n },\n };\n}\n\n/**\n * Memetakan data mentah dari Supabase dummy UMKM ke format standar widget.\n *\n * Format `raw` yang diharapkan dari dataSource:\n * ```\n * {\n * bookings: Array<{ id, created_at, total_amount, status, customer_name, product_id }>,\n * recent: Array<{ id, created_at, customer_name, total_amount, status, product_id }>,\n * staticCounts: { packages: number, sections: number } // opsional\n * }\n * ```\n *\n * @param {object} params\n * @param {object} params.raw - Data mentah dari dataSource.\n * @param {object} params.filters - State filter aktif.\n * @param {object} params.range - Rentang tanggal { fromISO, toISO, daysWindow }.\n * @param {string} params.dateLocale - Locale untuk format tanggal (misal: \"id-ID\").\n * @param {object} [params.labels] - Label i18n (opsional, untuk format status).\n * @returns {object} Objek data standar { stats, charts, table }.\n */\nexport function adaptDummyUmkmData({ raw, filters, range, dateLocale, labels }) {\n if (!raw) return createEmptyDummyUmkmData();\n\n const orders = raw.bookings || [];\n const recent = raw.recent || [];\n\n // Bangun bucket harian untuk chart tren\n const dailyBuckets = buildDayBuckets(range.daysWindow, range.fromISO, dateLocale);\n const dayLookup = new Map(dailyBuckets.map((b) => [b.dateKey, b]));\n\n const statusMap = new Map();\n let totalOrders = 0;\n let totalRevenue = 0;\n\n orders.forEach((row) => {\n const dayKey = String(row.created_at || \"\").slice(0, 10);\n const status = String(row.status || \"pending\").toLowerCase();\n const amount = toNumber(row.total_amount);\n\n statusMap.set(status, (statusMap.get(status) || 0) + 1);\n\n const bucket = dayLookup.get(dayKey);\n if (bucket) {\n if (status === \"confirmed\") {\n bucket.count += 1;\n bucket.revenue += amount;\n }\n if (status === \"pending\") {\n bucket.pendingCount += 1;\n }\n }\n\n if (status === \"confirmed\") {\n totalOrders += 1;\n totalRevenue += amount;\n }\n });\n\n // Distribusi status untuk pie chart\n const statusDistribution = Array.from(statusMap.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([status, count]) => ({\n status,\n label: labels?.formatStatusLabel ? labels.formatStatusLabel(status) : status,\n count,\n }));\n\n // Tabel recent orders — field mapping ke kontrak standar\n const recentBookings = recent.map((row) => {\n const status = String(row.status || \"pending\").toLowerCase();\n return {\n id: row.id,\n createdAt: row.created_at,\n customerName: row.customer_name || \"-\",\n packageName: row.product_name || row.product_id || \"-\",\n totalIDR: toNumber(row.total_amount),\n status,\n statusLabel: labels?.formatStatusLabel ? labels.formatStatusLabel(status) : status,\n };\n });\n\n return {\n stats: {\n bookingsConfirm: totalOrders,\n revenueConfirm: totalRevenue,\n totalProducts: toNumber(raw.staticCounts?.packages),\n totalCustomers: toNumber(raw.staticCounts?.sections),\n },\n charts: {\n dailyTrends: dailyBuckets,\n statusDistribution,\n audienceDistribution: [],\n topPackages: [],\n },\n table: {\n recentBookings,\n },\n };\n}\n","/**\r\n * tokoSepatuDashboardAdapter — Data-adapter layer untuk studi kasus\r\n * Toko Sepatu Online (domain retail/e-commerce).\r\n *\r\n * Adapter ini membuktikan bahwa modul reusable dashboard dapat digunakan\r\n * pada domain bisnis yang berbeda dari Cidika Travel hanya dengan\r\n * mengganti adapter, tanpa mengubah komponen inti.\r\n *\r\n * Struktur data Supabase Toko Sepatu yang diharapkan:\r\n * - Tabel `orders` : id, created_at, total_amount, status, customer_id\r\n * - Tabel `products` : id, name, brand, category, price_idr, stock\r\n * - Tabel `customers` : id, name, email, phone, city\r\n * - Tabel `order_items` : id, order_id, product_id, qty, price_idr, subtotal\r\n */\r\n\r\nimport { shortId } from \"../utils/formatters.js\";\r\nimport { toNumber, buildDayBuckets, sortMapEntries } from \"../utils/adapterHelpers.js\";\r\n\r\n/**\r\n * Membuat state kosong yang sesuai dengan kontrak data toko sepatu.\r\n * @returns {object} Empty dashboard data object.\r\n */\r\nexport function createEmptyTokoSepatuData() {\r\n return {\r\n stats: {\r\n bookingsConfirm: 0,\r\n bookingsPending: 0,\r\n revenueConfirm: 0,\r\n packages: 0,\r\n sections: 0,\r\n avgRevenue: 0,\r\n conversionRate: 0,\r\n },\r\n charts: {\r\n dailyTrends: [],\r\n statusDistribution: [],\r\n audienceDistribution: [],\r\n topPackages: [],\r\n },\r\n table: {\r\n recentBookings: [],\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Memetakan data mentah dari Supabase Toko Sepatu ke format standar widget.\r\n *\r\n * @param {object} params\r\n * @param {object} params.raw - Data mentah dari dataSource.\r\n * @param {object} params.filters - State filter aktif.\r\n * @param {object} params.range - Rentang tanggal { fromISO, toISO, daysWindow }.\r\n * @param {string} params.dateLocale - Locale untuk format tanggal.\r\n * @param {object} [params.labels] - Label i18n.\r\n * @returns {object} Objek data standar { stats, charts, table }.\r\n */\r\nexport function adaptTokoSepatuData({ raw, filters, range, dateLocale, labels }) {\r\n if (!raw) return createEmptyTokoSepatuData();\r\n\r\n const orders = raw.bookings || [];\r\n const recent = raw.recent || [];\r\n\r\n // Bangun bucket harian untuk chart tren\r\n const dailyBuckets = buildDayBuckets(range.daysWindow, range.fromISO, dateLocale);\r\n const dayLookup = new Map(dailyBuckets.map((b) => [b.dateKey, b]));\r\n\r\n const statusMap = new Map();\r\n const productCountMap = new Map();\r\n const productRevenueMap = new Map();\r\n\r\n let ordersConfirm = 0;\r\n let ordersPending = 0;\r\n let revenueConfirm = 0;\r\n\r\n // Buat lookup nama produk\r\n const productNameMap = new Map();\r\n (raw.products || []).forEach((p) => {\r\n productNameMap.set(p.id, p.name);\r\n });\r\n\r\n orders.forEach((row) => {\r\n const dayKey = String(row.created_at || \"\").slice(0, 10);\r\n const status = String(row.status || \"pending\").toLowerCase();\r\n const total = toNumber(row.total_amount);\r\n\r\n statusMap.set(status, (statusMap.get(status) || 0) + 1);\r\n\r\n const bucket = dayLookup.get(dayKey);\r\n if (bucket) {\r\n if (status === \"confirmed\") {\r\n bucket.count += 1;\r\n bucket.revenue += total;\r\n }\r\n if (status === \"pending\") {\r\n bucket.pendingCount += 1;\r\n }\r\n }\r\n\r\n if (status === \"confirmed\") {\r\n ordersConfirm += 1;\r\n revenueConfirm += total;\r\n\r\n // Hitung produk terlaris dari order_items\r\n const items = row.order_items || [];\r\n items.forEach((item) => {\r\n const pid = item.product_id;\r\n productCountMap.set(pid, (productCountMap.get(pid) || 0) + toNumber(item.qty));\r\n productRevenueMap.set(pid, (productRevenueMap.get(pid) || 0) + toNumber(item.subtotal));\r\n });\r\n } else if (status === \"pending\") {\r\n ordersPending += 1;\r\n }\r\n });\r\n\r\n // Distribusi status\r\n const statusDistribution = sortMapEntries(statusMap, \"desc\").map(\r\n ([status, count]) => ({\r\n status,\r\n label: labels?.formatStatusLabel ? labels.formatStatusLabel(status) : status,\r\n count,\r\n })\r\n );\r\n\r\n // Top products\r\n const metricMap =\r\n filters.sortPkgBy === \"revenue\" ? productRevenueMap : productCountMap;\r\n\r\n const topPackages = sortMapEntries(metricMap, filters.sortPkgDir || \"desc\")\r\n .slice(0, 5)\r\n .map(([productId, value]) => ({\r\n packageId: productId,\r\n name: productNameMap.get(productId) || shortId(productId, 6),\r\n value: toNumber(value),\r\n }));\r\n\r\n // Tabel recent orders\r\n const recentBookings = recent.map((row) => {\r\n const status = String(row.status || \"pending\").toLowerCase();\r\n // Ambil nama produk dari item pertama atau dari join\r\n const productName =\r\n row.product_name ||\r\n (row.order_items && row.order_items[0]\r\n ? productNameMap.get(row.order_items[0].product_id)\r\n : null) ||\r\n \"-\";\r\n\r\n return {\r\n id: row.id,\r\n createdAt: row.created_at,\r\n customerName: row.customer_name || \"-\",\r\n packageName: productName,\r\n totalIDR: toNumber(row.total_amount),\r\n status,\r\n statusLabel: labels?.formatStatusLabel ? labels.formatStatusLabel(status) : status,\r\n };\r\n });\r\n\r\n const avgRevenue =\r\n ordersConfirm > 0 ? Math.round(revenueConfirm / ordersConfirm) : 0;\r\n const conversionRate =\r\n ordersConfirm + ordersPending > 0\r\n ? Math.round((ordersConfirm / (ordersConfirm + ordersPending)) * 100)\r\n : 0;\r\n\r\n return {\r\n stats: {\r\n bookingsConfirm: ordersConfirm,\r\n bookingsPending: ordersPending,\r\n revenueConfirm,\r\n packages: toNumber(raw.staticCounts?.products),\r\n sections: toNumber(raw.staticCounts?.customers),\r\n avgRevenue,\r\n conversionRate,\r\n },\r\n charts: {\r\n dailyTrends: dailyBuckets,\r\n statusDistribution,\r\n audienceDistribution: [],\r\n topPackages,\r\n },\r\n table: {\r\n recentBookings,\r\n },\r\n };\r\n}\r\n","function ensureNoError(response, message) {\n if (response?.error) {\n const err = new Error(message);\n err.cause = response.error;\n throw err;\n }\n}\n\nexport function createCidikaSupabaseSource(supabase) {\n return {\n async fetchDashboardSnapshot({\n fromISO,\n toISO,\n audience,\n statusScope,\n languageCode,\n }) {\n const bookingsQuery = supabase\n .from(\"bookings\")\n .select(\n \"id, created_at, total_idr, status, package_id, audience, customer_name\"\n )\n .gte(\"created_at\", fromISO)\n .lte(\"created_at\", toISO)\n .order(\"created_at\", { ascending: true });\n\n if (audience) bookingsQuery.eq(\"audience\", audience);\n\n const recentQuery = supabase\n .from(\"bookings\")\n .select(\n \"id, created_at, customer_name, total_idr, status, package_id, audience\"\n )\n .gte(\"created_at\", fromISO)\n .lte(\"created_at\", toISO)\n .order(\"created_at\", { ascending: false })\n .limit(10);\n\n if (audience) recentQuery.eq(\"audience\", audience);\n if (statusScope && statusScope !== \"all\") {\n recentQuery.eq(\"status\", statusScope);\n }\n\n const [bookingsRes, recentRes, packagesRes, sectionsRes] = await Promise.all(\n [\n bookingsQuery,\n recentQuery,\n supabase.from(\"packages\").select(\"*\", { count: \"exact\", head: true }),\n supabase\n .from(\"page_sections\")\n .select(\"*\", { count: \"exact\", head: true }),\n ]\n );\n\n ensureNoError(bookingsRes, \"Failed to load booking rows.\");\n ensureNoError(recentRes, \"Failed to load recent rows.\");\n\n const bookings = bookingsRes.data || [];\n const recent = recentRes.data || [];\n\n const packageIds = Array.from(\n new Set(\n [...bookings, ...recent]\n .map((row) => row.package_id)\n .filter((value) => Boolean(value))\n )\n );\n\n let packageLocales = [];\n if (packageIds.length > 0) {\n const localeRes = await supabase\n .from(\"package_locales\")\n .select(\"package_id,title,lang\")\n .in(\"package_id\", packageIds)\n .in(\"lang\", [languageCode, \"en\", \"id\"]);\n\n if (!localeRes.error) {\n packageLocales = localeRes.data || [];\n }\n }\n\n return {\n bookings,\n recent,\n packageLocales,\n staticCounts: {\n packages: packagesRes.error ? 0 : packagesRes.count || 0,\n sections: sectionsRes.error ? 0 : sectionsRes.count || 0,\n },\n };\n },\n\n subscribeLiveUpdate(onEvent) {\n const channel = supabase\n .channel(\"reusable-dashboard-live\")\n .on(\n \"postgres_changes\",\n { event: \"*\", schema: \"public\", table: \"bookings\" },\n onEvent\n )\n .on(\n \"postgres_changes\",\n { event: \"*\", schema: \"public\", table: \"packages\" },\n onEvent\n )\n .on(\n \"postgres_changes\",\n { event: \"*\", schema: \"public\", table: \"page_sections\" },\n onEvent\n )\n .on(\n \"postgres_changes\",\n { event: \"*\", schema: \"public\", table: \"package_locales\" },\n onEvent\n )\n .subscribe();\n\n return () => {\n supabase.removeChannel(channel);\n };\n },\n };\n}\n","/**\r\n * tokoSepatuSupabaseSource — Data-source layer untuk studi kasus\r\n * Toko Sepatu Online.\r\n *\r\n * Mengimplementasikan kontrak yang sama dengan cidikaSupabaseSource:\r\n * - fetchDashboardSnapshot({ fromISO, toISO, statusScope })\r\n * - subscribeLiveUpdate(onEvent)\r\n *\r\n * Tabel yang diquery: orders, order_items, products, customers\r\n */\r\n\r\nfunction ensureNoError(response, message) {\r\n if (response?.error) {\r\n const err = new Error(message);\r\n err.cause = response.error;\r\n throw err;\r\n }\r\n}\r\n\r\n/**\r\n * Membuat data source untuk Toko Sepatu Online.\r\n *\r\n * @param {object} supabase - Instance Supabase client.\r\n * @returns {object} Objek data source { fetchDashboardSnapshot, subscribeLiveUpdate }.\r\n */\r\nexport function createTokoSepatuSupabaseSource(supabase) {\r\n return {\r\n /**\r\n * Mengambil snapshot data dashboard dari Supabase.\r\n */\r\n async fetchDashboardSnapshot({\r\n fromISO,\r\n toISO,\r\n audience,\r\n statusScope,\r\n }) {\r\n // Query semua orders dalam rentang waktu (dengan order_items untuk top products)\r\n const ordersQuery = supabase\r\n .from(\"orders\")\r\n .select(\r\n \"id, created_at, total_amount, status, customer_id, order_items(product_id, qty, price_idr, subtotal)\"\r\n )\r\n .gte(\"created_at\", fromISO)\r\n .lte(\"created_at\", toISO)\r\n .order(\"created_at\", { ascending: true });\r\n\r\n // Query recent orders (10 terbaru) dengan nama customer\r\n const recentQuery = supabase\r\n .from(\"orders\")\r\n .select(\r\n \"id, created_at, total_amount, status, customers(name), order_items(product_id, qty, products(name))\"\r\n )\r\n .gte(\"created_at\", fromISO)\r\n .lte(\"created_at\", toISO)\r\n .order(\"created_at\", { ascending: false })\r\n .limit(10);\r\n\r\n if (statusScope && statusScope !== \"all\") {\r\n recentQuery.eq(\"status\", statusScope);\r\n }\r\n\r\n const [ordersRes, recentRes, productsRes, customersRes] =\r\n await Promise.all([\r\n ordersQuery,\r\n recentQuery,\r\n supabase\r\n .from(\"products\")\r\n .select(\"id, name, brand, category, price_idr\"),\r\n supabase\r\n .from(\"customers\")\r\n .select(\"*\", { count: \"exact\", head: true }),\r\n ]);\r\n\r\n ensureNoError(ordersRes, \"Failed to load orders.\");\r\n ensureNoError(recentRes, \"Failed to load recent orders.\");\r\n\r\n const orders = ordersRes.data || [];\r\n const recentRaw = recentRes.data || [];\r\n const products = productsRes.data || [];\r\n\r\n // Map recent orders ke format yang adapter harapkan\r\n const recent = recentRaw.map((row) => ({\r\n id: row.id,\r\n created_at: row.created_at,\r\n total_amount: row.total_amount,\r\n status: row.status,\r\n customer_name: row.customers?.name || \"-\",\r\n product_name:\r\n row.order_items?.[0]?.products?.name || \"-\",\r\n order_items: row.order_items,\r\n }));\r\n\r\n return {\r\n bookings: orders,\r\n recent,\r\n products,\r\n packageLocales: [],\r\n staticCounts: {\r\n products: products.length,\r\n customers: customersRes.error ? 0 : customersRes.count || 0,\r\n },\r\n };\r\n },\r\n\r\n /**\r\n * Subscribe ke perubahan realtime pada tabel orders dan products.\r\n */\r\n subscribeLiveUpdate(onEvent) {\r\n const channel = supabase\r\n .channel(\"toko-sepatu-dashboard-live\")\r\n .on(\r\n \"postgres_changes\",\r\n { event: \"*\", schema: \"public\", table: \"orders\" },\r\n onEvent\r\n )\r\n .on(\r\n \"postgres_changes\",\r\n { event: \"*\", schema: \"public\", table: \"products\" },\r\n onEvent\r\n )\r\n .on(\r\n \"postgres_changes\",\r\n { event: \"*\", schema: \"public\", table: \"order_items\" },\r\n onEvent\r\n )\r\n .subscribe();\r\n\r\n return () => {\r\n supabase.removeChannel(channel);\r\n };\r\n },\r\n };\r\n}\r\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { createDefaultFilters, resolveDateRange } from \"../utils/dateRange.js\";\nimport { useRealtimeUpdate } from \"./useRealtimeUpdate.js\";\n\nexport function useReusableDashboard({\n config,\n dataSource,\n adapter,\n createEmptyState,\n languageCode,\n dateLocale,\n labels,\n}) {\n const [filters, setFilters] = useState(() =>\n createDefaultFilters(config?.defaultFilters)\n );\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(\"\");\n const [lastUpdatedAt, setLastUpdatedAt] = useState(null);\n const [data, setData] = useState(() => createEmptyState());\n\n\n const range = useMemo(\n () =>\n resolveDateRange({\n daysPreset: filters.daysPreset,\n dateFrom: filters.dateFrom,\n dateTo: filters.dateTo,\n }),\n [filters.daysPreset, filters.dateFrom, filters.dateTo]\n );\n\n const refresh = useCallback(\n async ({ silent = false } = {}) => {\n if (!dataSource?.fetchDashboardSnapshot) return;\n\n if (!silent) {\n setLoading(true);\n setError(\"\");\n }\n\n try {\n const raw = await dataSource.fetchDashboardSnapshot({\n fromISO: range.fromISO,\n toISO: range.toISO,\n audience: filters.audience,\n statusScope: filters.statusScope,\n languageCode,\n });\n\n const adapted = adapter({\n raw,\n filters,\n range,\n dateLocale,\n languageCode,\n labels,\n });\n\n setData(adapted);\n setLastUpdatedAt(new Date());\n if (!silent) setError(\"\");\n } catch (loadError) {\n console.error(loadError);\n if (!silent) {\n setError(labels.loadFailed);\n setData(createEmptyState());\n }\n } finally {\n if (!silent) setLoading(false);\n }\n },\n [\n dataSource,\n range,\n filters,\n languageCode,\n adapter,\n dateLocale,\n labels,\n createEmptyState,\n ]\n );\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n const { liveUpdateEnabled } = useRealtimeUpdate({\n dataSource,\n onUpdate: () => refresh({ silent: true }),\n });\n\n const updateFilter = useCallback((field, value) => {\n setFilters((current) => ({\n ...current,\n [field]: value,\n }));\n }, []);\n\n const resetFilters = useCallback(() => {\n setFilters(createDefaultFilters(config?.defaultFilters));\n }, [config?.defaultFilters]);\n\n return {\n filters,\n updateFilter,\n resetFilters,\n loading,\n error,\n data,\n refresh,\n range,\n liveUpdateEnabled,\n lastUpdatedAt,\n };\n}\n","function startOfDayISO(date) {\n const value = new Date(date);\n value.setHours(0, 0, 0, 0);\n return value.toISOString();\n}\n\nfunction endOfDayISO(date) {\n const value = new Date(date);\n value.setHours(23, 59, 59, 999);\n return value.toISOString();\n}\n\nexport function formatYYYYMMDD(date) {\n const value = new Date(date);\n const year = value.getFullYear();\n const month = String(value.getMonth() + 1).padStart(2, \"0\");\n const day = String(value.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\nexport function createDefaultFilters(base = {}) {\n const fromDate = new Date();\n fromDate.setDate(fromDate.getDate() - 29);\n\n return {\n statusScope: \"confirmed\",\n includePendingOverlay: false,\n audience: \"\",\n daysPreset: 30,\n dateFrom: formatYYYYMMDD(fromDate),\n dateTo: formatYYYYMMDD(new Date()),\n sortPkgBy: \"bookings\",\n sortPkgDir: \"desc\",\n ...base,\n };\n}\n\n/** Tahun minimum yang diizinkan untuk input tanggal kustom. */\nconst MIN_YEAR = 2000;\n/** Batas maksimum rentang hari untuk mencegah loop tak terhingga (5 tahun). */\nconst MAX_DAYS_WINDOW = 365 * 5;\n\n/**\n * Memvalidasi apakah tanggal masuk akal (tahun >= MIN_YEAR dan <= tahun sekarang + 1).\n * @param {Date} date\n * @returns {boolean}\n */\nfunction isReasonableDate(date) {\n if (!date || Number.isNaN(date.getTime())) return false;\n const year = date.getFullYear();\n return year >= MIN_YEAR && year <= new Date().getFullYear() + 1;\n}\n\nexport function resolveDateRange({ daysPreset, dateFrom, dateTo }) {\n if (Number(daysPreset) > 0) {\n const fromDate = new Date();\n fromDate.setDate(fromDate.getDate() - (Number(daysPreset) - 1));\n const toDate = new Date();\n return {\n fromISO: startOfDayISO(fromDate),\n toISO: endOfDayISO(toDate),\n daysWindow: Number(daysPreset),\n };\n }\n\n const fallbackFrom = new Date(Date.now() - 29 * 24 * 60 * 60 * 1000);\n const fallbackTo = new Date();\n\n let from = dateFrom ? new Date(dateFrom) : fallbackFrom;\n let to = dateTo ? new Date(dateTo) : fallbackTo;\n\n // Jika tanggal tidak masuk akal (misal tahun 0202), gunakan fallback\n if (!isReasonableDate(from)) from = fallbackFrom;\n if (!isReasonableDate(to)) to = fallbackTo;\n\n if (from.getTime() > to.getTime()) {\n const swap = from;\n from = to;\n to = swap;\n }\n\n const fromISO = startOfDayISO(from);\n const toISO = endOfDayISO(to);\n const diffMs = new Date(toISO).getTime() - new Date(fromISO).getTime();\n // Cap daysWindow agar tidak pernah melebihi MAX_DAYS_WINDOW\n const daysWindow = Math.min(\n MAX_DAYS_WINDOW,\n Math.max(1, Math.round(diffMs / 86400000) + 1)\n );\n\n return { fromISO, toISO, daysWindow };\n}\n","import { useEffect, useState } from \"react\";\n\n/**\n * useRealtimeUpdate — Custom hook untuk mengelola subscription live update\n * melalui mekanisme Supabase Realtime (Postgres Changes).\n *\n * Hook ini mengabstraksikan logika subscription dan debounce sehingga dapat\n * digunakan secara independen oleh consumer yang membutuhkan live update\n * tanpa menggunakan useReusableDashboard secara penuh.\n *\n * @param {object} params\n * @param {object} params.dataSource - Objek data source yang mengimplementasikan\n * `subscribeLiveUpdate(callback): unsubscribeFn`.\n * @param {Function} params.onUpdate - Callback yang dipanggil saat ada perubahan data.\n * Dipanggil setelah debounce selesai.\n * @param {number} [params.debounceMs=350] - Durasi debounce dalam milidetik.\n *\n * @returns {{ liveUpdateEnabled: boolean }} State apakah live update aktif.\n *\n * @example\n * const { liveUpdateEnabled } = useRealtimeUpdate({\n * dataSource,\n * onUpdate: () => refresh({ silent: true }),\n * });\n */\nexport function useRealtimeUpdate({ dataSource, onUpdate, debounceMs = 350 }) {\n const [liveUpdateEnabled, setLiveUpdateEnabled] = useState(false);\n\n useEffect(() => {\n if (!dataSource?.subscribeLiveUpdate) return undefined;\n\n let debounceId;\n setLiveUpdateEnabled(true);\n\n const unsubscribe = dataSource.subscribeLiveUpdate(() => {\n clearTimeout(debounceId);\n debounceId = setTimeout(() => {\n onUpdate?.();\n }, debounceMs);\n });\n\n return () => {\n clearTimeout(debounceId);\n setLiveUpdateEnabled(false);\n unsubscribe?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dataSource, debounceMs]);\n // Note: onUpdate sengaja tidak dimasukkan dependency array untuk menghindari\n // re-subscribe yang tidak perlu saat parent re-render. Consumer harus\n // memoize callback-nya dengan useCallback jika ingin reaktivitas penuh.\n\n return { liveUpdateEnabled };\n}\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * Button — Atom komponen tombol aksi.\n * Mendukung varian primary, secondary, dan ghost.\n *\n * @param {object} props\n * @param {\"primary\"|\"secondary\"|\"ghost\"} [props.variant=\"primary\"] - Varian visual tombol.\n * @param {\"sm\"|\"md\"|\"lg\"} [props.size=\"md\"] - Ukuran tombol.\n * @param {boolean} [props.disabled=false] - Apakah tombol non-aktif.\n * @param {string} [props.className=\"\"] - ClassName tambahan dari consumer.\n * @param {Function} [props.onClick] - Callback saat tombol diklik.\n * @param {React.ReactNode} props.children - Konten tombol.\n */\nexport default function Button({\n variant = \"primary\",\n size = \"md\",\n disabled = false,\n className = \"\",\n onClick,\n children,\n ...rest\n}) {\n const base =\n \"inline-flex items-center justify-center font-medium rounded-xl transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed\";\n\n const variants = {\n primary: \"bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500\",\n secondary:\n \"border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-200 hover:bg-slate-50 dark:hover:bg-slate-700 focus:ring-slate-400\",\n ghost:\n \"text-slate-600 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 focus:ring-slate-400\",\n };\n\n const sizes = {\n sm: \"px-2.5 py-1 text-xs gap-1\",\n md: \"px-3 py-1.5 text-sm gap-1.5\",\n lg: \"px-4 py-2 text-base gap-2\",\n };\n\n const classes = [base, variants[variant] || variants.primary, sizes[size] || sizes.md, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <button\n type=\"button\"\n className={classes}\n disabled={disabled}\n onClick={onClick}\n {...rest}\n >\n {children}\n </button>\n );\n}\n\nButton.propTypes = {\n /** Varian visual tombol. */\n variant: PropTypes.oneOf([\"primary\", \"secondary\", \"ghost\"]),\n /** Ukuran tombol. */\n size: PropTypes.oneOf([\"sm\", \"md\", \"lg\"]),\n /** Apakah tombol non-aktif. */\n disabled: PropTypes.bool,\n /** ClassName tambahan dari consumer. */\n className: PropTypes.string,\n /** Callback saat tombol diklik. */\n onClick: PropTypes.func,\n /** Konten tombol. */\n children: PropTypes.node.isRequired,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * Input — Atom field masukan teks dengan validasi dan label.\n *\n * @param {object} props\n * @param {string} [props.type=\"text\"] - Tipe input (text, date, search, number).\n * @param {string} [props.value] - Nilai input.\n * @param {Function} [props.onChange] - Callback saat nilai berubah.\n * @param {string} [props.placeholder] - Placeholder teks.\n * @param {string} [props.label] - Label di atas input.\n * @param {boolean} [props.disabled=false] - Apakah input non-aktif.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function Input({\n type = \"text\",\n value,\n onChange,\n placeholder,\n label,\n disabled = false,\n className = \"\",\n ...rest\n}) {\n const inputClasses = [\n \"px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600\",\n \"bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100\",\n \"text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div className=\"flex flex-col gap-1\">\n {label ? (\n <label className=\"text-xs font-medium text-slate-500 dark:text-slate-400\">\n {label}\n </label>\n ) : null}\n <input\n type={type}\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n disabled={disabled}\n className={inputClasses}\n {...rest}\n />\n </div>\n );\n}\n\nInput.propTypes = {\n /** Tipe input. */\n type: PropTypes.string,\n /** Nilai input. */\n value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n /** Callback saat nilai berubah. */\n onChange: PropTypes.func,\n /** Placeholder teks. */\n placeholder: PropTypes.string,\n /** Label di atas input. */\n label: PropTypes.string,\n /** Apakah input non-aktif. */\n disabled: PropTypes.bool,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport {\n BarChart3,\n Calendar,\n DollarSign,\n PieChart,\n RotateCcw,\n TrendingUp,\n TrendingDown,\n Users,\n Search,\n ChevronLeft,\n ChevronRight,\n ArrowUp,\n ArrowDown,\n AlertCircle,\n} from \"lucide-react\";\n\n/**\n * Registry ikon yang tersedia di modul dashboard.\n * @type {Object.<string, React.ComponentType>}\n */\nconst ICON_REGISTRY = {\n BarChart3,\n Calendar,\n DollarSign,\n PieChart,\n RotateCcw,\n TrendingUp,\n TrendingDown,\n Users,\n Search,\n ChevronLeft,\n ChevronRight,\n ArrowUp,\n ArrowDown,\n AlertCircle,\n};\n\n/**\n * Icon — Atom komponen ikon berbasis SVG menggunakan Lucide React.\n *\n * @param {object} props\n * @param {string} props.name - Nama ikon dari registry (misal: \"TrendingUp\").\n * @param {number} [props.size=20] - Ukuran ikon dalam piksel.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function Icon({ name, size = 20, className = \"\", ...rest }) {\n const IconComponent = ICON_REGISTRY[name] || BarChart3;\n\n return <IconComponent size={size} className={className} {...rest} />;\n}\n\n/**\n * Resolves an icon name to its Lucide React component.\n * Backward-compatible utility used internally.\n *\n * @param {string} name - Nama ikon.\n * @returns {React.ComponentType} Komponen ikon.\n */\nexport function resolveIcon(name) {\n return ICON_REGISTRY[name] || BarChart3;\n}\n\nIcon.propTypes = {\n /** Nama ikon dari registry Lucide React. */\n name: PropTypes.string.isRequired,\n /** Ukuran ikon dalam piksel. */\n size: PropTypes.number,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * Mapping varian ke elemen HTML dan className default.\n */\nconst VARIANT_MAP = {\n h1: { tag: \"h1\", className: \"text-2xl sm:text-3xl font-bold\" },\n h2: { tag: \"h2\", className: \"text-xl sm:text-2xl font-bold\" },\n h3: { tag: \"h3\", className: \"text-lg font-semibold\" },\n subheading: { tag: \"p\", className: \"text-sm font-medium text-slate-500 dark:text-slate-400\" },\n body: { tag: \"p\", className: \"text-sm text-slate-700 dark:text-slate-300\" },\n caption: { tag: \"span\", className: \"text-xs text-slate-500 dark:text-slate-400\" },\n metric: { tag: \"span\", className: \"text-3xl font-bold text-slate-900 dark:text-slate-100\" },\n};\n\n/**\n * Typography — Atom komponen teks dengan hierarki heading, subheading, dan body.\n *\n * @param {object} props\n * @param {\"h1\"|\"h2\"|\"h3\"|\"subheading\"|\"body\"|\"caption\"|\"metric\"} [props.variant=\"body\"]\n * Varian tipografi.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n * @param {React.ReactNode} props.children - Konten teks.\n */\nexport default function Typography({\n variant = \"body\",\n className = \"\",\n children,\n ...rest\n}) {\n const config = VARIANT_MAP[variant] || VARIANT_MAP.body;\n const Tag = config.tag;\n const classes = [config.className, className].filter(Boolean).join(\" \");\n\n return (\n <Tag className={classes} {...rest}>\n {children}\n </Tag>\n );\n}\n\nTypography.propTypes = {\n /** Varian tipografi. */\n variant: PropTypes.oneOf([\"h1\", \"h2\", \"h3\", \"subheading\", \"body\", \"caption\", \"metric\"]),\n /** ClassName tambahan. */\n className: PropTypes.string,\n /** Konten teks. */\n children: PropTypes.node.isRequired,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * Mapping status ke className warna.\n */\nconst STATUS_CLASSES = {\n confirmed: \"bg-green-100 text-green-800 dark:bg-green-900/50 dark:text-green-200\",\n pending: \"bg-yellow-100 text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-200\",\n cancelled: \"bg-red-100 text-red-800 dark:bg-red-900/50 dark:text-red-200\",\n default: \"bg-slate-100 text-slate-800 dark:bg-slate-700 dark:text-slate-200\",\n success: \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300\",\n info: \"bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300\",\n};\n\n/**\n * Badge — Atom label status berwarna untuk informasi kategorikal.\n *\n * @param {object} props\n * @param {string} [props.status=\"default\"] - Status yang menentukan warna badge.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n * @param {React.ReactNode} props.children - Label teks badge.\n */\nexport default function Badge({ status = \"default\", className = \"\", children, ...rest }) {\n const colorClass = STATUS_CLASSES[status] || STATUS_CLASSES.default;\n const classes = [\"px-2 py-1 rounded-full text-xs font-medium\", colorClass, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <span className={classes} {...rest}>\n {children}\n </span>\n );\n}\n\nBadge.propTypes = {\n /** Status yang menentukan warna badge. */\n status: PropTypes.string,\n /** ClassName tambahan. */\n className: PropTypes.string,\n /** Label teks badge. */\n children: PropTypes.node.isRequired,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * SkeletonLoader — Atom placeholder animasi saat data sedang dimuat.\n * Menampilkan efek pulse untuk memberikan umpan balik visual kepada pengguna.\n *\n * @param {object} props\n * @param {string} [props.className=\"\"] - ClassName tambahan untuk mengatur ukuran skeleton.\n */\nexport default function SkeletonLoader({ className = \"\" }) {\n return (\n <div\n className={`animate-pulse bg-slate-200 dark:bg-slate-700 rounded-xl ${className}`}\n role=\"status\"\n aria-label=\"Loading...\"\n />\n );\n}\n\nSkeletonLoader.propTypes = {\n /** ClassName tambahan untuk mengatur ukuran skeleton (misal: \"h-28\", \"h-64\"). */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Icon from \"../atoms/Icon.jsx\";\nimport Typography from \"../atoms/Typography.jsx\";\nimport { formatIDR } from \"../../utils/formatters.js\";\n\n/**\n * StatCard — Molecule kartu ringkasan metrik bisnis.\n * Kombinasi Typography, Icon, dan indikator trend.\n *\n * @param {object} props\n * @param {string} props.label - Label deskriptif metrik (misal: \"Total Booking\").\n * @param {number|string} props.value - Nilai metrik.\n * @param {string} [props.icon=\"TrendingUp\"] - Nama ikon dari registry Lucide React.\n * @param {\"number\"|\"currency\"|\"percent\"} [props.format=\"number\"] - Format tampilan nilai.\n * @param {\"up\"|\"down\"|null} [props.trend=null] - Arah tren opsional.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function StatCard({\n label,\n value,\n icon = \"TrendingUp\",\n format = \"number\",\n trend = null,\n className = \"\",\n}) {\n const formattedValue = renderValue(format, value);\n\n return (\n <div className={`card p-4 flex flex-col justify-between gap-2 ${className}`}>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-slate-500 dark:text-slate-400\">\n <Icon name={icon} size={20} />\n <Typography variant=\"subheading\">{label}</Typography>\n </div>\n {trend ? (\n <Icon\n name={trend === \"up\" ? \"TrendingUp\" : \"TrendingDown\"}\n size={16}\n className={trend === \"up\" ? \"text-emerald-500\" : \"text-red-500\"}\n />\n ) : null}\n </div>\n <Typography variant=\"metric\">{formattedValue}</Typography>\n </div>\n );\n}\n\n/**\n * Memformat nilai berdasarkan jenis format.\n * @param {\"number\"|\"currency\"|\"percent\"} format - Jenis format.\n * @param {number|string} value - Nilai mentah.\n * @returns {string} Nilai terformat.\n */\nfunction renderValue(format, value) {\n if (format === \"currency\") return `Rp ${formatIDR(value)}`;\n if (format === \"percent\") return `${Number(value) || 0}%`;\n return String(Number(value) || 0);\n}\n\nStatCard.propTypes = {\n /** Label deskriptif metrik. */\n label: PropTypes.string.isRequired,\n /** Nilai metrik. */\n value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),\n /** Nama ikon dari registry Lucide React. */\n icon: PropTypes.string,\n /** Format tampilan nilai. */\n format: PropTypes.oneOf([\"number\", \"currency\", \"percent\"]),\n /** Arah tren opsional. */\n trend: PropTypes.oneOf([\"up\", \"down\", null]),\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React, { useState, useCallback } from \"react\";\nimport PropTypes from \"prop-types\";\nimport Input from \"../atoms/Input.jsx\";\nimport Icon from \"../atoms/Icon.jsx\";\n\n/**\n * SearchBar — Molecule kombinasi Input dan Icon untuk pencarian data.\n *\n * @param {object} props\n * @param {string} [props.value=\"\"] - Nilai pencarian saat ini.\n * @param {Function} [props.onChange] - Callback saat nilai input berubah.\n * @param {Function} [props.onSearch] - Callback saat pencarian disubmit (Enter).\n * @param {string} [props.placeholder=\"Search...\"] - Placeholder teks.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function SearchBar({\n value: controlledValue,\n onChange,\n onSearch,\n placeholder = \"Search...\",\n className = \"\",\n}) {\n const [internalValue, setInternalValue] = useState(\"\");\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n\n const handleChange = useCallback(\n (event) => {\n const newValue = event.target.value;\n if (!isControlled) setInternalValue(newValue);\n if (onChange) onChange(newValue);\n if (onSearch) onSearch(newValue);\n },\n [isControlled, onChange, onSearch]\n );\n\n const handleKeyDown = useCallback(\n (event) => {\n if (event.key === \"Enter\" && onSearch) {\n onSearch(currentValue);\n }\n },\n [currentValue, onSearch]\n );\n\n return (\n <div className={`relative ${className}`}>\n <div className=\"absolute inset-y-0 left-3 flex items-center pointer-events-none\">\n <Icon name=\"Search\" size={16} className=\"text-slate-400\" />\n </div>\n <Input\n type=\"search\"\n value={currentValue}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n className=\"pl-9 w-full\"\n />\n </div>\n );\n}\n\nSearchBar.propTypes = {\n /** Nilai pencarian saat ini (controlled). */\n value: PropTypes.string,\n /** Callback saat nilai input berubah. */\n onChange: PropTypes.func,\n /** Callback saat pencarian disubmit. */\n onSearch: PropTypes.func,\n /** Placeholder teks. */\n placeholder: PropTypes.string,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React, { useState, useCallback } from \"react\";\nimport PropTypes from \"prop-types\";\nimport Typography from \"../atoms/Typography.jsx\";\n\n/**\n * Rentang tahun yang diizinkan untuk picker.\n */\nconst CURRENT_YEAR = new Date().getFullYear();\nconst MIN_YEAR = 2020;\nconst MAX_YEAR = CURRENT_YEAR + 1;\n\nconst MONTHS = [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n];\n\n/**\n * Menghasilkan array tahun dari MIN_YEAR sampai MAX_YEAR.\n */\nfunction getYears() {\n const years = [];\n for (let y = MAX_YEAR; y >= MIN_YEAR; y--) {\n years.push(y);\n }\n return years;\n}\n\n/**\n * Menghasilkan array hari (1–N) sesuai bulan dan tahun.\n */\nfunction getDaysInMonth(year, month) {\n return new Date(year, month, 0).getDate();\n}\n\n/**\n * Parse string \"YYYY-MM-DD\" ke { year, month, day }.\n * Fallback ke hari ini jika tidak valid.\n */\nfunction parseDate(value) {\n if (value && /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const [y, m, d] = value.split(\"-\").map(Number);\n if (y >= MIN_YEAR && y <= MAX_YEAR && m >= 1 && m <= 12) {\n return { year: y, month: m, day: d };\n }\n }\n const now = new Date();\n return { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };\n}\n\n/**\n * Format { year, month, day } ke \"YYYY-MM-DD\".\n */\nfunction formatDate({ year, month, day }) {\n return `${year}-${String(month).padStart(2, \"0\")}-${String(day).padStart(2, \"0\")}`;\n}\n\n/**\n * DatePicker — Komponen picker tanggal berbasis dropdown (year/month/day).\n * Menggantikan input type=\"date\" native untuk mencegah crash akibat input tahun tidak valid.\n */\nfunction DatePicker({ value, onChange, disabled = false, label = \"\" }) {\n const parsed = parseDate(value);\n const years = getYears();\n const maxDay = getDaysInMonth(parsed.year, parsed.month);\n\n const handleChange = useCallback(\n (field, newVal) => {\n const updated = { ...parsed, [field]: Number(newVal) };\n // Clamp day jika melebihi hari dalam bulan baru\n const maxD = getDaysInMonth(updated.year, updated.month);\n if (updated.day > maxD) updated.day = maxD;\n onChange(formatDate(updated));\n },\n [parsed, onChange]\n );\n\n const selectClass =\n \"px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 \" +\n \"bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 \" +\n \"text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 \" +\n \"disabled:opacity-50 disabled:cursor-not-allowed\";\n\n return (\n <div className=\"flex flex-col gap-1\">\n {label ? (\n <Typography variant=\"caption\" className=\"font-medium\">\n {label}\n </Typography>\n ) : null}\n <div className=\"flex items-center gap-1\">\n {/* Day */}\n <select\n className={selectClass}\n value={parsed.day}\n onChange={(e) => handleChange(\"day\", e.target.value)}\n disabled={disabled}\n aria-label={`${label} day`}\n >\n {Array.from({ length: maxDay }, (_, i) => i + 1).map((d) => (\n <option key={d} value={d}>\n {String(d).padStart(2, \"0\")}\n </option>\n ))}\n </select>\n\n {/* Month */}\n <select\n className={selectClass}\n value={parsed.month}\n onChange={(e) => handleChange(\"month\", e.target.value)}\n disabled={disabled}\n aria-label={`${label} month`}\n >\n {MONTHS.map((name, idx) => (\n <option key={idx + 1} value={idx + 1}>\n {name}\n </option>\n ))}\n </select>\n\n {/* Year */}\n <select\n className={selectClass}\n value={parsed.year}\n onChange={(e) => handleChange(\"year\", e.target.value)}\n disabled={disabled}\n aria-label={`${label} year`}\n >\n {years.map((y) => (\n <option key={y} value={y}>\n {y}\n </option>\n ))}\n </select>\n </div>\n </div>\n );\n}\n\nDatePicker.propTypes = {\n value: PropTypes.string.isRequired,\n onChange: PropTypes.func.isRequired,\n disabled: PropTypes.bool,\n label: PropTypes.string,\n};\n\n/**\n * DateRangeFilter — Molecule dua DatePicker untuk filter rentang tanggal.\n * Menggunakan dropdown picker (bukan input type=\"date\") untuk mencegah crash\n * akibat user mengetik tahun tidak valid secara parsial.\n *\n * @param {object} props\n * @param {string} props.dateFrom - Tanggal awal (format YYYY-MM-DD).\n * @param {string} props.dateTo - Tanggal akhir (format YYYY-MM-DD).\n * @param {Function} props.onRangeChange - Callback saat range berubah ({dateFrom, dateTo}).\n * @param {boolean} [props.disabled=false] - Apakah filter non-aktif.\n * @param {string} [props.labelFrom=\"From\"] - Label picker tanggal awal.\n * @param {string} [props.labelTo=\"To\"] - Label picker tanggal akhir.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function DateRangeFilter({\n dateFrom,\n dateTo,\n onRangeChange,\n disabled = false,\n labelFrom = \"From\",\n labelTo = \"To\",\n className = \"\",\n}) {\n const handleFromChange = useCallback(\n (newDate) => onRangeChange?.({ dateFrom: newDate, dateTo }),\n [dateTo, onRangeChange]\n );\n\n const handleToChange = useCallback(\n (newDate) => onRangeChange?.({ dateFrom, dateTo: newDate }),\n [dateFrom, onRangeChange]\n );\n\n return (\n <div className={`flex flex-wrap items-end gap-3 ${className}`}>\n <DatePicker\n value={dateFrom}\n onChange={handleFromChange}\n disabled={disabled}\n label={labelFrom}\n />\n <DatePicker\n value={dateTo}\n onChange={handleToChange}\n disabled={disabled}\n label={labelTo}\n />\n </div>\n );\n}\n\nDateRangeFilter.propTypes = {\n dateFrom: PropTypes.string.isRequired,\n dateTo: PropTypes.string.isRequired,\n onRangeChange: PropTypes.func.isRequired,\n disabled: PropTypes.bool,\n labelFrom: PropTypes.string,\n labelTo: PropTypes.string,\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Icon from \"../atoms/Icon.jsx\";\nimport Typography from \"../atoms/Typography.jsx\";\n\n/**\n * ChartHeader — Molecule kombinasi Typography dan Icon untuk header grafik.\n *\n * @param {object} props\n * @param {string} props.title - Judul grafik.\n * @param {string} [props.icon=\"BarChart3\"] - Nama ikon header.\n * @param {React.ReactNode} [props.actions] - Elemen aksi tambahan di sisi kanan.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function ChartHeader({\n title,\n icon = \"BarChart3\",\n actions = null,\n className = \"\",\n}) {\n return (\n <div className={`flex items-center justify-between mb-2 ${className}`}>\n <Typography variant=\"h3\" className=\"flex items-center gap-2\">\n <Icon name={icon} size={18} />\n {title}\n </Typography>\n {actions}\n </div>\n );\n}\n\nChartHeader.propTypes = {\n /** Judul grafik. */\n title: PropTypes.string.isRequired,\n /** Nama ikon header. */\n icon: PropTypes.string,\n /** Elemen aksi tambahan di sisi kanan. */\n actions: PropTypes.node,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React, { useMemo, useState, useCallback } from \"react\";\nimport PropTypes from \"prop-types\";\nimport SearchBar from \"../molecules/SearchBar.jsx\";\nimport Badge from \"../atoms/Badge.jsx\";\nimport Icon from \"../atoms/Icon.jsx\";\nimport { formatDate, formatIDR } from \"../../utils/formatters.js\";\n\n/**\n * DataTable — Organism tabel data interaktif dengan fitur pencarian,\n * pengurutan (sorting), dan paginasi.\n *\n * @param {object} props\n * @param {Array<object>} props.columns - Definisi kolom tabel.\n * @param {Array<object>} props.data - Array data baris.\n * @param {object} props.labels - Objek label i18n.\n * @param {string} [props.dateLocale=\"id-ID\"] - Locale untuk format tanggal.\n * @param {boolean} [props.searchable=true] - Apakah tabel mendukung pencarian.\n * @param {boolean} [props.sortable=true] - Apakah tabel mendukung pengurutan.\n * @param {number} [props.pageSize=10] - Jumlah baris per halaman.\n * @param {string} [props.emptyLabel=\"No data\"] - Label saat data kosong.\n * @param {string} [props.searchPlaceholder=\"Search...\"] - Placeholder pencarian.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function DataTable({\n columns,\n data = [],\n labels = {},\n dateLocale = \"id-ID\",\n searchable = true,\n sortable = true,\n pageSize = 10,\n emptyLabel = \"No data\",\n searchPlaceholder = \"Search...\",\n className = \"\",\n}) {\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [sortField, setSortField] = useState(null);\n const [sortDirection, setSortDirection] = useState(\"asc\");\n const [currentPage, setCurrentPage] = useState(1);\n\n // --- Pencarian ---\n const filteredData = useMemo(() => {\n if (!searchQuery.trim()) return data;\n const query = searchQuery.toLowerCase();\n return data.filter((row) =>\n columns.some((col) => {\n const value = row[col.accessor];\n return value != null && String(value).toLowerCase().includes(query);\n })\n );\n }, [data, searchQuery, columns]);\n\n // --- Pengurutan ---\n const sortedData = useMemo(() => {\n if (!sortField) return filteredData;\n const sorted = [...filteredData].sort((a, b) => {\n const aVal = a[sortField] ?? \"\";\n const bVal = b[sortField] ?? \"\";\n\n if (typeof aVal === \"number\" && typeof bVal === \"number\") {\n return sortDirection === \"asc\" ? aVal - bVal : bVal - aVal;\n }\n const comparison = String(aVal).localeCompare(String(bVal), undefined, {\n numeric: true,\n });\n return sortDirection === \"asc\" ? comparison : -comparison;\n });\n return sorted;\n }, [filteredData, sortField, sortDirection]);\n\n // --- Paginasi ---\n const totalPages = Math.max(1, Math.ceil(sortedData.length / pageSize));\n const safePage = Math.min(currentPage, totalPages);\n\n const paginatedData = useMemo(() => {\n const start = (safePage - 1) * pageSize;\n return sortedData.slice(start, start + pageSize);\n }, [sortedData, safePage, pageSize]);\n\n // --- Handlers ---\n const handleSearch = useCallback((value) => {\n setSearchQuery(value);\n setCurrentPage(1);\n }, []);\n\n const handleSort = useCallback(\n (accessor) => {\n if (!sortable) return;\n if (sortField === accessor) {\n setSortDirection((prev) => (prev === \"asc\" ? \"desc\" : \"asc\"));\n } else {\n setSortField(accessor);\n setSortDirection(\"asc\");\n }\n setCurrentPage(1);\n },\n [sortable, sortField]\n );\n\n const handlePrevPage = useCallback(() => {\n setCurrentPage((prev) => Math.max(1, prev - 1));\n }, []);\n\n const handleNextPage = useCallback(() => {\n setCurrentPage((prev) => Math.min(totalPages, prev + 1));\n }, [totalPages]);\n\n return (\n <div className={`space-y-3 ${className}`}>\n {/* Search Bar */}\n {searchable ? (\n <SearchBar\n value={searchQuery}\n onSearch={handleSearch}\n placeholder={searchPlaceholder}\n className=\"max-w-sm\"\n />\n ) : null}\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm border-collapse\">\n <thead>\n <tr className=\"bg-slate-100 dark:bg-slate-800 text-left\">\n {columns.map((column) => (\n <th\n key={column.id}\n className={[\n \"p-3\",\n sortable ? \"cursor-pointer select-none hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors\" : \"\",\n ].join(\" \")}\n onClick={() => handleSort(column.accessor)}\n >\n <div className=\"flex items-center gap-1\">\n <span>{labels[column.label] || column.label}</span>\n {sortable && sortField === column.accessor ? (\n <Icon\n name={sortDirection === \"asc\" ? \"ArrowUp\" : \"ArrowDown\"}\n size={14}\n className=\"text-blue-500\"\n />\n ) : null}\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {paginatedData.map((row) => (\n <tr\n key={row.id}\n className=\"border-b border-slate-200 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800/50\"\n >\n {columns.map((column) => (\n <td key={`${row.id}-${column.id}`} className=\"p-3\">\n {renderCell(column, row, dateLocale)}\n </td>\n ))}\n </tr>\n ))}\n {paginatedData.length === 0 ? (\n <tr>\n <td\n className=\"p-6 text-center text-slate-500\"\n colSpan={columns.length}\n >\n {emptyLabel}\n </td>\n </tr>\n ) : null}\n </tbody>\n </table>\n </div>\n\n {/* Pagination */}\n {sortedData.length > pageSize ? (\n <div className=\"flex items-center justify-between px-1\">\n <span className=\"text-xs text-slate-500\">\n {(safePage - 1) * pageSize + 1}–\n {Math.min(safePage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length}\n </span>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n className=\"p-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n onClick={handlePrevPage}\n disabled={safePage <= 1}\n aria-label=\"Previous page\"\n >\n <Icon name=\"ChevronLeft\" size={16} />\n </button>\n <span className=\"text-xs text-slate-600 dark:text-slate-300 min-w-[60px] text-center\">\n {safePage} / {totalPages}\n </span>\n <button\n type=\"button\"\n className=\"p-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n onClick={handleNextPage}\n disabled={safePage >= totalPages}\n aria-label=\"Next page\"\n >\n <Icon name=\"ChevronRight\" size={16} />\n </button>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * Merender nilai sel berdasarkan tipe kolom.\n * @param {object} column - Definisi kolom.\n * @param {object} row - Data baris.\n * @param {string} dateLocale - Locale untuk format tanggal.\n * @returns {React.ReactNode} Konten sel.\n */\nfunction renderCell(column, row, dateLocale) {\n const value = row[column.accessor];\n\n if (column.type === \"date\") return formatDate(value, dateLocale);\n if (column.type === \"currency\") return `Rp ${formatIDR(value)}`;\n if (column.type === \"statusBadge\") {\n const status = row[column.statusAccessor] || \"pending\";\n return <Badge status={status}>{value}</Badge>;\n }\n return value || \"-\";\n}\n\nDataTable.propTypes = {\n /** Definisi kolom tabel. */\n columns: PropTypes.arrayOf(\n PropTypes.shape({\n id: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n accessor: PropTypes.string.isRequired,\n type: PropTypes.oneOf([\"date\", \"currency\", \"statusBadge\"]),\n statusAccessor: PropTypes.string,\n })\n ).isRequired,\n /** Array data baris. */\n data: PropTypes.arrayOf(PropTypes.object),\n /** Objek label i18n. */\n labels: PropTypes.object,\n /** Locale untuk format tanggal. */\n dateLocale: PropTypes.string,\n /** Apakah tabel mendukung pencarian. */\n searchable: PropTypes.bool,\n /** Apakah tabel mendukung pengurutan. */\n sortable: PropTypes.bool,\n /** Jumlah baris per halaman. */\n pageSize: PropTypes.number,\n /** Label saat data kosong. */\n emptyLabel: PropTypes.string,\n /** Placeholder pencarian. */\n searchPlaceholder: PropTypes.string,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n Legend,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport ChartHeader from \"../molecules/ChartHeader.jsx\";\nimport SkeletonLoader from \"../atoms/SkeletonLoader.jsx\";\nimport { formatIDR } from \"../../utils/formatters.js\";\n\n/**\n * Palet warna default untuk grafik.\n * @type {string[]}\n */\nconst COLORS = [\n \"#0ea5e9\",\n \"#a78bfa\",\n \"#f59e0b\",\n \"#10b981\",\n \"#ef4444\",\n \"#22d3ee\",\n];\n\n/**\n * ChartCard — Organism kartu grafik yang mengintegrasikan ChartHeader\n * dengan area visualisasi. Mendukung tipe grafik area, pie, dan bar.\n *\n * @param {object} props\n * @param {object} props.widget - Konfigurasi widget chart.\n * @param {object} props.labels - Objek label i18n.\n * @param {boolean} props.loading - Apakah sedang loading.\n * @param {object} props.filters - State filter dashboard.\n * @param {object} props.chartData - Data untuk semua jenis chart.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function ChartCard({\n widget,\n labels,\n loading,\n filters,\n chartData,\n className = \"\",\n}) {\n const content = (() => {\n if (loading) return <SkeletonLoader className=\"h-64\" />;\n\n if (widget.type === \"dailyArea\") {\n return renderDailyArea(labels, filters, chartData.dailyTrends);\n }\n if (widget.type === \"statusPie\") {\n return renderPie(chartData.statusDistribution);\n }\n if (widget.type === \"audiencePie\") {\n return renderPie(chartData.audienceDistribution);\n }\n if (widget.type === \"topPackagesBar\") {\n return renderTopPackages(chartData.topPackages, labels, filters.sortPkgBy);\n }\n\n return <div className=\"text-sm text-slate-500\">Unsupported chart type.</div>;\n })();\n\n return (\n <div className={`card p-4 ${className}`}>\n <ChartHeader\n title={labels[widget.label] || widget.label}\n icon={widget.icon}\n />\n {content}\n </div>\n );\n}\n\n/**\n * Merender grafik area harian (daily area chart).\n * @param {object} labels - Label i18n.\n * @param {object} filters - Filter dashboard.\n * @param {Array} dailyData - Data daily trends.\n * @returns {React.ReactElement} Komponen AreaChart.\n */\nfunction renderDailyArea(labels, filters, dailyData = []) {\n return (\n <ResponsiveContainer width=\"100%\" height={256}>\n <AreaChart data={dailyData}>\n <CartesianGrid strokeDasharray=\"3 3\" />\n <XAxis dataKey=\"label\" />\n <YAxis yAxisId=\"left\" />\n <YAxis yAxisId=\"right\" orientation=\"right\" />\n <Tooltip\n formatter={(value, name) =>\n name === \"revenue\"\n ? [`Rp ${formatIDR(value)}`, labels.revenueMetric]\n : [value, labels.bookingsMetric]\n }\n />\n <Legend />\n <Area\n yAxisId=\"left\"\n type=\"monotone\"\n dataKey=\"count\"\n name={labels.confirmedBookingMetric}\n stroke=\"#0ea5e9\"\n fill=\"#0ea5e9\"\n fillOpacity={0.3}\n />\n <Area\n yAxisId=\"right\"\n type=\"monotone\"\n dataKey=\"revenue\"\n name={labels.confirmedRevenueMetric}\n stroke=\"#a78bfa\"\n fill=\"#a78bfa\"\n fillOpacity={0.3}\n />\n {filters.includePendingOverlay ? (\n <Area\n yAxisId=\"left\"\n type=\"monotone\"\n dataKey=\"pendingCount\"\n name={labels.pendingMetric}\n stroke=\"#ef4444\"\n fill=\"#ef4444\"\n fillOpacity={0.1}\n strokeDasharray=\"4 4\"\n />\n ) : null}\n </AreaChart>\n </ResponsiveContainer>\n );\n}\n\n/**\n * Merender diagram lingkaran (Pie/Donut Chart).\n * @param {Array} data - Data distribusi.\n * @returns {React.ReactElement} Komponen PieChart.\n */\nfunction renderPie(data = []) {\n return (\n <ResponsiveContainer width=\"100%\" height={256}>\n <PieChart>\n <Pie\n data={data}\n dataKey=\"count\"\n nameKey=\"label\"\n innerRadius={60}\n outerRadius={100}\n paddingAngle={2}\n >\n {data.map((_, index) => (\n <Cell\n key={`${index}-${data[index].label}`}\n fill={COLORS[index % COLORS.length]}\n />\n ))}\n </Pie>\n <Tooltip />\n <Legend />\n </PieChart>\n </ResponsiveContainer>\n );\n}\n\n/**\n * Merender grafik batang (Bar Chart) untuk paket teratas.\n * @param {Array} data - Data top packages.\n * @param {object} labels - Label i18n.\n * @param {string} sortPkgBy - Metrik pengurutan (bookings/revenue).\n * @returns {React.ReactElement} Komponen BarChart.\n */\nfunction renderTopPackages(data = [], labels, sortPkgBy) {\n return (\n <ResponsiveContainer width=\"100%\" height={256}>\n <BarChart data={data} layout=\"vertical\">\n <CartesianGrid strokeDasharray=\"3 3\" />\n <XAxis type=\"number\" allowDecimals={false} />\n <YAxis type=\"category\" dataKey=\"name\" width={120} />\n <Tooltip\n formatter={(value) =>\n sortPkgBy === \"revenue\"\n ? [`Rp ${formatIDR(value)}`, labels.revenueMetric]\n : [value, labels.bookingsMetric]\n }\n />\n <Bar\n dataKey=\"value\"\n name={\n sortPkgBy === \"revenue\"\n ? labels.revenueMetric\n : labels.bookingsMetric\n }\n fill=\"#10b981\"\n radius={[4, 4, 4, 4]}\n />\n </BarChart>\n </ResponsiveContainer>\n );\n}\n\nChartCard.propTypes = {\n /** Konfigurasi widget chart. */\n widget: PropTypes.shape({\n id: PropTypes.string.isRequired,\n type: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n icon: PropTypes.string,\n }).isRequired,\n /** Objek label i18n. */\n labels: PropTypes.object.isRequired,\n /** Apakah sedang loading. */\n loading: PropTypes.bool,\n /** State filter dashboard. */\n filters: PropTypes.object,\n /** Data untuk semua jenis chart. */\n chartData: PropTypes.object,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Button from \"../atoms/Button.jsx\";\nimport Input from \"../atoms/Input.jsx\";\nimport Typography from \"../atoms/Typography.jsx\";\nimport DateRangeFilter from \"../molecules/DateRangeFilter.jsx\";\n\n/**\n * FilterPanel — Organism panel filter yang menggabungkan DateRangeFilter\n * dan komponen filter lainnya (status, audience, sorting).\n *\n * @param {object} props\n * @param {object} props.filters - State filter saat ini.\n * @param {object} props.labels - Objek label i18n.\n * @param {Function} props.onFilterChange - Callback saat filter berubah (field, value).\n * @param {Function} props.onResetFilters - Callback saat filter di-reset.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\n\nconst STATUS_OPTIONS = [\"confirmed\", \"pending\", \"all\"];\nconst AUDIENCE_OPTIONS = [\"\", \"domestic\", \"foreign\"];\nconst DAY_PRESETS = [7, 30, 90, 0];\nconst SORT_BY_OPTIONS = [\"bookings\", \"revenue\"];\nconst SORT_DIR_OPTIONS = [\"desc\", \"asc\"];\n\nexport default function FilterPanel({\n filters,\n labels,\n onFilterChange,\n onResetFilters,\n className = \"\",\n}) {\n return (\n <div className={`flex flex-col gap-2 ${className}`}>\n {/* Row 1: Status, Pending overlay, Audience, Day preset */}\n <div className=\"grid grid-cols-1 lg:grid-cols-6 gap-2\">\n {/* Status Scope */}\n <select\n className=\"px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm\"\n value={filters.statusScope}\n onChange={(event) => onFilterChange(\"statusScope\", event.target.value)}\n >\n {STATUS_OPTIONS.map((status) => (\n <option key={status} value={status}>\n {status === \"confirmed\"\n ? labels.confirmedOnly\n : status === \"pending\"\n ? labels.pendingOnly\n : labels.allStatus}\n </option>\n ))}\n </select>\n\n {/* Pending Overlay */}\n <label className=\"inline-flex items-center gap-2 px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600\">\n <Input\n type=\"checkbox\"\n checked={filters.includePendingOverlay}\n onChange={(event) =>\n onFilterChange(\"includePendingOverlay\", event.target.checked)\n }\n />\n <Typography variant=\"body\">{labels.showPendingOverlay}</Typography>\n </label>\n\n {/* Audience */}\n <select\n className=\"px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm\"\n value={filters.audience}\n onChange={(event) => onFilterChange(\"audience\", event.target.value)}\n >\n {AUDIENCE_OPTIONS.map((audience) => (\n <option key={audience || \"all\"} value={audience}>\n {audience === \"domestic\"\n ? labels.audienceDomestic\n : audience === \"foreign\"\n ? labels.audienceForeign\n : labels.allAudience}\n </option>\n ))}\n </select>\n\n {/* Day Preset */}\n <select\n className=\"px-3 py-2 rounded-2xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm\"\n value={String(filters.daysPreset)}\n onChange={(event) =>\n onFilterChange(\"daysPreset\", Number(event.target.value))\n }\n >\n {DAY_PRESETS.map((days) => (\n <option key={String(days)} value={String(days)}>\n {days === 0 ? labels.customDate : labels.dayLabel(days)}\n </option>\n ))}\n </select>\n\n {/* Date Range Filter */}\n <DateRangeFilter\n dateFrom={filters.dateFrom || \"\"}\n dateTo={filters.dateTo || \"\"}\n onRangeChange={({ dateFrom, dateTo }) => {\n if (dateFrom !== filters.dateFrom) onFilterChange(\"dateFrom\", dateFrom);\n if (dateTo !== filters.dateTo) onFilterChange(\"dateTo\", dateTo);\n }}\n disabled={filters.daysPreset !== 0}\n className=\"lg:col-span-2\"\n />\n </div>\n\n {/* Row 2: Reset + Sort controls */}\n <div className=\"flex items-center justify-between\">\n <Button variant=\"secondary\" size=\"sm\" onClick={onResetFilters}>\n {labels.reset}\n </Button>\n <div className=\"flex items-center gap-2\">\n <Typography variant=\"caption\">{labels.topSort}:</Typography>\n <select\n className=\"px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm\"\n value={filters.sortPkgBy}\n onChange={(event) =>\n onFilterChange(\"sortPkgBy\", event.target.value)\n }\n >\n {SORT_BY_OPTIONS.map((sortBy) => (\n <option key={sortBy} value={sortBy}>\n {sortBy === \"bookings\"\n ? labels.sortBookings\n : labels.sortRevenue}\n </option>\n ))}\n </select>\n <select\n className=\"px-2 py-1.5 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-sm\"\n value={filters.sortPkgDir}\n onChange={(event) =>\n onFilterChange(\"sortPkgDir\", event.target.value)\n }\n >\n {SORT_DIR_OPTIONS.map((direction) => (\n <option key={direction} value={direction}>\n {direction === \"desc\" ? labels.sortDesc : labels.sortAsc}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n );\n}\n\nFilterPanel.propTypes = {\n /** State filter saat ini. */\n filters: PropTypes.shape({\n statusScope: PropTypes.string,\n includePendingOverlay: PropTypes.bool,\n audience: PropTypes.string,\n daysPreset: PropTypes.number,\n dateFrom: PropTypes.string,\n dateTo: PropTypes.string,\n sortPkgBy: PropTypes.string,\n sortPkgDir: PropTypes.string,\n }).isRequired,\n /** Objek label i18n. */\n labels: PropTypes.object.isRequired,\n /** Callback saat filter berubah (field, value). */\n onFilterChange: PropTypes.func.isRequired,\n /** Callback saat filter di-reset. */\n onResetFilters: PropTypes.func.isRequired,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Icon from \"../atoms/Icon.jsx\";\n\n/**\n * SidebarNavigation — Organism navigasi sidebar dengan daftar menu\n * dan indikator halaman aktif.\n *\n * Dapat digunakan langsung atau dijadikan referensi bagi consumer\n * untuk membuat sidebar navigasi kustom pada aplikasi mereka.\n *\n * @param {object} props\n * @param {Array} props.items - Daftar item menu navigasi.\n * @param {string} props.items[].id - ID unik item.\n * @param {string} props.items[].label - Label teks item.\n * @param {string} [props.items[].icon] - Nama ikon Lucide (opsional).\n * @param {string} [props.activeItem] - ID item yang sedang aktif.\n * @param {Function} [props.onItemClick] - Callback saat item diklik (id).\n * @param {React.ReactNode} [props.logo] - Konten logo/brand di atas sidebar.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function SidebarNavigation({\n items = [],\n activeItem = \"\",\n onItemClick,\n logo = null,\n className = \"\",\n}) {\n return (\n <aside\n className={`flex flex-col w-60 min-h-screen bg-white dark:bg-slate-900 border-r border-slate-200 dark:border-slate-800 ${className}`}\n >\n {/* Logo / Brand */}\n {logo ? (\n <div className=\"px-4 py-4 border-b border-slate-100 dark:border-slate-800\">\n {logo}\n </div>\n ) : null}\n\n {/* Navigation Items */}\n <nav className=\"flex-1 px-2 py-3 space-y-0.5\" aria-label=\"Sidebar navigation\">\n {items.map((item) => {\n const isActive = item.id === activeItem;\n\n return (\n <button\n key={item.id}\n type=\"button\"\n id={`sidebar-nav-${item.id}`}\n onClick={() => onItemClick?.(item.id)}\n aria-current={isActive ? \"page\" : undefined}\n className={[\n \"w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-colors text-left\",\n isActive\n ? \"bg-blue-50 dark:bg-blue-950/60 text-blue-700 dark:text-blue-300\"\n : \"text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 hover:text-slate-900 dark:hover:text-slate-100\",\n ].join(\" \")}\n >\n {item.icon ? (\n <Icon\n name={item.icon}\n size={18}\n className={\n isActive\n ? \"text-blue-600 dark:text-blue-400\"\n : \"text-slate-400 dark:text-slate-500\"\n }\n />\n ) : null}\n <span>{item.label}</span>\n {isActive ? (\n <span className=\"ml-auto w-1.5 h-1.5 rounded-full bg-blue-500\" />\n ) : null}\n </button>\n );\n })}\n </nav>\n </aside>\n );\n}\n\nSidebarNavigation.propTypes = {\n /** Daftar item menu navigasi. */\n items: PropTypes.arrayOf(\n PropTypes.shape({\n id: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n icon: PropTypes.string,\n })\n ),\n /** ID item yang sedang aktif. */\n activeItem: PropTypes.string,\n /** Callback saat item diklik, menerima id item sebagai argumen. */\n onItemClick: PropTypes.func,\n /** Konten logo/brand di atas sidebar. */\n logo: PropTypes.node,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Typography from \"../atoms/Typography.jsx\";\n\n/**\n * TopbarHeader — Organism header atas yang menampilkan judul halaman\n * dan aksi global (opsional).\n *\n * Dapat digunakan langsung sebagai header aplikasi atau dijadikan referensi\n * bagi consumer untuk membuat header kustom pada aplikasi mereka.\n *\n * @param {object} props\n * @param {string} props.title - Judul halaman yang ditampilkan.\n * @param {React.ReactNode} [props.actions] - Elemen aksi di sisi kanan (tombol, dsb.).\n * @param {React.ReactNode} [props.leading] - Elemen di sisi kiri sebelum judul (misal: hamburger menu).\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function TopbarHeader({\n title = \"\",\n actions = null,\n leading = null,\n className = \"\",\n}) {\n return (\n <header\n className={`sticky top-0 z-30 flex items-center justify-between h-14 px-4 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md border-b border-slate-200 dark:border-slate-800 ${className}`}\n >\n {/* Left: leading + title */}\n <div className=\"flex items-center gap-3\">\n {leading}\n {title ? (\n <Typography variant=\"h2\" className=\"truncate\">\n {title}\n </Typography>\n ) : null}\n </div>\n\n {/* Right: global actions */}\n {actions ? (\n <div className=\"flex items-center gap-2\">{actions}</div>\n ) : null}\n </header>\n );\n}\n\nTopbarHeader.propTypes = {\n /** Judul halaman yang ditampilkan. */\n title: PropTypes.string,\n /** Elemen aksi di sisi kanan (tombol, avatar, dsb.). */\n actions: PropTypes.node,\n /** Elemen di sisi kiri sebelum judul (misal: hamburger menu). */\n leading: PropTypes.node,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\n/**\n * DashboardLayout — Template tata letak dashboard utama.\n * Menyediakan struktur layout yang konsisten dengan area konten utama.\n * Komponen SidebarNavigation dan TopbarHeader dapat ditambahkan oleh consumer.\n *\n * @param {object} props\n * @param {React.ReactNode} [props.header] - Konten header atas (misal: TopbarHeader).\n * @param {React.ReactNode} [props.sidebar] - Konten sidebar (misal: SidebarNavigation).\n * @param {React.ReactNode} props.children - Konten utama dashboard.\n * @param {string} [props.className=\"\"] - ClassName tambahan.\n */\nexport default function DashboardLayout({\n header = null,\n sidebar = null,\n children,\n className = \"\",\n}) {\n return (\n <div className={`min-h-screen bg-slate-50 dark:bg-slate-900 ${className}`}>\n {header}\n <div className=\"flex\">\n {sidebar}\n <main className=\"flex-1 container mx-auto px-4 py-3 space-y-4\">\n {children}\n </main>\n </div>\n </div>\n );\n}\n\nDashboardLayout.propTypes = {\n /** Konten header atas. */\n header: PropTypes.node,\n /** Konten sidebar. */\n sidebar: PropTypes.node,\n /** Konten utama dashboard. */\n children: PropTypes.node.isRequired,\n /** ClassName tambahan. */\n className: PropTypes.string,\n};\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport Icon from \"./atoms/Icon.jsx\";\nimport SkeletonLoader from \"./atoms/SkeletonLoader.jsx\";\nimport Typography from \"./atoms/Typography.jsx\";\nimport Button from \"./atoms/Button.jsx\";\nimport Badge from \"./atoms/Badge.jsx\";\nimport StatCard from \"./molecules/StatCard.jsx\";\nimport FilterPanel from \"./organisms/FilterPanel.jsx\";\nimport ChartCard from \"./organisms/ChartCard.jsx\";\nimport DataTable from \"./organisms/DataTable.jsx\";\n\n/**\n * ReusableDashboardView — Komponen halaman (Page) dashboard utama.\n * Mengintegrasikan semua komponen Atomic Design (atoms, molecules, organisms)\n * untuk merender dashboard lengkap berdasarkan konfigurasi widget.\n *\n * @param {object} props\n * @param {object} props.config - Konfigurasi widget dashboard.\n * @param {object} props.labels - Objek label i18n.\n * @param {boolean} props.loading - Status loading data.\n * @param {string} props.error - Pesan error jika ada.\n * @param {object} props.filters - State filter dashboard.\n * @param {Function} props.onFilterChange - Callback perubahan filter (field, value).\n * @param {Function} props.onResetFilters - Callback reset filter.\n * @param {Function} props.onRefresh - Callback refresh data.\n * @param {object} props.data - Data dashboard (stats, charts, table).\n * @param {string} props.dateLocale - Locale untuk format tanggal.\n * @param {boolean} props.liveUpdateEnabled - Apakah live update aktif.\n */\nexport function ReusableDashboardView({\n config,\n labels,\n loading,\n error,\n filters,\n onFilterChange,\n onResetFilters,\n onRefresh,\n data,\n dateLocale,\n liveUpdateEnabled,\n}) {\n\n\n return (\n <div className=\"container mt-3 space-y-4\">\n {/* Header + Filter Panel */}\n <div>\n <div className=\"rounded-2xl border border-slate-200/60 dark:border-slate-800/60 backdrop-blur-md px-3 sm:px-4 py-2 glass shadow-smooth\">\n <div className=\"flex flex-col gap-2\">\n {/* Title Bar */}\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex items-center gap-3\">\n <Typography variant=\"h1\">{labels.title}</Typography>\n {liveUpdateEnabled ? (\n <Badge status=\"success\">{labels.liveUpdate}</Badge>\n ) : null}\n </div>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => onRefresh()}\n title={labels.refresh}\n >\n <Icon name=\"RotateCcw\" size={16} />\n </Button>\n </div>\n\n {/* Error Banner */}\n {error ? (\n <div className=\"rounded-xl border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/60 dark:bg-red-950/40 dark:text-red-300\">\n <div className=\"flex items-center justify-between gap-3\">\n <span>{error}</span>\n <Button variant=\"secondary\" size=\"sm\" onClick={() => onRefresh()}>\n {labels.retry}\n </Button>\n </div>\n </div>\n ) : null}\n\n {/* Filter Panel (Organism) */}\n <FilterPanel\n filters={filters}\n labels={labels}\n onFilterChange={onFilterChange}\n onResetFilters={onResetFilters}\n />\n </div>\n </div>\n </div>\n\n {/* Stat Cards (Molecules) */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n {loading\n ? Array.from({ length: 4 }).map((_, index) => (\n <SkeletonLoader key={`stat-skeleton-${index}`} className=\"h-28\" />\n ))\n : config.widgets.stats.map((widget) => (\n <StatCard\n key={widget.id}\n label={labels[widget.label] || widget.label}\n value={data.stats[widget.valueKey]}\n icon={widget.icon}\n format={widget.format}\n />\n ))}\n </div>\n\n {/* Chart Cards (Organisms) */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {config.widgets.charts.map((widget) => (\n <ChartCard\n key={widget.id}\n widget={widget}\n labels={labels}\n loading={loading}\n filters={filters}\n chartData={data.charts}\n />\n ))}\n </div>\n\n {/* Data Table (Organism) */}\n <div className=\"card p-4\">\n <Typography variant=\"h3\" className=\"flex items-center gap-2 mb-3\">\n <Icon name={config.widgets.table.icon} size={18} />\n {labels[config.widgets.table.label] || config.widgets.table.label}\n </Typography>\n {loading ? (\n <SkeletonLoader className=\"h-48\" />\n ) : (\n <DataTable\n columns={config.widgets.table.columns}\n data={data.table.recentBookings}\n labels={labels}\n dateLocale={dateLocale}\n emptyLabel={labels[config.widgets.table.emptyLabel] || config.widgets.table.emptyLabel}\n searchable={true}\n sortable={true}\n pageSize={10}\n />\n )}\n </div>\n </div>\n );\n}\n\nReusableDashboardView.propTypes = {\n /** Konfigurasi widget dashboard. */\n config: PropTypes.object.isRequired,\n /** Objek label i18n. */\n labels: PropTypes.object.isRequired,\n /** Status loading data. */\n loading: PropTypes.bool,\n /** Pesan error jika ada. */\n error: PropTypes.string,\n /** State filter dashboard. */\n filters: PropTypes.object,\n /** Callback perubahan filter. */\n onFilterChange: PropTypes.func.isRequired,\n /** Callback reset filter. */\n onResetFilters: PropTypes.func.isRequired,\n /** Callback refresh data. */\n onRefresh: PropTypes.func.isRequired,\n /** Data dashboard. */\n data: PropTypes.object,\n /** Locale untuk format tanggal. */\n dateLocale: PropTypes.string,\n /** Apakah live update aktif. */\n liveUpdateEnabled: PropTypes.bool,\n};\n","export function createDashboardLabels(t) {\n const labels = {\n title: t(\"admin.dashboard.title\", { defaultValue: \"Dashboard\" }),\n refresh: t(\"admin.dashboard.refresh\", { defaultValue: \"Refresh\" }),\n liveUpdate: t(\"admin.dashboard.liveUpdate\", { defaultValue: \"Live update\" }),\n loadFailed: t(\"admin.dashboard.loadFailed\", {\n defaultValue: \"Failed to load dashboard data.\",\n }),\n retry: t(\"admin.dashboard.retry\", { defaultValue: \"Retry\" }),\n confirmedOnly: t(\"admin.dashboard.filters.confirmedOnly\", {\n defaultValue: \"Confirmed only\",\n }),\n pendingOnly: t(\"admin.dashboard.filters.pendingOnly\", {\n defaultValue: \"Pending only\",\n }),\n allStatus: t(\"admin.dashboard.filters.allStatus\", {\n defaultValue: \"All status\",\n }),\n showPendingOverlay: t(\"admin.dashboard.filters.showPendingOverlay\", {\n defaultValue: \"Show pending overlay\",\n }),\n allAudience: t(\"admin.dashboard.filters.allAudience\", {\n defaultValue: \"All audience\",\n }),\n audienceDomestic: t(\"explore.domestic\", { defaultValue: \"Domestic\" }),\n audienceForeign: t(\"explore.foreign\", { defaultValue: \"Foreign\" }),\n customDate: t(\"admin.dashboard.filters.customDate\", {\n defaultValue: \"Custom\",\n }),\n reset: t(\"admin.dashboard.filters.reset\", { defaultValue: \"Reset\" }),\n topSort: t(\"admin.dashboard.filters.topSort\", {\n defaultValue: \"Top packages sort\",\n }),\n sortBookings: t(\"admin.dashboard.filters.sortBookings\", {\n defaultValue: \"Bookings\",\n }),\n sortRevenue: t(\"admin.dashboard.filters.sortRevenue\", {\n defaultValue: \"Revenue\",\n }),\n sortDesc: t(\"admin.dashboard.filters.sortDesc\", { defaultValue: \"Desc\" }),\n sortAsc: t(\"admin.dashboard.filters.sortAsc\", { defaultValue: \"Asc\" }),\n confirmedBookings: t(\"admin.dashboard.cards.confirmedBookings\", {\n defaultValue: \"Confirmed Bookings\",\n }),\n confirmedRevenue: t(\"admin.dashboard.cards.confirmedRevenue\", {\n defaultValue: \"Revenue (Confirmed)\",\n }),\n avgRevenue: t(\"admin.dashboard.cards.avgRevenue\", {\n defaultValue: \"Avg Revenue / Booking\",\n }),\n conversionRate: t(\"admin.dashboard.cards.conversionRate\", {\n defaultValue: \"Conversion Rate\",\n }),\n totalProducts: t(\"admin.dashboard.cards.totalProducts\", {\n defaultValue: \"Total Products\",\n }),\n totalCustomers: t(\"admin.dashboard.cards.totalCustomers\", {\n defaultValue: \"Total Customers\",\n }),\n dailyTrends: t(\"admin.dashboard.sections.dailyTrends\", {\n defaultValue: \"Daily Trends\",\n }),\n statusDistribution: t(\"admin.dashboard.sections.statusDistribution\", {\n defaultValue: \"Status Distribution\",\n }),\n audienceDistribution: t(\"admin.dashboard.sections.audienceDistribution\", {\n defaultValue: \"Audience Distribution\",\n }),\n topPackages: t(\"admin.dashboard.sections.topPackages\", {\n defaultValue: \"Top Packages\",\n }),\n recentBookings: t(\"admin.dashboard.sections.recentBookings\", {\n defaultValue: \"Recent Bookings\",\n }),\n date: t(\"admin.dashboard.table.date\", { defaultValue: \"Date\" }),\n customer: t(\"admin.dashboard.table.customer\", { defaultValue: \"Customer\" }),\n package: t(\"admin.dashboard.table.package\", { defaultValue: \"Package\" }),\n audience: t(\"admin.dashboard.table.audience\", { defaultValue: \"Audience\" }),\n total: t(\"admin.dashboard.table.total\", { defaultValue: \"Total\" }),\n status: t(\"admin.dashboard.table.status\", { defaultValue: \"Status\" }),\n noRecentBookings: t(\"admin.dashboard.emptyRecent\", {\n defaultValue: \"No recent bookings\",\n }),\n bookingsMetric: t(\"admin.dashboard.metrics.bookings\", {\n defaultValue: \"Bookings\",\n }),\n revenueMetric: t(\"admin.dashboard.metrics.revenue\", {\n defaultValue: \"Revenue\",\n }),\n pendingMetric: t(\"admin.dashboard.metrics.pendingBookings\", {\n defaultValue: \"Bookings (Pending)\",\n }),\n confirmedBookingMetric: t(\"admin.dashboard.metrics.confirmedBookings\", {\n defaultValue: \"Bookings (Confirmed)\",\n }),\n confirmedRevenueMetric: t(\"admin.dashboard.metrics.confirmedRevenue\", {\n defaultValue: \"Revenue (Confirmed)\",\n }),\n unknownAudience: t(\"admin.dashboard.filters.unknownAudience\", {\n defaultValue: \"Unknown\",\n }),\n };\n\n labels.dayLabel = (count) =>\n t(\"admin.dashboard.filters.dayWindow\", {\n count,\n defaultValue: \"{{count}} days\",\n });\n\n labels.formatStatusLabel = (status) => {\n const normalized = String(status || \"pending\").toLowerCase();\n const defaultValue =\n normalized.charAt(0).toUpperCase() + normalized.slice(1);\n\n return t(`admin.dashboard.status.${normalized}`, { defaultValue });\n };\n\n labels.formatAudienceLabel = (value) => {\n if (value === \"domestic\") return labels.audienceDomestic;\n if (value === \"foreign\") return labels.audienceForeign;\n return labels.unknownAudience;\n };\n\n return labels;\n}\n"],"mappings":"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","names":["ensureNoError","import_react","import_react","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","MIN_YEAR","formatDate","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes","import_react","import_prop_types","React","PropTypes"]}