Compare commits

...

2 Commits

Author SHA1 Message Date
c8828e7e5f Add 30 n1234567 2025-06-21 04:53:43 +03:00
489474e9d7 Add 30 n123456 2025-06-21 04:46:37 +03:00
3 changed files with 100 additions and 51 deletions

View File

@ -11,7 +11,7 @@ export default function IncomeOutcome()
{
// get needed redux state
const report = useAppSelector((state) => state.statisticsReducer.value.report);
const currencySymbol = useAppSelector((state) => state.settingsReducer.value.appGeneralSettings.currencySymbol || '$');
const settings = useAppSelector((state) => state.settingsReducer.value);
const themeType = useAppSelector((state) => state.themeTypeReducer.value.themeType);
const [isClient, setIsClient] = useState(false);
@ -27,8 +27,8 @@ export default function IncomeOutcome()
setIsClient(true);
}, []);
// if loading or no report, don't render the chart
if (!report || !isClient) {
// if loading or no report or settings not loaded, show loading spinner
if (!report || !isClient || !settings?.appGeneralSettings) {
return (
<div className="w-full h-[350px] flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-gray-900 dark:border-gray-100"></div>
@ -36,6 +36,9 @@ export default function IncomeOutcome()
);
}
// Get currency symbol with fallback to '$' if not available
const currencySymbol = settings.appGeneralSettings.currencySymbol || '$';
// prepare chart data
const data = [report?.totalIncome || 0, report?.totalOutcome || 0];
// prepare chart labels

View File

@ -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 (
<div className="w-full h-[350px] flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-gray-900 dark:border-gray-100"></div>
</div>
);
}
// 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 (
<div className="w-full h-[350px] flex items-center justify-center">
<p>{t('noDataAvailable')}</p>
</div>
);
}
// setup chart options
var options = {
const options = {
series: [{
name: t('subscription'),
data: data

View File

@ -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 (
<div className="w-full h-[350px] flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-gray-900 dark:border-gray-100"></div>
</div>
);
}
// 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 (
<div className="w-full h-[350px] flex items-center justify-center">
<p>{t('noDataAvailable')}</p>
</div>
);
}
// prepare chart options
var options = {
const options = {
series: [{
name: t('worker'),
data: data