Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate finance components #2747

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
544a013
summary migrated
vishvamsinh28 Mar 7, 2024
39c04e7
other components added
vishvamsinh28 Mar 7, 2024
4ad1b37
finance components added
vishvamsinh28 Mar 8, 2024
59e0f59
Merge branch 'migrate-ts' into MigrateFinanceComponent
anshgoyalevil Mar 8, 2024
b498e2d
lint fix
vishvamsinh28 Mar 8, 2024
37f7d60
Merge branch 'MigrateFinanceComponent' of https://github.com/vishvams…
vishvamsinh28 Mar 8, 2024
b5d42ab
lint error fix 2
vishvamsinh28 Mar 8, 2024
6599f49
lint final fix
vishvamsinh28 Mar 8, 2024
a58d638
revert adopter.json
vishvamsinh28 Mar 9, 2024
e4b2d7c
delete pages/finance
vishvamsinh28 Mar 9, 2024
58ec101
added recharts to devDependencies
vishvamsinh28 Mar 9, 2024
cf29703
updated jsdocs
vishvamsinh28 Mar 9, 2024
22fce2e
created separate files for components
vishvamsinh28 Mar 9, 2024
1fcdb82
separated data
vishvamsinh28 Mar 9, 2024
688f98f
merge conflict resolved
vishvamsinh28 Mar 9, 2024
fe52ba9
fix eslint errors
vishvamsinh28 Mar 9, 2024
eaad270
update jsdocs
vishvamsinh28 Mar 13, 2024
3f7156d
lint fix
vishvamsinh28 Mar 13, 2024
2062651
Merge branch 'migrate-ts' into MigrateFinanceComponent
akshatnema Mar 13, 2024
11e1232
fix recharts issue
anshgoyalevil Mar 14, 2024
1dd2c33
fix lint
anshgoyalevil Mar 14, 2024
b2e382e
fix package-lock.json
anshgoyalevil Mar 14, 2024
3aafc03
fix crossOrigin
anshgoyalevil Mar 14, 2024
d53b4fe
comments added to bar chart
vishvamsinh28 Mar 16, 2024
54be57e
Merge branch 'migrate-ts' into MigrateFinanceComponent
anshgoyalevil Mar 18, 2024
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
61 changes: 61 additions & 0 deletions components/FinancialSummary/AsyncAPISummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import Button from '../buttons/Button';
import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';

/**
* Component representing the AsyncAPI Financial Summary.
* {JSX.Element} The JSX representation of the component.
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
*/
export default function AsyncAPISummary() {
return (
<div className='px-4 sm:px-6 lg:px-8'>
<div className='mx-4 my-8 grid lg:grid-cols-9 lg:gap-8 lg:text-center'>
<div className='col-span-5 col-start-3'>
<Heading level={HeadingLevel.h2} className='m-3 text-center text-5xl'>
AsyncAPI Financial Summary
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='my-1 max-w-4xl text-darkGunMetal'>
To help improve the current state of Event-Driven Architectures and their tooling, you can show your support for
the AsyncAPI Initiative by making a financial contribution. We offer three donation options: <strong>Open Collective, GitHub
Sponsors, and Linux Foundation Crowdfunding</strong>. Our expenses are managed through Open Collective and GitHub Sponsors,
while Linux Foundation Crowdfunding operates separately.
</Paragraph>
</div>
</div>
<div className='mb-20 flex justify-center'>
<Button
text='Become a Sponsor'
href='https://opencollective.com/asyncapi#category-CONTRIBUTE'
target='_blank'
/>
</div>
<div className='mt-4 text-center text-sm'>
<Heading level={HeadingLevel.h1} typeStyle={HeadingTypeStyle.md} className='4xl'>
Ways to Support Us?
</Heading>
</div>
<div className='max-width my-4 text-center text-base text-darkGunMetal'>
<Paragraph typeStyle={ParagraphTypeStyle.sm} className='my-4'>
The easiest way to support AsyncAPI is by becoming a financial sponsor. While <br className='hidden lg:inline-block' />there are alternative options,
they may involve greater effort. Contribute <br className='hidden lg:inline-block' />monetarily using the following channels.
</Paragraph>
</div>

<div className='text-center'>
<a href='https://opencollective.com/asyncapi' target='_blank'>
<img className='mx-4 inline size-10 transition-transform hover:scale-110 active:scale-90' src='/img/logos/OpenCollective.svg' alt='Open Collective' />
</a>
<a href='https://crowdfunding.lfx.linuxfoundation.org/projects/445898e9-42a2-4965-9e0a-c2a714f381bc' target='_blank'>
<img className='mx-4 inline size-10 transition-transform hover:scale-110 active:scale-90' src='/img/logos/LFX.svg' alt='Linux Foundation' />
</a>
<a href='https://github.com/sponsors/asyncapi' target='_blank'>
<img className='mx-4 inline size-10 transition-transform hover:scale-110 active:scale-90' src='/img/logos/github-black.svg' alt='Github' />
</a>
</div>

</div>
);
}
123 changes: 123 additions & 0 deletions components/FinancialSummary/BarChartComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useEffect, useState } from 'react';
// eslint-disable-next-line import/no-extraneous-dependencies
Copy link
Member

