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

Add database #153

Merged
merged 18 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 7 additions & 0 deletions dashboard/15-final/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
POSTGRES_URL="postgres://default:IQA2FonHJi9d@ep-square-union-29037633-pooler.us-east-1.postgres.vercel-storage.com:5432/verceldb"
POSTGRES_PRISMA_URL="postgres://default:IQA2FonHJi9d@ep-square-union-29037633-pooler.us-east-1.postgres.vercel-storage.com:5432/verceldb?pgbouncer=true&connect_timeout=15"
StephDietz marked this conversation as resolved.
Show resolved Hide resolved
POSTGRES_URL_NON_POOLING="postgres://default:IQA2FonHJi9d@ep-square-union-29037633.us-east-1.postgres.vercel-storage.com:5432/verceldb"
POSTGRES_USER="default"
POSTGRES_HOST="ep-square-union-29037633-pooler.us-east-1.postgres.vercel-storage.com"
POSTGRES_PASSWORD="IQA2FonHJi9d"
POSTGRES_DATABASE="verceldb"
8 changes: 5 additions & 3 deletions dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import InvoiceForm from '@/app/ui/invoices/form';
import { invoices } from '@/app/lib/dummy-data';
import { notFound } from 'next/navigation';
import { Invoice } from '@/app/lib/definitions';
import { fetchInvoiceById } from '@/app/lib/data-fetches';

