Add ss 00
This commit is contained in:
parent
8d60c5ab9c
commit
8d1c19e5b0
@ -3,17 +3,12 @@ import { useAppSelector } from '@/redux/store';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Cookies from 'universal-cookie';
|
||||
const ReactApexChart = dynamic(() => import('react-apexcharts'), {
|
||||
ssr: false,
|
||||
});
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { AppDispatch } from '@/redux/store';
|
||||
import { setCurrentMembersGeneralOverviewDuration } from '@/redux/features/statistics-slice'
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
const ReactApexChart = dynamic(() => import('react-apexcharts'), {
|
||||
ssr: false,
|
||||
loading: () => <div className="flex items-center justify-center h-full">
|
||||
<Loader2 className="w-8 h-8 animate-spin" />
|
||||
</div>
|
||||
});
|
||||
|
||||
export default function MembersOverviewChart()
|
||||
{
|
||||
@ -21,7 +16,6 @@ export default function MembersOverviewChart()
|
||||
const report = useAppSelector((state) => state.statisticsReducer.value.report)
|
||||
const currentMembersGeneralOverviewDuration = useAppSelector((state) => state.statisticsReducer.value.currentMembersGeneralOverviewDuration)
|
||||
const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType)
|
||||
|
||||
// declare global variables
|
||||
const dispatch = useDispatch<AppDispatch>()
|
||||
const cookies = new Cookies();
|
||||
@ -29,63 +23,95 @@ export default function MembersOverviewChart()
|
||||
const locale = cookies.get("NEXT_LOCALE")
|
||||
const isRtl = locale == 'ar' ? true : false
|
||||
const isDark = themeType == 'dark' ? true : false
|
||||
const [chartSeries, setChartSeries] = useState<{ name: string; data: number[] }[]>([]);
|
||||
const [chartSeries , setChartSeries] = useState<{}[]>([]);
|
||||
const [labels , setLabels] = useState<string[]>([])
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// revenue Chart
|
||||
// prepare chart series and handle the transaction between currentMembersGeneralOverviewDuration
|
||||
useEffect(() => {
|
||||
if (!report?.membersGeneralOverview) {
|
||||
setIsLoading(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
// if chart duration is set to this week
|
||||
if (currentMembersGeneralOverviewDuration == 'thisWeek') {
|
||||
if(currentMembersGeneralOverviewDuration == 'thisWeek')
|
||||
{
|
||||
// set the labels
|
||||
setLabels([t('sat') , t('sun') , t('mon') , t('tue') , t('wed') , t('thu') , t('fri')])
|
||||
|
||||
// Initialize default data structure
|
||||
const defaultWeekData = {
|
||||
sat: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
sun: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
mon: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
tue: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
wed: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
thu: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 },
|
||||
fri: { totalMembers: 0, totalActiveSubs: 0, totalUnActiveSubs: 0, totalMansMembers: 0, totalGirlsMembers: 0 }
|
||||
};
|
||||
|
||||
// Use data from report if available, otherwise use default data
|
||||
const weekData = report?.membersGeneralOverview?.value?.thisWeek?.days || defaultWeekData;
|
||||
|
||||
// init this weekdata
|
||||
let data_thisWeek = {
|
||||
'sat': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'sun': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'mon': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'tue': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'wed': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'thu': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
},
|
||||
'fri': {
|
||||
'totalMembers': 0,
|
||||
'totalActiveSubs': 0,
|
||||
'totalUnActiveSubs': 0,
|
||||
'totalMansMembers': 0,
|
||||
'totalGirlsMembers': 0,
|
||||
}
|
||||
}
|
||||
// if there is a data from the backend we overwrite the currentData
|
||||
if(report?.membersGeneralOverview?.value.thisWeek.days) {
|
||||
data_thisWeek = report?.membersGeneralOverview?.value.thisWeek.days;
|
||||
}
|
||||
// prepare the chart series
|
||||
setChartSeries([
|
||||
{
|
||||
name: t('totalMembers'),
|
||||
data: ['sat', 'sun', 'mon', 'tue', 'wed', 'thu', 'fri'].map(day => weekData[day]?.totalMembers || 0),
|
||||
data: [data_thisWeek['sat']['totalMembers'], data_thisWeek['sun']['totalMembers'], data_thisWeek['mon']['totalMembers'], data_thisWeek['tue']['totalMembers'], data_thisWeek['wed']['totalMembers'], data_thisWeek['thu']['totalMembers'], data_thisWeek['fri']['totalMembers']],
|
||||
},
|
||||
{
|
||||
name: t('totalActiveSubs'),
|
||||
data: ['sat', 'sun', 'mon', 'tue', 'wed', 'thu', 'fri'].map(day => weekData[day]?.totalActiveSubs || 0),
|
||||
data: [data_thisWeek['sat']['totalActiveSubs'], data_thisWeek['sun']['totalActiveSubs'], data_thisWeek['mon']['totalActiveSubs'], data_thisWeek['tue']['totalActiveSubs'], data_thisWeek['wed']['totalActiveSubs'], data_thisWeek['thu']['totalActiveSubs'], data_thisWeek['fri']['totalActiveSubs']],
|
||||
},
|
||||
{
|
||||
name: t('totalUnActiveSubs'),
|
||||
data: ['sat', 'sun', 'mon', 'tue', 'wed', 'thu', 'fri'].map(day => weekData[day]?.totalUnActiveSubs || 0),
|
||||
data: [data_thisWeek['sat']['totalUnActiveSubs'], data_thisWeek['sun']['totalUnActiveSubs'], data_thisWeek['mon']['totalUnActiveSubs'], data_thisWeek['tue']['totalUnActiveSubs'], data_thisWeek['wed']['totalUnActiveSubs'], data_thisWeek['thu']['totalUnActiveSubs'], data_thisWeek['fri']['totalUnActiveSubs']],
|
||||
},
|
||||
{
|
||||
name: t('totalMansMembers'),
|
||||
data: ['sat', 'sun', 'mon', 'tue', 'wed', 'thu', 'fri'].map(day => weekData[day]?.totalMansMembers || 0),
|
||||
data: [data_thisWeek['sat']['totalMansMembers'], data_thisWeek['sun']['totalMansMembers'], data_thisWeek['mon']['totalMansMembers'], data_thisWeek['tue']['totalMansMembers'], data_thisWeek['wed']['totalMansMembers'], data_thisWeek['thu']['totalMansMembers'], data_thisWeek['fri']['totalMansMembers']],
|
||||
},
|
||||
{
|
||||
name: t('totalGirlsMembers'),
|
||||
data: ['sat', 'sun', 'mon', 'tue', 'wed', 'thu', 'fri'].map(day => weekData[day]?.totalGirlsMembers || 0),
|
||||
data: [data_thisWeek['sat']['totalGirlsMembers'], data_thisWeek['sun']['totalGirlsMembers'], data_thisWeek['mon']['totalGirlsMembers'], data_thisWeek['tue']['totalGirlsMembers'], data_thisWeek['wed']['totalGirlsMembers'], data_thisWeek['thu']['totalGirlsMembers'], data_thisWeek['fri']['totalGirlsMembers']],
|
||||
},
|
||||
]);
|
||||
])
|
||||
}
|
||||
// if chart duration is set to this month
|
||||
else if(currentMembersGeneralOverviewDuration == 'thisMonth')
|
||||
@ -462,137 +488,200 @@ export default function MembersOverviewChart()
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error preparing chart data:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [report, currentMembersGeneralOverviewDuration, t]);
|
||||
|
||||
// Chart options
|
||||
const chartOptions: ApexCharts.ApexOptions = {
|
||||
}, [currentMembersGeneralOverviewDuration])
|
||||
// prepare the chart options
|
||||
const options : any = {
|
||||
series: chartSeries,
|
||||
options: {
|
||||
chart: {
|
||||
type: 'bar',
|
||||
height: 350,
|
||||
stacked: true,
|
||||
height: 325,
|
||||
type: 'area',
|
||||
fontFamily: 'Nunito, sans-serif',
|
||||
zoom: {
|
||||
enabled: false,
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
data_thisWeekLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
curve: 'smooth',
|
||||
width: 2,
|
||||
lineCap: 'square',
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
opacity: 0.2,
|
||||
blur: 10,
|
||||
left: -7,
|
||||
top: 22,
|
||||
},
|
||||
colors: ['#38C172', '#38C172' , '#E3342F' , '#0263FF', '#FF30F7'],
|
||||
markers: {
|
||||
//discrete: [
|
||||
// {
|
||||
// seriesIndex: 0,
|
||||
// data_thisWeekPointIndex: 1,
|
||||
// fillColor: '#38C172',
|
||||
// strokeColor: 'transparent',
|
||||
// size: 7,
|
||||
// },
|
||||
// {
|
||||
// seriesIndex: 1,
|
||||
// data_thisWeekPointIndex: 1,
|
||||
// fillColor: '#E3342F',
|
||||
// strokeColor: 'transparent',
|
||||
// size: 7,
|
||||
// },
|
||||
//],
|
||||
},
|
||||
labels: labels,
|
||||
xaxis: {
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
},
|
||||
crosshairs: {
|
||||
show: true,
|
||||
},
|
||||
zoom: {
|
||||
enabled: true,
|
||||
},
|
||||
foreColor: isDark ? '#fff' : '#333',
|
||||
fontFamily: isRtl ? 'Tajawal, sans-serif' : 'Inter, sans-serif',
|
||||
},
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
offsetY: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
borderRadius: 5,
|
||||
dataLabels: {
|
||||
total: {
|
||||
enabled: true,
|
||||
style: {
|
||||
fontSize: '13px',
|
||||
fontWeight: 900,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: labels,
|
||||
labels: {
|
||||
offsetX: isRtl ? 2 : 0,
|
||||
offsetY: 5,
|
||||
style: {
|
||||
colors: isDark ? '#fff' : '#333',
|
||||
colors: isDark ? '#fff' : '#000',
|
||||
fontSize: '12px',
|
||||
cssClass: 'apexcharts-xaxis-title',
|
||||
},
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
tickAmount: 7,
|
||||
labels: {
|
||||
style: {
|
||||
colors: isDark ? '#fff' : '#333',
|
||||
formatter: (value: number) => {
|
||||
if(value > 1000)
|
||||
{
|
||||
return parseInt(value.toFixed(0)) + t('k')
|
||||
}
|
||||
else {
|
||||
return parseInt(value.toFixed(0))
|
||||
}
|
||||
},
|
||||
offsetX: isRtl ? -30 : -10,
|
||||
offsetY: 0,
|
||||
style: {
|
||||
colors: isDark ? '#fff' : '#000',
|
||||
fontSize: '12px',
|
||||
cssClass: 'apexcharts-yaxis-title',
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
borderColor: isDark ? '#191E3A' : '#E0E6ED',
|
||||
strokeDashArray: 5,
|
||||
xaxis: {
|
||||
lines: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
lines: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: 'right',
|
||||
offsetY: 40,
|
||||
labels: {
|
||||
colors: isDark ? '#fff' : '#333',
|
||||
position: 'top',
|
||||
horizontalAlign: 'right',
|
||||
fontSize: '16px',
|
||||
markers: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
offsetX: isRtl ? 5 : -5,
|
||||
},
|
||||
itemMargin: {
|
||||
horizontal: 10,
|
||||
vertical: 5,
|
||||
},
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
theme: isDark ? 'dark' : 'light',
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val.toString();
|
||||
x: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
shadeIntensity: 1,
|
||||
inverseColors: !1,
|
||||
opacityFrom: isDark ? 0.19 : 0.28,
|
||||
opacityTo: 0.05,
|
||||
stops: isDark ? [100, 100] : [45, 100],
|
||||
},
|
||||
},
|
||||
responsive: [{
|
||||
breakpoint: 420,
|
||||
options: {
|
||||
yaxis: {
|
||||
show: false,
|
||||
showAlways: false,
|
||||
},
|
||||
legend: {
|
||||
offsetY: 10,
|
||||
height: 60,
|
||||
position: 'bottom',
|
||||
horizontalAlign: 'center',
|
||||
fontSize: '12px',
|
||||
markers: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
offsetX: isRtl ? 5 : -5,
|
||||
},
|
||||
itemMargin: {
|
||||
horizontal: 10,
|
||||
vertical: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if (isLoading || !report?.membersGeneralOverview) {
|
||||
// return the ui
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center min-h-[400px]">
|
||||
<Loader2 className="w-8 h-8 animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full h-full">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-semibold">{t('membersGeneralOverview')}</h3>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => dispatch(setCurrentMembersGeneralOverviewDuration('thisWeek'))}
|
||||
className={`px-3 py-1 rounded-md text-sm ${currentMembersGeneralOverviewDuration === 'thisWeek' ? 'bg-primary text-white' : 'bg-gray-200 dark:bg-gray-700'}`}
|
||||
>
|
||||
<>
|
||||
<div className="flex flex-col gap-5 [&_*]:dark:!text-text-dark p-5 lg:w-2/3 w-full shadow border border-secondary-light bg-primary dark:bg-primary-dark rounded-[5px]">
|
||||
<h3 className="text-xl font-bold">{t('membersGeneralOverview')}</h3>
|
||||
<div className="w-full flex gap-3 justify-end">
|
||||
<button disabled={currentMembersGeneralOverviewDuration == 'thisWeek'} onClick={() => {
|
||||
dispatch(setCurrentMembersGeneralOverviewDuration('thisWeek'))
|
||||
}} className="disabled:dark:opacity-[0.5] disabled:opacity-[0.5]">
|
||||
{t('thisWeek')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => dispatch(setCurrentMembersGeneralOverviewDuration('thisMonth'))}
|
||||
className={`px-3 py-1 rounded-md text-sm ${currentMembersGeneralOverviewDuration === 'thisMonth' ? 'bg-primary text-white' : 'bg-gray-200 dark:bg-gray-700'}`}
|
||||
>
|
||||
<button disabled={currentMembersGeneralOverviewDuration == 'thisMonth'} onClick={() => {
|
||||
dispatch(setCurrentMembersGeneralOverviewDuration('thisMonth'))
|
||||
}} className="disabled:dark:opacity-[0.5] disabled:opacity-[0.5]">
|
||||
{t('thisMonth')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => dispatch(setCurrentMembersGeneralOverviewDuration('thisYear'))}
|
||||
className={`px-3 py-1 rounded-md text-sm ${currentMembersGeneralOverviewDuration === 'thisYear' ? 'bg-primary text-white' : 'bg-gray-200 dark:bg-gray-700'}`}
|
||||
>
|
||||
<button disabled={currentMembersGeneralOverviewDuration == 'thisYear'} onClick={() => {
|
||||
dispatch(setCurrentMembersGeneralOverviewDuration('thisYear'))
|
||||
}} className="disabled:dark:opacity-[0.5] disabled:opacity-[0.5]">
|
||||
{t('thisYear')}
|
||||
</button>
|
||||
</div>
|
||||
<ReactApexChart series={options.series} options={options.options} type="area" height={350} width={'100%'} />
|
||||
</div>
|
||||
|
||||
<div className="w-full h-[400px] mt-4">
|
||||
<ReactApexChart
|
||||
options={chartOptions}
|
||||
series={chartSeries}
|
||||
type="bar"
|
||||
height="100%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user