Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 34 additions & 48 deletions components/FinancialSummary/BarChartComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,24 @@ import ExpensesCard from './ExpensesCard';
* @description BarChartComponent component displays a bar chart for expense analysis.
*/
export default function BarChartComponent() {
// Setting up state variables using useState hook
const [selectedCategory, setSelectedCategory] = useState<string>('All Categories');
const [selectedMonth, setSelectedMonth] = useState<string>('All Months');
const [windowWidth, setWindowWidth] = useState<number>(0);
const [isMounted, setIsMounted] = useState(false);

// Extracting unique categories and months from the data
const categories: string[] = getUniqueCategories();
const months: string[] = Object.keys(ExpensesData);

// Effect hook to update windowWidth state on resize
useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
};

// Initial setup and event listener
handleResize();
window.addEventListener('resize', handleResize);

// Cleanup function to remove event listener
return () => {
window.removeEventListener('resize', handleResize);
};
setIsMounted(true);
}, []);

// Filtering data based on selected month and category
const categories: string[] = getUniqueCategories();
const months: string[] = Object.keys(ExpensesData);

const filteredData: ExpenseItem[] = Object.entries(ExpensesData).flatMap(([month, entries]) =>
selectedMonth === 'All Months' || selectedMonth === month
? entries.filter((entry) => selectedCategory === 'All Categories' || entry.Category === selectedCategory)
: []
);

// Calculating total amount of filtered data
const totalAmount: number = filteredData.reduce((total, entry) => total + parseFloat(entry.Amount), 0);

// Calculating total amount per category
const categoryAmounts: { [category: string]: number } = {};

filteredData.forEach((entry) => {
Expand All @@ -59,15 +41,11 @@ export default function BarChartComponent() {
}
});

// Formatting data for the chart
const chartData: { Category: string; Amount: number }[] = Object.keys(categoryAmounts).map((category) => ({
Category: category,
Amount: categoryAmounts[category]
}));

const barWidth: number | undefined = windowWidth && windowWidth < 900 ? undefined : 800;
const barHeight: number | undefined = windowWidth && windowWidth < 900 ? undefined : 400;

