TEMPORARY FIX TO TEST BUILD
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m15s

This commit is contained in:
i701 2025-04-10 23:18:19 +05:00
parent e8296ae3f6
commit b932fcf03c
Signed by: i701
GPG Key ID: 54A0DA1E26D8E587
49 changed files with 8314 additions and 8858 deletions

View File

@ -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">

View File

@ -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,

View File

@ -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,

View File

@ -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 = [
{

View File

@ -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
View File

@ -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

View File

@ -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: {

View File

@ -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: [

View File

@ -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>

View File

@ -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,

View File

@ -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);

View File

@ -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";

View File

@ -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.");

View File

@ -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 ? (

View File

@ -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;

View File

@ -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 ? (

View File

@ -55,7 +55,6 @@ type Categories = {
}[];
export async function AppSidebar({
role,
...props
}: React.ComponentProps<typeof Sidebar>) {
const categories = [

View File

@ -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 };

View File

@ -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: [

View File

@ -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!");

View File

@ -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>
)
);
}

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Device" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT false;

View File

@ -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;

View File

@ -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;

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Payment" ADD COLUMN "paidAt" TIMESTAMP(3);

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Payment" ADD COLUMN "expiresAt" TIMESTAMP(3);

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "accNo" TEXT;

View File

@ -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";

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Device" ADD COLUMN "blocked" BOOLEAN NOT NULL DEFAULT false;

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "walletBalance" DOUBLE PRECISION NOT NULL DEFAULT 0;

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Device" ADD COLUMN "reasonForBlocking" TEXT;

View File

@ -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")
);

View File

@ -1,5 +0,0 @@
-- CreateEnum
CREATE TYPE "Blocker" AS ENUM ('ADMIN', 'PARENT');
-- AlterTable
ALTER TABLE "Device" ADD COLUMN "blockedBy" "Blocker" NOT NULL DEFAULT 'PARENT';

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "ninja_user_id" TEXT;

View File

@ -1,5 +0,0 @@
-- CreateEnum
CREATE TYPE "PaymentType" AS ENUM ('WALLET', 'TRANSFER');
-- AlterTable
ALTER TABLE "Payment" ADD COLUMN "method" "PaymentType" NOT NULL DEFAULT 'TRANSFER';

View File

@ -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;

View File

@ -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"

View File

@ -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
}

View File

@ -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);
});