Adding API for ExpenseProjects.
This commit is contained in:
parent
b5084ad99d
commit
2397be3b8c
@ -1,111 +1,87 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Chart from "react-apexcharts";
|
||||
import { useExpenseType } from "../../hooks/masterHook/useMaster";
|
||||
import { useSelectedProject } from "../../slices/apiDataManager";
|
||||
import { useExpenseDataByProject } from "../../hooks/useDashboard_Data";
|
||||
|
||||
const ExpenseByProject = () => {
|
||||
const projectId = useSelectedProject();
|
||||
const [range, setRange] = useState("12M");
|
||||
const [selectedType, setSelectedType] = useState("");
|
||||
const [chartData, setChartData] = useState({ categories: [], data: [] });
|
||||
|
||||
// Dummy data grouped by year
|
||||
const expenseData = {
|
||||
"6M": {
|
||||
categories: [
|
||||
{ quarter: "Q1" },
|
||||
{ quarter: "Q2" },
|
||||
{ quarter: "Q3" },
|
||||
{ quarter: "Q4" },
|
||||
],
|
||||
data: [400, 430, 448, 470]
|
||||
},
|
||||
"12M": {
|
||||
categories: [
|
||||
{ quarter: "Q1" },
|
||||
{ quarter: "Q2" },
|
||||
{ quarter: "Q3" },
|
||||
{ quarter: "Q4" },
|
||||
{ quarter: "Q1" },
|
||||
{ quarter: "Q2" },
|
||||
{ quarter: "Q3" },
|
||||
{ quarter: "Q4" },
|
||||
],
|
||||
data: [400, 430, 448, 470, 540, 580, 690, 690]
|
||||
},
|
||||
All: {
|
||||
categories: [
|
||||
{ quarter: "Q1" },
|
||||
{ quarter: "Q2" },
|
||||
{ quarter: "Q3" },
|
||||
{ quarter: "Q4" },
|
||||
{ quarter: "Q1" },
|
||||
{ quarter: "Q2" },
|
||||
{ quarter: "Q3" },
|
||||
{ quarter: "Q4" },
|
||||
],
|
||||
data: [300, 350, 370, 390, 420, 460, 500, 530]
|
||||
const { ExpenseTypes, loading: typeLoading } = useExpenseType();
|
||||
|
||||
// Fetch API data
|
||||
const { data: expenseApiData, isLoading } = useExpenseDataByProject(
|
||||
projectId,
|
||||
selectedType,
|
||||
range === "All" ? null : parseInt(range)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (expenseApiData) {
|
||||
const categories = expenseApiData.map(
|
||||
(item) => `${item.monthName} ${item.year}`
|
||||
);
|
||||
const data = expenseApiData.map((item) => item.total);
|
||||
|
||||
setChartData({ categories, data });
|
||||
} else {
|
||||
setChartData({ categories: [], data: [] });
|
||||
}
|
||||
};
|
||||
}, [expenseApiData]);
|
||||
|
||||
const options = {
|
||||
chart: { type: "bar", toolbar: { show: false } },
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
columnWidth: "55%",
|
||||
borderRadius: 4
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: (val) => val
|
||||
},
|
||||
xaxis: {
|
||||
categories: expenseData[range].categories.map(c => `${c.quarter}`),
|
||||
labels: {
|
||||
style: { fontSize: "12px" },
|
||||
rotate: -45
|
||||
},
|
||||
group: {
|
||||
groups: [
|
||||
{
|
||||
title: "2022",
|
||||
cols: 4
|
||||
},
|
||||
{
|
||||
title: "2023",
|
||||
cols: 4
|
||||
},
|
||||
{
|
||||
title: "2024",
|
||||
cols: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
title: { text: "Expense" }
|
||||
},
|
||||
plotOptions: { bar: { horizontal: false, columnWidth: "55%", borderRadius: 4 } },
|
||||
dataLabels: { enabled: true, formatter: (val) => val },
|
||||
xaxis: { categories: chartData.categories, labels: { style: { fontSize: "12px" }, rotate: -45 } },
|
||||
fill: { opacity: 1 },
|
||||
colors: ["#2196f3"]
|
||||
};
|
||||
|
||||
const series = [
|
||||
{
|
||||
name: "Expense",
|
||||
data: expenseData[range].data
|
||||
name: selectedType || "Expense",
|
||||
data: chartData.data
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="card shadow-sm p-3 text-white" >
|
||||
<div className="card-header d-flex justify-content-between align-items-center" >
|
||||
<div>
|
||||
<h5 className="mb-1 fw-bold">Expense Breakdown</h5>
|
||||
<p className="card-subtitle me-3">Detailed project expenses</p>
|
||||
<div className="card shadow-sm ">
|
||||
{/* Header */}
|
||||
<div className="card-header">
|
||||
<div className="d-flex justify-content-between align-items-center mb-3 mt-3">
|
||||
<div>
|
||||
<h5 className="mb-1 fw-bold">Expense Breakdown</h5>
|
||||
<p className="card-subtitle me-3 mb-0">Detailed project expenses</p>
|
||||
</div>
|
||||
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
{/* Expense Type Dropdown */}
|
||||
<select
|
||||
className="form-select form-select-sm mb-2"
|
||||
value={selectedType}
|
||||
onChange={(e) => setSelectedType(e.target.value)}
|
||||
disabled={typeLoading}
|
||||
>
|
||||
<option value="">All Types</option>
|
||||
{ExpenseTypes.map((type) => (
|
||||
<option key={type.id} value={type.id}>
|
||||
{type.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
{/* Range Buttons */}
|
||||
<div className="d-flex gap-2">
|
||||
{["6M", "12M", "All"].map((item) => (
|
||||
<button
|
||||
key={item}
|
||||
className={`btn btn-sm mx-1 ${range === item ? "btn-primary" : "btn-outline-light"
|
||||
}`}
|
||||
className={`btn btn-xs ${range === item ? "btn-primary" : "btn-outline-light"}`}
|
||||
onClick={() => setRange(item)}
|
||||
>
|
||||
{item}
|
||||
@ -113,11 +89,19 @@ const ExpenseByProject = () => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body bg-white text-dark">
|
||||
<Chart options={options} series={series} type="bar" height={400} />
|
||||
|
||||
{/* Chart */}
|
||||
<div className="card-body bg-white text-dark" style={{ minHeight: "440px" }}>
|
||||
{isLoading ? (
|
||||
<p>Loading chart...</p>
|
||||
) : (
|
||||
<Chart options={options} series={series} type="bar" height={400} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExpenseByProject;
|
||||
export default ExpenseByProject;
|
||||
|
||||
|
||||
|
@ -200,63 +200,63 @@ export const useDashboard_Data = ({ days, FromDate, projectId }) => {
|
||||
// })
|
||||
// }
|
||||
|
||||
export const useDashboard_AttendanceData = (date,projectId)=>{
|
||||
return useQuery({
|
||||
queryKey:["dashboardAttendances",date,projectId],
|
||||
queryFn:async()=> {
|
||||
|
||||
const resp = await await GlobalRepository.getDashboardAttendanceData(date, projectId)
|
||||
return resp.data;
|
||||
export const useDashboard_AttendanceData = (date, projectId) => {
|
||||
return useQuery({
|
||||
queryKey: ["dashboardAttendances", date, projectId],
|
||||
queryFn: async () => {
|
||||
|
||||
const resp = await await GlobalRepository.getDashboardAttendanceData(date, projectId)
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const useDashboardTeamsCardData =(projectId)=>{
|
||||
return useQuery({
|
||||
queryKey:["dashboardTeams",projectId],
|
||||
queryFn:async()=> {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardTeamsCardData(projectId)
|
||||
return resp.data;
|
||||
export const useDashboardTeamsCardData = (projectId) => {
|
||||
return useQuery({
|
||||
queryKey: ["dashboardTeams", projectId],
|
||||
queryFn: async () => {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardTeamsCardData(projectId)
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const useDashboardTasksCardData = (projectId) => {
|
||||
return useQuery({
|
||||
queryKey:["dashboardTasks",projectId],
|
||||
queryFn:async()=> {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardTasksCardData(projectId)
|
||||
return resp.data;
|
||||
return useQuery({
|
||||
queryKey: ["dashboardTasks", projectId],
|
||||
queryFn: async () => {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardTasksCardData(projectId)
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
export const useAttendanceOverviewData = (projectId, days) => {
|
||||
return useQuery({
|
||||
queryKey:["dashboardAttendanceOverView",projectId,days],
|
||||
queryFn:async()=> {
|
||||
|
||||
const resp = await GlobalRepository.getAttendanceOverview(projectId, days);
|
||||
return resp.data;
|
||||
return useQuery({
|
||||
queryKey: ["dashboardAttendanceOverView", projectId, days],
|
||||
queryFn: async () => {
|
||||
|
||||
const resp = await GlobalRepository.getAttendanceOverview(projectId, days);
|
||||
return resp.data;
|
||||
},
|
||||
enabled:!!projectId
|
||||
enabled: !!projectId
|
||||
})
|
||||
}
|
||||
|
||||
export const useDashboardProjectsCardData = () => {
|
||||
return useQuery({
|
||||
queryKey:["dashboardProjects"],
|
||||
queryFn:async()=> {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardProjectsCardData();
|
||||
return resp.data;
|
||||
return useQuery({
|
||||
queryKey: ["dashboardProjects"],
|
||||
queryFn: async () => {
|
||||
|
||||
const resp = await GlobalRepository.getDashboardProjectsCardData();
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const useExpenseAnalysis = (projectId, startDate, endDate) => {
|
||||
const hasBothDates = !!startDate && !!endDate;
|
||||
const hasBothDates = !!startDate && !!endDate;
|
||||
const noDatesSelected = !startDate && !endDate;
|
||||
|
||||
const shouldFetch =
|
||||
@ -266,8 +266,19 @@ export const useExpenseAnalysis = (projectId, startDate, endDate) => {
|
||||
queryKey: ["expenseAnalysis", projectId, startDate, endDate],
|
||||
queryFn: async () => {
|
||||
const resp = await GlobalRepository.getExpenseData(projectId, startDate, endDate);
|
||||
return resp.data;
|
||||
return resp.data;
|
||||
},
|
||||
enabled:shouldFetch
|
||||
enabled: shouldFetch
|
||||
});
|
||||
};
|
||||
|
||||
export const useExpenseDataByProject = (projectId, categoryId, months) => {
|
||||
return useQuery({
|
||||
queryKey: ["expenseByProject", projectId, categoryId, months],
|
||||
queryFn: async () => {
|
||||
const resp = await GlobalRepository.getExpenseDataByProject(projectId, categoryId, months);
|
||||
return resp.data;
|
||||
},
|
||||
|
||||
});
|
||||
};
|
@ -3,12 +3,12 @@ import { api } from "../utils/axiosClient";
|
||||
const GlobalRepository = {
|
||||
getDashboardProgressionData: ({ days = '', FromDate = '', projectId = '' }) => {
|
||||
let params;
|
||||
if(projectId == null){
|
||||
if (projectId == null) {
|
||||
params = new URLSearchParams({
|
||||
days: days.toString(),
|
||||
FromDate,
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
params = new URLSearchParams({
|
||||
days: days.toString(),
|
||||
FromDate,
|
||||
@ -19,35 +19,35 @@ const GlobalRepository = {
|
||||
return api.get(`/api/Dashboard/Progression?${params.toString()}`);
|
||||
},
|
||||
|
||||
getDashboardAttendanceData: ( date,projectId ) => {
|
||||
getDashboardAttendanceData: (date, projectId) => {
|
||||
|
||||
return api.get(`/api/Dashboard/project-attendance/${projectId}?date=${date}`);
|
||||
},
|
||||
return api.get(`/api/Dashboard/project-attendance/${projectId}?date=${date}`);
|
||||
},
|
||||
getDashboardProjectsCardData: () => {
|
||||
return api.get(`/api/Dashboard/projects`);
|
||||
},
|
||||
|
||||
|
||||
getDashboardTeamsCardData: (projectId) => {
|
||||
const url = projectId
|
||||
? `/api/Dashboard/teams?projectId=${projectId}`
|
||||
: `/api/Dashboard/teams`;
|
||||
return api.get(url);
|
||||
},
|
||||
const url = projectId
|
||||
? `/api/Dashboard/teams?projectId=${projectId}`
|
||||
: `/api/Dashboard/teams`;
|
||||
return api.get(url);
|
||||
},
|
||||
|
||||
getDashboardTasksCardData: (projectId) => {
|
||||
const url = projectId
|
||||
? `/api/Dashboard/tasks?projectId=${projectId}`
|
||||
: `/api/Dashboard/tasks`;
|
||||
return api.get(url);
|
||||
},
|
||||
const url = projectId
|
||||
? `/api/Dashboard/tasks?projectId=${projectId}`
|
||||
: `/api/Dashboard/tasks`;
|
||||
return api.get(url);
|
||||
},
|
||||
|
||||
getAttendanceOverview:(projectId,days)=>api.get(`/api/dashboard/attendance-overview/${projectId}?days=${days}`),
|
||||
getAttendanceOverview: (projectId, days) => api.get(`/api/dashboard/attendance-overview/${projectId}?days=${days}`),
|
||||
|
||||
|
||||
getExpenseData: (projectId, startDate, endDate) => {
|
||||
let url = `api/Dashboard/expense/type`
|
||||
|
||||
const queryParams = [];
|
||||
getExpenseData: (projectId, startDate, endDate) => {
|
||||
let url = `api/Dashboard/expense/type`
|
||||
|
||||
const queryParams = [];
|
||||
|
||||
if (projectId) {
|
||||
queryParams.push(`projectId=${projectId}`);
|
||||
@ -56,7 +56,7 @@ const GlobalRepository = {
|
||||
if (startDate) {
|
||||
queryParams.push(`startDate=${startDate}`);
|
||||
}
|
||||
if (endDate) {
|
||||
if (endDate) {
|
||||
queryParams.push(`endDate=${endDate}`);
|
||||
}
|
||||
|
||||
@ -64,7 +64,31 @@ const GlobalRepository = {
|
||||
url += `?${queryParams.join("&")}`;
|
||||
}
|
||||
|
||||
return api.get(url );
|
||||
return api.get(url);
|
||||
},
|
||||
|
||||
|
||||
getExpenseDataByProject: (projectId, categoryId, months) => {
|
||||
let url = `api/Dashboard/expense/monthly`
|
||||
|
||||
const queryParams = [];
|
||||
|
||||
if (projectId) {
|
||||
queryParams.push(`projectId=${projectId}`);
|
||||
}
|
||||
|
||||
if (categoryId) {
|
||||
queryParams.push(`categoryId=${categoryId}`);
|
||||
}
|
||||
if (months) {
|
||||
queryParams.push(`months=${months}`);
|
||||
}
|
||||
|
||||
if (queryParams.length > 0) {
|
||||
url += `?${queryParams.join("&")}`;
|
||||
}
|
||||
|
||||
return api.get(url);
|
||||
},
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user