Update to latest + refactoring.

This commit is contained in:
Lee Robinson
2023-10-06 22:13:22 -05:00
parent 4be9de1269
commit 197ffcd6b9
16 changed files with 368 additions and 2491 deletions

View File

@@ -1,6 +1,4 @@
import NextAuth from 'next-auth';
import { authOptions } from '@/auth';
import { handlers } from '@/auth';
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
const { GET, POST } = handlers;
export { GET, POST };

View File

@@ -1,36 +1,38 @@
import Card from '@/app/ui/dashboard/card';
import { Suspense } from 'react';
import {
CardCollected,
CardPending,
CardTotalInvoices,
CardCustomers,
} from '@/app/ui/dashboard/card';
import RevenueChart from '@/app/ui/dashboard/revenue-chart';
import LatestInvoices from '@/app/ui/dashboard/latest-invoices';
import { lusitana } from '@/app/ui/fonts';
import { fetchCardData } from '@/app/lib/data';
import { Suspense } from 'react';
import {
RevenueChartSkeleton,
LatestInvoicesSkeleton,
CardSkeleton,
} from '@/app/ui/dashboard/skeletons';
export default async function Page() {
const {
numberOfInvoices,
numberOfCustomers,
totalPaidInvoices,
totalPendingInvoices,
} = await fetchCardData();
export default function Page() {
return (
<main>
<h1 className={`${lusitana.className} mb-4 text-xl md:text-2xl`}>
Dashboard
</h1>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
<Card title="Collected" value={totalPaidInvoices} type="collected" />
<Card title="Pending" value={totalPendingInvoices} type="pending" />
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
<Card
title="Total Customers"
value={numberOfCustomers}
type="customers"
/>
<Suspense fallback={<CardSkeleton />}>
<CardCollected />
</Suspense>
<Suspense fallback={<CardSkeleton />}>
<CardPending />
</Suspense>
<Suspense fallback={<CardSkeleton />}>
<CardTotalInvoices />
</Suspense>
<Suspense fallback={<CardSkeleton />}>
<CardCustomers />
</Suspense>
</div>
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
<Suspense fallback={<RevenueChartSkeleton />}>

View File

@@ -12,7 +12,6 @@ export default async function Page({
| undefined;
}) {
const query = searchParams?.query || '';
const customers = await fetchFilteredCustomers(query);
return (

View File

@@ -3,8 +3,9 @@ import { inter } from '@/app/ui/fonts';
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: 'Next.js Dashboard',
description: 'Built as part of nextjs.org/learn.',
metadataBase: new URL('https://next-learn-dashboard.vercel.sh'),
};
export default function RootLayout({

View File

@@ -79,6 +79,54 @@ export async function fetchCardData() {
}
}
export async function fetchInvoices() {
try {
const data = await sql`SELECT COUNT(*) FROM invoices`;
const numberOfInvoices = Number(data.rows[0].count ?? '0');
return {
numberOfInvoices,
};
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to card data.');
}
}
export async function fetchCustomers() {
try {
const data = await sql`SELECT COUNT(*) FROM customers`;
const numberOfCustomers = Number(data.rows[0].count ?? '0');
return {
numberOfCustomers,
};
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to card data.');
}
}
export async function fetchInvoiceStatus() {
try {
const data = await sql`SELECT
SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS "paid",
SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS "pending"
FROM invoices`;
const totalPaidInvoices = formatCurrency(data.rows[0].paid ?? '0');
const totalPendingInvoices = formatCurrency(data.rows[0].pending ?? '0');
return {
totalPaidInvoices,
totalPendingInvoices,
};
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to card data.');
}
}
export async function fetchFilteredInvoices(
query: string,
currentPage: number,
@@ -210,21 +258,21 @@ export async function fetchCustomersTable() {
export async function fetchFilteredCustomers(query: string) {
try {
const data = await sql<CustomersTable>`
SELECT
customers.id,
customers.name,
customers.email,
customers.image_url,
COUNT(invoices.id) AS total_invoices,
SUM(CASE WHEN invoices.status = 'pending' THEN invoices.amount ELSE 0 END) AS total_pending,
SUM(CASE WHEN invoices.status = 'paid' THEN invoices.amount ELSE 0 END) AS total_paid
FROM customers
LEFT JOIN invoices ON customers.id = invoices.customer_id
WHERE
customers.name ILIKE ${`%${query}%`} OR
customers.email ILIKE ${`%${query}%`}
GROUP BY customers.id, customers.name, customers.email, customers.image_url
ORDER BY customers.name ASC
SELECT
customers.id,
customers.name,
customers.email,
customers.image_url,
COUNT(invoices.id) AS total_invoices,
SUM(CASE WHEN invoices.status = 'pending' THEN invoices.amount ELSE 0 END) AS total_pending,
SUM(CASE WHEN invoices.status = 'paid' THEN invoices.amount ELSE 0 END) AS total_paid
FROM customers
LEFT JOIN invoices ON customers.id = invoices.customer_id
WHERE
customers.name ILIKE ${`%${query}%`} OR
customers.email ILIKE ${`%${query}%`}
GROUP BY customers.id, customers.name, customers.email, customers.image_url
ORDER BY customers.name ASC
`;
const customers = data.rows.map((customer) => ({

View File

@@ -1,11 +1,11 @@
import LoginForm from '@/app/ui/login-form';
import { authOptions } from '@/auth';
import { getServerSession } from 'next-auth';
import { auth } from '@/auth';
import { redirect } from 'next/navigation';
export default async function Page() {
const session = await getServerSession(authOptions);
const session = await auth();
if (session) redirect('/dashboard');
return (
<main>
<LoginForm />

View File

@@ -3,6 +3,7 @@ import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
import Link from 'next/link';
export default function Page() {
return (
<main className="flex min-h-screen flex-col p-6">

View File

@@ -5,36 +5,63 @@ import {
InboxIcon,
} from '@heroicons/react/24/outline';
import { lusitana } from '@/app/ui/fonts';
import {
fetchCustomers,
fetchInvoices,
fetchInvoiceStatus,
} from '@/app/lib/data';
const iconMap = {
collected: BanknotesIcon,
customers: UserGroupIcon,
pending: ClockIcon,
invoices: InboxIcon,
};
export async function CardCollected() {
const { numberOfInvoices } = await fetchInvoices();
export default function Card({
return <Card title="Collected">{numberOfInvoices}</Card>;
}
export async function CardPending() {
const { totalPendingInvoices } = await fetchInvoiceStatus();
return <Card title="Pending">{totalPendingInvoices}</Card>;
}
export async function CardTotalInvoices() {
const { totalPaidInvoices } = await fetchInvoiceStatus();
return <Card title="Invoices">{totalPaidInvoices}</Card>;
}
export async function CardCustomers() {
const { numberOfCustomers } = await fetchCustomers();
return <Card title="Customers">{numberOfCustomers}</Card>;
}
function Card({
title,
value,
type,
children,
}: {
title: string;
value: number | string;
type: 'invoices' | 'customers' | 'pending' | 'collected';
children: React.ReactNode;
}) {
const Icon = iconMap[type];
const icons = {
collected: BanknotesIcon,
customers: UserGroupIcon,
pending: ClockIcon,
invoices: InboxIcon,
};
const Icon = icons[title.toLowerCase()];
return (
<div className="rounded-xl bg-gray-50 p-2 shadow-sm">
<div className="flex p-4">
{Icon ? <Icon className="h-5 w-5 text-gray-700" /> : null}
<Icon className="h-5 w-5 text-gray-700" />
<h3 className="ml-2 text-sm font-medium">{title}</h3>
</div>
<p
className={`${lusitana.className}
truncate rounded-xl bg-white px-4 py-8 text-center text-2xl`}
>
{value}
{children}
</p>
</div>
);

View File

@@ -91,9 +91,7 @@ export default function Form({
placeholder="Enter USD amount"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
aria-describedby="amount-error"
style={
{ '-moz-appearance': 'textfield' } as React.CSSProperties
}
style={{ MozAppearance: 'textfield' } as React.CSSProperties}
/>
<CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>

View File

@@ -1,5 +1,7 @@
import { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import NextAuth from 'next-auth';
import type { NextAuthConfig } from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import GitHub from 'next-auth/providers/github';
import bcrypt from 'bcrypt';
import { User } from '@/app/lib/definitions';
import { sql } from '@vercel/postgres';
@@ -14,9 +16,10 @@ async function getUser(email: string) {
}
}
export const authOptions: NextAuthOptions = {
export const authConfig = {
providers: [
CredentialsProvider({
GitHub,
Credentials({
name: 'Sign-In with Credentials',
credentials: {
password: { label: 'Password', type: 'password' },
@@ -46,4 +49,6 @@ export const authOptions: NextAuthOptions = {
pages: {
signIn: '/login',
},
};
} satisfies NextAuthConfig;
export const { handlers, auth, signIn, signOut } = NextAuth(authConfig);

View File

@@ -1,4 +1,6 @@
export { default } from 'next-auth/middleware';
import { auth } from './auth';
export const middleware = auth;
export const config = {
matcher: ['/dashboard/:path*'],

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,4 @@
{
"name": "15-final",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
@@ -12,22 +10,22 @@
"dependencies": {
"@heroicons/react": "^2.0.18",
"@tailwindcss/forms": "^0.5.6",
"@types/node": "20.5.7",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"@vercel/postgres": "^0.4.1",
"autoprefixer": "10.4.15",
"@types/node": "20.8.3",
"@types/react": "18.2.25",
"@types/react-dom": "18.2.11",
"@vercel/postgres": "^0.5.0",
"autoprefixer": "10.4.16",
"bcrypt": "^5.1.1",
"clsx": "^2.0.0",
"next": "^13.5.3",
"next-auth": "^4.23.1",
"next": "13.5.5-canary.4",
"next-auth": "0.0.0-pr.8775.a98a849e",
"postcss": "8.4.31",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2",
"use-debounce": "^9.0.4",
"zod": "^3.22.2"
"zod": "^3.22.4"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2020 Vercel, Inc.
Copyright (c) 2023 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,6 +1,4 @@
{
"name": "15-final",
"version": "0.1.0",
"private": true,
"scripts": {
"lint": "eslint . --ext .cjs,.js,.jsx,.mjs,.ts,.tsx",

272
pnpm-lock.yaml generated
View File

@@ -220,20 +220,20 @@ importers:
specifier: ^0.5.6
version: 0.5.6(tailwindcss@3.3.3)
'@types/node':
specifier: 20.5.7
version: 20.5.7
specifier: 20.8.3
version: 20.8.3
'@types/react':
specifier: 18.2.21
version: 18.2.21
specifier: 18.2.25
version: 18.2.25
'@types/react-dom':
specifier: 18.2.7
version: 18.2.7
specifier: 18.2.11
version: 18.2.11
'@vercel/postgres':
specifier: ^0.4.1
version: 0.4.2
specifier: ^0.5.0
version: 0.5.0
autoprefixer:
specifier: 10.4.15
version: 10.4.15(postcss@8.4.31)
specifier: 10.4.16
version: 10.4.16(postcss@8.4.31)
bcrypt:
specifier: ^5.1.1
version: 5.1.1
@@ -241,11 +241,11 @@ importers:
specifier: ^2.0.0
version: 2.0.0
next:
specifier: ^13.5.3
version: 13.5.3(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0)
specifier: 13.5.5-canary.4
version: 13.5.5-canary.4(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0)
next-auth:
specifier: ^4.23.1
version: 4.23.2(next@13.5.3)(react-dom@18.2.0)(react@18.2.0)
specifier: 0.0.0-pr.8775.a98a849e
version: 0.0.0-pr.8775.a98a849e(next@13.5.5-canary.4)(react-dom@18.2.0)(react@18.2.0)
postcss:
specifier: 8.4.31
version: 8.4.31
@@ -265,8 +265,8 @@ importers:
specifier: ^9.0.4
version: 9.0.4(react@18.2.0)
zod:
specifier: ^3.22.2
version: 3.22.2
specifier: ^3.22.4
version: 3.22.4
devDependencies:
'@types/bcrypt':
specifier: ^5.0.0
@@ -632,8 +632,8 @@ packages:
resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
dev: true
/@neondatabase/serverless@0.5.6:
resolution: {integrity: sha512-Ru0lG6W/nQtHRkDFVQFF+1PJYx8wd3jereln0Ep0YkiHey50hjTLVUycQoE4X977605pXMuFWORweuktzph+Xg==}
/@neondatabase/serverless@0.6.0:
resolution: {integrity: sha512-qXxBRYN0m2v8kVQBfMxbzNGn2xFAhTXFibzQlE++NfJ56Shz3m7+MyBBtXDlEH+3Wfa6lToDXf1MElocY4sJ3w==}
dependencies:
'@types/pg': 8.6.6
dev: false
@@ -646,6 +646,10 @@ packages:
resolution: {integrity: sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ==}
dev: false
/@next/env@13.5.5-canary.4:
resolution: {integrity: sha512-tx4KDZqpizfNEC9w/VLOHvROR8xCajx1Gw5d/lIzdIS68x+vcERWWmmaV8GoDwfF2H+TB7hfMqdOgZ4pnurRzw==}
dev: false
/@next/eslint-plugin-next@13.4.19:
resolution: {integrity: sha512-N/O+zGb6wZQdwu6atMZHbR7T9Np5SUFUjZqCbj0sXm+MwQO35M8TazVB4otm87GkXYs2l6OPwARd3/PUWhZBVQ==}
dependencies:
@@ -670,6 +674,15 @@ packages:
dev: false
optional: true
/@next/swc-darwin-arm64@13.5.5-canary.4:
resolution: {integrity: sha512-BqAx4wV55DmkEYHKijnYv1bt3mPQDAFBwws1E7KiMN0tEJiyhipeBVZTOkpZP5axxLBLV+bhJTOSikVvC2DKrw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@next/swc-darwin-x64@13.5.3:
resolution: {integrity: sha512-UpBKxu2ob9scbpJyEq/xPgpdrgBgN3aLYlxyGqlYX5/KnwpJpFuIHU2lx8upQQ7L+MEmz+fA1XSgesoK92ppwQ==}
engines: {node: '>= 10'}
@@ -688,6 +701,15 @@ packages:
dev: false
optional: true
/@next/swc-darwin-x64@13.5.5-canary.4:
resolution: {integrity: sha512-Lxp+7rSYO+pyWcldy2S2Vh30bgg4w/bS7JoYnnDwTFMwf1IaDaVHsseNedlE56tkkQwZRBy/Q7GS3yE5i6GdmA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@next/swc-linux-arm64-gnu@13.5.3:
resolution: {integrity: sha512-5AzM7Yx1Ky+oLY6pHs7tjONTF22JirDPd5Jw/3/NazJ73uGB05NqhGhB4SbeCchg7SlVYVBeRMrMSZwJwq/xoA==}
engines: {node: '>= 10'}
@@ -706,6 +728,15 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-gnu@13.5.5-canary.4:
resolution: {integrity: sha512-Lm6Uqm/V4J8sJ82YCtq4xOHGXBj54zZ3ldsTNVO8LHqqWsPWX9vYds7CqFrBaKXdsz0bH9f2XkHbjKS0TaO5DQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@next/swc-linux-arm64-musl@13.5.3:
resolution: {integrity: sha512-A/C1shbyUhj7wRtokmn73eBksjTM7fFQoY2v/0rTM5wehpkjQRLOXI8WJsag2uLhnZ4ii5OzR1rFPwoD9cvOgA==}
engines: {node: '>= 10'}
@@ -724,6 +755,15 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-musl@13.5.5-canary.4:
resolution: {integrity: sha512-YQGNStscoM0NEoCZtB4B3PLpJFMGgGiiYwGmd0UTh83KbhrPdPzaQruXvG1WdxAcXHGsMar/lYIrI9H1otGdgw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@next/swc-linux-x64-gnu@13.5.3:
resolution: {integrity: sha512-FubPuw/Boz8tKkk+5eOuDHOpk36F80rbgxlx4+xty/U71e3wZZxVYHfZXmf0IRToBn1Crb8WvLM9OYj/Ur815g==}
engines: {node: '>= 10'}
@@ -742,6 +782,15 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-gnu@13.5.5-canary.4:
resolution: {integrity: sha512-VIno27rSb7WsTgYmlyaH58BroPbLqgeSsSbs0Re2aogb/lb7eJvGP21wIXKt0+LsrTKCbqPvl3raGPdTpjFXQA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@next/swc-linux-x64-musl@13.5.3:
resolution: {integrity: sha512-DPw8nFuM1uEpbX47tM3wiXIR0Qa+atSzs9Q3peY1urkhofx44o7E1svnq+a5Q0r8lAcssLrwiM+OyJJgV/oj7g==}
engines: {node: '>= 10'}
@@ -760,6 +809,15 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-musl@13.5.5-canary.4:
resolution: {integrity: sha512-G8vTuU8r5jeEkjyOTnmLkjXHcN57swr+woe117JKaN2Y7r1xxVEguRNYeE9zmnE2McLq2j27geb3z2uuMY+WRg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@next/swc-win32-arm64-msvc@13.5.3:
resolution: {integrity: sha512-zBPSP8cHL51Gub/YV8UUePW7AVGukp2D8JU93IHbVDu2qmhFAn9LWXiOOLKplZQKxnIPUkJTQAJDCWBWU4UWUA==}
engines: {node: '>= 10'}
@@ -778,6 +836,15 @@ packages:
dev: false
optional: true
/@next/swc-win32-arm64-msvc@13.5.5-canary.4:
resolution: {integrity: sha512-Zxl0365GKr902smRGZEfewLhCg4n23/DLYMfrCPoctMSZl4yn0wOXqxD5+cTIkIGphPeqtUIKXfHdeOwgFJRkw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@next/swc-win32-ia32-msvc@13.5.3:
resolution: {integrity: sha512-ONcL/lYyGUj4W37D4I2I450SZtSenmFAvapkJQNIJhrPMhzDU/AdfLkW98NvH1D2+7FXwe7yclf3+B7v28uzBQ==}
engines: {node: '>= 10'}
@@ -796,6 +863,15 @@ packages:
dev: false
optional: true
/@next/swc-win32-ia32-msvc@13.5.5-canary.4:
resolution: {integrity: sha512-HCysudS8C79Oo05TWAjBpkB0NrYPGSQxvzFURdrOwJQVirF8RpmHpCu6dPOQZdXyubG/8AovMR5JCtQVHPRquQ==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@next/swc-win32-x64-msvc@13.5.3:
resolution: {integrity: sha512-2Vz2tYWaLqJvLcWbbTlJ5k9AN6JD7a5CN2pAeIzpbecK8ZF/yobA39cXtv6e+Z8c5UJuVOmaTldEAIxvsIux/Q==}
engines: {node: '>= 10'}
@@ -814,6 +890,15 @@ packages:
dev: false
optional: true
/@next/swc-win32-x64-msvc@13.5.5-canary.4:
resolution: {integrity: sha512-7bSBhwUtQp/qyScGfyFc89SDIK7C8OPzDoy0ooOj0K8kt26GCFtWfKnyxLkZVw22uHYoBAegDe+D3iPU2rDieg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1:
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
dependencies:
@@ -876,7 +961,7 @@ packages:
/@types/bcrypt@5.0.0:
resolution: {integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==}
dependencies:
'@types/node': 20.5.7
'@types/node': 20.8.3
dev: true
/@types/debug@4.1.9:
@@ -913,8 +998,8 @@ packages:
resolution: {integrity: sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw==}
dev: true
/@types/node@20.5.7:
resolution: {integrity: sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==}
/@types/node@20.8.3:
resolution: {integrity: sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==}
/@types/normalize-package-data@2.4.2:
resolution: {integrity: sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==}
@@ -927,18 +1012,23 @@ packages:
/@types/pg@8.6.6:
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
dependencies:
'@types/node': 20.5.7
'@types/node': 20.8.3
pg-protocol: 1.6.0
pg-types: 2.2.0
dev: false
/@types/prop-types@15.7.7:
resolution: {integrity: sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog==}
dev: true
/@types/react-dom@18.2.7:
resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==}
/@types/prop-types@15.7.8:
resolution: {integrity: sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==}
dev: false
/@types/react-dom@18.2.11:
resolution: {integrity: sha512-zq6Dy0EiCuF9pWFW6I6k6W2LdpUixLE4P6XjXU1QHLfak3GPACQfLwEuHzY5pOYa4hzj1d0GxX/P141aFjZsyg==}
dependencies:
'@types/react': 18.2.21
'@types/react': 18.2.25
dev: false
/@types/react@18.2.21:
@@ -947,6 +1037,15 @@ packages:
'@types/prop-types': 15.7.7
'@types/scheduler': 0.16.4
csstype: 3.1.2
dev: true
/@types/react@18.2.25:
resolution: {integrity: sha512-24xqse6+VByVLIr+xWaQ9muX1B4bXJKXBbjszbld/UEDslGLY53+ZucF44HCmLbMPejTzGG9XgR+3m2/Wqu1kw==}
dependencies:
'@types/prop-types': 15.7.8
'@types/scheduler': 0.16.4
csstype: 3.1.2
dev: false
/@types/scheduler@0.16.4:
resolution: {integrity: sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==}
@@ -1152,14 +1251,14 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/@vercel/postgres@0.4.2:
resolution: {integrity: sha512-jwGBhozSPQBuFVgiXLunpW8iys3qMGyXhTSp7xKVrZjD3hJHunO+i1J6Yq2VP2FNSw36lSg1J2vDzkdOE3303g==}
/@vercel/postgres@0.5.0:
resolution: {integrity: sha512-MFWp9SZmADqBe2x2mzEvwmGLiwOd8PVkUxYeBZx/RqdHl0bd8/1BH0zBR+zSimGyi9P/MVtZoJLdf5dkWw9m5Q==}
engines: {node: '>=14.6'}
dependencies:
'@neondatabase/serverless': 0.5.6
'@neondatabase/serverless': 0.6.0
bufferutil: 4.0.7
utf-8-validate: 6.0.3
ws: 8.14.1(bufferutil@4.0.7)(utf-8-validate@6.0.3)
ws: 8.14.2(bufferutil@4.0.7)(utf-8-validate@6.0.3)
dev: false
/@vercel/style-guide@5.0.1(eslint@8.48.0)(prettier@3.0.3)(typescript@4.9.5):
@@ -1393,15 +1492,15 @@ packages:
has-symbols: 1.0.3
dev: true
/autoprefixer@10.4.15(postcss@8.4.31):
resolution: {integrity: sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==}
/autoprefixer@10.4.16(postcss@8.4.31):
resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.22.1
caniuse-lite: 1.0.30001541
caniuse-lite: 1.0.30001546
fraction.js: 4.3.6
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -1478,8 +1577,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001541
electron-to-chromium: 1.4.536
caniuse-lite: 1.0.30001546
electron-to-chromium: 1.4.544
node-releases: 2.0.13
update-browserslist-db: 1.0.13(browserslist@4.22.1)
@@ -1529,6 +1628,10 @@ packages:
/caniuse-lite@1.0.30001541:
resolution: {integrity: sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==}
dev: false
/caniuse-lite@1.0.30001546:
resolution: {integrity: sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==}
/ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -1653,7 +1756,7 @@ packages:
dev: false
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
/console-control-strings@1.1.0:
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
@@ -1831,8 +1934,8 @@ packages:
engines: {node: '>=12'}
dev: true
/electron-to-chromium@1.4.536:
resolution: {integrity: sha512-L4VgC/76m6y8WVCgnw5kJy/xs7hXrViCFdNKVG8Y7B2isfwrFryFyJzumh3ugxhd/oB1uEaEEvRdmeLrnd7OFA==}
/electron-to-chromium@1.4.544:
resolution: {integrity: sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==}
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1925,7 +2028,7 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.1
has: 1.0.3
has: 1.0.4
has-tostringtag: 1.0.0
dev: true
@@ -2517,6 +2620,7 @@ packages:
/function-bind@1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/function.prototype.name@1.1.6:
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
@@ -2750,6 +2854,11 @@ packages:
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: true
/has@1.0.4:
resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==}
engines: {node: '>= 0.4.0'}
/hast-util-from-parse5@7.1.2:
resolution: {integrity: sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==}
@@ -2915,7 +3024,7 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.1
has: 1.0.3
has: 1.0.4
side-channel: 1.0.4
dev: true
@@ -2990,7 +3099,7 @@ packages:
/is-core-module@2.13.0:
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
dependencies:
has: 1.0.3
has: 1.0.4
/is-date-object@1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
@@ -3189,8 +3298,8 @@ packages:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
dev: true
/jose@4.15.1:
resolution: {integrity: sha512-CinpaEMmwb/59YG0N6SC3DY1imdTU5iNl08HPWR7NdyxACPeFuQbqjaocEjCDGq04KbnxSqQu702vL3ZTvKe5w==}
/jose@4.15.2:
resolution: {integrity: sha512-IY73F228OXRl9ar3jJagh7Vnuhj/GzBunPiZP13K0lOl7Am9SoWW3kEzq3MCllJMTtZqHTiDXQvoRd4U95aU6A==}
dev: false
/js-tokens@4.0.0:
@@ -3704,8 +3813,8 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
/next-auth@4.23.2(next@13.5.3)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-VRmInu0r/yZNFQheDFeOKtiugu3bt90Po3owAQDnFQ3YLQFmUKgFjcE2+3L0ny5jsJpBXaKbm7j7W2QTc6Ye2A==}
/next-auth@0.0.0-pr.8775.a98a849e(next@13.5.5-canary.4)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-bPi6hzs3LCNYvm7m6vTzB8bvRqiI6ZPh9C5URVpg4fwakOgZLmOla3sLJ8umqPHKNpeNnyICuqy5NL/0khpHAA==}
peerDependencies:
next: ^12.2.5 || ^13
nodemailer: ^6.6.5
@@ -3718,12 +3827,12 @@ packages:
'@babel/runtime': 7.23.1
'@panva/hkdf': 1.1.1
cookie: 0.5.0
jose: 4.15.1
next: 13.5.3(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0)
jose: 4.15.2
next: 13.5.5-canary.4(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0)
oauth: 0.9.15
openid-client: 5.5.0
preact: 10.18.1
preact-render-to-string: 5.2.6(preact@10.18.1)
openid-client: 5.6.0
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
uuid: 8.3.2
@@ -3787,7 +3896,7 @@ packages:
'@next/env': 13.5.4
'@swc/helpers': 0.5.2
busboy: 1.6.0
caniuse-lite: 1.0.30001541
caniuse-lite: 1.0.30001546
postcss: 8.4.31
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -3808,6 +3917,45 @@ packages:
- babel-plugin-macros
dev: false
/next@13.5.5-canary.4(@babel/core@7.23.0)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-a07Akh5WtCXRY/indnpTU21ccXPqEAVrzVueHpcgOq55gRnmYWle7dF/qrBzAlvrldoLG7bzQKNt0AaG2inNWg==}
engines: {node: '>=16.14.0'}
hasBin: true
peerDependencies:
'@opentelemetry/api': ^1.1.0
react: ^18.2.0
react-dom: ^18.2.0
sass: ^1.3.0
peerDependenciesMeta:
'@opentelemetry/api':
optional: true
sass:
optional: true
dependencies:
'@next/env': 13.5.5-canary.4
'@swc/helpers': 0.5.2
busboy: 1.6.0
caniuse-lite: 1.0.30001546
postcss: 8.4.31
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
styled-jsx: 5.1.1(@babel/core@7.23.0)(react@18.2.0)
watchpack: 2.4.0
optionalDependencies:
'@next/swc-darwin-arm64': 13.5.5-canary.4
'@next/swc-darwin-x64': 13.5.5-canary.4
'@next/swc-linux-arm64-gnu': 13.5.5-canary.4
'@next/swc-linux-arm64-musl': 13.5.5-canary.4
'@next/swc-linux-x64-gnu': 13.5.5-canary.4
'@next/swc-linux-x64-musl': 13.5.5-canary.4
'@next/swc-win32-arm64-msvc': 13.5.5-canary.4
'@next/swc-win32-ia32-msvc': 13.5.5-canary.4
'@next/swc-win32-x64-msvc': 13.5.5-canary.4
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
dev: false
/node-addon-api@5.1.0:
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
dev: false
@@ -3996,10 +4144,10 @@ packages:
is-wsl: 2.2.0
dev: true
/openid-client@5.5.0:
resolution: {integrity: sha512-Y7Xl8BgsrkzWLHkVDYuroM67hi96xITyEDSkmWaGUiNX6CkcXC3XyQGdv5aWZ6dukVKBFVQCADi9gCavOmU14w==}
/openid-client@5.6.0:
resolution: {integrity: sha512-uFTkN/iqgKvSnmpVAS/T6SNThukRMBcmymTQ71Ngus1F60tdtKVap7zCrleocY+fogPtpmoxi5Q1YdrgYuTlkA==}
dependencies:
jose: 4.15.1
jose: 4.15.2
lru-cache: 6.0.0
object-hash: 2.2.0
oidc-token-hash: 5.0.3
@@ -4252,17 +4400,17 @@ packages:
xtend: 4.0.2
dev: false
/preact-render-to-string@5.2.6(preact@10.18.1):
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
/preact-render-to-string@5.2.3(preact@10.11.3):
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
peerDependencies:
preact: '>=10'
dependencies:
preact: 10.18.1
preact: 10.11.3
pretty-format: 3.8.0
dev: false
/preact@10.18.1:
resolution: {integrity: sha512-mKUD7RRkQQM6s7Rkmi7IFkoEHjuFqRQUaXamO61E6Nn7vqF/bo7EZCmSyrUnp2UWHw0O7XjZ2eeXis+m7tf4lg==}
/preact@10.11.3:
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
dev: false
/prelude-ls@1.2.1:
@@ -5379,8 +5527,8 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/ws@8.14.1(bufferutil@4.0.7)(utf-8-validate@6.0.3):
resolution: {integrity: sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==}
/ws@8.14.2(bufferutil@4.0.7)(utf-8-validate@6.0.3):
resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -5420,8 +5568,8 @@ packages:
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
dev: false
/zod@3.22.2:
resolution: {integrity: sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==}
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false
/zwitch@2.0.4: