Skip to content

Commit

Permalink
Merge pull request #19 from mayukh551/stats-page
Browse files Browse the repository at this point in the history
added designs of monthly and yearly categorywise expense doughnut charts
  • Loading branch information
mayukh551 authored Oct 1, 2023
2 parents 16eb210 + 5d76b61 commit 5973856
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 10 deletions.
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"axios": "^1.2.6",
"chart.js": "^4.1.2",
"chart.js": "^4.4.0",
"dotenv": "^16.0.3",
"framer-motion": "^10.16.4",
"react": "^18.2.0",
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Profile from "./Components/Profile/Profile";
import Account from "./Components/Account/Account";
import UserDetails from "./Components/Auth/UserDetails";
import ProductPage from "./Components/Home/Home";
import YearlyCategoryExpenseChart from "./Components/Profile/Chart/MonthlyExpensePieChart";

function App() {
return (
Expand All @@ -23,6 +24,7 @@ function App() {
<Route path="expenses" element={<Home />} />
<Route path="profile" element={<Profile />} />
<Route path="account" element={<Account />} />
<Route path="statistics" element={<YearlyCategoryExpenseChart/>} />
</Routes >
</BrowserRouter >

Expand Down
115 changes: 115 additions & 0 deletions src/Components/Profile/Chart/CategoryPieChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useEffect, useState } from 'react'
import '../Profile.css'

import { Chart as ChartJS, CategoryScale, ArcElement, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from "chart.js";
import SelectBtn from '../../UI/SelectBtn';
import { SelectChangeEvent } from '@mui/material/Select';
import ChartSpinner from '../../UI/Spinners/ChartSpinner';
import { Doughnut } from 'react-chartjs-2';

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, ArcElement);


const options = {
responsive: true,
plugins: {
legend: {
position: "top" as const
}
}
};


function CategoryPieChart() {

const [expenseData, setExpenseData] = useState<number[]>([40, 24, 12]);
const year: string = String(new Date().getFullYear());
const [chartYear, setChartYear] = useState<string>(localStorage.getItem('year')!);
const [labels, setLabels] = useState<string[]>([]);

var yearList: string[] = [];

const [isLoading, setIsLoading] = useState<boolean>(true);

const currentYear = parseInt(year);
for (let year = currentYear; year >= 2019; year--) {
yearList.push(String(year));
}
// console.log(expenseData)

const data = {
labels: labels,
datasets: [{
label: 'Expenses',
data: expenseData,
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)',
'rgb(75, 192, 192)'
],
hoverOffset: 4
}]
};

console.log(data);

const selectEventHandler = (event: SelectChangeEvent<string>) => {
setChartYear(event.target.value);
setIsLoading(true);
};

useEffect(() => {
async function fetchYearAnalytics() {
// console.log(isLoading)

console.log('fetching category pie chart data');

const response = await fetch(
`${process.env.REACT_APP_SERVER_URL}/profile/pie-chart/category/${localStorage.getItem('userId')}?year=${chartYear}`, {
headers: {
'x-access-token': `${localStorage.getItem('token')}`
}
});
const { data, labels } = await response.json();
console.log(data, labels);
setIsLoading(false);
return { data, labels };
}


fetchYearAnalytics()
.then((data) => {
if (data.data != null) {
setExpenseData([...data.data])
setLabels([...data.labels])
}
else {
setExpenseData([]);
setLabels([]);
}
})
}, [chartYear]);

return (
<div>
<div className="chart-wrapper">
<div className="chart" style={{ width: '370px', margin: 'auto', marginTop: '20px' }}>
<SelectBtn
options={yearList}
val={chartYear}
selectEventHandler={selectEventHandler}
style={{ backgroundColor: 'white', width: '100px', height: '30px', marginBottom: '10px' }}
/>
{isLoading && <ChartSpinner />}
{!isLoading && expenseData!.length === 0 && <h4 className='mt-8 mb-4 font-medium text-lg'>You have no expenses for {chartYear}</h4>}

{!isLoading && expenseData!.length > 0 && <Doughnut options={options} data={data} />}
</div>
<h4 className='mt-4 text-base font-bold px-4 py-2 rounded-md shadow-md w-fit mx-auto'>Category Based Expenses</h4>
</div>
</div>
)
}

export default CategoryPieChart;
123 changes: 123 additions & 0 deletions src/Components/Profile/Chart/MonthlyExpensePieChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useEffect, useState } from 'react'
import '../Profile.css'

import { Chart as ChartJS, CategoryScale, ArcElement, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from "chart.js";
import SelectBtn from '../../UI/SelectBtn';
import { SelectChangeEvent } from '@mui/material/Select';
import ChartSpinner from '../../UI/Spinners/ChartSpinner';
import { Doughnut } from 'react-chartjs-2';

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, ArcElement);


