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 all 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
78 changes: 78 additions & 0 deletions components/FinancialSummary/AsyncAPISummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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';

/**
* @description Component representing the AsyncAPI Financial Summary.
*/
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>
);
}
136 changes: 136 additions & 0 deletions components/FinancialSummary/BarChartComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React, { useEffect, useState } from 'react';
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';

/**
* @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);

// 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);
};
}, []);

// Filtering data based on selected month and category
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) => {
if (categoryAmounts[entry.Category]) {
categoryAmounts[entry.Category] += parseFloat(entry.Amount);
} else {
categoryAmounts[entry.Category] = parseFloat(entry.Amount);
}
});

// 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'>
<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>
);
}
41 changes: 41 additions & 0 deletions components/FinancialSummary/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { ExpenseItem, Expenses } from '@/types/FinancialSummary/BarChartComponent';

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

/**
* @description 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.
*/
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>
);
}
42 changes: 42 additions & 0 deletions components/FinancialSummary/ContactUs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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';

/**
* @description ContactUs component displays information about getting in touch.
*/
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>
);
}
25 changes: 25 additions & 0 deletions components/FinancialSummary/CustomTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { CustomTooltipProps } from '@/types/FinancialSummary/BarChartComponent';

/**
* @description CustomTooltip component displays custom tooltip for BarChart.
* @param {boolean} props.active - The active state of the tooltip
* @param {TooltipPayload[]} props.payload - The payload of the tooltip
*/
export default function CustomTooltip({ active, payload }: CustomTooltipProps) {
/**
* If the tooltip is active and the payload has data, display the category and amount of the bar
*/
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;
}
51 changes: 51 additions & 0 deletions components/FinancialSummary/ExpenseBreakdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

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

/**
* @description ExpenseBreakdown component displays a breakdown of expenses.
*/
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>
);
}
19 changes: 19 additions & 0 deletions components/FinancialSummary/ExpensesCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Expenses } from '@/types/FinancialSummary/BarChartComponent';

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

/**
* @description ExpensesCard component displays all expenses for each month.
*/
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>
);
}
Loading
Loading