revamp template

This commit is contained in:
fro1991
2025-02-01 16:44:51 +07:00
parent c432df568a
commit 276a289580
1212 changed files with 112762 additions and 0 deletions

View File

@ -0,0 +1,52 @@
import { useLanguage } from '@/i18n';
import { fCurrency } from '@/utils/FormatNumber';
import { toAbsoluteUrl } from '@/utils/Assets';
interface CardDataProduct {
title: string;
total: string;
type: Array<{ label: string; value: string; total: string }>;
count: 'sum' | 'count';
}
const Card = ({ title, total, type, count }: CardDataProduct) => {
const { isRTL } = useLanguage();
return (
<div className="card h-full bg-[length:85%] bg-[length:85%] [background-position:9rem_-4rem] rtl:[background-position:-4rem_-4rem] bg-no-repeat channel-stats-bg">
<div className="card-body flex flex-col gap-4 p-5 lg:p-b-7.5 lg:pt-4">
<div className="flex justify-between">
<div className="flex flex-col w-8/12" style={{ background: '' }}>
<span className="text-sm font-normal text-gray-600 mb-5">{title}</span>
<span className="text-3xl font-semibold text-gray-900 mb-0">
{count === 'sum' ? fCurrency(total) : total}
</span>
</div>
<div className="flex flex-col w-4/12 justify-between" style={{ background: '' }}>
<img
src={toAbsoluteUrl('/media/file-types/chart.svg')}
className="dark:hidden h-5 h-8"
alt="Chart Icon"
/>
</div>
</div>
{/* <hr className="" />
<div className="">
{type.map((data: any, index: number) => (
<div key={data.label}>
<div className="flex justify-between mb-1">
<div className="w-8/12 text-sm">{data.label}</div>
<div className="w-4/12 text-sm text-end">
{count === 'sum' ? fCurrency(data.total) : data.total}{' '}
</div>
</div>
{index !== type.length - 1 && <hr className="border-dashed my-2" />}
</div>
))}
</div> */}
</div>
</div>
);
};
export { Card };

View File

@ -0,0 +1,166 @@
import ApexChart from 'react-apexcharts';
import { ApexOptions } from 'apexcharts';
import { useEffect, useState } from 'react';
import { fCurrency } from '@/utils/FormatNumber';
interface Series {
name: string;
data: any[];
}
const Chart = ({
title,
toolbar,
chartType,
chartLegend,
subtitle,
number,
count,
chartData = []
}: any) => {
const [series, setSeries] = useState<Series[]>([]);
const [categories, setCategories] = useState<string[]>([]);
let legendOpt = null;
if (chartLegend == 'true') {
legendOpt = true;
} else {
legendOpt = false;
}
const options: ApexOptions = {
chart: {
type: 'area',
toolbar: {
show: false
}
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '50%'
}
},
dataLabels: {
enabled: true,
offsetY: -10,
offsetX: chartType === 'bar' ? 1.5 : 0,
formatter: (value: any) => {
if (count == 'sum') {
return fCurrency(value);
} else {
return value;
}
}
},
markers: {
size: 0,
shape: 'circle'
},
xaxis: {
categories: categories,
labels: {
style: {
colors: 'var(--tw-gray-500)',
fontSize: '12px'
}
}
},
yaxis: {
labels: {
style: {
colors: 'var(--tw-gray-500)',
fontSize: '12px'
},
formatter: (value: any) => {
if (count == 'sum') {
return fCurrency(value);
} else {
return value;
}
}
}
},
grid: {
borderColor: 'var(--tw-gray-200)',
strokeDashArray: 5,
padding: {
top: 0,
right: 0,
bottom: 20,
left: 0
}
},
tooltip: {
enabled: true,
shared: true,
intersect: false,
y: {
formatter: (value: any) => {
if (count == 'sum') {
return fCurrency(value);
} else {
return value;
}
}
}
},
stroke: {
show: true,
curve: 'smooth',
lineCap: 'butt',
colors: undefined,
width: 3,
dashArray: 0
},
legend: {
show: legendOpt,
position: 'right',
floating: false
}
};
useEffect(() => {
if (chartData && chartData.length !== 0) {
const categories = chartData.map((item: any) => item.month);
const statusNames = Object.keys(chartData[0]).filter((key) => key !== 'month');
const series = statusNames.map((status) => {
const cleanName = status
.replace('_count', '')
.replace(/_/g, ' ')
.replace(/(^|\s)\S/g, (match) => match.toUpperCase());
return {
name: cleanName,
data: chartData.map((item: any) => item[status])
};
});
setCategories(categories);
setSeries(series);
}
}, [chartData]);
return (
<div className="card h-full">
<div className="card-header border-0 ps-5 pb-0">
<h3 className="card-title">{title}</h3>
</div>
<div className="card-body flex flex-col gap-4 p-2 lg:p-b7.5 lg:pt-4">
<div className="flex justify-between">
<div className="flex flex-col w-full">
<div className="ps-3">{toolbar && <div>{toolbar}</div>}</div>
<span className="text-sm font-normal text-gray-700 mb-1">{subtitle}</span>
<span className="text-3xl font-semibold text-gray-900 mb-0">{number}</span>
</div>
</div>
<ApexChart
id="earnings_chart" //
options={options}
series={series}
type={chartType}
legend={chartLegend}
height={350}
/>
</div>
</div>
);
};
export { Chart };

View File

@ -0,0 +1,53 @@
import { useState } from 'react';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Calendar } from '@/components/ui/calendar';
import { DateRange } from 'react-day-picker';
import { format } from 'date-fns';
import { KeenIcon } from '@/components/keenicons';
import { cn } from '@/lib/utils';
interface DateRangePickerProps {
date: DateRange | undefined;
setDate: (date: DateRange | undefined) => void;
}
const DateRangePicker = ({ date, setDate }: DateRangePickerProps) => {
return (
<Popover>
<PopoverTrigger asChild>
<button
id="date"
className={cn(
'btn btn-sm btn-light data-[state=open]:bg-light-active',
!date && 'text-gray-400'
)}
>
<KeenIcon icon="calendar" className="me-0.5" />
{date?.from ? (
date.to ? (
<>
{format(date.from, 'LLL dd, y')} - {format(date.to, 'LLL dd, y')}
</>
) : (
format(date.from, 'LLL dd, y')
)
) : (
<span>Pick a date range</span>
)}
</button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="end">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
);
};
export { DateRangePicker };

View File

@ -0,0 +1,48 @@
import { useState, useEffect } from 'react';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from '@/components/ui/select';
import { get5LastYear } from '@/utils/Date';
interface YearPickerProps {
selectedYear: string;
setSelectedYear: (year: string) => void;
}
// Komponen YearPicker
const YearPicker = ({ selectedYear, setSelectedYear }: YearPickerProps) => {
const selectYear = get5LastYear();
const handleYearChange = (year: string) => {
setSelectedYear(year);
};
return (
<div className="flex gap-3">
<Select value={selectedYear} onValueChange={handleYearChange}>
<SelectTrigger size="sm" className="w-28">
<SelectValue placeholder="Pilih Tahun" />
</SelectTrigger>
<SelectContent>
{selectYear.length > 0 ? (
selectYear.map((year, index) => (
<SelectItem key={index} value={year}>
{year}
</SelectItem>
))
) : (
<SelectItem value="no-data" disabled>
No data available
</SelectItem>
)}
</SelectContent>
</Select>
</div>
);
};
export { YearPicker };

View File

@ -0,0 +1,4 @@
export * from './Card';
export * from './DateRangePicker';
export * from './Chart';
export * from './YearPicker';