mirror of
				https://github.com/i701/sarlink-portal.git
				synced 2025-10-31 09:56:59 +00:00 
			
		
		
		
	
		
			All checks were successful
		
		
	
	Build and Push Docker Images / Build and Push Docker Images (push) Successful in 5m17s
				
			
		
			
				
	
	
		
			228 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| "use server";
 | |
| 
 | |
| import { signUpFormSchema } from "@/lib/schemas";
 | |
| import {
 | |
| 	backendRegister,
 | |
| 	checkIdOrPhone,
 | |
| 	checkTempIdOrPhone,
 | |
| } from "@/queries/authentication";
 | |
| import { handleApiResponse, tryCatch } from "@/utils/tryCatch";
 | |
| import { redirect } from "next/navigation";
 | |
| import { z } from "zod";
 | |
| const formSchema = z.object({
 | |
| 	phoneNumber: z
 | |
| 		.string()
 | |
| 		.regex(/^[7|9][0-9]{2}-[0-9]{4}$/, "Please enter a valid phone number"),
 | |
| });
 | |
| 
 | |
| export type FilterUserResponse = {
 | |
| 	ok: boolean;
 | |
| 	verified: boolean;
 | |
| };
 | |
| export type FilterTempUserResponse = {
 | |
| 	ok: boolean;
 | |
| 	otp_verified: boolean;
 | |
| };
 | |
| 
 | |
| 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 FORMATTED_MOBILE_NUMBER: string = `${phoneNumber.split("-").join("")}`;
 | |
| 	console.log({ FORMATTED_MOBILE_NUMBER });
 | |
| 
 | |
| 	const user = await fetch(
 | |
| 		`${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?mobile=${FORMATTED_MOBILE_NUMBER}`,
 | |
| 		{
 | |
| 			method: "GET",
 | |
| 			headers: {
 | |
| 				"Content-Type": "application/json",
 | |
| 			},
 | |
| 		},
 | |
| 	);
 | |
| 	const userData = (await user.json()) as FilterUserResponse;
 | |
| 	console.log({ userData });
 | |
| 	if (!userData.ok) {
 | |
| 		redirect(`/auth/signup?phone_number=${phoneNumber}`);
 | |
| 	}
 | |
