mirror of
				https://github.com/i701/sarlink-portal.git
				synced 2025-11-04 06:26:59 +00:00 
			
		
		
		
	TEMPORARY FIX TO TEST BUILD
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m15s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m15s
				
			This commit is contained in:
		@@ -1,6 +1,4 @@
 | 
			
		||||
import SignUpForm from "@/components/auth/signup-form";
 | 
			
		||||
import type { ApiResponse, Atoll, Island } from "@/lib/backend-types";
 | 
			
		||||
import { getAtolls } from "@/queries/islands";
 | 
			
		||||
import Image from "next/image";
 | 
			
		||||
import { redirect } from "next/navigation";
 | 
			
		||||
 | 
			
		||||
@@ -9,18 +7,23 @@ export default async function SignupPage({
 | 
			
		||||
}: {
 | 
			
		||||
	searchParams: Promise<{ phone_number: string }>;
 | 
			
		||||
}) {
 | 
			
		||||
 | 
			
		||||
	const phone_number = (await searchParams).phone_number;
 | 
			
		||||
	console.log({ phone_number })
 | 
			
		||||
	console.log({ phone_number });
 | 
			
		||||
	if (!phone_number) {
 | 
			
		||||
		return redirect("/auth/login");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<div className="dark:bg-black w-full h-screen flex items-center justify-center font-sans">
 | 
			
		||||
			<div className="flex flex-col items-center justify-center w-full h-full ">
 | 
			
		||||
				<Image priority alt="Sar Link Logo" src="/logo.png" width={100} height={100} style={{ width: "auto", height: "auto" }} />
 | 
			
		||||
				<Image
 | 
			
		||||
					priority
 | 
			
		||||
					alt="Sar Link Logo"
 | 
			
		||||
					src="/logo.png"
 | 
			
		||||
					width={100}
 | 
			
		||||
					height={100}
 | 
			
		||||
					style={{ width: "auto", height: "auto" }}
 | 
			
		||||
				/>
 | 
			
		||||
				<div className="mt-4 flex flex-col items-center justify-center">
 | 
			
		||||
					<h4 className="font-bold text-xl text-gray-600">SAR Link Portal</h4>
 | 
			
		||||
					<p className="text-gray-500">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,8 @@ import { getPayment } from "@/actions/payment";
 | 
			
		||||
import { authOptions } from "@/app/auth";
 | 
			
		||||
import CancelPaymentButton from "@/components/billing/cancel-payment-button";
 | 
			
		||||
import DevicesToPay from "@/components/devices-to-pay";
 | 
			
		||||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
import { tryCatch } from "@/utils/tryCatch";
 | 
			
		||||
import { Trash2 } from "lucide-react";
 | 
			
		||||
import { getServerSession } from "next-auth";
 | 
			
		||||
export default async function PaymentPage({
 | 
			
		||||
	params,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,3 @@
 | 
			
		||||
import InputReadOnly from "@/components/input-read-only";
 | 
			
		||||
import { Badge } from "@/components/ui/badge";
 | 
			
		||||
import UserRejectDialog from "@/components/user/user-reject-dialog";
 | 
			
		||||
import { UserVerifyDialog } from "@/components/user/user-verify-dialog";
 | 
			
		||||
import { getNationalPerson } from "@/lib/person";
 | 
			
		||||
 | 
			
		||||
import Image from "next/image";
 | 
			
		||||
 | 
			
		||||
export default async function VerifyUserPage({
 | 
			
		||||
	params,
 | 
			
		||||
}: {
 | 
			
		||||
@@ -14,6 +6,7 @@ export default async function VerifyUserPage({
 | 
			
		||||
	}>;
 | 
			
		||||
}) {
 | 
			
		||||
	const userId = (await params).userId;
 | 
			
		||||
	console.log("userId", userId);
 | 
			
		||||
	// const dbUser = await prisma.user.findUnique({
 | 
			
		||||
	//   where: {
 | 
			
		||||
	//     id: userId,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import { Rejectuser } from "@/actions/user-actions";
 | 
			
		||||
import Filter from "@/components/filter";
 | 
			
		||||
import Search from "@/components/search";
 | 
			
		||||
import { UsersTable } from "@/components/user-table";
 | 
			
		||||
@@ -9,8 +8,7 @@ import {
 | 
			
		||||
	Hourglass,
 | 
			
		||||
	Minus,
 | 
			
		||||
} from "lucide-react";
 | 
			
		||||
import { redirect } from "next/navigation";
 | 
			
		||||
import React, { Suspense } from "react";
 | 
			
		||||
import { Suspense } from "react";
 | 
			
		||||
 | 
			
		||||
const sortfilterOptions = [
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,5 @@
 | 
			
		||||
import { blockDevice } from "@/actions/omada-actions";
 | 
			
		||||
import { validateApiKey } from "@/lib/utils";
 | 
			
		||||
import { addDays, addMonths, isAfter, isWithinInterval } from "date-fns";
 | 
			
		||||
 | 
			
		||||
const lastRunTime = new Date();
 | 
			
		||||
 | 
			
		||||
export async function GET(request: Request) {
 | 
			
		||||
	console.log(request.url);
 | 
			
		||||
	return Response.json({ message: "Request received" });
 | 
			
		||||
	// 	try {
 | 
			
		||||
	// 		// Validate API key before proceeding
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								app/next-auth.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								app/next-auth.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,7 @@
 | 
			
		||||
import NextAuth, { DefaultSession, type User } from "next-auth";
 | 
			
		||||
import { Session } from "next-auth";
 | 
			
		||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
			
		||||
// @ts-expect-error importing unused types are required here
 | 
			
		||||
import NextAuth, { DefaultSession, type User, Session } from "next-auth";
 | 
			
		||||
/* eslint-enable @typescript-eslint/no-unused-vars */
 | 
			
		||||
declare module "next-auth" {
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,18 @@
 | 
			
		||||
import {
 | 
			
		||||
	Table,
 | 
			
		||||
	TableBody,
 | 
			
		||||
	TableCaption,
 | 
			
		||||
	TableCell,
 | 
			
		||||
	TableFooter,
 | 
			
		||||
	TableHead,
 | 
			
		||||
	TableHeader,
 | 
			
		||||
	TableRow,
 | 
			
		||||
} from "@/components/ui/table";
 | 
			
		||||
import { headers } from "next/headers";
 | 
			
		||||
import Link from "next/link";
 | 
			
		||||
import BlockDeviceDialog from "../block-device-dialog";
 | 
			
		||||
import DeviceCard from "../device-card";
 | 
			
		||||
import Pagination from "../pagination";
 | 
			
		||||
// import {
 | 
			
		||||
// 	Table,
 | 
			
		||||
// 	TableBody,
 | 
			
		||||
// 	TableCaption,
 | 
			
		||||
// 	TableCell,
 | 
			
		||||
// 	TableFooter,
 | 
			
		||||
// 	TableHead,
 | 
			
		||||
// 	TableHeader,
 | 
			
		||||
// 	TableRow,
 | 
			
		||||
// } from "@/components/ui/table";
 | 
			
		||||
// import { headers } from "next/headers";
 | 
			
		||||
// import Link from "next/link";
 | 
			
		||||
// import BlockDeviceDialog from "../block-device-dialog";
 | 
			
		||||
// import DeviceCard from "../device-card";
 | 
			
		||||
// import Pagination from "../pagination";
 | 
			
		||||
 | 
			
		||||
export async function AdminDevicesTable({
 | 
			
		||||
	searchParams,
 | 
			
		||||
@@ -25,12 +25,14 @@ export async function AdminDevicesTable({
 | 
			
		||||
	}>;
 | 
			
		||||
	parentalControl?: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
	console.log(parentalControl);
 | 
			
		||||
	// 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 query = (await searchParams)?.query || "";
 | 
			
		||||
	const page = (await searchParams)?.page;
 | 
			
		||||
	console.log(query, page);
 | 
			
		||||
	// const sortBy = (await searchParams)?.sortBy || "asc";
 | 
			
		||||
	// const totalDevices = await prisma.device.count({
 | 
			
		||||
	// 	where: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,17 @@
 | 
			
		||||
import Pagination from "@/components/pagination";
 | 
			
		||||
import { Badge } from "@/components/ui/badge";
 | 
			
		||||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import {
 | 
			
		||||
	Table,
 | 
			
		||||
	TableBody,
 | 
			
		||||
	TableCaption,
 | 
			
		||||
	TableCell,
 | 
			
		||||
	TableFooter,
 | 
			
		||||
	TableHead,
 | 
			
		||||
	TableHeader,
 | 
			
		||||
	TableRow,
 | 
			
		||||
} from "@/components/ui/table";
 | 
			
		||||
import Link from "next/link";
 | 
			
		||||
// import Pagination from "@/components/pagination";
 | 
			
		||||
// import { Badge } from "@/components/ui/badge";
 | 
			
		||||
// import { Button } from "@/components/ui/button";
 | 
			
		||||
// import {
 | 
			
		||||
// 	Table,
 | 
			
		||||
// 	TableBody,
 | 
			
		||||
// 	TableCaption,
 | 
			
		||||
// 	TableCell,
 | 
			
		||||
// 	TableFooter,
 | 
			
		||||
// 	TableHead,
 | 
			
		||||
// 	TableHeader,
 | 
			
		||||
// 	TableRow,
 | 
			
		||||
// } from "@/components/ui/table";
 | 
			
		||||
// import Link from "next/link";
 | 
			
		||||
 | 
			
		||||
export async function UsersPaymentsTable({
 | 
			
		||||
	searchParams,
 | 
			
		||||
@@ -24,8 +24,9 @@ export async function UsersPaymentsTable({
 | 
			
		||||
	}>;
 | 
			
		||||
}) {
 | 
			
		||||
	const query = (await searchParams)?.query || "";
 | 
			
		||||
	const page = (await searchParams)?.page;
 | 
			
		||||
	const sortBy = (await searchParams)?.sortBy || "asc";
 | 
			
		||||
	console.log(query);
 | 
			
		||||
	// const page = (await searchParams)?.page;
 | 
			
		||||
	// const sortBy = (await searchParams)?.sortBy || "asc";
 | 
			
		||||
	// const totalPayments = await prisma.payment.count({
 | 
			
		||||
	//   where: {
 | 
			
		||||
	//     OR: [
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,11 @@ import {
 | 
			
		||||
} from "@/components/ui/popover";
 | 
			
		||||
import { Loader2, User as UserIcon } from "lucide-react";
 | 
			
		||||
import { signOut, useSession } from "next-auth/react";
 | 
			
		||||
import { useRouter } from "next/navigation";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
 | 
			
		||||
export function AccountPopover() {
 | 
			
		||||
	const session = useSession();
 | 
			
		||||
	const [loading, setLoading] = useState(false);
 | 
			
		||||
	const router = useRouter();
 | 
			
		||||
 | 
			
		||||
	if (session.status === "loading") {
 | 
			
		||||
		<Button variant={"outline"} disabled>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ import { getAtolls } from "@/queries/islands";
 | 
			
		||||
import { keepPreviousData, useQuery } from "@tanstack/react-query";
 | 
			
		||||
 | 
			
		||||
export default function SignUpForm() {
 | 
			
		||||
	const { data: atolls, isFetching } = useQuery<ApiResponse<Atoll>>({
 | 
			
		||||
	const { data: atolls } = useQuery<ApiResponse<Atoll>>({
 | 
			
		||||
		queryKey: ["ATOLLS"],
 | 
			
		||||
		queryFn: () => getAtolls(),
 | 
			
		||||
		placeholderData: keepPreviousData,
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,8 @@ export default function CancelPaymentButton({
 | 
			
		||||
		<Button
 | 
			
		||||
			onClick={async () => {
 | 
			
		||||
				setLoading(true);
 | 
			
		||||
				const [error, _] = await tryCatch(cancelPayment({ id: paymentId }));
 | 
			
		||||
				const [error, x] = await tryCatch(cancelPayment({ id: paymentId }));
 | 
			
		||||
				console.log(x);
 | 
			
		||||
				if (error) {
 | 
			
		||||
					toast.error(error.message);
 | 
			
		||||
					setLoading(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ import { TableCell, TableRow } from "@/components/ui/table";
 | 
			
		||||
import { deviceCartAtom } from "@/lib/atoms";
 | 
			
		||||
import type { Device } from "@/lib/backend-types";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
import { pl } from "date-fns/locale";
 | 
			
		||||
import { useAtom } from "jotai";
 | 
			
		||||
import { Hourglass } from "lucide-react";
 | 
			
		||||
import Link from "next/link";
 | 
			
		||||
 
 | 
			
		||||
@@ -5,18 +5,16 @@ import DeviceCard from "@/components/device-card";
 | 
			
		||||
import NumberInput from "@/components/number-input";
 | 
			
		||||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import { deviceCartAtom, numberOfMonths } from "@/lib/atoms";
 | 
			
		||||
import type { NewPayment, Payment } from "@/lib/backend-types";
 | 
			
		||||
import type { NewPayment } from "@/lib/backend-types";
 | 
			
		||||
import { tryCatch } from "@/utils/tryCatch";
 | 
			
		||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
 | 
			
		||||
import { CircleDollarSign, Loader2 } from "lucide-react";
 | 
			
		||||
import { useSession } from "next-auth/react";
 | 
			
		||||
import { redirect, usePathname } from "next/navigation";
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
import { toast } from "sonner";
 | 
			
		||||
export default function DevicesForPayment() {
 | 
			
		||||
	const baseAmount = 100;
 | 
			
		||||
	const discountPercentage = 75;
 | 
			
		||||
	const session = useSession();
 | 
			
		||||
	const pathname = usePathname();
 | 
			
		||||
	const devices = useAtomValue(deviceCartAtom);
 | 
			
		||||
	const setDeviceCart = useSetAtom(deviceCartAtom);
 | 
			
		||||
@@ -24,6 +22,7 @@ export default function DevicesForPayment() {
 | 
			
		||||
	const [message, setMessage] = useState("");
 | 
			
		||||
	const [disabled, setDisabled] = useState(false);
 | 
			
		||||
	const [total, setTotal] = useState(0);
 | 
			
		||||
	console.log(total);
 | 
			
		||||
	useEffect(() => {
 | 
			
		||||
		if (months === 7) {
 | 
			
		||||
			setMessage("You will get 1 month free.");
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ export async function DevicesTable({
 | 
			
		||||
	if (error) {
 | 
			
		||||
		return <pre>{JSON.stringify(error, null, 2)}</pre>;
 | 
			
		||||
	}
 | 
			
		||||
	const { meta, links, data } = devices;
 | 
			
		||||
	const { meta, data } = devices;
 | 
			
		||||
	return (
 | 
			
		||||
		<div>
 | 
			
		||||
			{data.length === 0 ? (
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import {
 | 
			
		||||
	TableRow,
 | 
			
		||||
} from "@/components/ui/table";
 | 
			
		||||
import type { Payment } from "@/lib/backend-types";
 | 
			
		||||
import { formatDate } from "@/lib/utils";
 | 
			
		||||
import {
 | 
			
		||||
	BadgeDollarSign,
 | 
			
		||||
	Clipboard,
 | 
			
		||||
@@ -26,6 +25,7 @@ export default function DevicesToPay({
 | 
			
		||||
	payment,
 | 
			
		||||
	user,
 | 
			
		||||
}: { payment?: Payment; user?: User }) {
 | 
			
		||||
	console.log(user);
 | 
			
		||||
	const [verifying, setVerifying] = useState(false);
 | 
			
		||||
 | 
			
		||||
	const devices = payment?.devices;
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@ export async function PaymentsTable({
 | 
			
		||||
			return <pre>{JSON.stringify(error, null, 2)}</pre>;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	const { data, meta, links } = payments;
 | 
			
		||||
	const { data, meta } = payments;
 | 
			
		||||
	return (
 | 
			
		||||
		<div>
 | 
			
		||||
			{data?.length === 0 ? (
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,6 @@ type Categories = {
 | 
			
		||||
}[];
 | 
			
		||||
 | 
			
		||||
export async function AppSidebar({
 | 
			
		||||
	role,
 | 
			
		||||
	...props
 | 
			
		||||
}: React.ComponentProps<typeof Sidebar>) {
 | 
			
		||||
	const categories = [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,71 +1,72 @@
 | 
			
		||||
"use client"
 | 
			
		||||
"use client";
 | 
			
		||||
 | 
			
		||||
import { ChevronLeft, ChevronRight } from "lucide-react"
 | 
			
		||||
import { DayPicker } from "react-day-picker"
 | 
			
		||||
import { ChevronLeft, ChevronRight } from "lucide-react";
 | 
			
		||||
import { DayPicker } from "react-day-picker";
 | 
			
		||||
 | 
			
		||||
import { buttonVariants } from "@/components/ui/button"
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
import { buttonVariants } from "@/components/ui/button";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
 | 
			
		||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>
 | 
			
		||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
 | 
			
		||||
 | 
			
		||||
function Calendar({
 | 
			
		||||
  className,
 | 
			
		||||
  classNames,
 | 
			
		||||
  showOutsideDays = true,
 | 
			
		||||
  ...props
 | 
			
		||||
	className,
 | 
			
		||||
	classNames,
 | 
			
		||||
	showOutsideDays = true,
 | 
			
		||||
	...props
 | 
			
		||||
}: CalendarProps) {
 | 
			
		||||
  return (
 | 
			
		||||
    <DayPicker
 | 
			
		||||
      showOutsideDays={showOutsideDays}
 | 
			
		||||
      className={cn("p-3", className)}
 | 
			
		||||
      classNames={{
 | 
			
		||||
        months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
 | 
			
		||||
        month: "space-y-4",
 | 
			
		||||
        caption: "flex justify-center pt-1 relative items-center",
 | 
			
		||||
        caption_label: "text-sm font-medium",
 | 
			
		||||
        nav: "space-x-1 flex items-center",
 | 
			
		||||
        nav_button: cn(
 | 
			
		||||
          buttonVariants({ variant: "outline" }),
 | 
			
		||||
          "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
 | 
			
		||||
        ),
 | 
			
		||||
        nav_button_previous: "absolute left-1",
 | 
			
		||||
        nav_button_next: "absolute right-1",
 | 
			
		||||
        table: "w-full border-collapse space-y-1",
 | 
			
		||||
        head_row: "flex",
 | 
			
		||||
        head_cell:
 | 
			
		||||
          "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
 | 
			
		||||
        row: "flex w-full mt-2",
 | 
			
		||||
        cell: cn(
 | 
			
		||||
          "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
 | 
			
		||||
          props.mode === "range"
 | 
			
		||||
            ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
 | 
			
		||||
            : "[&:has([aria-selected])]:rounded-md"
 | 
			
		||||
        ),
 | 
			
		||||
        day: cn(
 | 
			
		||||
          buttonVariants({ variant: "ghost" }),
 | 
			
		||||
          "h-8 w-8 p-0 font-normal aria-selected:opacity-100"
 | 
			
		||||
        ),
 | 
			
		||||
        day_range_start: "day-range-start",
 | 
			
		||||
        day_range_end: "day-range-end",
 | 
			
		||||
        day_selected:
 | 
			
		||||
          "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
 | 
			
		||||
        day_today: "bg-accent text-accent-foreground",
 | 
			
		||||
        day_outside:
 | 
			
		||||
          "day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
 | 
			
		||||
        day_disabled: "text-muted-foreground opacity-50",
 | 
			
		||||
        day_range_middle:
 | 
			
		||||
          "aria-selected:bg-accent aria-selected:text-accent-foreground",
 | 
			
		||||
        day_hidden: "invisible",
 | 
			
		||||
        ...classNames,
 | 
			
		||||
      }}
 | 
			
		||||
      components={{
 | 
			
		||||
        IconLeft: () => <ChevronLeft className="h-4 w-4" />,
 | 
			
		||||
        IconRight: () => <ChevronRight className="h-4 w-4" />,
 | 
			
		||||
      }}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
	return (
 | 
			
		||||
		<DayPicker
 | 
			
		||||
			showOutsideDays={showOutsideDays}
 | 
			
		||||
			className={cn("p-3", className)}
 | 
			
		||||
			classNames={{
 | 
			
		||||
				months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
 | 
			
		||||
				month: "space-y-4",
 | 
			
		||||
				caption: "flex justify-center pt-1 relative items-center",
 | 
			
		||||
				caption_label: "text-sm font-medium",
 | 
			
		||||
				nav: "space-x-1 flex items-center",
 | 
			
		||||
				nav_button: cn(
 | 
			
		||||
					buttonVariants({ variant: "outline" }),
 | 
			
		||||
					"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
 | 
			
		||||
				),
 | 
			
		||||
				nav_button_previous: "absolute left-1",
 | 
			
		||||
				nav_button_next: "absolute right-1",
 | 
			
		||||
				table: "w-full border-collapse space-y-1",
 | 
			
		||||
				head_row: "flex",
 | 
			
		||||
				head_cell:
 | 
			
		||||
					"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
 | 
			
		||||
				row: "flex w-full mt-2",
 | 
			
		||||
				cell: cn(
 | 
			
		||||
					"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
 | 
			
		||||
					props.mode === "range"
 | 
			
		||||
						? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
 | 
			
		||||
						: "[&:has([aria-selected])]:rounded-md",
 | 
			
		||||
				),
 | 
			
		||||
				day: cn(
 | 
			
		||||
					buttonVariants({ variant: "ghost" }),
 | 
			
		||||
					"h-8 w-8 p-0 font-normal aria-selected:opacity-100",
 | 
			
		||||
				),
 | 
			
		||||
				day_range_start: "day-range-start",
 | 
			
		||||
				day_range_end: "day-range-end",
 | 
			
		||||
				day_selected:
 | 
			
		||||
					"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
 | 
			
		||||
				day_today: "bg-accent text-accent-foreground",
 | 
			
		||||
				day_outside:
 | 
			
		||||
					"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
 | 
			
		||||
				day_disabled: "text-muted-foreground opacity-50",
 | 
			
		||||
				day_range_middle:
 | 
			
		||||
					"aria-selected:bg-accent aria-selected:text-accent-foreground",
 | 
			
		||||
				day_hidden: "invisible",
 | 
			
		||||
				...classNames,
 | 
			
		||||
			}}
 | 
			
		||||
			components={{
 | 
			
		||||
				// @ts-expect-error this works but types are not correct
 | 
			
		||||
				IconLeft: () => <ChevronLeft className="h-4 w-4" />,
 | 
			
		||||
				IconRight: () => <ChevronRight className="h-4 w-4" />,
 | 
			
		||||
			}}
 | 
			
		||||
			{...props}
 | 
			
		||||
		/>
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
Calendar.displayName = "Calendar"
 | 
			
		||||
Calendar.displayName = "Calendar";
 | 
			
		||||
 | 
			
		||||
export { Calendar }
 | 
			
		||||
export { Calendar };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,17 @@
 | 
			
		||||
import {
 | 
			
		||||
	Table,
 | 
			
		||||
	TableBody,
 | 
			
		||||
	TableCaption,
 | 
			
		||||
	TableCell,
 | 
			
		||||
	TableFooter,
 | 
			
		||||
	TableHead,
 | 
			
		||||
	TableHeader,
 | 
			
		||||
	TableRow,
 | 
			
		||||
} from "@/components/ui/table";
 | 
			
		||||
import Link from "next/link";
 | 
			
		||||
import Pagination from "./pagination";
 | 
			
		||||
import { Badge } from "./ui/badge";
 | 
			
		||||
import { Button } from "./ui/button";
 | 
			
		||||
// import {
 | 
			
		||||
// 	Table,
 | 
			
		||||
// 	TableBody,
 | 
			
		||||
// 	TableCaption,
 | 
			
		||||
// 	TableCell,
 | 
			
		||||
// 	TableFooter,
 | 
			
		||||
// 	TableHead,
 | 
			
		||||
// 	TableHeader,
 | 
			
		||||
// 	TableRow,
 | 
			
		||||
// } from "@/components/ui/table";
 | 
			
		||||
// import Link from "next/link";
 | 
			
		||||
// import Pagination from "./pagination";
 | 
			
		||||
// import { Badge } from "./ui/badge";
 | 
			
		||||
// import { Button } from "./ui/button";
 | 
			
		||||
 | 
			
		||||
export async function UsersTable({
 | 
			
		||||
	searchParams,
 | 
			
		||||
@@ -24,9 +24,10 @@ export async function UsersTable({
 | 
			
		||||
	}>;
 | 
			
		||||
}) {
 | 
			
		||||
	const query = (await searchParams)?.query || "";
 | 
			
		||||
	const page = (await searchParams)?.page;
 | 
			
		||||
	const sortBy = (await searchParams)?.sortBy || "asc";
 | 
			
		||||
	const verified = (await searchParams)?.status || "all";
 | 
			
		||||
	console.log(query);
 | 
			
		||||
	// const page = (await searchParams)?.page;
 | 
			
		||||
	// const sortBy = (await searchParams)?.sortBy || "asc";
 | 
			
		||||
	// const verified = (await searchParams)?.status || "all";
 | 
			
		||||
	// const totalUsers = await prisma.user.count({
 | 
			
		||||
	// 	where: {
 | 
			
		||||
	// 		OR: [
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ export default function AddDeviceDialogForm({ user_id }: { user_id?: string }) {
 | 
			
		||||
			toast.error(error.message || "Something went wrong.");
 | 
			
		||||
			setDisabled(false);
 | 
			
		||||
		} else {
 | 
			
		||||
			console.log(response);
 | 
			
		||||
			setOpen(false);
 | 
			
		||||
			setDisabled(false);
 | 
			
		||||
			toast.success("Device successfully added!");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
"use client"
 | 
			
		||||
"use client";
 | 
			
		||||
 | 
			
		||||
import { Rejectuser } from "@/actions/user-actions"
 | 
			
		||||
import { Button } from "@/components/ui/button"
 | 
			
		||||
import { Rejectuser } from "@/actions/user-actions";
 | 
			
		||||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import {
 | 
			
		||||
	Dialog,
 | 
			
		||||
	DialogContent,
 | 
			
		||||
@@ -10,56 +10,56 @@ import {
 | 
			
		||||
	DialogHeader,
 | 
			
		||||
	DialogTitle,
 | 
			
		||||
	DialogTrigger,
 | 
			
		||||
} from "@/components/ui/dialog"
 | 
			
		||||
import { Label } from "@/components/ui/label"
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
import { zodResolver } from "@hookform/resolvers/zod"
 | 
			
		||||
import type { User } from "@prisma/client"
 | 
			
		||||
import { UserX } from "lucide-react"
 | 
			
		||||
import { useState } from "react"
 | 
			
		||||
import { type SubmitHandler, useForm } from "react-hook-form"
 | 
			
		||||
import { toast } from "sonner"
 | 
			
		||||
import { z } from "zod"
 | 
			
		||||
import { Textarea } from "../ui/textarea"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} from "@/components/ui/dialog";
 | 
			
		||||
import { Label } from "@/components/ui/label";
 | 
			
		||||
import type { User } from "@/lib/types/user";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
import { zodResolver } from "@hookform/resolvers/zod";
 | 
			
		||||
import { UserX } from "lucide-react";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { type SubmitHandler, useForm } from "react-hook-form";
 | 
			
		||||
import { toast } from "sonner";
 | 
			
		||||
import { z } from "zod";
 | 
			
		||||
import { Textarea } from "../ui/textarea";
 | 
			
		||||
 | 
			
		||||
const validationSchema = z.object({
 | 
			
		||||
	reason: z.string().min(5, { message: "Reason is required" }),
 | 
			
		||||
})
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function UserRejectDialog({ user }: { user: User }) {
 | 
			
		||||
	const [disabled, setDisabled] = useState(false)
 | 
			
		||||
	const [open, setOpen] = useState(false)
 | 
			
		||||
	const [disabled, setDisabled] = useState(false);
 | 
			
		||||
	const [open, setOpen] = useState(false);
 | 
			
		||||
	const {
 | 
			
		||||
		register,
 | 
			
		||||
		handleSubmit,
 | 
			
		||||
		formState: { errors },
 | 
			
		||||
	} = useForm<z.infer<typeof validationSchema>>({
 | 
			
		||||
		resolver: zodResolver(validationSchema),
 | 
			
		||||
	})
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const onSubmit: SubmitHandler<z.infer<typeof validationSchema>> = (data) => {
 | 
			
		||||
		setDisabled(true)
 | 
			
		||||
		console.log(data)
 | 
			
		||||
		toast.promise(Rejectuser({
 | 
			
		||||
			userId: user.id,
 | 
			
		||||
			reason: data.reason,
 | 
			
		||||
		}), {
 | 
			
		||||
			loading: "Rejecting...",
 | 
			
		||||
			success: () => {
 | 
			
		||||
				setDisabled(false)
 | 
			
		||||
				setOpen((prev) => !prev)
 | 
			
		||||
				return "Rejected!"
 | 
			
		||||
		setDisabled(true);
 | 
			
		||||
		console.log(data);
 | 
			
		||||
		toast.promise(
 | 
			
		||||
			Rejectuser({
 | 
			
		||||
				userId: String(user.id),
 | 
			
		||||
				reason: data.reason,
 | 
			
		||||
			}),
 | 
			
		||||
			{
 | 
			
		||||
				loading: "Rejecting...",
 | 
			
		||||
				success: () => {
 | 
			
		||||
					setDisabled(false);
 | 
			
		||||
					setOpen((prev) => !prev);
 | 
			
		||||
					return "Rejected!";
 | 
			
		||||
				},
 | 
			
		||||
				error: (error) => {
 | 
			
		||||
					setDisabled(false);
 | 
			
		||||
					return error.message || "Something went wrong";
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			error: (error) => {
 | 
			
		||||
				setDisabled(false)
 | 
			
		||||
				return error.message || "Something went wrong"
 | 
			
		||||
			},
 | 
			
		||||
		})
 | 
			
		||||
		setDisabled(false)
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
		);
 | 
			
		||||
		setDisabled(false);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<Dialog open={open} onOpenChange={setOpen}>
 | 
			
		||||
@@ -71,20 +71,25 @@ export default function UserRejectDialog({ user }: { user: User }) {
 | 
			
		||||
			</DialogTrigger>
 | 
			
		||||
			<DialogContent className="sm:max-w-[425px]">
 | 
			
		||||
				<DialogHeader>
 | 
			
		||||
					<DialogTitle>Are you sure you want to {" "}
 | 
			
		||||
						<span className="text-red-500">reject</span>{" "}
 | 
			
		||||
						this user?</DialogTitle>
 | 
			
		||||
					<DialogTitle>
 | 
			
		||||
						Are you sure you want to{" "}
 | 
			
		||||
						<span className="text-red-500">reject</span> this user?
 | 
			
		||||
					</DialogTitle>
 | 
			
		||||
					<DialogDescription className="py-2">
 | 
			
		||||
						<li>Name: {user.name}</li>
 | 
			
		||||
						<li>
 | 
			
		||||
							Name: {user.first_name} {user.last_name}
 | 
			
		||||
						</li>
 | 
			
		||||
						<li>ID Card: {user.id_card}</li>
 | 
			
		||||
						<li>Address: {user.address}</li>
 | 
			
		||||
						<li>DOB: {new Date(user.dob ?? "").toLocaleDateString("en-US", {
 | 
			
		||||
							month: "short",
 | 
			
		||||
							day: "2-digit",
 | 
			
		||||
							year: "numeric",
 | 
			
		||||
						})}
 | 
			
		||||
						<li>
 | 
			
		||||
							DOB:{" "}
 | 
			
		||||
							{new Date(user.dob ?? "").toLocaleDateString("en-US", {
 | 
			
		||||
								month: "short",
 | 
			
		||||
								day: "2-digit",
 | 
			
		||||
								year: "numeric",
 | 
			
		||||
							})}
 | 
			
		||||
						</li>
 | 
			
		||||
						<li>Phone Number: {user.phoneNumber}</li>
 | 
			
		||||
						<li>Phone Number: {user.mobile}</li>
 | 
			
		||||
					</DialogDescription>
 | 
			
		||||
				</DialogHeader>
 | 
			
		||||
				<form onSubmit={handleSubmit(onSubmit)}>
 | 
			
		||||
@@ -93,7 +98,15 @@ export default function UserRejectDialog({ user }: { user: User }) {
 | 
			
		||||
							<Label htmlFor="reason" className="text-right">
 | 
			
		||||
								Rejection details
 | 
			
		||||
							</Label>
 | 
			
		||||
							<Textarea rows={10} {...register("reason")} id="reason" className={cn("col-span-5", errors.reason && "ring-2 ring-red-500")} />
 | 
			
		||||
							<Textarea
 | 
			
		||||
								rows={10}
 | 
			
		||||
								{...register("reason")}
 | 
			
		||||
								id="reason"
 | 
			
		||||
								className={cn(
 | 
			
		||||
									"col-span-5",
 | 
			
		||||
									errors.reason && "ring-2 ring-red-500",
 | 
			
		||||
								)}
 | 
			
		||||
							/>
 | 
			
		||||
							<span className="text-sm text-red-500">
 | 
			
		||||
								{errors.reason?.message}
 | 
			
		||||
							</span>
 | 
			
		||||
@@ -107,5 +120,5 @@ export default function UserRejectDialog({ user }: { user: User }) {
 | 
			
		||||
				</form>
 | 
			
		||||
			</DialogContent>
 | 
			
		||||
		</Dialog>
 | 
			
		||||
	)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
@@ -12,7 +12,7 @@ import {
 | 
			
		||||
	AlertDialogTrigger,
 | 
			
		||||
} from "@/components/ui/alert-dialog";
 | 
			
		||||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import type { User } from "@prisma/client";
 | 
			
		||||
import type { User } from "@/lib/types/user";
 | 
			
		||||
import { Check, CheckCheck } from "lucide-react";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import { toast } from "sonner";
 | 
			
		||||
@@ -37,15 +37,20 @@ export function UserVerifyDialog({ user }: { user: User }) {
 | 
			
		||||
					<AlertDialogDescription>
 | 
			
		||||
						Are you sure you want to verify the following user?
 | 
			
		||||
						<span className="inline-block my-4">
 | 
			
		||||
							<li>Name: {user.name}</li>
 | 
			
		||||
							<li>
 | 
			
		||||
								Name: {user.first_name} {user.last_name}
 | 
			
		||||
							</li>
 | 
			
		||||
							<li>ID Card: {user.id_card}</li>
 | 
			
		||||
							<li>Address: {user.address}</li>
 | 
			
		||||
							<li>DOB: {new Date(user.dob ?? "").toLocaleDateString("en-US", {
 | 
			
		||||
								month: "short",
 | 
			
		||||
								day: "2-digit",
 | 
			
		||||
								year: "numeric",
 | 
			
		||||
							})}</li>
 | 
			
		||||
							<li>Phone Number: {user.phoneNumber}</li>
 | 
			
		||||
							<li>
 | 
			
		||||
								DOB:{" "}
 | 
			
		||||
								{new Date(user.dob ?? "").toLocaleDateString("en-US", {
 | 
			
		||||
									month: "short",
 | 
			
		||||
									day: "2-digit",
 | 
			
		||||
									year: "numeric",
 | 
			
		||||
								})}
 | 
			
		||||
							</li>
 | 
			
		||||
							<li>Phone Number: {user.mobile}</li>
 | 
			
		||||
						</span>
 | 
			
		||||
					</AlertDialogDescription>
 | 
			
		||||
				</AlertDialogHeader>
 | 
			
		||||
@@ -55,7 +60,7 @@ export function UserVerifyDialog({ user }: { user: User }) {
 | 
			
		||||
						disabled={disabled}
 | 
			
		||||
						onClick={() => {
 | 
			
		||||
							setDisabled(true);
 | 
			
		||||
							toast.promise(VerifyUser(userId), {
 | 
			
		||||
							toast.promise(VerifyUser(String(userId)), {
 | 
			
		||||
								loading: "Verifying...",
 | 
			
		||||
								success: () => {
 | 
			
		||||
									setDisabled(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import type { Device } from "@prisma/client";
 | 
			
		||||
import { atom, createStore } from "jotai";
 | 
			
		||||
import type { Device } from "./backend-types";
 | 
			
		||||
 | 
			
		||||
// Create a single store instance
 | 
			
		||||
export const store = createStore();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"use server";
 | 
			
		||||
import type { TNationalPerson } from "@/lib/types";
 | 
			
		||||
import type { User } from "@prisma/client";
 | 
			
		||||
import { User } from "./types/user";
 | 
			
		||||
 | 
			
		||||
export async function getNationalPerson({
 | 
			
		||||
	idCard,
 | 
			
		||||
@@ -18,26 +18,27 @@ export async function getNationalPerson({
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function VerifyUserDetails({ user }: { user: User }) {
 | 
			
		||||
	const phoneNumber = String(user.phoneNumber).slice(4);
 | 
			
		||||
	console.log({ phoneNumber });
 | 
			
		||||
	const nationalData = await getNationalPerson({ idCard: user.id_card ?? "" });
 | 
			
		||||
	const dob = new Date(nationalData.dob);
 | 
			
		||||
	const age = new Date().getFullYear() - dob.getFullYear();
 | 
			
		||||
	console.log(user)
 | 
			
		||||
	// const phoneNumber = String(user.phoneNumber).slice(4);
 | 
			
		||||
	// console.log({ phoneNumber });
 | 
			
		||||
	// const nationalData = await getNationalPerson({ idCard: user.id_card ?? "" });
 | 
			
		||||
	// const dob = new Date(nationalData.dob);
 | 
			
		||||
	// const age = new Date().getFullYear() - dob.getFullYear();
 | 
			
		||||
 | 
			
		||||
	console.log("ID card", user.id_card === nationalData.nic);
 | 
			
		||||
	console.log("name", user.name === nationalData.name_en);
 | 
			
		||||
	console.log("house", user.address === nationalData.house_name_en);
 | 
			
		||||
	console.log("phone", phoneNumber === nationalData.primary_contact);
 | 
			
		||||
	console.log("db phone", phoneNumber);
 | 
			
		||||
	console.log("national phone", nationalData.primary_contact);
 | 
			
		||||
	// console.log("ID card", user.id_card === nationalData.nic);
 | 
			
		||||
	// console.log("name", user.name === nationalData.name_en);
 | 
			
		||||
	// console.log("house", user.address === nationalData.house_name_en);
 | 
			
		||||
	// console.log("phone", phoneNumber === nationalData.primary_contact);
 | 
			
		||||
	// console.log("db phone", phoneNumber);
 | 
			
		||||
	// console.log("national phone", nationalData.primary_contact);
 | 
			
		||||
 | 
			
		||||
	if (
 | 
			
		||||
		user.id_card === nationalData.nic &&
 | 
			
		||||
		user.name === nationalData.name_en &&
 | 
			
		||||
		user.address === nationalData.house_name_en &&
 | 
			
		||||
		age >= 18
 | 
			
		||||
	) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	// if (
 | 
			
		||||
	// 	user.id_card === nationalData.nic &&
 | 
			
		||||
	// 	user.name === nationalData.name_en &&
 | 
			
		||||
	// 	user.address === nationalData.house_name_en &&
 | 
			
		||||
	// 	age >= 18
 | 
			
		||||
	// ) {
 | 
			
		||||
	// 	return true;
 | 
			
		||||
	// }
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,10 @@ export interface User {
 | 
			
		||||
	user_permissions: Permission[];
 | 
			
		||||
	first_name: string;
 | 
			
		||||
	last_name: string;
 | 
			
		||||
	id_card?: string;
 | 
			
		||||
	address?: string;
 | 
			
		||||
	verified?: boolean;
 | 
			
		||||
	dob?: string;
 | 
			
		||||
	mobile?: string;
 | 
			
		||||
	wallet_balance?: number;
 | 
			
		||||
	is_superuser: boolean;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16143
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16143
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										21
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								package.json
									
									
									
									
									
								
							@@ -6,14 +6,9 @@
 | 
			
		||||
		"dev": "next dev --turbopack",
 | 
			
		||||
		"build": "next build",
 | 
			
		||||
		"start": "next start",
 | 
			
		||||
		"lint": "next lint",
 | 
			
		||||
		"studio": "npx prisma studio",
 | 
			
		||||
		"push": "npx prisma db push",
 | 
			
		||||
		"db-setup": "npx prisma migrate deploy && npx prisma generate && npx prisma db push"
 | 
			
		||||
	},
 | 
			
		||||
	"prisma": {
 | 
			
		||||
		"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
 | 
			
		||||
		"lint": "next lint"
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"@faker-js/faker": "^9.3.0",
 | 
			
		||||
		"@hookform/resolvers": "^3.9.1",
 | 
			
		||||
@@ -39,14 +34,14 @@
 | 
			
		||||
		"lucide-react": "^0.460.0",
 | 
			
		||||
		"moment": "^2.30.1",
 | 
			
		||||
		"motion": "^11.15.0",
 | 
			
		||||
		"next": "15.1.2",
 | 
			
		||||
		"next": "15.3.0",
 | 
			
		||||
		"next-auth": "^4.24.11",
 | 
			
		||||
		"next-themes": "^0.4.3",
 | 
			
		||||
		"nextjs-toploader": "^3.7.15",
 | 
			
		||||
		"react": "19.0.0",
 | 
			
		||||
		"react": "19.1.0",
 | 
			
		||||
		"react-aria-components": "^1.5.0",
 | 
			
		||||
		"react-day-picker": "^9.6.3",
 | 
			
		||||
		"react-dom": "19.0.0",
 | 
			
		||||
		"react-dom": "19.1.0",
 | 
			
		||||
		"react-hook-form": "^7.53.2",
 | 
			
		||||
		"react-phone-number-input": "^3.4.9",
 | 
			
		||||
		"sonner": "^1.7.1",
 | 
			
		||||
@@ -57,14 +52,14 @@
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@types/node": "^22.10.2",
 | 
			
		||||
		"@types/react": "^19.0.2",
 | 
			
		||||
		"@types/react-dom": "^19.0.2",
 | 
			
		||||
		"@types/react": "^19.1.0",
 | 
			
		||||
		"@types/react-dom": "^19.1.2",
 | 
			
		||||
		"eslint": "^9.17.0",
 | 
			
		||||
		"eslint-config-next": "15.1.2",
 | 
			
		||||
		"postcss": "^8.4.49",
 | 
			
		||||
		"tailwindcss": "^3.4.17",
 | 
			
		||||
		"ts-node": "^10.9.2",
 | 
			
		||||
		"typescript": "^5.7.2"
 | 
			
		||||
		"typescript": "^5.8.3"
 | 
			
		||||
	},
 | 
			
		||||
	"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,110 +0,0 @@
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "user" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT,
 | 
			
		||||
    "email" TEXT,
 | 
			
		||||
    "emailVerified" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "firstPaymentDone" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "verified" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "address" TEXT,
 | 
			
		||||
    "id_card" TEXT,
 | 
			
		||||
    "dob" TIMESTAMP(3),
 | 
			
		||||
    "image" TEXT,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "phoneNumber" TEXT NOT NULL,
 | 
			
		||||
    "phoneNumberVerified" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "role" TEXT,
 | 
			
		||||
    "lang" TEXT,
 | 
			
		||||
    "atollId" TEXT,
 | 
			
		||||
    "islandId" TEXT,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "user_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "session" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "userId" TEXT NOT NULL,
 | 
			
		||||
    "token" TEXT NOT NULL,
 | 
			
		||||
    "expiresAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "ipAddress" TEXT,
 | 
			
		||||
    "userAgent" TEXT,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "session_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "account" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "userId" TEXT NOT NULL,
 | 
			
		||||
    "accountId" TEXT NOT NULL,
 | 
			
		||||
    "providerId" TEXT NOT NULL,
 | 
			
		||||
    "accessToken" TEXT,
 | 
			
		||||
    "refreshToken" TEXT,
 | 
			
		||||
    "accessTokenExpiresAt" TIMESTAMP(3),
 | 
			
		||||
    "refreshTokenExpiresAt" TIMESTAMP(3),
 | 
			
		||||
    "scope" TEXT,
 | 
			
		||||
    "password" TEXT,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "idToken" TEXT,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "account_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "verification" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "identifier" TEXT NOT NULL,
 | 
			
		||||
    "value" TEXT NOT NULL,
 | 
			
		||||
    "expiresAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "verification_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Atoll" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Atoll_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Island" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "atollId" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Island_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "user_id_card_key" ON "user"("id_card");
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "user_phoneNumber_key" ON "user"("phoneNumber");
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "user" ADD CONSTRAINT "user_atollId_fkey" FOREIGN KEY ("atollId") REFERENCES "Atoll"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "user" ADD CONSTRAINT "user_islandId_fkey" FOREIGN KEY ("islandId") REFERENCES "Island"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Island" ADD CONSTRAINT "Island_atollId_fkey" FOREIGN KEY ("atollId") REFERENCES "Atoll"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Device" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT NOT NULL,
 | 
			
		||||
    "mac" TEXT NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "userId" TEXT,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Device_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Device" ADD CONSTRAINT "Device_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "user" ADD COLUMN     "policyAccepted" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
ADD COLUMN     "termsAccepted" BOOLEAN NOT NULL DEFAULT false;
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Bill" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT NOT NULL,
 | 
			
		||||
    "amount" INTEGER NOT NULL,
 | 
			
		||||
    "paid" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "deviceId" TEXT,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Bill_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "BillFormula" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "formula" TEXT NOT NULL,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "BillFormula_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Bill" ADD CONSTRAINT "Bill_deviceId_fkey" FOREIGN KEY ("deviceId") REFERENCES "Device"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,10 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  Warnings:
 | 
			
		||||
 | 
			
		||||
  - Added the required column `baseAmount` to the `BillFormula` table without a default value. This is not possible if the table is not empty.
 | 
			
		||||
  - Added the required column `discountPercentage` to the `BillFormula` table without a default value. This is not possible if the table is not empty.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "BillFormula" ADD COLUMN     "baseAmount" DOUBLE PRECISION NOT NULL,
 | 
			
		||||
ADD COLUMN     "discountPercentage" DOUBLE PRECISION NOT NULL;
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "isActive" BOOLEAN NOT NULL DEFAULT false;
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  Warnings:
 | 
			
		||||
 | 
			
		||||
  - You are about to drop the `Bill` table. If the table is not empty, all the data it contains will be lost.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
-- DropForeignKey
 | 
			
		||||
ALTER TABLE "Bill" DROP CONSTRAINT "Bill_deviceId_fkey";
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "billId" TEXT;
 | 
			
		||||
 | 
			
		||||
-- DropTable
 | 
			
		||||
DROP TABLE "Bill";
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Payment" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "name" TEXT NOT NULL,
 | 
			
		||||
    "amount" INTEGER NOT NULL,
 | 
			
		||||
    "paid" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
    "userId" TEXT NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Payment_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Device" ADD CONSTRAINT "Device_billId_fkey" FOREIGN KEY ("billId") REFERENCES "Payment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  Warnings:
 | 
			
		||||
 | 
			
		||||
  - You are about to drop the column `billId` on the `Device` table. All the data in the column will be lost.
 | 
			
		||||
  - You are about to drop the column `name` on the `Payment` table. All the data in the column will be lost.
 | 
			
		||||
  - Added the required column `numberOfMonths` to the `Payment` table without a default value. This is not possible if the table is not empty.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
-- DropForeignKey
 | 
			
		||||
ALTER TABLE "Device" DROP CONSTRAINT "Device_billId_fkey";
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" DROP COLUMN "billId",
 | 
			
		||||
ADD COLUMN     "expiryDate" TIMESTAMP(3),
 | 
			
		||||
ADD COLUMN     "paymentId" TEXT;
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Payment" DROP COLUMN "name",
 | 
			
		||||
ADD COLUMN     "numberOfMonths" INTEGER NOT NULL,
 | 
			
		||||
ALTER COLUMN "amount" SET DATA TYPE DOUBLE PRECISION;
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "Device" ADD CONSTRAINT "Device_paymentId_fkey" FOREIGN KEY ("paymentId") REFERENCES "Payment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Payment" ADD COLUMN     "paidAt" TIMESTAMP(3);
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Payment" ADD COLUMN     "expiresAt" TIMESTAMP(3);
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "user" ADD COLUMN     "accNo" TEXT;
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  Warnings:
 | 
			
		||||
 | 
			
		||||
  - You are about to drop the column `firstPaymentDone` on the `user` table. All the data in the column will be lost.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "registered" BOOLEAN NOT NULL DEFAULT false;
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "user" DROP COLUMN "firstPaymentDone";
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "blocked" BOOLEAN NOT NULL DEFAULT false;
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "user" ADD COLUMN     "walletBalance" DOUBLE PRECISION NOT NULL DEFAULT 0;
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "reasonForBlocking" TEXT;
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "Topup" (
 | 
			
		||||
    "id" TEXT NOT NULL,
 | 
			
		||||
    "amount" DOUBLE PRECISION NOT NULL,
 | 
			
		||||
    "userId" TEXT NOT NULL,
 | 
			
		||||
    "paid" BOOLEAN NOT NULL DEFAULT false,
 | 
			
		||||
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
			
		||||
    "updatedAt" TIMESTAMP(3) NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "Topup_pkey" PRIMARY KEY ("id")
 | 
			
		||||
);
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
-- CreateEnum
 | 
			
		||||
CREATE TYPE "Blocker" AS ENUM ('ADMIN', 'PARENT');
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" ADD COLUMN     "blockedBy" "Blocker" NOT NULL DEFAULT 'PARENT';
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "user" ADD COLUMN     "ninja_user_id" TEXT;
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
-- CreateEnum
 | 
			
		||||
CREATE TYPE "PaymentType" AS ENUM ('WALLET', 'TRANSFER');
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Payment" ADD COLUMN     "method" "PaymentType" NOT NULL DEFAULT 'TRANSFER';
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  Warnings:
 | 
			
		||||
 | 
			
		||||
  - You are about to drop the column `paymentId` on the `Device` table. All the data in the column will be lost.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
-- DropForeignKey
 | 
			
		||||
ALTER TABLE "Device" DROP CONSTRAINT "Device_paymentId_fkey";
 | 
			
		||||
 | 
			
		||||
-- AlterTable
 | 
			
		||||
ALTER TABLE "Device" DROP COLUMN "paymentId";
 | 
			
		||||
 | 
			
		||||
-- CreateTable
 | 
			
		||||
CREATE TABLE "_DeviceToPayment" (
 | 
			
		||||
    "A" TEXT NOT NULL,
 | 
			
		||||
    "B" TEXT NOT NULL,
 | 
			
		||||
 | 
			
		||||
    CONSTRAINT "_DeviceToPayment_AB_pkey" PRIMARY KEY ("A","B")
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
-- CreateIndex
 | 
			
		||||
CREATE INDEX "_DeviceToPayment_B_index" ON "_DeviceToPayment"("B");
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "_DeviceToPayment" ADD CONSTRAINT "_DeviceToPayment_A_fkey" FOREIGN KEY ("A") REFERENCES "Device"("id") ON DELETE CASCADE ON UPDATE CASCADE;
 | 
			
		||||
 | 
			
		||||
-- AddForeignKey
 | 
			
		||||
ALTER TABLE "_DeviceToPayment" ADD CONSTRAINT "_DeviceToPayment_B_fkey" FOREIGN KEY ("B") REFERENCES "Payment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
# Please do not edit this file manually
 | 
			
		||||
# It should be added in your version-control system (e.g., Git)
 | 
			
		||||
provider = "postgresql"
 | 
			
		||||
@@ -1,172 +0,0 @@
 | 
			
		||||
// This is your Prisma schema file,
 | 
			
		||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
 | 
			
		||||
 | 
			
		||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
 | 
			
		||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
 | 
			
		||||
 | 
			
		||||
generator client {
 | 
			
		||||
  provider = "prisma-client-js"
 | 
			
		||||
  binaryTargets = ["native", "debian-openssl-3.0.x"]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
datasource db {
 | 
			
		||||
  provider = "postgresql"
 | 
			
		||||
  url      = env("DATABASE_URL")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model User {
 | 
			
		||||
  id            String  @id @default(cuid())
 | 
			
		||||
  name          String?
 | 
			
		||||
  email         String? @unique
 | 
			
		||||
  emailVerified Boolean @default(false)
 | 
			
		||||
 | 
			
		||||
  verified Boolean   @default(false)
 | 
			
		||||
  accNo    String?
 | 
			
		||||
  // island           String?
 | 
			
		||||
  address  String?
 | 
			
		||||
  id_card  String?   @unique
 | 
			
		||||
  dob      DateTime?
 | 
			
		||||
  atoll    Atoll?    @relation(fields: [atollId], references: [id])
 | 
			
		||||
  island   Island?   @relation(fields: [islandId], references: [id])
 | 
			
		||||
 | 
			
		||||
  image               String?
 | 
			
		||||
  createdAt           DateTime @default(now())
 | 
			
		||||
  updatedAt           DateTime @updatedAt
 | 
			
		||||
  phoneNumber         String   @unique
 | 
			
		||||
  phoneNumberVerified Boolean  @default(false)
 | 
			
		||||
  termsAccepted       Boolean  @default(false)
 | 
			
		||||
  policyAccepted      Boolean  @default(false)
 | 
			
		||||
  walletBalance       Float    @default(0)
 | 
			
		||||
  ninja_user_id       String?
 | 
			
		||||
  devices             Device[]
 | 
			
		||||
 | 
			
		||||
  role     String?
 | 
			
		||||
  lang     String?
 | 
			
		||||
  atollId  String?
 | 
			
		||||
  islandId String?
 | 
			
		||||
  Bill     Payment[]
 | 
			
		||||
 | 
			
		||||
  @@map("user")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Session {
 | 
			
		||||
  id        String   @id @default(cuid())
 | 
			
		||||
  userId    String
 | 
			
		||||
  token     String   @unique
 | 
			
		||||
  expiresAt DateTime
 | 
			
		||||
  ipAddress String?
 | 
			
		||||
  userAgent String?
 | 
			
		||||
  createdAt DateTime @default(now())
 | 
			
		||||
  updatedAt DateTime @updatedAt
 | 
			
		||||
 | 
			
		||||
  @@map("session")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Account {
 | 
			
		||||
  id                    String    @id @default(cuid())
 | 
			
		||||
  userId                String
 | 
			
		||||
  accountId             String
 | 
			
		||||
  providerId            String
 | 
			
		||||
  accessToken           String?
 | 
			
		||||
  refreshToken          String?
 | 
			
		||||
  accessTokenExpiresAt  DateTime?
 | 
			
		||||
  refreshTokenExpiresAt DateTime?
 | 
			
		||||
  scope                 String?
 | 
			
		||||
  password              String?
 | 
			
		||||
  createdAt             DateTime  @default(now())
 | 
			
		||||
  updatedAt             DateTime  @updatedAt
 | 
			
		||||
 | 
			
		||||
  idToken String?
 | 
			
		||||
 | 
			
		||||
  @@map("account")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Verification {
 | 
			
		||||
  id         String   @id @default(cuid())
 | 
			
		||||
  identifier String
 | 
			
		||||
  value      String
 | 
			
		||||
  expiresAt  DateTime
 | 
			
		||||
  createdAt  DateTime @default(now())
 | 
			
		||||
  updatedAt  DateTime @updatedAt
 | 
			
		||||
 | 
			
		||||
  @@map("verification")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Atoll {
 | 
			
		||||
  id        String   @id @default(cuid())
 | 
			
		||||
  name      String
 | 
			
		||||
  createdAt DateTime @default(now())
 | 
			
		||||
  updatedAt DateTime @updatedAt
 | 
			
		||||
  islands   Island[]
 | 
			
		||||
  User      User[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Island {
 | 
			
		||||
  id        String   @id @default(cuid())
 | 
			
		||||
  atollId   String
 | 
			
		||||
  atoll     Atoll    @relation(fields: [atollId], references: [id])
 | 
			
		||||
  name      String
 | 
			
		||||
  createdAt DateTime @default(now())
 | 
			
		||||
  updatedAt DateTime @updatedAt
 | 
			
		||||
  User      User[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum Blocker {
 | 
			
		||||
  ADMIN
 | 
			
		||||
  PARENT
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum PaymentType {
 | 
			
		||||
  WALLET
 | 
			
		||||
  TRANSFER
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Device {
 | 
			
		||||
  id                String    @id @default(cuid())
 | 
			
		||||
  name              String
 | 
			
		||||
  mac               String
 | 
			
		||||
  reasonForBlocking String?
 | 
			
		||||
  isActive          Boolean   @default(false)
 | 
			
		||||
  registered        Boolean   @default(false)
 | 
			
		||||
  blocked           Boolean   @default(false)
 | 
			
		||||
  blockedBy         Blocker   @default(PARENT)
 | 
			
		||||
  expiryDate        DateTime?
 | 
			
		||||
  createdAt         DateTime  @default(now())
 | 
			
		||||
  updatedAt         DateTime  @updatedAt
 | 
			
		||||
  User              User?     @relation(fields: [userId], references: [id])
 | 
			
		||||
  userId            String?
 | 
			
		||||
  payments          Payment[]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Payment {
 | 
			
		||||
  id             String      @id @default(cuid())
 | 
			
		||||
  numberOfMonths Int
 | 
			
		||||
  amount         Float
 | 
			
		||||
  paid           Boolean     @default(false)
 | 
			
		||||
  user           User        @relation(fields: [userId], references: [id])
 | 
			
		||||
  paidAt         DateTime?
 | 
			
		||||
  method         PaymentType @default(TRANSFER)
 | 
			
		||||
  expiresAt      DateTime?
 | 
			
		||||
  createdAt      DateTime    @default(now())
 | 
			
		||||
  updatedAt      DateTime    @updatedAt
 | 
			
		||||
  devices        Device[]
 | 
			
		||||
  userId         String
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model BillFormula {
 | 
			
		||||
  id                 String   @id @default(cuid())
 | 
			
		||||
  formula            String
 | 
			
		||||
  baseAmount         Float
 | 
			
		||||
  discountPercentage Float
 | 
			
		||||
  createdAt          DateTime @default(now())
 | 
			
		||||
  updatedAt          DateTime @updatedAt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Topup {
 | 
			
		||||
  id        String   @id @default(cuid())
 | 
			
		||||
  amount    Float
 | 
			
		||||
  userId    String
 | 
			
		||||
  paid      Boolean  @default(false)
 | 
			
		||||
  createdAt DateTime @default(now())
 | 
			
		||||
  updatedAt DateTime @updatedAt
 | 
			
		||||
}
 | 
			
		||||
@@ -1,56 +0,0 @@
 | 
			
		||||
import { PrismaClient } from "@prisma/client";
 | 
			
		||||
 | 
			
		||||
const prisma = new PrismaClient();
 | 
			
		||||
 | 
			
		||||
const DEFAULT_ISLANDS = ["Dharanboodhoo", "Feeali", "Nilandhoo", "Magoodhoo"];
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
	await prisma.user.upsert({
 | 
			
		||||
		where: {
 | 
			
		||||
			phoneNumber: process.env.ADMIN_PHONENUMBER,
 | 
			
		||||
		},
 | 
			
		||||
		update: {},
 | 
			
		||||
		create: {
 | 
			
		||||
			name: process.env.ADMIN_FULLNAME,
 | 
			
		||||
			email: process.env.ADMIN_EMAIL,
 | 
			
		||||
			emailVerified: true,
 | 
			
		||||
			verified: true,
 | 
			
		||||
			address: process.env.ADMIN_ADDRESS,
 | 
			
		||||
			id_card: process.env.ADMIN_IDCARD,
 | 
			
		||||
			dob: new Date("1999-05-06"),
 | 
			
		||||
			phoneNumber: process.env.ADMIN_PHONENUMBER ?? "",
 | 
			
		||||
			phoneNumberVerified: true,
 | 
			
		||||
			role: "ADMIN",
 | 
			
		||||
		},
 | 
			
		||||
	});
 | 
			
		||||
	let FAAFU_ATOLL_ID = "";
 | 
			
		||||
	const atollExists = await prisma.atoll.findFirst({
 | 
			
		||||
		where: {
 | 
			
		||||
			name: "F",
 | 
			
		||||
		},
 | 
			
		||||
	});
 | 
			
		||||
	if (!atollExists) {
 | 
			
		||||
		const NEW_ATOLL = await prisma.atoll.create({
 | 
			
		||||
			data: {
 | 
			
		||||
				name: "F",
 | 
			
		||||
			},
 | 
			
		||||
		});
 | 
			
		||||
		FAAFU_ATOLL_ID = NEW_ATOLL.id;
 | 
			
		||||
 | 
			
		||||
		const islands = DEFAULT_ISLANDS.map((name) => ({
 | 
			
		||||
			name,
 | 
			
		||||
			atollId: FAAFU_ATOLL_ID,
 | 
			
		||||
		}));
 | 
			
		||||
		await prisma.island.createMany({
 | 
			
		||||
			data: islands,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
main()
 | 
			
		||||
	.then(() => prisma.$disconnect())
 | 
			
		||||
	.catch(async (e) => {
 | 
			
		||||
		console.error(e);
 | 
			
		||||
		await prisma.$disconnect();
 | 
			
		||||
		process.exit(1);
 | 
			
		||||
	});
 | 
			
		||||
		Reference in New Issue
	
	Block a user