├── .gitignore ├── README.md ├── app ├── dashboard │ ├── (overview) │ │ ├── loading.tsx │ │ └── page.tsx │ ├── customers │ │ └── page.tsx │ ├── invoices │ │ └── page.tsx │ ├── layout.tsx │ ├── loading.tsx │ └── page.tsx ├── layout.tsx ├── lib │ ├── data.ts │ ├── definitions.ts │ ├── placeholder-data.ts │ └── utils.ts ├── page.tsx ├── query │ └── route.ts ├── seed │ └── route.ts └── ui │ ├── acme-logo.tsx │ ├── button.tsx │ ├── customers │ └── table.tsx │ ├── dashboard │ ├── cards.tsx │ ├── latest-invoices.tsx │ ├── nav-links.tsx │ ├── revenue-chart.tsx │ └── sidenav.tsx │ ├── fonts.ts │ ├── global.css │ ├── home.module.css │ ├── invoices │ ├── breadcrumbs.tsx │ ├── buttons.tsx │ ├── create-form.tsx │ ├── edit-form.tsx │ ├── pagination.tsx │ ├── status.tsx │ └── table.tsx │ ├── login-form.tsx │ ├── search.tsx │ └── skeletons.tsx ├── next.config.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── customers │ ├── amy-burns.png │ ├── balazs-orban.png │ ├── delba-de-oliveira.png │ ├── evil-rabbit.png │ ├── lee-robinson.png │ └── michael-novotny.png ├── favicon.ico ├── hero-desktop.png ├── hero-mobile.png └── opengraph-image.png ├── tailwind.config.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | .env 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ifo-aka/NextJsandVercel context](https://badge.forgithub.com/ifo-aka/NextJsandVercel)](https://uithub.com/ifo-aka/NextJsandVercel) 2 | -------------------------------------------------------------------------------- /app/dashboard/(overview)/loading.tsx: -------------------------------------------------------------------------------- 1 | import DashboardSkeleton from "@/app/ui/skeletons"; 2 | 3 | export default function Loading() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /app/dashboard/(overview)/page.tsx: -------------------------------------------------------------------------------- 1 | import CardWrapper from '@/app/ui/dashboard/cards'; 2 | import RevenueChart from '@/app/ui/dashboard/revenue-chart'; 3 | import LatestInvoices from '@/app/ui/dashboard/latest-invoices'; 4 | import { lusitana } from '@/app/ui/fonts'; 5 | 6 | import { Suspense } from 'react'; 7 | import { RevenueChartSkeleton ,LatestInvoicesSkeleton,CardSkeleton } from '@/app/ui/skeletons'; 8 | 9 | export default async function Page() { 10 | 11 | 12 | return ( 13 |
14 |

15 | Dashboard 16 |

17 |
18 | }> 19 | 20 | 21 | 22 |
23 |
24 | }> 25 | 26 | 27 | }> 28 | 29 | 30 |
31 |
32 | ); 33 | } -------------------------------------------------------------------------------- /app/dashboard/customers/page.tsx: -------------------------------------------------------------------------------- 1 | export default function page(){ 2 | return

customer page

3 | } -------------------------------------------------------------------------------- /app/dashboard/invoices/page.tsx: -------------------------------------------------------------------------------- 1 | import Pagination from '@/app/ui/invoices/pagination'; 2 | import Search from '@/app/ui/search'; 3 | import Table from '@/app/ui/invoices/table'; 4 | import { CreateInvoice } from '@/app/ui/invoices/buttons'; 5 | import { lusitana } from '@/app/ui/fonts'; 6 | import { InvoicesTableSkeleton } from '@/app/ui/skeletons'; 7 | import { Suspense } from 'react'; 8 | import { fetchInvoicesPages } from '@/app/lib/data'; 9 | 10 | export default async function Page(props: { 11 | searchParams?: Promise<{ 12 | query?: string; 13 | page?: string; 14 | }>; 15 | }) { 16 | const searchParams = await props.searchParams; 17 | const query = searchParams?.query || ''; 18 | const currentPage = Number(searchParams?.page) || 1; 19 | const totalPages = await fetchInvoicesPages(query); 20 | return ( 21 |
22 |
23 |

Invoices

24 |
25 |
26 | 27 | 28 |
29 | }> 30 | 31 | 32 |
33 | 34 |
35 | 36 | ); 37 | } -------------------------------------------------------------------------------- /app/dashboard/layout.tsx: -------------------------------------------------------------------------------- 1 | import SideNav from '@/app/ui/dashboard/sidenav'; 2 | export const experimental_ppr = true; 3 | 4 | export default function Layout({ children }: { children: React.ReactNode }) { 5 | return ( 6 |
7 |
8 | 9 |
10 |
{children}
11 |
12 | ); 13 | } -------------------------------------------------------------------------------- /app/dashboard/loading.tsx: -------------------------------------------------------------------------------- 1 | import DashboardSkeleton from "../ui/skeletons"; 2 | 3 | export default function Loading() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /app/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | import CardWrapper from '../ui/dashboard/cards'; 2 | import RevenueChart from '@/app/ui/dashboard/revenue-chart'; 3 | import LatestInvoices from '@/app/ui/dashboard/latest-invoices'; 4 | import { lusitana } from '@/app/ui/fonts'; 5 | 6 | import { Suspense } from 'react'; 7 | import { RevenueChartSkeleton ,LatestInvoicesSkeleton,CardSkeleton} from '../ui/skeletons'; 8 | 9 | export default async function Page() { 10 | 11 | 12 | return ( 13 |
14 |

15 | Dashboard 16 |

17 |
18 | }> 19 | 20 | 21 |
22 |
23 | }> 24 | 25 | 26 | }> 27 | 28 | 29 | 30 |
31 |
32 | ); 33 | } -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@/app/ui/global.css'; 2 | import {inter} from '@/app/ui/fonts'; 3 | export default function RootLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode; 7 | }) { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /app/lib/data.ts: -------------------------------------------------------------------------------- 1 | import postgres from 'postgres'; 2 | import { 3 | CustomerField, 4 | CustomersTableType, 5 | InvoiceForm, 6 | InvoicesTable, 7 | LatestInvoiceRaw, 8 | Revenue, 9 | } from './definitions'; 10 | import { formatCurrency } from './utils'; 11 | 12 | const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); 13 | 14 | export async function fetchRevenue() { 15 | try { 16 | // Artificially delay a response for demo purposes. 17 | // Don't do this in production :) 18 | 19 | console.log('Fetching revenue data...'); 20 | 21 | 22 | const data = await sql`SELECT * FROM revenue`; 23 | console.log('Data fetch completed.'); 24 | 25 | return data; 26 | } catch (error) { 27 | console.error('Database Error:', error); 28 | throw new Error('Failed to fetch revenue data.'); 29 | } 30 | } 31 | 32 | export async function fetchLatestInvoices() { 33 | try { 34 | const data = await sql` 35 | SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id 36 | FROM invoices 37 | JOIN customers ON invoices.customer_id = customers.id 38 | ORDER BY invoices.date DESC 39 | LIMIT 5`; 40 | 41 | const latestInvoices = data.map((invoice) => ({ 42 | ...invoice, 43 | amount: formatCurrency(invoice.amount), 44 | })); 45 | return latestInvoices; 46 | } catch (error) { 47 | console.error('Database Error:', error); 48 | throw new Error('Failed to fetch the latest invoices.'); 49 | } 50 | } 51 | 52 | export async function fetchCardData() { 53 | try { 54 | // You can probably combine these into a single SQL query 55 | // However, we are intentionally splitting them to demonstrate 56 | // how to initialize multiple queries in parallel with JS. 57 | const invoiceCountPromise = sql`SELECT COUNT(*) FROM invoices`; 58 | const customerCountPromise = sql`SELECT COUNT(*) FROM customers`; 59 | const invoiceStatusPromise = sql`SELECT 60 | SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS "paid", 61 | SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS "pending" 62 | FROM invoices`; 63 | 64 | const data = await Promise.all([ 65 | invoiceCountPromise, 66 | customerCountPromise, 67 | invoiceStatusPromise, 68 | ]); 69 | 70 | const numberOfInvoices = Number(data[0][0].count ?? '0'); 71 | const numberOfCustomers = Number(data[1][0].count ?? '0'); 72 | const totalPaidInvoices = formatCurrency(data[2][0].paid ?? '0'); 73 | const totalPendingInvoices = formatCurrency(data[2][0].pending ?? '0'); 74 | 75 | return { 76 | numberOfCustomers, 77 | numberOfInvoices, 78 | totalPaidInvoices, 79 | totalPendingInvoices, 80 | }; 81 | } catch (error) { 82 | console.error('Database Error:', error); 83 | throw new Error('Failed to fetch card data.'); 84 | } 85 | } 86 | 87 | const ITEMS_PER_PAGE = 6; 88 | export async function fetchFilteredInvoices( 89 | query: string, 90 | currentPage: number, 91 | ) { 92 | const offset = (currentPage - 1) * ITEMS_PER_PAGE; 93 | 94 | try { 95 | const invoices = await sql` 96 | SELECT 97 | invoices.id, 98 | invoices.amount, 99 | invoices.date, 100 | invoices.status, 101 | customers.name, 102 | customers.email, 103 | customers.image_url 104 | FROM invoices 105 | JOIN customers ON invoices.customer_id = customers.id 106 | WHERE 107 | customers.name ILIKE ${`%${query}%`} OR 108 | customers.email ILIKE ${`%${query}%`} OR 109 | invoices.amount::text ILIKE ${`%${query}%`} OR 110 | invoices.date::text ILIKE ${`%${query}%`} OR 111 | invoices.status ILIKE ${`%${query}%`} 112 | ORDER BY invoices.date DESC 113 | LIMIT ${ITEMS_PER_PAGE} OFFSET ${offset} 114 | `; 115 | 116 | return invoices; 117 | } catch (error) { 118 | console.error('Database Error:', error); 119 | throw new Error('Failed to fetch invoices.'); 120 | } 121 | } 122 | 123 | export async function fetchInvoicesPages(query: string) { 124 | try { 125 | const data = await sql`SELECT COUNT(*) 126 | FROM invoices 127 | JOIN customers ON invoices.customer_id = customers.id 128 | WHERE 129 | customers.name ILIKE ${`%${query}%`} OR 130 | customers.email ILIKE ${`%${query}%`} OR 131 | invoices.amount::text ILIKE ${`%${query}%`} OR 132 | invoices.date::text ILIKE ${`%${query}%`} OR 133 | invoices.status ILIKE ${`%${query}%`} 134 | `; 135 | 136 | const totalPages = Math.ceil(Number(data[0].count) / ITEMS_PER_PAGE); 137 | return totalPages; 138 | } catch (error) { 139 | console.error('Database Error:', error); 140 | throw new Error('Failed to fetch total number of invoices.'); 141 | } 142 | } 143 | 144 | export async function fetchInvoiceById(id: string) { 145 | try { 146 | const data = await sql` 147 | SELECT 148 | invoices.id, 149 | invoices.customer_id, 150 | invoices.amount, 151 | invoices.status 152 | FROM invoices 153 | WHERE invoices.id = ${id}; 154 | `; 155 | 156 | const invoice = data.map((invoice) => ({ 157 | ...invoice, 158 | // Convert amount from cents to dollars 159 | amount: invoice.amount / 100, 160 | })); 161 | 162 | return invoice[0]; 163 | } catch (error) { 164 | console.error('Database Error:', error); 165 | throw new Error('Failed to fetch invoice.'); 166 | } 167 | } 168 | 169 | export async function fetchCustomers() { 170 | try { 171 | const customers = await sql` 172 | SELECT 173 | id, 174 | name 175 | FROM customers 176 | ORDER BY name ASC 177 | `; 178 | 179 | return customers; 180 | } catch (err) { 181 | console.error('Database Error:', err); 182 | throw new Error('Failed to fetch all customers.'); 183 | } 184 | } 185 | 186 | export async function fetchFilteredCustomers(query: string) { 187 | try { 188 | const data = await sql` 189 | SELECT 190 | customers.id, 191 | customers.name, 192 | customers.email, 193 | customers.image_url, 194 | COUNT(invoices.id) AS total_invoices, 195 | SUM(CASE WHEN invoices.status = 'pending' THEN invoices.amount ELSE 0 END) AS total_pending, 196 | SUM(CASE WHEN invoices.status = 'paid' THEN invoices.amount ELSE 0 END) AS total_paid 197 | FROM customers 198 | LEFT JOIN invoices ON customers.id = invoices.customer_id 199 | WHERE 200 | customers.name ILIKE ${`%${query}%`} OR 201 | customers.email ILIKE ${`%${query}%`} 202 | GROUP BY customers.id, customers.name, customers.email, customers.image_url 203 | ORDER BY customers.name ASC 204 | `; 205 | 206 | const customers = data.map((customer) => ({ 207 | ...customer, 208 | total_pending: formatCurrency(customer.total_pending), 209 | total_paid: formatCurrency(customer.total_paid), 210 | })); 211 | 212 | return customers; 213 | } catch (err) { 214 | console.error('Database Error:', err); 215 | throw new Error('Failed to fetch customer table.'); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /app/lib/definitions.ts: -------------------------------------------------------------------------------- 1 | // This file contains type definitions for your data. 2 | // It describes the shape of the data, and what data type each property should accept. 3 | // For simplicity of teaching, we're manually defining these types. 4 | // However, these types are generated automatically if you're using an ORM such as Prisma. 5 | export type User = { 6 | id: string; 7 | name: string; 8 | email: string; 9 | password: string; 10 | }; 11 | 12 | export type Customer = { 13 | id: string; 14 | name: string; 15 | email: string; 16 | image_url: string; 17 | }; 18 | 19 | export type Invoice = { 20 | id: string; 21 | customer_id: string; 22 | amount: number; 23 | date: string; 24 | // In TypeScript, this is called a string union type. 25 | // It means that the "status" property can only be one of the two strings: 'pending' or 'paid'. 26 | status: 'pending' | 'paid'; 27 | }; 28 | 29 | export type Revenue = { 30 | month: string; 31 | revenue: number; 32 | }; 33 | 34 | export type LatestInvoice = { 35 | id: string; 36 | name: string; 37 | image_url: string; 38 | email: string; 39 | amount: string; 40 | }; 41 | 42 | // The database returns a number for amount, but we later format it to a string with the formatCurrency function 43 | export type LatestInvoiceRaw = Omit & { 44 | amount: number; 45 | }; 46 | 47 | export type InvoicesTable = { 48 | id: string; 49 | customer_id: string; 50 | name: string; 51 | email: string; 52 | image_url: string; 53 | date: string; 54 | amount: number; 55 | status: 'pending' | 'paid'; 56 | }; 57 | 58 | export type CustomersTableType = { 59 | id: string; 60 | name: string; 61 | email: string; 62 | image_url: string; 63 | total_invoices: number; 64 | total_pending: number; 65 | total_paid: number; 66 | }; 67 | 68 | export type FormattedCustomersTable = { 69 | id: string; 70 | name: string; 71 | email: string; 72 | image_url: string; 73 | total_invoices: number; 74 | total_pending: string; 75 | total_paid: string; 76 | }; 77 | 78 | export type CustomerField = { 79 | id: string; 80 | name: string; 81 | }; 82 | 83 | export type InvoiceForm = { 84 | id: string; 85 | customer_id: string; 86 | amount: number; 87 | status: 'pending' | 'paid'; 88 | }; 89 | -------------------------------------------------------------------------------- /app/lib/placeholder-data.ts: -------------------------------------------------------------------------------- 1 | // This file contains placeholder data that you'll be replacing with real data in the Data Fetching chapter: 2 | // https://nextjs.org/learn/dashboard-app/fetching-data 3 | const users = [ 4 | { 5 | id: '410544b2-4001-4271-9855-fec4b6a6442a', 6 | name: 'User', 7 | email: 'user@nextmail.com', 8 | password: '123456', 9 | }, 10 | ]; 11 | 12 | const customers = [ 13 | { 14 | id: 'd6e15727-9fe1-4961-8c5b-ea44a9bd81aa', 15 | name: 'Evil Rabbit', 16 | email: 'evil@rabbit.com', 17 | image_url: '/customers/evil-rabbit.png', 18 | }, 19 | { 20 | id: '3958dc9e-712f-4377-85e9-fec4b6a6442a', 21 | name: 'Delba de Oliveira', 22 | email: 'delba@oliveira.com', 23 | image_url: '/customers/delba-de-oliveira.png', 24 | }, 25 | { 26 | id: '3958dc9e-742f-4377-85e9-fec4b6a6442a', 27 | name: 'Lee Robinson', 28 | email: 'lee@robinson.com', 29 | image_url: '/customers/lee-robinson.png', 30 | }, 31 | { 32 | id: '76d65c26-f784-44a2-ac19-586678f7c2f2', 33 | name: 'Michael Novotny', 34 | email: 'michael@novotny.com', 35 | image_url: '/customers/michael-novotny.png', 36 | }, 37 | { 38 | id: 'CC27C14A-0ACF-4F4A-A6C9-D45682C144B9', 39 | name: 'Amy Burns', 40 | email: 'amy@burns.com', 41 | image_url: '/customers/amy-burns.png', 42 | }, 43 | { 44 | id: '13D07535-C59E-4157-A011-F8D2EF4E0CBB', 45 | name: 'Balazs Orban', 46 | email: 'balazs@orban.com', 47 | image_url: '/customers/balazs-orban.png', 48 | }, 49 | ]; 50 | 51 | const invoices = [ 52 | { 53 | customer_id: customers[0].id, 54 | amount: 15795, 55 | status: 'pending', 56 | date: '2022-12-06', 57 | }, 58 | { 59 | customer_id: customers[1].id, 60 | amount: 20348, 61 | status: 'pending', 62 | date: '2022-11-14', 63 | }, 64 | { 65 | customer_id: customers[4].id, 66 | amount: 3040, 67 | status: 'paid', 68 | date: '2022-10-29', 69 | }, 70 | { 71 | customer_id: customers[3].id, 72 | amount: 44800, 73 | status: 'paid', 74 | date: '2023-09-10', 75 | }, 76 | { 77 | customer_id: customers[5].id, 78 | amount: 34577, 79 | status: 'pending', 80 | date: '2023-08-05', 81 | }, 82 | { 83 | customer_id: customers[2].id, 84 | amount: 54246, 85 | status: 'pending', 86 | date: '2023-07-16', 87 | }, 88 | { 89 | customer_id: customers[0].id, 90 | amount: 666, 91 | status: 'pending', 92 | date: '2023-06-27', 93 | }, 94 | { 95 | customer_id: customers[3].id, 96 | amount: 32545, 97 | status: 'paid', 98 | date: '2023-06-09', 99 | }, 100 | { 101 | customer_id: customers[4].id, 102 | amount: 1250, 103 | status: 'paid', 104 | date: '2023-06-17', 105 | }, 106 | { 107 | customer_id: customers[5].id, 108 | amount: 8546, 109 | status: 'paid', 110 | date: '2023-06-07', 111 | }, 112 | { 113 | customer_id: customers[1].id, 114 | amount: 500, 115 | status: 'paid', 116 | date: '2023-08-19', 117 | }, 118 | { 119 | customer_id: customers[5].id, 120 | amount: 8945, 121 | status: 'paid', 122 | date: '2023-06-03', 123 | }, 124 | { 125 | customer_id: customers[2].id, 126 | amount: 1000, 127 | status: 'paid', 128 | date: '2022-06-05', 129 | }, 130 | ]; 131 | 132 | const revenue = [ 133 | { month: 'Jan', revenue: 2000 }, 134 | { month: 'Feb', revenue: 1800 }, 135 | { month: 'Mar', revenue: 2200 }, 136 | { month: 'Apr', revenue: 2500 }, 137 | { month: 'May', revenue: 2300 }, 138 | { month: 'Jun', revenue: 3200 }, 139 | { month: 'Jul', revenue: 3500 }, 140 | { month: 'Aug', revenue: 3700 }, 141 | { month: 'Sep', revenue: 2500 }, 142 | { month: 'Oct', revenue: 2800 }, 143 | { month: 'Nov', revenue: 3000 }, 144 | { month: 'Dec', revenue: 4800 }, 145 | ]; 146 | 147 | export { users, customers, invoices, revenue }; 148 | -------------------------------------------------------------------------------- /app/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { Revenue } from './definitions'; 2 | 3 | export const formatCurrency = (amount: number) => { 4 | return (amount / 100).toLocaleString('en-US', { 5 | style: 'currency', 6 | currency: 'USD', 7 | }); 8 | }; 9 | 10 | export const formatDateToLocal = ( 11 | dateStr: string, 12 | locale: string = 'en-US', 13 | ) => { 14 | const date = new Date(dateStr); 15 | const options: Intl.DateTimeFormatOptions = { 16 | day: 'numeric', 17 | month: 'short', 18 | year: 'numeric', 19 | }; 20 | const formatter = new Intl.DateTimeFormat(locale, options); 21 | return formatter.format(date); 22 | }; 23 | 24 | export const generateYAxis = (revenue: Revenue[]) => { 25 | // Calculate what labels we need to display on the y-axis 26 | // based on highest record and in 1000s 27 | const yAxisLabels = []; 28 | const highestRecord = Math.max(...revenue.map((month) => month.revenue)); 29 | const topLabel = Math.ceil(highestRecord / 1000) * 1000; 30 | 31 | for (let i = topLabel; i >= 0; i -= 1000) { 32 | yAxisLabels.push(`$${i / 1000}K`); 33 | } 34 | 35 | return { yAxisLabels, topLabel }; 36 | }; 37 | 38 | export const generatePagination = (currentPage: number, totalPages: number) => { 39 | // If the total number of pages is 7 or less, 40 | // display all pages without any ellipsis. 41 | if (totalPages <= 7) { 42 | return Array.from({ length: totalPages }, (_, i) => i + 1); 43 | } 44 | 45 | // If the current page is among the first 3 pages, 46 | // show the first 3, an ellipsis, and the last 2 pages. 47 | if (currentPage <= 3) { 48 | return [1, 2, 3, '...', totalPages - 1, totalPages]; 49 | } 50 | 51 | // If the current page is among the last 3 pages, 52 | // show the first 2, an ellipsis, and the last 3 pages. 53 | if (currentPage >= totalPages - 2) { 54 | return [1, 2, '...', totalPages - 2, totalPages - 1, totalPages]; 55 | } 56 | 57 | // If the current page is somewhere in the middle, 58 | // show the first page, an ellipsis, the current page and its neighbors, 59 | // another ellipsis, and the last page. 60 | return [ 61 | 1, 62 | '...', 63 | currentPage - 1, 64 | currentPage, 65 | currentPage + 1, 66 | '...', 67 | totalPages, 68 | ]; 69 | }; 70 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import AcmeLogo from '@/app/ui/acme-logo'; 2 | import { ArrowRightIcon } from '@heroicons/react/24/outline'; 3 | import Link from 'next/link'; 4 | import styles from '@/app/ui/home.module.css' 5 | import {lusitana} from '@/app/ui/fonts'; 6 | import Image from 'next/image'; 7 | 8 | export default function Page() { 9 | return ( 10 |
11 |
12 | 13 |
14 |
15 |
16 |

17 | Welcome to Acme. This is the example for the{' '} 18 | 19 | Next.js Learn Course 20 | 21 | , brought to you by Vercel. 22 |

23 |
25 | 29 | Log in 30 | 31 |
32 |
33 | {/* Add Hero Images Here */} 34 | 41 | 48 |
49 |
50 |
51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /app/query/route.ts: -------------------------------------------------------------------------------- 1 | import postgres from 'postgres'; 2 | 3 | const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); 4 | 5 | async function listInvoices() { 6 | const data = await sql` 7 | SELECT invoices.amount, customers.name 8 | FROM invoices 9 | JOIN customers ON invoices.customer_id = customers.id 10 | WHERE invoices.amount = 666; 11 | `; 12 | 13 | return data; 14 | } 15 | 16 | export async function GET() { 17 | try { 18 | return Response.json(await listInvoices()); 19 | } catch (error) { 20 | return Response.json({ error }, { status: 500 }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/seed/route.ts: -------------------------------------------------------------------------------- 1 | import bcrypt from 'bcrypt'; 2 | import postgres from 'postgres'; 3 | import { invoices, customers, revenue, users } from '../lib/placeholder-data'; 4 | 5 | const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); 6 | 7 | async function seedUsers() { 8 | await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`; 9 | await sql` 10 | CREATE TABLE IF NOT EXISTS users ( 11 | id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, 12 | name VARCHAR(255) NOT NULL, 13 | email TEXT NOT NULL UNIQUE, 14 | password TEXT NOT NULL 15 | ); 16 | `; 17 | 18 | const insertedUsers = await Promise.all( 19 | users.map(async (user) => { 20 | const hashedPassword = await bcrypt.hash(user.password, 10); 21 | return sql` 22 | INSERT INTO users (id, name, email, password) 23 | VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword}) 24 | ON CONFLICT (id) DO NOTHING; 25 | `; 26 | }), 27 | ); 28 | 29 | return insertedUsers; 30 | } 31 | 32 | async function seedInvoices() { 33 | await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`; 34 | 35 | await sql` 36 | CREATE TABLE IF NOT EXISTS invoices ( 37 | id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, 38 | customer_id UUID NOT NULL, 39 | amount INT NOT NULL, 40 | status VARCHAR(255) NOT NULL, 41 | date DATE NOT NULL 42 | ); 43 | `; 44 | 45 | const insertedInvoices = await Promise.all( 46 | invoices.map( 47 | (invoice) => sql` 48 | INSERT INTO invoices (customer_id, amount, status, date) 49 | VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date}) 50 | ON CONFLICT (id) DO NOTHING; 51 | `, 52 | ), 53 | ); 54 | 55 | return insertedInvoices; 56 | } 57 | 58 | async function seedCustomers() { 59 | await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`; 60 | 61 | await sql` 62 | CREATE TABLE IF NOT EXISTS customers ( 63 | id UUID DEFAULT uuid_generate_v4() PRIMARY KEY, 64 | name VARCHAR(255) NOT NULL, 65 | email VARCHAR(255) NOT NULL, 66 | image_url VARCHAR(255) NOT NULL 67 | ); 68 | `; 69 | 70 | const insertedCustomers = await Promise.all( 71 | customers.map( 72 | (customer) => sql` 73 | INSERT INTO customers (id, name, email, image_url) 74 | VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url}) 75 | ON CONFLICT (id) DO NOTHING; 76 | `, 77 | ), 78 | ); 79 | 80 | return insertedCustomers; 81 | } 82 | 83 | async function seedRevenue() { 84 | await sql` 85 | CREATE TABLE IF NOT EXISTS revenue ( 86 | month VARCHAR(4) NOT NULL UNIQUE, 87 | revenue INT NOT NULL 88 | ); 89 | `; 90 | 91 | const insertedRevenue = await Promise.all( 92 | revenue.map( 93 | (rev) => sql` 94 | INSERT INTO revenue (month, revenue) 95 | VALUES (${rev.month}, ${rev.revenue}) 96 | ON CONFLICT (month) DO NOTHING; 97 | `, 98 | ), 99 | ); 100 | 101 | return insertedRevenue; 102 | } 103 | 104 | export async function GET() { 105 | try { 106 | const result = await sql.begin((sql) => [ 107 | seedUsers(), 108 | seedCustomers(), 109 | seedInvoices(), 110 | seedRevenue(), 111 | ]); 112 | 113 | return Response.json({ message: 'Database seeded successfully' }); 114 | } catch (error) { 115 | return Response.json({ error }, { status: 500 }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/ui/acme-logo.tsx: -------------------------------------------------------------------------------- 1 | import { GlobeAltIcon } from '@heroicons/react/24/outline'; 2 | import { lusitana } from '@/app/ui/fonts'; 3 | 4 | export default function AcmeLogo() { 5 | return ( 6 |
9 | 10 |

Acme

11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /app/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | 3 | interface ButtonProps extends React.ButtonHTMLAttributes { 4 | children: React.ReactNode; 5 | } 6 | 7 | export function Button({ children, className, ...rest }: ButtonProps) { 8 | return ( 9 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /app/ui/customers/table.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import { lusitana } from '@/app/ui/fonts'; 3 | import Search from '@/app/ui/search'; 4 | import { 5 | CustomersTableType, 6 | FormattedCustomersTable, 7 | } from '@/app/lib/definitions'; 8 | 9 | export default async function CustomersTable({ 10 | customers, 11 | }: { 12 | customers: FormattedCustomersTable[]; 13 | }) { 14 | return ( 15 |
16 |

17 | Customers 18 |

19 | 20 |
21 |
22 |
23 |
24 |
25 | {customers?.map((customer) => ( 26 |
30 |
31 |
32 |
33 |
34 | 41 |

{customer.name}

42 |
43 |
44 |

45 | {customer.email} 46 |

47 |
48 |
49 |
50 |
51 |

Pending

52 |

{customer.total_pending}

53 |
54 |
55 |

Paid

56 |

{customer.total_paid}

57 |
58 |
59 |
60 |

{customer.total_invoices} invoices

61 |
62 |
63 | ))} 64 |
65 |
66 | 67 | 68 | 71 | 74 | 77 | 80 | 83 | 84 | 85 | 86 | 87 | {customers.map((customer) => ( 88 | 89 | 101 | 104 | 107 | 110 | 113 | 114 | ))} 115 | 116 |
69 | Name 70 | 72 | Email 73 | 75 | Total Invoices 76 | 78 | Total Pending 79 | 81 | Total Paid 82 |
90 |
91 | {`${customer.name}'s 98 |

