sarlink-portal/actions/auth-actions.ts
i701 2c67848618
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m24s
Enhance user verification and UI components
- Updated `auth-actions.ts` to improve user verification notification formatting and date handling.
- Modified `layout.tsx` to support dark mode styling for better user experience.
- Refactored `signup/page.tsx` to enhance layout and responsiveness.
- Introduced a new API route in `route.ts` for sending user verification notifications.
- Improved user feedback in `user-payments-table.tsx` by updating the no payment message.
- Made minor adjustments in `application-layout.tsx` for consistent padding.
- Enhanced `signup-form.tsx` to display error messages for invalid user validation.

These changes improve the user verification process, enhance UI consistency, and provide better feedback to users.
2025-01-10 23:34:53 +05:00

191 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. \n
USER DETAILS:
Name: ${parsedData.data.name}
Address: ${parsedData.data.address}
ID Card: ${parsedData.data.id_card}
DOB: ${parsedData.data.dob.toLocaleDateString("en-US", {
month: "short",
day: "2-digit",
year: "numeric",
})}
ACC No: ${parsedData.data.accNo}\n\nVerify 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;
};