mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
code cleanup
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
import { configureIam } from "@tria-plc/iamui-common";
|
// import { configureIam } from "@tria-plc/iamui-common";
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import "@tria-plc/iamui-common/styles.css";
|
// import "@tria-plc/iamui-common/styles.css";
|
||||||
import { AppProviders } from './providers/AppProviders';
|
import { AppProviders } from './providers/AppProviders';
|
||||||
import { AppRouter } from './router';
|
import { AppRouter } from './router';
|
||||||
|
|
||||||
configureIam({ apiUrl: 'http://localhost:3001/api' });
|
// configureIam({ apiUrl: 'http://localhost:3001/api' });
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
50
apps/portal/src/app/components/ErrorBoundary.tsx
Normal file
50
apps/portal/src/app/components/ErrorBoundary.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { Component } from 'react';
|
||||||
|
import type { ReactNode, ErrorInfo } from 'react';
|
||||||
|
import { Center, Paper, Title, Text, Button } from '@mantine/core';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
hasError: boolean;
|
||||||
|
error: Error | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ErrorBoundary extends Component<Props, State> {
|
||||||
|
state: State = { hasError: false, error: null };
|
||||||
|
|
||||||
|
static getDerivedStateFromError(error: Error): State {
|
||||||
|
return { hasError: true, error };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||||
|
console.error('ErrorBoundary caught:', error, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
return (
|
||||||
|
<Center h="100vh">
|
||||||
|
<Paper p="xl" shadow="md" radius="md" w={400}>
|
||||||
|
<Title order={3} mb="sm">Something went wrong</Title>
|
||||||
|
<Text c="dimmed" size="sm" mb="lg">
|
||||||
|
{this.state.error?.message || 'An unexpected error occurred.'}
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({ hasError: false, error: null });
|
||||||
|
window.location.href = '/';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reload page
|
||||||
|
</Button>
|
||||||
|
</Paper>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,13 +49,13 @@ export function LoginPage() {
|
|||||||
url: '/auth/login',
|
url: '/auth/login',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: values,
|
body: values,
|
||||||
}).unwrap() as LoginPayload;
|
}).unwrap();
|
||||||
dispatch(loginSuccess(data));
|
dispatch(loginSuccess(data));
|
||||||
|
|
||||||
const me = await meTrigger({
|
const me = await meTrigger({
|
||||||
url: '/auth/me',
|
url: '/auth/me',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
}).unwrap() as AuthUser;
|
}).unwrap();
|
||||||
dispatch(setUser(me));
|
dispatch(setUser(me));
|
||||||
|
|
||||||
if (me.status === 'accepted') {
|
if (me.status === 'accepted') {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export function SignupPage() {
|
|||||||
url: '/auth/signup-with-pwd',
|
url: '/auth/signup-with-pwd',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: payload,
|
body: payload,
|
||||||
}).unwrap() as { token: string; refreshToken: string; isPhoneNumberVerified: boolean };
|
}).unwrap();
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
loginSuccess({
|
loginSuccess({
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { AuthProvider } from '@tria-plc/iamui-common';
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { store } from '../store';
|
import { store } from '../store';
|
||||||
import { MantineThemeProvider } from './MantineThemeProvider';
|
import { MantineThemeProvider } from './MantineThemeProvider';
|
||||||
|
import { ErrorBoundary } from '../components/ErrorBoundary';
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: { queries: { retry: 1, staleTime: 1000 * 60 * 5 } },
|
defaultOptions: { queries: { retry: 1, staleTime: 1000 * 60 * 5 } },
|
||||||
@@ -11,12 +12,14 @@ const queryClient = new QueryClient({
|
|||||||
|
|
||||||
export function AppProviders({ children }: { children: ReactNode }) {
|
export function AppProviders({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<ErrorBoundary>
|
||||||
<QueryClientProvider client={queryClient}>
|
<Provider store={store}>
|
||||||
<AuthProvider>
|
<QueryClientProvider client={queryClient}>
|
||||||
<MantineThemeProvider>{children}</MantineThemeProvider>
|
<AuthProvider>
|
||||||
</AuthProvider>
|
<MantineThemeProvider>{children}</MantineThemeProvider>
|
||||||
</QueryClientProvider>
|
</AuthProvider>
|
||||||
</Provider>
|
</QueryClientProvider>
|
||||||
|
</Provider>
|
||||||
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,11 @@ import { LoginPage } from './features/auth/pages/LoginPage';
|
|||||||
import { SignupPage } from './features/auth/pages/SignupPage';
|
import { SignupPage } from './features/auth/pages/SignupPage';
|
||||||
import { OTPVerificationPage } from './features/auth/pages/OTPVerificationPage';
|
import { OTPVerificationPage } from './features/auth/pages/OTPVerificationPage';
|
||||||
import { DashboardPage } from './features/dashboard/pages/DashboardPage';
|
import { DashboardPage } from './features/dashboard/pages/DashboardPage';
|
||||||
|
import { useAppSelector } from './store/hooks';
|
||||||
function getToken(): string | null {
|
|
||||||
return localStorage.getItem('ema-portal-auth-token');
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProtectedRoute({ children }: { children: ReactNode }) {
|
function ProtectedRoute({ children }: { children: ReactNode }) {
|
||||||
if (!getToken()) return <Navigate to="/login" replace />;
|
const isAuthenticated = useAppSelector((s) => s.auth.isAuthenticated);
|
||||||
|
if (!isAuthenticated) return <Navigate to="/login" replace />;
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
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 { authStorage } from '../features/auth/utils/auth-storage';
|
||||||
|
|
||||||
|
const preloadedAuth = (() => {
|
||||||
|
const token = authStorage.getToken();
|
||||||
|
const user = authStorage.getUser();
|
||||||
|
if (token && user) {
|
||||||
|
return { token, user, isAuthenticated: true };
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
})();
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
auth: authReducer,
|
auth: authReducer,
|
||||||
[baseApi.reducerPath]: baseApi.reducer,
|
[baseApi.reducerPath]: baseApi.reducer,
|
||||||
},
|
},
|
||||||
|
preloadedState: preloadedAuth ? { auth: preloadedAuth } : undefined,
|
||||||
middleware: (getDefaultMiddleware) =>
|
middleware: (getDefaultMiddleware) =>
|
||||||
getDefaultMiddleware().concat(baseApi.middleware),
|
getDefaultMiddleware().concat(baseApi.middleware),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user