{customer.name}

99 |
100 |
102 | {customer.email} 103 | 105 | {customer.total_invoices} 106 | 108 | {customer.total_pending} 109 | 111 | {customer.total_paid} 112 |
117 |
118 | 119 | 120 | 121 | 122 | ); 123 | } 124 | -------------------------------------------------------------------------------- /app/ui/dashboard/cards.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | BanknotesIcon, 3 | ClockIcon, 4 | UserGroupIcon, 5 | InboxIcon, 6 | } from '@heroicons/react/24/outline'; 7 | import { fetchCardData } from '@/app/lib/data'; 8 | import { lusitana } from '@/app/ui/fonts'; 9 | 10 | const iconMap = { 11 | collected: BanknotesIcon, 12 | customers: UserGroupIcon, 13 | pending: ClockIcon, 14 | invoices: InboxIcon, 15 | }; 16 | 17 | export default async function CardWrapper() { 18 | const { 19 | totalPaidInvoices, 20 | totalPendingInvoices, 21 | numberOfInvoices, 22 | numberOfCustomers 23 | } = await fetchCardData(); 24 | 25 | return ( 26 | <> 27 | {/* NOTE: Uncomment this code in Chapter 9 */} 28 | 29 | 30 | 31 | 32 | 37 | 38 | ); 39 | } 40 | 41 | export function Card({ 42 | title, 43 | value, 44 | type, 45 | }: { 46 | title: string; 47 | value: number | string; 48 | type: 'invoices' | 'customers' | 'pending' | 'collected'; 49 | }) { 50 | const Icon = iconMap[type]; 51 | 52 | return ( 53 |
54 |
55 | {Icon ? : null} 56 |

{title}

57 |
58 |

62 | {value} 63 |

64 |
65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /app/ui/dashboard/latest-invoices.tsx: -------------------------------------------------------------------------------- 1 | import { ArrowPathIcon } from '@heroicons/react/24/outline'; 2 | import clsx from 'clsx'; 3 | import Image from 'next/image'; 4 | import { lusitana } from '@/app/ui/fonts'; 5 | 6 | import { fetchLatestInvoices } from '@/app/lib/data'; 7 | export default async function LatestInvoices() { 8 | const latestInvoices = await fetchLatestInvoices(); 9 | return ( 10 |
11 |

12 | Latest Invoices 13 |

14 |
15 | {/* NOTE: Uncomment this code in Chapter 7 */} 16 | 17 |
18 | {latestInvoices.map((invoice, i) => { 19 | return ( 20 |
29 |
30 | {`${invoice.name}'s 37 |
38 |

39 | {invoice.name} 40 |

41 |

42 | {invoice.email} 43 |

44 |
45 |
46 |

49 | {invoice.amount} 50 |

51 |
52 | ); 53 | })} 54 |
55 |
56 | 57 |

Updated just now

58 |
59 |
60 |
61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /app/ui/dashboard/nav-links.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { 3 | UserGroupIcon, 4 | HomeIcon, 5 | DocumentDuplicateIcon, 6 | } from '@heroicons/react/24/outline'; 7 | import Link from 'next/link'; 8 | import { usePathname } from 'next/navigation'; 9 | import clsx from 'clsx'; 10 | // Map of links to display in the side navigation. 11 | // Depending on the size of the application, this would be stored in a database. 12 | 13 | const links = [ 14 | { name: 'Home', href: '/dashboard', icon: HomeIcon }, 15 | { 16 | name: 'Invoices', 17 | href: '/dashboard/invoices', 18 | icon: DocumentDuplicateIcon, 19 | }, 20 | { name: 'Customers', href: '/dashboard/customers', icon: UserGroupIcon }, 21 | ]; 22 | 23 | export default function NavLinks() { 24 | const pathName = usePathname(); 25 | 26 | return ( 27 | <> 28 | {links.map((link) => { 29 | const LinkIcon = link.icon; 30 | return ( 31 | 40 | 41 |

{link.name}

42 | 43 | ); 44 | })} 45 | 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /app/ui/dashboard/revenue-chart.tsx: -------------------------------------------------------------------------------- 1 | import { generateYAxis } from '@/app/lib/utils'; 2 | import { CalendarIcon } from '@heroicons/react/24/outline'; 3 | import { lusitana } from '@/app/ui/fonts'; 4 | import { Revenue } from '@/app/lib/definitions'; 5 | import { fetchRevenue } from '@/app/lib/data'; 6 | 7 | // This component is representational only. 8 | // For data visualization UI, check out: 9 | // https://www.tremor.so/ 10 | // https://www.chartjs.org/ 11 | // https://airbnb.io/visx/ 12 | 13 | export default async function RevenueChart() { 14 | const revenue =await fetchRevenue(); 15 | const chartHeight = 350; 16 | // NOTE: Uncomment this code in Chapter 7 17 | 18 | const { yAxisLabels, topLabel } = generateYAxis(revenue); 19 | 20 | if (!revenue || revenue.length === 0) { 21 | return

No data available.

; 22 | } 23 | 24 | return ( 25 |
26 |

27 | Recent Revenue 28 |

29 | {/* NOTE: Uncomment this code in Chapter 7 */} 30 | 31 |
32 |
33 |
37 | {yAxisLabels.map((label) => ( 38 |

{label}

39 | ))} 40 |
41 | 42 | {revenue.map((month) => ( 43 |
44 |
50 |

51 | {month.month} 52 |

53 |
54 | ))} 55 |
56 |
57 | 58 |

Last 12 months

59 |
60 |
61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /app/ui/dashboard/sidenav.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import NavLinks from '@/app/ui/dashboard/nav-links'; 3 | import AcmeLogo from '@/app/ui/acme-logo'; 4 | import { PowerIcon } from '@heroicons/react/24/outline'; 5 | 6 | 7 | export default function SideNav() { 8 | return ( 9 |
10 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 |
22 | 26 |
27 |
28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /app/ui/fonts.ts: -------------------------------------------------------------------------------- 1 | // app/ui/fonts.ts 2 | import { Inter,Lusitana } from 'next/font/google'; 3 | 4 | export const inter = Inter({ 5 | subsets: ['latin'], 6 | }); 7 | export const lusitana = Lusitana({ weight: ['400', '700'], subsets: ['latin'] }); -------------------------------------------------------------------------------- /app/ui/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | input[type='number'] { 6 | -moz-appearance: textfield; 7 | appearance: textfield; 8 | } 9 | 10 | input[type='number']::-webkit-inner-spin-button { 11 | -webkit-appearance: none; 12 | margin: 0; 13 | } 14 | 15 | input[type='number']::-webkit-outer-spin-button { 16 | -webkit-appearance: none; 17 | margin: 0; 18 | } 19 | -------------------------------------------------------------------------------- /app/ui/home.module.css: -------------------------------------------------------------------------------- 1 | .shape { 2 | height: 0; 3 | width: 0; 4 | border-bottom: 30px solid black; 5 | border-left: 20px solid transparent; 6 | border-right: 20px solid transparent; 7 | } -------------------------------------------------------------------------------- /app/ui/invoices/breadcrumbs.tsx: -------------------------------------------------------------------------------- 1 | import { clsx } from 'clsx'; 2 | import Link from 'next/link'; 3 | import { lusitana } from '@/app/ui/fonts'; 4 | 5 | interface Breadcrumb { 6 | label: string; 7 | href: string; 8 | active?: boolean; 9 | } 10 | 11 | export default function Breadcrumbs({ 12 | breadcrumbs, 13 | }: { 14 | breadcrumbs: Breadcrumb[]; 15 | }) { 16 | return ( 17 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /app/ui/invoices/buttons.tsx: -------------------------------------------------------------------------------- 1 | import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; 2 | import Link from 'next/link'; 3 | 4 | export function CreateInvoice() { 5 | return ( 6 | 10 | Create Invoice{' '} 11 | 12 | 13 | ); 14 | } 15 | 16 | export function UpdateInvoice({ id }: { id: string }) { 17 | return ( 18 | 22 | 23 | 24 | ); 25 | } 26 | 27 | export function DeleteInvoice({ id }: { id: string }) { 28 | return ( 29 | <> 30 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /app/ui/invoices/create-form.tsx: -------------------------------------------------------------------------------- 1 | import { CustomerField } from '@/app/lib/definitions'; 2 | import Link from 'next/link'; 3 | import { 4 | CheckIcon, 5 | ClockIcon, 6 | CurrencyDollarIcon, 7 | UserCircleIcon, 8 | } from '@heroicons/react/24/outline'; 9 | import { Button } from '@/app/ui/button'; 10 | 11 | export default function Form({ customers }: { customers: CustomerField[] }) { 12 | return ( 13 |
14 |
15 | {/* Customer Name */} 16 |
17 | 20 |
21 | 36 | 37 |
38 |
39 | 40 | {/* Invoice Amount */} 41 |
42 | 45 |
46 |
47 | 55 | 56 |
57 |
58 |
59 | 60 | {/* Invoice Status */} 61 |
62 | 63 | Set the invoice status 64 | 65 |
66 |
67 |
68 | 75 | 81 |
82 |
83 | 90 | 96 |
97 |
98 |
99 |
100 |
101 |
102 | 106 | Cancel 107 | 108 | 109 |
110 |
111 | ); 112 | } 113 | -------------------------------------------------------------------------------- /app/ui/invoices/edit-form.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { CustomerField, InvoiceForm } from '@/app/lib/definitions'; 4 | import { 5 | CheckIcon, 6 | ClockIcon, 7 | CurrencyDollarIcon, 8 | UserCircleIcon, 9 | } from '@heroicons/react/24/outline'; 10 | import Link from 'next/link'; 11 | import { Button } from '@/app/ui/button'; 12 | 13 | export default function EditInvoiceForm({ 14 | invoice, 15 | customers, 16 | }: { 17 | invoice: InvoiceForm; 18 | customers: CustomerField[]; 19 | }) { 20 | return ( 21 |
22 |
23 | {/* Customer Name */} 24 |
25 | 28 |
29 | 44 | 45 |
46 |
47 | 48 | {/* Invoice Amount */} 49 |
50 | 53 |
54 |
55 | 64 | 65 |
66 |
67 |
68 | 69 | {/* Invoice Status */} 70 |
71 | 72 | Set the invoice status 73 | 74 |
75 |
76 |
77 | 85 | 91 |
92 |
93 | 101 | 107 |
108 |
109 |
110 |
111 |
112 |
113 | 117 | Cancel 118 | 119 | 120 |
121 |
122 | ); 123 | } 124 | -------------------------------------------------------------------------------- /app/ui/invoices/pagination.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; 4 | import clsx from 'clsx'; 5 | import Link from 'next/link'; 6 | import { generatePagination } from '@/app/lib/utils'; 7 | import { usePathname, useSearchParams } from 'next/navigation'; 8 | 9 | export default function Pagination({ totalPages }: { totalPages: number }) { 10 | const searchParams = useSearchParams(); 11 | const pathname = usePathname(); 12 | const currentPage = Number(searchParams.get('page')) || 1; 13 | 14 | const createPageURL = (pageNumber: number | string) => { 15 | const params = new URLSearchParams(searchParams); 16 | params.set('page', pageNumber.toString()); 17 | return `${pathname}?${params.toString()}`; 18 | }; 19 | // NOTE: Uncomment this code in Chapter 11 20 | 21 | const allPages = generatePagination(currentPage, totalPages); 22 | 23 | return ( 24 | <> 25 | {/* NOTE: Uncomment this code in Chapter 11 */} 26 | 27 |
28 | 33 | 34 |
35 | {allPages.map((page, index) => { 36 | let position: 'first' | 'last' | 'single' | 'middle' | undefined; 37 | 38 | if (index === 0) position = 'first'; 39 | if (index === allPages.length - 1) position = 'last'; 40 | if (allPages.length === 1) position = 'single'; 41 | if (page === '...') position = 'middle'; 42 | 43 | return ( 44 | 51 | ); 52 | })} 53 |
54 | 55 | = totalPages} 59 | /> 60 |
61 | 62 | ); 63 | } 64 | 65 | function PaginationNumber({ 66 | page, 67 | href, 68 | isActive, 69 | position, 70 | }: { 71 | page: number | string; 72 | href: string; 73 | position?: 'first' | 'last' | 'middle' | 'single'; 74 | isActive: boolean; 75 | }) { 76 | const className = clsx( 77 | 'flex h-10 w-10 items-center justify-center text-sm border', 78 | { 79 | 'rounded-l-md': position === 'first' || position === 'single', 80 | 'rounded-r-md': position === 'last' || position === 'single', 81 | 'z-10 bg-blue-600 border-blue-600 text-white': isActive, 82 | 'hover:bg-gray-100': !isActive && position !== 'middle', 83 | 'text-gray-300': position === 'middle', 84 | }, 85 | ); 86 | 87 | return isActive || position === 'middle' ? ( 88 |
{page}
89 | ) : ( 90 | 91 | {page} 92 | 93 | ); 94 | } 95 | 96 | function PaginationArrow({ 97 | href, 98 | direction, 99 | isDisabled, 100 | }: { 101 | href: string; 102 | direction: 'left' | 'right'; 103 | isDisabled?: boolean; 104 | }) { 105 | const className = clsx( 106 | 'flex h-10 w-10 items-center justify-center rounded-md border', 107 | { 108 | 'pointer-events-none text-gray-300': isDisabled, 109 | 'hover:bg-gray-100': !isDisabled, 110 | 'mr-2 md:mr-4': direction === 'left', 111 | 'ml-2 md:ml-4': direction === 'right', 112 | }, 113 | ); 114 | 115 | const icon = 116 | direction === 'left' ? ( 117 | 118 | ) : ( 119 | 120 | ); 121 | 122 | return isDisabled ? ( 123 |
{icon}
124 | ) : ( 125 | 126 | {icon} 127 | 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /app/ui/invoices/status.tsx: -------------------------------------------------------------------------------- 1 | import { CheckIcon, ClockIcon } from '@heroicons/react/24/outline'; 2 | import clsx from 'clsx'; 3 | 4 | export default function InvoiceStatus({ status }: { status: string }) { 5 | return ( 6 | 15 | {status === 'pending' ? ( 16 | <> 17 | Pending 18 | 19 | 20 | ) : null} 21 | {status === 'paid' ? ( 22 | <> 23 | Paid 24 | 25 | 26 | ) : null} 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /app/ui/invoices/table.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import { UpdateInvoice, DeleteInvoice } from '@/app/ui/invoices/buttons'; 3 | import InvoiceStatus from '@/app/ui/invoices/status'; 4 | import { formatDateToLocal, formatCurrency } from '@/app/lib/utils'; 5 | import { fetchFilteredInvoices } from '@/app/lib/data'; 6 | 7 | export default async function InvoicesTable({ 8 | query, 9 | currentPage, 10 | }: { 11 | query: string; 12 | currentPage: number; 13 | }) { 14 | const invoices = await fetchFilteredInvoices(query, currentPage); 15 | 16 | return ( 17 |
18 |
19 |
20 |
21 | {invoices?.map((invoice) => ( 22 |
26 |
27 |
28 |
29 | {`${invoice.name}'s 36 |

{invoice.name}

37 |
38 |

{invoice.email}

39 |
40 | 41 |
42 |
43 |
44 |

45 | {formatCurrency(invoice.amount)} 46 |

47 |

{formatDateToLocal(invoice.date)}

48 |
49 |
50 | 51 | 52 |
53 |
54 |
55 | ))} 56 |
57 | 58 | 59 | 60 | 63 | 66 | 69 | 72 | 75 | 78 | 79 | 80 | 81 | {invoices?.map((invoice) => ( 82 | 86 | 98 | 101 | 104 | 107 | 110 | 116 | 117 | ))} 118 | 119 |
61 | Customer 62 | 64 | Email 65 | 67 | Amount 68 | 70 | Date 71 | 73 | Status 74 | 76 | Edit 77 |
87 |
88 | {`${invoice.name}'s 95 |

{invoice.name}

96 |
97 |
99 | {invoice.email} 100 | 102 | {formatCurrency(invoice.amount)} 103 | 105 | {formatDateToLocal(invoice.date)} 106 | 108 | 109 | 111 |
112 | 113 | 114 |
115 |
120 |
121 |
122 |
123 | ); 124 | } 125 | -------------------------------------------------------------------------------- /app/ui/login-form.tsx: -------------------------------------------------------------------------------- 1 | import { lusitana } from '@/app/ui/fonts'; 2 | import { 3 | AtSymbolIcon, 4 | KeyIcon, 5 | ExclamationCircleIcon, 6 | } from '@heroicons/react/24/outline'; 7 | import { ArrowRightIcon } from '@heroicons/react/20/solid'; 8 | import { Button } from './button'; 9 | 10 | export default function LoginForm() { 11 | return ( 12 |
13 |
14 |

15 | Please log in to continue. 16 |

17 |
18 |
19 | 25 |
26 | 34 | 35 |
36 |
37 |
38 | 44 |
45 | 54 | 55 |
56 |
57 |
58 | 61 |
62 | {/* Add form errors here */} 63 |
64 |
65 |
66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /app/ui/search.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; 4 | import { useSearchParams,usePathname,useRouter } from 'next/navigation'; 5 | import {useDebouncedCallback} from 'use-debounce'; 6 | 7 | export default function Search({ placeholder }: { placeholder: string }) { 8 | const searchParams = useSearchParams(); 9 | const pathname = usePathname(); 10 | const { replace } = useRouter(); 11 | 12 | const handleSearch = useDebouncedCallback((term) => { 13 | console.log(`Searching... ${term}`); 14 | 15 | const params = new URLSearchParams(searchParams); 16 | params.set('page', '1'); // Reset to first page on new search 17 | if (term) { 18 | params.set('query', term); 19 | } else { 20 | params.delete('query'); 21 | } 22 | replace(`${pathname}?${params.toString()}`); 23 | }, 500); 24 | return ( 25 |
26 | 29 | { 33 | handleSearch(e.target.value); 34 | }} 35 | defaultValue={searchParams.get('query')?.toString()} 36 | /> 37 | 38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /app/ui/skeletons.tsx: -------------------------------------------------------------------------------- 1 | // Loading animation 2 | const shimmer = 3 | 'before:absolute before:inset-0 before:-translate-x-full before:animate-[shimmer_2s_infinite] before:bg-gradient-to-r before:from-transparent before:via-white/60 before:to-transparent'; 4 | 5 | export function CardSkeleton() { 6 | return ( 7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ); 19 | } 20 | 21 | export function CardsSkeleton() { 22 | return ( 23 | <> 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export function RevenueChartSkeleton() { 33 | return ( 34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | ); 45 | } 46 | 47 | export function InvoiceSkeleton() { 48 | return ( 49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | ); 60 | } 61 | 62 | export function LatestInvoicesSkeleton() { 63 | return ( 64 |
67 |
68 |
69 |
70 | 71 | 72 | 73 | 74 | 75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | ); 83 | } 84 | 85 | export default function DashboardSkeleton() { 86 | return ( 87 | <> 88 |
91 |
92 | 93 | 94 | 95 | 96 |
97 |
98 | 99 | 100 |
101 | 102 | ); 103 | } 104 | 105 | export function TableRowSkeleton() { 106 | return ( 107 | 108 | {/* Customer Name and Image */} 109 | 110 |
111 |
112 |
113 |
114 | 115 | {/* Email */} 116 | 117 |
118 | 119 | {/* Amount */} 120 | 121 |
122 | 123 | {/* Date */} 124 | 125 |
126 | 127 | {/* Status */} 128 | 129 |
130 | 131 | {/* Actions */} 132 | 133 |
134 |
135 |
136 |
137 | 138 | 139 | ); 140 | } 141 | 142 | export function InvoicesMobileSkeleton() { 143 | return ( 144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | ); 164 | } 165 | 166 | export function InvoicesTableSkeleton() { 167 | return ( 168 |
169 |
170 |
171 |
172 | 173 | 174 | 175 | 176 | 177 | 178 |
179 | 180 | 181 | 182 | 185 | 188 | 191 | 194 | 197 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 |
183 | Customer 184 | 186 | Email 187 | 189 | Amount 190 | 192 | Date 193 | 195 | Status 196 | 201 | Edit 202 |
214 |
215 |
216 |
217 | ); 218 | } 219 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next'; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | experimental: { 6 | ppr: 'incremental', 7 | }, 8 | }; 9 | 10 | export default nextConfig; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "next build", 5 | "dev": "next dev --turbopack", 6 | "start": "next start" 7 | }, 8 | "dependencies": { 9 | "@heroicons/react": "^2.2.0", 10 | "@tailwindcss/forms": "^0.5.10", 11 | "autoprefixer": "10.4.20", 12 | "bcrypt": "^5.1.1", 13 | "clsx": "^2.1.1", 14 | "next": "15.4.2-canary.51", 15 | "next-auth": "5.0.0-beta.25", 16 | "postcss": "8.5.1", 17 | "postgres": "^3.4.6", 18 | "react": "latest", 19 | "react-dom": "latest", 20 | "tailwindcss": "3.4.17", 21 | "typescript": "5.7.3", 22 | "use-debounce": "^10.0.4", 23 | "zod": "^3.25.17" 24 | }, 25 | "devDependencies": { 26 | "@types/bcrypt": "^5.0.2", 27 | "@types/node": "22.10.7", 28 | "@types/react": "19.0.7", 29 | "@types/react-dom": "19.0.3" 30 | }, 31 | "pnpm": { 32 | "onlyBuiltDependencies": [ 33 | "bcrypt", 34 | "sharp" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@heroicons/react': 12 | specifier: ^2.2.0 13 | version: 2.2.0(react@19.1.0) 14 | '@tailwindcss/forms': 15 | specifier: ^0.5.10 16 | version: 0.5.10(tailwindcss@3.4.17) 17 | autoprefixer: 18 | specifier: 10.4.20 19 | version: 10.4.20(postcss@8.5.1) 20 | bcrypt: 21 | specifier: ^5.1.1 22 | version: 5.1.1 23 | clsx: 24 | specifier: ^2.1.1 25 | version: 2.1.1 26 | next: 27 | specifier: 15.4.2-canary.51 28 | version: 15.4.2-canary.51(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 29 | next-auth: 30 | specifier: 5.0.0-beta.25 31 | version: 5.0.0-beta.25(next@15.4.2-canary.51(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) 32 | postcss: 33 | specifier: 8.5.1 34 | version: 8.5.1 35 | postgres: 36 | specifier: ^3.4.6 37 | version: 3.4.6 38 | react: 39 | specifier: latest 40 | version: 19.1.0 41 | react-dom: 42 | specifier: latest 43 | version: 19.1.0(react@19.1.0) 44 | tailwindcss: 45 | specifier: 3.4.17 46 | version: 3.4.17 47 | typescript: 48 | specifier: 5.7.3 49 | version: 5.7.3 50 | use-debounce: 51 | specifier: ^10.0.4 52 | version: 10.0.4(react@19.1.0) 53 | zod: 54 | specifier: ^3.25.17 55 | version: 3.25.17 56 | devDependencies: 57 | '@types/bcrypt': 58 | specifier: ^5.0.2 59 | version: 5.0.2 60 | '@types/node': 61 | specifier: 22.10.7 62 | version: 22.10.7 63 | '@types/react': 64 | specifier: 19.0.7 65 | version: 19.0.7 66 | '@types/react-dom': 67 | specifier: 19.0.3 68 | version: 19.0.3(@types/react@19.0.7) 69 | 70 | packages: 71 | 72 | '@alloc/quick-lru@5.2.0': 73 | resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} 74 | engines: {node: '>=10'} 75 | 76 | '@auth/core@0.37.2': 77 | resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==} 78 | peerDependencies: 79 | '@simplewebauthn/browser': ^9.0.1 80 | '@simplewebauthn/server': ^9.0.2 81 | nodemailer: ^6.8.0 82 | peerDependenciesMeta: 83 | '@simplewebauthn/browser': 84 | optional: true 85 | '@simplewebauthn/server': 86 | optional: true 87 | nodemailer: 88 | optional: true 89 | 90 | '@emnapi/runtime@1.4.5': 91 | resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} 92 | 93 | '@heroicons/react@2.2.0': 94 | resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} 95 | peerDependencies: 96 | react: '>= 16 || ^19.0.0-rc' 97 | 98 | '@img/sharp-darwin-arm64@0.34.3': 99 | resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} 100 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 101 | cpu: [arm64] 102 | os: [darwin] 103 | 104 | '@img/sharp-darwin-x64@0.34.3': 105 | resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} 106 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 107 | cpu: [x64] 108 | os: [darwin] 109 | 110 | '@img/sharp-libvips-darwin-arm64@1.2.0': 111 | resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} 112 | cpu: [arm64] 113 | os: [darwin] 114 | 115 | '@img/sharp-libvips-darwin-x64@1.2.0': 116 | resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} 117 | cpu: [x64] 118 | os: [darwin] 119 | 120 | '@img/sharp-libvips-linux-arm64@1.2.0': 121 | resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} 122 | cpu: [arm64] 123 | os: [linux] 124 | 125 | '@img/sharp-libvips-linux-arm@1.2.0': 126 | resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} 127 | cpu: [arm] 128 | os: [linux] 129 | 130 | '@img/sharp-libvips-linux-ppc64@1.2.0': 131 | resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} 132 | cpu: [ppc64] 133 | os: [linux] 134 | 135 | '@img/sharp-libvips-linux-s390x@1.2.0': 136 | resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} 137 | cpu: [s390x] 138 | os: [linux] 139 | 140 | '@img/sharp-libvips-linux-x64@1.2.0': 141 | resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} 142 | cpu: [x64] 143 | os: [linux] 144 | 145 | '@img/sharp-libvips-linuxmusl-arm64@1.2.0': 146 | resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} 147 | cpu: [arm64] 148 | os: [linux] 149 | 150 | '@img/sharp-libvips-linuxmusl-x64@1.2.0': 151 | resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} 152 | cpu: [x64] 153 | os: [linux] 154 | 155 | '@img/sharp-linux-arm64@0.34.3': 156 | resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} 157 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 158 | cpu: [arm64] 159 | os: [linux] 160 | 161 | '@img/sharp-linux-arm@0.34.3': 162 | resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} 163 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 164 | cpu: [arm] 165 | os: [linux] 166 | 167 | '@img/sharp-linux-ppc64@0.34.3': 168 | resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} 169 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 170 | cpu: [ppc64] 171 | os: [linux] 172 | 173 | '@img/sharp-linux-s390x@0.34.3': 174 | resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} 175 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 176 | cpu: [s390x] 177 | os: [linux] 178 | 179 | '@img/sharp-linux-x64@0.34.3': 180 | resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} 181 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 182 | cpu: [x64] 183 | os: [linux] 184 | 185 | '@img/sharp-linuxmusl-arm64@0.34.3': 186 | resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} 187 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 188 | cpu: [arm64] 189 | os: [linux] 190 | 191 | '@img/sharp-linuxmusl-x64@0.34.3': 192 | resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} 193 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 194 | cpu: [x64] 195 | os: [linux] 196 | 197 | '@img/sharp-wasm32@0.34.3': 198 | resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} 199 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 200 | cpu: [wasm32] 201 | 202 | '@img/sharp-win32-arm64@0.34.3': 203 | resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} 204 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 205 | cpu: [arm64] 206 | os: [win32] 207 | 208 | '@img/sharp-win32-ia32@0.34.3': 209 | resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} 210 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 211 | cpu: [ia32] 212 | os: [win32] 213 | 214 | '@img/sharp-win32-x64@0.34.3': 215 | resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} 216 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 217 | cpu: [x64] 218 | os: [win32] 219 | 220 | '@isaacs/cliui@8.0.2': 221 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 222 | engines: {node: '>=12'} 223 | 224 | '@jridgewell/gen-mapping@0.3.8': 225 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 226 | engines: {node: '>=6.0.0'} 227 | 228 | '@jridgewell/resolve-uri@3.1.2': 229 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 230 | engines: {node: '>=6.0.0'} 231 | 232 | '@jridgewell/set-array@1.2.1': 233 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 234 | engines: {node: '>=6.0.0'} 235 | 236 | '@jridgewell/sourcemap-codec@1.5.0': 237 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 238 | 239 | '@jridgewell/trace-mapping@0.3.25': 240 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 241 | 242 | '@mapbox/node-pre-gyp@1.0.11': 243 | resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} 244 | hasBin: true 245 | 246 | '@next/env@15.4.2-canary.51': 247 | resolution: {integrity: sha512-xiO1sTeqYlXaa39tTUe7KsWAe/9Fzg9zjVsHUDgfO8wl+5hN7sE9sxZLSw2+or2s85ozaU4g2loIJTBpOX8ROg==} 248 | 249 | '@next/swc-darwin-arm64@15.4.2-canary.51': 250 | resolution: {integrity: sha512-9wKXXuJGQuNlNFrHdsSXMMEWA4zlXs7I2AcNk8MEQZbLIhaqE4pAyoLcXIyHWfbU+rQM49zAsRNF8jGkVxVKSw==} 251 | engines: {node: '>= 10'} 252 | cpu: [arm64] 253 | os: [darwin] 254 | 255 | '@next/swc-darwin-x64@15.4.2-canary.51': 256 | resolution: {integrity: sha512-MlR5N02MF/XL56MeLLkmGre8cAmWbHVeJkdj+Sjf6DVirT3NPzGfZNsj3MOq5fDy0O1Z0gKdTxrFndU4bSN91g==} 257 | engines: {node: '>= 10'} 258 | cpu: [x64] 259 | os: [darwin] 260 | 261 | '@next/swc-linux-arm64-gnu@15.4.2-canary.51': 262 | resolution: {integrity: sha512-iR8XYOUC0MWXIbW+gN8MRoI/yPb4HfccHGkVgz7hQsGgOTm33NqO01Bf1abm7ezhLpNHdw5oukLwGsQM3VdYkw==} 263 | engines: {node: '>= 10'} 264 | cpu: [arm64] 265 | os: [linux] 266 | 267 | '@next/swc-linux-arm64-musl@15.4.2-canary.51': 268 | resolution: {integrity: sha512-JALxctWDmZeUeb37tbphg1o4VSnzOvFanJMDDhlzcCogE/uKhyCBVcoUKb1Ifc1dQv2O47ow24PGUU4xOJZAAw==} 269 | engines: {node: '>= 10'} 270 | cpu: [arm64] 271 | os: [linux] 272 | 273 | '@next/swc-linux-x64-gnu@15.4.2-canary.51': 274 | resolution: {integrity: sha512-cJlwlNLQ6aQfzjjMRmPPA40ozrxpiXeNzflHlYPYDvr7OMNVWsg4JnKZsQudlldDZ6jcXaOpmru4u+LXkjAulg==} 275 | engines: {node: '>= 10'} 276 | cpu: [x64] 277 | os: [linux] 278 | 279 | '@next/swc-linux-x64-musl@15.4.2-canary.51': 280 | resolution: {integrity: sha512-bIvIPAC5bLjtqPuHyxifx524xBK0HelgqZKsXhGQM3mVBfIxGt1E78KYSRdGPDoZba8+i0TtgEsz7oH+FJnWpQ==} 281 | engines: {node: '>= 10'} 282 | cpu: [x64] 283 | os: [linux] 284 | 285 | '@next/swc-win32-arm64-msvc@15.4.2-canary.51': 286 | resolution: {integrity: sha512-wfa1TYSGMiSR2HgRfvQMa5p/Mw+J9DfYsTy/qxZucXq8mbbb7W2FFvYMjYBd9gMe0mBsiailrEWU9fq2g2qlUQ==} 287 | engines: {node: '>= 10'} 288 | cpu: [arm64] 289 | os: [win32] 290 | 291 | '@next/swc-win32-x64-msvc@15.4.2-canary.51': 292 | resolution: {integrity: sha512-XBlsGCdEW/MTvy0Zpn/2O43Gs60ZvKgkTgN2gT+BYkGLHGVyM8BpkMbaOpMocsk8rGgndZnqJFaGLoFBZZMNrQ==} 293 | engines: {node: '>= 10'} 294 | cpu: [x64] 295 | os: [win32] 296 | 297 | '@nodelib/fs.scandir@2.1.5': 298 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 299 | engines: {node: '>= 8'} 300 | 301 | '@nodelib/fs.stat@2.0.5': 302 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 303 | engines: {node: '>= 8'} 304 | 305 | '@nodelib/fs.walk@1.2.8': 306 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 307 | engines: {node: '>= 8'} 308 | 309 | '@panva/hkdf@1.2.1': 310 | resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} 311 | 312 | '@pkgjs/parseargs@0.11.0': 313 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 314 | engines: {node: '>=14'} 315 | 316 | '@swc/helpers@0.5.15': 317 | resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} 318 | 319 | '@tailwindcss/forms@0.5.10': 320 | resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} 321 | peerDependencies: 322 | tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' 323 | 324 | '@types/bcrypt@5.0.2': 325 | resolution: {integrity: sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==} 326 | 327 | '@types/cookie@0.6.0': 328 | resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} 329 | 330 | '@types/node@22.10.7': 331 | resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} 332 | 333 | '@types/react-dom@19.0.3': 334 | resolution: {integrity: sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==} 335 | peerDependencies: 336 | '@types/react': ^19.0.0 337 | 338 | '@types/react@19.0.7': 339 | resolution: {integrity: sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==} 340 | 341 | abbrev@1.1.1: 342 | resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} 343 | 344 | agent-base@6.0.2: 345 | resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} 346 | engines: {node: '>= 6.0.0'} 347 | 348 | ansi-regex@5.0.1: 349 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 350 | engines: {node: '>=8'} 351 | 352 | ansi-regex@6.1.0: 353 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 354 | engines: {node: '>=12'} 355 | 356 | ansi-styles@4.3.0: 357 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 358 | engines: {node: '>=8'} 359 | 360 | ansi-styles@6.2.1: 361 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 362 | engines: {node: '>=12'} 363 | 364 | any-promise@1.3.0: 365 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 366 | 367 | anymatch@3.1.3: 368 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 369 | engines: {node: '>= 8'} 370 | 371 | aproba@2.0.0: 372 | resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} 373 | 374 | are-we-there-yet@2.0.0: 375 | resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} 376 | engines: {node: '>=10'} 377 | deprecated: This package is no longer supported. 378 | 379 | arg@5.0.2: 380 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 381 | 382 | autoprefixer@10.4.20: 383 | resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} 384 | engines: {node: ^10 || ^12 || >=14} 385 | hasBin: true 386 | peerDependencies: 387 | postcss: ^8.1.0 388 | 389 | balanced-match@1.0.2: 390 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 391 | 392 | bcrypt@5.1.1: 393 | resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} 394 | engines: {node: '>= 10.0.0'} 395 | 396 | binary-extensions@2.3.0: 397 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 398 | engines: {node: '>=8'} 399 | 400 | brace-expansion@1.1.11: 401 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 402 | 403 | brace-expansion@2.0.1: 404 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 405 | 406 | braces@3.0.3: 407 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 408 | engines: {node: '>=8'} 409 | 410 | browserslist@4.24.5: 411 | resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} 412 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 413 | hasBin: true 414 | 415 | camelcase-css@2.0.1: 416 | resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 417 | engines: {node: '>= 6'} 418 | 419 | caniuse-lite@1.0.30001718: 420 | resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} 421 | 422 | chokidar@3.6.0: 423 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 424 | engines: {node: '>= 8.10.0'} 425 | 426 | chownr@2.0.0: 427 | resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} 428 | engines: {node: '>=10'} 429 | 430 | client-only@0.0.1: 431 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} 432 | 433 | clsx@2.1.1: 434 | resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 435 | engines: {node: '>=6'} 436 | 437 | color-convert@2.0.1: 438 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 439 | engines: {node: '>=7.0.0'} 440 | 441 | color-name@1.1.4: 442 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 443 | 444 | color-string@1.9.1: 445 | resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} 446 | 447 | color-support@1.1.3: 448 | resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} 449 | hasBin: true 450 | 451 | color@4.2.3: 452 | resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} 453 | engines: {node: '>=12.5.0'} 454 | 455 | commander@4.1.1: 456 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 457 | engines: {node: '>= 6'} 458 | 459 | concat-map@0.0.1: 460 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 461 | 462 | console-control-strings@1.1.0: 463 | resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} 464 | 465 | cookie@0.7.1: 466 | resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} 467 | engines: {node: '>= 0.6'} 468 | 469 | cross-spawn@7.0.6: 470 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 471 | engines: {node: '>= 8'} 472 | 473 | cssesc@3.0.0: 474 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 475 | engines: {node: '>=4'} 476 | hasBin: true 477 | 478 | csstype@3.1.3: 479 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 480 | 481 | debug@4.4.1: 482 | resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} 483 | engines: {node: '>=6.0'} 484 | peerDependencies: 485 | supports-color: '*' 486 | peerDependenciesMeta: 487 | supports-color: 488 | optional: true 489 | 490 | delegates@1.0.0: 491 | resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} 492 | 493 | detect-libc@2.0.4: 494 | resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} 495 | engines: {node: '>=8'} 496 | 497 | didyoumean@1.2.2: 498 | resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} 499 | 500 | dlv@1.1.3: 501 | resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 502 | 503 | eastasianwidth@0.2.0: 504 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 505 | 506 | electron-to-chromium@1.5.155: 507 | resolution: {integrity: sha512-ps5KcGGmwL8VaeJlvlDlu4fORQpv3+GIcF5I3f9tUKUlJ/wsysh6HU8P5L1XWRYeXfA0oJd4PyM8ds8zTFf6Ng==} 508 | 509 | emoji-regex@8.0.0: 510 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 511 | 512 | emoji-regex@9.2.2: 513 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 514 | 515 | escalade@3.2.0: 516 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 517 | engines: {node: '>=6'} 518 | 519 | fast-glob@3.3.3: 520 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 521 | engines: {node: '>=8.6.0'} 522 | 523 | fastq@1.19.1: 524 | resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 525 | 526 | fill-range@7.1.1: 527 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 528 | engines: {node: '>=8'} 529 | 530 | foreground-child@3.3.1: 531 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 532 | engines: {node: '>=14'} 533 | 534 | fraction.js@4.3.7: 535 | resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} 536 | 537 | fs-minipass@2.1.0: 538 | resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} 539 | engines: {node: '>= 8'} 540 | 541 | fs.realpath@1.0.0: 542 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 543 | 544 | fsevents@2.3.3: 545 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 546 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 547 | os: [darwin] 548 | 549 | function-bind@1.1.2: 550 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 551 | 552 | gauge@3.0.2: 553 | resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} 554 | engines: {node: '>=10'} 555 | deprecated: This package is no longer supported. 556 | 557 | glob-parent@5.1.2: 558 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 559 | engines: {node: '>= 6'} 560 | 561 | glob-parent@6.0.2: 562 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 563 | engines: {node: '>=10.13.0'} 564 | 565 | glob@10.4.5: 566 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 567 | hasBin: true 568 | 569 | glob@7.2.3: 570 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 571 | deprecated: Glob versions prior to v9 are no longer supported 572 | 573 | has-unicode@2.0.1: 574 | resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} 575 | 576 | hasown@2.0.2: 577 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 578 | engines: {node: '>= 0.4'} 579 | 580 | https-proxy-agent@5.0.1: 581 | resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} 582 | engines: {node: '>= 6'} 583 | 584 | inflight@1.0.6: 585 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 586 | deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. 587 | 588 | inherits@2.0.4: 589 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 590 | 591 | is-arrayish@0.3.2: 592 | resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} 593 | 594 | is-binary-path@2.1.0: 595 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 596 | engines: {node: '>=8'} 597 | 598 | is-core-module@2.16.1: 599 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 600 | engines: {node: '>= 0.4'} 601 | 602 | is-extglob@2.1.1: 603 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 604 | engines: {node: '>=0.10.0'} 605 | 606 | is-fullwidth-code-point@3.0.0: 607 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 608 | engines: {node: '>=8'} 609 | 610 | is-glob@4.0.3: 611 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 612 | engines: {node: '>=0.10.0'} 613 | 614 | is-number@7.0.0: 615 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 616 | engines: {node: '>=0.12.0'} 617 | 618 | isexe@2.0.0: 619 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 620 | 621 | jackspeak@3.4.3: 622 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 623 | 624 | jiti@1.21.7: 625 | resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} 626 | hasBin: true 627 | 628 | jose@5.10.0: 629 | resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} 630 | 631 | lilconfig@3.1.3: 632 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 633 | engines: {node: '>=14'} 634 | 635 | lines-and-columns@1.2.4: 636 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 637 | 638 | lru-cache@10.4.3: 639 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 640 | 641 | make-dir@3.1.0: 642 | resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} 643 | engines: {node: '>=8'} 644 | 645 | merge2@1.4.1: 646 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 647 | engines: {node: '>= 8'} 648 | 649 | micromatch@4.0.8: 650 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 651 | engines: {node: '>=8.6'} 652 | 653 | mini-svg-data-uri@1.4.4: 654 | resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} 655 | hasBin: true 656 | 657 | minimatch@3.1.2: 658 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 659 | 660 | minimatch@9.0.5: 661 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 662 | engines: {node: '>=16 || 14 >=14.17'} 663 | 664 | minipass@3.3.6: 665 | resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} 666 | engines: {node: '>=8'} 667 | 668 | minipass@5.0.0: 669 | resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} 670 | engines: {node: '>=8'} 671 | 672 | minipass@7.1.2: 673 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 674 | engines: {node: '>=16 || 14 >=14.17'} 675 | 676 | minizlib@2.1.2: 677 | resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} 678 | engines: {node: '>= 8'} 679 | 680 | mkdirp@1.0.4: 681 | resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} 682 | engines: {node: '>=10'} 683 | hasBin: true 684 | 685 | ms@2.1.3: 686 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 687 | 688 | mz@2.7.0: 689 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 690 | 691 | nanoid@3.3.11: 692 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 693 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 694 | hasBin: true 695 | 696 | next-auth@5.0.0-beta.25: 697 | resolution: {integrity: sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==} 698 | peerDependencies: 699 | '@simplewebauthn/browser': ^9.0.1 700 | '@simplewebauthn/server': ^9.0.2 701 | next: ^14.0.0-0 || ^15.0.0-0 702 | nodemailer: ^6.6.5 703 | react: ^18.2.0 || ^19.0.0-0 704 | peerDependenciesMeta: 705 | '@simplewebauthn/browser': 706 | optional: true 707 | '@simplewebauthn/server': 708 | optional: true 709 | nodemailer: 710 | optional: true 711 | 712 | next@15.4.2-canary.51: 713 | resolution: {integrity: sha512-0danfHCbTvU5cAXiSQWPow2AXgFC11ymChQzgMEBqqSd+1v/hBc2TASlB+x5GhUF/wLxmCe9861kcbqocEDDEQ==} 714 | engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} 715 | hasBin: true 716 | peerDependencies: 717 | '@opentelemetry/api': ^1.1.0 718 | '@playwright/test': ^1.51.1 719 | babel-plugin-react-compiler: '*' 720 | react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 721 | react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 722 | sass: ^1.3.0 723 | peerDependenciesMeta: 724 | '@opentelemetry/api': 725 | optional: true 726 | '@playwright/test': 727 | optional: true 728 | babel-plugin-react-compiler: 729 | optional: true 730 | sass: 731 | optional: true 732 | 733 | node-addon-api@5.1.0: 734 | resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} 735 | 736 | node-fetch@2.7.0: 737 | resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} 738 | engines: {node: 4.x || >=6.0.0} 739 | peerDependencies: 740 | encoding: ^0.1.0 741 | peerDependenciesMeta: 742 | encoding: 743 | optional: true 744 | 745 | node-releases@2.0.19: 746 | resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} 747 | 748 | nopt@5.0.0: 749 | resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} 750 | engines: {node: '>=6'} 751 | hasBin: true 752 | 753 | normalize-path@3.0.0: 754 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 755 | engines: {node: '>=0.10.0'} 756 | 757 | normalize-range@0.1.2: 758 | resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} 759 | engines: {node: '>=0.10.0'} 760 | 761 | npmlog@5.0.1: 762 | resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} 763 | deprecated: This package is no longer supported. 764 | 765 | oauth4webapi@3.5.1: 766 | resolution: {integrity: sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ==} 767 | 768 | object-assign@4.1.1: 769 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 770 | engines: {node: '>=0.10.0'} 771 | 772 | object-hash@3.0.0: 773 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 774 | engines: {node: '>= 6'} 775 | 776 | once@1.4.0: 777 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 778 | 779 | package-json-from-dist@1.0.1: 780 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 781 | 782 | path-is-absolute@1.0.1: 783 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 784 | engines: {node: '>=0.10.0'} 785 | 786 | path-key@3.1.1: 787 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 788 | engines: {node: '>=8'} 789 | 790 | path-parse@1.0.7: 791 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 792 | 793 | path-scurry@1.11.1: 794 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 795 | engines: {node: '>=16 || 14 >=14.18'} 796 | 797 | picocolors@1.1.1: 798 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 799 | 800 | picomatch@2.3.1: 801 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 802 | engines: {node: '>=8.6'} 803 | 804 | pify@2.3.0: 805 | resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} 806 | engines: {node: '>=0.10.0'} 807 | 808 | pirates@4.0.7: 809 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 810 | engines: {node: '>= 6'} 811 | 812 | postcss-import@15.1.0: 813 | resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} 814 | engines: {node: '>=14.0.0'} 815 | peerDependencies: 816 | postcss: ^8.0.0 817 | 818 | postcss-js@4.0.1: 819 | resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} 820 | engines: {node: ^12 || ^14 || >= 16} 821 | peerDependencies: 822 | postcss: ^8.4.21 823 | 824 | postcss-load-config@4.0.2: 825 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 826 | engines: {node: '>= 14'} 827 | peerDependencies: 828 | postcss: '>=8.0.9' 829 | ts-node: '>=9.0.0' 830 | peerDependenciesMeta: 831 | postcss: 832 | optional: true 833 | ts-node: 834 | optional: true 835 | 836 | postcss-nested@6.2.0: 837 | resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} 838 | engines: {node: '>=12.0'} 839 | peerDependencies: 840 | postcss: ^8.2.14 841 | 842 | postcss-selector-parser@6.1.2: 843 | resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} 844 | engines: {node: '>=4'} 845 | 846 | postcss-value-parser@4.2.0: 847 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 848 | 849 | postcss@8.4.31: 850 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} 851 | engines: {node: ^10 || ^12 || >=14} 852 | 853 | postcss@8.5.1: 854 | resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} 855 | engines: {node: ^10 || ^12 || >=14} 856 | 857 | postgres@3.4.6: 858 | resolution: {integrity: sha512-MXrZVqgUfiirfZ0MqQqXqZQa6oM5OWFjfuaHVKl7v2zW25LnOJeLpQk+UUW0ZuP94fcS+fZVqyDYm9v5SIJ11Q==} 859 | engines: {node: '>=12'} 860 | 861 | preact-render-to-string@5.2.3: 862 | resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} 863 | peerDependencies: 864 | preact: '>=10' 865 | 866 | preact@10.11.3: 867 | resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} 868 | 869 | pretty-format@3.8.0: 870 | resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} 871 | 872 | queue-microtask@1.2.3: 873 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 874 | 875 | react-dom@19.1.0: 876 | resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} 877 | peerDependencies: 878 | react: ^19.1.0 879 | 880 | react@19.1.0: 881 | resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} 882 | engines: {node: '>=0.10.0'} 883 | 884 | read-cache@1.0.0: 885 | resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} 886 | 887 | readable-stream@3.6.2: 888 | resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} 889 | engines: {node: '>= 6'} 890 | 891 | readdirp@3.6.0: 892 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 893 | engines: {node: '>=8.10.0'} 894 | 895 | resolve@1.22.10: 896 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 897 | engines: {node: '>= 0.4'} 898 | hasBin: true 899 | 900 | reusify@1.1.0: 901 | resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 902 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 903 | 904 | rimraf@3.0.2: 905 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 906 | deprecated: Rimraf versions prior to v4 are no longer supported 907 | hasBin: true 908 | 909 | run-parallel@1.2.0: 910 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 911 | 912 | safe-buffer@5.2.1: 913 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 914 | 915 | scheduler@0.26.0: 916 | resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} 917 | 918 | semver@6.3.1: 919 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 920 | hasBin: true 921 | 922 | semver@7.7.2: 923 | resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 924 | engines: {node: '>=10'} 925 | hasBin: true 926 | 927 | set-blocking@2.0.0: 928 | resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} 929 | 930 | sharp@0.34.3: 931 | resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} 932 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 933 | 934 | shebang-command@2.0.0: 935 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 936 | engines: {node: '>=8'} 937 | 938 | shebang-regex@3.0.0: 939 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 940 | engines: {node: '>=8'} 941 | 942 | signal-exit@3.0.7: 943 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 944 | 945 | signal-exit@4.1.0: 946 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 947 | engines: {node: '>=14'} 948 | 949 | simple-swizzle@0.2.2: 950 | resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} 951 | 952 | source-map-js@1.2.1: 953 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 954 | engines: {node: '>=0.10.0'} 955 | 956 | string-width@4.2.3: 957 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 958 | engines: {node: '>=8'} 959 | 960 | string-width@5.1.2: 961 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 962 | engines: {node: '>=12'} 963 | 964 | string_decoder@1.3.0: 965 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 966 | 967 | strip-ansi@6.0.1: 968 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 969 | engines: {node: '>=8'} 970 | 971 | strip-ansi@7.1.0: 972 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 973 | engines: {node: '>=12'} 974 | 975 | styled-jsx@5.1.6: 976 | resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} 977 | engines: {node: '>= 12.0.0'} 978 | peerDependencies: 979 | '@babel/core': '*' 980 | babel-plugin-macros: '*' 981 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' 982 | peerDependenciesMeta: 983 | '@babel/core': 984 | optional: true 985 | babel-plugin-macros: 986 | optional: true 987 | 988 | sucrase@3.35.0: 989 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 990 | engines: {node: '>=16 || 14 >=14.17'} 991 | hasBin: true 992 | 993 | supports-preserve-symlinks-flag@1.0.0: 994 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 995 | engines: {node: '>= 0.4'} 996 | 997 | tailwindcss@3.4.17: 998 | resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} 999 | engines: {node: '>=14.0.0'} 1000 | hasBin: true 1001 | 1002 | tar@6.2.1: 1003 | resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} 1004 | engines: {node: '>=10'} 1005 | 1006 | thenify-all@1.6.0: 1007 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1008 | engines: {node: '>=0.8'} 1009 | 1010 | thenify@3.3.1: 1011 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1012 | 1013 | to-regex-range@5.0.1: 1014 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1015 | engines: {node: '>=8.0'} 1016 | 1017 | tr46@0.0.3: 1018 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 1019 | 1020 | ts-interface-checker@0.1.13: 1021 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1022 | 1023 | tslib@2.8.1: 1024 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1025 | 1026 | typescript@5.7.3: 1027 | resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} 1028 | engines: {node: '>=14.17'} 1029 | hasBin: true 1030 | 1031 | undici-types@6.20.0: 1032 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 1033 | 1034 | update-browserslist-db@1.1.3: 1035 | resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} 1036 | hasBin: true 1037 | peerDependencies: 1038 | browserslist: '>= 4.21.0' 1039 | 1040 | use-debounce@10.0.4: 1041 | resolution: {integrity: sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==} 1042 | engines: {node: '>= 16.0.0'} 1043 | peerDependencies: 1044 | react: '*' 1045 | 1046 | util-deprecate@1.0.2: 1047 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 1048 | 1049 | webidl-conversions@3.0.1: 1050 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 1051 | 1052 | whatwg-url@5.0.0: 1053 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 1054 | 1055 | which@2.0.2: 1056 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1057 | engines: {node: '>= 8'} 1058 | hasBin: true 1059 | 1060 | wide-align@1.1.5: 1061 | resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} 1062 | 1063 | wrap-ansi@7.0.0: 1064 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1065 | engines: {node: '>=10'} 1066 | 1067 | wrap-ansi@8.1.0: 1068 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1069 | engines: {node: '>=12'} 1070 | 1071 | wrappy@1.0.2: 1072 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1073 | 1074 | yallist@4.0.0: 1075 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1076 | 1077 | yaml@2.8.0: 1078 | resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} 1079 | engines: {node: '>= 14.6'} 1080 | hasBin: true 1081 | 1082 | zod@3.25.17: 1083 | resolution: {integrity: sha512-8hQzQ/kMOIFbwOgPrm9Sf9rtFHpFUMy4HvN0yEB0spw14aYi0uT5xG5CE2DB9cd51GWNsz+DNO7se1kztHMKnw==} 1084 | 1085 | snapshots: 1086 | 1087 | '@alloc/quick-lru@5.2.0': {} 1088 | 1089 | '@auth/core@0.37.2': 1090 | dependencies: 1091 | '@panva/hkdf': 1.2.1 1092 | '@types/cookie': 0.6.0 1093 | cookie: 0.7.1 1094 | jose: 5.10.0 1095 | oauth4webapi: 3.5.1 1096 | preact: 10.11.3 1097 | preact-render-to-string: 5.2.3(preact@10.11.3) 1098 | 1099 | '@emnapi/runtime@1.4.5': 1100 | dependencies: 1101 | tslib: 2.8.1 1102 | optional: true 1103 | 1104 | '@heroicons/react@2.2.0(react@19.1.0)': 1105 | dependencies: 1106 | react: 19.1.0 1107 | 1108 | '@img/sharp-darwin-arm64@0.34.3': 1109 | optionalDependencies: 1110 | '@img/sharp-libvips-darwin-arm64': 1.2.0 1111 | optional: true 1112 | 1113 | '@img/sharp-darwin-x64@0.34.3': 1114 | optionalDependencies: 1115 | '@img/sharp-libvips-darwin-x64': 1.2.0 1116 | optional: true 1117 | 1118 | '@img/sharp-libvips-darwin-arm64@1.2.0': 1119 | optional: true 1120 | 1121 | '@img/sharp-libvips-darwin-x64@1.2.0': 1122 | optional: true 1123 | 1124 | '@img/sharp-libvips-linux-arm64@1.2.0': 1125 | optional: true 1126 | 1127 | '@img/sharp-libvips-linux-arm@1.2.0': 1128 | optional: true 1129 | 1130 | '@img/sharp-libvips-linux-ppc64@1.2.0': 1131 | optional: true 1132 | 1133 | '@img/sharp-libvips-linux-s390x@1.2.0': 1134 | optional: true 1135 | 1136 | '@img/sharp-libvips-linux-x64@1.2.0': 1137 | optional: true 1138 | 1139 | '@img/sharp-libvips-linuxmusl-arm64@1.2.0': 1140 | optional: true 1141 | 1142 | '@img/sharp-libvips-linuxmusl-x64@1.2.0': 1143 | optional: true 1144 | 1145 | '@img/sharp-linux-arm64@0.34.3': 1146 | optionalDependencies: 1147 | '@img/sharp-libvips-linux-arm64': 1.2.0 1148 | optional: true 1149 | 1150 | '@img/sharp-linux-arm@0.34.3': 1151 | optionalDependencies: 1152 | '@img/sharp-libvips-linux-arm': 1.2.0 1153 | optional: true 1154 | 1155 | '@img/sharp-linux-ppc64@0.34.3': 1156 | optionalDependencies: 1157 | '@img/sharp-libvips-linux-ppc64': 1.2.0 1158 | optional: true 1159 | 1160 | '@img/sharp-linux-s390x@0.34.3': 1161 | optionalDependencies: 1162 | '@img/sharp-libvips-linux-s390x': 1.2.0 1163 | optional: true 1164 | 1165 | '@img/sharp-linux-x64@0.34.3': 1166 | optionalDependencies: 1167 | '@img/sharp-libvips-linux-x64': 1.2.0 1168 | optional: true 1169 | 1170 | '@img/sharp-linuxmusl-arm64@0.34.3': 1171 | optionalDependencies: 1172 | '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 1173 | optional: true 1174 | 1175 | '@img/sharp-linuxmusl-x64@0.34.3': 1176 | optionalDependencies: 1177 | '@img/sharp-libvips-linuxmusl-x64': 1.2.0 1178 | optional: true 1179 | 1180 | '@img/sharp-wasm32@0.34.3': 1181 | dependencies: 1182 | '@emnapi/runtime': 1.4.5 1183 | optional: true 1184 | 1185 | '@img/sharp-win32-arm64@0.34.3': 1186 | optional: true 1187 | 1188 | '@img/sharp-win32-ia32@0.34.3': 1189 | optional: true 1190 | 1191 | '@img/sharp-win32-x64@0.34.3': 1192 | optional: true 1193 | 1194 | '@isaacs/cliui@8.0.2': 1195 | dependencies: 1196 | string-width: 5.1.2 1197 | string-width-cjs: string-width@4.2.3 1198 | strip-ansi: 7.1.0 1199 | strip-ansi-cjs: strip-ansi@6.0.1 1200 | wrap-ansi: 8.1.0 1201 | wrap-ansi-cjs: wrap-ansi@7.0.0 1202 | 1203 | '@jridgewell/gen-mapping@0.3.8': 1204 | dependencies: 1205 | '@jridgewell/set-array': 1.2.1 1206 | '@jridgewell/sourcemap-codec': 1.5.0 1207 | '@jridgewell/trace-mapping': 0.3.25 1208 | 1209 | '@jridgewell/resolve-uri@3.1.2': {} 1210 | 1211 | '@jridgewell/set-array@1.2.1': {} 1212 | 1213 | '@jridgewell/sourcemap-codec@1.5.0': {} 1214 | 1215 | '@jridgewell/trace-mapping@0.3.25': 1216 | dependencies: 1217 | '@jridgewell/resolve-uri': 3.1.2 1218 | '@jridgewell/sourcemap-codec': 1.5.0 1219 | 1220 | '@mapbox/node-pre-gyp@1.0.11': 1221 | dependencies: 1222 | detect-libc: 2.0.4 1223 | https-proxy-agent: 5.0.1 1224 | make-dir: 3.1.0 1225 | node-fetch: 2.7.0 1226 | nopt: 5.0.0 1227 | npmlog: 5.0.1 1228 | rimraf: 3.0.2 1229 | semver: 7.7.2 1230 | tar: 6.2.1 1231 | transitivePeerDependencies: 1232 | - encoding 1233 | - supports-color 1234 | 1235 | '@next/env@15.4.2-canary.51': {} 1236 | 1237 | '@next/swc-darwin-arm64@15.4.2-canary.51': 1238 | optional: true 1239 | 1240 | '@next/swc-darwin-x64@15.4.2-canary.51': 1241 | optional: true 1242 | 1243 | '@next/swc-linux-arm64-gnu@15.4.2-canary.51': 1244 | optional: true 1245 | 1246 | '@next/swc-linux-arm64-musl@15.4.2-canary.51': 1247 | optional: true 1248 | 1249 | '@next/swc-linux-x64-gnu@15.4.2-canary.51': 1250 | optional: true 1251 | 1252 | '@next/swc-linux-x64-musl@15.4.2-canary.51': 1253 | optional: true 1254 | 1255 | '@next/swc-win32-arm64-msvc@15.4.2-canary.51': 1256 | optional: true 1257 | 1258 | '@next/swc-win32-x64-msvc@15.4.2-canary.51': 1259 | optional: true 1260 | 1261 | '@nodelib/fs.scandir@2.1.5': 1262 | dependencies: 1263 | '@nodelib/fs.stat': 2.0.5 1264 | run-parallel: 1.2.0 1265 | 1266 | '@nodelib/fs.stat@2.0.5': {} 1267 | 1268 | '@nodelib/fs.walk@1.2.8': 1269 | dependencies: 1270 | '@nodelib/fs.scandir': 2.1.5 1271 | fastq: 1.19.1 1272 | 1273 | '@panva/hkdf@1.2.1': {} 1274 | 1275 | '@pkgjs/parseargs@0.11.0': 1276 | optional: true 1277 | 1278 | '@swc/helpers@0.5.15': 1279 | dependencies: 1280 | tslib: 2.8.1 1281 | 1282 | '@tailwindcss/forms@0.5.10(tailwindcss@3.4.17)': 1283 | dependencies: 1284 | mini-svg-data-uri: 1.4.4 1285 | tailwindcss: 3.4.17 1286 | 1287 | '@types/bcrypt@5.0.2': 1288 | dependencies: 1289 | '@types/node': 22.10.7 1290 | 1291 | '@types/cookie@0.6.0': {} 1292 | 1293 | '@types/node@22.10.7': 1294 | dependencies: 1295 | undici-types: 6.20.0 1296 | 1297 | '@types/react-dom@19.0.3(@types/react@19.0.7)': 1298 | dependencies: 1299 | '@types/react': 19.0.7 1300 | 1301 | '@types/react@19.0.7': 1302 | dependencies: 1303 | csstype: 3.1.3 1304 | 1305 | abbrev@1.1.1: {} 1306 | 1307 | agent-base@6.0.2: 1308 | dependencies: 1309 | debug: 4.4.1 1310 | transitivePeerDependencies: 1311 | - supports-color 1312 | 1313 | ansi-regex@5.0.1: {} 1314 | 1315 | ansi-regex@6.1.0: {} 1316 | 1317 | ansi-styles@4.3.0: 1318 | dependencies: 1319 | color-convert: 2.0.1 1320 | 1321 | ansi-styles@6.2.1: {} 1322 | 1323 | any-promise@1.3.0: {} 1324 | 1325 | anymatch@3.1.3: 1326 | dependencies: 1327 | normalize-path: 3.0.0 1328 | picomatch: 2.3.1 1329 | 1330 | aproba@2.0.0: {} 1331 | 1332 | are-we-there-yet@2.0.0: 1333 | dependencies: 1334 | delegates: 1.0.0 1335 | readable-stream: 3.6.2 1336 | 1337 | arg@5.0.2: {} 1338 | 1339 | autoprefixer@10.4.20(postcss@8.5.1): 1340 | dependencies: 1341 | browserslist: 4.24.5 1342 | caniuse-lite: 1.0.30001718 1343 | fraction.js: 4.3.7 1344 | normalize-range: 0.1.2 1345 | picocolors: 1.1.1 1346 | postcss: 8.5.1 1347 | postcss-value-parser: 4.2.0 1348 | 1349 | balanced-match@1.0.2: {} 1350 | 1351 | bcrypt@5.1.1: 1352 | dependencies: 1353 | '@mapbox/node-pre-gyp': 1.0.11 1354 | node-addon-api: 5.1.0 1355 | transitivePeerDependencies: 1356 | - encoding 1357 | - supports-color 1358 | 1359 | binary-extensions@2.3.0: {} 1360 | 1361 | brace-expansion@1.1.11: 1362 | dependencies: 1363 | balanced-match: 1.0.2 1364 | concat-map: 0.0.1 1365 | 1366 | brace-expansion@2.0.1: 1367 | dependencies: 1368 | balanced-match: 1.0.2 1369 | 1370 | braces@3.0.3: 1371 | dependencies: 1372 | fill-range: 7.1.1 1373 | 1374 | browserslist@4.24.5: 1375 | dependencies: 1376 | caniuse-lite: 1.0.30001718 1377 | electron-to-chromium: 1.5.155 1378 | node-releases: 2.0.19 1379 | update-browserslist-db: 1.1.3(browserslist@4.24.5) 1380 | 1381 | camelcase-css@2.0.1: {} 1382 | 1383 | caniuse-lite@1.0.30001718: {} 1384 | 1385 | chokidar@3.6.0: 1386 | dependencies: 1387 | anymatch: 3.1.3 1388 | braces: 3.0.3 1389 | glob-parent: 5.1.2 1390 | is-binary-path: 2.1.0 1391 | is-glob: 4.0.3 1392 | normalize-path: 3.0.0 1393 | readdirp: 3.6.0 1394 | optionalDependencies: 1395 | fsevents: 2.3.3 1396 | 1397 | chownr@2.0.0: {} 1398 | 1399 | client-only@0.0.1: {} 1400 | 1401 | clsx@2.1.1: {} 1402 | 1403 | color-convert@2.0.1: 1404 | dependencies: 1405 | color-name: 1.1.4 1406 | 1407 | color-name@1.1.4: {} 1408 | 1409 | color-string@1.9.1: 1410 | dependencies: 1411 | color-name: 1.1.4 1412 | simple-swizzle: 0.2.2 1413 | optional: true 1414 | 1415 | color-support@1.1.3: {} 1416 | 1417 | color@4.2.3: 1418 | dependencies: 1419 | color-convert: 2.0.1 1420 | color-string: 1.9.1 1421 | optional: true 1422 | 1423 | commander@4.1.1: {} 1424 | 1425 | concat-map@0.0.1: {} 1426 | 1427 | console-control-strings@1.1.0: {} 1428 | 1429 | cookie@0.7.1: {} 1430 | 1431 | cross-spawn@7.0.6: 1432 | dependencies: 1433 | path-key: 3.1.1 1434 | shebang-command: 2.0.0 1435 | which: 2.0.2 1436 | 1437 | cssesc@3.0.0: {} 1438 | 1439 | csstype@3.1.3: {} 1440 | 1441 | debug@4.4.1: 1442 | dependencies: 1443 | ms: 2.1.3 1444 | 1445 | delegates@1.0.0: {} 1446 | 1447 | detect-libc@2.0.4: {} 1448 | 1449 | didyoumean@1.2.2: {} 1450 | 1451 | dlv@1.1.3: {} 1452 | 1453 | eastasianwidth@0.2.0: {} 1454 | 1455 | electron-to-chromium@1.5.155: {} 1456 | 1457 | emoji-regex@8.0.0: {} 1458 | 1459 | emoji-regex@9.2.2: {} 1460 | 1461 | escalade@3.2.0: {} 1462 | 1463 | fast-glob@3.3.3: 1464 | dependencies: 1465 | '@nodelib/fs.stat': 2.0.5 1466 | '@nodelib/fs.walk': 1.2.8 1467 | glob-parent: 5.1.2 1468 | merge2: 1.4.1 1469 | micromatch: 4.0.8 1470 | 1471 | fastq@1.19.1: 1472 | dependencies: 1473 | reusify: 1.1.0 1474 | 1475 | fill-range@7.1.1: 1476 | dependencies: 1477 | to-regex-range: 5.0.1 1478 | 1479 | foreground-child@3.3.1: 1480 | dependencies: 1481 | cross-spawn: 7.0.6 1482 | signal-exit: 4.1.0 1483 | 1484 | fraction.js@4.3.7: {} 1485 | 1486 | fs-minipass@2.1.0: 1487 | dependencies: 1488 | minipass: 3.3.6 1489 | 1490 | fs.realpath@1.0.0: {} 1491 | 1492 | fsevents@2.3.3: 1493 | optional: true 1494 | 1495 | function-bind@1.1.2: {} 1496 | 1497 | gauge@3.0.2: 1498 | dependencies: 1499 | aproba: 2.0.0 1500 | color-support: 1.1.3 1501 | console-control-strings: 1.1.0 1502 | has-unicode: 2.0.1 1503 | object-assign: 4.1.1 1504 | signal-exit: 3.0.7 1505 | string-width: 4.2.3 1506 | strip-ansi: 6.0.1 1507 | wide-align: 1.1.5 1508 | 1509 | glob-parent@5.1.2: 1510 | dependencies: 1511 | is-glob: 4.0.3 1512 | 1513 | glob-parent@6.0.2: 1514 | dependencies: 1515 | is-glob: 4.0.3 1516 | 1517 | glob@10.4.5: 1518 | dependencies: 1519 | foreground-child: 3.3.1 1520 | jackspeak: 3.4.3 1521 | minimatch: 9.0.5 1522 | minipass: 7.1.2 1523 | package-json-from-dist: 1.0.1 1524 | path-scurry: 1.11.1 1525 | 1526 | glob@7.2.3: 1527 | dependencies: 1528 | fs.realpath: 1.0.0 1529 | inflight: 1.0.6 1530 | inherits: 2.0.4 1531 | minimatch: 3.1.2 1532 | once: 1.4.0 1533 | path-is-absolute: 1.0.1 1534 | 1535 | has-unicode@2.0.1: {} 1536 | 1537 | hasown@2.0.2: 1538 | dependencies: 1539 | function-bind: 1.1.2 1540 | 1541 | https-proxy-agent@5.0.1: 1542 | dependencies: 1543 | agent-base: 6.0.2 1544 | debug: 4.4.1 1545 | transitivePeerDependencies: 1546 | - supports-color 1547 | 1548 | inflight@1.0.6: 1549 | dependencies: 1550 | once: 1.4.0 1551 | wrappy: 1.0.2 1552 | 1553 | inherits@2.0.4: {} 1554 | 1555 | is-arrayish@0.3.2: 1556 | optional: true 1557 | 1558 | is-binary-path@2.1.0: 1559 | dependencies: 1560 | binary-extensions: 2.3.0 1561 | 1562 | is-core-module@2.16.1: 1563 | dependencies: 1564 | hasown: 2.0.2 1565 | 1566 | is-extglob@2.1.1: {} 1567 | 1568 | is-fullwidth-code-point@3.0.0: {} 1569 | 1570 | is-glob@4.0.3: 1571 | dependencies: 1572 | is-extglob: 2.1.1 1573 | 1574 | is-number@7.0.0: {} 1575 | 1576 | isexe@2.0.0: {} 1577 | 1578 | jackspeak@3.4.3: 1579 | dependencies: 1580 | '@isaacs/cliui': 8.0.2 1581 | optionalDependencies: 1582 | '@pkgjs/parseargs': 0.11.0 1583 | 1584 | jiti@1.21.7: {} 1585 | 1586 | jose@5.10.0: {} 1587 | 1588 | lilconfig@3.1.3: {} 1589 | 1590 | lines-and-columns@1.2.4: {} 1591 | 1592 | lru-cache@10.4.3: {} 1593 | 1594 | make-dir@3.1.0: 1595 | dependencies: 1596 | semver: 6.3.1 1597 | 1598 | merge2@1.4.1: {} 1599 | 1600 | micromatch@4.0.8: 1601 | dependencies: 1602 | braces: 3.0.3 1603 | picomatch: 2.3.1 1604 | 1605 | mini-svg-data-uri@1.4.4: {} 1606 | 1607 | minimatch@3.1.2: 1608 | dependencies: 1609 | brace-expansion: 1.1.11 1610 | 1611 | minimatch@9.0.5: 1612 | dependencies: 1613 | brace-expansion: 2.0.1 1614 | 1615 | minipass@3.3.6: 1616 | dependencies: 1617 | yallist: 4.0.0 1618 | 1619 | minipass@5.0.0: {} 1620 | 1621 | minipass@7.1.2: {} 1622 | 1623 | minizlib@2.1.2: 1624 | dependencies: 1625 | minipass: 3.3.6 1626 | yallist: 4.0.0 1627 | 1628 | mkdirp@1.0.4: {} 1629 | 1630 | ms@2.1.3: {} 1631 | 1632 | mz@2.7.0: 1633 | dependencies: 1634 | any-promise: 1.3.0 1635 | object-assign: 4.1.1 1636 | thenify-all: 1.6.0 1637 | 1638 | nanoid@3.3.11: {} 1639 | 1640 | next-auth@5.0.0-beta.25(next@15.4.2-canary.51(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0): 1641 | dependencies: 1642 | '@auth/core': 0.37.2 1643 | next: 15.4.2-canary.51(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1644 | react: 19.1.0 1645 | 1646 | next@15.4.2-canary.51(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 1647 | dependencies: 1648 | '@next/env': 15.4.2-canary.51 1649 | '@swc/helpers': 0.5.15 1650 | caniuse-lite: 1.0.30001718 1651 | postcss: 8.4.31 1652 | react: 19.1.0 1653 | react-dom: 19.1.0(react@19.1.0) 1654 | styled-jsx: 5.1.6(react@19.1.0) 1655 | optionalDependencies: 1656 | '@next/swc-darwin-arm64': 15.4.2-canary.51 1657 | '@next/swc-darwin-x64': 15.4.2-canary.51 1658 | '@next/swc-linux-arm64-gnu': 15.4.2-canary.51 1659 | '@next/swc-linux-arm64-musl': 15.4.2-canary.51 1660 | '@next/swc-linux-x64-gnu': 15.4.2-canary.51 1661 | '@next/swc-linux-x64-musl': 15.4.2-canary.51 1662 | '@next/swc-win32-arm64-msvc': 15.4.2-canary.51 1663 | '@next/swc-win32-x64-msvc': 15.4.2-canary.51 1664 | sharp: 0.34.3 1665 | transitivePeerDependencies: 1666 | - '@babel/core' 1667 | - babel-plugin-macros 1668 | 1669 | node-addon-api@5.1.0: {} 1670 | 1671 | node-fetch@2.7.0: 1672 | dependencies: 1673 | whatwg-url: 5.0.0 1674 | 1675 | node-releases@2.0.19: {} 1676 | 1677 | nopt@5.0.0: 1678 | dependencies: 1679 | abbrev: 1.1.1 1680 | 1681 | normalize-path@3.0.0: {} 1682 | 1683 | normalize-range@0.1.2: {} 1684 | 1685 | npmlog@5.0.1: 1686 | dependencies: 1687 | are-we-there-yet: 2.0.0 1688 | console-control-strings: 1.1.0 1689 | gauge: 3.0.2 1690 | set-blocking: 2.0.0 1691 | 1692 | oauth4webapi@3.5.1: {} 1693 | 1694 | object-assign@4.1.1: {} 1695 | 1696 | object-hash@3.0.0: {} 1697 | 1698 | once@1.4.0: 1699 | dependencies: 1700 | wrappy: 1.0.2 1701 | 1702 | package-json-from-dist@1.0.1: {} 1703 | 1704 | path-is-absolute@1.0.1: {} 1705 | 1706 | path-key@3.1.1: {} 1707 | 1708 | path-parse@1.0.7: {} 1709 | 1710 | path-scurry@1.11.1: 1711 | dependencies: 1712 | lru-cache: 10.4.3 1713 | minipass: 7.1.2 1714 | 1715 | picocolors@1.1.1: {} 1716 | 1717 | picomatch@2.3.1: {} 1718 | 1719 | pify@2.3.0: {} 1720 | 1721 | pirates@4.0.7: {} 1722 | 1723 | postcss-import@15.1.0(postcss@8.5.1): 1724 | dependencies: 1725 | postcss: 8.5.1 1726 | postcss-value-parser: 4.2.0 1727 | read-cache: 1.0.0 1728 | resolve: 1.22.10 1729 | 1730 | postcss-js@4.0.1(postcss@8.5.1): 1731 | dependencies: 1732 | camelcase-css: 2.0.1 1733 | postcss: 8.5.1 1734 | 1735 | postcss-load-config@4.0.2(postcss@8.5.1): 1736 | dependencies: 1737 | lilconfig: 3.1.3 1738 | yaml: 2.8.0 1739 | optionalDependencies: 1740 | postcss: 8.5.1 1741 | 1742 | postcss-nested@6.2.0(postcss@8.5.1): 1743 | dependencies: 1744 | postcss: 8.5.1 1745 | postcss-selector-parser: 6.1.2 1746 | 1747 | postcss-selector-parser@6.1.2: 1748 | dependencies: 1749 | cssesc: 3.0.0 1750 | util-deprecate: 1.0.2 1751 | 1752 | postcss-value-parser@4.2.0: {} 1753 | 1754 | postcss@8.4.31: 1755 | dependencies: 1756 | nanoid: 3.3.11 1757 | picocolors: 1.1.1 1758 | source-map-js: 1.2.1 1759 | 1760 | postcss@8.5.1: 1761 | dependencies: 1762 | nanoid: 3.3.11 1763 | picocolors: 1.1.1 1764 | source-map-js: 1.2.1 1765 | 1766 | postgres@3.4.6: {} 1767 | 1768 | preact-render-to-string@5.2.3(preact@10.11.3): 1769 | dependencies: 1770 | preact: 10.11.3 1771 | pretty-format: 3.8.0 1772 | 1773 | preact@10.11.3: {} 1774 | 1775 | pretty-format@3.8.0: {} 1776 | 1777 | queue-microtask@1.2.3: {} 1778 | 1779 | react-dom@19.1.0(react@19.1.0): 1780 | dependencies: 1781 | react: 19.1.0 1782 | scheduler: 0.26.0 1783 | 1784 | react@19.1.0: {} 1785 | 1786 | read-cache@1.0.0: 1787 | dependencies: 1788 | pify: 2.3.0 1789 | 1790 | readable-stream@3.6.2: 1791 | dependencies: 1792 | inherits: 2.0.4 1793 | string_decoder: 1.3.0 1794 | util-deprecate: 1.0.2 1795 | 1796 | readdirp@3.6.0: 1797 | dependencies: 1798 | picomatch: 2.3.1 1799 | 1800 | resolve@1.22.10: 1801 | dependencies: 1802 | is-core-module: 2.16.1 1803 | path-parse: 1.0.7 1804 | supports-preserve-symlinks-flag: 1.0.0 1805 | 1806 | reusify@1.1.0: {} 1807 | 1808 | rimraf@3.0.2: 1809 | dependencies: 1810 | glob: 7.2.3 1811 | 1812 | run-parallel@1.2.0: 1813 | dependencies: 1814 | queue-microtask: 1.2.3 1815 | 1816 | safe-buffer@5.2.1: {} 1817 | 1818 | scheduler@0.26.0: {} 1819 | 1820 | semver@6.3.1: {} 1821 | 1822 | semver@7.7.2: {} 1823 | 1824 | set-blocking@2.0.0: {} 1825 | 1826 | sharp@0.34.3: 1827 | dependencies: 1828 | color: 4.2.3 1829 | detect-libc: 2.0.4 1830 | semver: 7.7.2 1831 | optionalDependencies: 1832 | '@img/sharp-darwin-arm64': 0.34.3 1833 | '@img/sharp-darwin-x64': 0.34.3 1834 | '@img/sharp-libvips-darwin-arm64': 1.2.0 1835 | '@img/sharp-libvips-darwin-x64': 1.2.0 1836 | '@img/sharp-libvips-linux-arm': 1.2.0 1837 | '@img/sharp-libvips-linux-arm64': 1.2.0 1838 | '@img/sharp-libvips-linux-ppc64': 1.2.0 1839 | '@img/sharp-libvips-linux-s390x': 1.2.0 1840 | '@img/sharp-libvips-linux-x64': 1.2.0 1841 | '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 1842 | '@img/sharp-libvips-linuxmusl-x64': 1.2.0 1843 | '@img/sharp-linux-arm': 0.34.3 1844 | '@img/sharp-linux-arm64': 0.34.3 1845 | '@img/sharp-linux-ppc64': 0.34.3 1846 | '@img/sharp-linux-s390x': 0.34.3 1847 | '@img/sharp-linux-x64': 0.34.3 1848 | '@img/sharp-linuxmusl-arm64': 0.34.3 1849 | '@img/sharp-linuxmusl-x64': 0.34.3 1850 | '@img/sharp-wasm32': 0.34.3 1851 | '@img/sharp-win32-arm64': 0.34.3 1852 | '@img/sharp-win32-ia32': 0.34.3 1853 | '@img/sharp-win32-x64': 0.34.3 1854 | optional: true 1855 | 1856 | shebang-command@2.0.0: 1857 | dependencies: 1858 | shebang-regex: 3.0.0 1859 | 1860 | shebang-regex@3.0.0: {} 1861 | 1862 | signal-exit@3.0.7: {} 1863 | 1864 | signal-exit@4.1.0: {} 1865 | 1866 | simple-swizzle@0.2.2: 1867 | dependencies: 1868 | is-arrayish: 0.3.2 1869 | optional: true 1870 | 1871 | source-map-js@1.2.1: {} 1872 | 1873 | string-width@4.2.3: 1874 | dependencies: 1875 | emoji-regex: 8.0.0 1876 | is-fullwidth-code-point: 3.0.0 1877 | strip-ansi: 6.0.1 1878 | 1879 | string-width@5.1.2: 1880 | dependencies: 1881 | eastasianwidth: 0.2.0 1882 | emoji-regex: 9.2.2 1883 | strip-ansi: 7.1.0 1884 | 1885 | string_decoder@1.3.0: 1886 | dependencies: 1887 | safe-buffer: 5.2.1 1888 | 1889 | strip-ansi@6.0.1: 1890 | dependencies: 1891 | ansi-regex: 5.0.1 1892 | 1893 | strip-ansi@7.1.0: 1894 | dependencies: 1895 | ansi-regex: 6.1.0 1896 | 1897 | styled-jsx@5.1.6(react@19.1.0): 1898 | dependencies: 1899 | client-only: 0.0.1 1900 | react: 19.1.0 1901 | 1902 | sucrase@3.35.0: 1903 | dependencies: 1904 | '@jridgewell/gen-mapping': 0.3.8 1905 | commander: 4.1.1 1906 | glob: 10.4.5 1907 | lines-and-columns: 1.2.4 1908 | mz: 2.7.0 1909 | pirates: 4.0.7 1910 | ts-interface-checker: 0.1.13 1911 | 1912 | supports-preserve-symlinks-flag@1.0.0: {} 1913 | 1914 | tailwindcss@3.4.17: 1915 | dependencies: 1916 | '@alloc/quick-lru': 5.2.0 1917 | arg: 5.0.2 1918 | chokidar: 3.6.0 1919 | didyoumean: 1.2.2 1920 | dlv: 1.1.3 1921 | fast-glob: 3.3.3 1922 | glob-parent: 6.0.2 1923 | is-glob: 4.0.3 1924 | jiti: 1.21.7 1925 | lilconfig: 3.1.3 1926 | micromatch: 4.0.8 1927 | normalize-path: 3.0.0 1928 | object-hash: 3.0.0 1929 | picocolors: 1.1.1 1930 | postcss: 8.5.1 1931 | postcss-import: 15.1.0(postcss@8.5.1) 1932 | postcss-js: 4.0.1(postcss@8.5.1) 1933 | postcss-load-config: 4.0.2(postcss@8.5.1) 1934 | postcss-nested: 6.2.0(postcss@8.5.1) 1935 | postcss-selector-parser: 6.1.2 1936 | resolve: 1.22.10 1937 | sucrase: 3.35.0 1938 | transitivePeerDependencies: 1939 | - ts-node 1940 | 1941 | tar@6.2.1: 1942 | dependencies: 1943 | chownr: 2.0.0 1944 | fs-minipass: 2.1.0 1945 | minipass: 5.0.0 1946 | minizlib: 2.1.2 1947 | mkdirp: 1.0.4 1948 | yallist: 4.0.0 1949 | 1950 | thenify-all@1.6.0: 1951 | dependencies: 1952 | thenify: 3.3.1 1953 | 1954 | thenify@3.3.1: 1955 | dependencies: 1956 | any-promise: 1.3.0 1957 | 1958 | to-regex-range@5.0.1: 1959 | dependencies: 1960 | is-number: 7.0.0 1961 | 1962 | tr46@0.0.3: {} 1963 | 1964 | ts-interface-checker@0.1.13: {} 1965 | 1966 | tslib@2.8.1: {} 1967 | 1968 | typescript@5.7.3: {} 1969 | 1970 | undici-types@6.20.0: {} 1971 | 1972 | update-browserslist-db@1.1.3(browserslist@4.24.5): 1973 | dependencies: 1974 | browserslist: 4.24.5 1975 | escalade: 3.2.0 1976 | picocolors: 1.1.1 1977 | 1978 | use-debounce@10.0.4(react@19.1.0): 1979 | dependencies: 1980 | react: 19.1.0 1981 | 1982 | util-deprecate@1.0.2: {} 1983 | 1984 | webidl-conversions@3.0.1: {} 1985 | 1986 | whatwg-url@5.0.0: 1987 | dependencies: 1988 | tr46: 0.0.3 1989 | webidl-conversions: 3.0.1 1990 | 1991 | which@2.0.2: 1992 | dependencies: 1993 | isexe: 2.0.0 1994 | 1995 | wide-align@1.1.5: 1996 | dependencies: 1997 | string-width: 4.2.3 1998 | 1999 | wrap-ansi@7.0.0: 2000 | dependencies: 2001 | ansi-styles: 4.3.0 2002 | string-width: 4.2.3 2003 | strip-ansi: 6.0.1 2004 | 2005 | wrap-ansi@8.1.0: 2006 | dependencies: 2007 | ansi-styles: 6.2.1 2008 | string-width: 5.1.2 2009 | strip-ansi: 7.1.0 2010 | 2011 | wrappy@1.0.2: {} 2012 | 2013 | yallist@4.0.0: {} 2014 | 2015 | yaml@2.8.0: {} 2016 | 2017 | zod@3.25.17: {} 2018 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/customers/amy-burns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/amy-burns.png -------------------------------------------------------------------------------- /public/customers/balazs-orban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/balazs-orban.png -------------------------------------------------------------------------------- /public/customers/delba-de-oliveira.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/delba-de-oliveira.png -------------------------------------------------------------------------------- /public/customers/evil-rabbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/evil-rabbit.png -------------------------------------------------------------------------------- /public/customers/lee-robinson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/lee-robinson.png -------------------------------------------------------------------------------- /public/customers/michael-novotny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/customers/michael-novotny.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/favicon.ico -------------------------------------------------------------------------------- /public/hero-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/hero-desktop.png -------------------------------------------------------------------------------- /public/hero-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/hero-mobile.png -------------------------------------------------------------------------------- /public/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ifo-aka/NextJsandVercel/211a5520408d1892ba95d74b7fcd3541a70a4b98/public/opengraph-image.png -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | const config: Config = { 4 | content: [ 5 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | gridTemplateColumns: { 12 | '13': 'repeat(13, minmax(0, 1fr))', 13 | }, 14 | colors: { 15 | blue: { 16 | 400: '#2589FE', 17 | 500: '#0070F3', 18 | 600: '#2F6FEB', 19 | }, 20 | }, 21 | }, 22 | keyframes: { 23 | shimmer: { 24 | '100%': { 25 | transform: 'translateX(100%)', 26 | }, 27 | }, 28 | }, 29 | }, 30 | plugins: [require('@tailwindcss/forms')], 31 | }; 32 | export default config; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "baseUrl": ".", 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": [ 27 | "next-env.d.ts", 28 | "**/*.ts", 29 | "**/*.tsx", 30 | ".next/types/**/*.ts", 31 | "app/lib/placeholder-data.ts", 32 | "scripts/seed.js" 33 | ], 34 | "exclude": ["node_modules"] 35 | } 36 | --------------------------------------------------------------------------------