From e1e07b8756c2edaf851f7506a8b13defbc4e0200 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Mon, 10 Feb 2025 14:19:12 +0400 Subject: [PATCH 01/33] fix: update docker-compose --- dev/docker-compose.yml | 2 +- package.json | 5 +- src/app/page.tsx | 156 ++++++++++++++++++++--------------------- 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 19d7df5..aa2e829 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -3,7 +3,7 @@ version: "3.3" services: # postgresql://easy-invoice:easy-invoice@localhost:7406/easy-invoice postgres: - image: postgres:latest + image: postgres:16-alpine environment: POSTGRES_USER: easy-invoice POSTGRES_PASSWORD: easy-invoice diff --git a/package.json b/package.json index b18f59f..8c7f06f 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "build": "next build", "start": "next start", "lint": "next lint", - "db:push": "dotenv -e .env -- drizzle-kit push", - "db:studio": "dotenv -e .env -- drizzle-kit studio" + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio" }, "dependencies": { "@hookform/resolvers": "^3.9.1", @@ -51,6 +51,7 @@ "@types/pg": "^8.11.10", "@types/react": "^18", "@types/react-dom": "^18", + "dotenv-cli": "^7.3.0", "postcss": "^8", "tailwindcss": "^3.4.1", "typescript": "^5" diff --git a/src/app/page.tsx b/src/app/page.tsx index 3f01a66..0030ed4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,89 +4,89 @@ import Link from "next/link"; import { redirect } from "next/navigation"; export default async function LoginPage() { - const { user } = await getCurrentSession(); + const { user } = await getCurrentSession(); - if (user) { - return redirect("/dashboard"); - } + if (user) { + return redirect("/dashboard"); + } - return ( -
- {/* Decorative elements */} -
-
-
-
-
-
+ return ( +
+ {/* Decorative elements */} +
+
+
+
+
+
- {/* Dot pattern background */} -
+ {/* Dot pattern background */} +
- {/* Content */} -
-
- -
+ {/* Content */} +
+
+ +
-
-
-
-
- EASY TO USE CRYPTO INVOICING{" "} -
{" "} -

- {" "} - Welcome to EasyInvoice -

-

- Easily create and send invoices to your customers using crypto. -

-
+
+
+
+
+ EASY TO USE CRYPTO INVOICING{" "} +
{" "} +

+ {" "} + Welcome to EasyInvoice +

+

+ Easily create and send invoices to your customers using crypto. +

+
-
- - Google - Continue with Google - -
-
-
+
+ + Google + Continue with Google + +
+
+
-
-
-
- ยฉ 2024 EasyInvoice. All rights reserved. Built by{" "} - - Request Network - -
-
-
-
-
- ); +
+
+
+ ยฉ 2024 EasyInvoice. All rights reserved. Built by{" "} + + Request Network + +
+
+
+
+
+ ); } From 2afcaed255d5edc7fca420da71c9ef9b5a6faba2 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Mon, 10 Feb 2025 15:41:40 +0400 Subject: [PATCH 02/33] feat: update invoice schema and add creation logic --- drizzle.config.ts | 12 ++++----- package-lock.json | 51 +++++++++++++++++++++++++++++++++++ src/server/db/schema.ts | 15 +++++++++++ src/server/routers/invoice.ts | 26 +++++++++++++++++- 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/drizzle.config.ts b/drizzle.config.ts index e5de6ff..e0f35be 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,10 +1,10 @@ import { type Config } from "drizzle-kit"; export default { - schema: "./src/server/db/schema.ts", - dialect: "postgresql", - dbCredentials: { - url: process.env.DATABASE_URL as string, - }, - tablesFilter: ["invoicepro_*"], + schema: "./src/server/db/schema.ts", + dialect: "postgresql", + dbCredentials: { + url: process.env.DATABASE_URL as string, + }, + tablesFilter: ["easyinvoice_*"], } satisfies Config; diff --git a/package-lock.json b/package-lock.json index 548e7b9..f8ce3cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "easy-invoice", "version": "0.1.0", + "license": "MIT", "dependencies": { "@hookform/resolvers": "^3.9.1", "@oslojs/crypto": "^1.0.1", @@ -47,6 +48,7 @@ "@types/pg": "^8.11.10", "@types/react": "^18", "@types/react-dom": "^18", + "dotenv-cli": "^7.4.4", "postcss": "^8", "tailwindcss": "^3.4.1", "typescript": "^5" @@ -3096,6 +3098,45 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-cli": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.4.4.tgz", + "integrity": "sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, "node_modules/drizzle-kit": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.28.1.tgz", @@ -3778,6 +3819,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 4c2990b..b5e0aa5 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -3,6 +3,7 @@ import CryptoJS from "crypto-js"; import { InferSelectModel } from "drizzle-orm"; import { customType, + json, pgTableCreator, text, timestamp, @@ -44,6 +45,20 @@ export const userTable = createTable("user", { export const requestTable = createTable("request", { id: text().primaryKey().notNull(), type: text().notNull(), + dueDate: text().notNull(), + clientName: text().notNull(), + clientEmail: text().notNull(), + invoiceNumber: text().notNull(), + items: json().notNull(), + notes: text(), + amount: text().notNull(), + currency: text().notNull(), + status: text().notNull(), + payer: text().notNull(), + payee: text().notNull(), + requestId: text().notNull(), + paymentReference: text().notNull(), + createdAt: timestamp("created_at").defaultNow(), }); export const sessionTable = createTable("session", { diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index a8c4ee1..781ec3d 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -1,8 +1,9 @@ import { CURRENCY_VALUE } from "@/lib/currency"; import { invoiceFormSchema } from "@/lib/schemas/invoice"; - +import { requestTable } from "@/server/db/schema"; import { ethers } from "ethers"; import { protectedProcedure, router } from "../trpc"; +import { ulid } from "ulid"; export const invoiceRouter = router({ create: protectedProcedure @@ -11,6 +12,29 @@ export const invoiceRouter = router({ try { const { user, db } = ctx; + const totalAmount = input.items.reduce( + (acc, item) => acc + item.price * item.quantity, + 0, + ); + + await db.insert(requestTable).values({ + id: ulid(), + amount: totalAmount.toString(), + currency: input.cryptocurrency, + type: "invoice", + status: "pending", + payer: input.clientWallet, + payee: input.walletAddress, + dueDate: new Date(input.dueDate).toISOString(), + requestId: ulid(), + paymentReference: ulid(), + clientName: input.clientName, + clientEmail: input.clientEmail, + invoiceNumber: input.invoiceNumber, + items: input.items, + notes: input.notes, + }); + return { success: true }; } catch (error) { console.log("Error: ", error); From c705656f9797eb3d60d722a2e2e0d2dd50ccef90 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Mon, 10 Feb 2025 16:53:47 +0400 Subject: [PATCH 03/33] feat: update invoice schema and connect Request API --- package-lock.json | 102 +++++++++++++++++++++++++++++++++- package.json | 1 + src/lib/axios.ts | 8 +++ src/server/db/schema.ts | 28 +++++++++- src/server/routers/invoice.ts | 20 +++++-- 5 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 src/lib/axios.ts diff --git a/package-lock.json b/package-lock.json index f8ce3cb..c3b25b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@trpc/react-query": "^10.45.2", "@trpc/server": "^10.45.2", "arctic": "^2.2.2", + "axios": "^1.7.9", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "crypto-js": "^4.2.0", @@ -48,7 +49,7 @@ "@types/pg": "^8.11.10", "@types/react": "^18", "@types/react-dom": "^18", - "dotenv-cli": "^7.4.4", + "dotenv-cli": "^7.3.0", "postcss": "^8", "tailwindcss": "^3.4.1", "typescript": "^5" @@ -2819,6 +2820,23 @@ "node": ">=10" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3002,6 +3020,18 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -3075,6 +3105,15 @@ } } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -3449,6 +3488,26 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -3464,6 +3523,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3795,6 +3868,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -4371,6 +4465,12 @@ "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", "devOptional": true }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", diff --git a/package.json b/package.json index 8c7f06f..e3083da 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@trpc/react-query": "^10.45.2", "@trpc/server": "^10.45.2", "arctic": "^2.2.2", + "axios": "^1.7.9", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "crypto-js": "^4.2.0", diff --git a/src/lib/axios.ts b/src/lib/axios.ts new file mode 100644 index 0000000..8fa091f --- /dev/null +++ b/src/lib/axios.ts @@ -0,0 +1,8 @@ +import axios from "axios"; + +export const apiClient = axios.create({ + baseURL: process.env.REQUEST_API_URL, + headers: { + "x-api-key": process.env.REQUEST_API_KEY, + }, +}); diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index b5e0aa5..97d09e4 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -1,6 +1,6 @@ import { type EncryptionVersion, getEncryptionKey } from "@/lib/encryption"; import CryptoJS from "crypto-js"; -import { InferSelectModel } from "drizzle-orm"; +import { InferSelectModel, relations } from "drizzle-orm"; import { customType, json, @@ -59,6 +59,11 @@ export const requestTable = createTable("request", { requestId: text().notNull(), paymentReference: text().notNull(), createdAt: timestamp("created_at").defaultNow(), + userId: text() + .notNull() + .references(() => userTable.id, { + onDelete: "cascade", + }), }); export const sessionTable = createTable("session", { @@ -74,6 +79,27 @@ export const sessionTable = createTable("session", { }).notNull(), }); +// Relationships + +export const userRelations = relations(userTable, ({ many }) => ({ + requests: many(requestTable), + session: many(sessionTable), +})); + +export const requestRelations = relations(requestTable, ({ one }) => ({ + user: one(userTable, { + fields: [requestTable.userId], + references: [userTable.id], + }), +})); + +export const sessionRelations = relations(sessionTable, ({ one }) => ({ + user: one(userTable, { + fields: [sessionTable.userId], + references: [userTable.id], + }), +})); + export type Request = InferSelectModel; export type User = InferSelectModel; export type Session = InferSelectModel; diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index 781ec3d..9edc7b6 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -1,22 +1,29 @@ -import { CURRENCY_VALUE } from "@/lib/currency"; +import { apiClient } from "@/lib/axios"; import { invoiceFormSchema } from "@/lib/schemas/invoice"; import { requestTable } from "@/server/db/schema"; -import { ethers } from "ethers"; -import { protectedProcedure, router } from "../trpc"; import { ulid } from "ulid"; +import { protectedProcedure, router } from "../trpc"; export const invoiceRouter = router({ create: protectedProcedure .input(invoiceFormSchema) .mutation(async ({ ctx, input }) => { try { - const { user, db } = ctx; + const { db } = ctx; const totalAmount = input.items.reduce( (acc, item) => acc + item.price * item.quantity, 0, ); + const response = await apiClient.post("/v1/request", { + amount: totalAmount.toString(), + payer: input.clientWallet, + payee: input.walletAddress, + invoiceCurrency: "ETH-sepolia-sepolia", + paymentCurrency: "ETH-sepolia-sepolia", + }); + await db.insert(requestTable).values({ id: ulid(), amount: totalAmount.toString(), @@ -26,13 +33,14 @@ export const invoiceRouter = router({ payer: input.clientWallet, payee: input.walletAddress, dueDate: new Date(input.dueDate).toISOString(), - requestId: ulid(), - paymentReference: ulid(), + requestId: response.data.requestID as string, + paymentReference: response.data.paymentReference as string, clientName: input.clientName, clientEmail: input.clientEmail, invoiceNumber: input.invoiceNumber, items: input.items, notes: input.notes, + userId: ctx.user?.id as string, }); return { success: true }; From 11d7d4df34de116c4402f0201f74434206bc53ba Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Mon, 10 Feb 2025 16:53:57 +0400 Subject: [PATCH 04/33] refactor: update logo letters --- src/app/dashboard/page.tsx | 316 ++++++++--------- src/app/invoices/[requestID]/page.tsx | 476 +++++++++++++------------- src/app/invoices/create/page.tsx | 106 +++--- src/components/user-menu.tsx | 92 ++--- 4 files changed, 495 insertions(+), 495 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 3b2bf45..7eb17cf 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -3,12 +3,12 @@ import { redirect } from "next/navigation"; import Link from "next/link"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, } from "@/components/ui/table"; import { DollarSign, FileText, AlertCircle, PlusCircle } from "lucide-react"; import { UserMenu } from "@/components/user-menu"; @@ -16,167 +16,167 @@ import { Button } from "@/components/ui/button"; // Mock data for demonstration - In real app, this would come from your database const mockInvoices = [ - { id: "INV-001", dueDate: "2024-12-01", amount: 1500, status: "Paid" }, - { id: "INV-002", dueDate: "2024-12-15", amount: 2000, status: "Pending" }, - { id: "INV-003", dueDate: "2024-11-30", amount: 1000, status: "Overdue" }, - { id: "INV-004", dueDate: "2024-12-31", amount: 3000, status: "Pending" }, + { id: "INV-001", dueDate: "2024-12-01", amount: 1500, status: "Paid" }, + { id: "INV-002", dueDate: "2024-12-15", amount: 2000, status: "Pending" }, + { id: "INV-003", dueDate: "2024-11-30", amount: 1000, status: "Overdue" }, + { id: "INV-004", dueDate: "2024-12-31", amount: 3000, status: "Pending" }, ]; export default async function DashboardPage() { - const { user } = await getCurrentSession(); + const { user } = await getCurrentSession(); - if (!user) { - redirect("/"); - } + if (!user) { + redirect("/"); + } - const totalInvoices = mockInvoices.length; - const outstandingInvoices = mockInvoices.filter( - (inv) => inv.status !== "Paid" - ).length; - const totalPayments = mockInvoices.reduce( - (sum, inv) => (inv.status === "Paid" ? sum + inv.amount : sum), - 0 - ); + const totalInvoices = mockInvoices.length; + const outstandingInvoices = mockInvoices.filter( + (inv) => inv.status !== "Paid", + ).length; + const totalPayments = mockInvoices.reduce( + (sum, inv) => (inv.status === "Paid" ? sum + inv.amount : sum), + 0, + ); - return ( -
- {/* Decorative elements */} -
-
-
-
-
-
+ return ( +
+ {/* Decorative elements */} +
+
+
+
+
+
- {/* Dot pattern background */} -
+ {/* Dot pattern background */} +
- {/* Content */} -
- {/* Header */} -
- -
+ {/* Content */} +
+ {/* Header */} +
+ +
- {/* Main Content */} -
-
-

Dashboard

- -
+ {/* Main Content */} +
+
+

Dashboard

+ +
- {/* Summary Section */} -
- - - - Total Invoices - - - - -
- {totalInvoices} -
-
-
- - - - Outstanding Invoices - - - - -
- {outstandingInvoices} -
-
-
- - - - Total Payments - - - - -
- ${totalPayments.toLocaleString()} -
-
-
-
+ {/* Summary Section */} +
+ + + + Total Invoices + + + + +
+ {totalInvoices} +
+
+
+ + + + Outstanding Invoices + + + + +
+ {outstandingInvoices} +
+
+
+ + + + Total Payments + + + + +
+ ${totalPayments.toLocaleString()} +
+
+
+
- {/* Invoice List */} - - - Recent Invoices - - - - - - Invoice ID - Due Date - Amount - Status - - - - {mockInvoices.map((invoice) => ( - - - {invoice.id} - - {invoice.dueDate} - ${invoice.amount.toLocaleString()} - - - {invoice.status} - - - - ))} - -
-
-
-
-
-
- ); + {/* Invoice List */} + + + Recent Invoices + + + + + + Invoice ID + Due Date + Amount + Status + + + + {mockInvoices.map((invoice) => ( + + + {invoice.id} + + {invoice.dueDate} + ${invoice.amount.toLocaleString()} + + + {invoice.status} + + + + ))} + +
+
+
+ +
+
+ ); } diff --git a/src/app/invoices/[requestID]/page.tsx b/src/app/invoices/[requestID]/page.tsx index 4423767..5239c34 100644 --- a/src/app/invoices/[requestID]/page.tsx +++ b/src/app/invoices/[requestID]/page.tsx @@ -12,256 +12,256 @@ import { ArrowLeft, CheckCircle, Clock, XCircle } from "lucide-react"; // Mock data for demonstration const invoiceData = { - id: "INV-001", - amount: 1500, - dueDate: "2024-12-31", - status: "Pending", - clientName: "John Doe", - clientEmail: "john@example.com", - items: [ - { description: "Web Development", quantity: 1, price: 1000 }, - { description: "UI/UX Design", quantity: 1, price: 500 }, - ], - paymentMethod: "crypto", - cryptocurrency: "ETH", - walletAddress: "0x1234...5678", + id: "INV-001", + amount: 1500, + dueDate: "2024-12-31", + status: "Pending", + clientName: "John Doe", + clientEmail: "john@example.com", + items: [ + { description: "Web Development", quantity: 1, price: 1000 }, + { description: "UI/UX Design", quantity: 1, price: 500 }, + ], + paymentMethod: "crypto", + cryptocurrency: "ETH", + walletAddress: "0x1234...5678", }; export default function PaymentPage() { - const [paymentStatus, setPaymentStatus] = useState(invoiceData.status); - const [connectedWallet, setConnectedWallet] = useState(""); + const [paymentStatus, setPaymentStatus] = useState(invoiceData.status); + const [connectedWallet, setConnectedWallet] = useState(""); - const handleConnectWallet = () => { - // Simulating wallet connection - setConnectedWallet("0xABCD...EFGH"); - }; + const handleConnectWallet = () => { + // Simulating wallet connection + setConnectedWallet("0xABCD...EFGH"); + }; - const handlePayment = () => { - // Simulating payment process - setPaymentStatus("Processing"); - setTimeout(() => { - setPaymentStatus("Paid"); - }, 2000); - }; + const handlePayment = () => { + // Simulating payment process + setPaymentStatus("Processing"); + setTimeout(() => { + setPaymentStatus("Paid"); + }, 2000); + }; - return ( -
- {/* Decorative elements */} -
-
-
-
-
-
+ return ( +
+ {/* Decorative elements */} +
+
+
+
+
+
- {/* Dot pattern background */} -
+ {/* Dot pattern background */} +
- {/* Content */} -
- {/* Header */} -
- -
+ {/* Content */} +
+ {/* Header */} +
+ +
- {/* Main Content */} -
-
- - - -

- Invoice Payment -

-
+ {/* Main Content */} +
+
+ + + +

+ Invoice Payment +

+
-
- {/* Payment Section */} - - - - Payment Details - - {paymentStatus === "Paid" && ( - - )} - {paymentStatus === "Processing" && ( - - )} - {paymentStatus === "Pending" && ( - - )} - {paymentStatus} - - - - -
-

- Secure Payment -

-

- This payment is secured using blockchain technology. Your - transaction will be processed safely and transparently. -

-
+
+ {/* Payment Section */} + + + + Payment Details + + {paymentStatus === "Paid" && ( + + )} + {paymentStatus === "Processing" && ( + + )} + {paymentStatus === "Pending" && ( + + )} + {paymentStatus} + + + + +
+

+ Secure Payment +

+

+ This payment is secured using blockchain technology. Your + transaction will be processed safely and transparently. +

+
-
- -
- ${invoiceData.amount.toFixed(2)}{" "} - {invoiceData.cryptocurrency} -
-
+
+ +
+ ${invoiceData.amount.toFixed(2)}{" "} + {invoiceData.cryptocurrency} +
+
-
- -
- {invoiceData.walletAddress} -
-
+
+ +
+ {invoiceData.walletAddress} +
+
- - - Connect Wallet - Manual Transfer - - - {connectedWallet ? ( -
- -
- {connectedWallet} -
-
- ) : ( - - )} - {connectedWallet && ( - - )} -
- -
- -

- Please send the exact amount of{" "} - {invoiceData.amount.toFixed(2)}{" "} - {invoiceData.cryptocurrency} to the recipient address - above. Once the transaction is confirmed on the - blockchain, your payment will be marked as complete. -

-
- -
-
-
-
+ + + Connect Wallet + Manual Transfer + + + {connectedWallet ? ( +
+ +
+ {connectedWallet} +
+
+ ) : ( + + )} + {connectedWallet && ( + + )} +
+ +
+ +

+ Please send the exact amount of{" "} + {invoiceData.amount.toFixed(2)}{" "} + {invoiceData.cryptocurrency} to the recipient address + above. Once the transaction is confirmed on the + blockchain, your payment will be marked as complete. +

+
+ +
+
+ + - {/* Invoice Preview */} - - - Invoice Preview - - -
-

- Invoice #{invoiceData.id} -

-

Due Date: {invoiceData.dueDate}

-
-
-

Bill To:

-

{invoiceData.clientName}

-

{invoiceData.clientEmail}

-
-
-

Items:

- - - - - - - - - - - {invoiceData.items.map((item, index) => ( - - - - - - - ))} - - - - - - - -
DescriptionQtyPriceTotal
{item.description}{item.quantity} - ${item.price.toFixed(2)} - - ${(item.quantity * item.price).toFixed(2)} -
- Total: - - ${invoiceData.amount.toFixed(2)} -
-
-
-

Payment Details:

-

Cryptocurrency: {invoiceData.cryptocurrency}

-

Recipient Wallet: {invoiceData.walletAddress}

-
-
-
-
-
-
-
- ); + {/* Invoice Preview */} + + + Invoice Preview + + +
+

+ Invoice #{invoiceData.id} +

+

Due Date: {invoiceData.dueDate}

+
+
+

Bill To:

+

{invoiceData.clientName}

+

{invoiceData.clientEmail}

+
+
+

Items:

+ + + + + + + + + + + {invoiceData.items.map((item, index) => ( + + + + + + + ))} + + + + + + + +
DescriptionQtyPriceTotal
{item.description}{item.quantity} + ${item.price.toFixed(2)} + + ${(item.quantity * item.price).toFixed(2)} +
+ Total: + + ${invoiceData.amount.toFixed(2)} +
+
+
+

Payment Details:

+

Cryptocurrency: {invoiceData.cryptocurrency}

+

Recipient Wallet: {invoiceData.walletAddress}

+
+
+
+
+ +
+
+ ); } diff --git a/src/app/invoices/create/page.tsx b/src/app/invoices/create/page.tsx index 4ee4cdf..a33836b 100644 --- a/src/app/invoices/create/page.tsx +++ b/src/app/invoices/create/page.tsx @@ -5,63 +5,63 @@ import Link from "next/link"; import { redirect } from "next/navigation"; export default async function CreateInvoicePage() { - const { session } = await getCurrentSession(); + const { session } = await getCurrentSession(); - if (!session) { - redirect("/"); - } + if (!session) { + redirect("/"); + } - return ( -
- {/* Decorative elements */} -
-
-
-
-
-
+ return ( +
+ {/* Decorative elements */} +
+
+
+
+
+
- {/* Dot pattern background */} -
+ {/* Dot pattern background */} +
- {/* Content */} -
- {/* Header */} -
- -
+ {/* Content */} +
+ {/* Header */} +
+ +
- {/* Main Content */} -
-
- - - -

- Create New Invoice -

-
+ {/* Main Content */} +
+
+ + + +

+ Create New Invoice +

+
- -
-
-
- ); + + +
+
+ ); } diff --git a/src/components/user-menu.tsx b/src/components/user-menu.tsx index b146dbf..3ee4847 100644 --- a/src/components/user-menu.tsx +++ b/src/components/user-menu.tsx @@ -2,12 +2,12 @@ import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { LogOut } from "lucide-react"; import { type User } from "@/server/db/schema"; @@ -15,48 +15,48 @@ import { api } from "@/trpc/react"; import { useRouter } from "next/navigation"; interface UserMenuProps { - user: Pick; + user: Pick; } export function UserMenu({ user }: UserMenuProps) { - const router = useRouter(); - const logout = api.auth.logout.useMutation({ - onSuccess: () => { - router.replace("/"); - }, - }); + const router = useRouter(); + const logout = api.auth.logout.useMutation({ + onSuccess: () => { + router.replace("/"); + }, + }); - return ( - - - - - - -
-

- {user.name ?? "User"} -

-
-
- - logout.mutate()} - className="text-sm text-neutral-700 cursor-pointer hover:text-neutral-900" - > - - Log out - -
-
- ); + return ( + + + + + + +
+

+ {user.name ?? "User"} +

+
+
+ + logout.mutate()} + className="text-sm text-neutral-700 cursor-pointer hover:text-neutral-900" + > + + Log out + +
+
+ ); } From 1256700dcd4dda8313ba026cc0790014f47576d0 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 14:54:07 +0400 Subject: [PATCH 05/33] feat: query invoices and display them in dashboard --- src/app/dashboard/page.tsx | 159 +++++++++++++++----------- src/app/invoices/[requestID]/page.tsx | 12 +- src/server/routers/invoice.ts | 22 ++++ 3 files changed, 122 insertions(+), 71 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 7eb17cf..e4b39b1 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,6 +1,4 @@ -import { getCurrentSession } from "@/server/auth"; -import { redirect } from "next/navigation"; -import Link from "next/link"; +import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Table, @@ -10,33 +8,30 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { DollarSign, FileText, AlertCircle, PlusCircle } from "lucide-react"; import { UserMenu } from "@/components/user-menu"; -import { Button } from "@/components/ui/button"; - -// Mock data for demonstration - In real app, this would come from your database -const mockInvoices = [ - { id: "INV-001", dueDate: "2024-12-01", amount: 1500, status: "Paid" }, - { id: "INV-002", dueDate: "2024-12-15", amount: 2000, status: "Pending" }, - { id: "INV-003", dueDate: "2024-11-30", amount: 1000, status: "Overdue" }, - { id: "INV-004", dueDate: "2024-12-31", amount: 3000, status: "Pending" }, -]; +import { getCurrentSession } from "@/server/auth"; +import { api } from "@/trpc/server"; +import { + AlertCircle, + DollarSign, + Eye, + FileText, + PlusCircle, +} from "lucide-react"; +import Link from "next/link"; +import { redirect } from "next/navigation"; export default async function DashboardPage() { const { user } = await getCurrentSession(); + const { invoices, totalPayments, outstandingInvoices } = + await api.invoice.getAll.query(); + if (!user) { redirect("/"); } - const totalInvoices = mockInvoices.length; - const outstandingInvoices = mockInvoices.filter( - (inv) => inv.status !== "Paid", - ).length; - const totalPayments = mockInvoices.reduce( - (sum, inv) => (inv.status === "Paid" ? sum + inv.amount : sum), - 0, - ); + const totalInvoices = invoices.length; return (
@@ -79,15 +74,14 @@ export default async function DashboardPage() {

Dashboard

- + + Create Invoice +
{/* Summary Section */} @@ -136,43 +130,80 @@ export default async function DashboardPage() { {/* Invoice List */} - Recent Invoices +
+ + Recent Invoices + +
- - - - - Invoice ID - Due Date - Amount - Status - - - - {mockInvoices.map((invoice) => ( - - - {invoice.id} - - {invoice.dueDate} - ${invoice.amount.toLocaleString()} - - - {invoice.status} - - + + {invoices.length === 0 ? ( +
+ +

No invoices found

+

Get started by creating your first invoice.

+ + + Create Invoice + +
+ ) : ( +
+ + + Invoice # + Client + Amount + Due Date + Status + Actions - ))} - -
+ + + {invoices.map((invoice) => ( + + + {invoice.invoiceNumber} + + {invoice.clientName} + + {Number(invoice.amount).toLocaleString()} {invoice.currency} + + + {new Date(invoice.dueDate).toLocaleDateString()} + + + + {invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)} + + + +
+ + + View + +
+
+
+ ))} +
+ + )}
diff --git a/src/app/invoices/[requestID]/page.tsx b/src/app/invoices/[requestID]/page.tsx index 5239c34..e0ba4b3 100644 --- a/src/app/invoices/[requestID]/page.tsx +++ b/src/app/invoices/[requestID]/page.tsx @@ -1,14 +1,12 @@ "use client"; -import { useState } from "react"; -import Image from "next/image"; -import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { ArrowLeft, CheckCircle, Clock, XCircle } from "lucide-react"; +import { ArrowLeft, CheckCircle, Clock } from "lucide-react"; +import Link from "next/link"; +import { useState } from "react"; // Mock data for demonstration const invoiceData = { @@ -103,8 +101,8 @@ export default function PaymentPage() { paymentStatus === "Paid" ? "bg-green-100 text-green-800" : paymentStatus === "Processing" - ? "bg-yellow-100 text-yellow-800" - : "bg-blue-100 text-blue-800" + ? "bg-yellow-100 text-yellow-800" + : "bg-blue-100 text-blue-800" }`} > {paymentStatus === "Paid" && ( diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index 9edc7b6..2c12e5e 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -3,6 +3,7 @@ import { invoiceFormSchema } from "@/lib/schemas/invoice"; import { requestTable } from "@/server/db/schema"; import { ulid } from "ulid"; import { protectedProcedure, router } from "../trpc"; +import { eq } from "drizzle-orm"; export const invoiceRouter = router({ create: protectedProcedure @@ -49,4 +50,25 @@ export const invoiceRouter = router({ return { success: false }; } }), + getAll: protectedProcedure.query(async ({ ctx }) => { + const { db } = ctx; + const invoices = await db.query.requestTable.findMany({ + where: eq(requestTable.userId, ctx.user?.id as string), + }); + + const totalPayments = invoices.reduce( + (acc, invoice) => acc + Number(invoice.amount), + 0, + ); + + const outstandingInvoices = invoices.filter( + (invoice) => invoice.status !== "paid", + ); + + return { + invoices, + totalPayments, + outstandingInvoices: outstandingInvoices.length, + }; + }), }); From 083e81861e809279c4701724fb3c0f5c96181c66 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 16:14:24 +0400 Subject: [PATCH 06/33] feat: improve invoice creation flow --- package-lock.json | 22 +++++++++++++++++++++ package.json | 2 ++ src/app/layout.tsx | 3 +++ src/components/invoice-creator.tsx | 27 ++++++++++++++++++++++++-- src/components/ui/sonner.tsx | 31 ++++++++++++++++++++++++++++++ src/server/routers/invoice.ts | 9 ++++++--- 6 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/components/ui/sonner.tsx diff --git a/package-lock.json b/package-lock.json index c3b25b4..3082be3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,10 +32,12 @@ "ioredis": "^5.4.1", "lucide-react": "^0.460.0", "next": "14.2.16", + "next-themes": "^0.4.4", "pg": "^8.13.1", "react": "^18", "react-dom": "^18", "react-hook-form": "^7.53.2", + "sonner": "^1.7.4", "superjson": "^2.2.1", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", @@ -4012,6 +4014,16 @@ } } }, + "node_modules/next-themes": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz", + "integrity": "sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -4731,6 +4743,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/sonner": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", + "integrity": "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index e3083da..6c473dc 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,12 @@ "ioredis": "^5.4.1", "lucide-react": "^0.460.0", "next": "14.2.16", + "next-themes": "^0.4.4", "pg": "^8.13.1", "react": "^18", "react-dom": "^18", "react-hook-form": "^7.53.2", + "sonner": "^1.7.4", "superjson": "^2.2.1", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ee092b8..357b7aa 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,8 @@ import localFont from "next/font/local"; import "./globals.css"; import { cookies } from "next/headers"; import { TRPCReactProvider } from "@/trpc/react"; +import { Toaster } from "@/components/ui/sonner" + const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -33,6 +35,7 @@ export default function RootLayout({ {children} + ); diff --git a/src/components/invoice-creator.tsx b/src/components/invoice-creator.tsx index 1ffd7e9..fd67d4e 100644 --- a/src/components/invoice-creator.tsx +++ b/src/components/invoice-creator.tsx @@ -8,11 +8,28 @@ import { InvoiceForm } from "@/components/invoice-form"; import { InvoicePreview } from "@/components/invoice-preview"; import { api } from "@/trpc/react"; import { useRouter } from "next/navigation"; +import { toast } from "sonner"; export function InvoiceCreator() { const router = useRouter(); - const { mutate: createInvoice, isLoading } = api.invoice.create.useMutation(); + const { mutate: createInvoice, isLoading } = api.invoice.create.useMutation({ + onSuccess: (data) => { + if(!data.invoice) { + toast.error("Failed to create invoice", { + description: "Please try again", + }); + return; + } + + toast.success("Invoice created successfully" , { + description: "Redirecting to invoice details in 3 seconds", + }); + setTimeout(() => { + router.push(`/invoices/${data.invoice.id}`); + }, 3000); + }, + }); const form = useForm({ resolver: zodResolver(invoiceFormSchema), @@ -30,7 +47,13 @@ export function InvoiceCreator() { }); const onSubmit = async (data: InvoiceFormValues) => { - createInvoice(data); + try{ + await createInvoice(data); + } catch (error) { + toast.error("Failed to create invoice", { + description: error instanceof Error ? error.message : "An unexpected error occurred", + }); + } }; return ( diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx new file mode 100644 index 0000000..452f4d9 --- /dev/null +++ b/src/components/ui/sonner.tsx @@ -0,0 +1,31 @@ +"use client" + +import { useTheme } from "next-themes" +import { Toaster as Sonner } from "sonner" + +type ToasterProps = React.ComponentProps + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + + ) +} + +export { Toaster } diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index 2c12e5e..37f8811 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -25,7 +25,7 @@ export const invoiceRouter = router({ paymentCurrency: "ETH-sepolia-sepolia", }); - await db.insert(requestTable).values({ + const invoice = await db.insert(requestTable).values({ id: ulid(), amount: totalAmount.toString(), currency: input.cryptocurrency, @@ -42,9 +42,12 @@ export const invoiceRouter = router({ items: input.items, notes: input.notes, userId: ctx.user?.id as string, - }); + }).returning(); - return { success: true }; + return { + success: true, + invoice: invoice[0], + }; } catch (error) { console.log("Error: ", error); return { success: false }; From 2f04256c1c8ce2ffb18e24b1f1c79692b3f7c4ec Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 16:18:19 +0400 Subject: [PATCH 07/33] refactor: optimize date and status display --- package-lock.json | 11 ++++++ package.json | 1 + src/app/dashboard/page.tsx | 80 ++++++++++++++++++++------------------ 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3082be3..63597df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "crypto-js": "^4.2.0", + "date-fns": "^4.1.0", "drizzle-kit": "^0.28.1", "drizzle-orm": "^0.36.3", "ethers": "^5.7.2", @@ -3091,6 +3092,16 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "devOptional": true }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", diff --git a/package.json b/package.json index 6c473dc..01bf20a 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "crypto-js": "^4.2.0", + "date-fns": "^4.1.0", "drizzle-kit": "^0.28.1", "drizzle-orm": "^0.36.3", "ethers": "^5.7.2", diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index e4b39b1..0a07bb9 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -20,6 +20,7 @@ import { } from "lucide-react"; import Link from "next/link"; import { redirect } from "next/navigation"; +import { format, isPast } from "date-fns"; export default async function DashboardPage() { const { user } = await getCurrentSession(); @@ -163,44 +164,49 @@ export default async function DashboardPage() { - {invoices.map((invoice) => ( - - - {invoice.invoiceNumber} - - {invoice.clientName} - - {Number(invoice.amount).toLocaleString()} {invoice.currency} - - - {new Date(invoice.dueDate).toLocaleDateString()} - - - - {invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)} - - - -
- { + const dueDate = new Date(invoice.dueDate); + const isOverdue = invoice.status === "pending" && isPast(dueDate); + + return ( + + + {invoice.invoiceNumber} + + {invoice.clientName} + + {Number(invoice.amount).toLocaleString()} {invoice.currency} + + + {format(dueDate, 'do MMMM yyyy')} + + + - - View - -
-
-
- ))} + {isOverdue ? "Overdue" : invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)} + + + +
+ + + View + +
+
+ + ); + })}
)} From 5aa389beaeec79e0859fa0ab7aa04c60e6d945c8 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 17:00:22 +0400 Subject: [PATCH 08/33] feat: update invoice flow to use tokne-list currencies and support conversion --- src/app/dashboard/page.tsx | 7 +++- src/components/invoice-creator.tsx | 3 +- src/components/invoice-form.tsx | 57 ++++++++++++++++++++++++------ src/components/invoice-preview.tsx | 12 ++++--- src/lib/currencies.ts | 39 ++++++++++++++++++++ src/lib/schemas/invoice.ts | 6 ++-- src/server/db/schema.ts | 3 +- src/server/routers/invoice.ts | 7 ++-- 8 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 src/lib/currencies.ts diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 0a07bb9..bd834b4 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -21,6 +21,7 @@ import { import Link from "next/link"; import { redirect } from "next/navigation"; import { format, isPast } from "date-fns"; +import { formatCurrencyLabel } from "@/lib/currencies"; export default async function DashboardPage() { const { user } = await getCurrentSession(); @@ -158,6 +159,7 @@ export default async function DashboardPage() { Invoice # Client Amount + Currency Due Date Status Actions @@ -175,7 +177,10 @@ export default async function DashboardPage() { {invoice.clientName} - {Number(invoice.amount).toLocaleString()} {invoice.currency} + {Number(invoice.amount).toLocaleString()} + + + {formatCurrencyLabel(invoice.invoiceCurrency)} {format(dueDate, 'do MMMM yyyy')} diff --git a/src/components/invoice-creator.tsx b/src/components/invoice-creator.tsx index fd67d4e..d44cf12 100644 --- a/src/components/invoice-creator.tsx +++ b/src/components/invoice-creator.tsx @@ -40,7 +40,8 @@ export function InvoiceCreator() { clientEmail: "", items: [{ description: "", quantity: 1, price: 0 }], notes: "", - cryptocurrency: "eth", + invoiceCurrency: "USD", + paymentCurrency: "", walletAddress: "", clientWallet: "", }, diff --git a/src/components/invoice-form.tsx b/src/components/invoice-form.tsx index 3b2e7fb..e1a8cfd 100644 --- a/src/components/invoice-form.tsx +++ b/src/components/invoice-form.tsx @@ -14,6 +14,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { INVOICE_CURRENCIES, getPaymentCurrenciesForInvoice, formatCurrencyLabel, InvoiceCurrency } from "@/lib/currencies"; interface InvoiceFormProps { form: UseFormReturn; @@ -155,29 +156,63 @@ export function InvoiceForm({ form, onSubmit, isLoading }: InvoiceFormProps) {
- + - {form.formState.errors.cryptocurrency && ( + {form.formState.errors.invoiceCurrency && (

- {form.formState.errors.cryptocurrency.message} + {form.formState.errors.invoiceCurrency.message}

)}
+ {/* Only show payment currency selector for USD invoices */} + {form.watch("invoiceCurrency") === "USD" && ( +
+ + + {form.formState.errors.paymentCurrency && ( +

+ {form.formState.errors.paymentCurrency.message} +

+ )} +
+ )} +
; @@ -48,11 +49,11 @@ export function InvoicePreview({ data }: InvoicePreviewProps) { {item.quantity || 0} {(item.price || 0).toFixed(2)}{" "} - {data.cryptocurrency?.toUpperCase() || "---"} + {formatCurrencyLabel(data.invoiceCurrency || "---")} {((item.quantity || 0) * (item.price || 0)).toFixed(2)}{" "} - {data.cryptocurrency?.toUpperCase() || "---"} + {formatCurrencyLabel(data.invoiceCurrency || "---")} ))} @@ -64,7 +65,7 @@ export function InvoicePreview({ data }: InvoicePreviewProps) { {calculateTotal().toFixed(2)}{" "} - {data.cryptocurrency?.toUpperCase() || "---"} + {formatCurrencyLabel(data.invoiceCurrency || "---")} @@ -72,7 +73,10 @@ export function InvoicePreview({ data }: InvoicePreviewProps) {

Payment Details:

-

Cryptocurrency: {data.cryptocurrency || "---"}

+

Invoice Currency: {formatCurrencyLabel(data.invoiceCurrency || "---")}

+ {data.paymentCurrency && data.paymentCurrency !== data.invoiceCurrency && ( +

Payment Currency: {formatCurrencyLabel(data.paymentCurrency)}

+ )}

Your Wallet: {data.walletAddress || "---"}

Client's Wallet: {data.clientWallet || "---"}

diff --git a/src/lib/currencies.ts b/src/lib/currencies.ts new file mode 100644 index 0000000..dfc9982 --- /dev/null +++ b/src/lib/currencies.ts @@ -0,0 +1,39 @@ +export const INVOICE_CURRENCIES = [ + 'USD', + 'ETH-sepolia-sepolia', + 'FAU-sepolia', + 'fUSDC-sepolia', + 'fUSDT-sepolia' +] as const; +export type InvoiceCurrency = (typeof INVOICE_CURRENCIES)[number]; + +export const PAYMENT_CURRENCIES = { + USD: ['ETH-sepolia-sepolia', 'FAU-sepolia'] as const, + 'ETH-sepolia-sepolia': ['ETH-sepolia-sepolia'] as const, + 'FAU-sepolia': ['FAU-sepolia'] as const, + 'fUSDC-sepolia': ['fUSDC-sepolia'] as const, + 'fUSDT-sepolia': ['fUSDT-sepolia'] as const, +} as const; + +export type PaymentCurrency = (typeof PAYMENT_CURRENCIES)[InvoiceCurrency][number]; + +export function getPaymentCurrenciesForInvoice(invoiceCurrency: InvoiceCurrency): PaymentCurrency[] { + return [...PAYMENT_CURRENCIES[invoiceCurrency]]; +} + +export function formatCurrencyLabel(currency: string): string { + switch (currency) { + case 'ETH-sepolia-sepolia': + return 'Sepolia ETH'; + case 'FAU-sepolia': + return 'Faucet Token (FAU)'; + case 'fUSDC-sepolia': + return 'Sepolia USDC'; + case 'fUSDT-sepolia': + return 'Sepolia USDT'; + case 'USD': + return 'US Dollar'; + default: + return currency; + } +} diff --git a/src/lib/schemas/invoice.ts b/src/lib/schemas/invoice.ts index 012d170..2c88f00 100644 --- a/src/lib/schemas/invoice.ts +++ b/src/lib/schemas/invoice.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { INVOICE_CURRENCIES, PAYMENT_CURRENCIES } from "@/lib/currencies"; export const invoiceFormSchema = z.object({ invoiceNumber: z.string().min(1, "Invoice number is required"), @@ -15,9 +16,10 @@ export const invoiceFormSchema = z.object({ ) .min(1, "At least one item is required"), notes: z.string().optional(), - cryptocurrency: z.enum(["eth", "usdc", "fau"], { - required_error: "Please select a cryptocurrency", + invoiceCurrency: z.enum(INVOICE_CURRENCIES, { + required_error: "Please select an invoice currency", }), + paymentCurrency: z.string().min(1, "Payment currency is required"), walletAddress: z.string().min(1, "Wallet address is required"), clientWallet: z.string().min(1, "Client wallet address is required"), }); diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 97d09e4..32b42ab 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -52,7 +52,8 @@ export const requestTable = createTable("request", { items: json().notNull(), notes: text(), amount: text().notNull(), - currency: text().notNull(), + invoiceCurrency: text().notNull(), + paymentCurrency: text().notNull(), status: text().notNull(), payer: text().notNull(), payee: text().notNull(), diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index 37f8811..c69ffec 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -21,14 +21,15 @@ export const invoiceRouter = router({ amount: totalAmount.toString(), payer: input.clientWallet, payee: input.walletAddress, - invoiceCurrency: "ETH-sepolia-sepolia", - paymentCurrency: "ETH-sepolia-sepolia", + invoiceCurrency: input.invoiceCurrency, + paymentCurrency: input.paymentCurrency, }); const invoice = await db.insert(requestTable).values({ id: ulid(), amount: totalAmount.toString(), - currency: input.cryptocurrency, + invoiceCurrency: input.invoiceCurrency, + paymentCurrency: input.paymentCurrency, type: "invoice", status: "pending", payer: input.clientWallet, From 4417d1c882c2bea38d43d1bf0eec547c663bb83a Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 17:13:17 +0400 Subject: [PATCH 09/33] feat: update payment page to use live data --- src/app/invoices/[ID]/page.tsx | 142 ++++++++++++++ src/app/invoices/[requestID]/page.tsx | 265 -------------------------- src/components/payment-section.tsx | 157 +++++++++++++++ src/server/routers/invoice.ts | 8 + 4 files changed, 307 insertions(+), 265 deletions(-) create mode 100644 src/app/invoices/[ID]/page.tsx delete mode 100644 src/app/invoices/[requestID]/page.tsx create mode 100644 src/components/payment-section.tsx diff --git a/src/app/invoices/[ID]/page.tsx b/src/app/invoices/[ID]/page.tsx new file mode 100644 index 0000000..e999b93 --- /dev/null +++ b/src/app/invoices/[ID]/page.tsx @@ -0,0 +1,142 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { ArrowLeft } from "lucide-react"; +import Link from "next/link"; +import { PaymentSection } from "@/components/payment-section"; +import { notFound } from "next/navigation"; +import { api } from "@/trpc/server"; +import { formatCurrencyLabel } from "@/lib/currencies"; + +type InvoiceItem = { + description: string; + quantity: number; + price: number; +}; + +export default async function PaymentPage({ + params, +}: { + params: { ID: string }; +}) { + const invoice = await api.invoice.getById.query(params.ID); + + if (!invoice) { + notFound(); + } + + return ( +
+ {/* Decorative elements */} +
+
+
+
+
+
+ + {/* Dot pattern background */} +
+ + {/* Content */} +
+ {/* Header */} +
+ +
+ + {/* Main Content */} +
+
+

+ Invoice Payment +

+
+ +
+ {/* Payment Section */} + + + {/* Invoice Preview */} + + + Invoice Preview + + +
+

+ Invoice #{invoice.invoiceNumber} +

+

Due Date: {new Date(invoice.dueDate).toLocaleDateString()}

+
+
+

Bill To:

+

{invoice.clientName}

+

{invoice.clientEmail}

+
+
+

Items:

+ + + + + + + + + + + {(invoice.items as InvoiceItem[]).map((item, index) => ( + + + + + + + ))} + + + + + + + +
DescriptionQtyPriceTotal
{item.description}{item.quantity} + ${item.price.toFixed(2)} + + ${(item.quantity * item.price).toFixed(2)} +
+ Total: + + ${Number(invoice.amount).toFixed(2)} +
+
+
+

Payment Details:

+

Invoice Currency: {formatCurrencyLabel(invoice.invoiceCurrency)}

+

Payment Currency: {formatCurrencyLabel(invoice.paymentCurrency)}

+

Recipient Wallet: {invoice.payee}

+
+
+
+
+
+
+
+ ); +} diff --git a/src/app/invoices/[requestID]/page.tsx b/src/app/invoices/[requestID]/page.tsx deleted file mode 100644 index e0ba4b3..0000000 --- a/src/app/invoices/[requestID]/page.tsx +++ /dev/null @@ -1,265 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { ArrowLeft, CheckCircle, Clock } from "lucide-react"; -import Link from "next/link"; -import { useState } from "react"; - -// Mock data for demonstration -const invoiceData = { - id: "INV-001", - amount: 1500, - dueDate: "2024-12-31", - status: "Pending", - clientName: "John Doe", - clientEmail: "john@example.com", - items: [ - { description: "Web Development", quantity: 1, price: 1000 }, - { description: "UI/UX Design", quantity: 1, price: 500 }, - ], - paymentMethod: "crypto", - cryptocurrency: "ETH", - walletAddress: "0x1234...5678", -}; - -export default function PaymentPage() { - const [paymentStatus, setPaymentStatus] = useState(invoiceData.status); - const [connectedWallet, setConnectedWallet] = useState(""); - - const handleConnectWallet = () => { - // Simulating wallet connection - setConnectedWallet("0xABCD...EFGH"); - }; - - const handlePayment = () => { - // Simulating payment process - setPaymentStatus("Processing"); - setTimeout(() => { - setPaymentStatus("Paid"); - }, 2000); - }; - - return ( -
- {/* Decorative elements */} -
-
-
-
-
-
- - {/* Dot pattern background */} -
- - {/* Content */} -
- {/* Header */} -
- -
- - {/* Main Content */} -
-
- - - -

- Invoice Payment -

-
- -
- {/* Payment Section */} - - - - Payment Details - - {paymentStatus === "Paid" && ( - - )} - {paymentStatus === "Processing" && ( - - )} - {paymentStatus === "Pending" && ( - - )} - {paymentStatus} - - - - -
-

- Secure Payment -

-

- This payment is secured using blockchain technology. Your - transaction will be processed safely and transparently. -

-
- -
- -
- ${invoiceData.amount.toFixed(2)}{" "} - {invoiceData.cryptocurrency} -
-
- -
- -
- {invoiceData.walletAddress} -
-
- - - - Connect Wallet - Manual Transfer - - - {connectedWallet ? ( -
- -
- {connectedWallet} -
-
- ) : ( - - )} - {connectedWallet && ( - - )} -
- -
- -

- Please send the exact amount of{" "} - {invoiceData.amount.toFixed(2)}{" "} - {invoiceData.cryptocurrency} to the recipient address - above. Once the transaction is confirmed on the - blockchain, your payment will be marked as complete. -

-
- -
-
-
-
- - {/* Invoice Preview */} - - - Invoice Preview - - -
-

- Invoice #{invoiceData.id} -

-

Due Date: {invoiceData.dueDate}

-
-
-

Bill To:

-

{invoiceData.clientName}

-

{invoiceData.clientEmail}

-
-
-

Items:

- - - - - - - - - - - {invoiceData.items.map((item, index) => ( - - - - - - - ))} - - - - - - - -
DescriptionQtyPriceTotal
{item.description}{item.quantity} - ${item.price.toFixed(2)} - - ${(item.quantity * item.price).toFixed(2)} -
- Total: - - ${invoiceData.amount.toFixed(2)} -
-
-
-

Payment Details:

-

Cryptocurrency: {invoiceData.cryptocurrency}

-

Recipient Wallet: {invoiceData.walletAddress}

-
-
-
-
-
-
-
- ); -} diff --git a/src/components/payment-section.tsx b/src/components/payment-section.tsx new file mode 100644 index 0000000..f5d4a2e --- /dev/null +++ b/src/components/payment-section.tsx @@ -0,0 +1,157 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Label } from "@/components/ui/label"; +import { CheckCircle, Clock, Wallet } from "lucide-react"; +import { useState } from "react"; +import { formatCurrencyLabel } from "@/lib/currencies"; +import { Request } from "@/server/db/schema"; + +interface PaymentSectionProps { + invoice: NonNullable; +} + +export function PaymentSection({ invoice }: PaymentSectionProps) { + const [paymentStatus, setPaymentStatus] = useState(invoice.status); + const [connectedWallet, setConnectedWallet] = useState(""); + const [currentStep, setCurrentStep] = useState(1); + + const handleConnectWallet = () => { + setConnectedWallet("0xABCD...EFGH"); + setCurrentStep(2); + }; + + const handlePayment = () => { + setPaymentStatus("processing"); + setTimeout(() => { + setPaymentStatus("paid"); + }, 2000); + }; + + const showCurrencyConversion = invoice.invoiceCurrency !== invoice.paymentCurrency; + + return ( + + + + Payment Details + + {paymentStatus === "paid" && ( + + )} + {paymentStatus === "processing" && ( + + )} + {paymentStatus === "pending" && ( + + )} + {paymentStatus} + + + + +
+

+ Secure Payment +

+

+ This payment is secured using blockchain technology. Your + transaction will be processed safely and transparently. +

+
+ +
+ +
+
+ {formatCurrencyLabel(invoice.invoiceCurrency)} {Number(invoice.amount).toFixed(2)} +
+ {showCurrencyConversion && ( +
+ Payment will be processed in {formatCurrencyLabel(invoice.paymentCurrency)} +
+ Note: The final amount in {formatCurrencyLabel(invoice.paymentCurrency)} will be calculated at the current exchange rate when payment is initiated. +
+
+ )} +
+
+ +
+ +
+ {invoice.payee} +
+
+ + {/* Payment Steps */} +
+ {/* Step indicators */} +
+
+
= 1 ? 'text-black' : 'text-zinc-300'}`}> +
= 1 ? 'border-black bg-zinc-50' : 'border-zinc-300'}`}> + +
+ Connect Wallet +
+
= 2 ? 'bg-black' : 'bg-zinc-300'}`} /> +
= 2 ? 'text-black' : 'text-zinc-300'}`}> +
= 2 ? 'border-black bg-zinc-50' : 'border-zinc-300'}`}> + +
+ Complete Payment +
+
+
+ + {/* Step Content */} +
+ {currentStep === 1 && ( +
+

+ Connect your wallet to proceed with the payment +

+ +
+ )} + + {currentStep === 2 && ( +
+
+ +
+ {connectedWallet} +
+
+

+ Please confirm the payment amount and recipient address before proceeding. + {showCurrencyConversion && ` Payment will be processed in ${formatCurrencyLabel(invoice.paymentCurrency)}.`} +

+ +
+ )} +
+
+ + + ); +} diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index c69ffec..d9907b3 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -4,6 +4,7 @@ import { requestTable } from "@/server/db/schema"; import { ulid } from "ulid"; import { protectedProcedure, router } from "../trpc"; import { eq } from "drizzle-orm"; +import { z } from "zod"; export const invoiceRouter = router({ create: protectedProcedure @@ -75,4 +76,11 @@ export const invoiceRouter = router({ outstandingInvoices: outstandingInvoices.length, }; }), + getById: protectedProcedure.input(z.string()).query(async ({ ctx, input }) => { + const { db } = ctx; + const invoice = await db.query.requestTable.findFirst({ + where: eq(requestTable.id, input), + }); + return invoice; + }), }); From f84d0cebedbecaafd737f87c37906ee6837fbe83 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 17:35:19 +0400 Subject: [PATCH 10/33] feat: add appKit wallet to the app --- package-lock.json | 2074 ++++++++++++++++++++++++---- package.json | 2 + src/app/invoices/[ID]/page.tsx | 7 +- src/app/layout.tsx | 50 +- src/components/app-kit.tsx | 28 + src/components/payment-section.tsx | 359 +++-- 6 files changed, 2114 insertions(+), 406 deletions(-) create mode 100644 src/components/app-kit.tsx diff --git a/package-lock.json b/package-lock.json index 63597df..1b4b456 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,8 @@ "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.1", + "@reown/appkit": "^1.6.8", + "@reown/appkit-adapter-ethers5": "^1.6.8", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.45.2", "@trpc/react-query": "^10.45.2", @@ -61,7 +63,8 @@ "node_modules/@adraffy/ens-normalize": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", - "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==" + "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==", + "license": "MIT" }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", @@ -74,6 +77,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@coinbase/wallet-sdk": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.0.tgz", + "integrity": "sha512-T3+SNmiCw4HzDm4we9wCHCxlP0pqCiwKe4sOwPH3YAK2KSKjxPRydKu6UQJrdONFVLG7ujXvbd/6ZqmvJb8rkw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@noble/hashes": "^1.4.0", + "clsx": "^1.2.1", + "eventemitter3": "^5.0.1", + "preact": "^10.24.2" + } + }, + "node_modules/@coinbase/wallet-sdk/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@drizzle-team/brocli": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", @@ -1587,6 +1613,21 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.3.0.tgz", + "integrity": "sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", + "integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0" + } + }, "node_modules/@next/env": { "version": "14.2.16", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.16.tgz", @@ -1727,6 +1768,57 @@ "node": ">= 10" } }, + "node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2473,33 +2565,180 @@ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" }, + "node_modules/@reown/appkit": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.6.8.tgz", + "integrity": "sha512-GA7VZ+TZ7POVjfjWNyeffLoTIjX+iEvmRdKo9TEEvPBZ77996eiQFnhaaQHCNg1Wf9Ba/lptxVJT07gSZknh5A==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.6.8", + "@reown/appkit-core": "1.6.8", + "@reown/appkit-polyfills": "1.6.8", + "@reown/appkit-scaffold-ui": "1.6.8", + "@reown/appkit-ui": "1.6.8", + "@reown/appkit-utils": "1.6.8", + "@reown/appkit-wallet": "1.6.8", + "@walletconnect/types": "2.18.0", + "@walletconnect/universal-provider": "2.18.0", + "@walletconnect/utils": "2.18.0", + "bs58": "6.0.0", + "valtio": "1.13.2", + "viem": ">=2.23.0" + } + }, + "node_modules/@reown/appkit-adapter-ethers5": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-adapter-ethers5/-/appkit-adapter-ethers5-1.6.8.tgz", + "integrity": "sha512-c9URdpm1UwO/YyBG1mJi05uRvghjGx0tYu+kBl2JzhDkvwDloBg6SxghTeRwzZBtBG1toEewWpT3U+1tt/36xg==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit": "1.6.8", + "@reown/appkit-common": "1.6.8", + "@reown/appkit-core": "1.6.8", + "@reown/appkit-polyfills": "1.6.8", + "@reown/appkit-scaffold-ui": "1.6.8", + "@reown/appkit-ui": "1.6.8", + "@reown/appkit-utils": "1.6.8", + "@reown/appkit-wallet": "1.6.8", + "@walletconnect/universal-provider": "2.18.0", + "@walletconnect/utils": "2.18.0", + "valtio": "1.13.2" + }, + "optionalDependencies": { + "@coinbase/wallet-sdk": "4.3.0" + }, + "peerDependencies": { + "@ethersproject/sha2": "5.7.0", + "ethers": ">=4.1 <6.0.0" + } + }, + "node_modules/@reown/appkit-common": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.6.8.tgz", + "integrity": "sha512-i3J2qLC/51yhOBLAor8ToXDcD5LNiew12leWLBsnigl/N5OqhXNMxPHepC+01MYCDGDn2pOnU1ub+ES/OS6UrA==", + "license": "Apache-2.0", + "dependencies": { + "big.js": "6.2.2", + "dayjs": "1.11.10", + "viem": ">=2.23.0" + } + }, + "node_modules/@reown/appkit-core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-core/-/appkit-core-1.6.8.tgz", + "integrity": "sha512-biFB+wiAjx0kaqqX6wNEbK1v6yVYSWdOrCk3HqjVctJwuBNBX6ZLRf6Lm7a1pUiVRVjDc88hT828WL5MhZ6zgw==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.6.8", + "@reown/appkit-wallet": "1.6.8", + "@walletconnect/universal-provider": "2.18.0", + "valtio": "1.13.2", + "viem": ">=2.23" + } + }, + "node_modules/@reown/appkit-polyfills": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.6.8.tgz", + "integrity": "sha512-Iw1IEloHDlv2StRFnqZhA1/Q8DLs4OUtDBAp0AoAgDfz2EkCdUzFiC464I5xOnmSqUwyGm3dQGObBdq7aesPkA==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/@reown/appkit-scaffold-ui": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.6.8.tgz", + "integrity": "sha512-5uDOmlrnBIsPZCZ1/PyIVqkxQ+n39bLtTePrWteRoIaAtGRd1TiYCpPB+HO0SdLhXn66B4YzoQMCEIrIpzFqDg==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.6.8", + "@reown/appkit-core": "1.6.8", + "@reown/appkit-ui": "1.6.8", + "@reown/appkit-utils": "1.6.8", + "@reown/appkit-wallet": "1.6.8", + "lit": "3.1.0" + } + }, + "node_modules/@reown/appkit-ui": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.6.8.tgz", + "integrity": "sha512-UB3AaCiLRKkEI73i6LoX3rxbEUPELw/1Twdi5UlSm+IwwacGp0IAmkcRq0d9OwgTJymN6dEslUlNrH+PTpFblg==", + "license": "Apache-2.0", + "dependencies": { + "lit": "3.1.0", + "qrcode": "1.5.3" + } + }, + "node_modules/@reown/appkit-utils": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.6.8.tgz", + "integrity": "sha512-n/RLOy3a9SRcRGg3YT9p2BDdbBPBB50/mQiZ9pB19+hlO+FSikOinPSLoAtn2v4LEKCZWTTb14f3jMoa+n+djQ==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.6.8", + "@reown/appkit-core": "1.6.8", + "@reown/appkit-polyfills": "1.6.8", + "@reown/appkit-wallet": "1.6.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/universal-provider": "2.18.0", + "valtio": "1.13.2", + "viem": ">=2.23.0" + }, + "peerDependencies": { + "valtio": "1.13.2" + } + }, + "node_modules/@reown/appkit-wallet": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.6.8.tgz", + "integrity": "sha512-lYjdz8dTTIigrIyfbu2Lh1jc/YvXaZYM+vwZ8Lc9PD5e1GKZBOH8mU68EMXkoqqvLIsG1Y5aMYuBgzcGaRGuvA==", + "license": "Apache-2.0", + "dependencies": { + "@reown/appkit-common": "1.6.8", + "@reown/appkit-polyfills": "1.6.8", + "@walletconnect/logger": "2.1.2", + "zod": "3.22.4" + } + }, + "node_modules/@reown/appkit-wallet/node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.4.tgz", + "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==", + "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@scure/bip32": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.5.0.tgz", - "integrity": "sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", + "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", + "license": "MIT", "dependencies": { - "@noble/curves": "~1.6.0", - "@noble/hashes": "~1.5.0", - "@scure/base": "~1.1.7" + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.2" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@scure/bip32/node_modules/@noble/curves": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", - "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", "dependencies": { - "@noble/hashes": "1.5.0" + "@noble/hashes": "1.7.1" }, "engines": { "node": "^14.21.3 || >=16" @@ -2508,35 +2747,14 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@scure/bip39": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.4.0.tgz", - "integrity": "sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", + "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", + "license": "MIT", "dependencies": { - "@noble/hashes": "~1.5.0", - "@scure/base": "~1.1.8" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", - "engines": { - "node": "^14.21.3 || >=16" + "@noble/hashes": "~1.7.1", + "@scure/base": "~1.2.4" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -2733,132 +2951,576 @@ "@types/react": "*" } }, - "node_modules/abitype": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz", - "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node_modules/@walletconnect/core": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.18.0.tgz", + "integrity": "sha512-i/olu/IwYtBiWYqyfNUMxq4b6QS5dv+ZVVGmLT2buRwdH6MGETN0Bx3/z6rXJzd1sNd+QL07fxhSFxCekL57tA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "@walletconnect/window-getters": "1.0.1", + "events": "3.3.0", + "lodash.isequal": "4.5.0", + "uint8arrays": "3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@walletconnect/environment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", + "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" } }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node_modules/@walletconnect/environment/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", + "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", + "license": "MIT", + "dependencies": { + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + "node_modules/@walletconnect/events/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@walletconnect/heartbeat": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz", + "integrity": "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" + "@walletconnect/events": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "events": "^3.3.0" } }, - "node_modules/arctic": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.2.2.tgz", - "integrity": "sha512-m6xyOTBom5/qvAOiJPDpmHuR+vW3q5qH1LwWzWQMQE4tmWOX+CPSeTv3SFYG+CsnmPhfuXz2CfvxIQJmsS/u2w==", + "node_modules/@walletconnect/jsonrpc-http-connection": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", + "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", + "license": "MIT", "dependencies": { - "@oslojs/crypto": "1.0.1", - "@oslojs/encoding": "1.1.0", - "@oslojs/jwt": "0.2.0" + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.1", + "cross-fetch": "^3.1.4", + "events": "^3.3.0" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "node_modules/aria-hidden": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", - "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "node_modules/@walletconnect/jsonrpc-provider": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz", + "integrity": "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==", + "license": "MIT", "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" + "node_modules/@walletconnect/jsonrpc-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz", + "integrity": "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "keyvaluestorage-interface": "^1.0.0" + } }, - "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "node_modules/@walletconnect/jsonrpc-utils": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", + "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "@walletconnect/environment": "^1.0.1", + "@walletconnect/jsonrpc-types": "^1.0.3", + "tslib": "1.14.1" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "node_modules/@walletconnect/jsonrpc-utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + "node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", + "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=8.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/logger": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.1.2.tgz", + "integrity": "sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.2", + "pino": "7.11.0" + } + }, + "node_modules/@walletconnect/relay-api": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.11.tgz", + "integrity": "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-types": "^1.0.2" + } + }, + "node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/safe-json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", + "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/safe-json/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/sign-client": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.18.0.tgz", + "integrity": "sha512-oUjlRIsbHxMSRif2WvMRdvm6tMsQjMj07rl7YVcKVvZ1gF1/9GcbJPjzL/U87fv8qAQkVhIlbEg2vHaVYf6J/g==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/core": "2.18.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "2.1.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", + "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/time/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/types": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.18.0.tgz", + "integrity": "sha512-g0jU+6LUuw3E/EPAQfHNK2xK/95IpRfz68tdNAFckLmefZU6kzoE1mIM1SrPJq8rT9kUPp6/APMQE+ReH2OdBA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.18.0.tgz", + "integrity": "sha512-zF/e1NAipLqYjNNgM+XZTchh94efaxciBmgcDOaLznS97R7S/1bYj5okQCAEDKx9RALhEKqZKoyo9jwn4p3BVA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0", + "lodash": "4.17.21" + } + }, + "node_modules/@walletconnect/utils": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.18.0.tgz", + "integrity": "sha512-6AUXIcjSxTHGRsTtmUP/oqudtwRILrQqrJsH3jS5T28FFDzZt7+On6fR4mXzi64k4nNYeWg1wMCGLEdtxmGbZQ==", + "license": "Apache-2.0", + "dependencies": { + "@ethersproject/transactions": "5.7.0", + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.18.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "detect-browser": "5.3.0", + "elliptic": "6.6.1", + "query-string": "7.1.3", + "uint8arrays": "3.1.0" + } + }, + "node_modules/@walletconnect/utils/node_modules/@noble/curves": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.1" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/bn.js": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "license": "MIT" + }, + "node_modules/@walletconnect/utils/node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@walletconnect/window-getters": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", + "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-getters/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@walletconnect/window-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", + "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", + "license": "MIT", + "dependencies": { + "@walletconnect/window-getters": "^1.0.1", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-metadata/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/abitype": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", + "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arctic": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.2.2.tgz", + "integrity": "sha512-m6xyOTBom5/qvAOiJPDpmHuR+vW3q5qH1LwWzWQMQE4tmWOX+CPSeTv3SFYG+CsnmPhfuXz2CfvxIQJmsS/u2w==", + "dependencies": { + "@oslojs/crypto": "1.0.1", + "@oslojs/encoding": "1.1.0", + "@oslojs/jwt": "0.2.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base-x": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bn.js": { @@ -2890,6 +3552,39 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2906,6 +3601,15 @@ "node": ">=10.16.0" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2978,19 +3682,100 @@ "url": "https://joebell.co.uk" } }, - "node_modules/class-variance-authority/node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3043,6 +3828,12 @@ "node": ">= 6" } }, + "node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, "node_modules/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -3057,6 +3848,15 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3070,6 +3870,15 @@ "node": ">= 8" } }, + "node_modules/crossws": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.4.tgz", + "integrity": "sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -3102,6 +3911,12 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -3118,6 +3933,30 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3135,6 +3974,27 @@ "node": ">=0.10" } }, + "node_modules/derive-valtio": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", + "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", + "license": "MIT", + "peerDependencies": { + "valtio": "*" + } + }, + "node_modules/destr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", + "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==", + "license": "MIT" + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -3145,6 +4005,12 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -3327,6 +4193,18 @@ } } }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3356,6 +4234,21 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/esbuild": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", @@ -3418,6 +4311,7 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -3454,7 +4348,17 @@ "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } }, "node_modules/fast-glob": { "version": "3.3.2", @@ -3482,6 +4386,15 @@ "node": ">= 6" } }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -3501,6 +4414,28 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -3571,6 +4506,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -3625,6 +4569,24 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/h3": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.0.tgz", + "integrity": "sha512-OsjX4JW8J4XGgCgEcad20pepFQWnuKH+OwkCJjogF3C+9AZ1iYdtB4hX6vAb5DskBiu5ljEXqApINjR8CqoCMQ==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.3", + "defu": "^6.1.4", + "destr": "^2.0.3", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.0", + "ohash": "^1.1.4", + "radix3": "^1.1.2", + "ufo": "^1.5.4", + "uncrypto": "^0.1.3" + } + }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -3655,6 +4617,32 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3692,6 +4680,15 @@ "url": "https://opencollective.com/ioredis" } }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3814,6 +4811,12 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/keyvaluestorage-interface": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", + "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==", + "license": "MIT" + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -3827,6 +4830,55 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/lit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", + "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, + "node_modules/lit-element": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.1.1.tgz", + "integrity": "sha512-HO9Tkkh34QkTeUmEdNYhMT8hzLid7YlMlATSi1q4q17HE5d9mrrEHJ/o8O2D0cMi182zK1F3v7x0PWFjrhXFew==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.0.4", + "lit-html": "^3.2.0" + } + }, + "node_modules/lit-html": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.2.1.tgz", + "integrity": "sha512-qI/3lziaPMSKsrwlxH/xMgikhQ0EGOX2ICU73Bi/YHFvz2j/yMCIrw4+puF2IpQ4+upd3EWbvnHM9+PnJn48YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -3837,6 +4889,13 @@ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3949,6 +5008,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "license": "(Apache-2.0 AND MIT)" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -4062,6 +5127,38 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", + "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.0.tgz", + "integrity": "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==", + "license": "MIT" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4092,16 +5189,49 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", "devOptional": true }, + "node_modules/ofetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", + "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.3", + "node-fetch-native": "^1.6.4", + "ufo": "^1.5.4" + } + }, + "node_modules/ohash": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.4.tgz", + "integrity": "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", + "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/ox": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.1.2.tgz", - "integrity": "sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", + "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/wevm" } ], + "license": "MIT", "dependencies": { "@adraffy/ens-normalize": "^1.10.1", "@noble/curves": "^1.6.0", @@ -4120,29 +5250,40 @@ } } }, - "node_modules/ox/node_modules/@noble/curves": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", - "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", "dependencies": { - "@noble/hashes": "1.5.0" + "p-try": "^2.0.0" }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">=6" }, "funding": { - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ox/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", - "engines": { - "node": "^14.21.3 || >=16" + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" } }, "node_modules/package-json-from-dist": { @@ -4150,6 +5291,15 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4292,6 +5442,44 @@ "node": ">=0.10.0" } }, + "node_modules/pino": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", + "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.0.0", + "on-exit-leak-free": "^0.2.0", + "pino-abstract-transport": "v0.5.0", + "pino-std-serializers": "^4.0.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.1.0", + "safe-stable-stringify": "^2.1.0", + "sonic-boom": "^2.2.1", + "thread-stream": "^0.15.1" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", + "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "license": "MIT", + "dependencies": { + "duplexify": "^4.1.2", + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", + "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==", + "license": "MIT" + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -4300,6 +5488,15 @@ "node": ">= 6" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/postcss": { "version": "8.4.49", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", @@ -4488,12 +5685,71 @@ "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", "devOptional": true }, + "node_modules/preact": { + "version": "10.25.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.25.4.tgz", + "integrity": "sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==", + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", + "license": "MIT" + }, + "node_modules/proxy-compare": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", + "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4513,6 +5769,18 @@ } ] }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -4626,6 +5894,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4637,6 +5919,15 @@ "node": ">=8.10.0" } }, + "node_modules/real-require": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", + "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -4656,6 +5947,21 @@ "node": ">=4" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4711,6 +6017,35 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -4724,6 +6059,12 @@ "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4754,6 +6095,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/sonic-boom": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", + "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/sonner": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", @@ -4789,6 +6139,15 @@ "source-map": "^0.6.0" } }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -4802,6 +6161,12 @@ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -4810,6 +6175,24 @@ "node": ">=10.0.0" } }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -5035,6 +6418,15 @@ "node": ">=0.8" } }, + "node_modules/thread-stream": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", + "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.1.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5046,6 +6438,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -5069,6 +6467,21 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "license": "MIT" + }, + "node_modules/uint8arrays": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", + "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } + }, "node_modules/ulid": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", @@ -5077,12 +6490,110 @@ "ulid": "bin/cli.js" } }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "devOptional": true }, + "node_modules/unstorage": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.14.4.tgz", + "integrity": "sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^3.6.0", + "destr": "^2.0.3", + "h3": "^1.13.0", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.4", + "ofetch": "^1.4.1", + "ufo": "^1.5.4" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.5.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3", + "@deno/kv": ">=0.8.4", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.1" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, "node_modules/use-callback-ref": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", @@ -5137,25 +6648,60 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/valtio": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", + "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", + "license": "MIT", + "dependencies": { + "derive-valtio": "0.1.0", + "proxy-compare": "2.6.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/valtio/node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/viem": { - "version": "2.21.48", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.21.48.tgz", - "integrity": "sha512-/hBHyG1gdIIuiQv0z9YmzXl5eWJa0UCZGwkeuQzH2Bmg6FIEwZeEcxgiytXZydip+p2wMBFa1jdr7o5O1+mrIg==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.1.tgz", + "integrity": "sha512-c5AyJCTA5LeNI/KCu++vkbqbh7irYjUSHxLIAHPKJ6IEcBNMt8+7sPG7gjMXpqVWnqPMzaW9CA2n+yUsKWttDA==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/wevm" } ], + "license": "MIT", "dependencies": { - "@noble/curves": "1.6.0", - "@noble/hashes": "1.5.0", - "@scure/bip32": "1.5.0", - "@scure/bip39": "1.4.0", - "abitype": "1.0.6", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", + "@scure/bip32": "1.6.2", + "@scure/bip39": "1.5.4", + "abitype": "1.0.8", "isows": "1.0.6", - "ox": "0.1.2", - "webauthn-p256": "0.0.10", + "ox": "0.6.7", "ws": "8.18.0" }, "peerDependencies": { @@ -5168,23 +6714,13 @@ } }, "node_modules/viem/node_modules/@noble/curves": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", - "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", + "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", + "license": "MIT", "dependencies": { - "@noble/hashes": "1.5.0" - }, - "engines": { - "node": "^14.21.3 || >=16" + "@noble/hashes": "1.7.1" }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", "engines": { "node": "^14.21.3 || >=16" }, @@ -5212,44 +6748,20 @@ } } }, - "node_modules/webauthn-p256": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/webauthn-p256/-/webauthn-p256-0.0.10.tgz", - "integrity": "sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "dependencies": { - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.4.0" - } - }, - "node_modules/webauthn-p256/node_modules/@noble/curves": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", - "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { - "@noble/hashes": "1.5.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/webauthn-p256/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/which": { @@ -5266,6 +6778,12 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -5350,6 +6868,12 @@ "node": ">=8" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", @@ -5378,6 +6902,12 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, "node_modules/yaml": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", @@ -5389,6 +6919,82 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/zod": { "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", diff --git a/package.json b/package.json index 01bf20a..932cbdf 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.1", + "@reown/appkit": "^1.6.8", + "@reown/appkit-adapter-ethers5": "^1.6.8", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.45.2", "@trpc/react-query": "^10.45.2", diff --git a/src/app/invoices/[ID]/page.tsx b/src/app/invoices/[ID]/page.tsx index e999b93..0dfd555 100644 --- a/src/app/invoices/[ID]/page.tsx +++ b/src/app/invoices/[ID]/page.tsx @@ -1,10 +1,9 @@ +import { PaymentSection } from "@/components/payment-section"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { ArrowLeft } from "lucide-react"; +import { formatCurrencyLabel } from "@/lib/currencies"; +import { api } from "@/trpc/server"; import Link from "next/link"; -import { PaymentSection } from "@/components/payment-section"; import { notFound } from "next/navigation"; -import { api } from "@/trpc/server"; -import { formatCurrencyLabel } from "@/lib/currencies"; type InvoiceItem = { description: string; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 357b7aa..4cc4495 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,40 +3,42 @@ import localFont from "next/font/local"; import "./globals.css"; import { cookies } from "next/headers"; import { TRPCReactProvider } from "@/trpc/react"; -import { Toaster } from "@/components/ui/sonner" - +import { Toaster } from "@/components/ui/sonner"; +import { AppKit } from "@/components/app-kit"; const geistSans = localFont({ - src: "./fonts/GeistVF.woff", - variable: "--font-geist-sans", - weight: "100 900", + src: "./fonts/GeistVF.woff", + variable: "--font-geist-sans", + weight: "100 900", }); const geistMono = localFont({ - src: "./fonts/GeistMonoVF.woff", - variable: "--font-geist-mono", - weight: "100 900", + src: "./fonts/GeistMonoVF.woff", + variable: "--font-geist-mono", + weight: "100 900", }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Create Next App", + description: "Generated by create next app", }; export default function RootLayout({ - children, + children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode; }>) { - return ( - - - - {children} - - - - - ); + return ( + + + + + {children} + + + + + + ); } diff --git a/src/components/app-kit.tsx b/src/components/app-kit.tsx new file mode 100644 index 0000000..c709ecd --- /dev/null +++ b/src/components/app-kit.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { createAppKit } from "@reown/appkit/react"; +import { Ethers5Adapter } from "@reown/appkit-adapter-ethers5"; +import { sepolia } from "@reown/appkit/networks"; + +const metadata = { + name: "Easy Invoice", + description: "Easy Invoice is a simple and secure invoice payment platform.", + url: "https://easyinvoice.request.network", + icons: ["./assets/logo.svg"], +}; + +createAppKit({ + adapters: [new Ethers5Adapter()], + metadata, + networks: [sepolia], + projectId: process.env.NEXT_PUBLIC_REOWN_PROJECT_ID as string, + features: { + analytics: false, + email: false, + socials: false, + }, +}); + +export function AppKit({ children }: { children: React.ReactNode }) { + return <>{children}; +} diff --git a/src/components/payment-section.tsx b/src/components/payment-section.tsx index f5d4a2e..8918eea 100644 --- a/src/components/payment-section.tsx +++ b/src/components/payment-section.tsx @@ -3,155 +3,226 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { CheckCircle, Clock, Wallet } from "lucide-react"; -import { useState } from "react"; +import { CheckCircle, Clock, Wallet, Loader2 } from "lucide-react"; +import { useState, useEffect } from "react"; import { formatCurrencyLabel } from "@/lib/currencies"; import { Request } from "@/server/db/schema"; +import { useAppKit, useAppKitAccount } from "@reown/appkit/react"; interface PaymentSectionProps { - invoice: NonNullable; + invoice: NonNullable; } export function PaymentSection({ invoice }: PaymentSectionProps) { - const [paymentStatus, setPaymentStatus] = useState(invoice.status); - const [connectedWallet, setConnectedWallet] = useState(""); - const [currentStep, setCurrentStep] = useState(1); - - const handleConnectWallet = () => { - setConnectedWallet("0xABCD...EFGH"); - setCurrentStep(2); - }; - - const handlePayment = () => { - setPaymentStatus("processing"); - setTimeout(() => { - setPaymentStatus("paid"); - }, 2000); - }; - - const showCurrencyConversion = invoice.invoiceCurrency !== invoice.paymentCurrency; - - return ( - - - - Payment Details - - {paymentStatus === "paid" && ( - - )} - {paymentStatus === "processing" && ( - - )} - {paymentStatus === "pending" && ( - - )} - {paymentStatus} - - - - -
-

- Secure Payment -

-

- This payment is secured using blockchain technology. Your - transaction will be processed safely and transparently. -

-
- -
- -
-
- {formatCurrencyLabel(invoice.invoiceCurrency)} {Number(invoice.amount).toFixed(2)} -
- {showCurrencyConversion && ( -
- Payment will be processed in {formatCurrencyLabel(invoice.paymentCurrency)} -
- Note: The final amount in {formatCurrencyLabel(invoice.paymentCurrency)} will be calculated at the current exchange rate when payment is initiated. -
-
- )} -
-
- -
- -
- {invoice.payee} -
-
- - {/* Payment Steps */} -
- {/* Step indicators */} -
-
-
= 1 ? 'text-black' : 'text-zinc-300'}`}> -
= 1 ? 'border-black bg-zinc-50' : 'border-zinc-300'}`}> - -
- Connect Wallet -
-
= 2 ? 'bg-black' : 'bg-zinc-300'}`} /> -
= 2 ? 'text-black' : 'text-zinc-300'}`}> -
= 2 ? 'border-black bg-zinc-50' : 'border-zinc-300'}`}> - -
- Complete Payment -
-
-
- - {/* Step Content */} -
- {currentStep === 1 && ( -
-

- Connect your wallet to proceed with the payment -

- -
- )} - - {currentStep === 2 && ( -
-
- -
- {connectedWallet} -
-
-

- Please confirm the payment amount and recipient address before proceeding. - {showCurrencyConversion && ` Payment will be processed in ${formatCurrencyLabel(invoice.paymentCurrency)}.`} -

- -
- )} -
-
- - - ); + const [paymentStatus, setPaymentStatus] = useState(invoice.status); + const [currentStep, setCurrentStep] = useState(1); + const [isAppKitReady, setIsAppKitReady] = useState(false); + + const { open } = useAppKit(); + const { isConnected, address } = useAppKitAccount(); + + useEffect(() => { + // Simulate AppKit initialization delay + const timer = setTimeout(() => { + setIsAppKitReady(true); + }, 2000); + + return () => clearTimeout(timer); + }, []); + + useEffect(() => { + setCurrentStep(isConnected ? 2 : 1); + }, [isConnected]); + + const handleConnectWallet = () => { + if (isAppKitReady) { + open(); + } + }; + + const handlePayment = () => { + setPaymentStatus("processing"); + setTimeout(() => { + setPaymentStatus("paid"); + }, 2000); + }; + + const showCurrencyConversion = + invoice.invoiceCurrency !== invoice.paymentCurrency; + + return ( + + + + Payment Details + + {paymentStatus === "paid" && ( + + )} + {paymentStatus === "processing" && ( + + )} + {paymentStatus === "pending" && ( + + )} + {paymentStatus} + + + + +
+

Secure Payment

+

+ This payment is secured using blockchain technology. Your + transaction will be processed safely and transparently. +

+
+ +
+ +
+
+ {formatCurrencyLabel(invoice.invoiceCurrency)}{" "} + {Number(invoice.amount).toFixed(2)} +
+ {showCurrencyConversion && ( +
+ Payment will be processed in{" "} + {formatCurrencyLabel(invoice.paymentCurrency)} +
+ Note: The final amount in{" "} + {formatCurrencyLabel(invoice.paymentCurrency)} will be + calculated at the current exchange rate when payment is + initiated. +
+
+ )} +
+
+ +
+ +
+ {invoice.payee} +
+
+ + {/* Payment Steps */} +
+ {/* Step indicators */} +
+
+
= 1 ? "text-black" : "text-zinc-300" + }`} + > +
= 1 + ? "border-black bg-zinc-50" + : "border-zinc-300" + }`} + > + +
+ Connect Wallet +
+
= 2 ? "bg-black" : "bg-zinc-300" + }`} + /> +
= 2 ? "text-black" : "text-zinc-300" + }`} + > +
= 2 + ? "border-black bg-zinc-50" + : "border-zinc-300" + }`} + > + +
+ Complete Payment +
+
+
+ + {/* Step Content */} +
+ {currentStep === 1 && ( +
+

+ Connect your wallet to proceed with the payment +

+ +
+ )} + + {currentStep === 2 && ( +
+
+
+ + +
+
+ {address} +
+
+

+ Please confirm the payment amount and recipient address before + proceeding. + {showCurrencyConversion && + ` Payment will be processed in ${formatCurrencyLabel( + invoice.paymentCurrency, + )}.`} +

+ +
+ )} +
+
+ + + ); } From ada26ac973898f1041d620dc63d7d343b10e3e16 Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 18:25:17 +0400 Subject: [PATCH 11/33] feat: add flow to make payment --- src/app/dashboard/page.tsx | 48 +++--- src/components/payment-section.tsx | 263 +++++++++++++++++++---------- src/server/routers/invoice.ts | 79 ++++++--- 3 files changed, 254 insertions(+), 136 deletions(-) diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index bd834b4..66f0de1 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -88,41 +88,41 @@ export default async function DashboardPage() { {/* Summary Section */}
- + - + Total Invoices - + -
+
{totalInvoices}
- + - + Outstanding Invoices - + -
+
{outstandingInvoices}
- + - + Total Payments - + -
+
${totalPayments.toLocaleString()}
@@ -142,8 +142,12 @@ export default async function DashboardPage() { {invoices.length === 0 ? (
-

No invoices found

-

Get started by creating your first invoice.

+

+ No invoices found +

+

+ Get started by creating your first invoice. +

{invoices.map((invoice) => { const dueDate = new Date(invoice.dueDate); - const isOverdue = invoice.status === "pending" && isPast(dueDate); - + const isOverdue = + invoice.status === "pending" && isPast(dueDate); + return ( @@ -183,7 +188,7 @@ export default async function DashboardPage() { {formatCurrencyLabel(invoice.invoiceCurrency)} - {format(dueDate, 'do MMMM yyyy')} + {format(dueDate, "do MMMM yyyy")} - {isOverdue ? "Overdue" : invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)} + {isOverdue + ? "Overdue" + : invoice.status.charAt(0).toUpperCase() + + invoice.status.slice(1)} diff --git a/src/components/payment-section.tsx b/src/components/payment-section.tsx index 8918eea..d7246ef 100644 --- a/src/components/payment-section.tsx +++ b/src/components/payment-section.tsx @@ -7,7 +7,14 @@ import { CheckCircle, Clock, Wallet, Loader2 } from "lucide-react"; import { useState, useEffect } from "react"; import { formatCurrencyLabel } from "@/lib/currencies"; import { Request } from "@/server/db/schema"; -import { useAppKit, useAppKitAccount } from "@reown/appkit/react"; +import { + useAppKit, + useAppKitAccount, + useAppKitProvider, +} from "@reown/appkit/react"; +import { ethers } from "ethers"; +import { api } from "@/trpc/react"; +import { toast } from "sonner"; interface PaymentSectionProps { invoice: NonNullable; @@ -15,11 +22,28 @@ interface PaymentSectionProps { export function PaymentSection({ invoice }: PaymentSectionProps) { const [paymentStatus, setPaymentStatus] = useState(invoice.status); + const [paymentProgress, setPaymentProgress] = useState("idle"); const [currentStep, setCurrentStep] = useState(1); const [isAppKitReady, setIsAppKitReady] = useState(false); + const { mutateAsync: payRequest, isLoading } = + api.invoice.payRequest.useMutation(); const { open } = useAppKit(); const { isConnected, address } = useAppKitAccount(); + const { walletProvider } = useAppKitProvider("eip155"); + + const displayPaymentProgress = () => { + switch (paymentProgress) { + case "idle": + return "Start payment"; + case "getting-transactions": + return "Getting payment transactions"; + case "approving": + return "Approving payment"; + case "paying": + return "Sending payment"; + } + }; useEffect(() => { // Simulate AppKit initialization delay @@ -40,11 +64,62 @@ export function PaymentSection({ invoice }: PaymentSectionProps) { } }; - const handlePayment = () => { - setPaymentStatus("processing"); - setTimeout(() => { + const handlePayment = async () => { + if (paymentProgress !== "idle") return; + + setPaymentProgress("getting-transactions"); + + // @ts-ignore + const ethersProvider = new ethers.providers.Web3Provider(walletProvider); + + const signer = await ethersProvider.getSigner(); + + try { + const paymentData = await payRequest(invoice.paymentReference).then( + (response) => response.data, + ); + + const isApprovalNeeded = paymentData.metadata.needsApproval; + + if (isApprovalNeeded) { + setPaymentProgress("approving"); + toast("Payment Approval Required", { + description: "Please approve the payment in your wallet", + }); + + const approvalIndex = paymentData.metadata.approvalTransactionIndex; + + const approvalTransaction = await signer.sendTransaction( + paymentData.transactions[approvalIndex], + ); + + approvalTransaction.wait(); + } + + setPaymentProgress("paying"); + + toast("Initiating payment", { + description: "Please confirm the payment in your wallet", + }); + + const paymentTransaction = await signer.sendTransaction( + paymentData.transactions[isApprovalNeeded ? 1 : 0], + ); + + paymentTransaction.wait(); + + toast("Payment completed", { + description: "Payment completed successfully", + }); + setPaymentStatus("paid"); - }, 2000); + } catch (error) { + console.error("Error : ", error); + toast("Payment Failed", { + description: "Please try again", + }); + } + setPaymentProgress("idle"); }; const showCurrencyConversion = @@ -116,112 +191,120 @@ export function PaymentSection({ invoice }: PaymentSectionProps) {
{/* Payment Steps */} -
- {/* Step indicators */} -
-
-
= 1 ? "text-black" : "text-zinc-300" - }`} - > + {paymentStatus !== "paid" && ( +
+ {/* Step indicators */} +
+
= 1 ? "text-black" : "text-zinc-300" + }`} + > +
= 1 ? "border-black bg-zinc-50" : "border-zinc-300" }`} - > - + > + +
+ Connect Wallet
- Connect Wallet -
-
= 2 ? "bg-black" : "bg-zinc-300" - }`} - /> -
= 2 ? "text-black" : "text-zinc-300" - }`} - >
= 2 ? "bg-black" : "bg-zinc-300" + }`} + /> +
= 2 ? "text-black" : "text-zinc-300" + }`} + > +
= 2 ? "border-black bg-zinc-50" : "border-zinc-300" }`} - > - + > + +
+ Complete Payment
- Complete Payment
-
- {/* Step Content */} -
- {currentStep === 1 && ( -
-

- Connect your wallet to proceed with the payment -

- -
- )} + {/* Step Content */} +
+ {currentStep === 1 && ( +
+

+ Connect your wallet to proceed with the payment +

+ +
+ )} - {currentStep === 2 && ( -
-
-
- - -
-
- {address} + {currentStep === 2 && ( +
+
+
+ + +
+
+ {address} +
+

+ Please confirm the payment amount and recipient address + before proceeding. + {showCurrencyConversion && + ` Payment will be processed in ${formatCurrencyLabel( + invoice.paymentCurrency, + )}.`} +

+
-

- Please confirm the payment amount and recipient address before - proceeding. - {showCurrencyConversion && - ` Payment will be processed in ${formatCurrencyLabel( - invoice.paymentCurrency, - )}.`} -

- -
- )} + )} +
-
+ )} ); diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index d9907b3..36ec6f4 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -26,25 +26,28 @@ export const invoiceRouter = router({ paymentCurrency: input.paymentCurrency, }); - const invoice = await db.insert(requestTable).values({ - id: ulid(), - amount: totalAmount.toString(), - invoiceCurrency: input.invoiceCurrency, - paymentCurrency: input.paymentCurrency, - type: "invoice", - status: "pending", - payer: input.clientWallet, - payee: input.walletAddress, - dueDate: new Date(input.dueDate).toISOString(), - requestId: response.data.requestID as string, - paymentReference: response.data.paymentReference as string, - clientName: input.clientName, - clientEmail: input.clientEmail, - invoiceNumber: input.invoiceNumber, - items: input.items, - notes: input.notes, - userId: ctx.user?.id as string, - }).returning(); + const invoice = await db + .insert(requestTable) + .values({ + id: ulid(), + amount: totalAmount.toString(), + invoiceCurrency: input.invoiceCurrency, + paymentCurrency: input.paymentCurrency, + type: "invoice", + status: "pending", + payer: input.clientWallet, + payee: input.walletAddress, + dueDate: new Date(input.dueDate).toISOString(), + requestId: response.data.requestID as string, + paymentReference: response.data.paymentReference as string, + clientName: input.clientName, + clientEmail: input.clientEmail, + invoiceNumber: input.invoiceNumber, + items: input.items, + notes: input.notes, + userId: ctx.user?.id as string, + }) + .returning(); return { success: true, @@ -76,11 +79,35 @@ export const invoiceRouter = router({ outstandingInvoices: outstandingInvoices.length, }; }), - getById: protectedProcedure.input(z.string()).query(async ({ ctx, input }) => { - const { db } = ctx; - const invoice = await db.query.requestTable.findFirst({ - where: eq(requestTable.id, input), - }); - return invoice; - }), + getById: protectedProcedure + .input(z.string()) + .query(async ({ ctx, input }) => { + const { db } = ctx; + const invoice = await db.query.requestTable.findFirst({ + where: eq(requestTable.id, input), + }); + return invoice; + }), + payRequest: protectedProcedure + .input(z.string()) + .mutation(async ({ ctx, input }) => { + const { db } = ctx; + const invoice = await db.query.requestTable.findFirst({ + where: eq(requestTable.paymentReference, input), + }); + + if (!invoice) { + return { success: false, message: "Invoice not found" }; + } + + const response = await apiClient.get( + `/v1/request/${invoice.paymentReference}/pay`, + ); + + if (response.status !== 200) { + return { success: false, message: "Failed to pay invoice" }; + } + + return { success: true, data: response.data }; + }), }); From 73c4749933db4d7f2d46dd2c2928599c012de2af Mon Sep 17 00:00:00 2001 From: Aimen Sahnoun Date: Tue, 11 Feb 2025 19:05:08 +0400 Subject: [PATCH 12/33] refactor: update invoice preview --- src/app/invoices/[ID]/page.tsx | 178 +++++++++--- src/components/invoice-form.tsx | 442 ++++++++++++++--------------- src/components/invoice-preview.tsx | 237 ++++++++++------ 3 files changed, 502 insertions(+), 355 deletions(-) diff --git a/src/app/invoices/[ID]/page.tsx b/src/app/invoices/[ID]/page.tsx index 0dfd555..b6efe1b 100644 --- a/src/app/invoices/[ID]/page.tsx +++ b/src/app/invoices/[ID]/page.tsx @@ -22,6 +22,14 @@ export default async function PaymentPage({ notFound(); } + const formatDate = (date: string) => { + return new Date(date).toLocaleDateString("en-US", { + year: "2-digit", + month: "2-digit", + day: "2-digit", + }); + }; + return (
{/* Decorative elements */} @@ -69,67 +77,143 @@ export default async function PaymentPage({ {/* Invoice Preview */} - - - Invoice Preview - - -
-

- Invoice #{invoice.invoiceNumber} -

-

Due Date: {new Date(invoice.dueDate).toLocaleDateString()}

+ + + {/* Header Section */} +
+
+
+
+ INVOICE NO +
+
+ {invoice.invoiceNumber} +
+
+
+
+ ISSUED +
+
+ {formatDate(new Date().toISOString())} +
+
+
+
+ DUE DATE +
+
+ {formatDate(invoice.dueDate)} +
+
+
-
-

Bill To:

-

{invoice.clientName}

-

{invoice.clientEmail}

+ + {/* From/To Section */} +
+
+
FROM
+
+
PAYABLE TO:
+
+ {invoice.payee} +
+
+
+
+
TO
+
+
{invoice.clientName}
+
+ {invoice.clientEmail} +
+
+
-
-

Items:

+ + {/* Items Table */} +
- - - - - + + + + + - + {(invoice.items as InvoiceItem[]).map((item, index) => ( - - - - + + - + ))} - - - - - -
DescriptionQtyPriceTotal
+ DESCRIPTION + + QTY + + PRICE + + AMOUNT +
{item.description}{item.quantity} - ${item.price.toFixed(2)} +
+
{item.description}
+
+ {item.quantity} - ${(item.quantity * item.price).toFixed(2)} + + {item.price.toFixed(2)} + + {(item.quantity * item.price).toFixed(2)}
- Total: - - ${Number(invoice.amount).toFixed(2)} -
+ + {/* Totals */} +
+
+
+ + Subtotal + + + {Number(invoice.amount).toFixed(2)} + +
+
+ Total +
+
+ {Number(invoice.amount).toFixed(2)} +
+
+ {formatCurrencyLabel(invoice.invoiceCurrency)} +
+
+
+
+
-
-

Payment Details:

-

Invoice Currency: {formatCurrencyLabel(invoice.invoiceCurrency)}

-

Payment Currency: {formatCurrencyLabel(invoice.paymentCurrency)}

-

Recipient Wallet: {invoice.payee}

+ + {/* Payment Details and Notes Section */} +
+
+
+ PAYABLE IN +
+
+ {formatCurrencyLabel(invoice.paymentCurrency)} +
+
+ {invoice.notes && ( +
+
NOTES
+
+ {invoice.notes} +
+
+ )}
diff --git a/src/components/invoice-form.tsx b/src/components/invoice-form.tsx index e1a8cfd..d2add80 100644 --- a/src/components/invoice-form.tsx +++ b/src/components/invoice-form.tsx @@ -8,245 +8,237 @@ import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Plus, Trash2 } from "lucide-react"; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, } from "@/components/ui/select"; -import { INVOICE_CURRENCIES, getPaymentCurrenciesForInvoice, formatCurrencyLabel, InvoiceCurrency } from "@/lib/currencies"; +import { + INVOICE_CURRENCIES, + getPaymentCurrenciesForInvoice, + formatCurrencyLabel, + InvoiceCurrency, +} from "@/lib/currencies"; interface InvoiceFormProps { - form: UseFormReturn; - onSubmit: (data: InvoiceFormValues) => void; - isLoading: boolean; + form: UseFormReturn; + onSubmit: (data: InvoiceFormValues) => void; + isLoading: boolean; } export function InvoiceForm({ form, onSubmit, isLoading }: InvoiceFormProps) { - const { fields, append, remove } = useFieldArray({ - name: "items", - control: form.control, - }); - - return ( -
-
-
- - - {form.formState.errors.invoiceNumber && ( -

- {form.formState.errors.invoiceNumber.message} -

- )} -
+ const { fields, append, remove } = useFieldArray({ + name: "items", + control: form.control, + }); -
- - - {form.formState.errors.dueDate && ( -

- {form.formState.errors.dueDate.message} -

- )} -
-
+ return ( + +
+
+ + + {form.formState.errors.invoiceNumber && ( +

+ {form.formState.errors.invoiceNumber.message} +

+ )} +
-
- - - {form.formState.errors.clientName && ( -

- {form.formState.errors.clientName.message} -

- )} -
+
+ + + {form.formState.errors.dueDate && ( +

+ {form.formState.errors.dueDate.message} +

+ )} +
+
-
- - - {form.formState.errors.clientEmail && ( -

- {form.formState.errors.clientEmail.message} -

- )} -
+
+ + + {form.formState.errors.clientName && ( +

+ {form.formState.errors.clientName.message} +

+ )} +
-
- - {fields.map((field, index) => ( -
-
- - {form.formState.errors.items?.[index]?.description && ( -

- {form.formState.errors.items[index]?.description?.message} -

- )} -
-
- - {form.formState.errors.items?.[index]?.quantity && ( -

- {form.formState.errors.items[index]?.quantity?.message} -

- )} -
-
- - {form.formState.errors.items?.[index]?.price && ( -

- {form.formState.errors.items[index]?.price?.message} -

- )} -
- -
- ))} - -
+
+ + + {form.formState.errors.clientEmail && ( +

+ {form.formState.errors.clientEmail.message} +

+ )} +
-
- -