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

Rh/testing #39

Open
wants to merge 28 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2224122
changed invoice page to no longer hit our API route, but to get the s…
Gambarou Nov 15, 2023
2143797
Added api file to lib folder to hold third party api call logic
Gambarou Nov 15, 2023
a7d6786
Added error prop to InvoiceDisplay component
Gambarou Nov 15, 2023
09791e5
Small change to Navbar
Gambarou Nov 15, 2023
930592a
Fixed pagination issue in the DataTable.
Gambarou Nov 15, 2023
76861c5
Changes to the mappedData prop in overview component
Gambarou Nov 15, 2023
eb58558
Changes to admin page and utils file
Gambarou Nov 15, 2023
63aca66
Updated the admin page to be more modular, and separated more of the …
Gambarou Nov 15, 2023
30c46db
Updated the XAxis datakey to be month instead of name
Gambarou Nov 15, 2023
8b737e2
Cleaned up the utils file and changed the functions to be more concis…
Gambarou Nov 15, 2023
37cb5a3
Deleted unused components
Gambarou Nov 15, 2023
eb61108
Deletes unused types in types.ts file
Gambarou Nov 15, 2023
6a86cb9
Fixed the most recent sales component so now it actually shows the mo…
Gambarou Nov 15, 2023
2acbd6b
Changed table headers from buttons to divs
Gambarou Nov 15, 2023
da3b3aa
Small UI change to InvoiceDisplay
Gambarou Nov 15, 2023
4aa56cb
Deletes include statement that wasn't being used
Gambarou Nov 15, 2023
ee154eb
Deletes unused API route. Changes invoice display to be shadCN compon…
Gambarou Nov 15, 2023
125f979
Adds shadCN badge component in InvoiceDisplay
Gambarou Nov 15, 2023
ea37eae
Fixes mobile formatting issue with splash page.
Gambarou Nov 15, 2023
04c0af6
Small changes
Gambarou Nov 15, 2023
fa2e211
Deleted old import statement
Gambarou Nov 15, 2023
43547e3
Fixes logic for getReveneueByMonth in utils file
Gambarou Nov 15, 2023
1ff7b64
Fixes logic with getRevenueByMonth
Gambarou Nov 15, 2023
8744814
Adds style to globals that overrides the default white background on …
Gambarou Nov 15, 2023
867aaf7
Adds testing with Jest and React Testing Library. Tests added for hom…
Gambarou Nov 17, 2023
da646e1
Fixes some UI issues with the admin sign in page
Gambarou Nov 17, 2023
139e190
Few small UI changes
Gambarou Nov 17, 2023
9ccdfc3
Adds priorty to next image
Gambarou Nov 17, 2023
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
7 changes: 6 additions & 1 deletion bill-bot-baggins/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"extends": ["next/core-web-vitals", "prettier"]
"extends": [
"next/core-web-vitals",
"prettier",
"plugin:testing-library/react",
"plugin:jest-dom/recommended"
]
}
48 changes: 48 additions & 0 deletions bill-bot-baggins/__tests__/AdminDashboardPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { getRevenueData } from '@/lib/utils';

describe('getRevenueData', () => {
it('should format revenue data correctly', () => {
const currentDate = new Date();
const formattedDate = currentDate.toISOString().split('T')[0];

const mockData = [
{
sf_unique_id: '1',
invoice_id: '2',
amount: 10000,
invoice_sent_date: '2023-10-14',
payment_date: formattedDate,
invoice_due_date: '2023-11-14',
payment_method: 'credit card',
project_name: 'C12',
account_name: 'VendorSeekr',
},
{
sf_unique_id: '2',
invoice_id: '3',
amount: 3500,
invoice_sent_date: '2023-11-14',
payment_date: formattedDate,
invoice_due_date: '2023-12-14',
payment_method: 'credit card',
project_name: 'C23',
account_name: 'BillBotBaggins',
},
{
sf_unique_id: '3',
invoice_id: '4',
amount: 5000,
invoice_sent_date: '2023-08-14',
payment_date: formattedDate,
invoice_due_date: '2023-09-14',
payment_method: 'credit card',
project_name: 'C34',
account_name: 'Aimbu',
},
];
const result = getRevenueData(mockData);

expect(result.payments).toBeDefined();
expect(result.monthRevenue).toBe(18500);
});
});
49 changes: 49 additions & 0 deletions bill-bot-baggins/__tests__/Home.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @jest-environment jsdom
*/
import React from 'react';
import { render, screen } from '@testing-library/react';
import Home from '@/app/(main)/(routes)/page';