const options = {
responsive: true,
plugins: {
legend: {
position: "top" as const
}
}
};

const monthList = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// bacground colors for 12 months
const backgroundColors = [
'rgb(255, 99, 132)', 'rgb(255, 159, 64)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)',
'rgb(54, 162, 235)', 'rgb(153, 102, 255)', 'rgb(201, 203, 207)', 'rgb(255, 99, 132)',
'rgb(255, 159, 64)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)', 'rgb(54, 162, 235)'
];

function MonthlyExpensePieChart() {

const [expenseData, setExpenseData] = useState<number[]>([]);
const year: string = String(new Date().getFullYear());
const [chartYear, setChartYear] = useState<string>(localStorage.getItem('year')!);

var yearList: string[] = [];

const [isLoading, setIsLoading] = useState<boolean>(true);

const currentYear = parseInt(year);
for (let year = currentYear; year >= 2019; year--) {
yearList.push(String(year));
}
// console.log(expenseData)

const data = {
labels: monthList,
datasets: [{
label: 'Expense',
data: expenseData,
backgroundColor: backgroundColors,
hoverOffset: 4
}]
};

console.log(data);

const selectEventHandler = (event: SelectChangeEvent<string>) => {
setChartYear(event.target.value);
setIsLoading(true);
};

useEffect(() => {
async function fetchYearAnalytics() {
// console.log(isLoading)

console.log('fetching category pie chart data');

const response = await fetch(
`${process.env.REACT_APP_SERVER_URL}/profile/pie-chart/month/${localStorage.getItem('userId')}?year=${chartYear}`, {
headers: {
'x-access-token': `${localStorage.getItem('token')}`
}
});
const { data } = await response.json();
console.log(data);
setIsLoading(false);
return { data };
}


fetchYearAnalytics()
.then((data) => {

// check if data.data array does not contain 0 values for all 12 months
// if yes, then set expenseData to empty array
// else set expenseData to data.data array
console.log(data.data);
const isDataEmpty = data.data.every((value: number) => value === 0);

if (!isDataEmpty) {
setExpenseData([...data.data])
}
else {
setExpenseData([]);
}
})
}, [chartYear]);

console.log('For Monthly Expense Pie Chart', !isLoading && expenseData!.length > 0);

return (
<div>
<div className="chart-wrapper">
<div className="chart" style={{ width: '370px', margin: 'auto', marginTop: '20px' }}>
<SelectBtn
options={yearList}
val={chartYear}
selectEventHandler={selectEventHandler}
style={{ backgroundColor: 'white', width: '100px', height: '30px', marginBottom: '10px' }}
/>
{isLoading && <ChartSpinner />}
{!isLoading && expenseData!.length === 0 && <h4 className='mt-8 mb-4 font-medium text-lg'>You have no expenses for {chartYear}</h4>}

{!isLoading && expenseData!.length > 0 && <Doughnut options={options} data={data} />}
</div>
<h4 className='mt-4 text-base font-bold px-4 py-2 rounded-md shadow-md w-fit mx-auto'>Monthly Based Expenses</h4>
</div>
</div>
)
}

export default MonthlyExpensePieChart;
1 change: 0 additions & 1 deletion src/Components/Profile/Chart/YearExpenseChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement
import { Line } from "react-chartjs-2";
import SelectBtn from '../../UI/SelectBtn';
import { SelectChangeEvent } from '@mui/material/Select';
import Modal from '../../UI/Modal';
import ChartSpinner from '../../UI/Spinners/ChartSpinner';

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
Expand Down
6 changes: 6 additions & 0 deletions src/Components/Profile/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Analytics from './Analytics'
import Nav from '../Navbar/Nav'
import YearExpenseChart from './Chart/YearExpenseChart';
import MonthExpenseChart from './Chart/MonthExpenseChart';
import MonthlyExpensePieChart from './Chart/MonthlyExpensePieChart';
import CategoryPieChart from './Chart/CategoryPieChart';

const Profile: React.FC = () => {

Expand All @@ -13,6 +15,10 @@ const Profile: React.FC = () => {
<Nav hasProfile={hasVisitedProfile} />
<YearExpenseChart />
<MonthExpenseChart />
<div className='flex flex-row space-x-5 justify-center items-center my-10'>
<CategoryPieChart />
<MonthlyExpensePieChart />
</div>
<Analytics />
</div>
)
Expand Down

1 comment on commit 5973856

@vercel
Copy link

@vercel vercel bot commented on 5973856 Oct 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.