| 	if (!userData.verified) {
 | |
| 		return {
 | |
| 			message:
 | |
| 				"Your account is on pending verification. Please wait for a response from admin or contact shihaam.",
 | |
| 			status: "error",
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	const sendOTPResponse = await fetch(
 | |
| 		`${process.env.SARLINK_API_BASE_URL}/auth/mobile/`,
 | |
| 		{
 | |
| 			method: "POST",
 | |
| 			headers: {
 | |
| 				"Content-Type": "application/json",
 | |
| 			},
 | |
| 			body: JSON.stringify({
 | |
| 				mobile: FORMATTED_MOBILE_NUMBER,
 | |
| 			}),
 | |
| 		},
 | |
| 	);
 | |
| 	const otpResponse = await sendOTPResponse.json();
 | |
| 	console.log("otpResponse", otpResponse);
 | |
| 
 | |
| 	redirect(`/auth/verify-otp?phone_number=${FORMATTED_MOBILE_NUMBER}`);
 | |
| }
 | |
| 
 | |
| export type ActionState = {
 | |
| 	status?: string;
 | |
| 	payload?: FormData;
 | |
| 	errors?: z.typeToFlattenedError<
 | |
| 		{
 | |
| 			id_card: string;
 | |
| 			phone_number: string;
 | |
| 			name: string;
 | |
| 			atoll_id: string;
 | |
| 			island_id: string;
 | |
| 			address: string;
 | |
| 			dob: Date;
 | |
| 			terms: string;
 | |
| 			policy: string;
 | |
| 			accNo: string;
 | |
| 		},
 | |
| 		string
 | |
| 	>;
 | |
| 	db_error?: string;
 | |
| 	error?: string;
 | |
| };
 | |
| 
 | |
| 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
 | |
| 
 | |
| 	console.log("DATA ON SERVER SIDE", data);
 | |
| 
 | |
| 	if (!parsedData.success) {
 | |
| 		return {
 | |
| 			message: "Invalid form data",
 | |
| 			payload: formData,
 | |
| 			errors: parsedData.error.flatten(),
 | |
| 		};
 | |
| 	}
 | |
| 	const age =
 | |
| 		new Date().getFullYear() - new Date(parsedData.data.dob).getFullYear();
 | |
| 	if (age < 18) {
 | |
| 		return {
 | |
| 			message: "You must be at least 18 years old to register.",
 | |
| 			payload: formData,
 | |
| 			db_error: "dob",
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	const idCardExists = await checkIdOrPhone({
 | |
| 		id_card: parsedData.data.id_card,
 | |
| 	});
 | |
| 	if (idCardExists.ok) {
 | |
| 		return {
 | |
| 			message: "ID card already exists.",
 | |
| 			payload: formData,
 | |
| 			db_error: "id_card",
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	const phoneNumberExists = await checkIdOrPhone({
 | |
| 		phone_number: parsedData.data.phone_number,
 | |
| 	});
 | |
| 
 | |
| 	const tempPhoneNumberExists = await checkTempIdOrPhone({
 | |
| 		phone_number: parsedData.data.phone_number,
 | |
| 	});
 | |
| 	if (phoneNumberExists.ok || tempPhoneNumberExists.ok) {
 | |
| 		return {
 | |
| 			message: "Phone number already exists.",
 | |
| 			payload: formData,
 | |
| 			db_error: "phone_number",
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	const [signupError, signupResponse] = await tryCatch(
 | |
| 		backendRegister({
 | |
| 			payload: {
 | |
| 				firstname: parsedData.data.name.split(" ")[0],
 | |
| 				lastname: parsedData.data.name.split(" ").slice(1).join(" "),
 | |
| 				username: parsedData.data.phone_number,
 | |
| 				address: parsedData.data.address,
 | |
| 				id_card: parsedData.data.id_card,
 | |
| 				dob: new Date(parsedData.data.dob).toISOString().split("T")[0],
 | |
| 				mobile: parsedData.data.phone_number,
 | |
| 				island: Number.parseInt(parsedData.data.island_id),
 | |
| 				atoll: Number.parseInt(parsedData.data.atoll_id),
 | |
| 				acc_no: parsedData.data.accNo,
 | |
| 				terms_accepted: parsedData.data.terms,
 | |
| 				policy_accepted: parsedData.data.policy,
 | |
| 			},
 | |
| 		}),
 | |
| 	);
 | |
| 	if (signupError) {
 | |
| 		return {
 | |
| 			message: signupError.message,
 | |
| 			payload: formData,
 | |
| 			db_error: "phone_number",
 | |
| 		};
 | |
| 	}
 | |
| 	console.log("SIGNUP RESPONSE", signupResponse);
 | |
| 
 | |
| 	redirect(
 | |
| 		`/auth/verify-otp-registration?phone_number=${encodeURIComponent(signupResponse.t_username)}`,
 | |
| 	);
 | |
| 	return { message: "User created successfully", error: "success" };
 | |
| }
 | |
| 
 | |
| 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;
 | |
| };
 | |
| 
 | |
| export async function backendMobileLogin({ mobile }: { mobile: string }) {
 | |
| 	const response = await fetch(
 | |
| 		`${process.env.SARLINK_API_BASE_URL}/auth/mobile/`,
 | |
| 		{
 | |
| 			method: "POST",
 | |
| 			headers: {
 | |
| 				"Content-Type": "application/json",
 | |
| 			},
 | |
| 			body: JSON.stringify({
 | |
| 				mobile,
 | |
| 			}),
 | |
| 		},
 | |
| 	);
 | |
| 	return handleApiResponse<{ detail: string }>(response, "backendMobileLogin");
 | |
| }
 |