Choose a reason for hiding this comment

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

Don't disable the eslint rules. Instead try to resolve them. You have to install recharts library using npm in the project. Kindly use the appropriate version to install the dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eslint was not allowing it in devDependency

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, recharts library shouldn't be part of devDependency. It's types can only be part of devDependency.

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

import type { ExpenseItem, ExpensesLinkItem } from '@/types/FinancialSummary/BarChartComponent';

import ExpensesData from '../../config/finance/json-data/2024/Expenses.json';
import ExpensesLinkData from '../../config/finance/json-data/2024/ExpensesLink.json';
import { getUniqueCategories } from '../../utils/getUniqueCategories';
import CustomTooltip from './CustomTooltip';
import ExpensesCard from './ExpensesCard';

/**
* BarChartComponent component displays a bar chart for expense analysis.
* {JSX.Element} BarChartComponent component.
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
*/
export default function BarChartComponent() {
const [selectedCategory, setSelectedCategory] = useState<string>('All Categories');
const [selectedMonth, setSelectedMonth] = useState<string>('All Months');
const [windowWidth, setWindowWidth] = useState<number>(0);

const categories: string[] = getUniqueCategories();
const months: string[] = Object.keys(ExpensesData);

useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
};

handleResize();
window.addEventListener('resize', handleResize);

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

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

const totalAmount: number = filteredData.reduce((total, entry) => total + parseFloat(entry.Amount), 0);

const categoryAmounts: { [category: string]: number } = {};

filteredData.forEach(entry => {
if (categoryAmounts[entry.Category]) {
categoryAmounts[entry.Category] += parseFloat(entry.Amount);
} else {
categoryAmounts[entry.Category] = parseFloat(entry.Amount);
}
});
Copy link
Member

Choose a reason for hiding this comment

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

Add comments to explain this part of code.


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'>
<div className='mb-5'>
<h1 id='budget-analysis' className='my-2 mb-4 text-3xl font-semibold'>Budget Analysis</h1>
<p>Gain insights into the allocation of funds across different categories through our Budget Analysis</p>
<div className='my-4 flex flex-col justify-between md:m-8 md:flex-row md:items-center md:justify-between'>
<div className='my-2'>
<p className='text-center sm:text-left'>Expenses</p>
<p className='mt-1 text-center text-xl font-semibold sm:text-left'>${totalAmount.toFixed(2)}</p>
</div>
<div className='space-x-4 md:flex'>
<div className='mx-auto'>
<select
className='m-1 w-full rounded-md border border-gray-600 bg-white p-2 text-xs font-semibold text-violet sm:w-auto md:w-48'
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
>
<option value='All Categories'>All Categories</option>
{categories.map(category => (
<option key={category} value={category}>{category}</option>
))}
</select>
<select
className='m-1 w-full rounded-md border border-gray-600 bg-violet p-2 pr-8 text-xs font-semibold text-white sm:w-auto md:w-48'
value={selectedMonth}
onChange={(e) => setSelectedMonth(e.target.value)}
>
<option value='All Months'>All Months</option>
{months.map(month => (
<option key={month} value={month}>{month}</option>
))}
</select>
</div>
</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);

