mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-02-22 17:02:01 +00:00
- Updated `next.config.ts` to include remote image patterns for user verification. - Introduced `VerifyUserDetails` function in `lib/person.ts` to validate user data against national records. - Added `usePerson` hook for fetching national data based on ID card. - Enhanced `signup` and `signin` functions in `auth-actions.ts` to handle user verification status and send notifications for pending verifications. - Refactored `VerifyUser` function in `user-actions.ts` to incorporate national data validation. - Improved UI components in the user verification page to display both database and national information. - Updated `InputReadOnly` component to support customizable label classes for better styling. These changes improve the user verification process, ensuring data integrity and enhancing the overall user experience.
188 lines
4.9 KiB
TypeScript
188 lines
4.9 KiB
TypeScript
"use server";
|
|
|
|
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()
|
|
.regex(/^[7|9][0-9]{2}-[0-9]{4}$/, "Please enter a valid phone number"),
|
|
});
|
|
|
|
export async function signin(previousState: ActionState, formData: FormData) {
|
|
const phoneNumber = formData.get("phoneNumber") as string;
|
|
const result = formSchema.safeParse({ phoneNumber });
|
|
console.log(phoneNumber);
|
|
|
|
if (!result.success) {
|
|
return {
|
|
message: result.error.errors[0].message, // Get the error message from Zod
|
|
status: "error",
|
|
};
|
|
}
|
|
|
|
if (!phoneNumber) {
|
|
return {
|
|
message: "Please enter a phone number",
|
|
status: "error",
|
|
};
|
|
}
|
|
const NUMBER_WITH_COUNTRY_CODE: string = `+960${phoneNumber.split("-").join("")}`;
|
|
|
|
const userExists = await prisma.user.findUnique({
|
|
where: {
|
|
phoneNumber: NUMBER_WITH_COUNTRY_CODE,
|
|
},
|
|
});
|
|
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,
|
|
});
|
|
redirect(
|
|
`/verify-otp?phone_number=${encodeURIComponent(NUMBER_WITH_COUNTRY_CODE)}`,
|
|
);
|
|
}
|
|
|
|
type ActionState = {
|
|
message: string;
|
|
payload?: FormData;
|
|
};
|
|
|
|
export async function signup(_actionState: ActionState, formData: FormData) {
|
|
const data = Object.fromEntries(formData.entries());
|
|
const parsedData = signUpFormSchema.safeParse(data);
|
|
// get phone number from /signup?phone_number=999-1231
|
|
const headersList = await headers();
|
|
const referer = headersList.get("referer");
|
|
const number = referer?.split("?")[1]?.split("=")[1];
|
|
let NUMBER_WITH_COUNTRY_CODE: string;
|
|
|
|
console.log(data);
|
|
|
|
if (!parsedData.success) {
|
|
return {
|
|
message: "Invalid form data",
|
|
payload: formData,
|
|
errors: parsedData.error.flatten(),
|
|
};
|
|
}
|
|
|
|
if (number) {
|
|
NUMBER_WITH_COUNTRY_CODE = `+960${number.split("-").join("")}`;
|
|
} else {
|
|
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,
|
|
},
|
|
});
|
|
|
|
if (idCardExists) {
|
|
return {
|
|
message: "ID card already exists.",
|
|
payload: formData,
|
|
db_error: "id_card",
|
|
};
|
|
}
|
|
|
|
const phoneNumberExists = await prisma.user.findFirst({
|
|
where: {
|
|
phoneNumber: NUMBER_WITH_COUNTRY_CODE,
|
|
},
|
|
});
|
|
|
|
if (phoneNumberExists) {
|
|
return {
|
|
message: "Phone number already exists.",
|
|
payload: formData,
|
|
db_error: "phone_number",
|
|
};
|
|
}
|
|
|
|
const newUser = await prisma.user.create({
|
|
data: {
|
|
name: parsedData.data.name,
|
|
islandId: parsedData.data.island_id,
|
|
atollId: parsedData.data.atoll_id,
|
|
address: parsedData.data.address,
|
|
id_card: parsedData.data.id_card,
|
|
dob: new Date(parsedData.data.dob),
|
|
role: "USER",
|
|
accNo: parsedData.data.accNo,
|
|
phoneNumber: NUMBER_WITH_COUNTRY_CODE,
|
|
},
|
|
});
|
|
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: "User created successfully" };
|
|
}
|
|
|
|
export const sendOtp = async (phoneNumber: string, code: string) => {
|
|
// Implement sending OTP code via SMS
|
|
console.log("Send OTP server fn", phoneNumber, code);
|
|
const respose = await fetch(`${process.env.SMS_API_BASE_URL}/api/sms`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${process.env.SMS_API_KEY}`,
|
|
},
|
|
body: JSON.stringify({
|
|
check_delivery: false,
|
|
number: phoneNumber,
|
|
message: `Your OTP code is ${code}`,
|
|
}),
|
|
});
|
|
const data = await respose.json();
|
|
console.log(data);
|
|
return data;
|
|
};
|