);
diff --git a/components/auth/signup-form.tsx b/components/auth/signup-form.tsx
index b9dd15f..e87c4e4 100644
--- a/components/auth/signup-form.tsx
+++ b/components/auth/signup-form.tsx
@@ -48,7 +48,7 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
if (actionState.db_error === "invalidPersonValidation") {
return (
<>
-
Go to {" "}
diff --git a/components/device-cart.tsx b/components/device-cart.tsx
index 55ce539..2a00151 100644
--- a/components/device-cart.tsx
+++ b/components/device-cart.tsx
@@ -1,200 +1,124 @@
"use client";
-import { createPayment } from "@/actions/payment";
import { Button } from "@/components/ui/button";
import {
- Drawer,
- DrawerClose,
- DrawerContent,
- DrawerDescription,
- DrawerFooter,
- DrawerHeader,
- DrawerTitle,
- DrawerTrigger,
-} from "@/components/ui/drawer";
-import {
- cartDrawerOpenAtom,
- deviceCartAtom,
- numberOfMonths,
+ deviceCartAtom
} from "@/lib/atoms";
import { authClient } from "@/lib/auth-client";
-import type { PaymentType } from "@/lib/types";
-import type { BillFormula, Device } from "@prisma/client";
-import { useAtom, useAtomValue, useSetAtom } from "jotai";
+import { useAtomValue } from "jotai";
import {
- CircleDollarSign,
- Loader2,
- MonitorSmartphone,
- Trash2,
+ MonitorSmartphone
} from "lucide-react";
import { usePathname, useRouter } from "next/navigation";
-import { useEffect, useState } from "react";
-import { toast } from "sonner";
-import NumberInput from "./number-input";
-export function DeviceCartDrawer({
- billFormula,
-}: {
- billFormula: BillFormula | null;
-}) {
- const baseAmount = billFormula?.baseAmount || 100;
- const discountPercentage = billFormula?.discountPercentage || 75;
- const session = authClient.useSession();
+export function DeviceCartDrawer() {
const pathname = usePathname();
const devices = useAtomValue(deviceCartAtom);
- const setDeviceCart = useSetAtom(deviceCartAtom);
- const [months, setMonths] = useAtom(numberOfMonths);
- const [isOpen, setIsOpen] = useAtom(cartDrawerOpenAtom);
- const [message, setMessage] = useState("");
- const [disabled, setDisabled] = useState(false);
- const [total, setTotal] = useState(0);
const router = useRouter();
- useEffect(() => {
- if (months === 7) {
- setMessage("You will get 1 month free.");
- } else if (months === 12) {
- setMessage("You will get 2 months free.");
- } else {
- setMessage("");
- }
- setTotal(baseAmount + ((devices.length + 1) - 1) * discountPercentage);
- }, [months, devices.length, baseAmount, discountPercentage]);
- if (pathname === "/payment") {
+
+ if (pathname === "/payment" || pathname === "/devices-to-pay") {
return null;
}
- const data: PaymentType = {
- numberOfMonths: months,
- userId: session?.data?.user.id ?? "",
- deviceIds: devices.map((device) => device.id),
- amount: Number.parseFloat(total.toFixed(2)),
- paid: false,
- };
+
if (devices.length === 0) return null
- return (
- <>
-
-
-
-
-
-
-
- Selected Devices
- Selected devices pay.
-
-
-
{JSON.stringify(isOpen, null, 2)}
- {devices.map((device) => (
-
- ))}
-
-
- setMonths(value)}
- maxAllowed={12}
- isDisabled={devices.length === 0}
- />
- {message && (
-
- {message}
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- >
+ return
- );
+ // <>
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // Selected Devices
+ // Selected devices pay.
+ //
+ //
+ //
{JSON.stringify(isOpen, null, 2)}
+ // {devices.map((device) => (
+ //
+ // ))}
+ //
+ //
+ // setMonths(value)}
+ // maxAllowed={12}
+ // isDisabled={devices.length === 0}
+ // />
+ // {message && (
+ //
+ // {message}
+ //
+ // )}
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // >
+
+ // );
}
-function DeviceCard({ device }: { device: Device }) {
- const setDeviceCart = useSetAtom(deviceCartAtom);
- return (
-
-
-
-
-
-
-
- );
-}
diff --git a/components/devices-for-payment.tsx b/components/devices-for-payment.tsx
new file mode 100644
index 0000000..1a578be
--- /dev/null
+++ b/components/devices-for-payment.tsx
@@ -0,0 +1,107 @@
+
+"use client";
+
+import { createPayment } from "@/actions/payment";
+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 { authClient } from "@/lib/auth-client";
+import type { PaymentType } from "@/lib/types";
+import type { BillFormula } from "@prisma/client";
+import { useAtom, useAtomValue, useSetAtom } from "jotai";
+import {
+ CircleDollarSign,
+ Loader2
+} from "lucide-react";
+import { usePathname } from "next/navigation";
+import { useEffect, useState } from "react";
+export default function DevicesForPayment({
+ billFormula,
+}: {
+ billFormula?: BillFormula;
+}) {
+ const baseAmount = billFormula?.baseAmount || 100;
+ const discountPercentage = billFormula?.discountPercentage || 75;
+ const session = authClient.useSession();
+ const pathname = usePathname();
+ const devices = useAtomValue(deviceCartAtom);
+ const setDeviceCart = useSetAtom(deviceCartAtom);
+ const [months, setMonths] = useAtom(numberOfMonths);
+ const [message, setMessage] = useState("");
+ const [disabled, setDisabled] = useState(false);
+ const [total, setTotal] = useState(0);
+ useEffect(() => {
+ if (months === 7) {
+ setMessage("You will get 1 month free.");
+ } else if (months === 12) {
+ setMessage("You will get 2 months free.");
+ } else {
+ setMessage("");
+ }
+ setTotal(baseAmount + ((devices.length + 1) - 1) * discountPercentage);
+ }, [months, devices.length, baseAmount, discountPercentage]);
+
+ if (pathname === "/payment") {
+ return null;
+ }
+
+ const data: PaymentType = {
+ numberOfMonths: months,
+ userId: session?.data?.user.id ?? "",
+ deviceIds: devices.map((device) => device.id),
+ amount: Number.parseFloat(total.toFixed(2)),
+ paid: false,
+ };
+
+ return (
+
+
+ {devices.map((device) => (
+
+ ))}
+
+
+ setMonths(value)}
+ maxAllowed={12}
+ isDisabled={devices.length === 0}
+ />
+ {message && (
+
+ {message}
+
+ )}
+
+
+
+
+ )
+}
diff --git a/components/input-read-only.tsx b/components/input-read-only.tsx
index a9335de..3851b1d 100644
--- a/components/input-read-only.tsx
+++ b/components/input-read-only.tsx
@@ -1,20 +1,40 @@
-import { cn } from '@/lib/utils'
-import React from 'react'
+import { cn } from '@/lib/utils';
+import { CheckCheck, X } from 'lucide-react';
-export default function InputReadOnly({ label, value, labelClassName, className }: { label: string, value: string, labelClassName?: string, className?: string }) {
+export default function InputReadOnly({ label, value, labelClassName, className, showCheck = true, checkTrue = false }: {
+ label: string;
+ value: string;
+ labelClassName?: string;
+ className?: string;
+ showCheck?: boolean;
+ checkTrue?: boolean
+}) {
return (
-
-
-
+
+
+
+
+
+
+
+ {showCheck && (
+
+ {checkTrue ? (
+
+ ) : (
+
+ )}
+
+ )}
)
diff --git a/components/user/user-reject-dialog.tsx b/components/user/user-reject-dialog.tsx
index a772a46..2c44b0e 100644
--- a/components/user/user-reject-dialog.tsx
+++ b/components/user/user-reject-dialog.tsx
@@ -54,7 +54,7 @@ export default function UserRejectDialog({ user }: { user: User }) {
},
error: (error) => {
setDisabled(false)
- return error || "Something went wrong"
+ return error.message || "Something went wrong"
},
})
setDisabled(false)
diff --git a/lib/auth-utils.ts b/lib/auth-utils.ts
index bd16390..4f4b3d6 100644
--- a/lib/auth-utils.ts
+++ b/lib/auth-utils.ts
@@ -1,10 +1,15 @@
"use server";
import { headers } from "next/headers";
+import { cache } from "react";
import { auth } from "./auth";
-export async function getCurrentUser() {
+const getCurrentUserCache = cache(async () => {
const session = await auth.api.getSession({
headers: await headers(),
});
return session?.user;
+});
+
+export async function getCurrentUser() {
+ return await getCurrentUserCache();
}
diff --git a/lib/auth.ts b/lib/auth.ts
index ef94605..79b8421 100644
--- a/lib/auth.ts
+++ b/lib/auth.ts
@@ -1,11 +1,16 @@
import { sendOtp } from "@/actions/auth-actions";
-import { PrismaClient } from "@prisma/client";
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { phoneNumber } from "better-auth/plugins";
+import prisma from "./db";
-const prisma = new PrismaClient();
export const auth = betterAuth({
+ session: {
+ cookieCache: {
+ enabled: true,
+ maxAge: 10 * 60, // Cache duration in seconds
+ },
+ },
trustedOrigins: process.env.BETTER_AUTH_TRUSTED_ORIGINS?.split(",") || [
"localhost:3000",
],
@@ -25,7 +30,7 @@ export const auth = betterAuth({
},
},
database: prismaAdapter(prisma, {
- provider: "sqlite", // or "mysql", "postgresql", ...etc
+ provider: "postgresql", // or "mysql", "postgresql", ...etc
}),
plugins: [
phoneNumber({
diff --git a/lib/person.ts b/lib/person.ts
index 64a1be1..523ce11 100644
--- a/lib/person.ts
+++ b/lib/person.ts
@@ -35,7 +35,6 @@ export async function VerifyUserDetails({ user }: { user: User }) {
user.id_card === nationalData.nic &&
user.name === nationalData.name_en &&
user.address === nationalData.house_name_en &&
- phoneNumber === nationalData.primary_contact &&
age >= 18
) {
return true;
diff --git a/middleware.ts b/middleware.ts
index d89d581..828efb8 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -1,4 +1,3 @@
-import { betterFetch } from "@better-fetch/fetch";
import type { Session } from "better-auth/types";
import { type NextRequest, NextResponse } from "next/server";
@@ -6,29 +5,28 @@ export default async function authMiddleware(request: NextRequest) {
const protocol = request.headers.get("x-forwarded-proto") || "http";
const host = request.headers.get("host") || "localhost:3000";
- console.log(protocol)
- console.log(host)
-
try {
- const { data: session } = await betterFetch
(
- "http://localhost:3000/api/auth/get-session",
- {
- baseURL: `${protocol}://${host}`,
- headers: {
- //get the cookie from the request
- cookie: request.headers.get("cookie") || "",
- host: host
- },
-
+ const response = await fetch(`${protocol}://${host}/api/auth/get-session`, {
+ method: "GET",
+ headers: {
+ cookie: request.headers.get("cookie") || "",
+ host: host,
},
- );
+ next: { revalidate: 600 }, // Cache for 10 minutes (600 seconds)
+ });
+
+ if (!response.ok) {
+ throw new Error("Failed to fetch session");
+ }
+
+ const session: Session = await response.json();
if (!session) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
} catch (error) {
- console.log("Middlewaree", error);
+ console.log("Middleware error", error);
return NextResponse.redirect(new URL("/login", request.url));
}
}
diff --git a/next.config.ts b/next.config.ts
index 11c875e..da25007 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -11,6 +11,13 @@ const nextConfig: NextConfig = {
search: "",
port: "",
},
+ {
+ protocol: "https",
+ hostname: "i.pravatar.cc",
+ pathname: "/300/**",
+ search: "",
+ port: "",
+ },
],
},
output: "standalone",
diff --git a/package-lock.json b/package-lock.json
index f7810b1..5a57d72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,7 +24,7 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"@tanstack/react-query": "^5.61.4",
- "better-auth": "^1.0.0",
+ "better-auth": "^1.1.13",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
@@ -73,14 +73,17 @@
}
},
"node_modules/@better-auth/utils": {
- "version": "0.2.2",
- "license": "MIT",
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.3.tgz",
+ "integrity": "sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==",
"dependencies": {
"uncrypto": "^0.1.3"
}
},
"node_modules/@better-fetch/fetch": {
- "version": "1.1.12"
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.12.tgz",
+ "integrity": "sha512-B3bfloI/2UBQWIATRN6qmlORrvx3Mp0kkNjmXLv0b+DtbtR+pP4/I5kQA/rDUv+OReLywCCldf6co4LdDmh8JA=="
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
@@ -561,6 +564,66 @@
"node": ">= 6"
}
},
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.2.tgz",
+ "integrity": "sha512-b9TN7q+j5/7+rGLhFAVZiKJGIASuo8tWvInGfAd8wsULjB1uNGRCj1z1WZwwPWzVQbIKWFYqc+9L7W09qwt52w==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.2.tgz",
+ "integrity": "sha512-caR62jNDUCU+qobStO6YJ05p9E+LR0EoXh1EEmyU69cYydsAy7drMcOlUlRtQihM6K6QfvNwJuLhsHcCzNpqtA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.2.tgz",
+ "integrity": "sha512-fHHXBusURjBmN6VBUtu6/5s7cCeEkuGAb/ZZiGHBLVBXMBy4D5QpM8P33Or8JD1nlOjm/ZT9sEE5HouQ0F+hUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.2.tgz",
+ "integrity": "sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@next/swc-linux-x64-gnu": {
"version": "15.1.2",
"cpu": [
@@ -589,6 +652,36 @@
"node": ">= 10"
}
},
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.2.tgz",
+ "integrity": "sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.1.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.2.tgz",
+ "integrity": "sha512-D3cNA8NoT3aWISWmo7HF5Eyko/0OdOO+VagkoJuiTk7pyX3P/b+n8XA/MYvyR+xSVcbKn68B1rY9fgqjNISqzQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@noble/ciphers": {
"version": "0.6.0",
"license": "MIT",
@@ -3673,30 +3766,34 @@
"license": "MIT"
},
"node_modules/better-auth": {
- "version": "1.1.3",
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.1.13.tgz",
+ "integrity": "sha512-Tt4QYGFKuAFTjJx6RyXzC50KNyh96/QeVT2QxJRnXiEmp6wGEGmua9iRb5XL3bSnBu8oepAE7xlLF/AvfkEZig==",
"dependencies": {
- "@better-auth/utils": "0.2.2",
+ "@better-auth/utils": "0.2.3",
"@better-fetch/fetch": "1.1.12",
"@noble/ciphers": "^0.6.0",
"@noble/hashes": "^1.6.1",
"@simplewebauthn/browser": "^13.0.0",
"@simplewebauthn/server": "^13.0.0",
- "better-call": "0.3.3-beta.4",
+ "better-call": "0.3.3",
"defu": "^6.1.4",
"jose": "^5.9.6",
"kysely": "^0.27.4",
+ "nanostores": "^0.11.3",
"uncrypto": "^0.1.3",
- "zod": "^3.23.8"
+ "zod": "^3.24.1"
}
},
"node_modules/better-call": {
- "version": "0.3.3-beta.4",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/better-call/-/better-call-0.3.3.tgz",
+ "integrity": "sha512-N4lDVm0NGmFfDJ0XMQ4O83Zm/3dPlvIQdxvwvgSLSkjFX5PM4GUYSVAuxNzXN27QZMHDkrJTWUqxBrm4tPC3eA==",
"dependencies": {
"@better-fetch/fetch": "^1.1.4",
"rou3": "^0.5.1",
- "set-cookie-parser": "^2.7.1",
"uncrypto": "^0.1.3",
- "zod": "^3.23.8"
+ "zod": "^3.24.1"
}
},
"node_modules/binary-extensions": {
@@ -5994,6 +6091,20 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/nanostores": {
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.3.tgz",
+ "integrity": "sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"dev": true,
@@ -6943,7 +7054,8 @@
},
"node_modules/rou3": {
"version": "0.5.1",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.5.1.tgz",
+ "integrity": "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ=="
},
"node_modules/run-parallel": {
"version": "1.2.0",
@@ -7013,10 +7125,6 @@
"semver": "bin/semver.js"
}
},
- "node_modules/set-cookie-parser": {
- "version": "2.7.1",
- "license": "MIT"
- },
"node_modules/set-function-length": {
"version": "1.2.2",
"dev": true,
@@ -7808,7 +7916,8 @@
},
"node_modules/uncrypto": {
"version": "0.1.3",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
+ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="
},
"node_modules/undici-types": {
"version": "6.20.0",
diff --git a/package.json b/package.json
index 57a11df..dc93028 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"@tanstack/react-query": "^5.61.4",
- "better-auth": "^1.0.0",
+ "better-auth": "^1.1.13",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 2e4cfe6..2939431 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -11,13 +11,13 @@ async function main() {
},
update: {},
create: {
- name: "Admin Admin",
+ name: process.env.ADMIN_FULLNAME,
email: process.env.ADMIN_EMAIL,
emailVerified: true,
verified: true,
- address: "Sky villa",
+ address: process.env.ADMIN_ADDRESS,
id_card: process.env.ADMIN_IDCARD,
- dob: new Date("1990-01-01"),
+ dob: new Date("1999-05-06"),
phoneNumber: process.env.ADMIN_PHONENUMBER ?? "",
phoneNumberVerified: true,
role: "ADMIN",