describe('Home', () => {
it('renders the PayStream logo', () => {
render(<Home />);

const logo = screen.getByAltText('PayStream logo');

expect(logo).toBeInTheDocument();
});

it('renders the PayStream logo with correct attributes', () => {
render(<Home />);
const logo = screen.getByAltText('PayStream logo');
expect(logo).toBeInTheDocument();
expect(logo).toHaveAttribute(
'src',
'/_next/image?url=%2Flogo.png&w=828&q=75'
);
// Add more attribute checks if needed
});

it('renders buttons with correct links', () => {
render(<Home />);
const experienceButton = screen.getByText('Experience PayStream');
const learnMoreButton = screen.getByText('Learn more');

expect(experienceButton.closest('a')).toHaveAttribute('href', '/admin');
expect(learnMoreButton.closest('a')).toHaveAttribute(
'href',
'https://github.com/oslabs-beta/PayStream'
);
});

it('renders team members info correctly', () => {
render(<Home />);
const teamMember = screen.getByText('Chandler');

expect(teamMember.closest('a')).toHaveAttribute(
'href',
'mailto:[email protected]'
);
});
});
134 changes: 44 additions & 90 deletions bill-bot-baggins/app/(admin)/(routes)/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -1,94 +1,37 @@
import React from 'react';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import Overview from '@/components/overview';
import { Overview, RecentSales, columns, DataTable } from '@/components/index';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { columns } from '@/components/Columns';
import React from 'react';
import { RecentSales } from '@/components/RecentSales';
import { DataTable } from '@/components/DataTable';
import {
getSalesForceAccessToken,
getSalesForceInvoiceData,
formatSalesForceData,
} from '@/lib/utils';

import type { PaymentProps } from '@/lib/types';
import { getRevenueData } from '@/lib/utils';
import { getSalesForceAccessToken, getSalesForceInvoiceData } from '@/lib/api';

