diff --git a/actions/auth-actions.ts b/actions/auth-actions.ts
index 91b4eb9..d84b7ae 100644
--- a/actions/auth-actions.ts
+++ b/actions/auth-actions.ts
@@ -2,11 +2,13 @@
import { authClient } from "@/lib/auth-client";
import prisma from "@/lib/db";
+import VerifyUserDetails from "@/lib/person";
import { signUpFormSchema } from "@/lib/schemas";
import { headers } from "next/headers";
// import type { User } from "@prisma/client";
import { redirect } from "next/navigation";
import { z } from "zod";
+import { SendUserRejectionDetailSMS } from "./user-actions";
const formSchema = z.object({
phoneNumber: z
.string()
@@ -41,6 +43,14 @@ export async function signin(previousState: ActionState, formData: FormData) {
if (!userExists) {
return redirect(`/signup?phone_number=${phoneNumber}`);
}
+
+ if (!userExists?.verified)
+ return {
+ message:
+ "Your account is on pending verification. Please wait for a response from admin or contact shihaam.",
+ status: "error",
+ };
+
await authClient.phoneNumber.sendOtp({
phoneNumber: NUMBER_WITH_COUNTRY_CODE,
});
@@ -79,6 +89,7 @@ export async function signup(_actionState: ActionState, formData: FormData) {
NUMBER_WITH_COUNTRY_CODE = `+960${parsedData.data.phone_number.split("-").join("")}`;
}
console.log({ NUMBER_WITH_COUNTRY_CODE });
+
const idCardExists = await prisma.user.findFirst({
where: {
id_card: parsedData.data.id_card,
@@ -120,14 +131,39 @@ export async function signup(_actionState: ActionState, formData: FormData) {
phoneNumber: NUMBER_WITH_COUNTRY_CODE,
},
});
- await authClient.phoneNumber.sendOtp({
- phoneNumber: newUser.phoneNumber,
- });
+ const isValidPerson = await VerifyUserDetails({ user: newUser });
+
+ if (!isValidPerson) {
+ await SendUserRejectionDetailSMS({
+ details: `
+ A new user has requested for verification.
+ USER DETAILS:
+ Name: ${parsedData.data.name}
+ Address: ${parsedData.data.address}
+ ID Card: ${parsedData.data.id_card}
+ DOB: ${parsedData.data.dob}
+ ACC No: ${parsedData.data.accNo}
+ Verify the user with the folloiwing link: ${process.env.BETTER_AUTH_URL}/users/${newUser.id}/verify
+ `,
+ phoneNumber: process.env.ADMIN_PHONENUMBER ?? "",
+ });
+ return {
+ message:
+ "Your account has been requested for verification. Please wait for a response from admin.",
+ payload: formData,
+ db_error: "invalidPersonValidation",
+ };
+ }
+
+ if (isValidPerson) {
+ await authClient.phoneNumber.sendOtp({
+ phoneNumber: newUser.phoneNumber,
+ });
+ }
redirect(
`/verify-otp?phone_number=${encodeURIComponent(newUser.phoneNumber)}`,
);
-
- return { message: "Post created" };
+ return { message: "User created successfully" };
}
export const sendOtp = async (phoneNumber: string, code: string) => {
diff --git a/actions/ninja/client.ts b/actions/ninja/client.ts
index 540e55b..b909eed 100644
--- a/actions/ninja/client.ts
+++ b/actions/ninja/client.ts
@@ -1,25 +1,4 @@
"use server";
-// const raw = {
-// group_settings_id: "",
-// address1: "",
-// city: "F",
-// state: "Dharanboodhoo",
-// postal_code: "12040",
-// country_id: "462",
-// address2: "Skyvilla",
-// contacts: [
-// {
-// first_name: "Abdulla",
-// last_name: "Aidhaan",
-// email: "",
-// phone: "778-0588",
-// send_email: false,
-// custom_value1: "1971-02-24",
-// custom_value2: "A265117",
-// custom_value3: "",
-// },
-// ],
-// };
type CreateClientProps = {
group_settings_id: string;
diff --git a/actions/user-actions.ts b/actions/user-actions.ts
index 2afbc25..2c6c34e 100644
--- a/actions/user-actions.ts
+++ b/actions/user-actions.ts
@@ -1,6 +1,8 @@
"use server";
+import usePerson from "@/hooks/use-person";
import prisma from "@/lib/db";
+import VerifyUserDetails from "@/lib/person";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { CreateClient } from "./ninja/client";
@@ -18,33 +20,42 @@ export async function VerifyUser(userId: string) {
if (!user) {
throw new Error("User not found");
}
- await prisma.user.update({
- where: {
- id: userId,
- },
- data: {
- verified: true,
- },
- });
- const ninjaClient = await CreateClient({
- group_settings_id: "",
- address1: "",
- city: user.atoll?.name || "",
- state: user.island?.name || "",
- postal_code: "",
- country_id: "462",
- address2: user.address || "",
- contacts: {
- first_name: user.name?.split(" ")[0] || "",
- last_name: user.name?.split(" ")[1] || "",
- email: user.email || "",
- phone: user.phoneNumber || "",
- send_email: false,
- custom_value1: user.dob?.toISOString().split("T")[0] || "",
- custom_value2: user.id_card || "",
- custom_value3: "",
- },
- });
+ const isValidPerson = await VerifyUserDetails({ user });
+
+ if (!isValidPerson)
+ throw new Error("The user details does not match national data.");
+
+ if (isValidPerson) {
+ await prisma.user.update({
+ where: {
+ id: userId,
+ },
+ data: {
+ verified: true,
+ },
+ });
+
+ const ninjaClient = await CreateClient({
+ group_settings_id: "",
+ address1: "",
+ city: user.atoll?.name || "",
+ state: user.island?.name || "",
+ postal_code: "",
+ country_id: "462",
+ address2: user.address || "",
+ contacts: {
+ first_name: user.name?.split(" ")[0] || "",
+ last_name: user.name?.split(" ")[1] || "",
+ email: user.email || "",
+ phone: user.phoneNumber || "",
+ send_email: false,
+ custom_value1: user.dob?.toISOString().split("T")[0] || "",
+ custom_value2: user.id_card || "",
+ custom_value3: "",
+ },
+ });
+ }
+
revalidatePath("/users");
}
diff --git a/app/(dashboard)/users/[userId]/verify/page.tsx b/app/(dashboard)/users/[userId]/verify/page.tsx
index c3deb72..536c55b 100644
--- a/app/(dashboard)/users/[userId]/verify/page.tsx
+++ b/app/(dashboard)/users/[userId]/verify/page.tsx
@@ -2,8 +2,11 @@ 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 usePerson from '@/hooks/use-person';
import prisma from '@/lib/db';
+import type { TNationalPerson } from '@/lib/types';
+import Image from 'next/image';
import React from 'react'
export default async function VerifyUserPage({
@@ -18,7 +21,16 @@ export default async function VerifyUserPage({
where: {
id: userId,
},
+ include: {
+ island: {
+ include: {
+ atoll: true
+ }
+ }
+ }
})
+
+ const nationalData = await usePerson({ idCard: dbUser?.id_card ?? "" })
return (
@@ -35,30 +47,45 @@ export default async function VerifyUserPage({
diff --git a/components/auth/signup-form.tsx b/components/auth/signup-form.tsx
index 0a349c0..357cecb 100644
--- a/components/auth/signup-form.tsx
+++ b/components/auth/signup-form.tsx
@@ -9,7 +9,6 @@ import type { Island, Prisma } from "@prisma/client";
import { Loader2 } from "lucide-react";
import { useSearchParams } from "next/navigation";
import * as React from "react";
-import { useActionState } from "react";
import {
Select,
@@ -31,7 +30,7 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
const [atoll, setAtoll] = React.useState
();
const [islands, setIslands] = React.useState();
- const [actionState, action, isPending] = useActionState(signup, {
+ const [actionState, action, isPending] = React.useActionState(signup, {
message: "",
});
@@ -45,6 +44,7 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
const phoneNumberFromUrl = params.get("phone_number");
const NUMBER_WITHOUT_DASH = phoneNumberFromUrl?.split("-").join("");
+
return (
- {actionState.errors?.fieldErrors.name && (
+ {actionState?.errors?.fieldErrors.name && (
- {actionState.errors?.fieldErrors.name}
+ {actionState?.errors?.fieldErrors.name}
)}
@@ -82,22 +82,22 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
type="text"
maxLength={7}
disabled={isPending}
- defaultValue={(actionState.payload?.get("id_card") || "") as string}
+ defaultValue={(actionState?.payload?.get("id_card") || "") as string}
className={cn(
"text-base",
- actionState.errors?.fieldErrors?.id_card &&
+ actionState?.errors?.fieldErrors?.id_card &&
"border-2 border-red-500",
)}
placeholder="ID Card"
/>
{actionState?.errors?.fieldErrors?.id_card?.[0] && (
- {actionState.errors.fieldErrors.id_card[0]}
+ {actionState?.errors.fieldErrors.id_card[0]}
)}
- {actionState.db_error === "id_card" && (
+ {actionState?.db_error === "id_card" && (
- {actionState.message}
+ {actionState?.message}
)}
@@ -128,9 +128,9 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
))}
- {actionState.errors?.fieldErrors?.atoll_id && (
+ {actionState?.errors?.fieldErrors?.atoll_id && (
- {actionState.errors?.fieldErrors?.atoll_id}
+ {actionState?.errors?.fieldErrors?.atoll_id}
)}
@@ -153,9 +153,9 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
))}
- {actionState.errors?.fieldErrors?.island_id && (
+ {actionState?.errors?.fieldErrors?.island_id && (
- {actionState.errors?.fieldErrors?.island_id}
+ {actionState?.errors?.fieldErrors?.island_id}
)}
@@ -169,20 +169,20 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
- {actionState.errors?.fieldErrors?.address && (
+ {actionState?.errors?.fieldErrors?.address && (
- {actionState.errors?.fieldErrors?.address}
+ {actionState?.errors?.fieldErrors?.address}
)}
@@ -194,17 +194,17 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
- {actionState.errors?.fieldErrors?.dob && (
+ {actionState?.errors?.fieldErrors?.dob && (
- {actionState.errors?.fieldErrors?.dob}
+ {actionState?.errors?.fieldErrors?.dob}
)}
@@ -216,17 +216,17 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
- {actionState.errors?.fieldErrors.accNo && (
+ {actionState?.errors?.fieldErrors.accNo && (
- {actionState.errors?.fieldErrors.accNo}
+ {actionState?.errors?.fieldErrors.accNo}
)}
@@ -241,7 +241,7 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
disabled={isPending}
className={cn(
!phoneNumberFromUrl &&
- actionState.errors?.fieldErrors?.phone_number &&
+ actionState?.errors?.fieldErrors?.phone_number &&
"border-2 border-red-500 rounded-md",
)}
defaultValue={NUMBER_WITHOUT_DASH ?? ""}
@@ -251,19 +251,19 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
{actionState?.errors?.fieldErrors?.phone_number?.[0] && (
- {actionState.errors.fieldErrors.phone_number[0]}
+ {actionState?.errors.fieldErrors.phone_number[0]}
)}
- {actionState.db_error === "phone_number" && (
+ {actionState?.db_error === "phone_number" && (
- {actionState.message}
+ {actionState?.message}
)}
- {actionState.errors?.fieldErrors?.terms && (
+ {actionState?.errors?.fieldErrors?.terms && (
- {actionState.errors?.fieldErrors?.terms}
+ {actionState?.errors?.fieldErrors?.terms}
)}
- {actionState.errors?.fieldErrors?.policy && (
+ {actionState?.errors?.fieldErrors?.policy && (
- {actionState.errors?.fieldErrors?.policy}
+ {actionState?.errors?.fieldErrors?.policy}
)}
diff --git a/components/input-read-only.tsx b/components/input-read-only.tsx
index 06af355..a9335de 100644
--- a/components/input-read-only.tsx
+++ b/components/input-read-only.tsx
@@ -1,9 +1,10 @@
+import { cn } from '@/lib/utils'
import React from 'react'
-export default function InputReadOnly({ label, value }: { label: string, value?: string }) {
+export default function InputReadOnly({ label, value, labelClassName, className }: { label: string, value: string, labelClassName?: string, className?: string }) {
return (
-
-