if (matchedLinkObject) {
window.open(matchedLinkObject.link, '_blank');
}
}}
/>
</BarChart>
</div>
{windowWidth && windowWidth < 900 ? <ExpensesCard /> : null}
</div>
</div>
);
};
40 changes: 40 additions & 0 deletions components/FinancialSummary/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { ExpenseItem, Expenses } from '@/types/FinancialSummary/BarChartComponent';

import ExpensesLinkData from '../../config/finance/json-data/2024/ExpensesLink.json';

/**
* Card component displays expense details for a specific month.
* @param {Object} props - Props for Card component.
* @param {string} props.month - Month for which expenses are displayed.
* @param {ExpenseItem[]} props.data - Expense data for the month.
* {JSX.Element} Card component.
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
*/
export default function Card({ month, data }: { month: keyof Expenses; data: ExpenseItem[]; }) {
/**
* Handles the click event on an expense category.
* Opens a new window with the corresponding link if available.
* @param {string} category - The expense category clicked.
* {void}
*/
function handleExpenseClick(category: string) {
const matchedLinkObject = ExpensesLinkData.find(obj => obj.category === category);

if (matchedLinkObject) {
window.open(matchedLinkObject.link, '_blank');
}
}

return (
<div className='flex h-56 flex-col overflow-hidden rounded-lg bg-slate-100 p-4 shadow-lg'>
<div className='mb-4 text-lg font-semibold'>{month}</div>
<div className='flex flex-col overflow-auto'>
{data.map((item, index) => (
<div key={index} className='flex justify-between'>
<div className='m-2 text-sm' onClick={() => handleExpenseClick(item.Category)}>{item.Category}</div>
<div className='m-2 text-sm'>${item.Amount}</div>
</div>
))}
</div>
</div>
);
}
36 changes: 36 additions & 0 deletions components/FinancialSummary/ContactUs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import Button from '../buttons/Button';
import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';
import TextLink from '../typography/TextLink';

/**
* ContactUs component displays information about getting in touch.
* {JSX.Element} ContactUs component.
Copy link
Member

Choose a reason for hiding this comment

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

Kindly add @description and remove the return JSX.Element. Check the suggestions above.

*/
export default function ContactUs() {
return (
<div className='px-4 sm:px-6 lg:px-8'>
<div className='my-4 grid lg:grid-cols-9 lg:gap-8 lg:text-center'>
<div className='col-span-5 col-start-3'>
<div className='mx-2'>
<Heading level={HeadingLevel.h1} typeStyle={HeadingTypeStyle.lg}>Interested in getting in touch?</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='my-2 max-w-4xl'>
Feel free to contact us if you need more explanation. We are happy to hop on a call and help with
onboarding to the project as a sponsor. Write email to <span><TextLink className='text-base font-semibold text-violet' href='mailto:[email protected]' target='_blank'>[email protected]</TextLink></span>
</Paragraph>
</div>
</div>
</div>
<div className='flex justify-center'>
<Button
text='Contact Us'
href='mailto:[email protected]'
target='_blank'
/>
</div>
</div>
);
};
24 changes: 24 additions & 0 deletions components/FinancialSummary/CustomTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { CustomTooltipProps } from '@/types/FinancialSummary/BarChartComponent';

/**
* CustomTooltip component displays custom tooltip for BarChart.
* @param {CustomTooltipProps} props - Props for CustomTooltip component.
* {JSX.Element} CustomTooltip component.
*/
export default function CustomTooltip(props: CustomTooltipProps) {
const { active, payload } = props;
Copy link
Member

Choose a reason for hiding this comment

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

We should de-structure the props in the function arguments only.


if (active && payload && payload.length) {
Copy link
Member

Choose a reason for hiding this comment

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

describe this if condition.

const data = payload[0].payload;

return (
<div className='bg-opacity-90/90 rounded-md border border-gray-300 bg-white p-2 shadow-md'>
<p className='text-14 mb-1 font-bold'>{data.Category}</p>
<p className='text-12 text-gray-900'>${data.Amount.toFixed(2)}</p>
<p>Click the bar to learn more</p>
</div>
);
}

return null;
}
45 changes: 45 additions & 0 deletions components/FinancialSummary/ExpenseBreakdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';
import { expenseData } from './data/ExpenseBreakdownData';

