mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-29 19:58:13 +00:00
code cleanup
This commit is contained in:
@@ -61,7 +61,7 @@ const router = createBrowserRouter([
|
|||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
{ path: '/login', element: <Login /> },
|
{ path: '/login', element: <Login /> },
|
||||||
{ path: '/set-password', element: <SetPasswordPage /> },
|
{ path: '/otp-verify', element: <SetPasswordPage /> },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ path: '/404', element: <div>Page not found</div> },
|
{ path: '/404', element: <div>Page not found</div> },
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
|
|
||||||
import { loginSuccess, logout as logoutAction, hydrateAuth } from '../store/auth.slice';
|
|
||||||
import type { LoginPayload } from '../types/auth.types';
|
|
||||||
|
|
||||||
export function useAuth() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { user, token, isAuthenticated } = useAppSelector((s) => s.auth);
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
token,
|
|
||||||
isAuthenticated,
|
|
||||||
login: (p: LoginPayload) => dispatch(loginSuccess(p)),
|
|
||||||
logout: () => dispatch(logoutAction()),
|
|
||||||
hydrate: () => dispatch(hydrateAuth()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -17,15 +17,12 @@ import { useNavigate, Link } from 'react-router-dom';
|
|||||||
import { useAppDispatch } from '../../../store/hooks';
|
import { useAppDispatch } from '../../../store/hooks';
|
||||||
import { loginSuccess, setUser } from '../store/auth.slice';
|
import { loginSuccess, setUser } from '../store/auth.slice';
|
||||||
import type { LoginPayload, AuthUser } from '../types/auth.types';
|
import type { LoginPayload, AuthUser } from '../types/auth.types';
|
||||||
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
import { notify } from '@ema-platform/ui';
|
import { notify } from '@ema-platform/ui';
|
||||||
|
|
||||||
const BASE_API_URL =
|
|
||||||
(import.meta as { env?: Record<string, string> }).env?.['VITE_BASE_API_URL'] ??
|
|
||||||
'http://localhost:3001/api';
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email('Enter a valid email'),
|
email: z.string().email({ message: 'Enter a valid email' }),
|
||||||
password: z.string().min(0, 'Password must be at least 6 characters'),
|
password: z.string().min(5, { message: 'Password must be at least 6 characters' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
type FormValues = z.infer<typeof schema>;
|
type FormValues = z.infer<typeof schema>;
|
||||||
@@ -34,6 +31,8 @@ export function LoginPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [loginTrigger] = useApiMutation<LoginPayload>();
|
||||||
|
const [meTrigger] = useApiMutation<AuthUser>();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -46,26 +45,23 @@ export function LoginPage() {
|
|||||||
const onSubmit = async (values: FormValues) => {
|
const onSubmit = async (values: FormValues) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${BASE_API_URL}/auth/login`, {
|
const data = await loginTrigger({
|
||||||
|
url: '/auth/login',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
body: values,
|
||||||
body: JSON.stringify(values),
|
}).unwrap() as LoginPayload;
|
||||||
});
|
|
||||||
if (!res.ok) throw new Error('Login failed');
|
|
||||||
const data = (await res.json()) as LoginPayload;
|
|
||||||
dispatch(loginSuccess(data));
|
dispatch(loginSuccess(data));
|
||||||
|
|
||||||
const meRes = await fetch(`${BASE_API_URL}/auth/me`, {
|
const me = await meTrigger({
|
||||||
headers: { Authorization: `Bearer ${data.token}` },
|
url: '/auth/me',
|
||||||
});
|
method: 'GET',
|
||||||
if (!meRes.ok) throw new Error('Failed to fetch user');
|
}).unwrap() as AuthUser;
|
||||||
const me = (await meRes.json()) as AuthUser;
|
|
||||||
dispatch(setUser(me));
|
dispatch(setUser(me));
|
||||||
|
|
||||||
if (me.status === 'accepted') {
|
if (me.status === 'accepted') {
|
||||||
navigate('/dashboard');
|
navigate('/dashboard');
|
||||||
} else {
|
} else {
|
||||||
navigate('/set-password', {
|
navigate('/otp-verify', {
|
||||||
state: { email: me.email, phoneNumber: me.phoneNumber },
|
state: { email: me.email, phoneNumber: me.phoneNumber },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,36 +11,26 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
import {
|
|
||||||
setPasswordStart,
|
|
||||||
setPasswordSuccess,
|
|
||||||
setPasswordFailure,
|
|
||||||
} from '../store/set-password.slice';
|
|
||||||
import { notify } from '@ema-platform/ui';
|
import { notify } from '@ema-platform/ui';
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
const BASE_API_URL =
|
|
||||||
(import.meta as { env?: Record<string, string> }).env?.['VITE_BASE_API_URL'] ??
|
|
||||||
'http://localhost:3001/api';
|
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
verificationCode: z.string().min(1, 'Verification code is required'),
|
verificationCode: z.string().min(1, { message: 'Verification code is required' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
type FormValues = z.infer<typeof schema>;
|
type FormValues = z.infer<typeof schema>;
|
||||||
|
|
||||||
export function SetPasswordPage() {
|
export function OTPVerificationPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { loading } = useAppSelector((s) => s.setPassword);
|
|
||||||
const state = location.state as
|
const state = location.state as
|
||||||
| { email?: string; phoneNumber?: string }
|
| { email?: string; phoneNumber?: string }
|
||||||
| null;
|
| null;
|
||||||
const email = state?.email ?? '';
|
const email = state?.email ?? '';
|
||||||
const phoneNumber = state?.phoneNumber ?? '';
|
const phoneNumber = state?.phoneNumber ?? '';
|
||||||
const [resending, setResending] = useState(false);
|
|
||||||
|
const [verifyTrigger, { isLoading: loading }] = useApiMutation();
|
||||||
|
const [resendTrigger, { isLoading: resending }] = useApiMutation();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -51,53 +41,33 @@ export function SetPasswordPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (values: FormValues) => {
|
const onSubmit = async (values: FormValues) => {
|
||||||
dispatch(setPasswordStart());
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${BASE_API_URL}/auth/verify-phone-number`, {
|
await verifyTrigger({
|
||||||
|
url: '/auth/verify-phone-number',
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
body: { email, phoneNumber, verificationCode: values.verificationCode },
|
||||||
body: JSON.stringify({
|
}).unwrap();
|
||||||
email,
|
|
||||||
phoneNumber,
|
|
||||||
verificationCode: values.verificationCode,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const errorData = await res.json().catch(() => null);
|
|
||||||
throw new Error(errorData?.message ?? 'Verification failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(setPasswordSuccess());
|
|
||||||
notify.success('Phone number verified successfully');
|
notify.success('Phone number verified successfully');
|
||||||
navigate('/dashboard');
|
navigate('/dashboard');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
||||||
dispatch(setPasswordFailure(msg));
|
|
||||||
notify.error(msg);
|
notify.error(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResendOtp = async () => {
|
const handleResendOtp = async () => {
|
||||||
setResending(true);
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${BASE_API_URL}/auth/resend-otp`, {
|
await resendTrigger({
|
||||||
|
url: '/auth/resend-otp',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
body: { email },
|
||||||
body: JSON.stringify({ email }),
|
}).unwrap();
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const errorData = await res.json().catch(() => null);
|
|
||||||
throw new Error(errorData?.message ?? 'Failed to resend OTP');
|
|
||||||
}
|
|
||||||
|
|
||||||
notify.success('Verification code resent to your email');
|
notify.success('Verification code resent to your email');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
||||||
notify.error(msg);
|
notify.error(msg);
|
||||||
} finally {
|
|
||||||
setResending(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -13,26 +13,21 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
|
import { useAppDispatch } from '../../../store/hooks';
|
||||||
import { signupStart, signupSuccess, signupFailure } from '../store/signup.slice';
|
import { loginSuccess } from '../store/auth.slice';
|
||||||
import { hydrateAuth } from '../store/auth.slice';
|
import { useApiMutation } from '@ema-platform/api';
|
||||||
import { authStorage } from '../utils/auth-storage';
|
|
||||||
import { notify } from '@ema-platform/ui';
|
import { notify } from '@ema-platform/ui';
|
||||||
|
|
||||||
const BASE_API_URL =
|
|
||||||
(import.meta as { env?: Record<string, string> }).env?.['VITE_BASE_API_URL'] ??
|
|
||||||
'http://localhost:3001/api';
|
|
||||||
|
|
||||||
const schema = z
|
const schema = z
|
||||||
.object({
|
.object({
|
||||||
email: z.string().email('Enter a valid email'),
|
email: z.string().email(),
|
||||||
username: z.string().min(3, 'Username must be at least 3 characters'),
|
username: z.string().min(3, { message: 'Username must be at least 3 characters' }),
|
||||||
phoneNumber: z.string().min(1, 'Phone number is required'),
|
phoneNumber: z.string().min(1, { message: 'Phone number is required' }),
|
||||||
userType: z.literal('individual'),
|
userType: z.literal('individual'),
|
||||||
nameEn: z.string().min(1, 'Name (English) is required'),
|
nameEn: z.string().min(1, { message: 'Name (English) is required' }),
|
||||||
nameAm: z.string().optional(),
|
nameAm: z.string().optional(),
|
||||||
password: z.string().min(8, 'Password must be at least 8 characters'),
|
password: z.string().min(8, { message: 'Password must be at least 8 characters' }),
|
||||||
confirmPassword: z.string().min(8, 'Confirm your password'),
|
confirmPassword: z.string().min(8, { message: 'Confirm your password' }),
|
||||||
})
|
})
|
||||||
.refine((data) => data.password === data.confirmPassword, {
|
.refine((data) => data.password === data.confirmPassword, {
|
||||||
message: 'Passwords do not match',
|
message: 'Passwords do not match',
|
||||||
@@ -57,7 +52,11 @@ interface SignupPayload {
|
|||||||
export function SignupPage() {
|
export function SignupPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { loading } = useAppSelector((s) => s.signup);
|
const [signupTrigger, { isLoading: loading }] = useApiMutation<{
|
||||||
|
token: string;
|
||||||
|
refreshToken: string;
|
||||||
|
isPhoneNumberVerified: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -69,7 +68,6 @@ export function SignupPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (values: FormValues) => {
|
const onSubmit = async (values: FormValues) => {
|
||||||
dispatch(signupStart());
|
|
||||||
try {
|
try {
|
||||||
const payload: SignupPayload = {
|
const payload: SignupPayload = {
|
||||||
email: values.email,
|
email: values.email,
|
||||||
@@ -81,30 +79,25 @@ export function SignupPage() {
|
|||||||
confirmPassword: values.confirmPassword,
|
confirmPassword: values.confirmPassword,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(`${BASE_API_URL}/auth/signup-with-pwd`, {
|
const data = await signupTrigger({
|
||||||
|
url: '/auth/signup-with-pwd',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
body: payload,
|
||||||
body: JSON.stringify(payload),
|
}).unwrap() as { token: string; refreshToken: string; isPhoneNumberVerified: boolean };
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
dispatch(
|
||||||
const errorData = await res.json().catch(() => null);
|
loginSuccess({
|
||||||
throw new Error(errorData?.message ?? 'Signup failed');
|
token: data.token,
|
||||||
}
|
refreshToken: data.refreshToken,
|
||||||
|
isPhoneNumberVerified: data.isPhoneNumberVerified,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const data = (await res.json()) as { token: string; refreshToken: string; isPhoneNumberVerified: boolean };
|
navigate('/otp-verify', {
|
||||||
|
|
||||||
authStorage.setToken(data.token);
|
|
||||||
authStorage.setRefreshToken(data.refreshToken);
|
|
||||||
dispatch(hydrateAuth());
|
|
||||||
dispatch(signupSuccess());
|
|
||||||
|
|
||||||
navigate('/set-password', {
|
|
||||||
state: { email: values.email, phoneNumber: values.phoneNumber },
|
state: { email: values.email, phoneNumber: values.phoneNumber },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
const msg = err instanceof Error ? err.message : 'Something went wrong';
|
||||||
dispatch(signupFailure(msg));
|
|
||||||
notify.error(msg);
|
notify.error(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
interface SetPasswordState {
|
|
||||||
loading: boolean;
|
|
||||||
success: boolean;
|
|
||||||
error: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: SetPasswordState = {
|
|
||||||
loading: false,
|
|
||||||
success: false,
|
|
||||||
error: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const setPasswordSlice = createSlice({
|
|
||||||
name: 'setPassword',
|
|
||||||
initialState,
|
|
||||||
reducers: {
|
|
||||||
setPasswordStart(state) {
|
|
||||||
state.loading = true;
|
|
||||||
state.error = null;
|
|
||||||
state.success = false;
|
|
||||||
},
|
|
||||||
setPasswordSuccess(state) {
|
|
||||||
state.loading = false;
|
|
||||||
state.success = true;
|
|
||||||
},
|
|
||||||
setPasswordFailure(state, action: PayloadAction<string>) {
|
|
||||||
state.loading = false;
|
|
||||||
state.error = action.payload;
|
|
||||||
},
|
|
||||||
resetSetPassword(state) {
|
|
||||||
state.loading = false;
|
|
||||||
state.success = false;
|
|
||||||
state.error = null;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const { setPasswordStart, setPasswordSuccess, setPasswordFailure, resetSetPassword } =
|
|
||||||
setPasswordSlice.actions;
|
|
||||||
export const setPasswordReducer = setPasswordSlice.reducer;
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
||||||
|
|
||||||
interface SignupState {
|
|
||||||
loading: boolean;
|
|
||||||
success: boolean;
|
|
||||||
error: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: SignupState = {
|
|
||||||
loading: false,
|
|
||||||
success: false,
|
|
||||||
error: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const signupSlice = createSlice({
|
|
||||||
name: 'signup',
|
|
||||||
initialState,
|
|
||||||
reducers: {
|
|
||||||
signupStart(state) {
|
|
||||||
state.loading = true;
|
|
||||||
state.error = null;
|
|
||||||
state.success = false;
|
|
||||||
},
|
|
||||||
signupSuccess(state) {
|
|
||||||
state.loading = false;
|
|
||||||
state.success = true;
|
|
||||||
},
|
|
||||||
signupFailure(state, action: PayloadAction<string>) {
|
|
||||||
state.loading = false;
|
|
||||||
state.error = action.payload;
|
|
||||||
},
|
|
||||||
resetSignup(state) {
|
|
||||||
state.loading = false;
|
|
||||||
state.success = false;
|
|
||||||
state.error = null;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const { signupStart, signupSuccess, signupFailure, resetSignup } = signupSlice.actions;
|
|
||||||
export const signupReducer = signupSlice.reducer;
|
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
import { AppShell, Group, Text, Button } from '@mantine/core';
|
import { AppShell, Group, Text, Button } from '@mantine/core';
|
||||||
import { Outlet, useNavigate } from 'react-router-dom';
|
import { Outlet, useNavigate } from 'react-router-dom';
|
||||||
|
import { useAppDispatch, useAppSelector } from '../store/hooks';
|
||||||
|
import { logout } from '../features/auth/store/auth.slice';
|
||||||
|
|
||||||
export function PortalLayout() {
|
export function PortalLayout() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const isLoggedIn = !!localStorage.getItem('ema-portal-auth-token');
|
const dispatch = useAppDispatch();
|
||||||
|
const isAuthenticated = useAppSelector((s) => s.auth.isAuthenticated);
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
dispatch(logout());
|
||||||
|
navigate('/login');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppShell header={{ height: 56 }} padding="md">
|
<AppShell header={{ height: 56 }} padding="md">
|
||||||
<AppShell.Header>
|
<AppShell.Header>
|
||||||
<Group h="100%" px="md" justify="space-between">
|
<Group h="100%" px="md" justify="space-between">
|
||||||
<Text fw={700}>EMA Portal</Text>
|
<Text fw={700}>EMA Portal</Text>
|
||||||
{isLoggedIn ? (
|
{isAuthenticated ? (
|
||||||
<Button
|
<Button variant="subtle" size="sm" onClick={handleLogout}>
|
||||||
variant="subtle"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => {
|
|
||||||
localStorage.removeItem('ema-portal-auth-token');
|
|
||||||
navigate('/login');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import type { ReactNode } from 'react';
|
|||||||
import { PortalLayout } from './layouts/PortalLayout';
|
import { PortalLayout } from './layouts/PortalLayout';
|
||||||
import { LoginPage } from './features/auth/pages/LoginPage';
|
import { LoginPage } from './features/auth/pages/LoginPage';
|
||||||
import { SignupPage } from './features/auth/pages/SignupPage';
|
import { SignupPage } from './features/auth/pages/SignupPage';
|
||||||
import { SetPasswordPage } from './features/auth/pages/SetPasswordPage';
|
import { OTPVerificationPage } from './features/auth/pages/OTPVerificationPage';
|
||||||
import { DashboardPage } from './features/dashboard/pages/DashboardPage';
|
import { DashboardPage } from './features/dashboard/pages/DashboardPage';
|
||||||
import { UserManagementPage, UserManagementLayout } from "@tria-plc/iamui-common";
|
|
||||||
|
|
||||||
function getToken(): string | null {
|
function getToken(): string | null {
|
||||||
return localStorage.getItem('ema-portal-auth-token');
|
return localStorage.getItem('ema-portal-auth-token');
|
||||||
@@ -21,10 +20,14 @@ export function AppRouter() {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route path="/signup" element={<SignupPage />} />
|
<Route path="/signup" element={<SignupPage />} />
|
||||||
<Route path="/set-password" element={<SetPasswordPage />} />
|
<Route
|
||||||
<Route element={<UserManagementLayout />}>
|
path="/otp-verify"
|
||||||
<Route path="/users" element={<UserManagementPage />} />
|
element={
|
||||||
</Route>
|
<ProtectedRoute>
|
||||||
|
<OTPVerificationPage />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route element={<PortalLayout />}>
|
<Route element={<PortalLayout />}>
|
||||||
<Route path="/" element={<Navigate to="/dashboard" replace />} />
|
<Route path="/" element={<Navigate to="/dashboard" replace />} />
|
||||||
<Route
|
<Route
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
import { baseApi } from '@ema-platform/api';
|
import { baseApi } from '@ema-platform/api';
|
||||||
import { authReducer } from '../features/auth/store/auth.slice';
|
import { authReducer } from '../features/auth/store/auth.slice';
|
||||||
import { signupReducer } from '../features/auth/store/signup.slice';
|
|
||||||
import { setPasswordReducer } from '../features/auth/store/set-password.slice';
|
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
auth: authReducer,
|
auth: authReducer,
|
||||||
signup: signupReducer,
|
|
||||||
setPassword: setPasswordReducer,
|
|
||||||
[baseApi.reducerPath]: baseApi.reducer,
|
[baseApi.reducerPath]: baseApi.reducer,
|
||||||
},
|
},
|
||||||
middleware: (getDefaultMiddleware) =>
|
middleware: (getDefaultMiddleware) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user