diff --git a/actions/auth-actions.ts b/actions/auth-actions.ts index d6f6ead..d7d65e5 100644 --- a/actions/auth-actions.ts +++ b/actions/auth-actions.ts @@ -1,227 +1,229 @@ "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"; +import { signUpFormSchema } from "@/lib/schemas"; +import { + backendRegister, + checkIdOrPhone, + checkTempIdOrPhone, +} from "@/queries/authentication"; +import { handleApiResponse, tryCatch } from "@/utils/tryCatch"; + const formSchema = z.object({ - phoneNumber: z - .string() - .regex(/^[7|9][0-9]{2}-[0-9]{4}$/, "Please enter a valid phone number"), + 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; + ok: boolean; + verified: boolean; }; export type FilterTempUserResponse = { - ok: boolean; - otp_verified: boolean; + ok: boolean; + otp_verified: boolean; + t_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); +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 (!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 }); + 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 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); + 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}`); + 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; + 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 + 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); + 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", - }; - } + 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 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 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 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); + 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" }; + 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; + // 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"); + 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"); } diff --git a/queries/authentication.ts b/queries/authentication.ts index efbe42f..144840c 100644 --- a/queries/authentication.ts +++ b/queries/authentication.ts @@ -1,218 +1,201 @@ "use server"; -import { - type ActionState, - type FilterTempUserResponse, - type FilterUserResponse, - backendMobileLogin, +import { z } from "zod"; +import type { + ActionState, + FilterTempUserResponse, + FilterUserResponse, } from "@/actions/auth-actions"; import type { TAuthUser, User } from "@/lib/types/user"; import axiosInstance from "@/utils/axiosInstance"; -import { handleApiResponse, tryCatch } from "@/utils/tryCatch"; -import { redirect } from "next/navigation"; -import { z } from "zod"; +import { handleApiResponse } from "@/utils/tryCatch"; export async function login({ - password, - username, + password, + username, }: { - username: string; - password: string; + username: string; + password: string; }): Promise { - const response = await axiosInstance - .post("/auth/login/", { - username: username, - password: password, - }) - .then((res) => { - console.log(res); - return res.data; // Return the data from the response - }) - .catch((err) => { - console.log(err.response); - throw err; // Throw the error to maintain the Promise rejection - }); + const response = await axiosInstance + .post("/auth/login/", { + username: username, + password: password, + }) + .then((res) => { + console.log(res); + return res.data; // Return the data from the response + }) + .catch((err) => { + console.log(err.response); + throw err; // Throw the error to maintain the Promise rejection + }); - return response; + return response; } export async function logout({ token }: { token: string }) { - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/auth/logout/`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Token ${token}`, // Include the token for authentication - }, - }, - ); + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/auth/logout/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Token ${token}`, // Include the token for authentication + }, + }, + ); - if (response.status !== 204) { - throw new Error("Failed to log out from the backend"); - } - console.log("logout res in backend", response); + if (response.status !== 204) { + throw new Error("Failed to log out from the backend"); + } + console.log("logout res in backend", response); - // Since the API endpoint returns 204 No Content on success, we don't need to parse JSON - return null; // Return null to indicate a successful logout with no content + // Since the API endpoint returns 204 No Content on success, we don't need to parse JSON + return null; // Return null to indicate a successful logout with no content } export async function checkIdOrPhone({ - id_card, - phone_number, + id_card, + phone_number, }: { - id_card?: string; - phone_number?: string; + id_card?: string; + phone_number?: string; }) { - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?id_card=${id_card}&mobile=${phone_number}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }, - ); - const data = (await response.json()) as FilterUserResponse; - return data; + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?id_card=${id_card}&mobile=${phone_number}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }, + ); + const data = (await response.json()) as FilterUserResponse; + return data; } export async function checkTempIdOrPhone({ - id_card, - phone_number, + id_card, + phone_number, }: { - id_card?: string; - phone_number?: string; + id_card?: string; + phone_number?: string; }) { - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/users/temp/filter/?id_card=${id_card}&mobile=${phone_number}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }, - ); - const data = (await response.json()) as FilterTempUserResponse; - return data; + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/users/temp/filter/?id_card=${id_card}&mobile=${phone_number}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }, + ); + const data = (await response.json()) as FilterTempUserResponse; + return data; } type TSignupUser = Pick< - User, - "username" | "address" | "mobile" | "id_card" | "dob" + User, + "username" | "address" | "mobile" | "id_card" | "dob" > & { - firstname: string; - lastname: string; - atoll: number; - island: number; - acc_no: string; - terms_accepted: boolean; - policy_accepted: boolean; + firstname: string; + lastname: string; + atoll: number; + island: number; + acc_no: string; + terms_accepted: boolean; + policy_accepted: boolean; }; export async function backendRegister({ payload }: { payload: TSignupUser }) { - console.log("backendRegister payload", payload); - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/register/`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(payload), - }, - ); - console.log("backendRegister response", response); - return handleApiResponse<{ t_username: string }>(response, "backendRegister"); + console.log("backendRegister payload", payload); + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/register/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + }, + ); + console.log("backendRegister response", response); + return handleApiResponse<{ t_username: string }>(response, "backendRegister"); } const formSchema = z.object({ - mobile: z.string().regex(/^[79]\d{6}$/, "Please enter a valid phone number"), - otp: z - .string() - .min(6, { - message: "OTP is required.", - }) - .max(6, { - message: "OTP is required.", - }), + mobile: z.string().regex(/^[79]\d{6}$/, "Please enter a valid phone number"), + otp: z + .string() + .min(6, { + message: "OTP is required.", + }) + .max(6, { + message: "OTP is required.", + }), }); export async function VerifyRegistrationOTP( - _actionState: ActionState, - formData: FormData, + _actionState: ActionState, + formData: FormData, ) { - const formValues = Object.fromEntries(formData.entries()); - const result = formSchema.safeParse(formValues); - console.log("formValues", formValues); - if (!result.success) { - return { - message: result.error.errors[0].message, // Get the error message from Zod - status: "error", - }; - } + const formValues = Object.fromEntries(formData.entries()); + const result = formSchema.safeParse(formValues); + console.log("formValues", formValues); + if (!result.success) { + return { + message: result.error.errors[0].message, // Get the error message from Zod + status: "error", + }; + } - if (formValues.otp === "") { - return { - message: "OTP is required.", - status: "error", - }; - } + if (formValues.otp === "") { + return { + message: "OTP is required.", + status: "error", + }; + } - const { mobile, otp } = formValues; + const { mobile, otp } = formValues; - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/register/verify/`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - mobile: mobile, - otp: otp as string, - }), - }, - ); - const data = (await response.json()) as { message: string }; + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/register/verify/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + mobile: mobile, + otp: otp as string, + }), + }, + ); + const responseJson = await response.json(); + console.log("responseJson", responseJson); + const data = responseJson as { message: string; verified: boolean }; - const [error, userVerified] = await tryCatch( - checkIdOrPhone({ phone_number: mobile as string }), - ); - - if (error) { - return { - message: - "There was an error fetching your account information. Please contact support.", - status: "user_check_error", - }; - } - if (userVerified.verified) { - return { - message: - "Your account has been successfully verified! You may login now.", - status: "verify_success", - }; - // const [mobileLoginError, mobileLoginResponse] = await tryCatch( - // backendMobileLogin({ mobile: mobile as string }), - // ); - // if (mobileLoginError) { - // return { - // message: "Login Failed. Please contact support.", - // status: "login_error", - // }; - // } - // if (mobileLoginResponse) { - // redirect(`/auth/verify-otp?phone_number=${mobile}`); - // } - } - if (data.message === "User created successfully.") { - return { - message: - "Your account could not be verified. Please wait for you verification to be processed.", - status: "verify_error", - }; - } - return { - message: data.message, - status: "otp_error", - }; + if (data.verified) { + return { + message: + "Your account has been successfully verified! You may login now.", + status: "verify_success", + }; + // const [mobileLoginError, mobileLoginResponse] = await tryCatch( + // backendMobileLogin({ mobile: mobile as string }), + // ); + // if (mobileLoginError) { + // return { + // message: "Login Failed. Please contact support.", + // status: "login_error", + // }; + // } + // if (mobileLoginResponse) { + // redirect(`/auth/verify-otp?phone_number=${mobile}`); + // } + } + return { + message: + "Your account could not be verified. Please wait for you verification to be processed.", + status: "verify_error", + }; }