Files
revenue-fe/src/pages/dashboards/home/DashboardHomePage.tsx
wayanrivan 0ef5573e8a update
2025-05-23 13:02:08 +07:00

409 lines
14 KiB
TypeScript

import { Container, KeenIcon, DefaultTooltip } from '@/components';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from '@/components/ui/select';
import { DateRange } from 'react-day-picker';
import { useState, useEffect, useCallback } from 'react';
import { Card, Chart, YearPicker } from './blocks';
import moment from 'moment';
import { useFetchCardData, useFetchChartData } from './hooks';
import { Button } from '@/components/ui/button';
import { useFetchYear } from './hooks/useFetchYear';
import { get5LastYear } from '@/utils/Date';
import { staticChartData } from './staticChart';
import { Helmet } from 'react-helmet';
import BalanceCard from './blocks/BalanceCard';
import { getAuth } from '@/auth';
import { useCallApi } from '@/hooks';
import { apiConfig } from '@/config/api.config';
import TransactionValue from './blocks/TransactionValue';
import TransactionPieChart from './blocks/TransactionPieChart';
import MemberActivity from './blocks/MemberActivity';
import BankSaldo from './blocks/BankSaldo';
// sum -> nominal, count-> total
type CountType = 'sum' | 'count';
type ChartType = 'line' | 'bar';
type ChartLegend = 'true' | 'false';
const DashboardHomePage = () => {
const selectYear = get5LastYear();
const [initialYear, setInitialYear] = useState<string>('');
const [selectedYear, setSelectedYear] = useState<string>('');
const [count, setCount] = useState<CountType>('sum');
const [chartType, setChartType] = useState<ChartType>('line');
const [chartLegend, setChartLegend] = useState<ChartLegend>('true');
const [dateRange, setDateRange] = useState<{ from: Date; to: Date }>({
from: new Date(),
to: new Date()
});
const getFirstDayOfMonth = () => {
const now = new Date();
return new Date(now.getFullYear(), now.getMonth(), 1);
};
const getToday = () => {
return new Date();
};
const [fromDate, setFromDate] = useState(getFirstDayOfMonth());
const [toDate, setToDate] = useState(getToday());
const API_URL = apiConfig.api_dashboard;
const { GetData } = useCallApi();
const API_URL_BANK = apiConfig.service_wallet;
const [responseStatisticCard, setResponseStatisticCard] = useState<any>(null);
const fetchData = async () => {
const res = await GetData(`${API_URL}/card-statistic`, {});
setResponseStatisticCard(res);
};
const [bankaccount, setbankaccount] = useState<any>(null);
const fetchDataBankAccount = async () => {
const res = await GetData(`${API_URL_BANK}/dashboard/balance/account/${getAuth()?.user?.customer?.id}`, {});
setbankaccount(res);
};
useEffect(() => {
fetchData();
}, []);
useEffect(() => {
fetchDataBankAccount();
}, []);
const [responseGraphic, setresponseGraphic] = useState<any>(null);
useEffect(() => {
const fetchDataGraphic = async () => {
const res = await GetData(`${API_URL}/cashin-vs-cashout`, {
date_from: fromDate.toISOString(),
date_to: toDate.toISOString()
});
setresponseGraphic(res);
};
fetchDataGraphic();
}, [fromDate, toDate]);
let staticChartDataApiFetch = [];
// Make map for date => { cashin: 0, cashout: 0 }
const dataMap: Record<string, { cashin: number; cashout: number }> = {};
const current = moment(fromDate);
const end = moment(toDate);
// Inisialization dataMap with all dates
while (current.isSameOrBefore(end, 'day')) {
const dateStr = current.format('DD-MM-YYYY');
dataMap[dateStr] = { cashin: 0, cashout: 0 };
current.add(1, 'day');
}
// Add cashin
if (Array.isArray(responseGraphic?.data.total_cashin)) {
responseGraphic.data.total_cashin.forEach((item: any) => {
const date = moment(item.created_date).format('DD-MM-YYYY');
// Only update cashin if it's not already set (meaning no value was added before)
if (dataMap[date]) {
dataMap[date].cashin = Number(item.total_count ?? 0);
}
});
}
// Add cashout
if (Array.isArray(responseGraphic?.data.total_cashout)) {
responseGraphic.data.total_cashout.forEach((item: any) => {
const date = moment(item.created_date).format('DD-MM-YYYY');
// Only update cashout if it's not already set (meaning no value was added before)
if (dataMap[date]) {
dataMap[date].cashout = Number(item.total_count ?? 0);
}
});
}
// Change to array for chart
staticChartDataApiFetch = Object.entries(dataMap).map(([month, values]) => ({
month,
cashin: values.cashin,
cashout: values.cashout
}));
// Change to array for chart
staticChartDataApiFetch = Object.entries(dataMap).map(([month, values]) => ({
month,
cashin: values.cashin,
cashout: values.cashout
}));
const currentRole = getAuth()?.role_name;
const idCustomer = getAuth()?.user.customer?.id;
// console.log(currentRole);
// Menyusun tanggal awal dan akhir berdasarkan selectedYear
useEffect(() => {
if (selectYear.length > 0 && !selectedYear) {
let latestYear = Math.max(...selectYear.map((item) => parseInt(item, 10))).toString();
// console.log('latestYear :', latestYear);
setSelectedYear(latestYear);
setInitialYear(latestYear);
}
}, [selectYear, selectedYear]);
useEffect(() => {
if (selectedYear) {
setDateRange({
from: moment(`${selectedYear}-01-01`, 'YYYY-MM-DD').toDate(),
to: moment(`${selectedYear}-12-31`, 'YYYY-MM-DD').toDate()
});
}
}, [selectedYear]);
useEffect(() => {
if (initialYear) {
setDateRange({
from: moment(`${initialYear}-01-01`, 'YYYY-MM-DD').toDate(),
to: moment(`${initialYear}-12-31`, 'YYYY-MM-DD').toDate()
});
}
}, [initialYear]);
const handleYearChange = (year: string) => {
setSelectedYear(year);
};
const handleCountType = (value: CountType) => {
setCount(value);
};
const handleChartType = (value: ChartType) => {
setChartType(value);
};
const handleChartLegend = (value: ChartLegend) => {
setChartLegend(value);
};
const resetFilter = useCallback(() => {
const firstDay = getFirstDayOfMonth();
const today = getToday();
setFromDate(firstDay);
setToDate(today);
// reset filter yang lain kalau perlu
setDateRange({ from: firstDay, to: today });
setSelectedYear(initialYear);
setCount('sum');
setChartType('line');
setChartLegend('true');
}, [initialYear]);
const { cardData } = useFetchCardData(
moment(dateRange.from).format('YYYY-MM-DD'),
moment(dateRange.to).format('YYYY-MM-DD'),
count
);
const { chartData } = useFetchChartData(
moment(dateRange.from).format('YYYY-MM-DD'),
moment(dateRange.to).format('YYYY-MM-DD'),
count
);
const toolbar = (
<div className="flex gap-3 items-center w-1/2">
<div className="w-auto min-w-[120px]">
<Select value={chartType} onValueChange={handleChartType}>
<SelectTrigger size="sm">
<SelectValue placeholder="Select Chart Type" />
</SelectTrigger>
<SelectContent className="w-32">
<SelectItem value="line">Line</SelectItem>
<SelectItem value="bar">Bar</SelectItem>
</SelectContent>
</Select>
</div>
<div className="w-auto min-w-[120px]">
<Select value={chartLegend} onValueChange={handleChartLegend}>
<SelectTrigger size="sm">
<SelectValue placeholder="Select Legend Visibility" />
</SelectTrigger>
<SelectContent className="w-full">
<SelectItem value="true">Show Legend</SelectItem>
<SelectItem value="false">Hide Legend</SelectItem>
</SelectContent>
</Select>
</div>
</div>
);
const number: number = responseStatisticCard?.data.total_cash_in ?? 0;
const formattedNumber: number = parseFloat(number.toFixed(2));
const numbercashout: number = responseStatisticCard?.data.total_cash_out ?? 0;
const formattedNumbercashout: number = parseFloat(numbercashout.toFixed(2));
return (
<>
<Helmet>
<title>TPAY | Dashboard</title>
</Helmet>
<Container>
{/* Account Balance Cards */}
{/* {currentRole === 'Escrow' || currentRole === 'Master Agent' ? (
<div className="grid gap-5 lg:gap-7.5 mb-14 mt-7">
<BalanceCard id={idCustomer} />
</div>
) : null} */}
<div className="flex space-x-4 mt-5">
{bankaccount?.data && bankaccount?.data.length > 0
&& getAuth()?.statusbalance=='Y'
? (
bankaccount?.data.map((bankaccountdatas: { id_balance:string,amount: string, credit_limit: string, monthly_limit: string; wallet: string; }, index: number) => (
<BankSaldo
title={bankaccountdatas.wallet}
balance={bankaccountdatas.amount}
creditLimit={bankaccountdatas.credit_limit}
monthlyLimit={bankaccountdatas.monthly_limit}
idbalance={bankaccountdatas.id_balance}
/>
))
) : (
""
)}
</div>
{/* Cards */}
<div className="flex gap-6 overflow-x-auto pb-2 mt-5">
<Card
title="Registered Users"
total={responseStatisticCard?.data.total_registered ?? 0}
growth={parseFloat((responseStatisticCard?.data?.registered_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.registered_last_week.surplus ?? false}
icon="test"
/>
<Card
title="Unregistered Users"
total={responseStatisticCard?.data.total_unregistered ?? 0}
growth={parseFloat((responseStatisticCard?.data?.unregistered_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.unregistered_last_week.surplus ?? false}
icon="test"
/>
<Card
title="Total Cash-in"
total={formattedNumber.toFixed(2)} // now a number: 972.80
growth={parseFloat((responseStatisticCard?.data?.cash_in_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.cash_in_last_week.surplus ?? false}
icon="test"
/>
<Card
title="Total Cash-out"
total={formattedNumbercashout.toFixed(2)} // now a number: 972.80
growth={parseFloat((responseStatisticCard?.data?.cash_out_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.cash_out_last_week.surplus ?? false}
icon="test"
/>
<Card
title="Active Event"
total={responseStatisticCard?.data.total_event ?? 0}
growth={parseFloat((responseStatisticCard?.data?.event_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.event_last_week.surplus ?? false}
icon="test"
/>
<Card
title="Total Billing"
total={responseStatisticCard?.data.total_billing ?? 0}
growth={parseFloat((responseStatisticCard?.data?.billing_last_week.percent ?? 0).toFixed(2)) ?? 0}
surplus={responseStatisticCard?.data.billing_last_week.surplus ?? false}
icon='test'
/>
</div>
<div className="flex gap-3 items-center mb-6 mt-6">
<div className="flex gap-3 items-center w-full md:w-auto">
<label className="input input-sm w-[160px]">
From
<input
type="date"
name="from"
value={moment(fromDate).format('YYYY-MM-DD')}
onChange={(e) => {
if (e.target.value) {
setFromDate(new Date(e.target.value));
} else {
// Reset to default value (e.g. first day of current month)
setFromDate(getFirstDayOfMonth());
}
}}
/>
</label>
<label className="input input-sm w-[160px]">
To
<input
type="date"
name="to"
value={moment(toDate).format('YYYY-MM-DD')}
onChange={(e) => {
if (e.target.value) {
setToDate(new Date(e.target.value));
} else {
// Reset to default value (e.g. today)
setToDate(getToday());
}
}}
/>
</label>
</div>
<DefaultTooltip title="Reset Filter" placement="top">
<Button variant="outline" className="h-7.5" onClick={resetFilter}>
<KeenIcon icon="arrow-circle-left" />
</Button>
</DefaultTooltip>
</div>
{/* Chart */}
<div className="grid gap-5 lg:gap-7.5 mt-5">
<div className="grid lg:grid-cols-1 gap-y-5 lg:gap-5 items-stretch">
<div className="lg:col-span-1">
<Chart
title="Overview"
count={12}
toolbar={toolbar}
chartData={staticChartDataApiFetch}
chartType={chartType}
chartLegend={chartLegend}
/>
</div>
</div>
</div>
<div className="flex space-x-4 mt-5">
<TransactionValue startdate={fromDate.toISOString()} enddate={toDate.toISOString()} />
<TransactionPieChart startdate={fromDate.toISOString()} enddate={toDate.toISOString()} />
<MemberActivity startdate={fromDate.toISOString()} enddate={toDate.toISOString()} />
</div>
</Container>
</>
);
};
export default DashboardHomePage;