Add s s 8854yh499j40440
This commit is contained in:
parent
e5f8e7519d
commit
63a785ba5a
@ -1,110 +1,62 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useAppSelector } from "@/redux/store"
|
import { useAppSelector } from "@/redux/store"
|
||||||
import { isLoggedIn, mountCheckIfValid, logOut } from "@/redux/features/auth-slice";
|
import { isLoggedIn , mountCheckIfValid } from "@/redux/features/auth-slice";
|
||||||
import { useDispatch } from "react-redux"
|
import { useDispatch } from "react-redux"
|
||||||
import { AppDispatch } from '@/redux/store';
|
import { AppDispatch } from '@/redux/store';
|
||||||
import { useEffect, useCallback } from "react";
|
import { useEffect } from "react";
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import FullScreenLoader from "@/components/common/fullScreenLoader";
|
import FullScreenLoader from "@/components/common/fullScreenLoader";
|
||||||
import { load } from '@/redux/features/settings-slice'
|
import { load } from '@/redux/features/settings-slice'
|
||||||
import ErrorBoundary from '@/components/common/ErrorBoundary';
|
|
||||||
import axios from 'axios'; // Added axios import
|
|
||||||
|
|
||||||
// HOC for auth pages (only accept auth user)
|
// HOC for auth pages ( only accept auth user )
|
||||||
export default function LocaleLayout({ children }: { children: ReactNode }) {
|
export default function LocaleLayout({children} : { children : ReactNode }) {
|
||||||
const router = useRouter();
|
|
||||||
|
const router = useRouter()
|
||||||
const dispatch = useDispatch<AppDispatch>();
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
|
// load states
|
||||||
// Load states
|
const isValid = useAppSelector((state) => state.authReducer.value.isValid)
|
||||||
const isValid = useAppSelector((state) => state.authReducer.value.isValid);
|
const checkIfValidMounted = useAppSelector((state) => state.authReducer.value.checkIfValidMounted)
|
||||||
const checkIfValidMounted = useAppSelector((state) => state.authReducer.value.checkIfValidMounted);
|
const notAuthRedirectPage = useAppSelector((state) => state.settingsReducer.value.notAuthRedirectPage)
|
||||||
const notAuthRedirectPage = useAppSelector((state) => state.settingsReducer.value.notAuthRedirectPage);
|
const isLoadingSettings = useAppSelector((state) => state.settingsReducer.value.isLoadingSettings)
|
||||||
const isLoadingSettings = useAppSelector((state) => state.settingsReducer.value.isLoadingSettings);
|
const loadedFirstTime = useAppSelector((state) => state.settingsReducer.value.loadedFirstTime)
|
||||||
const loadedFirstTime = useAppSelector((state) => state.settingsReducer.value.loadedFirstTime);
|
// Get redux states
|
||||||
|
// init isLoggedIn
|
||||||
// Handle not logged in state
|
|
||||||
const handleNotLoggedIn = useCallback(() => {
|
|
||||||
// Clear any invalid token from cookies
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
// Clear Redux state
|
|
||||||
dispatch(logOut());
|
|
||||||
// Redirect to login page
|
|
||||||
router.push(notAuthRedirectPage);
|
|
||||||
}, [notAuthRedirectPage, router, dispatch]);
|
|
||||||
|
|
||||||
// Initialize auth check
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (checkIfValidMounted) return;
|
if(checkIfValidMounted) return
|
||||||
|
dispatch(mountCheckIfValid())
|
||||||
const checkAuth = async () => {
|
async function a()
|
||||||
try {
|
{
|
||||||
await dispatch(mountCheckIfValid());
|
await dispatch(isLoggedIn({NotLoggedInCallback}))
|
||||||
await dispatch(isLoggedIn({ NotLoggedInCallback: handleNotLoggedIn }));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Auth check failed:', error);
|
|
||||||
handleNotLoggedIn();
|
|
||||||
}
|
}
|
||||||
};
|
a()
|
||||||
|
}, [])
|
||||||
checkAuth();
|
// load settings
|
||||||
}, [checkIfValidMounted, dispatch, handleNotLoggedIn]);
|
|
||||||
|
|
||||||
// Load settings
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loadedFirstTime || isLoadingSettings) return;
|
if(loadedFirstTime) return
|
||||||
|
if(isLoadingSettings) return
|
||||||
const loadSettings = async () => {
|
async function a()
|
||||||
try {
|
{
|
||||||
await dispatch(load({ page: 1 }));
|
await dispatch(load({page : 1}))
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load settings:', error);
|
|
||||||
}
|
}
|
||||||
};
|
a()
|
||||||
|
}, [])
|
||||||
loadSettings();
|
// if wasnt logged in this will fire
|
||||||
}, [loadedFirstTime, isLoadingSettings, dispatch]);
|
function NotLoggedInCallback()
|
||||||
|
{
|
||||||
// Add global error handler for API requests
|
return router.push(notAuthRedirectPage)
|
||||||
useEffect(() => {
|
|
||||||
const responseInterceptor = (response: any) => response;
|
|
||||||
|
|
||||||
const errorInterceptor = (error: any) => {
|
|
||||||
if (error.response?.status === 401) {
|
|
||||||
// Handle unauthorized (token expired/invalid)
|
|
||||||
handleNotLoggedIn();
|
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add request interceptor
|
|
||||||
const requestInterceptor = axios.interceptors.request.use(
|
|
||||||
config => config,
|
|
||||||
error => Promise.reject(error)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add response interceptor
|
|
||||||
const responseIntercept = axios.interceptors.response.use(
|
|
||||||
responseInterceptor,
|
|
||||||
errorInterceptor
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cleanup function
|
|
||||||
return () => {
|
|
||||||
axios.interceptors.request.eject(requestInterceptor);
|
|
||||||
axios.interceptors.response.eject(responseIntercept);
|
|
||||||
};
|
|
||||||
}, [handleNotLoggedIn]);
|
|
||||||
|
|
||||||
// Show loading state while checking auth
|
|
||||||
if (isValid === null) {
|
|
||||||
return <FullScreenLoader />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<>
|
||||||
{isValid ? children : <FullScreenLoader />}
|
{
|
||||||
</ErrorBoundary>
|
isValid ?
|
||||||
|
<>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
<FullScreenLoader />
|
||||||
|
}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import { NextResponse } from 'next/server';
|
|
||||||
import { cookies } from 'next/headers';
|
|
||||||
import jwt from 'jsonwebtoken';
|
|
||||||
import { dbConnect } from '@/lib/dbConnect';
|
|
||||||
import User from '@/database/models/userModel';
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
try {
|
|
||||||
await dbConnect();
|
|
||||||
|
|
||||||
// Get the token from cookies
|
|
||||||
const cookieStore = cookies();
|
|
||||||
const token = cookieStore.get('authToken')?.value;
|
|
||||||
|
|
||||||
if (!token) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ valid: false, message: 'No token provided' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Verify the token
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
|
|
||||||
|
|
||||||
// Check if user still exists
|
|
||||||
const user = await User.findById(decoded.userId).select('-password');
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ valid: false, message: 'User not found' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json({ valid: true });
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof jwt.TokenExpiredError) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ valid: false, message: 'Token expired' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(
|
|
||||||
{ valid: false, message: 'Invalid token' },
|
|
||||||
{ status: 401 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Token verification error:', error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ valid: false, message: 'Server error' },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { Component, ErrorInfo, ReactNode } from 'react';
|
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children: ReactNode;
|
|
||||||
fallback?: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State {
|
|
||||||
hasError: boolean;
|
|
||||||
error?: Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ErrorBoundary extends Component<Props, State> {
|
|
||||||
public state: State = {
|
|
||||||
hasError: false
|
|
||||||
};
|
|
||||||
|
|
||||||
public static getDerivedStateFromError(error: Error): State {
|
|
||||||
return { hasError: true, error };
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
||||||
console.error('Uncaught error:', error, errorInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleReset = () => {
|
|
||||||
// Clear auth token and reload
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
window.location.href = '/';
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
if (this.state.hasError) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-center min-h-screen p-4">
|
|
||||||
<div className="text-center max-w-md">
|
|
||||||
<h2 className="text-2xl font-bold mb-4">
|
|
||||||
{this.state.error?.message === 'Session expired' ? 'Session Expired' : 'Something went wrong'}
|
|
||||||
</h2>
|
|
||||||
<p className="mb-6 text-gray-600 dark:text-gray-300">
|
|
||||||
{this.state.error?.message === 'Session expired'
|
|
||||||
? 'Your session has expired. Please log in again.'
|
|
||||||
: 'An unexpected error occurred. Please try again.'}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
onClick={this.handleReset}
|
|
||||||
className="px-6 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors"
|
|
||||||
>
|
|
||||||
Return to Home
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.props.children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ErrorBoundary;
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
||||||
import { store } from '@/redux/store';
|
|
||||||
import { logOut } from '@/redux/features/auth-slice';
|
|
||||||
|
|
||||||
const api: AxiosInstance = axios.create({
|
|
||||||
baseURL: '/api',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Request interceptor to add auth token
|
|
||||||
api.interceptors.request.use(
|
|
||||||
(config) => {
|
|
||||||
const token = store.getState().authReducer.value.authToken;
|
|
||||||
if (token) {
|
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Response interceptor to handle 401 errors
|
|
||||||
api.interceptors.response.use(
|
|
||||||
(response: AxiosResponse) => response,
|
|
||||||
async (error: AxiosError) => {
|
|
||||||
const originalRequest = error.config as any;
|
|
||||||
|
|
||||||
// If the error is 401 and we haven't tried to refresh yet
|
|
||||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
||||||
originalRequest._retry = true;
|
|
||||||
|
|
||||||
// Clear any existing auth state
|
|
||||||
store.dispatch(logOut());
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
|
|
||||||
// Redirect to login page
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
window.location.href = '/login';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export default api;
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
import jwt from 'jsonwebtoken';
|
|
||||||
import { cookies } from 'next/headers';
|
|
||||||
|
|
||||||
export async function verifyToken(token?: string): Promise<boolean> {
|
|
||||||
if (!token) return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Verify the token
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
|
|
||||||
return !!decoded;
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof jwt.TokenExpiredError) {
|
|
||||||
console.log('Token expired');
|
|
||||||
} else if (error instanceof jwt.JsonWebTokenError) {
|
|
||||||
console.log('Invalid token');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAuthToken(): string | undefined {
|
|
||||||
const cookieStore = cookies();
|
|
||||||
return cookieStore.get('authToken')?.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearAuthToken() {
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setAuthToken(token: string) {
|
|
||||||
const expires = new Date();
|
|
||||||
expires.setTime(expires.getTime() + 3 * 60 * 60 * 1000); // 3 hours
|
|
||||||
|
|
||||||
document.cookie = `authToken=${token}; Path=/; Expires=${expires.toUTCString()}; HttpOnly; SameSite=Lax`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to get user ID from token
|
|
||||||
export function getUserIdFromToken(token?: string): string | null {
|
|
||||||
if (!token) return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string };
|
|
||||||
return decoded.userId;
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,7 +5,7 @@
|
|||||||
* * https://redux-toolkit.js.org/api/createAsyncThunk
|
* * https://redux-toolkit.js.org/api/createAsyncThunk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
import { createAsyncThunk , createSlice } from '@reduxjs/toolkit'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import Cookies from 'universal-cookie';
|
import Cookies from 'universal-cookie';
|
||||||
import { fireAlert } from './alert-slice';
|
import { fireAlert } from './alert-slice';
|
||||||
@ -33,10 +33,11 @@ const initialState = {
|
|||||||
|
|
||||||
const logIn = createAsyncThunk(
|
const logIn = createAsyncThunk(
|
||||||
'auth/logInStatus',
|
'auth/logInStatus',
|
||||||
async (actionPayload: { username: string, password: string, successCallback: any }, thunkAPI) => {
|
async (actionPayload : {username: string , password: string , successCallback : any}, thunkAPI) => {
|
||||||
try {
|
try {
|
||||||
let { data } = await axios.post('/api/auth', actionPayload)
|
let { data } = await axios.post('/api/auth' , actionPayload)
|
||||||
if (data.success) {
|
if(data.success)
|
||||||
|
{
|
||||||
actionPayload.successCallback()
|
actionPayload.successCallback()
|
||||||
// fire the success alert
|
// fire the success alert
|
||||||
thunkAPI.dispatch(fireAlert({
|
thunkAPI.dispatch(fireAlert({
|
||||||
@ -45,78 +46,47 @@ const logIn = createAsyncThunk(
|
|||||||
}))
|
}))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
thunkAPI.dispatch(fireAlert({
|
thunkAPI.dispatch(fireAlert({
|
||||||
success: false,
|
success: false,
|
||||||
message: data.message
|
message: data.message
|
||||||
}))
|
}))
|
||||||
return { success: false }
|
return { success : false }
|
||||||
}
|
}
|
||||||
} catch (err) {
|
}catch(err) {
|
||||||
thunkAPI.dispatch(fireAlert({
|
thunkAPI.dispatch(fireAlert({
|
||||||
success: false,
|
success: false,
|
||||||
message: "unkownError",
|
message: "unkownError",
|
||||||
}))
|
}))
|
||||||
return { success: false }
|
return { success : false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const isLoggedIn = createAsyncThunk(
|
const isLoggedIn = createAsyncThunk(
|
||||||
'auth/isLoggedInStatus',
|
'auth/isLoggedInStatus',
|
||||||
async (actionPayload: { LoggedInCallback?: () => void; NotLoggedInCallback?: () => void }, { dispatch, getState }) => {
|
async (actionPayload : {LoggedInCallback? : any , NotLoggedInCallback? : any}, thunkAPI) => {
|
||||||
try {
|
try {
|
||||||
const state = getState() as RootState;
|
const state : any = thunkAPI.getState()
|
||||||
const { authToken } = state.authReducer.value;
|
let { data } = await axios.get('/api/auth?authToken='+state.authReducer.value.authToken)
|
||||||
|
if(!data.success && actionPayload.NotLoggedInCallback)
|
||||||
// If no token, immediately trigger not logged in
|
{
|
||||||
if (!authToken) {
|
actionPayload.NotLoggedInCallback()
|
||||||
if (actionPayload.NotLoggedInCallback) {
|
|
||||||
actionPayload.NotLoggedInCallback();
|
|
||||||
}
|
}
|
||||||
return { isValid: false };
|
else if(actionPayload.LoggedInCallback && data.success)
|
||||||
|
{
|
||||||
|
actionPayload.LoggedInCallback()
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
try {
|
isValid : data.success
|
||||||
const { data } = await axios.get('/api/auth?authToken=' + authToken);
|
|
||||||
|
|
||||||
if (!data.success) {
|
|
||||||
// If token is invalid or expired, clear it
|
|
||||||
if (data.message === 'expiredToken' || data.message === 'invalidToken') {
|
|
||||||
dispatch(logOut());
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
}
|
}
|
||||||
|
}catch(e : any)
|
||||||
if (actionPayload.NotLoggedInCallback) {
|
{
|
||||||
actionPayload.NotLoggedInCallback();
|
actionPayload.NotLoggedInCallback()
|
||||||
|
return {
|
||||||
|
isValid : false
|
||||||
}
|
}
|
||||||
} else if (actionPayload.LoggedInCallback) {
|
|
||||||
actionPayload.LoggedInCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { isValid: data.success };
|
|
||||||
} catch (error: any) {
|
|
||||||
// Handle network errors or server issues
|
|
||||||
console.error('Token validation error:', error);
|
|
||||||
|
|
||||||
// If it's an auth-related error, clear the token
|
|
||||||
if (error.response?.status === 401 || error.response?.data?.message === 'expiredToken') {
|
|
||||||
dispatch(logOut());
|
|
||||||
document.cookie = 'authToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionPayload.NotLoggedInCallback) {
|
|
||||||
actionPayload.NotLoggedInCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in isLoggedIn:', error);
|
|
||||||
if (actionPayload.NotLoggedInCallback) {
|
|
||||||
actionPayload.NotLoggedInCallback();
|
|
||||||
}
|
|
||||||
return { isValid: false };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -138,15 +108,16 @@ export const auth = createSlice({
|
|||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
// logIn thunk reducer
|
// logIn thunk reducer
|
||||||
builder.addCase(logIn.fulfilled, (state: IinitialState, action) => {
|
builder.addCase(logIn.fulfilled, (state : IinitialState , action) => {
|
||||||
// set the state
|
// set the state
|
||||||
if (action.payload.success) {
|
if(action.payload.success)
|
||||||
|
{
|
||||||
state.value.authToken = action.payload.authToken;
|
state.value.authToken = action.payload.authToken;
|
||||||
state.value.isValid = true
|
state.value.isValid = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// check if user authToken cookie is a valid one
|
// check if user authToken cookie is a valid one
|
||||||
builder.addCase(isLoggedIn.fulfilled, (state: IinitialState, action) => {
|
builder.addCase(isLoggedIn.fulfilled, (state : IinitialState , action) => {
|
||||||
// set the state
|
// set the state
|
||||||
state.value.isValid = action.payload.isValid;
|
state.value.isValid = action.payload.isValid;
|
||||||
state.value.checkIfValidMounted = true
|
state.value.checkIfValidMounted = true
|
||||||
@ -155,6 +126,6 @@ export const auth = createSlice({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// export the functions
|
// export the functions
|
||||||
export const { logOut, mountCheckIfValid } = auth.actions;
|
export const { logOut , mountCheckIfValid } = auth.actions;
|
||||||
export { logIn, isLoggedIn };
|
export { logIn , isLoggedIn };
|
||||||
export default auth.reducer;
|
export default auth.reducer;
|
||||||
Loading…
Reference in New Issue
Block a user