diff --git a/actions/auth-actions.ts b/actions/auth-actions.ts index 938ffb5..6f8d155 100644 --- a/actions/auth-actions.ts +++ b/actions/auth-actions.ts @@ -1,10 +1,7 @@ "use server"; -import { authClient } from "@/lib/auth-client"; -import prisma from "@/lib/db"; import { VerifyUserDetails } from "@/lib/person"; import { signUpFormSchema } from "@/lib/schemas"; -import { phoneNumber } from "better-auth/plugins"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; import { z } from "zod"; @@ -34,7 +31,7 @@ export async function signin(previousState: ActionState, formData: FormData) { }; } const FORMATTED_MOBILE_NUMBER: string = `${phoneNumber.split("-").join("")}`; - console.log(FORMATTED_MOBILE_NUMBER); + console.log({ FORMATTED_MOBILE_NUMBER }); const userExistsResponse = await fetch( `${process.env.SARLINK_API_BASE_URL}/auth/mobile/`, { @@ -48,7 +45,7 @@ export async function signin(previousState: ActionState, formData: FormData) { }, ); const userExists = await userExistsResponse.json(); - console.log(userExists.non_field_errors); + console.log("user exists", userExists); if (userExists?.non_field_errors) { return redirect(`/signup?phone_number=${phoneNumber}`); } @@ -75,7 +72,6 @@ export async function signup(_actionState: ActionState, formData: FormData) { const data = Object.fromEntries(formData.entries()); const parsedData = signUpFormSchema.safeParse(data); // get phone number from /signup?phone_number=999-1231 - const headersList = await headers(); console.log("DATA ON SERVER SIDE", data); @@ -87,83 +83,82 @@ export async function signup(_actionState: ActionState, formData: FormData) { }; } - const idCardExists = await prisma.user.findFirst({ - where: { - id_card: parsedData.data.id_card, - }, - }); + // const idCardExists = await prisma.user.findFirst({ + // where: { + // id_card: parsedData.data.id_card, + // }, + // }); - if (idCardExists) { - return { - message: "ID card already exists.", - payload: formData, - db_error: "id_card", - }; - } + // if (idCardExists) { + // return { + // message: "ID card already exists.", + // payload: formData, + // db_error: "id_card", + // }; + // } - const phoneNumberExists = await prisma.user.findFirst({ - where: { - phoneNumber: parsedData.data.phone_number, - }, - }); + // const phoneNumberExists = await prisma.user.findFirst({ + // where: { + // phoneNumber: parsedData.data.phone_number, + // }, + // }); - if (phoneNumberExists) { - return { - message: "Phone number already exists.", - payload: formData, - db_error: "phone_number", - }; - } + // if (phoneNumberExists) { + // return { + // message: "Phone number already exists.", + // payload: formData, + // db_error: "phone_number", + // }; + // } - const newUser = await prisma.user.create({ - data: { - name: parsedData.data.name, - islandId: parsedData.data.island_id, - atollId: parsedData.data.atoll_id, - address: parsedData.data.address, - id_card: parsedData.data.id_card, - dob: new Date(parsedData.data.dob), - role: "USER", - accNo: parsedData.data.accNo, - phoneNumber: parsedData.data.phone_number, - }, - }); - const isValidPerson = await VerifyUserDetails({ user: newUser }); + // const newUser = await prisma.user.create({ + // data: { + // name: parsedData.data.name, + // islandId: parsedData.data.island_id, + // atollId: parsedData.data.atoll_id, + // address: parsedData.data.address, + // id_card: parsedData.data.id_card, + // dob: new Date(parsedData.data.dob), + // role: "USER", + // accNo: parsedData.data.accNo, + // phoneNumber: parsedData.data.phone_number, + // }, + // }); + // const isValidPerson = await VerifyUserDetails({ user: newUser }); - if (!isValidPerson) { - await SendUserRejectionDetailSMS({ - details: ` - A new user has requested for verification. \n -USER DETAILS: -Name: ${parsedData.data.name} -Address: ${parsedData.data.address} -ID Card: ${parsedData.data.id_card} -DOB: ${parsedData.data.dob.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} -ACC No: ${parsedData.data.accNo}\n\nVerify the user with the following link: ${process.env.BETTER_AUTH_URL}/users/${newUser.id}/verify - `, - phoneNumber: process.env.ADMIN_PHONENUMBER ?? "", - }); - return { - message: - "Your account has been requested for verification. Please wait for a response from admin.", - payload: formData, - db_error: "invalidPersonValidation", - }; - } + // if (!isValidPerson) { + // await SendUserRejectionDetailSMS({ + // details: ` + // A new user has requested for verification. \n + // USER DETAILS: + // Name: ${parsedData.data.name} + // Address: ${parsedData.data.address} + // ID Card: ${parsedData.data.id_card} + // DOB: ${parsedData.data.dob.toLocaleDateString("en-US", { + // month: "short", + // day: "2-digit", + // year: "numeric", + // })} + // ACC No: ${parsedData.data.accNo}\n\nVerify the user with the following link: ${process.env.BETTER_AUTH_URL}/users/${newUser.id}/verify + // `, + // phoneNumber: process.env.ADMIN_PHONENUMBER ?? "", + // }); + // return { + // message: + // "Your account has been requested for verification. Please wait for a response from admin.", + // payload: formData, + // db_error: "invalidPersonValidation", + // }; - if (isValidPerson) { - await authClient.phoneNumber.sendOtp({ - phoneNumber: newUser.phoneNumber, - }); - } - redirect( - `/verify-otp?phone_number=${encodeURIComponent(newUser.phoneNumber)}`, - ); - return { message: "User created successfully" }; + // if (isValidPerson) { + // await authClient.phoneNumber.sendOtp({ + // phoneNumber: newUser.phoneNumber, + // }); + // } + // redirect( + // `/verify-otp?phone_number=${encodeURIComponent(newUser.phoneNumber)}`, + // ); + // return { message: "User created successfully" }; } export const sendOtp = async (phoneNumber: string, code: string) => { diff --git a/actions/user-actions.ts b/actions/user-actions.ts index 9d64627..40514c3 100644 --- a/actions/user-actions.ts +++ b/actions/user-actions.ts @@ -1,85 +1,79 @@ "use server"; - -import prisma from "@/lib/db"; import { VerifyUserDetails } from "@/lib/person"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { CreateClient } from "./ninja/client"; export async function VerifyUser(userId: string) { - const user = await prisma.user.findUnique({ - where: { - id: userId, - }, - include: { - atoll: true, - island: true, - }, - }); - if (!user) { - throw new Error("User not found"); - } - const isValidPerson = await VerifyUserDetails({ user }); - - if (!isValidPerson) - throw new Error("The user details does not match national data."); - - if (isValidPerson) { - await prisma.user.update({ - where: { - id: userId, - }, - data: { - verified: true, - }, - }); - - const ninjaClient = await CreateClient({ - group_settings_id: "", - address1: "", - city: user.atoll?.name || "", - state: user.island?.name || "", - postal_code: "", - country_id: "462", - address2: user.address || "", - contacts: { - first_name: user.name?.split(" ")[0] || "", - last_name: user.name?.split(" ")[1] || "", - email: user.email || "", - phone: user.phoneNumber || "", - send_email: false, - custom_value1: user.dob?.toISOString().split("T")[0] || "", - custom_value2: user.id_card || "", - custom_value3: "", - }, - }); - } - - revalidatePath("/users"); + // const user = await prisma.user.findUnique({ + // where: { + // id: userId, + // }, + // include: { + // atoll: true, + // island: true, + // }, + // }); + // if (!user) { + // throw new Error("User not found"); + // } + // const isValidPerson = await VerifyUserDetails({ user }); + // if (!isValidPerson) + // throw new Error("The user details does not match national data."); + // if (isValidPerson) { + // await prisma.user.update({ + // where: { + // id: userId, + // }, + // data: { + // verified: true, + // }, + // }); + // const ninjaClient = await CreateClient({ + // group_settings_id: "", + // address1: "", + // city: user.atoll?.name || "", + // state: user.island?.name || "", + // postal_code: "", + // country_id: "462", + // address2: user.address || "", + // contacts: { + // first_name: user.name?.split(" ")[0] || "", + // last_name: user.name?.split(" ")[1] || "", + // email: user.email || "", + // phone: user.phoneNumber || "", + // send_email: false, + // custom_value1: user.dob?.toISOString().split("T")[0] || "", + // custom_value2: user.id_card || "", + // custom_value3: "", + // }, + // }); + // } + // revalidatePath("/users"); } export async function Rejectuser({ userId, reason, }: { userId: string; reason: string }) { - const user = await prisma.user.findUnique({ - where: { - id: userId, - }, - }); - if (!user) { - throw new Error("User not found"); - } + // const user = await prisma.user.findUnique({ + // where: { + // id: userId, + // }, + // }); + // if (!user) { + // throw new Error("User not found"); + // } - await SendUserRejectionDetailSMS({ - details: reason, - phoneNumber: user.phoneNumber, - }); - await prisma.user.delete({ - where: { - id: userId, - }, - }); + // await SendUserRejectionDetailSMS({ + // details: reason, + // phoneNumber: user.phoneNumber, + // }); + // await prisma.user.delete({ + // where: { + // id: userId, + // }, + // }); revalidatePath("/users"); redirect("/users"); } @@ -117,13 +111,13 @@ export async function AddDevice({ mac_address, user_id, }: { name: string; mac_address: string; user_id: string }) { - const newDevice = await prisma.device.create({ - data: { - name: name, - mac: mac_address, - userId: user_id, - }, - }); + // const newDevice = await prisma.device.create({ + // data: { + // name: name, + // mac: mac_address, + // userId: user_id, + // }, + // }); revalidatePath("/devices"); - return newDevice; + // return newDevice; } diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 1e31963..1b9f7dd 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -1,12 +1,11 @@ import LoginForm from "@/components/auth/login-form"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import { headers } from "next/headers"; import Image from "next/image"; import { redirect } from "next/navigation"; import React from "react"; export default async function LoginPage() { - return (
diff --git a/app/(dashboard)/payments/[paymentId]/page.tsx b/app/(dashboard)/payments/[paymentId]/page.tsx index 2661af0..198d2cd 100644 --- a/app/(dashboard)/payments/[paymentId]/page.tsx +++ b/app/(dashboard)/payments/[paymentId]/page.tsx @@ -1,51 +1,53 @@ import DevicesToPay from "@/components/devices-to-pay"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import prisma from "@/lib/db"; import { cn } from "@/lib/utils"; import { headers } from "next/headers"; import React from "react"; export default async function PaymentPage({ - params, + params, }: { - params: Promise<{ paymentId: string }>; + params: Promise<{ paymentId: string }>; }) { - const session = await auth.api.getSession({ - headers: await headers() - }) - const user = await prisma.user.findUnique({ - where: { - id: session?.session.userId - } - }) - const paymentId = (await params).paymentId; - const payment = await prisma.payment.findUnique({ - where: { - id: paymentId, - }, - include: { - devices: true, - }, - }); - return ( -
-
-

- Payment -

- - {payment?.paid ? "Paid" : "Pending"} - -
+ const session = await auth.api.getSession({ + headers: await headers(), + }); + const user = await prisma.user.findUnique({ + where: { + id: session?.session.userId, + }, + }); + const paymentId = (await params).paymentId; + const payment = await prisma.payment.findUnique({ + where: { + id: paymentId, + }, + include: { + devices: true, + }, + }); + return ( +
+
+

Payment

+ + {payment?.paid ? "Paid" : "Pending"} + +
-
- -
-
- ); +
+ +
+
+ ); } diff --git a/app/api/auth/[...all]/route.ts b/app/api/auth/[...all]/route.ts index e11351a..24c5477 100644 --- a/app/api/auth/[...all]/route.ts +++ b/app/api/auth/[...all]/route.ts @@ -1,4 +1,4 @@ -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import { toNextJsHandler } from "better-auth/next-js"; export const { GET, POST } = toNextJsHandler(auth.handler); diff --git a/app/auth.ts b/app/auth.ts new file mode 100644 index 0000000..4cde7a7 --- /dev/null +++ b/app/auth.ts @@ -0,0 +1,108 @@ +import { logout } from "@/queries/authentication"; +import type { NextAuthOptions } from "next-auth"; +import type { JWT } from "next-auth/jwt"; +import CredentialsProvider from "next-auth/providers/credentials"; + +export const authOptions: NextAuthOptions = { + pages: { + signIn: "/auth/signin", + }, + session: { + strategy: "jwt", + maxAge: 30 * 60, // 30 mins + }, + events: { + signOut({ token }) { + const apitoken = token.apiToken; + console.log("apitoken", apitoken); + logout({ token: apitoken as string }); + }, + }, + providers: [ + CredentialsProvider({ + name: "Credentials", + credentials: { + email: { label: "Email", type: "text", placeholder: "jsmith" }, + password: { label: "Password", type: "password" }, + }, + async authorize(credentials) { + const { email, password } = credentials as { + email: string; + password: string; + }; + console.log("email and password", email, password); + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/auth/login/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + username: email, + password: password, + }), + }, + ); + console.log("status", res.status); + + const data = await res.json(); + console.log({ data }); + switch (res.status) { + case 200: + return { ...data.user, apiToken: data.token, expiry: data.expiry }; + case 400: + throw new Error( + JSON.stringify({ message: data.message, status: res.status }), + ); + case 429: + throw new Error( + JSON.stringify({ message: data.message, status: res.status }), + ); + case 403: + throw new Error( + JSON.stringify({ message: data.error, status: res.status }), + ); + default: + throw new Error( + JSON.stringify({ + message: "FATAL: Unexprted Error occured!", + status: res.status, + }), + ); + } + }, + }), + ], + callbacks: { + redirect: async ({ url, baseUrl }) => { + // Allows relative callback URLs + if (url.startsWith("/")) return `${baseUrl}${url}`; + return baseUrl; + }, + session: async ({ session, token }) => { + const sanitizedToken = Object.keys(token).reduce((p, c) => { + // strip unnecessary properties + if (c !== "iat" && c !== "exp" && c !== "jti" && c !== "apiToken") { + Object.assign(p, { [c]: token[c] }); + } + return p; + }, {}); + // session.expires = token.expiry + return { + ...session, + user: sanitizedToken, + apiToken: token.apiToken, + // expires: token.expiry, + }; + }, + jwt: ({ token, user }) => { + if (typeof user !== "undefined") { + // user has just signed in so the user object is populated + return user as unknown as JWT; + } + return token; + }, + }, + secret: process.env.NEXTAUTH_SECRET, +}; diff --git a/components/admin/admin-devices-table.tsx b/components/admin/admin-devices-table.tsx index 570fe81..ea6b3f1 100644 --- a/components/admin/admin-devices-table.tsx +++ b/components/admin/admin-devices-table.tsx @@ -1,14 +1,14 @@ import { - Table, - TableBody, - TableCaption, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, } from "@/components/ui/table"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import prisma from "@/lib/db"; import { headers } from "next/headers"; import Link from "next/link"; @@ -17,180 +17,188 @@ import DeviceCard from "../device-card"; import Pagination from "../pagination"; export async function AdminDevicesTable({ - searchParams, - parentalControl, + searchParams, + parentalControl, }: { - searchParams: Promise<{ - query: string; - page: number; - sortBy: string; - }>; - parentalControl?: boolean; + searchParams: Promise<{ + query: string; + page: number; + sortBy: string; + }>; + parentalControl?: boolean; }) { - const session = await auth.api.getSession({ - headers: await headers() - }) - const isAdmin = session?.user.role === "ADMIN" - const query = (await searchParams)?.query || ""; - const page = (await searchParams)?.page; - const sortBy = (await searchParams)?.sortBy || "asc"; - const totalDevices = await prisma.device.count({ - where: { - OR: [ - { - name: { - contains: query || "", - mode: "insensitive", - }, - }, - { - mac: { - contains: query || "", - mode: "insensitive", - }, - }, - ], - }, - }); + const session = await auth.api.getSession({ + headers: await headers(), + }); + const isAdmin = session?.user.role === "ADMIN"; + const query = (await searchParams)?.query || ""; + const page = (await searchParams)?.page; + const sortBy = (await searchParams)?.sortBy || "asc"; + const totalDevices = await prisma.device.count({ + where: { + OR: [ + { + name: { + contains: query || "", + mode: "insensitive", + }, + }, + { + mac: { + contains: query || "", + mode: "insensitive", + }, + }, + ], + }, + }); - const totalPages = Math.ceil(totalDevices / 10); - const limit = 10; - const offset = (Number(page) - 1) * limit || 0; + const totalPages = Math.ceil(totalDevices / 10); + const limit = 10; + const offset = (Number(page) - 1) * limit || 0; - const devices = await prisma.device.findMany({ - where: { - OR: [ - { - name: { - contains: query || "", - mode: "insensitive", - }, - }, - { - mac: { - contains: query || "", - mode: "insensitive", - }, - }, - ], - }, - include: { - User: true, - payments: true, - }, - skip: offset, - take: limit, - orderBy: { - name: `${sortBy}` as "asc" | "desc", - }, - }); + const devices = await prisma.device.findMany({ + where: { + OR: [ + { + name: { + contains: query || "", + mode: "insensitive", + }, + }, + { + mac: { + contains: query || "", + mode: "insensitive", + }, + }, + ], + }, + include: { + User: true, + payments: true, + }, + skip: offset, + take: limit, + orderBy: { + name: `${sortBy}` as "asc" | "desc", + }, + }); - return ( -
- {devices.length === 0 ? ( -
-

No devices yet.

-
- ) : ( - <> -
- - Table of all devices. - - - Device Name - User - MAC Address - isActive - blocked - blockedBy - expiryDate - - - - {devices.map((device) => ( - - -
- - {device.name} - - {device.isActive && ( + return ( +
+ {devices.length === 0 ? ( +
+

No devices yet.

+
+ ) : ( + <> +
+
+ Table of all devices. + + + Device Name + User + MAC Address + isActive + blocked + blockedBy + expiryDate + + + + {devices.map((device) => ( + + +
+ + {device.name} + + {device.isActive && ( + + Active until{" "} + {new Date().toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", + })} + + )} - - Active until{" "} - {new Date().toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} - - )} + {device.blocked && ( +
+ Comment: +

+ blocked because he was watching youtube +

+
+ )} +
+
+ + {device.User?.name} + - {device.blocked && ( -
- Comment: -

- blocked because he was watching youtube -

-
- )} - - - - {device.User?.name} - - {device.mac} - - {device.isActive ? "Active" : "Inactive"} - - - {device.blocked ? "Blocked" : "Not Blocked"} - - - {device.blocked ? device.blockedBy : ""} - - - {new Date().toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} - - - - -
- ))} -
- - - - {query.length > 0 && ( -

- Showing {devices.length} locations for "{query} - " -

- )} -
- - {totalDevices} devices - -
-
-
- -
-
- {devices.map((device) => ( - - ))} -
- - )} -
- ); + {device.mac} + + {device.isActive ? "Active" : "Inactive"} + + + {device.blocked ? "Blocked" : "Not Blocked"} + + + {device.blocked ? device.blockedBy : ""} + + + {new Date().toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", + })} + + + + + + ))} + + + + + {query.length > 0 && ( +

+ Showing {devices.length} locations for "{query} + " +

+ )} +
+ + {totalDevices} devices + +
+
+ + +
+
+ {devices.map((device) => ( + + ))} +
+ + )} +
+ ); } diff --git a/components/auth/application-layout.tsx b/components/auth/application-layout.tsx index c31313c..f4bf083 100644 --- a/components/auth/application-layout.tsx +++ b/components/auth/application-layout.tsx @@ -10,7 +10,7 @@ import { SidebarProvider, SidebarTrigger, } from "@/components/ui/sidebar"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import prisma from "@/lib/db"; import { headers } from "next/headers"; import { AccountPopover } from "./account-popver"; @@ -19,7 +19,7 @@ export async function ApplicationLayout({ children, }: { children: React.ReactNode }) { const session = await auth.api.getSession({ - headers: await headers() + headers: await headers(), }); const billFormula = await prisma.billFormula.findFirst(); const user = await prisma.user.findFirst({ diff --git a/components/auth/login-form.tsx b/components/auth/login-form.tsx index 834250a..9062dc7 100644 --- a/components/auth/login-form.tsx +++ b/components/auth/login-form.tsx @@ -23,6 +23,7 @@ export default function LoginForm() { {state.message}

)} - diff --git a/components/devices-table.tsx b/components/devices-table.tsx index a8f4434..a93682f 100644 --- a/components/devices-table.tsx +++ b/components/devices-table.tsx @@ -8,7 +8,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import prisma from "@/lib/db"; import { headers } from "next/headers"; import ClickableRow from "./clickable-row"; @@ -27,9 +27,9 @@ export async function DevicesTable({ parentalControl?: boolean; }) { const session = await auth.api.getSession({ - headers: await headers() - }) - const isAdmin = session?.user.role === "ADMIN" + headers: await headers(), + }); + const isAdmin = session?.user.role === "ADMIN"; const query = (await searchParams)?.query || ""; const page = (await searchParams)?.page; const sortBy = (await searchParams)?.sortBy || "asc"; @@ -53,12 +53,16 @@ export async function DevicesTable({ NOT: { payments: { some: { - paid: false - } - } + paid: false, + }, + }, }, isActive: isAdmin ? undefined : parentalControl, - blocked: isAdmin ? undefined : parentalControl !== undefined ? undefined : false, + blocked: isAdmin + ? undefined + : parentalControl !== undefined + ? undefined + : false, }, }); @@ -86,8 +90,8 @@ export async function DevicesTable({ NOT: { payments: { some: { - paid: false - } + paid: false, + }, }, }, isActive: parentalControl, @@ -158,7 +162,12 @@ export async function DevicesTable({ // )} // // - + ))} @@ -181,7 +190,11 @@ export async function DevicesTable({
{devices.map((device) => ( - + ))}
diff --git a/components/payments-table.tsx b/components/payments-table.tsx index 7d6bd9e..b26ea7a 100644 --- a/components/payments-table.tsx +++ b/components/payments-table.tsx @@ -1,17 +1,17 @@ import { - Table, - TableBody, - TableCaption, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, } from "@/components/ui/table"; import prisma from "@/lib/db"; import Link from "next/link"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import { cn } from "@/lib/utils"; import type { Prisma } from "@prisma/client"; import { Calendar } from "lucide-react"; @@ -22,219 +22,258 @@ import { Button } from "./ui/button"; import { Separator } from "./ui/separator"; type PaymentWithDevices = Prisma.PaymentGetPayload<{ - include: { - devices: true; - }; -}> + include: { + devices: true; + }; +}>; export async function PaymentsTable({ - searchParams, + searchParams, }: { - searchParams: Promise<{ - query: string; - page: number; - sortBy: string; - }>; + searchParams: Promise<{ + query: string; + page: number; + sortBy: string; + }>; }) { - const session = await auth.api.getSession({ - headers: await headers() - }) - const query = (await searchParams)?.query || ""; - const page = (await searchParams)?.page; - const totalPayments = await prisma.payment.count({ - where: { - userId: session?.session.userId, - OR: [ - { - devices: { - every: { - name: { - contains: query || "", - mode: "insensitive", - }, - }, - }, - }, - ], - }, - }); + const session = await auth.api.getSession({ + headers: await headers(), + }); + const query = (await searchParams)?.query || ""; + const page = (await searchParams)?.page; + const totalPayments = await prisma.payment.count({ + where: { + userId: session?.session.userId, + OR: [ + { + devices: { + every: { + name: { + contains: query || "", + mode: "insensitive", + }, + }, + }, + }, + ], + }, + }); - const totalPages = Math.ceil(totalPayments / 10); - const limit = 10; - const offset = (Number(page) - 1) * limit || 0; + const totalPages = Math.ceil(totalPayments / 10); + const limit = 10; + const offset = (Number(page) - 1) * limit || 0; - const payments = await prisma.payment.findMany({ - where: { - userId: session?.session.userId, - OR: [ - { - devices: { - every: { - name: { - contains: query || "", - mode: "insensitive", - }, - }, - }, - }, - ], - }, - include: { - devices: true - }, + const payments = await prisma.payment.findMany({ + where: { + userId: session?.session.userId, + OR: [ + { + devices: { + every: { + name: { + contains: query || "", + mode: "insensitive", + }, + }, + }, + }, + ], + }, + include: { + devices: true, + }, - skip: offset, - take: limit, - orderBy: { - createdAt: "desc", - }, - }); + skip: offset, + take: limit, + orderBy: { + createdAt: "desc", + }, + }); - return ( -
- {payments.length === 0 ? ( -
-

No Payments yet.

-
- ) : ( - <> -
- - Table of all devices. - - - Details - Duration + return ( +
+ {payments.length === 0 ? ( +
+

No Payments yet.

+
+ ) : ( + <> +
+
+ Table of all devices. + + + Details + Duration - Amount - - - - {payments.map((payment) => ( - - -
-
- - - {new Date(payment.createdAt).toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} - -
+ Amount + + + + {payments.map((payment) => ( + + +
+
+ + + {new Date(payment.createdAt).toLocaleDateString( + "en-US", + { + month: "short", + day: "2-digit", + year: "numeric", + }, + )} + +
-
- - - - - {payment.paid ? "Paid" : "Unpaid"} - -
-
-

Devices

-
    - {payment.devices.map((device) => ( -
  1. - {device.name} -
  2. - ))} -
-
-
-
- - {payment.numberOfMonths} Months - - - - {payment.amount.toFixed(2)} - - MVR - -
- ))} -
- - - - {query.length > 0 && ( -

- Showing {payments.length} locations for "{query} - " -

- )} -
- - {totalPayments} payments - -
-
-
- -
-
- {payments.map((payment) => ( - - ))} -
- - )} -
- ); +
+ + + + + {payment.paid ? "Paid" : "Unpaid"} + +
+
+

Devices

+
    + {payment.devices.map((device) => ( +
  1. + {device.name} +
  2. + ))} +
+
+ + + + {payment.numberOfMonths} Months + + + + {payment.amount.toFixed(2)} + + MVR + + + ))} + + + + + {query.length > 0 && ( +

+ Showing {payments.length} locations for "{query} + " +

+ )} +
+ + {totalPayments} payments + +
+
+ + + +
+ {payments.map((payment) => ( + + ))} +
+ + )} + + ); } - function MobilePaymentDetails({ payment }: { payment: PaymentWithDevices }) { - return ( -
-
- - - {new Date(payment.createdAt).toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} - -
+ return ( +
+
+ + + {new Date(payment.createdAt).toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", + })} + +
-
- - - - - {payment.paid ? "Paid" : "Unpaid"} - -
-
-

Devices

-
    - {payment.devices.map((device) => ( -
  1. - {device.name} -
  2. - ))} -
-
- -

Duration

- - {payment.numberOfMonths} Months - - -

Amount

- - {payment.amount.toFixed(2)} MVR - -
-
-
- ) -} \ No newline at end of file +
+ + + + + {payment.paid ? "Paid" : "Unpaid"} + +
+
+

Devices

+
    + {payment.devices.map((device) => ( +
  1. + {device.name} +
  2. + ))} +
+
+ +

Duration

+ + {payment.numberOfMonths} Months + + +

Amount

+ + {payment.amount.toFixed(2)} MVR + +
+
+
+ ); +} diff --git a/components/ui/phone-input.tsx b/components/ui/phone-input.tsx index 9713af6..5474a58 100644 --- a/components/ui/phone-input.tsx +++ b/components/ui/phone-input.tsx @@ -5,164 +5,160 @@ import flags from "react-phone-number-input/flags"; import { Button } from "@/components/ui/button"; import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, } from "@/components/ui/command"; import { Input } from "@/components/ui/input"; import { - Popover, - PopoverContent, - PopoverTrigger, + Popover, + PopoverContent, + PopoverTrigger, } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; type PhoneInputProps = Omit< - React.ComponentProps<"input">, - "onChange" | "value" | "ref" + React.ComponentProps<"input">, + "onChange" | "value" | "ref" > & - Omit, "onChange"> & { - onChange?: (value: RPNInput.Value) => void; - }; + Omit, "onChange"> & { + onChange?: (value: RPNInput.Value) => void; + }; const PhoneInput: React.ForwardRefExoticComponent = - React.forwardRef, PhoneInputProps>( - ({ className, onChange, ...props }, ref) => { - return ( - onChange?.(value || ("" as RPNInput.Value))} - {...props} - /> - ); - }, - ); + React.forwardRef, PhoneInputProps>( + ({ className, onChange, ...props }, ref) => { + return ( + onChange?.(value || ("" as RPNInput.Value))} + {...props} + /> + ); + }, + ); PhoneInput.displayName = "PhoneInput"; const InputComponent = React.forwardRef< - HTMLInputElement, - React.ComponentProps<"input"> + HTMLInputElement, + React.ComponentProps<"input"> >(({ className, ...props }, ref) => ( - + )); InputComponent.displayName = "InputComponent"; type CountryEntry = { label: string; value: RPNInput.Country | undefined }; type CountrySelectProps = { - disabled?: boolean; - value: RPNInput.Country; - options: CountryEntry[]; - onChange: (country: RPNInput.Country) => void; + disabled?: boolean; + value: RPNInput.Country; + options: CountryEntry[]; + onChange: (country: RPNInput.Country) => void; }; const CountrySelect = ({ - disabled, - value: selectedCountry, - options: countryList, - onChange, + disabled, + value: selectedCountry, + options: countryList, + onChange, }: CountrySelectProps) => { - return ( - - - - - - - - - - No country found. - - {countryList.map(({ value, label }) => - value ? ( - - ) : null, - )} - - - - - - - ); + return ( + + + + + + + + + + No country found. + + {countryList.map(({ value, label }) => + value ? ( + + ) : null, + )} + + + + + + + ); }; interface CountrySelectOptionProps extends RPNInput.FlagProps { - selectedCountry: RPNInput.Country; - onChange: (country: RPNInput.Country) => void; + selectedCountry: RPNInput.Country; + onChange: (country: RPNInput.Country) => void; } const CountrySelectOption = ({ - country, - countryName, - selectedCountry, - onChange, + country, + countryName, + selectedCountry, + onChange, }: CountrySelectOptionProps) => { - return ( - onChange(country)}> - - {countryName} - {`+${RPNInput.getCountryCallingCode(country)}`} - - - ); + return ( + onChange(country)}> + + {countryName} + {`+${RPNInput.getCountryCallingCode(country)}`} + + + ); }; const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => { - const Flag = flags[country]; + const Flag = flags[country]; - return ( - - {Flag && } - - ); + return ( + + {Flag && } + + ); }; export { PhoneInput }; diff --git a/lib/auth-client.ts b/lib/auth-client.ts deleted file mode 100644 index 440c83c..0000000 --- a/lib/auth-client.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { phoneNumberClient } from "better-auth/client/plugins"; -import { createAuthClient } from "better-auth/react"; - -export const authClient = createAuthClient({ - baseURL: process.env.BETTER_AUTH_URL, - plugins: [phoneNumberClient()], -}); diff --git a/lib/auth-guard.ts b/lib/auth-guard.ts index 720e6aa..8c9416e 100644 --- a/lib/auth-guard.ts +++ b/lib/auth-guard.ts @@ -1,5 +1,5 @@ "use server"; -import { auth } from "@/lib/auth"; +import { auth } from "@/app/auth"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; diff --git a/lib/auth-utils.ts b/lib/auth-utils.ts index 4f4b3d6..78685d4 100644 --- a/lib/auth-utils.ts +++ b/lib/auth-utils.ts @@ -1,7 +1,7 @@ "use server"; import { headers } from "next/headers"; import { cache } from "react"; -import { auth } from "./auth"; +import { auth } from "../app/auth"; const getCurrentUserCache = cache(async () => { const session = await auth.api.getSession({ diff --git a/lib/auth.ts b/lib/auth.ts deleted file mode 100644 index 79b8421..0000000 --- a/lib/auth.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { sendOtp } from "@/actions/auth-actions"; -import { betterAuth } from "better-auth"; -import { prismaAdapter } from "better-auth/adapters/prisma"; -import { phoneNumber } from "better-auth/plugins"; -import prisma from "./db"; - -export const auth = betterAuth({ - session: { - cookieCache: { - enabled: true, - maxAge: 10 * 60, // Cache duration in seconds - }, - }, - trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(",") || [ - "localhost:3000", - ], - user: { - additionalFields: { - role: { - type: "string", - required: false, - defaultValue: "USER", - input: false, // don't allow user to set role - }, - lang: { - type: "string", - required: false, - defaultValue: "en", - }, - }, - }, - database: prismaAdapter(prisma, { - provider: "postgresql", // or "mysql", "postgresql", ...etc - }), - plugins: [ - phoneNumber({ - sendOTP: async ({ phoneNumber, code }) => { - // Implement sending OTP code via SMS - console.log("Send OTP in auth.ts", phoneNumber, code); - await sendOtp(phoneNumber, code); - }, - }), - ], -}); diff --git a/lib/db.ts b/lib/db.ts deleted file mode 100644 index db5f7ff..0000000 --- a/lib/db.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PrismaClient } from "@prisma/client"; - -const prismaClientSingleton = () => { - return new PrismaClient(); -}; - -type PrismaClientSingleton = ReturnType; - -const globalForPrisma = globalThis as unknown as { - prisma: PrismaClientSingleton | undefined; -}; - -const prisma = globalForPrisma.prisma ?? prismaClientSingleton(); - -export default prisma; - -if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; diff --git a/lib/types/user.ts b/lib/types/user.ts new file mode 100644 index 0000000..41de3f4 --- /dev/null +++ b/lib/types/user.ts @@ -0,0 +1,38 @@ +import type { ISODateString } from "next-auth"; + +export interface Permission { + id: number; + name: string; + user: User; +} + +export interface TAuthUser { + expiry?: string; + token?: string; + user: User; +} + +export interface User { + id: number; + username: string; + email: string; + user_permissions: Permission[]; + first_name: string; + last_name: string; + is_superuser: boolean; + date_joined: string; + last_login: string; +} + +export interface Session { + user?: { + token?: string; + name?: string | null; + email?: string | null; + image?: string | null; + user?: User & { + expiry?: string; + }; + }; + expires: ISODateString; +} diff --git a/package-lock.json b/package-lock.json index 5a57d72..ac2ed7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@faker-js/faker": "^9.3.0", "@hookform/resolvers": "^3.9.1", - "@prisma/client": "^6.1.0", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-collapsible": "^1.1.1", @@ -24,7 +23,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@tanstack/react-query": "^5.61.4", - "better-auth": "^1.1.13", + "axios": "^1.8.4", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", @@ -34,12 +33,12 @@ "moment": "^2.30.1", "motion": "^11.15.0", "next": "15.1.2", + "next-auth": "^4.24.11", "next-themes": "^0.4.3", "nextjs-toploader": "^3.7.15", - "prisma": "^6.1.0", "react": "19.0.0", "react-aria-components": "^1.5.0", - "react-day-picker": "^8.10.1", + "react-day-picker": "^9.6.3", "react-dom": "19.0.0", "react-hook-form": "^7.53.2", "react-phone-number-input": "^3.4.9", @@ -63,7 +62,6 @@ }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -72,22 +70,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@better-auth/utils": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.3.tgz", - "integrity": "sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==", + "node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", "dependencies": { - "uncrypto": "^0.1.3" + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@better-fetch/fetch": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.12.tgz", - "integrity": "sha512-B3bfloI/2UBQWIATRN6qmlORrvx3Mp0kkNjmXLv0b+DtbtR+pP4/I5kQA/rDUv+OReLywCCldf6co4LdDmh8JA==" - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -96,6 +92,11 @@ "node": ">=12" } }, + "node_modules/@date-fns/tz": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.2.0.tgz", + "integrity": "sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "dev": true, @@ -290,10 +291,6 @@ "tslib": "2" } }, - "node_modules/@hexagon/base64": { - "version": "1.1.28", - "license": "MIT" - }, "node_modules/@hookform/resolvers": { "version": "3.9.1", "license": "MIT", @@ -456,7 +453,6 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -472,7 +468,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -485,7 +480,6 @@ }, "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -494,7 +488,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -502,7 +495,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -510,22 +502,17 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@levischuck/tiny-cbor": { - "version": "0.2.2", - "license": "MIT" - }, "node_modules/@next/env": { "version": "15.1.2", "license": "MIT" @@ -682,26 +669,8 @@ "node": ">= 10" } }, - "node_modules/@noble/ciphers": { - "version": "0.6.0", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.6.1", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -713,7 +682,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -721,7 +689,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -739,114 +706,22 @@ "node": ">=12.4.0" } }, - "node_modules/@peculiar/asn1-android": { - "version": "2.3.15", - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-ecc": { - "version": "2.3.15", - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "@peculiar/asn1-x509": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-rsa": { - "version": "2.3.15", - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "@peculiar/asn1-x509": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.3.15", - "license": "MIT", - "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.3.15", - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" + "node_modules/@panva/hkdf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", + "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "funding": { + "url": "https://github.com/sponsors/panva" } }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "dev": true, "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, - "node_modules/@prisma/client": { - "version": "6.1.0", - "hasInstallScript": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/debug": { - "version": "6.1.0", - "license": "Apache-2.0" - }, - "node_modules/@prisma/engines": { - "version": "6.1.0", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.1.0", - "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "@prisma/fetch-engine": "6.1.0", - "@prisma/get-platform": "6.1.0" - } - }, - "node_modules/@prisma/engines-version": { - "version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "license": "Apache-2.0" - }, - "node_modules/@prisma/fetch-engine": { - "version": "6.1.0", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.1.0", - "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959", - "@prisma/get-platform": "6.1.0" - } - }, - "node_modules/@prisma/get-platform": { - "version": "6.1.0", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "6.1.0" - } - }, "node_modules/@radix-ui/number": { "version": "1.1.0", "license": "MIT" @@ -3121,27 +2996,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@simplewebauthn/browser": { - "version": "13.0.0", - "license": "MIT" - }, - "node_modules/@simplewebauthn/server": { - "version": "13.0.0", - "license": "MIT", - "dependencies": { - "@hexagon/base64": "^1.1.27", - "@levischuck/tiny-cbor": "^0.2.2", - "@peculiar/asn1-android": "^2.3.10", - "@peculiar/asn1-ecc": "^2.3.8", - "@peculiar/asn1-rsa": "^2.3.8", - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "cross-fetch": "^4.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@swc/counter": { "version": "0.1.3", "license": "Apache-2.0" @@ -3177,22 +3031,22 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.11", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/estree": { @@ -3212,7 +3066,7 @@ }, "node_modules/@types/node": { "version": "22.10.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -3220,7 +3074,7 @@ }, "node_modules/@types/react": { "version": "19.0.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -3228,7 +3082,7 @@ }, "node_modules/@types/react-dom": { "version": "19.0.2", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -3459,7 +3313,7 @@ }, "node_modules/acorn": { "version": "8.14.0", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3478,7 +3332,7 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -3504,7 +3358,6 @@ }, "node_modules/ansi-regex": { "version": "6.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3515,7 +3368,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3529,12 +3381,10 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -3546,7 +3396,6 @@ }, "node_modules/arg": { "version": "5.0.2", - "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -3713,23 +3562,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/asn1js": { - "version": "3.0.5", - "license": "BSD-3-Clause", - "dependencies": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/ast-types-flow": { "version": "0.0.8", "dev": true, "license": "MIT" }, + "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/available-typed-arrays": { "version": "1.0.7", "dev": true, @@ -3752,6 +3594,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "dev": true, @@ -3762,43 +3614,10 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "license": "MIT" }, - "node_modules/better-auth": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.1.13.tgz", - "integrity": "sha512-Tt4QYGFKuAFTjJx6RyXzC50KNyh96/QeVT2QxJRnXiEmp6wGEGmua9iRb5XL3bSnBu8oepAE7xlLF/AvfkEZig==", - "dependencies": { - "@better-auth/utils": "0.2.3", - "@better-fetch/fetch": "1.1.12", - "@noble/ciphers": "^0.6.0", - "@noble/hashes": "^1.6.1", - "@simplewebauthn/browser": "^13.0.0", - "@simplewebauthn/server": "^13.0.0", - "better-call": "0.3.3", - "defu": "^6.1.4", - "jose": "^5.9.6", - "kysely": "^0.27.4", - "nanostores": "^0.11.3", - "uncrypto": "^0.1.3", - "zod": "^3.24.1" - } - }, - "node_modules/better-call": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/better-call/-/better-call-0.3.3.tgz", - "integrity": "sha512-N4lDVm0NGmFfDJ0XMQ4O83Zm/3dPlvIQdxvwvgSLSkjFX5PM4GUYSVAuxNzXN27QZMHDkrJTWUqxBrm4tPC3eA==", - "dependencies": { - "@better-fetch/fetch": "^1.1.4", - "rou3": "^0.5.1", - "uncrypto": "^0.1.3", - "zod": "^3.24.1" - } - }, "node_modules/binary-extensions": { "version": "2.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3818,7 +3637,6 @@ }, "node_modules/braces": { "version": "3.0.3", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -3855,7 +3673,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3890,7 +3707,6 @@ }, "node_modules/camelcase-css": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -3931,7 +3747,6 @@ }, "node_modules/chokidar": { "version": "3.6.0", - "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -3954,7 +3769,6 @@ }, "node_modules/chokidar/node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -4016,7 +3830,6 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4027,7 +3840,6 @@ }, "node_modules/color-name": { "version": "1.1.4", - "devOptional": true, "license": "MIT" }, "node_modules/color-string": { @@ -4039,9 +3851,19 @@ "simple-swizzle": "^0.2.2" } }, + "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", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -4052,25 +3874,25 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/country-flag-icons": { "version": "1.5.13", "license": "MIT" }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, + "devOptional": true, "license": "MIT" }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4083,7 +3905,6 @@ }, "node_modules/cssesc": { "version": "3.0.0", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -4094,7 +3915,7 @@ }, "node_modules/csstype": { "version": "3.1.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -4158,6 +3979,11 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==" + }, "node_modules/debug": { "version": "4.4.0", "dev": true, @@ -4215,9 +4041,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/defu": { - "version": "6.1.4", - "license": "MIT" + "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/detect-libc": { "version": "2.0.3", @@ -4233,12 +4063,11 @@ }, "node_modules/didyoumean": { "version": "1.2.2", - "dev": true, "license": "Apache-2.0" }, "node_modules/diff": { "version": "4.0.2", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -4246,7 +4075,6 @@ }, "node_modules/dlv": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/doctrine": { @@ -4262,7 +4090,6 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -4275,12 +4102,10 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", - "dev": true, "license": "MIT" }, "node_modules/enhanced-resolve": { @@ -4357,7 +4182,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4365,7 +4189,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4399,7 +4222,6 @@ }, "node_modules/es-object-atoms": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4409,13 +4231,14 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "dev": true, - "license": "MIT", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -4874,7 +4697,6 @@ }, "node_modules/fast-glob": { "version": "3.3.2", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4889,7 +4711,6 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -4910,7 +4731,6 @@ }, "node_modules/fastq": { "version": "1.18.0", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -4929,7 +4749,6 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -4970,6 +4789,25 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "dev": true, @@ -4980,7 +4818,6 @@ }, "node_modules/foreground-child": { "version": "3.3.0", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", @@ -4993,6 +4830,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/framer-motion": { "version": "11.15.0", "license": "MIT", @@ -5020,7 +4871,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5055,7 +4905,6 @@ }, "node_modules/get-intrinsic": { "version": "1.2.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -5112,7 +4961,6 @@ }, "node_modules/glob": { "version": "10.4.5", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -5131,7 +4979,6 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -5142,7 +4989,6 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.5", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -5156,7 +5002,6 @@ }, "node_modules/glob/node_modules/minimatch/node_modules/brace-expansion": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -5190,7 +5035,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5255,7 +5099,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5266,7 +5109,6 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -5280,7 +5122,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5413,7 +5254,6 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -5469,7 +5309,6 @@ }, "node_modules/is-core-module": { "version": "2.16.1", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5514,7 +5353,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5536,7 +5374,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5558,7 +5395,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -5580,7 +5416,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -5735,7 +5570,6 @@ }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, "license": "ISC" }, "node_modules/iterator.prototype": { @@ -5756,7 +5590,6 @@ }, "node_modules/jackspeak": { "version": "3.4.3", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -5770,15 +5603,15 @@ }, "node_modules/jiti": { "version": "1.21.7", - "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, "node_modules/jose": { - "version": "5.9.6", - "license": "MIT", + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "funding": { "url": "https://github.com/sponsors/panva" } @@ -5865,13 +5698,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kysely": { - "version": "0.27.5", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/language-subtag-registry": { "version": "0.3.23", "dev": true, @@ -5906,7 +5732,6 @@ }, "node_modules/lilconfig": { "version": "3.1.3", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -5917,7 +5742,6 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { @@ -5951,7 +5775,6 @@ }, "node_modules/lru-cache": { "version": "10.4.3", - "dev": true, "license": "ISC" }, "node_modules/lucide-react": { @@ -5963,12 +5786,11 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/math-intrinsics": { "version": "1.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5976,7 +5798,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -5984,7 +5805,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -5994,6 +5814,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "dev": true, @@ -6015,7 +5854,6 @@ }, "node_modules/minipass": { "version": "7.1.2", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -6067,7 +5905,6 @@ }, "node_modules/mz": { "version": "2.7.0", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -6091,20 +5928,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/nanostores": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.3.tgz", - "integrity": "sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -6162,6 +5985,37 @@ } } }, + "node_modules/next-auth": { + "version": "4.24.11", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz", + "integrity": "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.7.0", + "jose": "^4.15.5", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "@auth/core": "0.34.2", + "next": "^12.2.5 || ^13 || ^14 || ^15", + "nodemailer": "^6.6.5", + "react": "^17.0.2 || ^18 || ^19", + "react-dom": "^17.0.2 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@auth/core": { + "optional": true + }, + "nodemailer": { + "optional": true + } + } + }, "node_modules/next-themes": { "version": "0.4.4", "license": "MIT", @@ -6212,27 +6066,8 @@ "react-dom": ">= 16.0.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/normalize-path": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6242,6 +6077,11 @@ "version": "0.2.0", "license": "MIT" }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, "node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -6251,7 +6091,6 @@ }, "node_modules/object-hash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -6355,6 +6194,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-token-hash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.0.tgz", + "integrity": "sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, + "node_modules/openid-client": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", + "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", + "dependencies": { + "jose": "^4.15.9", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/openid-client/node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/optionator": { "version": "0.9.4", "dev": true, @@ -6401,7 +6281,6 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -6425,7 +6304,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6433,12 +6311,10 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -6457,7 +6333,6 @@ }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -6468,7 +6343,6 @@ }, "node_modules/pify": { "version": "2.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6476,7 +6350,6 @@ }, "node_modules/pirates": { "version": "4.0.6", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -6492,7 +6365,6 @@ }, "node_modules/postcss": { "version": "8.4.49", - "dev": true, "funding": [ { "type": "opencollective", @@ -6519,7 +6391,6 @@ }, "node_modules/postcss-import": { "version": "15.1.0", - "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -6535,7 +6406,6 @@ }, "node_modules/postcss-js": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -6553,7 +6423,6 @@ }, "node_modules/postcss-load-config": { "version": "4.0.2", - "dev": true, "funding": [ { "type": "opencollective", @@ -6587,7 +6456,6 @@ }, "node_modules/postcss-nested": { "version": "6.2.0", - "dev": true, "funding": [ { "type": "opencollective", @@ -6611,7 +6479,6 @@ }, "node_modules/postcss-selector-parser": { "version": "6.1.2", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -6623,9 +6490,28 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "dev": true, "license": "MIT" }, + "node_modules/preact": { + "version": "10.26.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.4.tgz", + "integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -6634,22 +6520,10 @@ "node": ">= 0.8.0" } }, - "node_modules/prisma": { - "version": "6.1.0", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/engines": "6.1.0" - }, - "bin": { - "prisma": "build/index.js" - }, - "engines": { - "node": ">=18.18" - }, - "optionalDependencies": { - "fsevents": "2.3.3" - } + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" }, "node_modules/prop-types": { "version": "15.8.1", @@ -6660,6 +6534,11 @@ "react-is": "^16.13.1" } }, + "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", "dev": true, @@ -6668,23 +6547,8 @@ "node": ">=6" } }, - "node_modules/pvtsutils": { - "version": "1.3.6", - "license": "MIT", - "dependencies": { - "tslib": "^2.8.1" - } - }, - "node_modules/pvutils": { - "version": "1.1.3", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -6800,15 +6664,23 @@ } }, "node_modules/react-day-picker": { - "version": "8.10.1", - "license": "MIT", + "version": "9.6.3", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.6.3.tgz", + "integrity": "sha512-rDqCSKAl5MLX0z1fLkYcBenQK4ANlYaAhUR0ruVSVAhAa7/ZmKQqgDpXPoS7bYEkgBRH06LO1qNFP1Ki8uiZpw==", + "dependencies": { + "@date-fns/tz": "^1.2.0", + "date-fns": "^4.1.0", + "date-fns-jalali": "^4.1.0-0" + }, + "engines": { + "node": ">=18" + }, "funding": { "type": "individual", "url": "https://github.com/sponsors/gpbl" }, "peerDependencies": { - "date-fns": "^2.28.0 || ^3.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": ">=16.8.0" } }, "node_modules/react-dom": { @@ -6953,7 +6825,6 @@ }, "node_modules/read-cache": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -6961,7 +6832,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -6991,6 +6861,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", "dev": true, @@ -7010,7 +6885,6 @@ }, "node_modules/resolve": { "version": "1.22.10", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -7045,21 +6919,14 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rou3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.5.1.tgz", - "integrity": "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==" - }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -7206,7 +7073,6 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -7217,7 +7083,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7293,7 +7158,6 @@ }, "node_modules/signal-exit": { "version": "4.1.0", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -7338,7 +7202,6 @@ }, "node_modules/string-width": { "version": "5.1.2", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -7355,7 +7218,6 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -7368,12 +7230,10 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -7384,7 +7244,6 @@ }, "node_modules/string-width-cjs/node_modules/strip-ansi/node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7392,7 +7251,6 @@ }, "node_modules/string-width/node_modules/strip-ansi": { "version": "7.1.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -7406,7 +7264,6 @@ }, "node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { "version": "6.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7518,7 +7375,6 @@ }, "node_modules/strip-ansi": { "version": "7.1.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -7533,7 +7389,6 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -7544,7 +7399,6 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7592,7 +7446,6 @@ }, "node_modules/sucrase": { "version": "3.35.0", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -7624,7 +7477,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7643,7 +7495,6 @@ }, "node_modules/tailwindcss": { "version": "3.4.17", - "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -7694,7 +7545,6 @@ }, "node_modules/thenify": { "version": "3.3.1", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -7702,7 +7552,6 @@ }, "node_modules/thenify-all": { "version": "1.6.0", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -7713,7 +7562,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -7722,10 +7570,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, "node_modules/ts-api-utils": { "version": "1.4.3", "dev": true, @@ -7739,12 +7583,11 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "dev": true, "license": "Apache-2.0" }, "node_modules/ts-node": { "version": "10.9.2", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -7786,7 +7629,7 @@ }, "node_modules/ts-node/node_modules/arg": { "version": "4.1.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tsconfig-paths": { @@ -7887,7 +7730,7 @@ }, "node_modules/typescript": { "version": "5.7.2", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7914,14 +7757,9 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uncrypto": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", - "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" - }, "node_modules/undici-types": { "version": "6.20.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/uri-js": { @@ -7980,12 +7818,19 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, "license": "MIT" }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/vaul": { @@ -7999,21 +7844,8 @@ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -8115,7 +7947,6 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -8132,7 +7963,6 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -8148,7 +7978,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -8161,12 +7990,10 @@ }, "node_modules/wrap-ansi-cjs/node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -8177,7 +8004,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi/node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8185,7 +8011,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8196,7 +8021,6 @@ }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "7.1.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -8210,7 +8034,6 @@ }, "node_modules/wrap-ansi/node_modules/strip-ansi/node_modules/ansi-regex": { "version": "6.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8219,9 +8042,13 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yaml": { "version": "2.6.1", - "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -8232,7 +8059,7 @@ }, "node_modules/yn": { "version": "3.1.1", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index dc93028..b48710e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "dependencies": { "@faker-js/faker": "^9.3.0", "@hookform/resolvers": "^3.9.1", - "@prisma/client": "^6.1.0", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-collapsible": "^1.1.1", @@ -31,7 +30,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", "@tanstack/react-query": "^5.61.4", - "better-auth": "^1.1.13", + "axios": "^1.8.4", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", @@ -41,12 +40,12 @@ "moment": "^2.30.1", "motion": "^11.15.0", "next": "15.1.2", + "next-auth": "^4.24.11", "next-themes": "^0.4.3", "nextjs-toploader": "^3.7.15", - "prisma": "^6.1.0", "react": "19.0.0", "react-aria-components": "^1.5.0", - "react-day-picker": "^8.10.1", + "react-day-picker": "^9.6.3", "react-dom": "19.0.0", "react-hook-form": "^7.53.2", "react-phone-number-input": "^3.4.9", @@ -68,4 +67,4 @@ "typescript": "^5.7.2" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} \ No newline at end of file +} diff --git a/queries/atoll.ts b/queries/atoll.ts deleted file mode 100644 index bc6cea3..0000000 --- a/queries/atoll.ts +++ /dev/null @@ -1,10 +0,0 @@ -"use server"; - -import type { Atoll, DataResponse } from "@/lib/backend-types"; - -export async function getAtollsWithIslands(): Promise> { - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/atolls`, - ); - return response.json(); -} diff --git a/queries/authentication.ts b/queries/authentication.ts new file mode 100644 index 0000000..ac18613 --- /dev/null +++ b/queries/authentication.ts @@ -0,0 +1,48 @@ +"use server"; +import type { TAuthUser } from "@/lib/types/user"; +import axiosInstance from "@/utils/axiosInstance"; + +export async function login({ + password, + username, +}: { + username: string; + password: string; +}): Promise { + const response = await axiosInstance + .post("/auth/login/", { + username: username, + password: password, + }) + .then((res) => { + console.log(res); + return res.data; // Return the data from the response + }) + .catch((err) => { + console.log(err.response); + throw err; // Throw the error to maintain the Promise rejection + }); + + return response; +} + +export async function logout({ token }: { token: string }) { + const response = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/auth/logout/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Token ${token}`, // Include the token for authentication + }, + }, + ); + + if (response.status !== 204) { + throw new Error("Failed to log out from the backend"); + } + console.log("logout res in backend", response); + + // Since the API endpoint returns 204 No Content on success, we don't need to parse JSON + return null; // Return null to indicate a successful logout with no content +} diff --git a/utils/axiosInstance.ts b/utils/axiosInstance.ts new file mode 100644 index 0000000..68cef36 --- /dev/null +++ b/utils/axiosInstance.ts @@ -0,0 +1,13 @@ +import axios from "axios"; + +axios.defaults.xsrfCookieName = "csrftoken"; +axios.defaults.xsrfHeaderName = "X-CSRFToken"; + +const axiosInstance = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL, + validateStatus: (status) => { + return status < 500; // Resolve only if the status code is less than 500 + }, +}); + +export default axiosInstance;