Compare commits
4 Commits
e476e3a3ad
...
bd3ee8db53
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd3ee8db53 | ||
|
|
6a00b9207e | ||
|
|
bd92f9a09f | ||
|
|
b7e029546f |
227
app/components/ui/chart.tsx
Normal file
227
app/components/ui/chart.tsx
Normal file
@ -0,0 +1,227 @@
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
ArcElement,
|
||||
Tooltip,
|
||||
Legend,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
type ChartOptions,
|
||||
type ChartEvent,
|
||||
type ActiveElement,
|
||||
} from 'chart.js'
|
||||
import { useState } from 'react'
|
||||
import { Bar, Doughnut, Pie } from 'react-chartjs-2'
|
||||
ChartJS.register(
|
||||
ArcElement,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
)
|
||||
|
||||
type HandleChartClick = (event: ChartEvent, elements: ActiveElement[]) => void
|
||||
|
||||
export const UiChartPie = () => {
|
||||
const data = {
|
||||
labels: [
|
||||
'Pidana',
|
||||
'Perdata',
|
||||
'Perceraian',
|
||||
'Surat Bisnis',
|
||||
'Surat Tanah',
|
||||
'Lainnya',
|
||||
],
|
||||
datasets: [
|
||||
{
|
||||
data: [33.7, 13, 22.8, 9.3, 9.3, 21.2],
|
||||
backgroundColor: [
|
||||
'#FFB300',
|
||||
'#4CAF50',
|
||||
'#3F51B5',
|
||||
'#F44336',
|
||||
'#2196F3',
|
||||
'#FF9800',
|
||||
],
|
||||
hoverOffset: 4,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const options: ChartOptions<'pie'> = {
|
||||
maintainAspectRatio: true,
|
||||
responsive: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: 'circle',
|
||||
padding: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
padding: 0,
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-[300px] w-full items-center justify-center rounded-lg bg-white p-5 text-center">
|
||||
<h2 className="text-xl font-bold">Top 5 Konten</h2>
|
||||
<Pie
|
||||
height={225}
|
||||
width={450}
|
||||
data={data}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const UiChartBar = () => {
|
||||
const yearlyData = {
|
||||
labels: ['2022', '2023', '2024'],
|
||||
datasets: [
|
||||
{
|
||||
label: 'Total Sales',
|
||||
data: [800, 950, 1200],
|
||||
backgroundColor: '#1E3A8A',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const monthlyData = {
|
||||
labels: [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec',
|
||||
],
|
||||
datasets: [
|
||||
{
|
||||
label: 'Monthly Sales',
|
||||
data: [70, 90, 750, 80, 90, 95, 75, 85, 78, 88, 95, 0],
|
||||
backgroundColor: '#2E2F7C',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const [view, setView] = useState('month') // Default tampil bulanan
|
||||
const [selectedYear, setSelectedYear] = useState('')
|
||||
|
||||
const handleChartClick: HandleChartClick = (event, elements) => {
|
||||
if (elements.length > 0 && view === 'year') {
|
||||
const clickedIndex = elements[0].index
|
||||
const year = yearlyData.labels[clickedIndex]
|
||||
setSelectedYear(year)
|
||||
setView('month')
|
||||
}
|
||||
}
|
||||
|
||||
const handleBackToYear = () => {
|
||||
setView('year')
|
||||
setSelectedYear('')
|
||||
}
|
||||
|
||||
const options = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: handleChartClick,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: view == 'month' ? 100 : 1500,
|
||||
ticks: {
|
||||
stepSize: 25,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-xl bg-white p-6 shadow-lg">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2 className="text-xl font-bold">
|
||||
{view === 'year'
|
||||
? 'Penjualan Tahunan'
|
||||
: `Penjualan Bulanan ${selectedYear || '2024'}`}
|
||||
</h2>
|
||||
{view === 'month' && (
|
||||
<button
|
||||
className="rounded-lg bg-gray-200 px-4 py-2"
|
||||
onClick={handleBackToYear}
|
||||
>
|
||||
Tahun
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Bar
|
||||
data={view === 'year' ? yearlyData : monthlyData}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const ChartSubscription = () => {
|
||||
const data = {
|
||||
labels: ['Selesai', 'Belum Selesai'],
|
||||
datasets: [
|
||||
{
|
||||
data: [70, 30],
|
||||
backgroundColor: ['#1e3a8a', '#e5e7eb'],
|
||||
borderWidth: 0,
|
||||
cutout: '70%',
|
||||
circumference: 180,
|
||||
rotation: 270,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const options: ChartOptions<'doughnut'> = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: 'circle',
|
||||
boxWidth: 10,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-xl bg-white p-6 shadow-lg">
|
||||
<h2 className="mb-4 text-[20px]">Subscription Selesai</h2>
|
||||
<div className="flex items-center justify-between">
|
||||
<div style={{ height: '200px', width: '100%' }}>
|
||||
<Doughnut
|
||||
data={data}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
app/pages/dashboard-subscriptions/data.ts
Normal file
21
app/pages/dashboard-subscriptions/data.ts
Normal file
@ -0,0 +1,21 @@
|
||||
type TSubscriptions = {
|
||||
id: number
|
||||
createdAt: string
|
||||
date: string
|
||||
name: string
|
||||
email: string
|
||||
category: string
|
||||
status: string
|
||||
}
|
||||
|
||||
export const CONTENTS: TSubscriptions[] = [
|
||||
{
|
||||
id: 1,
|
||||
createdAt: '24/10/2024',
|
||||
date: '24/10/2024',
|
||||
name: 'John Doe',
|
||||
email: 'test@test.com',
|
||||
category: 'Education',
|
||||
status: 'Published',
|
||||
},
|
||||
]
|
||||
36
app/pages/dashboard-subscriptions/index.tsx
Normal file
36
app/pages/dashboard-subscriptions/index.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import DT from 'datatables.net-dt'
|
||||
import DataTable from 'datatables.net-react'
|
||||
|
||||
import { TitleDashboard } from '~/components/ui/title-dashboard'
|
||||
|
||||
import { CONTENTS } from './data'
|
||||
|
||||
export const SubscriptionsPage = () => {
|
||||
DataTable.use(DT)
|
||||
const columns = [
|
||||
{ title: 'No', data: 'id' },
|
||||
{ title: 'Tanggal Subscribe', data: 'date' },
|
||||
{ title: 'Nama User', data: 'name' },
|
||||
{ title: 'Email', data: 'email' },
|
||||
{ title: 'Kategori', data: 'category' },
|
||||
{ title: 'Status', data: 'status' },
|
||||
{ title: 'Action', data: 'id', render: () => 'Subscribed' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<TitleDashboard title="Subscription" />
|
||||
<DataTable
|
||||
className="cell-border"
|
||||
data={CONTENTS}
|
||||
columns={columns}
|
||||
options={{
|
||||
paging: true,
|
||||
searching: true,
|
||||
ordering: true,
|
||||
info: true,
|
||||
}}
|
||||
></DataTable>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -1,10 +1,14 @@
|
||||
import { CardReport } from '~/components/ui/card-report'
|
||||
import {
|
||||
ChartSubscription,
|
||||
UiChartBar,
|
||||
UiChartPie,
|
||||
} from '~/components/ui/chart'
|
||||
|
||||
import { HISTORY, REPORT } from './data'
|
||||
export const DashboardPage = () => {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="container mx-auto">
|
||||
<section className="mb-5 flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold">Dashboard</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
@ -19,8 +23,7 @@ export const DashboardPage = () => {
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="mb-5 grid grid-cols-3 gap-4">
|
||||
<div className="mt-5 grid grid-cols-1 grid-rows-1 gap-6 sm:grid-cols-3">
|
||||
{REPORT.map(({ title, amount, icon }, index) => (
|
||||
<CardReport
|
||||
key={index}
|
||||
@ -31,8 +34,7 @@ export const DashboardPage = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-x-4 gap-y-4">
|
||||
<div className="grid gap-y-4">
|
||||
<div className="mt-5 grid grid-cols-1 gap-6 sm:grid-cols-3 sm:grid-rows-2">
|
||||
{HISTORY.map(({ title, amount, icon, counter }, index) => (
|
||||
<CardReport
|
||||
key={index}
|
||||
@ -42,27 +44,24 @@ export const DashboardPage = () => {
|
||||
counter={counter}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<img
|
||||
src="/images/dummy-chart-2.svg"
|
||||
alt=""
|
||||
/>
|
||||
<div className="max-h-[300px] sm:col-span-2 sm:col-start-2 sm:row-span-2 sm:row-start-1">
|
||||
<UiChartPie />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 flex justify-between gap-5">
|
||||
<div className="w-[600px] shadow-sm">
|
||||
<img
|
||||
src="/images/dummy-chart-1.svg"
|
||||
alt=""
|
||||
/>
|
||||
<div className="mt-5 grid max-h-[280px] grid-cols-1 grid-rows-2 gap-6 sm:grid-cols-5 sm:grid-rows-1">
|
||||
<div className="sm:col-span-3">
|
||||
<div className="h-30 w-full">
|
||||
<div className="shadow-sm">
|
||||
<UiChartBar />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:col-span-2 sm:col-start-4">
|
||||
<div className="h-30 w-full">
|
||||
<div className="shadow-sm">
|
||||
<ChartSubscription />
|
||||
</div>
|
||||
<div className="w-[480px] shadow-sm">
|
||||
<img
|
||||
src="/images/dummy-chart-3.svg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import { SubscriptionsPage } from '~/pages/dashboard-subscriptions'
|
||||
|
||||
const DashboardSubscriptionsLayout = () => {
|
||||
return <div>Subscriptions Page</div>
|
||||
return <SubscriptionsPage />
|
||||
}
|
||||
export default DashboardSubscriptionsLayout
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user