/**
* ExpenseBreakdown component displays a breakdown of expenses.
* {JSX.Element} ExpenseBreakdown component.
*/
export default function ExpenseBreakdown() {
return (
<div className='bg-[#EFFAFE] px-4 sm:px-6 lg:px-8'>
<div className='mb-16 grid lg:grid-cols-9 lg:gap-8 lg:text-center'>
<div className='col-span-7 col-start-2 my-12'>
<div className='mx-2'>
<Heading className='m-3 text-center text-base'>
Expense Breakdown
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mx-auto my-3 max-w-4xl text-center text-darkGunMetal'>
Funds from GitHub Sponsors are directly transferred to our AsyncAPI Open
Collective account. We maintain transparency in all expenses, and the TSC approves
anticipated expenses.
</Paragraph>
</div>
<div className='mx-3 mt-8 grid grid-cols-1 gap-10 md:grid-cols-3'>
{expenseData.map((expense, index) => (
<div key={index} className='flex flex-col items-center rounded-md bg-white p-4 shadow-md transition-transform hover:scale-105 active:scale-90'>
<a href={expense.link} target='_blank' rel='noopener noreferrer'>
<div className='text-darkGunMetal'>
<div className='flex flex-col items-center'>
<img src={expense.imageUrl} alt={expense.title} className='m-1 h-auto w-1/5 rounded-md object-cover' />
<h2 className='my-2 text-center text-2xl font-semibold text-darkGunMetal'>{expense.title}</h2>
</div>
<p className='text-center text-base text-darkGunMetal'>{expense.description}</p>
</div>
</a>
</div>
))}
</div>
</div>
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions components/FinancialSummary/ExpensesCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Expenses } from '@/types/FinancialSummary/BarChartComponent';

import ExpensesData from '../../config/finance/json-data/2024/Expenses.json';
import Card from './Card';

/**
* ExpensesCard component displays all expenses for each month.
* {JSX.Element} ExpensesCard component.
*/
export default function ExpensesCard() {
return (
<div className='overflow-x-auto'>
<div className='grid auto-cols-max grid-flow-col gap-4 p-4'>
{Object.entries(ExpensesData).map(function ([month, data], index) {
return (
<Card key={index} month={month as keyof Expenses} data={data} />
);
})}
</div>
</div>
);
}
39 changes: 39 additions & 0 deletions components/FinancialSummary/OtherFormsComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

import Heading from '../typography/Heading';
import Paragraph from '../typography/Paragraph';
import { otherFormsData } from './data/otherFormsData';

/**
* OtherFormsComponent displays other forms of financial support.
* {JSX.Element} OtherFormsComponent.
*/
export default function OtherFormsComponent() {
return (
<div className='bg-[#F5F5F5] px-4 sm:px-6 lg:px-8'>
<div className='grid lg:grid-cols-9 lg:gap-8 lg:text-center'>
<div className='col-span-7 col-start-2 my-12'>
<div className='mx-2'>
<Heading className='mx-3 mb-5 mt-10 text-center text-base'>
Other Forms Of Financial Support
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mx-auto mb-3 max-w-4xl text-center text-darkGunMetal'>
You can also support AsyncAPI initiative by getting<br className='hidden lg:inline-block'></br> involved through employment, providing services and<br className='hidden lg:inline-block'></br> organizing events
</Paragraph>
</div>
<div className='mx-3 mt-8 grid grid-cols-1 gap-10 md:grid-cols-3'>
{otherFormsData.map((form, index) => ( // Mapping over the data array
<div key={index} className='flex flex-col items-center rounded-md bg-white p-4 text-center shadow-md'>
<img src={form.imageUrl} alt={form.title} className='m-2 h-auto w-1/3 object-cover' />
<h2 className='my-2 text-2xl font-semibold'>{form.title}</h2>
<p className='mx-2 mt-1 text-base text-darkGunMetal'>
{form.description}
</p>
</div>
))}
</div>
</div>
</div>
</div>
);
};
Loading
Loading