ironGym/webapp/src/components/dashboard/home/membersOverviewChart.tsx
2025-06-23 14:35:41 +03:00

687 lines
30 KiB
TypeScript

import { useEffect, useState } from 'react'
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'
export default function MembersOverviewChart()
{
// get needed redux state
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();
const t = useTranslations('statistics');
const locale = cookies.get("NEXT_LOCALE")
const isRtl = locale == 'ar' ? true : false
const isDark = themeType == 'dark' ? true : false
const [chartSeries , setChartSeries] = useState<{}[]>([]);
const [labels , setLabels] = useState<string[]>([])
// revenue Chart
// prepare chart series and handle the transaction between currentMembersGeneralOverviewDuration
useEffect(() => {
// if chart duration is set to this week
if(currentMembersGeneralOverviewDuration == 'thisWeek')
{
// set the labels
setLabels([t('sat') , t('sun') , t('mon') , t('tue') , t('wed') , t('thu') , t('fri')])
// 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: [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: [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: [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: [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: [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')
{
let thisMonthTotalSum : {
week : number,
thisWeekSum : {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
}[];
if(report?.membersGeneralOverview?.value.thisMonth)
{
// if we founded a data for the current month
thisMonthTotalSum = report?.membersGeneralOverview?.value.thisMonth.weeks.map((v : any , i : number) : {
week : number,
thisWeekSum : {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
} => {
// we init the this week sum
let thisWeekSum = {
"totalMembers": 0,
"totalActiveSubs": 0,
"totalUnActiveSubs": 0,
"totalMansMembers": 0,
"totalGirlsMembers": 0
}
// we map through this month weeks
v.days.map((w : {
'sat': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'sun': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'mon': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'tue': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'wed': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'thu': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'fri': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
}
} , i : number) => {
// we loop through week days and we sum there data
Object.keys(w).forEach(function(key : "sat" | "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "_id" , index : number) {
if(key == '_id') return
thisWeekSum.totalMembers = thisWeekSum.totalMembers + w[key].totalMembers
thisWeekSum.totalActiveSubs = thisWeekSum.totalActiveSubs + w[key].totalActiveSubs
thisWeekSum.totalUnActiveSubs = thisWeekSum.totalUnActiveSubs + w[key].totalUnActiveSubs
thisWeekSum.totalMansMembers = thisWeekSum.totalMansMembers + w[key].totalMansMembers
thisWeekSum.totalGirlsMembers = thisWeekSum.totalGirlsMembers + w[key].totalGirlsMembers
})
})
// each week we return there sum data
return {
week: v.week,
thisWeekSum: thisWeekSum
}
})
let labels : [] = [];
thisMonthTotalSum.forEach(function(v , i) {
labels.push(t('week')+ ' ' +thisMonthTotalSum[i]["week"])
})
// set the labels
setLabels(labels)
// we setup chart_series ( chart data )
let a : {
name: string,
data: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
}[] = ['totalMembers' , 'totalActiveSubs' , 'totalUnActiveSubs' , 'totalMansMembers' , 'totalGirlsMembers'].map((v : string , i : number) : {
name: string,
data: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
} => {
let data = thisMonthTotalSum.map((v2 : {
week: number,
thisWeekSum: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
},i2 : number) => {
let index : 'totalMembers' | 'totalActiveSubs' | 'totalUnActiveSubs' | 'totalMansMembers' | 'totalGirlsMembers' = v;
return v2.thisWeekSum[index];
})
// return the line data
return {
name: t(v),
data: data
};
})
setChartSeries(a)
}
// if there was no data we use default return
else {
setChartSeries([
{
name: '1'+t('week'),
data: [0,0,0,0,0],
},
{
name: '2'+t('week'),
data: [0,0,0,0,0],
},
{
name: '3'+t('week'),
data: [0,0,0,0,0],
},
{
name: '4'+t('week'),
data: [0,0,0,0,0],
}
])
}
}
// if chart duration is set to this month
else if(currentMembersGeneralOverviewDuration == 'thisYear')
{
// set the labels
setLabels([t('1month'), t('2month'), t('3month'), t('4month'), t('5month'), t('6month'), t('7month'), t('8month'), t('9month'), t('10month'), t('11month')])
// check if there is current month report
let thisYearTotalSum : {
month: number,
thisMonthWeeksSum: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
}[]
if(report?.membersGeneralOverview?.value.thisYear)
{
// if we founded a data for the current month
thisYearTotalSum = report?.membersGeneralOverview?.value.thisYear.months.map((v : any , i : number) : {
month : number,
thisMonthWeeksSum : {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
} => {
let summedWeeks = v.weeks.map((w : any , i : number) => {
// we map through this month weeks
let weekSum = w.days.map((d : {
'sat': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'sun': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'mon': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'tue': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'wed': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'thu': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
},
'fri': {
'totalMembers': number,
'totalActiveSubs': number,
'totalUnActiveSubs': number,
'totalMansMembers': number,
'totalGirlsMembers': number,
}
} , i : number) => {
// we init the this week sum
let thisWeekSum = {
"totalMembers": 0,
"totalActiveSubs": 0,
"totalUnActiveSubs": 0,
"totalMansMembers": 0,
"totalGirlsMembers": 0
}
// we loop through week days and we sum there data
Object.keys(d).forEach(function(key : "sat" | "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "_id" , index : number) {
if(key == '_id') return
thisWeekSum.totalMembers = thisWeekSum.totalMembers + d[key].totalMembers
thisWeekSum.totalActiveSubs = thisWeekSum.totalActiveSubs + d[key].totalActiveSubs
thisWeekSum.totalUnActiveSubs = thisWeekSum.totalUnActiveSubs + d[key].totalUnActiveSubs
thisWeekSum.totalMansMembers = thisWeekSum.totalMansMembers + d[key].totalMansMembers
thisWeekSum.totalGirlsMembers = thisWeekSum.totalGirlsMembers + d[key].totalGirlsMembers
})
// each week we return there sum data
return thisWeekSum
})
return {
week: w.week,
weekSum: weekSum
}
})
let thisMonthWeeksSum = {
"totalMembers": 0,
"totalActiveSubs": 0,
"totalUnActiveSubs": 0,
"totalMansMembers": 0,
"totalGirlsMembers": 0
}
summedWeeks.map((v : {week: number, weekSum: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}[]},i : number) => {
thisMonthWeeksSum.totalMembers += v.weekSum[0].totalMembers
thisMonthWeeksSum.totalActiveSubs += v.weekSum[0].totalActiveSubs
thisMonthWeeksSum.totalUnActiveSubs += v.weekSum[0].totalUnActiveSubs
thisMonthWeeksSum.totalMansMembers += v.weekSum[0].totalMansMembers
thisMonthWeeksSum.totalGirlsMembers += v.weekSum[0].totalGirlsMembers
})
return {
month: v.month,
thisMonthWeeksSum: thisMonthWeeksSum
}
})
// prepare the labels
let labels : [] = [];
thisYearTotalSum.forEach(function(v , i) {
labels.push(t(thisYearTotalSum[i]["month"]+"month"))
})
setLabels(labels)
// we setup chart_series ( chart data )
let a : {
name: string,
data: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
}[] = ['totalMembers' , 'totalActiveSubs' , 'totalUnActiveSubs' , 'totalMansMembers' , 'totalGirlsMembers'].map((v : string , i : number) : {
name: string,
data: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
} => {
let data = thisYearTotalSum.map((v2 : {
month: number,
thisMonthWeeksSum: {
"totalMembers": number,
"totalActiveSubs": number,
"totalUnActiveSubs": number,
"totalMansMembers": number,
"totalGirlsMembers": number
}
},i2 : number) => {
let index : 'totalMembers' | 'totalActiveSubs' | 'totalUnActiveSubs' | 'totalMansMembers' | 'totalGirlsMembers' = v;
return v2.thisMonthWeeksSum[index];
})
// return the line data
return {
name: t(v),
data: data
};
})
setChartSeries(a)
}
// if there was no data we use default return
else {
setChartSeries([
{
name: '1'+t('week'),
data: [0,0,0,0,0],
},
{
name: '2'+t('week'),
data: [0,0,0,0,0],
},
{
name: '3'+t('week'),
data: [0,0,0,0,0],
},
{
name: '4'+t('week'),
data: [0,0,0,0,0],
}
])
}
}
}, [currentMembersGeneralOverviewDuration])
// prepare the chart options
const options : any = {
series: chartSeries,
options: {
chart: {
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,
},
labels: {
offsetX: isRtl ? 2 : 0,
offsetY: 5,
style: {
colors: isDark ? '#fff' : '#000',
fontSize: '12px',
cssClass: 'apexcharts-xaxis-title',
},
},
},
yaxis: {
tickAmount: 7,
labels: {
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: 'top',
horizontalAlign: 'right',
fontSize: '16px',
markers: {
width: 10,
height: 10,
offsetX: isRtl ? 5 : -5,
},
itemMargin: {
horizontal: 10,
vertical: 5,
},
},
tooltip: {
theme: isDark ? 'dark' : 'light',
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,
},
},
}
}],
},
};
// return the ui
return (
<>
<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 disabled={currentMembersGeneralOverviewDuration == 'thisMonth'} onClick={() => {
dispatch(setCurrentMembersGeneralOverviewDuration('thisMonth'))
}} className="disabled:dark:opacity-[0.5] disabled:opacity-[0.5]">
{t('thisMonth')}
</button>
<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>
</>
)
}