async function AdminDashboardPage() {
const currentYear = new Date().getFullYear().toString();
// get SF accessToken
const accessToken = await getSalesForceAccessToken();
// get SF invoice data using accessToken
const data = await getSalesForceInvoiceData(accessToken);
// get formatted revenue data
const revenueData = getRevenueData(data);

/*
Gets total amount of all payments to use as revenue data in the overview component
*/
let revenue = 0;
let monthrevenue = 0;
let pastmonthrevenue = 0;
let outstandingInvoices = 0;
let pastyearrevenue = 0;
const payments: PaymentProps[] = [];
const currentYear = new Date().getFullYear().toString();
const pastYear = (new Date().getFullYear() - 1).toString();
const currentMonth = (new Date().getMonth() + 1).toString();
const pastMonth = new Date().getMonth().toString();
const currentDate = new Date();

// gets 5 payments to display in the recent payments (need to change this to be only the most recent 5 payments)
for (let i = 0; i < data.length && i < 5; i++) {
if (data[i].payment_date && data[i].payment_date?.includes(currentYear)) {
payments.push(data[i]);
}
}

// get the total revenue to display
data.forEach((invoice) => {
if (invoice.payment_date && invoice.payment_date.includes(currentYear)) {
revenue += invoice.amount;
}
});

data.forEach((invoice) => {
if (invoice.payment_date && invoice.payment_date.includes(pastYear)) {
pastyearrevenue += invoice.amount;
}
if (
invoice.payment_date &&
invoice.payment_date.slice(5, 7).includes(currentMonth)
) {
monthrevenue += invoice.amount;
}
if (
invoice.payment_date &&
invoice.payment_date.slice(5, 7).includes(pastMonth)
) {
pastmonthrevenue += invoice.amount;
}
if (
invoice.invoice_due_date &&
new Date(invoice.invoice_due_date) < currentDate &&
invoice.payment_date == undefined
) {
outstandingInvoices += 1;
}
});
const monthrevenuegrowth =
monthrevenue / pastmonthrevenue < Infinity
? monthrevenue / pastmonthrevenue
: 100;
const yearrevenuegrowth =
revenue / pastyearrevenue < Infinity ? revenue / pastyearrevenue : 100;

const mappedData = formatSalesForceData(data);
const {
payments,
monthRevenue,
yearRevenue,
outstandingInvoices,
revenueDataByMonth,
monthRevenueGrowth,
yearRevenueGrowth,
} = revenueData;

return (
<div className='aspect-auto h-full flex-1 space-y-4 pt-4 xl:h-5/6 xl:pl-36'>
<div className='aspect-auto h-full flex-1 space-y-4 px-5 pt-4 xl:h-5/6 xl:pl-36'>
<div className='flex items-center justify-between space-y-2'>
<h2 className='text-3xl font-bold tracking-tight'>Dashboard</h2>
<div className='flex items-center space-x-2'></div>
Expand All @@ -98,8 +41,8 @@ async function AdminDashboardPage() {
<TabsTrigger value='overview'>Overview</TabsTrigger>
<TabsTrigger value='analytics'>Analytics</TabsTrigger>
</TabsList>
<TabsContent value='overview' className='space-y-4 pr-36'>
<div className='grid gap-4 md:grid-cols-2 lg:grid-cols-3'>
<TabsContent value='overview' className='space-y-4 xl:pr-36'>
<div className='grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3'>
<Card>
<CardHeader className='flex flex-row items-center justify-between space-y-0 pb-2'>
<CardTitle className='text-sm font-medium'>
Expand All @@ -119,15 +62,16 @@ async function AdminDashboardPage() {
</svg>
</CardHeader>
<CardContent>
<div className='text-2xl font-bold'>{`${revenue.toLocaleString(
<div className='text-2xl font-bold'>{`${yearRevenue.toLocaleString(
'en-US',
{
style: 'currency',
currency: 'USD',
}
)}`}</div>
<p className='text-xs text-muted-foreground'>
+{`${yearrevenuegrowth}`}% from last year
{yearRevenueGrowth >= 0 && '+'}
{`${yearRevenueGrowth}`}% from last year
</p>
</CardContent>
</Card>
Expand All @@ -146,21 +90,20 @@ async function AdminDashboardPage() {
strokeWidth='2'
className='h-4 w-4 text-muted-foreground'
>
<path d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2' />
<circle cx='9' cy='7' r='4' />
<path d='M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75' />
<path d='M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6' />
</svg>
</CardHeader>
<CardContent>
<div className='text-2xl font-bold'>{`${monthrevenue.toLocaleString(
<div className='text-2xl font-bold'>{`${monthRevenue.toLocaleString(
'en-US',
{
style: 'currency',
currency: 'USD',
}
)}`}</div>
<p className='text-xs text-muted-foreground'>
+{`${monthrevenuegrowth}`}% from last month
{monthRevenueGrowth >= 0 && '+'}
{`${monthRevenueGrowth}% from last month`}
</p>
</CardContent>
</Card>
Expand All @@ -187,20 +130,25 @@ async function AdminDashboardPage() {
<div className='text-2xl font-bold'>
{`${outstandingInvoices}`}
</div>

</CardContent>
</Card>
</div>
<div className='grid gap-4 md:grid-cols-2 lg:grid-cols-7'>
<Card className='col-span-4'>
<div className='grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-5'>
<Card className='col-span-2 lg:col-span-3'>
<CardHeader>
<CardTitle>{`Overview of ${currentYear}`}</CardTitle>
</CardHeader>
<CardContent className='pl-2'>
<Overview data={mappedData} />
{revenueDataByMonth ? (
<Overview data={revenueDataByMonth} />
) : (
<div className='flex h-[300px] items-center justify-center'>
Error fetching data...
</div>
)}
</CardContent>
</Card>
<Card className='col-span-3'>
<Card className='col-span-2 lg:col-span-2'>
<CardHeader>
<CardTitle>Recent Payments</CardTitle>
<CardDescription>
Expand All @@ -213,8 +161,14 @@ async function AdminDashboardPage() {
</Card>
</div>
</TabsContent>
<TabsContent value='analytics' className='pr-36'>
<DataTable columns={columns} data={data} />
<TabsContent value='analytics' className='xl:pr-36'>
{data ? (
<DataTable columns={columns} data={data} />
) : (
<div className='flex h-full items-center justify-center'>
Error fetching data...
</div>
)}
</TabsContent>
</Tabs>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import React from 'react';

function SignInPage() {
return (
<div className='container relative h-full flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0'>
<div className='relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex'>
<div className='absolute inset-0 bg-black opacity-80' />
<div className='relative h-full w-full flex-col items-center justify-center lg:grid lg:max-w-none lg:grid-cols-2 lg:px-0'>
<div className='relative hidden h-full flex-col bg-black p-10 text-white dark:border-r lg:flex'>
<ParticleEffect />
<div className='relative z-20 flex items-center text-lg font-medium'>
<div className='absolute left-10 top-10 z-20'>
<Link href='/'>
<Image
src='/logo.png'
alt='Billbot Baggins logo'
alt='PayStream logo'
width={240}
height={25}
quality={95}
priority={true}
className='w-auto object-contain'
/>
</Link>
Expand All @@ -32,8 +32,21 @@ function SignInPage() {
</blockquote>
</div>
</div>
<div className='z-20 flex h-full items-center justify-center bg-neutral-900 lg:p-8'>
<div className='mx-auto flex w-full flex-col space-y-6 rounded-lg border border-neutral-700 bg-neutral-800 p-12 sm:w-[400px]'>
<div className='z-20 flex h-full w-full flex-col items-center justify-center bg-black lg:bg-neutral-900 lg:p-8'>
<div className='flex -translate-y-[80px] items-center justify-center lg:hidden'>
<Link href='/'>
<Image
src='/logo.png'
alt='PayStream logo'
width={240}
height={25}
quality={95}
priority={true}
className='h-[60px] w-auto object-contain'
/>
</Link>
</div>
<div className='flex w-[400px] flex-col space-y-6 rounded-lg border border-neutral-700 bg-neutral-800 p-12'>
<div className='flex flex-col space-y-2'>
<h1 className='text-2xl font-semibold tracking-tight'>
Admin Login
Expand Down
Loading