From c8828e7e5f14bd5e2da53a3b514a5b9a74c3e2c6 Mon Sep 17 00:00:00 2001 From: yznahmad Date: Sat, 21 Jun 2025 04:53:43 +0300 Subject: [PATCH] Add 30 n1234567 --- .../dashboard/home/servicesSubscriptions.tsx | 71 ++++++++++++------- .../dashboard/home/workersJobTypes.tsx | 71 ++++++++++++------- 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/webapp/src/components/dashboard/home/servicesSubscriptions.tsx b/webapp/src/components/dashboard/home/servicesSubscriptions.tsx index 41f9eeb..b4b3dac 100644 --- a/webapp/src/components/dashboard/home/servicesSubscriptions.tsx +++ b/webapp/src/components/dashboard/home/servicesSubscriptions.tsx @@ -2,6 +2,7 @@ import { useAppSelector } from '@/redux/store'; import { useTranslations } from 'next-intl'; import dynamic from 'next/dynamic'; import Cookies from 'universal-cookie'; +import { useState, useEffect } from 'react'; const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false, }); @@ -9,34 +10,56 @@ const ReactApexChart = dynamic(() => import('react-apexcharts'), { export default function ServicesSubscriptions() { // get redux needed state - const report = useAppSelector((state) => state.statisticsReducer.value.report) - const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType) + const report = useAppSelector((state) => state.statisticsReducer.value.report); + const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType); + const [isClient, setIsClient] = useState(false); + // declare global variables 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 - // if loading show load screen - if(!report) return - // setup chart data - let data = report?.servicesNameAndSubscribers.value.map((v : { - _id: string, - name: string, - totalSubscribers: number, - } , i : number) => { - return v?.totalSubscribers; - }) - // setup chart labels - let labels = report?.servicesNameAndSubscribers.value.map((v : { - _id: string, - name: string, - totalSubscribers: number, - } , i : number) => { - return v?.name; - }) + const locale = cookies.get("NEXT_LOCALE"); + const isRtl = locale === 'ar'; + const isDark = themeType === 'dark'; + + // Set isClient to true after component mounts + useEffect(() => { + setIsClient(true); + }, []); + + // if loading or no report, show loading spinner + if (!report || !isClient) { + return ( +
+
+
+ ); + } + + // setup chart data with null checks + const data = report?.servicesNameAndSubscribers?.value?.map((v: { + _id: string; + name: string; + totalSubscribers: number; + }) => v?.totalSubscribers) || []; + + // setup chart labels with null checks + const labels = report?.servicesNameAndSubscribers?.value?.map((v: { + _id: string; + name: string; + totalSubscribers: number; + }) => v?.name) || []; + + // Return empty state if no data + if (data.length === 0 || labels.length === 0) { + return ( +
+

{t('noDataAvailable')}

+
+ ); + } + // setup chart options - var options = { + const options = { series: [{ name: t('subscription'), data: data diff --git a/webapp/src/components/dashboard/home/workersJobTypes.tsx b/webapp/src/components/dashboard/home/workersJobTypes.tsx index e810a8d..e1710b1 100644 --- a/webapp/src/components/dashboard/home/workersJobTypes.tsx +++ b/webapp/src/components/dashboard/home/workersJobTypes.tsx @@ -2,6 +2,7 @@ import { useAppSelector } from '@/redux/store'; import { useTranslations } from 'next-intl'; import dynamic from 'next/dynamic'; import Cookies from 'universal-cookie'; +import { useState, useEffect } from 'react'; const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false, }); @@ -9,34 +10,56 @@ const ReactApexChart = dynamic(() => import('react-apexcharts'), { export default function WorkersJobTypes() { // get needed redux state - const report = useAppSelector((state) => state.statisticsReducer.value.report) - const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType) + const report = useAppSelector((state) => state.statisticsReducer.value.report); + const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType); + const [isClient, setIsClient] = useState(false); + // declare global variables 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 - // if loading show load screen - if(!report) return - // prepare chart data - let data = report?.workersNameAndJobType.value.map((v : { - _id: string, - jobType: string, - count: number, - } , i : number) => { - return v?.count; - }) - // prepare chart labels - let labels = report?.workersNameAndJobType.value.map((v : { - _id: string, - jobType: string, - count: number, - } , i : number) => { - return v?.jobType; - }) + const locale = cookies.get("NEXT_LOCALE"); + const isRtl = locale === 'ar'; + const isDark = themeType === 'dark'; + + // Set isClient to true after component mounts + useEffect(() => { + setIsClient(true); + }, []); + + // if loading or no report, show loading spinner + if (!report || !isClient) { + return ( +
+
+
+ ); + } + + // prepare chart data with null checks + const data = report?.workersNameAndJobType?.value?.map((v: { + _id: string; + jobType: string; + count: number; + }) => v?.count) || []; + + // prepare chart labels with null checks + const labels = report?.workersNameAndJobType?.value?.map((v: { + _id: string; + jobType: string; + count: number; + }) => v?.jobType) || []; + + // Return empty state if no data + if (data.length === 0 || labels.length === 0) { + return ( +
+

{t('noDataAvailable')}

+
+ ); + } + // prepare chart options - var options = { + const options = { series: [{ name: t('worker'), data: data