use iam module login page for backoffice

This commit is contained in:
mengstabketemaw
2026-06-03 14:17:06 +03:00
parent 4faf851a8f
commit d730be3e85
6 changed files with 29 additions and 160 deletions

View File

@@ -1,5 +1 @@
import { LoginForm } from '../components/LoginForm';
export function LoginPage() {
return <LoginForm />;
}
export { Login as LoginPage } from '@tria-plc/iamui-common';

View File

@@ -1,137 +1 @@
import {
Paper,
TextInput,
PasswordInput,
Button,
Stack,
Title,
Text,
} from '@mantine/core';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
import {
setPasswordStart,
setPasswordSuccess,
setPasswordFailure,
} from '../store/set-password.slice';
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({
userId: z.string().min(1, 'User ID is required'),
email: z.string().email('Enter a valid email'),
verificationCode: z.string().min(1, 'Verification code is required'),
newPassword: z.string().min(6, 'Password must be at least 6 characters'),
confirmPassword: z.string().min(6, 'Confirm your password'),
})
.refine((data) => data.newPassword === data.confirmPassword, {
message: 'Passwords do not match',
path: ['confirmPassword'],
});
type FormValues = z.infer<typeof schema>;
export function SetPasswordPage() {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const location = useLocation();
const { loading } = useAppSelector((s) => s.setPassword);
const signupEmail = (location.state as { email?: string } | null)?.email ?? '';
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: { email: signupEmail },
});
const onSubmit = async (values: FormValues) => {
dispatch(setPasswordStart());
try {
const res = await fetch(`${BASE_API_URL}/auth/set-password`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userId: values.userId,
email: values.email,
verificationCode: values.verificationCode,
newPassword: values.newPassword,
confirmPassword: values.confirmPassword,
}),
});
if (!res.ok) {
const errorData = await res.json().catch(() => null);
throw new Error(errorData?.message ?? 'Failed to set password');
}
dispatch(setPasswordSuccess());
notify.success('Password set successfully');
navigate('/dashboard');
} catch (err) {
const msg = err instanceof Error ? err.message : 'Something went wrong';
dispatch(setPasswordFailure(msg));
notify.error(msg);
}
};
return (
<Paper p="xl" shadow="md" radius="md">
<Stack gap="lg">
<Stack gap={4}>
<Title order={2}>Set your password</Title>
<Text c="dimmed" size="sm">
A verification code has been sent to your email. Enter it below along
with your new password to complete registration.
</Text>
</Stack>
<form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="md">
<TextInput
label="User ID"
placeholder="Enter your user ID"
error={errors.userId?.message}
{...register('userId')}
/>
<TextInput
label="Email"
placeholder="you@example.com"
error={errors.email?.message}
{...register('email')}
/>
<TextInput
label="Verification Code"
placeholder="Enter the code from your email"
error={errors.verificationCode?.message}
{...register('verificationCode')}
/>
<PasswordInput
label="New Password"
placeholder="Enter a new password"
error={errors.newPassword?.message}
{...register('newPassword')}
/>
<PasswordInput
label="Confirm Password"
placeholder="Confirm your new password"
error={errors.confirmPassword?.message}
{...register('confirmPassword')}
/>
<Button type="submit" loading={loading} fullWidth mt="sm">
Set Password
</Button>
</Stack>
</form>
</Stack>
</Paper>
);
}
export { SetPasswordPage } from '@tria-plc/iamui-common';

View File

@@ -29,3 +29,13 @@ export function IamProviders({ children }: IamProvidersProps) {
</AuthProvider>
);
}
export function AuthProviders({ children }: { children: ReactNode }) {
return (
<AuthProvider>
<BrandingProvider>
{children}
</BrandingProvider>
</AuthProvider>
);
}

View File

@@ -1,12 +1,5 @@
import { Center, Box } from '@mantine/core';
import { Outlet } from 'react-router-dom';
export function AuthLayout() {
return (
<Center h="100vh" bg="gray.0">
<Box w={420}>
<Outlet />
</Box>
</Center>
);
return <Outlet />;
}

View File

@@ -1,14 +1,14 @@
import { Group, Text, ActionIcon, Burger } from '@mantine/core';
import { IconLogout } from '@tabler/icons-react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../features/auth/hooks/useAuth';
import { useAuthUser } from '@tria-plc/iamui-common';
interface AppHeaderProps {
onToggle: () => void;
}
export function AppHeader({ onToggle }: AppHeaderProps) {
const { logout } = useAuth();
const { logout } = useAuthUser();
const navigate = useNavigate();
const handleLogout = () => {

View File

@@ -1,5 +1,7 @@
import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom';
import {
Login,
SetPasswordPage,
UserManagementLayout,
UserManagementPage,
BulkUploadPage,
@@ -11,17 +13,18 @@ import {
import { ProtectedRoute } from './ProtectedRoute';
import { BackofficeLayout } from '../layouts/BackofficeLayout';
import { AuthLayout } from '../layouts/AuthLayout';
import { LoginPage } from '../features/auth/pages/LoginPage';
import { SignupPage } from '../features/auth/pages/SignupPage';
import { SetPasswordPage } from '../features/auth/pages/SetPasswordPage';
import { DashboardPage } from '../features/dashboard/pages/DashboardPage';
import { ItemPage } from '../features/item/pages/ItemPage';
import { AuditLogPageWrapper } from '../iam/pages/AuditLogPage';
import { IamProviders } from '../iam/IamProviders';
import { IamProviders, AuthProviders } from '../iam/IamProviders';
const router = createBrowserRouter([
{
element: <ProtectedRoute />,
element: (
<AuthProviders>
<ProtectedRoute />
</AuthProviders>
),
children: [
{
element: <BackofficeLayout />,
@@ -51,10 +54,13 @@ const router = createBrowserRouter([
],
},
{
element: <AuthLayout />,
element: (
<AuthProviders>
<AuthLayout />
</AuthProviders>
),
children: [
{ path: '/login', element: <LoginPage /> },
{ path: '/signup', element: <SignupPage /> },
{ path: '/login', element: <Login /> },
{ path: '/set-password', element: <SetPasswordPage /> },
],
},