return (
<div className='mt-8 flex items-center justify-center sm:px-6 lg:px-8'>
<div className='w-full px-4 text-center lg:w-2/3'>
Expand Down Expand Up @@ -111,29 +89,37 @@ export default function BarChartComponent() {
</div>
</div>
</div>
<div className='flex justify-center'>
<BarChart width={barWidth} height={barHeight} data={chartData}>
<CartesianGrid strokeDasharray='3 3' />
<YAxis tickFormatter={(value) => `$${value}`} />
<Tooltip content={<CustomTooltip />} />
<Legend />
<Bar
dataKey='Amount'
fill='#7B5DD3FF'
onClick={(data) => {
const category = data.payload.Category;
const matchedLinkObject: ExpensesLinkItem | undefined = ExpensesLinkData.find(
(obj) => obj.category === category
);
<div className='flex justify-center h-[400px]'>
{isMounted ? (
<BarChart width={800} height={400} data={chartData}>
<CartesianGrid strokeDasharray='3 3' />
<YAxis tickFormatter={(value) => `$${value}`} />
<Tooltip content={<CustomTooltip />} />
<Legend />
<Bar
dataKey='Amount'
fill='#7B5DD3FF'
onClick={(data) => {
const category = data.payload.Category;
const matchedLinkObject: ExpensesLinkItem | undefined = ExpensesLinkData.find(
(obj) => obj.category === category
);

if (matchedLinkObject) {
window.open(matchedLinkObject.link, '_blank');
}
}}
/>
</BarChart>
if (matchedLinkObject) {
window.open(matchedLinkObject.link, '_blank');
}
}}
/>
</BarChart>
) : (
<div className='h-[400px] w-full flex items-center justify-center bg-gray-50 rounded-lg'>
Loading chart...
</div>
)}
Comment on lines +92 to +118
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fixed width={800} will cause horizontal overflow on viewports narrower than 800px.

The hardcoded width means the chart won't adapt to smaller screens, causing a horizontal scrollbar or clipping. This replaces one layout problem (CLS) with another (overflow). Use recharts' ResponsiveContainer to make the chart fluid.

🔧 Proposed fix using ResponsiveContainer

Add ResponsiveContainer to the recharts import:

-import { Bar, BarChart, CartesianGrid, Legend, Tooltip, YAxis } from 'recharts';
+import { Bar, BarChart, CartesianGrid, Legend, ResponsiveContainer, Tooltip, YAxis } from 'recharts';

Then replace the fixed-dimension chart:

-        <div className='flex justify-center h-[400px]'>
+        <div className='h-[400px] w-full'>
           {isMounted ? (
-            <BarChart width={800} height={400} data={chartData}>
-              <CartesianGrid strokeDasharray='3 3' />
-              <YAxis tickFormatter={(value) => `$${value}`} />
-              <Tooltip content={<CustomTooltip />} />
-              <Legend />
-              <Bar
-                dataKey='Amount'
-                fill='#7B5DD3FF'
-                onClick={(data) => {
-                  const category = data.payload.Category;
-                  const matchedLinkObject: ExpensesLinkItem | undefined = ExpensesLinkData.find(
-                    (obj) => obj.category === category
-                  );
-
-                  if (matchedLinkObject) {
-                    window.open(matchedLinkObject.link, '_blank');
-                  }
-                }}
-              />
-            </BarChart>
+            <ResponsiveContainer width='100%' height={400}>
+              <BarChart data={chartData}>
+                <CartesianGrid strokeDasharray='3 3' />
+                <YAxis tickFormatter={(value) => `$${value}`} />
+                <Tooltip content={<CustomTooltip />} />
+                <Legend />
+                <Bar
+                  dataKey='Amount'
+                  fill='#7B5DD3FF'
+                  onClick={(data) => {
+                    const category = data.payload.Category;
+                    const matchedLinkObject: ExpensesLinkItem | undefined = ExpensesLinkData.find(
+                      (obj) => obj.category === category
+                    );
+
+                    if (matchedLinkObject) {
+                      window.open(matchedLinkObject.link, '_blank');
+                    }
+                  }}
+                />
+              </BarChart>
+            </ResponsiveContainer>
           ) : (

ResponsiveContainer handles resize internally via its own ResizeObserver, and since it's rendered only after mount (behind the isMounted guard), it won't cause hydration mismatches.

🤖 Prompt for AI Agents
In `@components/FinancialSummary/BarChartComponent.tsx` around lines 92 - 118, The
BarChart is using a hardcoded width (width={800}) which causes horizontal
overflow on small viewports; modify BarChartComponent to import
ResponsiveContainer from 'recharts' and wrap the <BarChart ...> inside
<ResponsiveContainer width="100%" height="100%"> (or height={400} on the
container) and remove the fixed width/height props from <BarChart>, preserving
existing props like data={chartData}, <CartesianGrid/>, <YAxis/>, <Tooltip
content={<CustomTooltip/>}/>, <Legend/> and the <Bar dataKey='Amount' ... />
click handler so the chart becomes fluid while still guarded by the isMounted
check.

</div>
<div className='block min-[901px]:hidden mt-8'>
<ExpensesCard />
</div>
{windowWidth && windowWidth < 900 ? <ExpensesCard /> : null}
</div>
</div>
);
Expand Down
30 changes: 9 additions & 21 deletions pages/finance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,6 @@ import Container from '../components/layout/Container';
* bar chart, success stories, and contact us components.
*/
export default function FinancialSummary() {
const [windowWidth, setWindowWidth] = useState<number>(0);

const handleResizeRef = useRef<() => void>(null!);

handleResizeRef.current = () => {
setWindowWidth(window.innerWidth);
};

// Handle window resize event to update the window width state value for responsive design purposes
useEffect(() => {
handleResizeRef.current!();
window.addEventListener('resize', handleResizeRef.current!);

return () => {
window.removeEventListener('resize', handleResizeRef.current!);
};
}, []);

const title = 'AsyncAPI Finance Summary';
const description = 'Financial Summary of AsyncAPI';

Expand All @@ -53,7 +35,13 @@ export default function FinancialSummary() {
</>
);

const shouldUseContainer = windowWidth > 1700;

return <div>{shouldUseContainer ? <Container wide>{renderComponents()}</Container> : renderComponents()}</div>;
return (
<Container
fluid
className='min-[1701px]:mx-auto min-[1701px]:w-full min-[1701px]:max-w-screen-xl'
padding='none'
>
{renderComponents()}
</Container>
);
}
Loading