From db6a485374451da51c6b375bba6e61d78c118f98 Mon Sep 17 00:00:00 2001 From: mengstabketemaw Date: Thu, 9 Jul 2026 11:34:41 +0300 Subject: [PATCH] fix: fix redirect based on profile bug --- .../src/app/providers/AppProviders.tsx | 17 ++------ apps/backoffice/src/app/router/index.tsx | 4 +- .../src/app/components/ProfileGuard.tsx | 4 +- .../src/app/components/SmartDashboard.tsx | 11 +++++ .../profile-setup/pages/ProfileSetupPage.tsx | 16 ++++++-- .../portal/src/app/providers/AppProviders.tsx | 13 +----- apps/portal/src/app/router.tsx | 12 +++--- libs/auth/src/index.ts | 2 - libs/auth/src/lib/AuthConfig.tsx | 40 ------------------- libs/auth/src/lib/components/AuthShell.tsx | 9 ++--- .../auth/src/lib/pages/ForgotPasswordPage.tsx | 8 ++-- libs/auth/src/lib/pages/LoginPage.tsx | 19 +++++---- .../src/lib/pages/OTPVerificationPage.tsx | 6 +-- libs/auth/src/lib/pages/SignupPage.tsx | 8 ++-- 14 files changed, 65 insertions(+), 104 deletions(-) create mode 100644 apps/portal/src/app/components/SmartDashboard.tsx delete mode 100644 libs/auth/src/lib/AuthConfig.tsx diff --git a/apps/backoffice/src/app/providers/AppProviders.tsx b/apps/backoffice/src/app/providers/AppProviders.tsx index 8782892f6..2be88a654 100644 --- a/apps/backoffice/src/app/providers/AppProviders.tsx +++ b/apps/backoffice/src/app/providers/AppProviders.tsx @@ -1,7 +1,6 @@ import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { AuthConfigProvider } from '@ema-platform/auth'; import type { ReactNode } from 'react'; import { store } from '../store'; import { i18n } from '../i18n/config'; @@ -17,19 +16,9 @@ export function AppProviders({ children }: { children: ReactNode }) { return ( - - - {children} - - + + {children} + ); diff --git a/apps/backoffice/src/app/router/index.tsx b/apps/backoffice/src/app/router/index.tsx index 73a324d40..06bf91cd4 100644 --- a/apps/backoffice/src/app/router/index.tsx +++ b/apps/backoffice/src/app/router/index.tsx @@ -41,8 +41,8 @@ const router = createBrowserRouter([ { element: , children: [ - { path: '/login', element: }, - { path: '/forgot-password', element: }, + { path: '/login', element: }, + { path: '/forgot-password', element: }, { path: '/otp-verify', element: }, ], }, diff --git a/apps/portal/src/app/components/ProfileGuard.tsx b/apps/portal/src/app/components/ProfileGuard.tsx index 5a564b142..1e64a8c49 100644 --- a/apps/portal/src/app/components/ProfileGuard.tsx +++ b/apps/portal/src/app/components/ProfileGuard.tsx @@ -4,8 +4,8 @@ import type { ReactNode } from 'react'; import { authStorage } from '@ema-platform/auth'; const ROUTE_ACCESS: Record = { - SEAFARER: ['/dashboard', '/seafarer-', '/seaman-book', '/documents', '/certificates', '/endorsements', '/notifications', '/basic-safety-training'], - VESSEL_OWNER: ['/vessel-owner', '/vessel-registration'], + SEAFARER: ['/','/dashboard', '/seafarer-', '/seaman-book', '/documents', '/certificates', '/endorsements', '/notifications', '/basic-safety-training'], + VESSEL_OWNER: ['/','/dashboard', '/vessel-owner', '/vessel-registration'], }; const SHARED = ['/profile', '/support']; diff --git a/apps/portal/src/app/components/SmartDashboard.tsx b/apps/portal/src/app/components/SmartDashboard.tsx new file mode 100644 index 000000000..004b4ea04 --- /dev/null +++ b/apps/portal/src/app/components/SmartDashboard.tsx @@ -0,0 +1,11 @@ +import { Navigate } from 'react-router-dom'; +import { authStorage } from '@ema-platform/auth'; +import { DashboardPage } from '../features/dashboard/pages/DashboardPage'; + +export function SmartDashboard() { + const profile = authStorage.getProfile<{ type: string }>(); + if (profile?.type === 'VESSEL_OWNER') { + return ; + } + return ; +} diff --git a/apps/portal/src/app/features/profile-setup/pages/ProfileSetupPage.tsx b/apps/portal/src/app/features/profile-setup/pages/ProfileSetupPage.tsx index 570a9c868..c7f05262b 100644 --- a/apps/portal/src/app/features/profile-setup/pages/ProfileSetupPage.tsx +++ b/apps/portal/src/app/features/profile-setup/pages/ProfileSetupPage.tsx @@ -116,7 +116,7 @@ export function ProfileSetupPage() { const [active, setActive] = useState(0); const [completed, setCompleted] = useState([]); const [submitting, setSubmitting] = useState(false); - const [professions, setProfessions] = useState>([]); + const [professions, setProfessions] = useState>([]); const [professionsLoading, setProfessionsLoading] = useState(true); const [profileTrigger] = useApiMutation<{ id: string }>(); const [addressTrigger] = useApiMutation(); @@ -147,6 +147,14 @@ export function ProfileSetupPage() { return map; }, [professions]); + const professionTypeMap = useMemo(() => { + const map: Record = {}; + professions.forEach((p) => { + if (p.type) map[p.id] = p.type; + }); + return map; + }, [professions]); + const nameParts = useMemo(() => (user?.name?.en || '').trim().split(/\s+/), [user]); const profileDefaults: ProfileValues = useMemo(() => ({ professionId: '', @@ -218,13 +226,14 @@ export function ProfileSetupPage() { const pv = profileWatch(); const av = addressWatch(); const selectedProfessionName = professionNameMap[pv.professionId] ?? ''; + const selectedType = professionTypeMap[pv.professionId] || 'SEAFARER'; const profileResult = await profileTrigger({ url: '/profiles', method: 'POST', body: { userId: user?.id, - type: 'SEAFARER', + type: selectedType, professionId: pv.professionId, firstName: pv.firstName, middleName: pv.middleName, @@ -261,8 +270,7 @@ export function ProfileSetupPage() { }).unwrap(); notify.success('Profile setup complete!'); - //TODO: update the comparision - navigate('SEAFARER' === 'VESSEL_OWNER' ? '/vessel-owner/dashboard' : '/dashboard'); + navigate('/dashboard'); } catch { notify.error('Failed to save profile. Please try again.'); } finally { diff --git a/apps/portal/src/app/providers/AppProviders.tsx b/apps/portal/src/app/providers/AppProviders.tsx index 15ec0c1d2..b907bae8d 100644 --- a/apps/portal/src/app/providers/AppProviders.tsx +++ b/apps/portal/src/app/providers/AppProviders.tsx @@ -1,6 +1,5 @@ import { Provider } from 'react-redux'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { AuthConfigProvider } from '@ema-platform/auth'; import type { ReactNode } from 'react'; import { store } from '../store'; import { MantineThemeProvider } from './MantineThemeProvider'; @@ -15,17 +14,7 @@ export function AppProviders({ children }: { children: ReactNode }) { - - {children} - + {children} diff --git a/apps/portal/src/app/router.tsx b/apps/portal/src/app/router.tsx index eb7c6d09e..95a4b7be3 100644 --- a/apps/portal/src/app/router.tsx +++ b/apps/portal/src/app/router.tsx @@ -4,6 +4,7 @@ import { i18n } from './i18n/config'; import { PortalLayout } from './layouts/PortalLayout'; import { ProtectedRoute } from './components/ProtectedRoute'; import { ProfileGuard } from './components/ProfileGuard'; +import { SmartDashboard } from './components/SmartDashboard'; // Auth (standalone pages, no portal chrome) import { LoginPage, SignupPage, OTPVerificationPage, ForgotPasswordPage } from '@ema-platform/auth'; @@ -12,7 +13,6 @@ import { LoginPage, SignupPage, OTPVerificationPage, ForgotPasswordPage } from ' import { ProfileSetupPage } from './features/profile-setup/pages/ProfileSetupPage'; // Portal feature pages -import { DashboardPage } from './features/dashboard/pages/DashboardPage'; import { ProfilePage } from './features/profile/pages/ProfilePage'; import { SupportPage } from './features/support/pages/SupportPage'; import { SeafarerRegistrationPage } from './features/seafarer/pages/SeafarerRegistrationPage'; @@ -45,11 +45,11 @@ import { VesselOwnerDashboardPage } from './features/vessel-owner/pages/VesselOw export const router = createBrowserRouter([ // Public auth pages - { path: '/login', element: }, - { path: '/signup', element: }, + { path: '/login', element: }, + { path: '/signup', element: }, // Public auth pages - { path: '/forgot-password', element: }, + { path: '/forgot-password', element: }, // Protected auth pages { @@ -73,8 +73,8 @@ export const router = createBrowserRouter([ ), children: [ - { path: '/', element: }, - { path: '/dashboard', element: }, + { path: '/', element: }, + { path: '/dashboard', element: }, // Seafarer { path: '/seafarer-registration', element: }, diff --git a/libs/auth/src/index.ts b/libs/auth/src/index.ts index 7c178a615..1b729dbd7 100644 --- a/libs/auth/src/index.ts +++ b/libs/auth/src/index.ts @@ -1,5 +1,3 @@ -export { AuthConfigProvider, useAuthConfig } from './lib/AuthConfig'; -export type { AuthConfigValue } from './lib/AuthConfig'; export { AuthShell, BrandMark } from './lib/components/AuthShell'; export { ProtectedRoute } from './lib/components/ProtectedRoute'; export { LoginPage } from './lib/pages/LoginPage'; diff --git a/libs/auth/src/lib/AuthConfig.tsx b/libs/auth/src/lib/AuthConfig.tsx deleted file mode 100644 index bbc446adb..000000000 --- a/libs/auth/src/lib/AuthConfig.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { createContext, useContext, type ReactNode } from 'react'; - -export interface AuthConfigValue { - appName: string; - storagePrefix: string; - loginRedirectPath: string; - enableSignup: boolean; - enableForgotPassword: boolean; - logoUrl: string; -} - -const defaultConfig: AuthConfigValue = { - appName: 'Portal', - storagePrefix: 'ema-auth', - loginRedirectPath: '/dashboard', - enableSignup: true, - enableForgotPassword: true, - logoUrl: '/brand/ema-white.png', -}; - -const AuthConfigContext = createContext(defaultConfig); - -export function AuthConfigProvider({ - children, - value, -}: { - children: ReactNode; - value: Partial; -}) { - const merged = { ...defaultConfig, ...value }; - return ( - - {children} - - ); -} - -export function useAuthConfig() { - return useContext(AuthConfigContext); -} diff --git a/libs/auth/src/lib/components/AuthShell.tsx b/libs/auth/src/lib/components/AuthShell.tsx index f3e75ba54..6696cea3a 100644 --- a/libs/auth/src/lib/components/AuthShell.tsx +++ b/libs/auth/src/lib/components/AuthShell.tsx @@ -15,14 +15,14 @@ import { type BoxProps, } from '@mantine/core'; import { IconCheck, IconMoon, IconSun } from '@tabler/icons-react'; -import { useAuthConfig } from '../AuthConfig'; + +const LOGO_URL = '/brand/ema-white.png'; export function BrandMark({ size = 44, ...boxProps }: BoxProps & { size?: number }) { - const { logoUrl } = useAuthConfig(); return ( diff --git a/libs/auth/src/lib/pages/ForgotPasswordPage.tsx b/libs/auth/src/lib/pages/ForgotPasswordPage.tsx index 98552e2b8..39e3e2216 100644 --- a/libs/auth/src/lib/pages/ForgotPasswordPage.tsx +++ b/libs/auth/src/lib/pages/ForgotPasswordPage.tsx @@ -24,7 +24,6 @@ import { Link } from 'react-router-dom'; import { useApiMutation } from '@ema-platform/api'; import { notify } from '@ema-platform/ui'; import { AuthShell } from '../components/AuthShell'; -import { useAuthConfig } from '../AuthConfig'; const schema = z.object({ email: z.string().email({ message: 'Enter a valid email' }), @@ -32,8 +31,11 @@ const schema = z.object({ type FormValues = z.infer; -export function ForgotPasswordPage() { - const { appName } = useAuthConfig(); +interface ForgotPasswordPageProps { + appName?: string; +} + +export function ForgotPasswordPage({ appName = 'Portal' }: ForgotPasswordPageProps) { const [forgotTrigger, { isLoading }] = useApiMutation(); const [sentTo, setSentTo] = useState(null); const [serverError, setServerError] = useState(null); diff --git a/libs/auth/src/lib/pages/LoginPage.tsx b/libs/auth/src/lib/pages/LoginPage.tsx index 54be7d675..063738a9e 100644 --- a/libs/auth/src/lib/pages/LoginPage.tsx +++ b/libs/auth/src/lib/pages/LoginPage.tsx @@ -28,7 +28,6 @@ import { notify } from '@ema-platform/ui'; import { AuthShell } from '../components/AuthShell'; import { loginSuccess, setUser, setCurrentProfile } from '../store/auth.slice'; import type { LoginPayload, AuthUser, CurrentProfile } from '../types/auth.types'; -import { useAuthConfig } from '../AuthConfig'; import { authStorage } from '../utils/auth-storage'; const schema = z.object({ @@ -38,11 +37,19 @@ const schema = z.object({ type FormValues = z.infer; -export function LoginPage() { +interface LoginPageProps { + appName?: string; + enableSignup?: boolean; + enableForgotPassword?: boolean; +} + +export function LoginPage({ + appName = 'Portal', + enableSignup = true, + enableForgotPassword = true, +}: LoginPageProps) { const navigate = useNavigate(); const dispatch = useDispatch(); - const { appName, loginRedirectPath, enableSignup, enableForgotPassword } = - useAuthConfig(); const [isLoading, setIsLoading] = useState(false); const [rememberMe, setRememberMe] = useState(true); const [serverError, setServerError] = useState(null); @@ -75,7 +82,6 @@ export function LoginPage() { dispatch(setUser(me)); let hasProfile = false; - let profileType: string | undefined; try { const q = `w=user_id:=:${me.id}&i=user,address,profession`; const result = await profileCheckTrigger({ @@ -84,7 +90,6 @@ export function LoginPage() { }).unwrap(); if (result.total > 0 && result.items.length > 0) { const profile = result.items[0]; - profileType = 'VESSEL_OWNER'; authStorage.setProfileId(profile.id); dispatch(setCurrentProfile(profile)); hasProfile = true; @@ -109,7 +114,7 @@ export function LoginPage() { return; } - navigate(profileType === 'VESSEL_OWNER' ? '/vessel-owner/dashboard' : loginRedirectPath); + navigate('/dashboard'); } catch (err: unknown) { const msg = (err as { data?: { message?: string } })?.data?.message ?? diff --git a/libs/auth/src/lib/pages/OTPVerificationPage.tsx b/libs/auth/src/lib/pages/OTPVerificationPage.tsx index 17f25762e..e59593f88 100644 --- a/libs/auth/src/lib/pages/OTPVerificationPage.tsx +++ b/libs/auth/src/lib/pages/OTPVerificationPage.tsx @@ -20,7 +20,6 @@ import { useNavigate, useLocation } from 'react-router-dom'; import { useApiMutation } from '@ema-platform/api'; import { notify } from '@ema-platform/ui'; import { AuthShell } from '../components/AuthShell'; -import { useAuthConfig } from '../AuthConfig'; const CODE_LENGTH = 6; const RESEND_SECONDS = 30; @@ -36,7 +35,6 @@ type FormValues = z.infer; export function OTPVerificationPage() { const navigate = useNavigate(); const location = useLocation(); - const { loginRedirectPath } = useAuthConfig(); const state = location.state as | { email?: string; phoneNumber?: string; needsProfile?: boolean } | null; @@ -73,7 +71,7 @@ export function OTPVerificationPage() { }).unwrap(); notify.success('Phone number verified successfully'); - navigate(needsProfile ? '/profile-setup' : loginRedirectPath); + navigate(needsProfile ? '/profile-setup' : '/dashboard'); } catch (err: unknown) { const msg = (err as { data?: { message?: string } })?.data?.message ?? @@ -182,7 +180,7 @@ export function OTPVerificationPage() { variant="light" fullWidth size="md" - onClick={() => navigate(loginRedirectPath)} + onClick={() => navigate('/dashboard')} > Skip verification for now diff --git a/libs/auth/src/lib/pages/SignupPage.tsx b/libs/auth/src/lib/pages/SignupPage.tsx index 76a875ef2..970c285ea 100644 --- a/libs/auth/src/lib/pages/SignupPage.tsx +++ b/libs/auth/src/lib/pages/SignupPage.tsx @@ -30,7 +30,6 @@ import { notify } from '@ema-platform/ui'; import { AuthShell } from '../components/AuthShell'; import { loginSuccess, setUser } from '../store/auth.slice'; import type { AuthUser } from '../types/auth.types'; -import { useAuthConfig } from '../AuthConfig'; const schema = z .object({ @@ -63,10 +62,13 @@ interface SignupPayload { confirmPassword: string; } -export function SignupPage() { +interface SignupPageProps { + appName?: string; +} + +export function SignupPage({ appName = 'Portal' }: SignupPageProps) { const navigate = useNavigate(); const dispatch = useDispatch(); - const { appName, loginRedirectPath } = useAuthConfig(); const [agreed, setAgreed] = useState(false); const [serverError, setServerError] = useState(null); const [signupTrigger, { isLoading: loading }] = useApiMutation<{