export default function Page({ params }: { params: { id: string } }) {
export default async function Page({ params }: { params: { id: string } }) {
const id = params.id ? parseInt(params.id) : null;
const invoice = invoices.find((invoice) => invoice.id === id);
const invoiceData = await fetchInvoiceById(id);
const invoice = invoiceData.rows[0] as Invoice;

if (!invoice) {
notFound();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Invoice, Revenue } from './definitions';
import { fetchLatestInvoices } from './data-fetches';

export const calculateAllInvoices = (
invoices: Invoice[],
Expand All @@ -19,7 +20,7 @@ export const calculateCustomerInvoices = (
customerId: number,
) => {
return invoices
.filter((invoice) => invoice.customerId === customerId)
.filter((invoice) => invoice.customer_id === customerId)
.filter((invoice) => !status || invoice.status === status)
.reduce((total, invoice) => total + invoice.amount / 100, 0)
.toLocaleString('en-US', {
Expand All @@ -38,13 +39,12 @@ export const countCustomerInvoices = (
invoices: Invoice[],
customerId: number,
) => {
return invoices.filter((invoice) => invoice.customerId === customerId).length;
return invoices.filter((invoice) => invoice.customer_id === customerId)
.length;
};

export const findLatestInvoices = (invoices: Invoice[]) => {
return [...invoices]
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
.slice(0, 5);
export const findLatestInvoices = async () => {
return await fetchLatestInvoices();
};

export const generateYAxis = (revenue: Revenue[]) => {
Expand Down
65 changes: 65 additions & 0 deletions dashboard/15-final/app/lib/data-fetches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { sql } from '@vercel/postgres';

export async function fetchAllInvoices() {
const invoicesData = await sql`SELECT * FROM invoices`;
return invoicesData.rows;
}

export async function fetchAllCustomers() {
const customersData = await sql`SELECT * FROM customers`;
return customersData.rows;
}

export async function fetchAllRevenue() {
const revenueData = await sql`SELECT * FROM revenue`;
return revenueData.rows;
}

export async function fetchFilteredInvoices(
searchTerm: string,
currentPage: number,
ITEMS_PER_PAGE: number,
) {
const invoicesData = await sql`
SELECT
invoices.*,
customers.name AS customer_name,
customers.email AS customer_email,
customers.image_url AS customer_image
FROM
invoices
JOIN
customers ON invoices.customer_id = customers.id
WHERE
invoices.id::text ILIKE ${`%${searchTerm}%`} OR
customers.name ILIKE ${`%${searchTerm}%`} OR
customers.email ILIKE ${`%${searchTerm}%`} OR
invoices.amount::text ILIKE ${`%${searchTerm}%`} OR
invoices.date::text ILIKE ${`%${searchTerm}%`} OR
invoices.status ILIKE ${`%${searchTerm}%`}
LIMIT ${ITEMS_PER_PAGE}
OFFSET ${(currentPage - 1) * ITEMS_PER_PAGE}
`;
return invoicesData.rows;
}

export async function fetchInvoiceCountBySearchTerm(searchTerm: string) {
const { rows: countRows } = await sql`
SELECT COUNT(*)
FROM invoices
LEFT JOIN customers ON invoices.customer_id = customers.id
WHERE (invoices.id::text ILIKE ${`%${searchTerm}%`} OR customers.name ILIKE ${`%${searchTerm}%`} OR customers.email ILIKE ${`%${searchTerm}%`})
`;
return countRows[0].count;
}

export async function fetchInvoiceById(id: number | null) {
return await sql`SELECT * from INVOICES where id=${id}`;
}

export async function fetchLatestInvoices() {
const latestInvoices = await sql`SELECT * FROM invoices
ORDER BY date DESC
LIMIT 5;`;
return latestInvoices.rows;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export type Customer = {
id: number;
name: string;
email: string;
imageUrl: string;
image_url: string;
};

export type Invoice = {
id: number;
customerId: number;
customer_id: number;
amount: number;
// In TypeScript, this is called a string union type.
// It means that the "status" property can only be one of the two strings: 'pending' or 'paid'.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { User, Customer, Invoice, Revenue } from './definitions';

// This file contains dummy data that you'll be replacing with real data in Chapter 7.
export const users: User[] = [
const users = [
{
id: 1,
name: 'User',
Expand All @@ -10,142 +8,142 @@ export const users: User[] = [
},
];

export const customers: Customer[] = [
const customers = [
{
id: 1,
name: 'Ada Lovelace',
email: '[email protected]',
imageUrl: '/customers/ada-lovelace.png',
image_url: '/customers/ada-lovelace.png',
},
{
id: 2,
name: 'Grace Hopper',
email: '[email protected]',
imageUrl: '/customers/grace-hopper.png',
image_url: '/customers/grace-hopper.png',
},
{
id: 3,
name: 'Hedy Lammar',
email: '[email protected]',
imageUrl: '/customers/hedy-lammar.png',
image_url: '/customers/hedy-lammar.png',
},
{
id: 4,
name: 'Margaret Hamilton',
email: '[email protected]',
imageUrl: '/customers/margaret-hamilton.png',
image_url: '/customers/margaret-hamilton.png',
},
];

export const invoices: Invoice[] = [
const invoices = [
{
id: 1,
customerId: 1,
customer_id: 1,
amount: 15795,
status: 'pending',
date: '2023-12-06',
},
{
id: 2,
customerId: 2,
customer_id: 2,
amount: 20348,
status: 'pending',
date: '2023-11-14',
},
{
id: 3,
customerId: 3,
customer_id: 3,
amount: 3040,
status: 'paid',
date: '2023-10-29',
},
{
id: 4,
customerId: 4,
customer_id: 4,
amount: 44800,
status: 'paid',
date: '2023-09-10',
},
{
id: 5,
customerId: 1,
customer_id: 1,
amount: 34577,
status: 'pending',
date: '2023-08-05',
},
{
id: 6,
customerId: 2,
customer_id: 2,
amount: 54246,
status: 'pending',
date: '2023-07-16',
},
{
id: 7,
customerId: 3,
customer_id: 3,
amount: 8945,
status: 'pending',
date: '2023-06-27',
},
{
id: 8,
customerId: 4,
customer_id: 4,
amount: 32545,
status: 'paid',
date: '2023-06-09',
},
{
id: 9,
customerId: 3,
customer_id: 3,
amount: 1250,
status: 'paid',
date: '2023-06-17',
},
{
id: 10,
customerId: 1,
customer_id: 1,
amount: 8945,
status: 'paid',
date: '2023-06-07',
},
{
id: 11,
customerId: 2,
customer_id: 2,
amount: 500,
status: 'paid',
date: '2023-08-19',
},
{
id: 12,
customerId: 3,
customer_id: 3,
amount: 8945,
status: 'paid',
date: '2023-06-03',
},
{
id: 13,
customerId: 3,
customer_id: 3,
amount: 8945,
status: 'paid',
date: '2023-06-18',
},
{
id: 14,
customerId: 4,
customer_id: 4,
amount: 8945,
status: 'paid',
date: '2023-10-04',
},
{
id: 15,
customerId: 3,
customer_id: 3,
amount: 1000,
status: 'paid',
date: '2022-06-05',
},
];

export const revenue: Revenue[] = [
const revenue = [
{ month: 'Jan', revenue: 2000 },
{ month: 'Feb', revenue: 1800 },
{ month: 'Mar', revenue: 2200 },
Expand All @@ -159,3 +157,10 @@ export const revenue: Revenue[] = [
{ month: 'Nov', revenue: 3000 },
{ month: 'Dec', revenue: 4800 },
];

module.exports = {
users,
customers,
invoices,
revenue,
};
10 changes: 7 additions & 3 deletions dashboard/15-final/app/ui/customers/table.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { customers, invoices } from '@/app/lib/dummy-data';
import {
countCustomerInvoices,
calculateCustomerInvoices,
} from '@/app/lib/calculations';
import { Customer, Invoice } from '@/app/lib/definitions';
import { fetchAllCustomers, fetchAllInvoices } from '@/app/lib/data-fetches';
import Image from 'next/image';

export default function CustomersTable() {
export default async function CustomersTable() {
const invoices = (await fetchAllInvoices()) as Invoice[];
const customers = (await fetchAllCustomers()) as Customer[];

return (
<div className="w-full">
<div className="flex w-full items-center justify-between">
Expand Down Expand Up @@ -42,7 +46,7 @@ export default function CustomersTable() {
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-black sm:pl-6">
<div className="flex items-center gap-3">
<Image
src={customer.imageUrl}
src={customer.image_url}
className="rounded-full"
alt={customer.name}
width={28}
Expand Down
8 changes: 4 additions & 4 deletions dashboard/15-final/app/ui/dashboard/latest-invoices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import { Customer, Invoice } from '@/app/lib/definitions';
import { findLatestInvoices } from '@/app/lib/calculations';
import Image from 'next/image';

export default function LatestInvoices({
export default async function LatestInvoices({
invoices,
customers,
}: {
invoices: Invoice[];
customers: Customer[];
}) {
const lastFiveInvoices = findLatestInvoices(invoices);
const lastFiveInvoices = await findLatestInvoices();

return (
<div className="w-full rounded-xl border p-6 shadow-sm md:col-span-4 lg:col-span-3">
<h2 className="font-semibold">Latest Invoices</h2>

{lastFiveInvoices.map((invoice) => {
const customer = customers.find(
(customer) => customer.id === invoice.customerId,
(customer) => customer.id === invoice.customer_id,
);
return (
<div
Expand All @@ -27,7 +27,7 @@ export default function LatestInvoices({
>
<div className="flex items-center">
<Image
src={customer?.imageUrl || ''}
src={customer?.image_url || ''}
alt={customer?.name || ''}
className="mr-4 rounded-full"
width={32}
Expand Down
Loading
Loading