UI updation in Expense Breakdown #471
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import Chart from "react-apexcharts";
|
||||
import { useExpenseAnalysis } from "../../hooks/useDashboard_Data";
|
||||
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||
@ -10,36 +10,27 @@ const ExpenseAnalysis = () => {
|
||||
const projectId = useSelectedProject();
|
||||
|
||||
const methods = useForm({
|
||||
defaultValues: {
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
},
|
||||
defaultValues: { startDate: "", endDate: "" },
|
||||
});
|
||||
|
||||
const { watch } = methods;
|
||||
|
||||
|
||||
const [startDate, endDate] = watch(["startDate", "endDate"]);
|
||||
|
||||
const { data, isLoading, isError, error, isFetching } = useExpenseAnalysis(
|
||||
projectId,
|
||||
startDate ? localToUtc(startDate) : null,
|
||||
endDate ? localToUtc(endDate) : null
|
||||
projectId,
|
||||
startDate ? localToUtc(startDate) : null,
|
||||
endDate ? localToUtc(endDate) : null
|
||||
);
|
||||
|
||||
if (isError) return <div>{error.message}</div>;
|
||||
|
||||
|
||||
|
||||
|
||||
const report = data?.report ?? [];
|
||||
|
||||
const { labels, series, total } = useMemo(() => {
|
||||
const labels = report.map((item) => item.projectName);
|
||||
const series = report.map((item) => item.totalApprovedAmount || 0);
|
||||
const total = formatCurrency(data?.totalAmount || 0);
|
||||
|
||||
return { labels, series, total };
|
||||
}, [report, data?.totalAmount]);
|
||||
const { labels, series, total } = useMemo(() => {
|
||||
const labels = report.map((item) => item.projectName);
|
||||
const series = report.map((item) => item.totalApprovedAmount || 0);
|
||||
const total = formatCurrency(data?.totalAmount || 0);
|
||||
return { labels, series, total };
|
||||
}, [report, data?.totalAmount]);
|
||||
|
||||
const donutOptions = {
|
||||
chart: { type: "donut" },
|
||||
@ -63,26 +54,34 @@ const { labels, series, total } = useMemo(() => {
|
||||
},
|
||||
},
|
||||
},
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 576, // mobile breakpoint
|
||||
options: {
|
||||
chart: { width: "100%" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="card-header d-flex justify-content-between align-items-center ">
|
||||
<div>
|
||||
<h5 className="mb-1 card-title text-start">Expense Breakdown</h5>
|
||||
<p className="card-subtitle">Category Wise Expense Breakdown</p>
|
||||
{/* Header */}
|
||||
<div className="card-header d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2">
|
||||
<div className="text-start w-100">
|
||||
<h5 className="mb-1 card-title">Expense Breakdown</h5>
|
||||
<p className="card-subtitle mb-0">Category Wise Expense Breakdown</p>
|
||||
</div>
|
||||
|
||||
<div className="text-end">
|
||||
<div className="text-start text-sm-end w-75">
|
||||
<FormProvider {...methods}>
|
||||
<DateRangePicker1 />
|
||||
</FormProvider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Card body */}
|
||||
<div className="card-body position-relative">
|
||||
{/* Initial loading: show full loader */}
|
||||
{isLoading && (
|
||||
<div
|
||||
className="d-flex justify-content-center align-items-center"
|
||||
@ -92,14 +91,12 @@ const { labels, series, total } = useMemo(() => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Data display */}
|
||||
{!isLoading && report.length === 0 && (
|
||||
<div className="text-center py-5 text-muted ">No data found</div>
|
||||
<div className="text-center py-5 text-muted">No data found</div>
|
||||
)}
|
||||
|
||||
{!isLoading && report.length > 0 && (
|
||||
<>
|
||||
{/* Overlay spinner for refetch */}
|
||||
{isFetching && (
|
||||
<div className="position-absolute top-0 start-0 w-100 h-100 d-flex justify-content-center align-items-center bg-white bg-opacity-75">
|
||||
<span>Loading...</span>
|
||||
@ -109,17 +106,18 @@ const { labels, series, total } = useMemo(() => {
|
||||
<div className="d-flex justify-content-center mb-3">
|
||||
<Chart
|
||||
options={donutOptions}
|
||||
series={report.map((item) => item.totalApprovedAmount || 0)}
|
||||
series={series}
|
||||
type="donut"
|
||||
width="320"
|
||||
width="100%"
|
||||
height={320}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2 w-100">
|
||||
<div className="row">
|
||||
<div className="row g-2">
|
||||
{report.map((item, idx) => (
|
||||
<div
|
||||
className="col-6 d-flex justify-content-start align-items-start mb-2"
|
||||
className="col-12 col-sm-6 d-flex align-items-start"
|
||||
key={idx}
|
||||
>
|
||||
<div className="avatar me-2">
|
||||
@ -127,16 +125,14 @@ const { labels, series, total } = useMemo(() => {
|
||||
className="avatar-initial rounded-2"
|
||||
style={{
|
||||
backgroundColor:
|
||||
donutOptions.colors[
|
||||
idx % donutOptions.colors.length
|
||||
],
|
||||
donutOptions.colors[idx % donutOptions.colors.length],
|
||||
}}
|
||||
>
|
||||
<i className="bx bx-receipt fs-4"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div className="d-flex flex-column gap-1 text-start">
|
||||
<small className="fw-semibold ">{item.projectName}</small>
|
||||
<small className="fw-semibold">{item.projectName}</small>
|
||||
<span className="fw-semibold text-muted ms-1">
|
||||
{formatCurrency(item.totalApprovedAmount)}
|
||||
</span>
|
||||
|
Loading…
x
Reference in New Issue
Block a user