// type PayloadAction = { // type: string; // payload: T; // } import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import axios from "axios"; import AsyncStorage from "@react-native-async-storage/async-storage"; import * as SecureStore from "expo-secure-store"; import urls, { STORAGE_KEYS, MESSAGES, StatusType, AUTH_STATUSES, } from "../constants/config"; interface AuthState { phone: string | null; otpId: number | null; isLoggedIn: boolean; status: StatusType; sendOTPError: string | null; verifyOTPError: string | null; generalError: string | null; } interface SendOTPResponse { status: boolean; message: string; data: { otpId: number; }; } interface VerifyOTPResponse { status: boolean; message: string; token: string; refreshToken: string; } interface SendOTPParams { phone: string | null; } interface VerifyOTPParams { phone: string | null; otp: string | null; otpId: number | null; } const initialState: AuthState = { phone: null, otpId: null, isLoggedIn: false, status: AUTH_STATUSES.IDLE, sendOTPError: null, verifyOTPError: null, generalError: null, }; //async thunk to send otp export const sendOTP = createAsyncThunk( "auth/sendOTP", async (params, { rejectWithValue }) => { try { console.log(urls.BASE_URL, "BASE_URL"); // const response = await axios.post( // `${urls.BASE_URL}/send-otp`, // params // ); // return response.data; return { status: true, message: "Done", data: { otpId: 22, }, }; // if (!response.data.status) throw new Error(response.data.message); } catch (error: any) { return rejectWithValue(error.response?.data?.message || error.message); } } ); export const verifyOTP = createAsyncThunk( "auth/verifyOTP", async (params, { rejectWithValue }) => { try { const response = await axios.post( `${urls.BASE_URL}/verify-otp`, params ); if (!response.data.status) throw new Error(response.data.message); // Store tokens await AsyncStorage.setItem(STORAGE_KEYS.AUTH_TOKEN, response.data.token); await SecureStore.setItemAsync( STORAGE_KEYS.REFRESH_TOKEN, response.data.refreshToken ); return response.data; } catch (error: any) { return rejectWithValue(MESSAGES.AUTHENTICATION.VERIFICATION_FAILED); } } ); export const logout = createAsyncThunk( "auth/logout", async (_, { dispatch }) => { await AsyncStorage.removeItem(STORAGE_KEYS.AUTH_TOKEN); await SecureStore.deleteItemAsync(STORAGE_KEYS.REFRESH_TOKEN); dispatch(authSlice.actions.logout()); } ); const authSlice = createSlice({ name: "auth", initialState, reducers: { loginRequest: (state) => { state.status = AUTH_STATUSES.LOADING; }, loginSuccess: (state, action) => { state.status = AUTH_STATUSES.SUCCESS; state.isLoggedIn = true; // Set logged-in state to true }, setIsLoggedIn: (state, action) => { state.isLoggedIn = action.payload; }, loginFailure: (state, action: PayloadAction) => { state.status = AUTH_STATUSES.FAILED; state.generalError = action.payload; }, logout: (state) => { state.isLoggedIn = false; }, clearSendOTPError: (state) => { state.sendOTPError = null; }, clearVerifyOTPError: (state) => { state.verifyOTPError = null; }, clearAllErrors: (state) => { state.sendOTPError = null; state.verifyOTPError = null; state.generalError = null; }, }, extraReducers: (builder) => { builder .addCase(sendOTP.pending, (state) => { state.status = AUTH_STATUSES.LOADING; state.sendOTPError = null; }) .addCase(sendOTP.fulfilled, (state, action) => { state.status = AUTH_STATUSES.SUCCESS; state.otpId = action.payload.data.otpId; state.phone = action.meta.arg.phone; state.sendOTPError = null; }) .addCase(sendOTP.rejected, (state, action) => { state.status = AUTH_STATUSES.FAILED; state.sendOTPError = action.error.message || "Failed to send OTP"; }) .addCase(verifyOTP.pending, (state) => { state.status = AUTH_STATUSES.LOADING; state.verifyOTPError = null; }) .addCase(verifyOTP.fulfilled, (state, action) => { state.status = AUTH_STATUSES.SUCCESS; state.isLoggedIn = true; state.verifyOTPError = null; const token = action.payload.token; AsyncStorage.setItem(STORAGE_KEYS.AUTH_TOKEN, token).catch((error) => { console.log("Error storing token", error); }); const refreshToken = action.payload.refreshToken; SecureStore.setItemAsync( STORAGE_KEYS.REFRESH_TOKEN, refreshToken ).catch((error) => { console.log("Error storing refresh token", error); }); }) .addCase(verifyOTP.rejected, (state, action) => { state.status = AUTH_STATUSES.FAILED; state.verifyOTPError = action.error.message || "Failed to verify OTP"; }) .addCase(logout.pending, (state) => { state.status = AUTH_STATUSES.LOADING; }) .addCase(logout.fulfilled, (state) => { state.otpId = null; state.isLoggedIn = false; state.status = AUTH_STATUSES.IDLE; state.verifyOTPError = null; state.generalError = null; state.sendOTPError = null; state.phone = null; }) .addCase(logout.rejected, (state, action) => { state.status = AUTH_STATUSES.FAILED; state.generalError = action.error.message || "Failed to log out"; }); }, }); export const { logout: localLogout, clearSendOTPError, clearVerifyOTPError, clearAllErrors, } = authSlice.actions; export default authSlice.reducer;