From 369f05cc81d13830418e6508377cdf5d55b5715a Mon Sep 17 00:00:00 2001 From: Lokesh <77314004+LokeshXs@users.noreply.github.com> Date: Tue, 28 May 2024 16:41:31 +0530 Subject: [PATCH] added a transaction view --- .github/workflows/deploy.yaml | 10 +- apps/web/auth.ts | 9 +- apps/web/package.json | 13 +- apps/web/src/actions/addMoney.ts | 7 +- apps/web/src/actions/authentication.ts | 4 +- apps/web/src/actions/transferMoney.ts | 4 +- apps/web/src/actions/updateProfile.ts | 200 + apps/web/src/app/api/contacts/route.ts | 39 + apps/web/src/app/api/myoauthaccount/route.ts | 17 + apps/web/src/app/api/myprofile/route.tsx | 17 + apps/web/src/app/api/p2ptransfers/route.ts | 63 + .../web/src/app/api/transaction/[id]/route.ts | 5 +- apps/web/src/app/auth/error/page.tsx | 2 + apps/web/src/app/auth/signin/loading.tsx | 10 + apps/web/src/app/auth/signin/page.tsx | 5 +- apps/web/src/app/auth/signup/loading.tsx | 10 + apps/web/src/app/auth/signup/page.tsx | 6 +- apps/web/src/app/error.tsx | 9 + apps/web/src/app/layout.tsx | 8 +- apps/web/src/app/loading.tsx | 10 + .../src/app/myaccount/dashboard/loading.tsx | 10 + apps/web/src/app/myaccount/dashboard/page.tsx | 103 +- apps/web/src/app/myaccount/layout.tsx | 17 +- .../src/app/myaccount/mywallet/loading.tsx | 10 + apps/web/src/app/myaccount/mywallet/page.tsx | 8 +- .../src/app/myaccount/p2ptransfer/loading.tsx | 10 + .../app/myaccount/transactions/loading.tsx | 10 + .../src/app/myaccount/transactions/page.tsx | 67 + apps/web/src/app/page.tsx | 58 +- apps/web/src/config/site-config.ts | 2 + apps/web/src/lib/data.ts | 52 + apps/web/tailwind.config.ts | 24 +- apps/webhook/package.json | 1 + apps/webhook/src/index.ts | 5 +- package-lock.json | 1399 +- .../migrations/20240510192406_/migration.sql | 10 + .../migrations/20240510195444_/migration.sql | 10 + packages/database/prisma/schema.prisma | 4 +- packages/schemas/src/authenticationSchema.ts | 71 +- packages/ui/package.json | 21 +- .../components/CustomProfileUpdateForm.tsx | 129 + packages/ui/src/components/DashboardPanel.tsx | 66 +- packages/ui/src/components/Globe.tsx | 305 + packages/ui/src/components/GlobeContainer.tsx | 400 + packages/ui/src/components/Loader.tsx | 30 + packages/ui/src/components/MoneyFlowChart.tsx | 2 +- .../ui/src/components/MoneyFlowContainer.tsx | 8 +- packages/ui/src/components/MyProfile.tsx | 57 + .../src/components/OAuthProfileUpdateForm.tsx | 137 + .../ui/src/components/P2PTransactionCard.tsx | 2 +- packages/ui/src/components/PasswordInput.tsx | 5 +- .../src/components/PaymentDetailsDialog.tsx | 75 + .../src/components/RecentTransactionCard.tsx | 47 + packages/ui/src/components/SignInForm.tsx | 11 +- packages/ui/src/components/SignUpForm.tsx | 11 +- .../ui/src/components/StatisticsPieChart.tsx | 54 + .../StatisticsPieChartContainer.tsx | 69 + .../ui/src/components/TransactionCard.tsx | 35 +- .../ui/src/components/TransactionTabs.tsx | 29 +- .../ui/src/components/TransferAmountForm.tsx | 173 +- packages/ui/src/components/columns.tsx | 164 + .../components/data-table-faceted-filter.tsx | 147 + packages/ui/src/components/data-table.tsx | 172 + .../src/components/infinite-moving-cards.tsx | 128 + .../ui/src/components/loader/PageLoader.tsx | 17 + .../src/components/loader/loader.module.css | 140 + packages/ui/src/components/ui/command.tsx | 155 + packages/ui/src/components/ui/input-otp.tsx | 71 + packages/ui/src/components/ui/pagination.tsx | 121 + packages/ui/src/components/ui/popover.tsx | 33 + packages/ui/src/components/ui/sheet.tsx | 140 + packages/ui/src/components/ui/table.tsx | 120 + packages/ui/src/components/ui/toast.tsx | 129 + packages/ui/src/components/ui/toaster.tsx | 35 + packages/ui/src/components/ui/use-toast.ts | 194 + packages/ui/src/data/globe.json | 12306 ++++++++++++++++ ...{tailwind.config.js => tailwind.config.ts} | 23 +- 77 files changed, 17916 insertions(+), 164 deletions(-) create mode 100644 apps/web/src/actions/updateProfile.ts create mode 100644 apps/web/src/app/api/contacts/route.ts create mode 100644 apps/web/src/app/api/myoauthaccount/route.ts create mode 100644 apps/web/src/app/api/myprofile/route.tsx create mode 100644 apps/web/src/app/api/p2ptransfers/route.ts create mode 100644 apps/web/src/app/auth/signin/loading.tsx create mode 100644 apps/web/src/app/auth/signup/loading.tsx create mode 100644 apps/web/src/app/error.tsx create mode 100644 apps/web/src/app/loading.tsx create mode 100644 apps/web/src/app/myaccount/dashboard/loading.tsx create mode 100644 apps/web/src/app/myaccount/mywallet/loading.tsx create mode 100644 apps/web/src/app/myaccount/p2ptransfer/loading.tsx create mode 100644 apps/web/src/app/myaccount/transactions/loading.tsx create mode 100644 apps/web/src/app/myaccount/transactions/page.tsx create mode 100644 apps/web/src/config/site-config.ts create mode 100644 packages/database/prisma/migrations/20240510192406_/migration.sql create mode 100644 packages/database/prisma/migrations/20240510195444_/migration.sql create mode 100644 packages/ui/src/components/CustomProfileUpdateForm.tsx create mode 100644 packages/ui/src/components/Globe.tsx create mode 100644 packages/ui/src/components/GlobeContainer.tsx create mode 100644 packages/ui/src/components/Loader.tsx create mode 100644 packages/ui/src/components/MyProfile.tsx create mode 100644 packages/ui/src/components/OAuthProfileUpdateForm.tsx create mode 100644 packages/ui/src/components/PaymentDetailsDialog.tsx create mode 100644 packages/ui/src/components/RecentTransactionCard.tsx create mode 100644 packages/ui/src/components/StatisticsPieChart.tsx create mode 100644 packages/ui/src/components/StatisticsPieChartContainer.tsx create mode 100644 packages/ui/src/components/columns.tsx create mode 100644 packages/ui/src/components/data-table-faceted-filter.tsx create mode 100644 packages/ui/src/components/data-table.tsx create mode 100644 packages/ui/src/components/infinite-moving-cards.tsx create mode 100644 packages/ui/src/components/loader/PageLoader.tsx create mode 100644 packages/ui/src/components/loader/loader.module.css create mode 100644 packages/ui/src/components/ui/command.tsx create mode 100644 packages/ui/src/components/ui/input-otp.tsx create mode 100644 packages/ui/src/components/ui/pagination.tsx create mode 100644 packages/ui/src/components/ui/popover.tsx create mode 100644 packages/ui/src/components/ui/sheet.tsx create mode 100644 packages/ui/src/components/ui/table.tsx create mode 100644 packages/ui/src/components/ui/toast.tsx create mode 100644 packages/ui/src/components/ui/toaster.tsx create mode 100644 packages/ui/src/components/ui/use-toast.ts create mode 100644 packages/ui/src/data/globe.json rename packages/ui/{tailwind.config.js => tailwind.config.ts} (75%) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 7b8df1f..3521af4 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -48,8 +48,8 @@ jobs: sudo docker stop paytm-clone-webhook || true sudo docker rm paytm-clone-user || true sudo docker rm paytm-clone-webhook || true - sudo docker network disconnect my_network paytm-clone-user || true - sudo docker network disconnect my_network paytm-clone-webhook || true - sudo docker network create my_network - sudo docker run -d --name paytm-clone-user --network my_network -e AUTH_SECRET=${{ secrets.AUTH_SECRET }} -e AUTH_GOOGLE_ID=${{ secrets.AUTH_GOOGLE_ID }} -e AUTH_GOOGLE_SECRET=${{ secrets.AUTH_GOOGLE_SECRET }} -e DATABASE_URL=${{ secrets.DATABASE_URL }} -p 3000:3000 lokesh1129/paytm-clone-user:latest - sudo docker run -d --name paytm-clone-webhook --network my_network -e DATABASE_URL=${{ secrets.DATABASE_URL }} lokesh1129/paytm-clone-webhook:latest \ No newline at end of file + sudo docker network disconnect paytm-network paytm-clone-user || true + sudo docker network disconnect paytm-network paytm-clone-webhook || true + sudo docker network create paytm-network + sudo docker run -d --name paytm-clone-user --network paytm-network -e AUTH_SECRET=${{ secrets.AUTH_SECRET }} -e AUTH_GOOGLE_ID=${{ secrets.AUTH_GOOGLE_ID }} -e AUTH_GOOGLE_SECRET=${{ secrets.AUTH_GOOGLE_SECRET }} -e DATABASE_URL=${{ secrets.DATABASE_URL }} -p 3000:3000 lokesh1129/paytm-clone-user:latest + sudo docker run -d --name paytm-clone-webhook --network paytm-network -e DATABASE_URL=${{ secrets.DATABASE_URL }} lokesh1129/paytm-clone-webhook:latest \ No newline at end of file diff --git a/apps/web/auth.ts b/apps/web/auth.ts index 152b3af..9be17c8 100755 --- a/apps/web/auth.ts +++ b/apps/web/auth.ts @@ -13,6 +13,7 @@ declare module "next-auth" { interface Session { /** The user's postal address. */ userId: string; + } } @@ -55,14 +56,21 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ callbacks: { async signIn({ user, account, profile, email, credentials }) { + return true; }, async session({ session, user, token }) { // console.log(token); session.userId = token.sub!; + + return session; }, + async jwt({ token, user, account, profile, isNewUser }) { + + return token + }, async redirect({ url, baseUrl }) { return "/myaccount/dashboard"; }, @@ -71,7 +79,6 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ events: { async signIn({ isNewUser, user }) { - // console.log("Is new user", isNewUser); if (isNewUser) { await db.balance.create({ diff --git a/apps/web/package.json b/apps/web/package.json index 09d550f..12c32bb 100755 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,8 +10,8 @@ "type-check": "tsc --noEmit" }, "dependencies": { + "@repo/database": "*", "@repo/ui": "*", - "@repo/database":"*", "@types/bcryptjs": "^2.4.6", "@types/uuid": "^9.0.8", "bcryptjs": "^2.4.3", @@ -22,15 +22,16 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.3.0", + "twilio": "^5.0.4", "uuid": "^9.0.1", "zod": "^3.22.4" }, "devDependencies": { "@next/eslint-plugin-next": "^14.1.1", "@repo/eslint-config": "*", + "@repo/schemas": "*", "@repo/tailwind-config": "*", "@repo/typescript-config": "*", - "@repo/schemas":"*", "@types/node": "^20.11.24", "@types/react": "^18.2.61", "@types/react-dom": "^18.2.19", @@ -42,8 +43,10 @@ "exports": { "./signUp": "./src/actions/authentication.ts", "./auth": "./auth.ts", - "./logout":"./src/actions/logout.ts", - "./db":"./src/lib/db.ts", - "./mobilenavcontext":"./src/context/MobileNavContext.tsx" + "./logout": "./src/actions/logout.ts", + "./db": "./src/lib/db.ts", + "./mobilenavcontext": "./src/context/MobileNavContext.tsx", + "./baseurl": "./src/config/site-config.ts", + "./updateProfile": "./src/actions/updateProfile.ts" } } diff --git a/apps/web/src/actions/addMoney.ts b/apps/web/src/actions/addMoney.ts index b71d932..4cec64f 100755 --- a/apps/web/src/actions/addMoney.ts +++ b/apps/web/src/actions/addMoney.ts @@ -5,13 +5,14 @@ import db from "../lib/db"; import { auth } from "../../auth"; import { revalidatePath } from "next/cache"; import { v4 as uuidv4 } from "uuid"; +import { BASE_URL, WEBHOOK_URL } from "../config/site-config"; export async function addMoney(values: z.infer) { try { const session = await auth(); const userId = session?.userId; - console.log(values); + // 1.) zod validation @@ -34,7 +35,7 @@ export async function addMoney(values: z.infer) { data: { status: "Processing", amount: amountInNumber, - startTime: new Date(), + timestamp: new Date(), userId: userId!, token: uuidv4(), paymentCardId: bank, @@ -44,7 +45,7 @@ export async function addMoney(values: z.infer) { revalidatePath("/dashboard"); // console.log(transactionDetails); setTimeout(async () => { - await fetch("http://localhost:3001/webhook", { + await fetch(`${WEBHOOK_URL}/webhook`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/apps/web/src/actions/authentication.ts b/apps/web/src/actions/authentication.ts index 9d06aa8..65eabc4 100755 --- a/apps/web/src/actions/authentication.ts +++ b/apps/web/src/actions/authentication.ts @@ -57,7 +57,6 @@ export async function signUp(values: z.infer) { }, }); - // Initialising the user with Zero balance await db.balance.create({ data: { @@ -67,6 +66,7 @@ export async function signUp(values: z.infer) { }, }); + return { status: "success", message: "Signed up successfully", @@ -119,7 +119,7 @@ export async function signInAction(values: z.infer) { message: "Successfully Signed in", }; } catch (error) { - console.log(error); + // console.log(error); if (error instanceof AuthError) { switch (error.type) { diff --git a/apps/web/src/actions/transferMoney.ts b/apps/web/src/actions/transferMoney.ts index b04adeb..47812ac 100755 --- a/apps/web/src/actions/transferMoney.ts +++ b/apps/web/src/actions/transferMoney.ts @@ -113,7 +113,7 @@ export default async function TransferMoney( data: { toUserId: toUser.id, fromUserId: session.userId, - Amount: Number(validatedValues.data.amount) * 100, + amount: Number(validatedValues.data.amount) * 100, status: "Success", }, }); @@ -133,7 +133,7 @@ export default async function TransferMoney( data: { toUserId: toUser.id, fromUserId: session.userId, - Amount: Number(validatedValues.data.amount) * 100, + amount: Number(validatedValues.data.amount) * 100, status: "Failed", }, }); diff --git a/apps/web/src/actions/updateProfile.ts b/apps/web/src/actions/updateProfile.ts new file mode 100644 index 0000000..b764267 --- /dev/null +++ b/apps/web/src/actions/updateProfile.ts @@ -0,0 +1,200 @@ +"use server"; + +import { UpdateCustomProfileSchema } from "@repo/schemas/authenticationSchema"; +import { z } from "zod"; +import db from "../lib/db"; +import { auth } from "../../auth"; +import bcrypt from "bcryptjs"; +import {Prisma} from "@prisma/client" + +export const updateProfile = async ( + values: z.infer +) => { + console.log(values); + try { + const session = await auth(); + + const validatedValues = UpdateCustomProfileSchema.safeParse(values); + + if (!validatedValues.success) { + return { + status: "error", + message: "Values are not valid", + }; + } + + const validatedValuesData: { + name: string; + phonenumber: string; + email: string; + password: string; + [key: string]: string; // Index signature + } = validatedValues.data; + + // 1.) Fetch the updatable fields from DB + + const userOriginalDetails: { + name: string | null; + phonenumber: string | null; + email: string; + password: string | null; + [key: string]: string | null; // Index signature + } | null = await db.user.findUnique({ + where: { + id: session?.userId, + }, + select: { + name: true, + email: true, + password: true, + phonenumber: true, + }, + }); + + const toBeUpdatedFields: any = {}; + + for (let [key, value] of Object.entries(userOriginalDetails || {})) { + if (userOriginalDetails) { + if (key === "password") { + const isValid = await bcrypt.compare( + validatedValuesData["password"], + userOriginalDetails["password"] || "" + ); + + if (!isValid && validatedValuesData["password"] !== "") { + toBeUpdatedFields["password"] = validatedValuesData["password"]; + } + } else { + if (userOriginalDetails[key] !== validatedValuesData[key]) { + toBeUpdatedFields[key] = validatedValuesData[key]; + } + } + } + } + + + + // 2.) Update fields + + await db.user.update({ + where: { + id: session?.userId, + }, + data: toBeUpdatedFields, + }); + + return { + status: "success", + message: "Profile is updated successfully", + }; + } catch (error) { + + console.log(error); + + if(error instanceof Prisma.PrismaClientKnownRequestError){ + if(error.code === "P2002"){ + return { + status:"error", + message:"User with the details already exist" + } + } + } + + return { + status: "error", + message: "Something went wrong, try after sometime", + }; + } +}; + + + + +// ****************************************************************************** + +export const updateOAuthProfile = async ( + values: {number:string} + ) => { + try { + const session = await auth(); + + const validatedValues = UpdateCustomProfileSchema.safeParse(values); + + if (!validatedValues.success) { + return { + status: "error", + message: "Values are not valid", + }; + } + + const validatedValuesData: { + name: string; + phonenumber: string; + email: string; + password: string; + [key: string]: string; // Index signature + } = validatedValues.data; + + // 1.) Fetch the updatable fields from DB + + const userOriginalDetails: { + name: string | null; + phonenumber: string | null; + email: string; + password: string | null; + [key: string]: string | null; // Index signature + } | null = await db.user.findUnique({ + where: { + id: session?.userId, + }, + select: { + name: true, + email: true, + password: true, + phonenumber: true, + }, + }); + + const toBeUpdatedFields: any = {}; + + for (let [key, value] of Object.entries(userOriginalDetails || {})) { + if (userOriginalDetails) { + if (key === "password") { + const isValid = await bcrypt.compare( + validatedValuesData["password"], + userOriginalDetails["password"] || "" + ); + + if (!isValid && validatedValuesData["password"] !== "") { + toBeUpdatedFields["password"] = validatedValuesData["password"]; + } + } else { + if (userOriginalDetails[key] !== validatedValuesData[key]) { + toBeUpdatedFields[key] = validatedValuesData[key]; + } + } + } + } + + // 2.) Update fields + + await db.user.update({ + where: { + id: session?.userId, + }, + data: toBeUpdatedFields, + }); + + return { + status: "success", + message: "Profile is updated successfully", + }; + } catch (error) { + return { + status: "error", + message: "Something went wrong, try after sometime", + }; + } + }; + + diff --git a/apps/web/src/app/api/contacts/route.ts b/apps/web/src/app/api/contacts/route.ts new file mode 100644 index 0000000..d3f3b8b --- /dev/null +++ b/apps/web/src/app/api/contacts/route.ts @@ -0,0 +1,39 @@ +import db from "@repo/database/client"; +import { auth } from "@repo/web/auth"; + +export async function POST(request: Request) { + const session = await auth(); + + const { searchedContact } = await request.json(); + + const data = await db.user.findMany({ + where: { + phonenumber: { + contains: searchedContact, + }, + NOT: { + id: session?.userId, + }, + }, + }); + + // console.log(data); + const filteredData = data.map((contact) => { + return { + name: contact.name, + phoneNumber: contact.phonenumber, + image: contact.image, + }; + }); + + await new Promise((resolve) => { + setTimeout(() => { + resolve(""); + }, 2000); + }); + + return Response.json({ + status: "success", + data: filteredData, + }); +} diff --git a/apps/web/src/app/api/myoauthaccount/route.ts b/apps/web/src/app/api/myoauthaccount/route.ts new file mode 100644 index 0000000..fbd4592 --- /dev/null +++ b/apps/web/src/app/api/myoauthaccount/route.ts @@ -0,0 +1,17 @@ +import db from "@repo/database/client"; + +export async function POST(request: Request) { + const { userId }: { userId: string } = await request.json(); + const userDetails = await db.account.findFirst({ + where:{ + userId:userId + } + }); + +// console.log(userDetails); + + return Response.json({ + status: "success", + data:{provider:userDetails?.provider} + }); +} diff --git a/apps/web/src/app/api/myprofile/route.tsx b/apps/web/src/app/api/myprofile/route.tsx new file mode 100644 index 0000000..9f4abc6 --- /dev/null +++ b/apps/web/src/app/api/myprofile/route.tsx @@ -0,0 +1,17 @@ +import db from "@repo/database/client"; + +export async function POST(request: Request) { + const { userId }: { userId: string } = await request.json(); + const userDetails = await db.user.findUnique({ + where:{ + id:userId + } + }); + + // console.log(userDetails); + + return Response.json({ + status: "success", + data:{name:userDetails?.name,email:userDetails?.email,phoneNumber:userDetails?.phonenumber} + }); +} diff --git a/apps/web/src/app/api/p2ptransfers/route.ts b/apps/web/src/app/api/p2ptransfers/route.ts new file mode 100644 index 0000000..744610b --- /dev/null +++ b/apps/web/src/app/api/p2ptransfers/route.ts @@ -0,0 +1,63 @@ +import db from "@repo/database/client"; +import { auth } from "@repo/web/auth"; + +export async function POST(request: Request) { + const session = await auth(); + + const { numberOfContacts }: { numberOfContacts: string } = + await request.json(); + + const totalP2PTransfers = await db.p2pTransfers.findMany({ + where: { + OR:[ + { + fromUserId: session?.userId, + }, + { + toUserId:session?.userId + } + ] + }, + distinct: ["toUserId","fromUserId"], + take: Number(numberOfContacts), + }); + + const contactDetails = totalP2PTransfers.map(async (transferDetails) => { + const contact = await db.user.findFirst({ + where: { + OR:[ + { + id: transferDetails.toUserId, + }, + { + id: transferDetails.fromUserId + } + ], + NOT:{ + id:session?.userId + } + }, + }); + + return { + name: contact?.name, + phoneNumber: contact?.phonenumber, + image: contact?.image, + }; + }); + + const latestTransfersContacts = await Promise.all(contactDetails); + + // console.log(latestTransfersContacts); + + await new Promise((resolve) => { + setTimeout(() => { + resolve(""); + }, 2000); + }); + + return Response.json({ + status: "success", + data: latestTransfersContacts, + }); +} diff --git a/apps/web/src/app/api/transaction/[id]/route.ts b/apps/web/src/app/api/transaction/[id]/route.ts index fbc941d..6e2ff1a 100755 --- a/apps/web/src/app/api/transaction/[id]/route.ts +++ b/apps/web/src/app/api/transaction/[id]/route.ts @@ -5,7 +5,7 @@ export async function GET( request: Request, { params }: { params: { id: string } } ) { - // console.log(params); + const transaction = await db.onRampTransactions.findUnique({ where: { @@ -17,6 +17,7 @@ export async function GET( return Response.json({ - status: transaction?.status, + status: "success", + data: transaction }); } diff --git a/apps/web/src/app/auth/error/page.tsx b/apps/web/src/app/auth/error/page.tsx index a2aef9d..a22db45 100755 --- a/apps/web/src/app/auth/error/page.tsx +++ b/apps/web/src/app/auth/error/page.tsx @@ -1,4 +1,6 @@ +"use client"; + export default function ErrorPage(){ return (
diff --git a/apps/web/src/app/auth/signin/loading.tsx b/apps/web/src/app/auth/signin/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/auth/signin/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/auth/signin/page.tsx b/apps/web/src/app/auth/signin/page.tsx index 773fa76..1aa3d84 100755 --- a/apps/web/src/app/auth/signin/page.tsx +++ b/apps/web/src/app/auth/signin/page.tsx @@ -13,7 +13,10 @@ export default function SignUpPage({searchParams}:{searchParams:{error:string}}) // console.log(searchParams); return (
-
+
+ + Back to home +

diff --git a/apps/web/src/app/auth/signup/loading.tsx b/apps/web/src/app/auth/signup/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/auth/signup/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/auth/signup/page.tsx b/apps/web/src/app/auth/signup/page.tsx index f5a33f6..7c72e12 100755 --- a/apps/web/src/app/auth/signup/page.tsx +++ b/apps/web/src/app/auth/signup/page.tsx @@ -10,8 +10,12 @@ import { signIn } from "../../../../auth"; export default function SignUpPage() { return (
-
+
+ + Back to home +
+

New Era of Global Payments diff --git a/apps/web/src/app/error.tsx b/apps/web/src/app/error.tsx new file mode 100644 index 0000000..5911b18 --- /dev/null +++ b/apps/web/src/app/error.tsx @@ -0,0 +1,9 @@ +"use client"; + +export default function ErrorPage(){ + return ( +
+ Error some thing went wrong +
+ ) + } \ No newline at end of file diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index e975e14..3d4515c 100755 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,6 +1,7 @@ import "@repo/ui/globals.css" import type { Metadata } from "next"; +import { SessionProvider } from "next-auth/react"; import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); @@ -15,9 +16,14 @@ export default function RootLayout({ }: { children: React.ReactNode; }): JSX.Element { + return ( - {children} + + + {children} + + ); } diff --git a/apps/web/src/app/loading.tsx b/apps/web/src/app/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/myaccount/dashboard/loading.tsx b/apps/web/src/app/myaccount/dashboard/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/myaccount/dashboard/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/myaccount/dashboard/page.tsx b/apps/web/src/app/myaccount/dashboard/page.tsx index ce19d2d..54d2537 100755 --- a/apps/web/src/app/myaccount/dashboard/page.tsx +++ b/apps/web/src/app/myaccount/dashboard/page.tsx @@ -2,7 +2,9 @@ import db from "../../../lib/db"; import { auth } from "../../../../auth"; import { formattCurrency } from "@repo/ui/formatcurrency"; import MoneyFlowContainer from "@repo/ui/MoneyFlowContainer"; - +import { Button } from "@repo/ui/button"; +import RecentTransactionCard from "@repo/ui/RecentTransactionCard"; +import StatisticsPieChartContainer from "@repo/ui/StatisticsPieChartContainer"; export default async function DashboardPage() { const session = await auth(); @@ -15,14 +17,102 @@ export default async function DashboardPage() { const totalBalance = formattCurrency(balance?.amount || 0); + const recentWalletTransactions = await db.onRampTransactions.findMany({ + where: { + userId: session?.userId, + }, + take: 3, + }); + + // console.log(recentWalletTransactions); + + const recentP2PTransactions = await db.p2pTransfers.findMany({ + where: { + OR: [ + { + toUserId: session?.userId, + }, + { + fromUserId: session?.userId, + }, + ], + }, + + take: 3, + }); + + // console.log(recentWalletTransactions); + + const allTransactionsInOrder = [ + ...recentWalletTransactions, + ...recentP2PTransactions, + ].sort((a, b) => { + return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() ; + }).slice(0,3); + // console.log(allTransactionsInOrder); return (
-
- +
+
+

Unlimited Cashback

+

+ Instant 2% cashback on your first 5 spend to your wallet +

+ +
+
+

Moneyflow

+ +
+ +
+
+

Recent Transactions

+ +
+ +
+ {allTransactionsInOrder.length === 0 &&
+

No transaction made yet

+
} + {allTransactionsInOrder.map((transactionDetails) => { + if (!("paymentCardId" in transactionDetails)) { + if (session?.userId === transactionDetails.toUserId) { + if (transactionDetails.status === "Success") { + ; + } + } + } + return ( + + ); + })} +
+
-
+

Wallet

@@ -38,6 +128,11 @@ export default async function DashboardPage() {
+ +
+

Statistics

+ +
); diff --git a/apps/web/src/app/myaccount/layout.tsx b/apps/web/src/app/myaccount/layout.tsx index d22bbdc..1bb056b 100755 --- a/apps/web/src/app/myaccount/layout.tsx +++ b/apps/web/src/app/myaccount/layout.tsx @@ -1,8 +1,8 @@ import { Avatar, AvatarFallback, AvatarImage } from "@repo/ui/avatar"; import { auth } from "../../../auth"; - import DashboardPanel from "@repo/ui/DashboardPanel"; +import { SessionProvider } from "next-auth/react"; interface Props { children: React.ReactNode; @@ -14,15 +14,16 @@ export default async function DashboardLayout({ children }: Props) { return (
-
- - {/* */} -
-
-
{children}
+ +
+ +
+
+
{children}
+
-
+
); } diff --git a/apps/web/src/app/myaccount/mywallet/loading.tsx b/apps/web/src/app/myaccount/mywallet/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/myaccount/mywallet/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/myaccount/mywallet/page.tsx b/apps/web/src/app/myaccount/mywallet/page.tsx index c7be0bf..6cbe51c 100755 --- a/apps/web/src/app/myaccount/mywallet/page.tsx +++ b/apps/web/src/app/myaccount/mywallet/page.tsx @@ -93,7 +93,7 @@ export default async function DashboardView() {

Quick Links

- +
@@ -102,7 +102,7 @@ export default async function DashboardView() {
- +
@@ -111,7 +111,7 @@ export default async function DashboardView() {
- +
@@ -120,7 +120,7 @@ export default async function DashboardView() {
- +
diff --git a/apps/web/src/app/myaccount/p2ptransfer/loading.tsx b/apps/web/src/app/myaccount/p2ptransfer/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/myaccount/p2ptransfer/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/myaccount/transactions/loading.tsx b/apps/web/src/app/myaccount/transactions/loading.tsx new file mode 100644 index 0000000..ddc465c --- /dev/null +++ b/apps/web/src/app/myaccount/transactions/loading.tsx @@ -0,0 +1,10 @@ +import PageLoader from "@repo/ui/PageLoader"; + +export default function Loading(){ + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/myaccount/transactions/page.tsx b/apps/web/src/app/myaccount/transactions/page.tsx new file mode 100644 index 0000000..0aff8cf --- /dev/null +++ b/apps/web/src/app/myaccount/transactions/page.tsx @@ -0,0 +1,67 @@ +import { DataTable } from "@repo/ui/data-table"; +import { Transaction, columns } from "@repo/ui/columns"; +import { auth } from "../../../../auth"; +import db from "@repo/database/client"; +import { SessionProvider } from "next-auth/react"; + + +async function getData(): Promise { + const session = await auth(); + // Fetch data from your API here. + + const recentWalletTransactions = await db.onRampTransactions.findMany({ + where: { + userId: session?.userId, + }, + }); + + // console.log(recentWalletTransactions); + + const recentP2PTransactions = await db.p2pTransfers.findMany({ + where: { + OR: [ + { + toUserId: session?.userId, + }, + { + fromUserId: session?.userId, + }, + ], + }, + }); + + // console.log(recentWalletTransactions); + + const allTransactionsInOrder = [ + ...recentWalletTransactions, + ...recentP2PTransactions, + ] + .sort((a, b) => { + return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() ; + }) + .map((transferDetail) => ({ + id: transferDetail.id, + amount: transferDetail.amount, + status: transferDetail.status, + invoice: transferDetail.id, + name: "paymentCardId" in transferDetail ? "Wallet" : "Peer", + date: transferDetail.timestamp, + fromUserId: "fromUserId" in transferDetail? transferDetail.fromUserId:null, + toUserId: "toUserId" in transferDetail? transferDetail.toUserId:null, + })); + return allTransactionsInOrder; +} + +export default async function TransactionsPage() { + const session = await auth(); + const data = await getData(); + + return ( +
+ + + + +
+ ); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 978b9f4..19ccb2f 100755 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -2,18 +2,22 @@ import { Button } from "@repo/ui/button"; import Image from "next/image"; import { Volume2 } from "lucide-react"; import { AnimatedTooltip } from "@repo/ui/animatedtooltip"; -import { FEEDBACK_DATA } from "../lib/data"; +import { FEEDBACK_DATA, testimonials } from "../lib/data"; import NavBar from "@repo/ui/navbar"; +import InfiniteMovingCards from "@repo/ui/InfiniteMovingCards"; + +import GlobeContainer from "@repo/ui/GlobeContainer"; +// import { World } from "@repo/ui/Globe"; export default async function Page() { return (
-
-
+
+

- The New Era of Gloabl Payments + The New Era of Gloabl Payments

Lorem ipsum, dolor sit amet consectetur adipisicing elit. @@ -51,26 +55,12 @@ export default async function Page() {

-
-
-

- Easy payment for anyone. No rush, stress, or high costs. -

-
- -
-
- Lady +
+
-
+

Get to know more about
"PayCard"

@@ -123,7 +113,9 @@ export default async function Page() {
-

Secure Payments

+

+ Secure Payments +

payment illustration
-

Global Currencies

+

+ Global Currencies +

payment illustration
-

Seamless money Transfers

+

+ Seamless money Transfers +

payment illustration
+ +
+

+ Some testimonials from our
valuable clients +

+
+ + +
+
); diff --git a/apps/web/src/config/site-config.ts b/apps/web/src/config/site-config.ts new file mode 100644 index 0000000..029c903 --- /dev/null +++ b/apps/web/src/config/site-config.ts @@ -0,0 +1,2 @@ +export const BASE_URL = 'http://localhost:3000'; +export const WEBHOOK_URL='http://paytmwebhook:3001'; \ No newline at end of file diff --git a/apps/web/src/lib/data.ts b/apps/web/src/lib/data.ts index 4ed99e8..9428edf 100755 --- a/apps/web/src/lib/data.ts +++ b/apps/web/src/lib/data.ts @@ -41,3 +41,55 @@ export const FEEDBACK_DATA: { image: "https://images.pexels.com/photos/1036623/pexels-photo-1036623.jpeg?auto=compress&cs=tinysrgb&w=300" } ]; + + +export const testimonials = [ + { + quote: "The ease of adding money to my wallet and making peer-to-peer transactions on this platform is incredible!", + name: "Alice Johnson", + title: "Freelancer", + image: "https://randomuser.me/api/portraits/women/1.jpg" + }, + { + quote: "I've tried many other apps for peer-to-peer transactions, but none compare to the speed and reliability of this one.", + name: "Bob Smith", + title: "Entrepreneur", + image: "https://randomuser.me/api/portraits/men/2.jpg" + }, + { + quote: "This platform has completely changed the way I handle my finances. It's so convenient and efficient!", + name: "Emily Davis", + title: "Small Business Owner", + image: "https://randomuser.me/api/portraits/women/3.jpg" + }, + { + quote: "I love how I can quickly transfer money to my friends and family whenever I need to. It's so convenient!", + name: "John Doe", + title: "Student", + image: "https://randomuser.me/api/portraits/men/4.jpg" + }, + { + quote: "The security measures in place give me peace of mind knowing that my transactions are safe and protected.", + name: "Sarah Miller", + title: "Investor", + image: "https://randomuser.me/api/portraits/women/5.jpg" + }, + { + quote: "I highly recommend this platform to anyone looking for a fast and reliable way to manage their finances.", + name: "David Brown", + title: "Financial Analyst", + image: "https://randomuser.me/api/portraits/men/6.jpg" + }, + { + quote: "The user interface is intuitive and user-friendly, making it easy for anyone to navigate and use the app.", + name: "Anna White", + title: "Digital Nomad", + image: "https://randomuser.me/api/portraits/women/7.jpg" + }, + { + quote: "I've never experienced any issues with transactions on this platform. It's always smooth sailing!", + name: "Michael Johnson", + title: "Software Engineer", + image: "https://randomuser.me/api/portraits/men/8.jpg" + } +]; diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts index e96af3b..5011098 100755 --- a/apps/web/tailwind.config.ts +++ b/apps/web/tailwind.config.ts @@ -1,6 +1,10 @@ import type { Config } from "tailwindcss"; import tailwindcssAnimate from "tailwindcss-animate"; +const { + default: flattenColorPalette, +} = require("tailwindcss/lib/util/flattenColorPalette"); + const config = { darkMode: ["class"], content: [ @@ -69,14 +73,32 @@ const config = { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, + scroll:{ + to: { + transform: "translate(calc(-50% - 0.5rem))", + }, + } }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + scroll: "scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite", }, }, }, - plugins: [tailwindcssAnimate], + plugins: [tailwindcssAnimate,addVariablesForColors], } satisfies Config; + +function addVariablesForColors({ addBase, theme }: any) { + let allColors = flattenColorPalette(theme("colors")); + let newVars = Object.fromEntries( + Object.entries(allColors).map(([key, val]) => [`--${key}`, val]) + ); + + addBase({ + ":root": newVars, + }); +} + export default config; \ No newline at end of file diff --git a/apps/webhook/package.json b/apps/webhook/package.json index cd7ff7d..a6ef976 100755 --- a/apps/webhook/package.json +++ b/apps/webhook/package.json @@ -16,6 +16,7 @@ "@types/express": "^4.17.21", "@prisma/client": "^5.12.1", "@repo/database":"*", + "@repo/web":"*", "cors": "^2.8.5", "esbuild": "^0.20.2", "express": "^4.19.2" diff --git a/apps/webhook/src/index.ts b/apps/webhook/src/index.ts index c7d1fee..a904750 100755 --- a/apps/webhook/src/index.ts +++ b/apps/webhook/src/index.ts @@ -1,5 +1,6 @@ import express from "express"; import db from "@repo/database/client" +import {BASE_URL} from "@repo/web/baseurl"; import cors from "cors"; const app = express(); @@ -7,7 +8,7 @@ const app = express(); app.use(express.json()); app.use(cors({ - origin:"http://localhost:3000" + origin:BASE_URL })) @@ -42,7 +43,7 @@ app.post("/webhook", async (req, res) => { message: "Captured", }); } catch (error) { - console.log(error); + // console.log(error); res.status(411).json({ message: "Error while processing the webhook", diff --git a/package-lock.json b/package-lock.json index 9cb80c2..68b2348 100755 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.3.0", + "twilio": "^5.0.4", "uuid": "^9.0.1", "zod": "^3.22.4" }, @@ -1180,6 +1181,11 @@ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.8.tgz", + "integrity": "sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==" + }, "node_modules/@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -1211,6 +1217,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.0.5.tgz", + "integrity": "sha512-53sCTG4FaJBaAq/tcufARtVYDMDGqyBT9i7F453pWGhZ5LqubDHDWtYoHo9VhQqMcHTEexdJqSsR58y+9HVmQA==", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, "node_modules/@next/env": { "version": "14.1.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", @@ -1910,6 +1927,43 @@ } } }, + "node_modules/@radix-ui/react-popover": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.7.tgz", + "integrity": "sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-popper": "1.1.3", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz", @@ -2157,6 +2211,40 @@ } } }, + "node_modules/@radix-ui/react-toast": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz", + "integrity": "sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-visually-hidden": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", @@ -2311,6 +2399,171 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@react-spring/animated": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.6.1.tgz", + "integrity": "sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==", + "dependencies": { + "@react-spring/shared": "~9.6.1", + "@react-spring/types": "~9.6.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.6.1.tgz", + "integrity": "sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==", + "dependencies": { + "@react-spring/animated": "~9.6.1", + "@react-spring/rafz": "~9.6.1", + "@react-spring/shared": "~9.6.1", + "@react-spring/types": "~9.6.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.6.1.tgz", + "integrity": "sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==" + }, + "node_modules/@react-spring/shared": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.6.1.tgz", + "integrity": "sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==", + "dependencies": { + "@react-spring/rafz": "~9.6.1", + "@react-spring/types": "~9.6.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.6.1.tgz", + "integrity": "sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==", + "dependencies": { + "@react-spring/animated": "~9.6.1", + "@react-spring/core": "~9.6.1", + "@react-spring/shared": "~9.6.1", + "@react-spring/types": "~9.6.1" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "three": ">=0.126" + } + }, + "node_modules/@react-spring/types": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.6.1.tgz", + "integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==" + }, + "node_modules/@react-three/drei": { + "version": "9.105.6", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.105.6.tgz", + "integrity": "sha512-JBgYeV36N9N9f1c3o1ZfLYW4rXZA7UQTq32Y8s3DEF6lwj1/y+RP/yq2VG5I8OzUPl7gsmWdy8fpWZgrlAqUpQ==", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@mediapipe/tasks-vision": "0.10.8", + "@monogrid/gainmap-js": "^3.0.5", + "@react-spring/three": "~9.6.1", + "@use-gesture/react": "^10.2.24", + "camera-controls": "^2.4.2", + "cross-env": "^7.0.3", + "detect-gpu": "^5.0.28", + "glsl-noise": "^0.0.0", + "hls.js": "1.3.5", + "maath": "^0.10.7", + "meshline": "^3.1.6", + "react-composer": "^5.0.3", + "stats-gl": "^2.0.0", + "stats.js": "^0.17.0", + "suspend-react": "^0.1.3", + "three-mesh-bvh": "^0.7.0", + "three-stdlib": "^2.29.9", + "troika-three-text": "^0.49.0", + "tunnel-rat": "^0.1.2", + "utility-types": "^3.10.0", + "uuid": "^9.0.1", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "@react-three/fiber": ">=8.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "three": ">=0.137" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "8.16.6", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.6.tgz", + "integrity": "sha512-sKEqocYKRI3deW7z9CAVjedDID1an2i8FwxQVv2reMJxzIxIlyxCYXMIAqXBCgHTFtVX2hWGTZYhLL5nyne8kA==", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/react-reconciler": "^0.26.7", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "react-use-measure": "^2.1.1", + "scheduler": "^0.21.0", + "suspend-react": "^0.1.3", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "react-native": ">=0.64", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/@repo/database": { "resolved": "packages/database", "link": true @@ -2353,6 +2606,73 @@ "tslib": "^2.4.0" } }, + "node_modules/@tanstack/react-table": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.17.0.tgz", + "integrity": "sha512-LSJxTDzlKGs8EN7/UHB1l3yLR9HUIxoHFkTbTjHaUUGL4kgYZFYhsQsdDJSIykG86qpIA/6gSWmtwNfy5Iprhw==", + "dependencies": { + "@tanstack/table-core": "8.16.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.16.0.tgz", + "integrity": "sha512-dCG8vQGk4js5v88/k83tTedWOwjGnIyONrKpHpfmSJB8jwFHl8GSu1sBBxbtACVAPtAQgwNxl0rw1d3RqRM1Tg==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", + "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", + "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.2", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.2.tgz", + "integrity": "sha512-kMCNaZCJugWI86xiEHaY338CU5JpD0B97p1j1IKNn/Zto8PgACjQx0UxbHjmOcLl/dDOBnItwD07KmCs75pxtQ==" + }, "node_modules/@types/bcryptjs": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", @@ -2388,6 +2708,11 @@ "@types/node": "*" } }, + "node_modules/@types/draco3d": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.9.tgz", + "integrity": "sha512-4MMUjMQb4yA5fJ4osXx+QxGHt0/ZSy4spT6jL1HM7Tn8OJEC35siqdnpOo+HxPhYjqEFumKfGVF9hJfdyKBIBA==" + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -2446,11 +2771,15 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "devOptional": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/qs": { "version": "6.9.14", @@ -2466,7 +2795,6 @@ "version": "18.2.74", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.74.tgz", "integrity": "sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==", - "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2481,6 +2809,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -2506,11 +2842,34 @@ "@types/send": "*" } }, + "node_modules/@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==" + }, + "node_modules/@types/three": { + "version": "0.164.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.164.0.tgz", + "integrity": "sha512-SFDofn9dJVrE+1DKta7xj7lc4ru7B3S3yf10NsxOserW57aQlB6GxtAS1UK5To3LfEMN5HUHMu3n5v+M5rApgA==", + "peer": true, + "dependencies": { + "@tweenjs/tween.js": "~23.1.1", + "@types/stats.js": "*", + "@types/webxr": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" }, + "node_modules/@types/webxr": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.16.tgz", + "integrity": "sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", @@ -2830,6 +3189,22 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/@vercel/style-guide": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@vercel/style-guide/-/style-guide-5.2.0.tgz", @@ -2892,6 +3267,14 @@ "node": ">= 0.6" } }, + "node_modules/accessor-fn": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.0.tgz", + "integrity": "sha512-dml7D96DY/K5lt4Ra2jMnpL9Bhw5HEGws4p1OAIxFFj9Utd/RxNfEO3T3f0QIWFNwQU7gNxH9snUfqF/zNkP/w==", + "engines": { + "node": ">=12" + } + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -2913,6 +3296,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3178,6 +3572,11 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -3239,6 +3638,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -3257,11 +3666,38 @@ "resolved": "apps/webhook", "link": true }, + "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" + } + ] + }, "node_modules/bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -3362,6 +3798,34 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", @@ -3428,6 +3892,14 @@ "node": ">= 6" } }, + "node_modules/camera-controls": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.8.3.tgz", + "integrity": "sha512-zFjqUR6onLkG+z1A6vAWfzovxZxWVSvp6e5t3lfZgfgPZtX3n74aykNAUaoRbq8Y3tOxadHkDjbfGDOP9hFf2w==", + "peerDependencies": { + "three": ">=0.126.1" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001606", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz", @@ -3576,6 +4048,19 @@ "node": ">=6" } }, + "node_modules/cmdk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz", + "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==", + "dependencies": { + "@radix-ui/react-dialog": "1.0.5", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3592,6 +4077,17 @@ "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==", + "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", @@ -3656,6 +4152,23 @@ "node": ">= 0.10" } }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3683,8 +4196,142 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-voronoi": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.0.1.tgz", + "integrity": "sha512-KeBrhSLyN6fdcjGxpmil9I7JNsRQIbp58PybKFnebG1qpbwon5ia43epUpYgjgZZxfrhjb+3up0f6IwkQuPkwg==", + "dependencies": { + "d3-array": "3", + "d3-delaunay": "6", + "d3-geo": "3", + "d3-tricontour": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-tricontour": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.0.2.tgz", + "integrity": "sha512-HIRxHzHagPtUPNabjOlfcyismJYIsc+Xlq4mlsts4e8eAcwyq9Tgk/sYdyhlBpQ0MHwVquc/8j+e29YjXnmxeA==", + "dependencies": { + "d3-delaunay": "6", + "d3-scale": "4" + }, + "engines": { + "node": ">=12" + } }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -3692,6 +4339,17 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/data-joint": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/data-joint/-/data-joint-1.3.1.tgz", + "integrity": "sha512-tMK0m4OVGqiA3zkn8JmO6YAqD8UwJqIAx4AAwFl1SKTtKAqcXePuT+n2aayiX9uITtlN3DFtKKTOxJRUc2+HvQ==", + "dependencies": { + "index-array-by": "^1.4.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -3743,11 +4401,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3799,6 +4466,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3825,6 +4508,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-gpu": { + "version": "5.0.38", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.38.tgz", + "integrity": "sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, "node_modules/detect-indent": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.1.tgz", @@ -3894,11 +4585,29 @@ "node": ">=12" } }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==" + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5175,6 +5884,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5264,6 +5978,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -5288,6 +6021,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5309,6 +6055,14 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/frame-ticker": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/frame-ticker/-/frame-ticker-1.0.3.tgz", + "integrity": "sha512-E0X2u2JIvbEMrqEg5+4BpTqaD22OwojJI63K7MdKHdncjtAhGRbCR8nJCr2vwEt9NWBPCPcu70X9smPviEBy8Q==", + "dependencies": { + "simplesignal": "^2.1.6" + } + }, "node_modules/framer-motion": { "version": "11.1.7", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.1.7.tgz", @@ -5561,6 +6315,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==" + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -5583,6 +6342,16 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/h3-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.1.0.tgz", + "integrity": "sha512-LQhmMl1dRQQjMXPzJc7MpZ/CqPOWWuAvVEoVJM9n/s7vHypj+c3Pd5rLQCkAsOgAoAYKbNCsYFE++LF7MvSfCQ==", + "engines": { + "node": ">=4", + "npm": ">=3", + "yarn": ">=1.3.0" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -5660,6 +6429,11 @@ "node": ">= 0.4" } }, + "node_modules/hls.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.3.5.tgz", + "integrity": "sha512-uybAvKS6uDe0MnWNEPnO0krWVr+8m2R0hJ/viql8H3MVK+itq8gGQuIYoFHL3rECkIpNH98Lw8YuuWMKZxp3Ew==" + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -5681,6 +6455,18 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5692,6 +6478,25 @@ "node": ">=0.10.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" + } + ] + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -5701,6 +6506,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -5735,6 +6545,14 @@ "node": ">=8" } }, + "node_modules/index-array-by": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.1.tgz", + "integrity": "sha512-Zu6THdrxQdyTuT2uA5FjUoBEsFHPzHcPIj18FszN6yXKHxSfGcR4TPLabfuT//E25q1Igyx9xta2WMvD/x9P/g==", + "engines": { + "node": ">=12" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5750,6 +6568,15 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/input-otp": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.2.4.tgz", + "integrity": "sha512-md6rhmD+zmMnUh5crQNSQxq3keBRYvE3odbr4Qb9g2NWzQv9azi+t1a3X4TBTbh98fsGHgEEJlzbe1q860uGCA==", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -5764,6 +6591,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -6046,6 +6881,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6198,6 +7038,25 @@ "set-function-name": "^2.0.1" } }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.8", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", + "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", @@ -6302,6 +7161,38 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -6317,6 +7208,36 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kapsule": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.14.5.tgz", + "integrity": "sha512-H0iSpTynUzZw3tgraDmReprpFRmH5oP5GPmaNsurSwLx2H5iCpOMIkp5q+sfhB4Tz/UJd1E1IbEE9Z6ksnJ6RA==", + "dependencies": { + "lodash-es": "4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6357,6 +7278,14 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -6391,12 +7320,52 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6425,6 +7394,15 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/maath": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.7.tgz", + "integrity": "sha512-zQ2xd7dNOIVTjAS+hj22fyj1EFYmOJX6tzKjZ92r6WDoq8hyFxjuGA2q950tmR4iC/EKXoMQdSipkaJVuUHDTg==", + "peerDependencies": { + "@types/three": ">=0.144.0", + "three": ">=0.144.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6446,6 +7424,19 @@ "node": ">= 8" } }, + "node_modules/meshline": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.0.tgz", + "integrity": "sha512-EKKf2TLnfyqUeA7ryWFKgT9HchTMATvECGZnMQjtlcyxK0sB8shVLVkemBUp9dB3tkDEmoqQDLJCPStjkH8D7A==", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==" + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -6537,8 +7528,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -7235,6 +8225,11 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" + }, "node_modules/preact": { "version": "10.11.3", "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", @@ -7376,11 +8371,19 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -7399,6 +8402,11 @@ "node": ">= 0.10" } }, + "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==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7441,6 +8449,11 @@ } ] }, + "node_modules/rafor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rafor/-/rafor-1.0.2.tgz", + "integrity": "sha512-b8e8/srbSbC0FZTxivEz9pj5z1mQM8CpCEv1aAxuaK26ljSOHJk8AjimcTaHpHIZlwH/VPbli12LuKKrJyyGmA==" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7483,6 +8496,17 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-composer": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", + "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", + "dependencies": { + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -7513,8 +8537,30 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/react-remove-scroll": { "version": "2.5.5", @@ -7583,6 +8629,18 @@ } } }, + "node_modules/react-use-measure": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", + "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", + "dependencies": { + "debounce": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.13", + "react-dom": ">=16.13" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -7778,6 +8836,14 @@ "jsesc": "bin/jsesc" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -7836,6 +8902,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7925,6 +8996,11 @@ "loose-envify": "^1.1.0" } }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8072,6 +9148,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simplesignal": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/simplesignal/-/simplesignal-2.1.7.tgz", + "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8210,6 +9291,31 @@ "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, + "node_modules/stats-gl": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.2.8.tgz", + "integrity": "sha512-94G5nZvduDmzxBS7K0lYnynYwreZpkknD8g5dZmU6mpwIhy3caCrjAm11Qm1cbyx7mqix7Fp00RkbsonzKWnoQ==", + "dependencies": { + "@types/three": "^0.163.0" + } + }, + "node_modules/stats-gl/node_modules/@types/three": { + "version": "0.163.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.163.0.tgz", + "integrity": "sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==", + "dependencies": { + "@tweenjs/tween.js": "~23.1.1", + "@types/stats.js": "*", + "@types/webxr": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -8526,6 +9632,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "peerDependencies": { + "react": ">=17.0" + } + }, "node_modules/synckit": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", @@ -8632,6 +9746,123 @@ "node": ">=0.8" } }, + "node_modules/three": { + "version": "0.164.1", + "resolved": "https://registry.npmjs.org/three/-/three-0.164.1.tgz", + "integrity": "sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==" + }, + "node_modules/three-conic-polygon-geometry": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-1.6.3.tgz", + "integrity": "sha512-uJhuUBHc5K4IFQ+31qVQboMIlEQ485WWX7+pN4qR2p4ctTO66nlJ2NWrXNn8x2A89Utyf09v+zyBIpWUVe1inQ==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5", + "d3-array": "1 - 3", + "d3-geo": "1 - 3", + "d3-geo-voronoi": "^2.0", + "d3-scale": "1 - 4", + "delaunator": "5", + "earcut": "2" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-fatline": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/three-fatline/-/three-fatline-0.6.2.tgz", + "integrity": "sha512-4PnwvGRk0NVKYoo1wGxEwbl9w6ipx//brPvRR0JuP0rap08/SHZeXYSmsRVmf6LW6GcQN3P+W6hoqD5EUvTw5A==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.84.0" + } + }, + "node_modules/three-geojson-geometry": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/three-geojson-geometry/-/three-geojson-geometry-1.3.2.tgz", + "integrity": "sha512-eJflV+2KLDrQNHAbEhvXadF355LYat3izE2sD3Qt1L6Sw41LZ7Nwc/FV9T/z1edeZVQxydeYpmWBsYsFzsPEHA==", + "dependencies": { + "d3-geo": "1 - 3", + "earcut": "2" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.72.0" + } + }, + "node_modules/three-globe": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.31.0.tgz", + "integrity": "sha512-p2pCPaqAoBdjZxS0e+oLbv5d4R5ud6m8wkQENaENToyPX4S5NVnMRXu8zyMP4jnhYbtDqnefeDlKo9wqe4jUug==", + "dependencies": { + "@tweenjs/tween.js": "18 - 23", + "accessor-fn": "1", + "d3-array": "3", + "d3-color": "3", + "d3-geo": "3", + "d3-interpolate": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "data-joint": "1", + "earcut": "2", + "frame-ticker": "1", + "h3-js": "4", + "index-array-by": "1", + "kapsule": "1", + "three-conic-polygon-geometry": "1", + "three-fatline": "^0.6", + "three-geojson-geometry": "1", + "tinycolor2": "1", + "yaot": "^1.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "three": ">=0.125" + } + }, + "node_modules/three-mesh-bvh": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.4.tgz", + "integrity": "sha512-flxe0A4uflTPR6elgq/Y8VrLoljDNS899i422SxQcU3EtMj6o8z4kZRyqZqGWzR0qMf1InTZzY1/0xZl/rnvVw==", + "peerDependencies": { + "three": ">= 0.151.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.30.0.tgz", + "integrity": "sha512-ALL7rn57jq/MovDRk5hGjeWCvOeZlZhFCWIdpbBAQNudCO3nMwxEba5ZulsMgiI1ymQMzUzTMcxhLTCVlUaKDw==", + "dependencies": { + "@types/draco3d": "^1.4.0", + "@types/offscreencanvas": "^2019.6.4", + "@types/webxr": "^0.5.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "potpack": "^1.0.1" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, + "node_modules/three-stdlib/node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -8660,6 +9891,33 @@ "node": ">=0.6" } }, + "node_modules/troika-three-text": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.49.1.tgz", + "integrity": "sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.49.0", + "troika-worker-utils": "^0.49.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.49.0.tgz", + "integrity": "sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==", + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.49.0.tgz", + "integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==" + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -8727,6 +9985,41 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "dependencies": { + "zustand": "^4.3.2" + } + }, + "node_modules/tunnel-rat/node_modules/zustand": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/turbo": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.13.2.tgz", @@ -8822,6 +10115,23 @@ "win32" ] }, + "node_modules/twilio": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-5.0.4.tgz", + "integrity": "sha512-Dw8s93zXBA2+Wo1sS0yfWgHx89q6Ue+ch02LkGAkWodiWfq/JJBkzSdUQLoYp1bLha1h4Xi/hBtuMQUrJBED7A==", + "dependencies": { + "axios": "^1.6.8", + "dayjs": "^1.11.9", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^9.0.2", + "qs": "^6.9.4", + "scmp": "^2.1.0", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9052,11 +10362,27 @@ } } }, + "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==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "engines": { + "node": ">= 4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -9095,6 +10421,16 @@ "node": ">= 0.8" } }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9281,6 +10617,14 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "engines": { + "node": ">=6.0" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -9298,6 +10642,14 @@ "node": ">= 14" } }, + "node_modules/yaot": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/yaot/-/yaot-1.1.3.tgz", + "integrity": "sha512-AE8LInj21hTuA01RUK+9pSsl0ltQXO+rxn4Q+CJT4+NI/X7dhGGblF7vvzGj6ro0qXRCGAE/7ccEfu6S4DJayw==", + "dependencies": { + "rafor": "^1.0.2" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -9318,6 +10670,22 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "packages/config-eslint": { "name": "@repo/eslint-config", "version": "0.0.0", @@ -9368,17 +10736,26 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@react-three/drei": "^9.105.6", + "@react-three/fiber": "^8.16.6", + "@tanstack/react-table": "^8.17.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cmdk": "^1.0.0", "framer-motion": "^11.1.7", + "input-otp": "^1.2.4", "lucide-react": "^0.365.0", "react-hook-form": "^7.51.2", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7", + "three": "^0.164.1", + "three-globe": "^2.31.0", "zod": "^3.22.4" }, "devDependencies": { diff --git a/packages/database/prisma/migrations/20240510192406_/migration.sql b/packages/database/prisma/migrations/20240510192406_/migration.sql new file mode 100644 index 0000000..4bad702 --- /dev/null +++ b/packages/database/prisma/migrations/20240510192406_/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `startTime` on the `onRampTransactions` table. All the data in the column will be lost. + - Added the required column `timestamp` to the `onRampTransactions` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "onRampTransactions" DROP COLUMN "startTime", +ADD COLUMN "timestamp" TIMESTAMP(3) NOT NULL; diff --git a/packages/database/prisma/migrations/20240510195444_/migration.sql b/packages/database/prisma/migrations/20240510195444_/migration.sql new file mode 100644 index 0000000..9e71672 --- /dev/null +++ b/packages/database/prisma/migrations/20240510195444_/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `Amount` on the `p2pTransfers` table. All the data in the column will be lost. + - Added the required column `amount` to the `p2pTransfers` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "p2pTransfers" DROP COLUMN "Amount", +ADD COLUMN "amount" INTEGER NOT NULL; diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma index 18026dd..3245b3b 100755 --- a/packages/database/prisma/schema.prisma +++ b/packages/database/prisma/schema.prisma @@ -92,7 +92,7 @@ model onRampTransactions { status OnRampStatus token String @unique amount Int - startTime DateTime + timestamp DateTime userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) paymentCard paymentCards? @relation(fields: [paymentCardId], references: [cardNumber]) @@ -103,7 +103,7 @@ model p2pTransfers { id String @id @default(cuid()) toUserId String fromUserId String - Amount Int + amount Int status String @default("Success") toUser User @relation("TransferToUser", fields: [toUserId], references: [id]) fromUser User @relation("TransferFromUser", fields: [fromUserId], references: [id]) diff --git a/packages/schemas/src/authenticationSchema.ts b/packages/schemas/src/authenticationSchema.ts index 50241d6..71440b1 100755 --- a/packages/schemas/src/authenticationSchema.ts +++ b/packages/schemas/src/authenticationSchema.ts @@ -1,15 +1,66 @@ - -import {z} from "zod"; +import { z } from "zod"; export const SignUpSchema = z.object({ - fullname: z.string().min(2,"Too Short!"), - phonenumber: z.string().regex(/^[789][0-9]{9}$/,"Invalid Number!"), + fullname: z.string().min(2, "Too Short!"), + phonenumber: z.string().regex(/^[789][0-9]{9}$/, "Invalid Number!"), email: z.string().email(), - password: z.string().regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/,"Password requirement not met"), -}) - + password: z + .string() + .regex( + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/, + "Password requirement not met" + ), +}); export const SignInSchema = z.object({ - phonenumber:z.string().regex(/^[789][0-9]{9}$/,"Invalid number!"), - password:z.string().min(2,"Invalid password"), -}) \ No newline at end of file + phonenumber: z.string().regex(/^[789][0-9]{9}$/, "Invalid number!"), + password: z.string().min(2, "Invalid password"), +}); + +export const UpdateCustomProfileSchema = z.object({ + name: z.string().min(2, "Too Short"), + phonenumber: z.string().regex(/^[789][0-9]{9}$/, "Invalid Number!"), + email: z.string().email(), + password: z + .string() + .refine( + (password) => { + if (!password) { + return true; + } + + const passwordIsValid = + password.length >= 8 && + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(password); + + return passwordIsValid; + }, + { + message: "Password requirement not met", + } + ), +}); + +export const UpdateOAuthProfileScheama = z.object({ + name: z.string().min(2, "Too Short"), + phonenumber: z.string().regex(/^[789][0-9]{9}$/, "Invalid Number!"), + email: z.string().email(), + password: z + .string() + .refine( + (password) => { + if (!password) { + return true; + } + + const passwordIsValid = + password.length >= 8 && + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(password); + + return passwordIsValid; + }, + { + message: "Password requirement not met", + } + ), +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index ba5fb07..f7a0cb0 100755 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -29,8 +29,16 @@ "./mobilenavbar": "./src/components/MobileNav.tsx", "./transactionTabs": "./src/components/TransactionTabs.tsx", "./addcard": "./src/components/AddCard.tsx", - "./DashboardPanel":"./src/components/DashboardPanel.tsx", - "./MoneyFlowContainer":"./src/components/MoneyFlowContainer.tsx" + "./DashboardPanel": "./src/components/DashboardPanel.tsx", + "./MoneyFlowContainer": "./src/components/MoneyFlowContainer.tsx", + "./RecentTransactionCard": "./src/components/RecentTransactionCard.tsx", + "./StatisticsPieChartContainer": "./src/components/StatisticsPieChartContainer.tsx", + "./GlobeContainer": "./src/components/GlobeContainer.tsx", + "./columns": "./src/components/columns.tsx", + "./data-table": "./src/components/data-table.tsx", + "./InfiniteMovingCards": "./src/components/infinite-moving-cards.tsx", + "./PageLoader": "./src/components/loader/PageLoader.tsx", + "./MyProfile": "./src/components/MyProfile.tsx" }, "license": "MIT", "scripts": { @@ -61,17 +69,26 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@react-three/drei": "^9.105.6", + "@react-three/fiber": "^8.16.6", + "@tanstack/react-table": "^8.17.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cmdk": "^1.0.0", "framer-motion": "^11.1.7", + "input-otp": "^1.2.4", "lucide-react": "^0.365.0", "react-hook-form": "^7.51.2", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7", + "three": "^0.164.1", + "three-globe": "^2.31.0", "zod": "^3.22.4" } } diff --git a/packages/ui/src/components/CustomProfileUpdateForm.tsx b/packages/ui/src/components/CustomProfileUpdateForm.tsx new file mode 100644 index 0000000..0a622ed --- /dev/null +++ b/packages/ui/src/components/CustomProfileUpdateForm.tsx @@ -0,0 +1,129 @@ +import { z } from "zod"; +import { UpdateCustomProfileSchema } from "@repo/schemas/authenticationSchema"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { Button } from "./ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "./ui/form"; +import { Input } from "./ui/input"; +import {updateProfile} from "@repo/web/updateProfile"; +import { useState, useTransition } from "react"; +import SuccessMsg from "./SuccessMsg"; +import ErrorMsg from "./ErrorMsg"; + +type Props = { + profileDetails: + | { + name: string | null; + email: string; + phoneNumber: string | null; + } + | null + | undefined; +} + +export default function CustomProfileUpdateForm({profileDetails}:Props) { + + const [successMsg, setSuccessMsg] = useState(""); + const [errorMsg, setErrorMsg] = useState(""); + const [isPending, startTransition] = useTransition(); + + const form = useForm>({ + resolver: zodResolver(UpdateCustomProfileSchema), + defaultValues: { + name: profileDetails?.name || "", + email: profileDetails?.email || "", + phonenumber: profileDetails?.phoneNumber || "", + password: "", + }, + }); + + const onSubmit = (values: z.infer) => { + + setSuccessMsg(""); + setErrorMsg(""); + startTransition(() => { + updateProfile(values).then((response) => { + if (response.status === "success") { + setSuccessMsg(response.message); + } + if (response.status === "error") { + setErrorMsg(response.message); + } + }); + }); + + }; + + return ( +
+ + ( + + Full Name + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + ( + + Email + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + ( + + PhoneNumber + + + + + + )} + /> + ( + + Password + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + + {successMsg && } + {errorMsg && } + + + ); +} diff --git a/packages/ui/src/components/DashboardPanel.tsx b/packages/ui/src/components/DashboardPanel.tsx index 7574f0f..0f64314 100644 --- a/packages/ui/src/components/DashboardPanel.tsx +++ b/packages/ui/src/components/DashboardPanel.tsx @@ -6,13 +6,17 @@ import { PanelRightOpen, Rotate3D, Wallet, + ArrowLeftRight, } from "lucide-react"; import { Button } from "./ui/button"; import DashboardLink from "./DashboardLink"; import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; import LogoutButton from "./LogoutButton"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import clsx from "clsx"; +import MyProfile from "./MyProfile"; +import { useSession } from "next-auth/react"; +import { BASE_URL } from "@repo/web/baseurl"; type Props = { user: { @@ -21,8 +25,63 @@ type Props = { }; }; -export default function DashboardPanel({ user }: Props) { +export default async function DashboardPanel({ user }: Props) { const [isPanelOpen, setPanelOpen] = useState(true); + const session = useSession(); + + + const [profileDetails, setProfileDetails] = useState<{ + + name: string | null; + email: string; + phoneNumber: string | null; + + + } | null>(); + + const [accountDetails, setAccountDetails] = useState<{ + + provider: string; + + } | null>(); + + useEffect(() => { + const fetchUserDetails = async () => { + const response = await fetch(`${BASE_URL}/api/myprofile`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + userId:session.data?.userId + }), + }); + + const details = await response.json(); + + setProfileDetails(details.data); + }; + + const fetchOAuthAccountDetails = async () => { + const response = await fetch(`${BASE_URL}/api/myoauthaccount`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + userId:session.data?.userId + }), + }); + + const details = await response.json(); + + setAccountDetails(details.data); + }; + + fetchUserDetails(); + fetchOAuthAccountDetails(); + }, []); + return ( <> @@ -46,6 +105,7 @@ export default function DashboardPanel({ user }: Props) { > } name="Dashboard" /> } name="My Wallet" /> + } name="Transactions" /> } name="P2P Transfer" />
@@ -59,7 +119,7 @@ export default function DashboardPanel({ user }: Props) { {user?.name?.toUpperCase().slice(0, 2)} - +
diff --git a/packages/ui/src/components/Globe.tsx b/packages/ui/src/components/Globe.tsx new file mode 100644 index 0000000..14c5014 --- /dev/null +++ b/packages/ui/src/components/Globe.tsx @@ -0,0 +1,305 @@ +"use client"; +import { useEffect, useRef, useState } from "react"; +import { Color, Scene, Fog, PerspectiveCamera, Vector3 } from "three"; +import ThreeGlobe from "three-globe"; +import { useThree, Object3DNode, Canvas, extend } from "@react-three/fiber"; +import { OrbitControls } from "@react-three/drei"; +import countries from "../data/globe.json" +declare module "@react-three/fiber" { + interface ThreeElements { + threeGlobe: Object3DNode; + } +} + +extend({ ThreeGlobe }); + +const RING_PROPAGATION_SPEED = 3; +const aspect = 1.2; +const cameraZ = 300; + +type Position = { + order: number; + startLat: number; + startLng: number; + endLat: number; + endLng: number; + arcAlt: number; + color: string; +}; + +export type GlobeConfig = { + pointSize?: number; + globeColor?: string; + showAtmosphere?: boolean; + atmosphereColor?: string; + atmosphereAltitude?: number; + emissive?: string; + emissiveIntensity?: number; + shininess?: number; + polygonColor?: string; + ambientLight?: string; + directionalLeftLight?: string; + directionalTopLight?: string; + pointLight?: string; + arcTime?: number; + arcLength?: number; + rings?: number; + maxRings?: number; + initialPosition?: { + lat: number; + lng: number; + }; + autoRotate?: boolean; + autoRotateSpeed?: number; +}; + +interface WorldProps { + globeConfig: GlobeConfig; + data: Position[]; +} + +let numbersOfRings = [0]; + +export function Globe({ globeConfig, data }: WorldProps) { + const [globeData, setGlobeData] = useState< + | { + size: number; + order: number; + color: (t: number) => string; + lat: number; + lng: number; + }[] + | null + >(null); + + const globeRef = useRef(null); + + const defaultProps = { + pointSize: 1, + atmosphereColor: "#ffffff", + showAtmosphere: true, + atmosphereAltitude: 0.1, + polygonColor: "rgba(255,255,255,0.7)", + globeColor: "#1d072e", + emissive: "#000000", + emissiveIntensity: 0.1, + shininess: 0.9, + arcTime: 2000, + arcLength: 0.9, + rings: 1, + maxRings: 3, + ...globeConfig, + }; + + useEffect(() => { + if (globeRef.current) { + _buildData(); + _buildMaterial(); + } + }, [globeRef.current]); + + const _buildMaterial = () => { + if (!globeRef.current) return; + + const globeMaterial = globeRef.current.globeMaterial() as unknown as { + color: Color; + emissive: Color; + emissiveIntensity: number; + shininess: number; + }; + globeMaterial.color = new Color(globeConfig.globeColor); + globeMaterial.emissive = new Color(globeConfig.emissive); + globeMaterial.emissiveIntensity = globeConfig.emissiveIntensity || 0.1; + globeMaterial.shininess = globeConfig.shininess || 0.9; + }; + + const _buildData = () => { + const arcs = data; + let points = []; + for (let i = 0; i < arcs.length; i++) { + const arc = arcs[i]; + const rgb = hexToRgb(arc.color) as { r: number; g: number; b: number }; + points.push({ + size: defaultProps.pointSize, + order: arc.order, + color: (t: number) => `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${1 - t})`, + lat: arc.startLat, + lng: arc.startLng, + }); + points.push({ + size: defaultProps.pointSize, + order: arc.order, + color: (t: number) => `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${1 - t})`, + lat: arc.endLat, + lng: arc.endLng, + }); + } + + // remove duplicates for same lat and lng + const filteredPoints = points.filter( + (v, i, a) => + a.findIndex((v2) => + ["lat", "lng"].every( + (k) => v2[k as "lat" | "lng"] === v[k as "lat" | "lng"] + ) + ) === i + ); + + setGlobeData(filteredPoints); + }; + + useEffect(() => { + if (globeRef.current && globeData) { + globeRef.current + .hexPolygonsData(countries.features) + .hexPolygonResolution(3) + .hexPolygonMargin(0.7) + .showAtmosphere(defaultProps.showAtmosphere) + .atmosphereColor(defaultProps.atmosphereColor) + .atmosphereAltitude(defaultProps.atmosphereAltitude) + .hexPolygonColor((e) => { + return defaultProps.polygonColor; + }); + startAnimation(); + } + }, [globeData]); + + const startAnimation = () => { + if (!globeRef.current || !globeData) return; + + globeRef.current + .arcsData(data) + .arcStartLat((d) => (d as { startLat: number }).startLat * 1) + .arcStartLng((d) => (d as { startLng: number }).startLng * 1) + .arcEndLat((d) => (d as { endLat: number }).endLat * 1) + .arcEndLng((d) => (d as { endLng: number }).endLng * 1) + .arcColor((e: any) => (e as { color: string }).color) + .arcAltitude((e) => { + return (e as { arcAlt: number }).arcAlt * 1; + }) + .arcStroke((e) => { + return [0.32, 0.28, 0.3][Math.round(Math.random() * 2)]; + }) + .arcDashLength(defaultProps.arcLength) + .arcDashInitialGap((e) => (e as { order: number }).order * 1) + .arcDashGap(15) + .arcDashAnimateTime((e) => defaultProps.arcTime); + + globeRef.current + .pointsData(data) + .pointColor((e) => (e as { color: string }).color) + .pointsMerge(true) + .pointAltitude(0.0) + .pointRadius(2); + + globeRef.current + .ringsData([]) + .ringColor((e: any) => (t: any) => e.color(t)) + .ringMaxRadius(defaultProps.maxRings) + .ringPropagationSpeed(RING_PROPAGATION_SPEED) + .ringRepeatPeriod( + (defaultProps.arcTime * defaultProps.arcLength) / defaultProps.rings + ); + }; + + useEffect(() => { + if (!globeRef.current || !globeData) return; + + const interval = setInterval(() => { + if (!globeRef.current || !globeData) return; + numbersOfRings = genRandomNumbers( + 0, + data.length, + Math.floor((data.length * 4) / 5) + ); + + globeRef.current.ringsData( + globeData.filter((d, i) => numbersOfRings.includes(i)) + ); + }, 2000); + + return () => { + clearInterval(interval); + }; + }, [globeRef.current, globeData]); + + return ( + <> + + + ); +} + +export function WebGLRendererConfig() { + const { gl, size } = useThree(); + + useEffect(() => { + gl.setPixelRatio(window.devicePixelRatio); + gl.setSize(size.width, size.height); + gl.setClearColor(0xffaaff, 0); + }, []); + + return null; +} + +export function World(props: WorldProps) { + const { globeConfig } = props; + const scene = new Scene(); + scene.fog = new Fog(0xffffff, 400, 2000); + return ( + + + + + + + + + + ); +} + +export function hexToRgb(hex: string) { + var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, function (m, r, g, b) { + return r + r + g + g + b + b; + }); + + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } + : null; +} + +export function genRandomNumbers(min: number, max: number, count: number) { + const arr = []; + while (arr.length < count) { + const r = Math.floor(Math.random() * (max - min)) + min; + if (arr.indexOf(r) === -1) arr.push(r); + } + + return arr; +} diff --git a/packages/ui/src/components/GlobeContainer.tsx b/packages/ui/src/components/GlobeContainer.tsx new file mode 100644 index 0000000..1570f98 --- /dev/null +++ b/packages/ui/src/components/GlobeContainer.tsx @@ -0,0 +1,400 @@ +"use client"; + +import dynamic from "next/dynamic"; +const World = dynamic(() => import("./Globe").then((m) => m.World), { + ssr: false, +}); + +const globeConfig = { + pointSize: 4, + globeColor: "#004852", + showAtmosphere: true, + atmosphereColor: "#004852", + atmosphereAltitude: 0.1, + emissive: "#062056", + emissiveIntensity: 0.1, + shininess: 0.5, + polygonColor: "rgba(255,255,255,0.7)", + ambientLight: "#38bdf8", + directionalLeftLight: "#ffffff", + directionalTopLight: "#ffffff", + pointLight: "#ffffff", + arcTime: 1000, + arcLength: 0.9, + rings: 1, + maxRings: 3, + initialPosition: { lat: 22.3193, lng: 114.1694 }, + autoRotate: true, + autoRotateSpeed: 0.5, +}; +const colors = ["#e3ff57", "#e3ff57", "#e3ff57"]; +const sampleArcs = [ + { + order: 1, + startLat: -19.885592, + startLng: -43.951191, + endLat: -22.9068, + endLng: -43.1729, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 1, + startLat: 28.6139, + startLng: 77.209, + endLat: 3.139, + endLng: 101.6869, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 1, + startLat: -19.885592, + startLng: -43.951191, + endLat: -1.303396, + endLng: 36.852443, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: 1.3521, + startLng: 103.8198, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: 51.5072, + startLng: -0.1276, + endLat: 3.139, + endLng: 101.6869, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: -15.785493, + startLng: -47.909029, + endLat: 36.162809, + endLng: -115.119411, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: -33.8688, + startLng: 151.2093, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: 21.3099, + startLng: -157.8581, + endLat: 40.7128, + endLng: -74.006, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: -6.2088, + startLng: 106.8456, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: 11.986597, + startLng: 8.571831, + endLat: -15.595412, + endLng: -56.05918, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: -34.6037, + startLng: -58.3816, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: 51.5072, + startLng: -0.1276, + endLat: 48.8566, + endLng: -2.3522, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 14.5995, + startLng: 120.9842, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 1.3521, + startLng: 103.8198, + endLat: -33.8688, + endLng: 151.2093, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 34.0522, + startLng: -118.2437, + endLat: 48.8566, + endLng: -2.3522, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: -15.432563, + startLng: 28.315853, + endLat: 1.094136, + endLng: -63.34546, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: 37.5665, + startLng: 126.978, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: 22.3193, + startLng: 114.1694, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: -19.885592, + startLng: -43.951191, + endLat: -15.595412, + endLng: -56.05918, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: 48.8566, + startLng: -2.3522, + endLat: 52.52, + endLng: 13.405, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: 52.52, + startLng: 13.405, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: -8.833221, + startLng: 13.264837, + endLat: -33.936138, + endLng: 18.436529, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: 49.2827, + startLng: -123.1207, + endLat: 52.3676, + endLng: 4.9041, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: 1.3521, + startLng: 103.8198, + endLat: 40.7128, + endLng: -74.006, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 51.5072, + startLng: -0.1276, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 22.3193, + startLng: 114.1694, + endLat: -22.9068, + endLng: -43.1729, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 1.3521, + startLng: 103.8198, + endLat: -34.6037, + endLng: -58.3816, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: -22.9068, + startLng: -43.1729, + endLat: 28.6139, + endLng: 77.209, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: 34.0522, + startLng: -118.2437, + endLat: 31.2304, + endLng: 121.4737, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: -6.2088, + startLng: 106.8456, + endLat: 52.3676, + endLng: 4.9041, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: 41.9028, + startLng: 12.4964, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: -6.2088, + startLng: 106.8456, + endLat: 31.2304, + endLng: 121.4737, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: 22.3193, + startLng: 114.1694, + endLat: 1.3521, + endLng: 103.8198, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 34.0522, + startLng: -118.2437, + endLat: 37.7749, + endLng: -122.4194, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 35.6762, + startLng: 139.6503, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 22.3193, + startLng: 114.1694, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: 52.52, + startLng: 13.405, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: 11.986597, + startLng: 8.571831, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: -22.9068, + startLng: -43.1729, + endLat: -34.6037, + endLng: -58.3816, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 14, + startLat: -33.936138, + startLng: 18.436529, + endLat: 21.395643, + endLng: 39.883798, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, +]; + +export default function GlobeContainer() { + return ( +
+ +
+ ); +} diff --git a/packages/ui/src/components/Loader.tsx b/packages/ui/src/components/Loader.tsx new file mode 100644 index 0000000..01756e0 --- /dev/null +++ b/packages/ui/src/components/Loader.tsx @@ -0,0 +1,30 @@ +export default function LoadingAnimation() { + return ( +
+ + + + +
+ ); +} diff --git a/packages/ui/src/components/MoneyFlowChart.tsx b/packages/ui/src/components/MoneyFlowChart.tsx index 6ea2bff..56547e5 100644 --- a/packages/ui/src/components/MoneyFlowChart.tsx +++ b/packages/ui/src/components/MoneyFlowChart.tsx @@ -27,7 +27,6 @@ ChartJS.register( export default function MoneyflowChart({chartData}:{chartData:number[]}){ -console.log(chartData); const options = { responsive:true, maintainAspectRatio: false, @@ -59,6 +58,7 @@ console.log(chartData); label: "Balance", data: chartData, tension: 0.3, + borderColor: '#004852', backgroundColor: '#ccdadc', pointBackgroundColor:"#e3ff57", diff --git a/packages/ui/src/components/MoneyFlowContainer.tsx b/packages/ui/src/components/MoneyFlowContainer.tsx index 1a79fc2..1d14365 100644 --- a/packages/ui/src/components/MoneyFlowContainer.tsx +++ b/packages/ui/src/components/MoneyFlowContainer.tsx @@ -32,7 +32,7 @@ export default async function MoneyFlowContainer() { where: { status: "Success", userId: userId, - startTime: { + timestamp: { gte: new Date(unixTime1200SecAgo).toISOString(), }, }, @@ -65,7 +65,7 @@ export default async function MoneyFlowContainer() { const onRamp = oneDayDataOnRamp.map((details) => { if ( new Date((Math.floor(oneDayAgo.getTime() / 1000) - time) * 1000) < - details.startTime + details.timestamp ) { return details; } @@ -94,7 +94,7 @@ export default async function MoneyFlowContainer() { if (!currentVal) { return 0; } - return acc + currentVal?.Amount; + return acc + currentVal?.amount; }, 0); // Sent @@ -114,7 +114,7 @@ export default async function MoneyFlowContainer() { if (!currentVal) { return 0; } - return acc + currentVal?.Amount; + return acc + currentVal?.amount; }, 0); console.log(onRampTotal); console.log(receivedTotal); diff --git a/packages/ui/src/components/MyProfile.tsx b/packages/ui/src/components/MyProfile.tsx new file mode 100644 index 0000000..c3d65d7 --- /dev/null +++ b/packages/ui/src/components/MyProfile.tsx @@ -0,0 +1,57 @@ +import CustomProfileUpdateForm from "./CustomProfileUpdateForm"; +import OAuthProfileUpdateForm from "./OAuthProfileUpdateForm"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "./ui/sheet"; + +type Props = { + userId: string; + profileDetails: + | { + name: string | null; + email: string; + phoneNumber: string | null; + } + | null + | undefined; + accountDetails: + | { + provider: string | null; + } + | null + | undefined; +}; + +export default function MyProfile({ + userId, + profileDetails, + accountDetails, +}: Props) { + + + const ProfileForm = accountDetails?.provider ? ( + + ) : ( + + ); + + + return ( + + + My Profile + + + + Profile + {ProfileForm} + + + + ); +} diff --git a/packages/ui/src/components/OAuthProfileUpdateForm.tsx b/packages/ui/src/components/OAuthProfileUpdateForm.tsx new file mode 100644 index 0000000..3a8942d --- /dev/null +++ b/packages/ui/src/components/OAuthProfileUpdateForm.tsx @@ -0,0 +1,137 @@ +import { z } from "zod"; +import { UpdateOAuthProfileScheama } from "@repo/schemas/authenticationSchema"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { Button } from "./ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "./ui/form"; +import { Input } from "./ui/input"; +import { updateProfile } from "@repo/web/updateProfile"; +import { useState, useTransition } from "react"; +import SuccessMsg from "./SuccessMsg"; +import ErrorMsg from "./ErrorMsg"; + +type Props = { + profileDetails: + | { + name: string | null; + email: string; + phoneNumber: string | null; + } + | null + | undefined; +} + +export default function OAuthProfileUpdateForm({profileDetails}:Props) { + + const [successMsg, setSuccessMsg] = useState(""); + const [errorMsg, setErrorMsg] = useState(""); + const [isPending, startTransition] = useTransition(); + + const form = useForm>({ + resolver: zodResolver(UpdateOAuthProfileScheama), + defaultValues: { + name: profileDetails?.name||"", + email: profileDetails?.email || "", + phonenumber: profileDetails?.phoneNumber || "", + password: "", + }, + }); + + const onSubmit = (values: z.infer) => { + console.log(values); + // todo: Make sure to send only number to backend + setSuccessMsg(""); + setErrorMsg(""); + startTransition(() => { + updateProfile({ + name:profileDetails?.name || "", + email:profileDetails?.email || "", + password:"", + phonenumber:values.phonenumber + + }).then((response) => { + if (response.status === "success") { + setSuccessMsg(response.message); + } + if (response.status === "error") { + setErrorMsg(response.message); + } + }); + }); + + + }; + + return ( +
+ + ( + + Full Name + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + ( + + Email + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + ( + + PhoneNumber + + + + + + )} + /> + ( + + Password + + + + {/* todo: Remove the Form Message no use here */} + + + )} + /> + + {successMsg && } + {errorMsg && } + + + ); +} diff --git a/packages/ui/src/components/P2PTransactionCard.tsx b/packages/ui/src/components/P2PTransactionCard.tsx index 3647174..31d8b01 100644 --- a/packages/ui/src/components/P2PTransactionCard.tsx +++ b/packages/ui/src/components/P2PTransactionCard.tsx @@ -27,7 +27,7 @@ export default async function P2PTransactionCard({ date, amount,toUserId,fromUse } }) return ( -
+

{status}

diff --git a/packages/ui/src/components/PasswordInput.tsx b/packages/ui/src/components/PasswordInput.tsx index 699c1ee..a9ea8c8 100755 --- a/packages/ui/src/components/PasswordInput.tsx +++ b/packages/ui/src/components/PasswordInput.tsx @@ -8,6 +8,7 @@ import { Eye, EyeOff } from "lucide-react"; type Props = { isPending: boolean; + isdisabled? : boolean; field: ControllerRenderProps< { email: string; @@ -26,7 +27,7 @@ type Props = { >; }; -export default function PasswordInput({ isPending, field }: Props) { +export default function PasswordInput({ isPending, field,isdisabled }: Props) { const [showPassword, setShowPassword] = useState(false); return ( @@ -35,7 +36,7 @@ export default function PasswordInput({ isPending, field }: Props) { placeholder="Password" type={showPassword ? "text" : "password"} className=" pr-12" - disabled={isPending} + disabled={isPending || isdisabled} {...field} /> + + + + {transactionDetails.id} +

{formattCurrency(transactionDetails.amount)}

+ +

From: {transactionDetails.provider}

+

From: {transactionDetails.provider}

+
+
+ +
+ + ); +} diff --git a/packages/ui/src/components/RecentTransactionCard.tsx b/packages/ui/src/components/RecentTransactionCard.tsx new file mode 100644 index 0000000..cfa9ae4 --- /dev/null +++ b/packages/ui/src/components/RecentTransactionCard.tsx @@ -0,0 +1,47 @@ +import { Wallet, UsersRound } from "lucide-react"; +import { formattCurrency } from "../lib/formatting"; +import clsx from "clsx"; + +type Props = { + type:'Wallet'|'Peer', + date: Date, + amount: number, + status:string +} + +export default function RecentTransactionCard({type,date,amount,status}:Props) { + + const formattedAmount = formattCurrency(amount); + return ( +
+
+ {type ==="Wallet" && + + } + {type ==="Peer" && + + } + +

{type}

+
+ +
+

{date.toLocaleDateString()}

+

{date.toLocaleTimeString()}

+
+ +
+

{formattedAmount}

+
+ +
+

{status}

+
+
+ ); +} diff --git a/packages/ui/src/components/SignInForm.tsx b/packages/ui/src/components/SignInForm.tsx index afc4d1e..48867fa 100755 --- a/packages/ui/src/components/SignInForm.tsx +++ b/packages/ui/src/components/SignInForm.tsx @@ -46,14 +46,7 @@ export default function SignInForm({ setSuccessMsg(""); setErrorMsg(""); startTransition(() => { - action(values).then((response) => { - if (response.status === "success") { - setSuccessMsg(response.message); - } - if (response.status === "error") { - setErrorMsg(response.message); - } - }); + action(values); }); } @@ -91,7 +84,7 @@ export default function SignInForm({ />
{successMsg && } {errorMsg && } diff --git a/packages/ui/src/components/SignUpForm.tsx b/packages/ui/src/components/SignUpForm.tsx index d24a510..477a175 100755 --- a/packages/ui/src/components/SignUpForm.tsx +++ b/packages/ui/src/components/SignUpForm.tsx @@ -21,6 +21,7 @@ import { useState, useTransition } from "react"; import SuccessMsg from "./SuccessMsg"; import ErrorMsg from "./ErrorMsg"; + export default function SignUpForm({ action, }: { @@ -59,10 +60,14 @@ export default function SignUpForm({ } return ( -
+ +
+ + + + +
); } diff --git a/packages/ui/src/components/StatisticsPieChart.tsx b/packages/ui/src/components/StatisticsPieChart.tsx new file mode 100644 index 0000000..aaee329 --- /dev/null +++ b/packages/ui/src/components/StatisticsPieChart.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { Pie } from "react-chartjs-2"; +import { Chart as ChartJS, ArcElement, Tooltip, Legend , plugins,} from "chart.js"; + +ChartJS.register(ArcElement, Tooltip, Legend,plugins ); + + +const options = { + responsive:true, + maintainAspectRatio: false, + + plugins:{ + legend:{ + display:false + } + } + +}; + + +type Props = { + totalWalletMoneyAdded: number, + totalPeerSent:number, + totalPeerReceived:number +} + +export default function ({totalPeerReceived,totalWalletMoneyAdded,totalPeerSent}:Props) { + + if(!(totalPeerReceived || totalWalletMoneyAdded || totalPeerSent)){ + return
+

No Data

+
+ } + + const data = { + labels: ["Wallet Add Money", "Peers sent", "Peers Received"], + datasets: [ + { + label: "Amount", + data: [totalWalletMoneyAdded, totalPeerSent, totalPeerReceived], + backgroundColor: [ + "#004852", + "#93da9d", + "#e3ff57", + ], + + borderWidth: 1, + }, + ], + }; + + return ; +} diff --git a/packages/ui/src/components/StatisticsPieChartContainer.tsx b/packages/ui/src/components/StatisticsPieChartContainer.tsx new file mode 100644 index 0000000..9159291 --- /dev/null +++ b/packages/ui/src/components/StatisticsPieChartContainer.tsx @@ -0,0 +1,69 @@ +import StatisticsPieChart from "./StatisticsPieChart"; +import db from "@repo/database/client"; +import { auth } from "@repo/web/auth"; + +export default async function StatisticsPieChartContainer() { + const session = await auth(); + + const walletAddMoney = await db.onRampTransactions.findMany({ + where: { + AND: [ + { + userId: session?.userId, + }, + { + status: "Success", + }, + ], + }, + }); + + const totalWalletMoneyAdded = walletAddMoney.reduce((acc, currentVal) => { + return acc + currentVal.amount; + }, 0); + + const totalPeerTransafers = await db.p2pTransfers.findMany({ + where: { + AND: [ + { + OR: [ + { + fromUserId: session?.userId, + }, + { + toUserId: session?.userId, + }, + ], + }, + { + status: "Success", + }, + ], + }, + }); + + // console.log(totalPeerTransafers); + + + const totalPeerSent= totalPeerTransafers.reduce((acc, currentVal) => { + if(currentVal.fromUserId === session?.userId){ + + return acc + currentVal.amount; + } + + return acc + }, 0); + const totalPeerReceived= totalPeerTransafers.reduce((acc, currentVal) => { + if(currentVal.toUserId === session?.userId){ + + return acc + currentVal.amount; + } + + return acc + }, 0); + + // console.log('Total received',totalPeerReceived); + // console.log('Total sent',totalPeerSent); + + return ; +} diff --git a/packages/ui/src/components/TransactionCard.tsx b/packages/ui/src/components/TransactionCard.tsx index c25220c..bb8f86e 100755 --- a/packages/ui/src/components/TransactionCard.tsx +++ b/packages/ui/src/components/TransactionCard.tsx @@ -6,6 +6,7 @@ import { formattCurrency } from "../lib/formatting"; import db from "@repo/web/db"; import { useEffect, useState } from "react"; import { useRouter } from 'next/navigation' +import {BASE_URL} from "@repo/web/baseurl"; type TransactionCardProps = { transactionId: string; @@ -21,55 +22,35 @@ export default function TransactionCard({ amount, cardId, }: TransactionCardProps) { - console.log(status); + const [transactionStatus, setTransactionStatus] = useState(status); const router = useRouter(); const formattedAmount = formattCurrency(amount); - // useEffect(() => { - // const fetchStatus = async () => { - // const res = await fetch( - // `http://localhost:3000/api/transaction/${transactionId}`, - // { - // cache: "no-store", - // } - // ); - - // const data = await res.json(); - - // setTransactionStatus(data.status); - // }; - - // fetchStatus(); - // }, []); if (transactionStatus === "Processing" || transactionStatus === "") { const intervalId = setInterval(async () => { const res = await fetch( - `http://localhost:3000/api/transaction/${transactionId}`, + `${BASE_URL}/api/transaction/${transactionId}`, { cache: "no-store", } ); const data = await res.json(); + - setTransactionStatus(data.status); - if(data.status !== "Processing"){ + + if(data.data.status !== "Processing"){ + setTransactionStatus(data.data.status); clearInterval(intervalId); router.refresh(); } - - }, 5000); } - // if(transactionStatus === ""){ - // return ( - //
Fetching
- // ) - // } + return (
diff --git a/packages/ui/src/components/TransactionTabs.tsx b/packages/ui/src/components/TransactionTabs.tsx index 435ec85..2cfbc2e 100644 --- a/packages/ui/src/components/TransactionTabs.tsx +++ b/packages/ui/src/components/TransactionTabs.tsx @@ -18,7 +18,7 @@ export default async function TransactionTabs({ defaultSelection }: Props) { }); const sortedOnRampTransactions = onRampTransactions.sort((a, b) => { - return new Date(b.startTime).getTime() - new Date(a.startTime).getTime(); + return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(); }); const p2pTransactions = await db.p2pTransfers.findMany({ @@ -65,7 +65,7 @@ export default async function TransactionTabs({ defaultSelection }: Props) { value="all" className="data-[state=active]:bg-secondary text-secondary data-[state=active]:text-primary " > - All Transactions + Wallet Transactions + {sortedOnRampTransactions.length === 0 &&
+

No transaction made yet

+
}
    {sortedOnRampTransactions.map((transactionDetails) => (
  • ))}
+ {sortedP2pTransactions.length === 0 &&
+

No transaction made yet

+
}
    {sortedP2pTransactions.map((transactionDetails) => { if (session?.userId === transactionDetails.toUserId) { @@ -113,7 +120,7 @@ export default async function TransactionTabs({ defaultSelection }: Props) {
  • + {sortedP2pSentTransactions.length === 0 &&
    +

    No transaction made yet

    +
    }
      {sortedP2pSentTransactions.map((transactionDetails) => (
    • + {sortedP2pReceivedTransactions.length === 0 &&
      +

      No transaction made yet

      +
      }
        {sortedP2pReceivedTransactions.map((transactionDetails) => { if (session?.userId === transactionDetails.toUserId) { @@ -164,7 +177,7 @@ export default async function TransactionTabs({ defaultSelection }: Props) {
      • ) => Promise<{ status: string; message: string; -}>; + }>; }) { - + const [open, setOpen] = useState(false); + const [isPending, startTransition] = useTransition(); + const [searchedContact, setSearchedContact] = useState(""); + const [isFetching, setIsFetching] = useState(false); + const [data, setData] = useState< + { name: string | null; phoneNumber: string | null; image: string | null }[] + >([]); const [successMsg, setSuccessMsg] = useState(""); const [errorMsg, setErrorMsg] = useState(""); - const [isPending, startTransition] = useTransition(); + + useEffect(() => { + const fetchLatestFiveTransfers = async () => { + setData([]); + setIsFetching(true); + const latestFiveTransfers = await fetch( + `${BASE_URL}/api/p2ptransfers`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + numberOfContacts: 5, + }), + } + ); + + const latestTransfers = await latestFiveTransfers.json(); + + setData(latestTransfers.data); + setIsFetching(false); + }; + + if (searchedContact === "") { + fetchLatestFiveTransfers(); + } + }, [searchedContact]); + + useEffect(() => { + const fetchData = async () => { + setData([]); + setIsFetching(true); + const searchedContacts = await fetch( + `${BASE_URL}/api/contacts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + searchedContact, + }), + } + ); + + const fetchedContacts = await searchedContacts.json(); + + setData(fetchedContacts.data); + setIsFetching(false); + }; + + if (searchedContact !== "") { + fetchData(); + } + }, [searchedContact]); const form = useForm>({ resolver: zodResolver(p2pTranferFormSchema), @@ -64,16 +140,81 @@ export default function TransferAmountForm({ name="phonenumber" render={({ field }) => ( - + PhoneNumber - - - + + + + + + + + + { + // console.log(searchedValue); + setSearchedContact(searchedValue); + }} + /> + + {isFetching ? : "No contact found"} + + + + {data.map((contact) => ( + { + form.setValue( + "phonenumber", + contact.phoneNumber || "" + ); + setOpen(false); + }} + > + +
        + + + {contact.name?.slice(0, 1)} + + + +

        + {" "} + {`${contact.name} (${contact.phoneNumber})`} +

        +
        +
        + ))} +
        +
        +
        +
        +
        +
        )} @@ -83,7 +224,9 @@ export default function TransferAmountForm({ name="amount" render={({ field }) => ( - Amount + + Amount + - {isPending ? "In Progress..." : "Send"} + {isPending ? "In Progress..." : "Send"} {successMsg && } - {errorMsg && } + {errorMsg && } ); diff --git a/packages/ui/src/components/columns.tsx b/packages/ui/src/components/columns.tsx new file mode 100644 index 0000000..fc18acf --- /dev/null +++ b/packages/ui/src/components/columns.tsx @@ -0,0 +1,164 @@ +"use client"; + +import { ColumnDef } from "@tanstack/react-table"; +import clsx from "clsx"; +import { ArrowUpDown, UsersRound, Wallet } from "lucide-react"; +import { useSession } from "next-auth/react"; +import { Button } from "./ui/button"; +import { formattCurrency } from "../lib/formatting"; +import PaymentDetailsDialog from "./PaymentDetailsDialog"; +import { useState } from "react"; + + +export type Transaction = { + id: String; + name: string; + status: string; + date: Date; + invoice: string; + amount: number; + fromUserId: string | null; + toUserId: string | null; +}; + +export const columns: ColumnDef[] = [ + { + accessorKey: "name", + header: "Name/Business", + cell: ({ row }) => { + const name: string = row.getValue("name"); + + if (name === "Wallet") { + return ( +
        + + + +

        {name}

        +
        + ); + } + + return ( +
        + + + +

        {name}

        +
        + ); + }, + + filterFn: (row,id,value) =>{ + return value.includes(row.getValue(id)) + } + }, + { + accessorKey: "date", + header: ({ column }) => { + return ( + + ); + }, + + cell: ({ row }) => { + const date: Date = row.getValue("date"); + + return ( +
        +

        {date.toLocaleDateString()}

        +

        + {date.toLocaleTimeString()} +

        +
        + ); + }, + }, + { + accessorKey: "invoice", + header: "Invoice ID", + }, + { + accessorKey: "amount", + header: ({column})=>{ + + return ( + + ) + }, + cell: ({ row }) => { + const session = useSession(); + + const amount: number = row.getValue("amount"); + const status: string = row.getValue("status"); + const name: string = row.getValue("name"); + + if (name === "Peer") { + const fromUserId: string = row.getValue("fromUserId"); + const toUserId: string = row.getValue("toUserId"); + return ( +

        + {toUserId === session.data?.userId && "+"}{" "} + {fromUserId === session.data?.userId && "-"} {formattCurrency(amount)} +

        + ); + } + + return ( +

        + {name === "Wallet" && status === "Success" && "+"} {formattCurrency(amount)} +

        + ); + }, + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => { + const status: string = row.getValue("status"); + + if (status === "Processing") { + return ( +

        + {status} +

        + ); + } + if (status === "Failed") { + return ( +

        + {status} +

        + ); + } + + return ( +

        + {status} +

        + ); + }, + }, + { + accessorKey: "fromUserId", + header: "FromUserId", + }, + { + accessorKey: "toUserId", + header: "ToUserId", + }, + +]; diff --git a/packages/ui/src/components/data-table-faceted-filter.tsx b/packages/ui/src/components/data-table-faceted-filter.tsx new file mode 100644 index 0000000..84196e5 --- /dev/null +++ b/packages/ui/src/components/data-table-faceted-filter.tsx @@ -0,0 +1,147 @@ +import * as React from "react" +import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons" +import { Column } from "@tanstack/react-table" + +import { cn } from "@repo/ui/lib" +import { Badge } from "./ui/badge" +import { Button } from "./ui/button" +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "./ui/command" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "./ui/popover" +import { Separator } from "./ui/separator" + +interface DataTableFacetedFilterProps { + column?: Column + title?: string + options: { + label: string + value: string + icon?: React.ComponentType<{ className?: string }> + }[] +} + +export function DataTableFacetedFilter({ + column, + title, + options, +}: DataTableFacetedFilterProps) { + const facets = column?.getFacetedUniqueValues() + const selectedValues = new Set(column?.getFilterValue() as string[]) + + return ( + + + + + + + + + No results found. + + {options.map((option) => { + const isSelected = selectedValues.has(option.value) + return ( + { + if (isSelected) { + selectedValues.delete(option.value) + } else { + selectedValues.add(option.value) + } + const filterValues = Array.from(selectedValues) + column?.setFilterValue( + filterValues.length ? filterValues : undefined + ) + }} + > +
        + +
        + {option.icon && ( + + )} + {option.label} + {facets?.get(option.value) && ( + + {facets.get(option.value)} + + )} +
        + ) + })} +
        + {selectedValues.size > 0 && ( + <> + + + column?.setFilterValue(undefined)} + className="justify-center text-center" + > + Clear filters + + + + )} +
        +
        +
        +
        + ) +} \ No newline at end of file diff --git a/packages/ui/src/components/data-table.tsx b/packages/ui/src/components/data-table.tsx new file mode 100644 index 0000000..677f6be --- /dev/null +++ b/packages/ui/src/components/data-table.tsx @@ -0,0 +1,172 @@ +"use client"; + +import { + ColumnDef, + flexRender, + getCoreRowModel, + useReactTable, + getPaginationRowModel, + SortingState, + getSortedRowModel, + ColumnFiltersState, + getFilteredRowModel, +} from "@tanstack/react-table"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "./ui/table"; + +import { Button } from "./ui/button"; +import { useState } from "react"; +import { Input } from "./ui/input"; +import { DataTableFacetedFilter } from "./data-table-faceted-filter"; +import { CircleUserRound, Wallet } from "lucide-react"; + + +interface DataTableProps { + columns: ColumnDef[]; + data: TData[]; +} + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const [sorting, setSorting] = useState([]); + const [columnFilters, setColumnFilters] = useState([]); + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + state: { + sorting, + columnFilters, + }, + + initialState: { + columnVisibility: { + fromUserId: false, + toUserId: false, + }, + pagination: { + pageSize: 8, + }, + }, + }); + + return ( +
        +
        + + table.getColumn("invoice")?.setFilterValue(event.target.value) + } + className=" max-w-sm w-full" + /> + + +
        +
        + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No Results. + + + )} + +
        +
        +
        + + +
        + +
        + ); +} diff --git a/packages/ui/src/components/infinite-moving-cards.tsx b/packages/ui/src/components/infinite-moving-cards.tsx new file mode 100644 index 0000000..dc6e370 --- /dev/null +++ b/packages/ui/src/components/infinite-moving-cards.tsx @@ -0,0 +1,128 @@ +"use client"; + +import { cn } from "../lib/lib"; +import React, { useEffect, useState } from "react"; +import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; + +export const InfiniteMovingCards = ({ + items, + direction = "left", + speed = "fast", + pauseOnHover = true, + className, +}: { + items: { + quote: string; + name: string; + title: string; + image:string; + }[]; + direction?: "left" | "right"; + speed?: "fast" | "normal" | "slow"; + pauseOnHover?: boolean; + className?: string; +}) => { + const containerRef = React.useRef(null); + const scrollerRef = React.useRef(null); + + useEffect(() => { + addAnimation(); + }, []); + const [start, setStart] = useState(false); + function addAnimation() { + if (containerRef.current && scrollerRef.current) { + const scrollerContent = Array.from(scrollerRef.current.children); + + scrollerContent.forEach((item) => { + const duplicatedItem = item.cloneNode(true); + if (scrollerRef.current) { + scrollerRef.current.appendChild(duplicatedItem); + } + }); + + getDirection(); + getSpeed(); + setStart(true); + } + } + const getDirection = () => { + if (containerRef.current) { + if (direction === "left") { + containerRef.current.style.setProperty( + "--animation-direction", + "forwards" + ); + } else { + containerRef.current.style.setProperty( + "--animation-direction", + "reverse" + ); + } + } + }; + const getSpeed = () => { + if (containerRef.current) { + if (speed === "fast") { + containerRef.current.style.setProperty("--animation-duration", "20s"); + } else if (speed === "normal") { + containerRef.current.style.setProperty("--animation-duration", "40s"); + } else { + containerRef.current.style.setProperty("--animation-duration", "80s"); + } + } + }; + return ( +
        +
          + {items.map((item, idx) => ( +
        • +
          + + + {item.quote} + +
          + + + + UR + + + + + {item.name} + + + {item.title} + + +
          +
          +
        • + ))} +
        +
        + ); +}; + +export default InfiniteMovingCards; \ No newline at end of file diff --git a/packages/ui/src/components/loader/PageLoader.tsx b/packages/ui/src/components/loader/PageLoader.tsx new file mode 100644 index 0000000..a5aa9d6 --- /dev/null +++ b/packages/ui/src/components/loader/PageLoader.tsx @@ -0,0 +1,17 @@ + +import styles from "./loader.module.css"; + +export default function PageLoader(){ + + return ( +
        +
        +
        +
        +
        +
        +
        +
        +
        + ) +} \ No newline at end of file diff --git a/packages/ui/src/components/loader/loader.module.css b/packages/ui/src/components/loader/loader.module.css new file mode 100644 index 0000000..63e7acf --- /dev/null +++ b/packages/ui/src/components/loader/loader.module.css @@ -0,0 +1,140 @@ +@keyframes square-animation { + 0% { + left: 0; + top: 0; + } + + 10.5% { + left: 0; + top: 0; + } + + 12.5% { + left: 32px; + top: 0; + } + + 23% { + left: 32px; + top: 0; + } + + 25% { + left: 64px; + top: 0; + } + + 35.5% { + left: 64px; + top: 0; + } + + 37.5% { + left: 64px; + top: 32px; + } + + 48% { + left: 64px; + top: 32px; + } + + 50% { + left: 32px; + top: 32px; + } + + 60.5% { + left: 32px; + top: 32px; + } + + 62.5% { + left: 32px; + top: 64px; + } + + 73% { + left: 32px; + top: 64px; + } + + 75% { + left: 0; + top: 64px; + } + + 85.5% { + left: 0; + top: 64px; + } + + 87.5% { + left: 0; + top: 32px; + } + + 98% { + left: 0; + top: 32px; + } + + 100% { + left: 0; + top: 0; + } + } + + .loader { + position: relative; + width: 96px; + height: 96px; + transform: rotate(45deg); + } + + .loader-square { + position: absolute; + top: 0; + left: 0; + width: 20px; + height: 20px; + margin: 2px; + border-radius: 0px; + background: #004852; + background-size: cover; + background-position: center; + background-attachment: fixed; + animation: square-animation 10s ease-in-out infinite both; + } + + .loader-square:nth-of-type(0) { + animation-delay: 0s; + } + + .loader-square:nth-of-type(1) { + animation-delay: -1.4285714286s; + } + + .loader-square:nth-of-type(2) { + animation-delay: -2.8571428571s; + } + + .loader-square:nth-of-type(3) { + animation-delay: -4.2857142857s; + } + + .loader-square:nth-of-type(4) { + animation-delay: -5.7142857143s; + } + + .loader-square:nth-of-type(5) { + animation-delay: -7.1428571429s; + } + + .loader-square:nth-of-type(6) { + animation-delay: -8.5714285714s; + } + + .loader-square:nth-of-type(7) { + animation-delay: -10s; + } \ No newline at end of file diff --git a/packages/ui/src/components/ui/command.tsx b/packages/ui/src/components/ui/command.tsx new file mode 100644 index 0000000..fa875b4 --- /dev/null +++ b/packages/ui/src/components/ui/command.tsx @@ -0,0 +1,155 @@ +"use client" + +import * as React from "react" +import { type DialogProps } from "@radix-ui/react-dialog" +import { MagnifyingGlassIcon } from "@radix-ui/react-icons" +import { Command as CommandPrimitive } from "cmdk" + +import { cn } from "@repo/ui/lib" +import { Dialog, DialogContent } from "./dialog" + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Command.displayName = CommandPrimitive.displayName + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ) +} + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
        + + +
        +)) + +CommandInput.displayName = CommandPrimitive.Input.displayName + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandList.displayName = CommandPrimitive.List.displayName + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)) + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandGroup.displayName = CommandPrimitive.Group.displayName + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +CommandSeparator.displayName = CommandPrimitive.Separator.displayName + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) + +CommandItem.displayName = CommandPrimitive.Item.displayName + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +CommandShortcut.displayName = "CommandShortcut" + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/packages/ui/src/components/ui/input-otp.tsx b/packages/ui/src/components/ui/input-otp.tsx new file mode 100644 index 0000000..55be0b5 --- /dev/null +++ b/packages/ui/src/components/ui/input-otp.tsx @@ -0,0 +1,71 @@ +"use client" + +import * as React from "react" +import { DashIcon } from "@radix-ui/react-icons" +import { OTPInput, OTPInputContext } from "input-otp" + +import { cn } from "@repo/ui/lib" + +const InputOTP = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, containerClassName, ...props }, ref) => ( + +)) +InputOTP.displayName = "InputOTP" + +const InputOTPGroup = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> +>(({ className, ...props }, ref) => ( +
        +)) +InputOTPGroup.displayName = "InputOTPGroup" + +const InputOTPSlot = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> & { index: number } +>(({ index, className, ...props }, ref) => { + const inputOTPContext = React.useContext(OTPInputContext) + const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index] + + return ( +
        + {char} + {hasFakeCaret && ( +
        +
        +
        + )} +
        + ) +}) +InputOTPSlot.displayName = "InputOTPSlot" + +const InputOTPSeparator = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> +>(({ ...props }, ref) => ( +
        + +
        +)) +InputOTPSeparator.displayName = "InputOTPSeparator" + +export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } diff --git a/packages/ui/src/components/ui/pagination.tsx b/packages/ui/src/components/ui/pagination.tsx new file mode 100644 index 0000000..177b2b8 --- /dev/null +++ b/packages/ui/src/components/ui/pagination.tsx @@ -0,0 +1,121 @@ +import * as React from "react" +import { + ChevronLeftIcon, + ChevronRightIcon, + DotsHorizontalIcon, +} from "@radix-ui/react-icons" +import Link from "next/link" +import { cn } from "@repo/ui/lib" +import { ButtonProps, buttonVariants } from "./button" + +const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => ( +