#4 create auth form

parent 2bd6873f
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-redux": "^9.1.0", "react-redux": "^9.1.0",
"react-router-dom": "^6.22.3", "react-router-dom": "^6.22.3",
"redux-persist": "^6.0.0" "redux-persist": "^6.0.0",
"sass": "^1.87.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.43", "@types/react": "^18.2.43",
......
This diff is collapsed.
import { Routes } from 'react-router-dom'; import { shallowEqual } from 'react-redux';
import { Route, Routes } from 'react-router-dom';
import WrapperLayout from './components/layout/WrapperLayout';
import { ProtectedRoute } from './components/ui/routes/ProtectedRoute';
import Auth from './pages/auth/Auth';
import { useAppSelector } from './store/hooks';
function App() { function App() {
return <Routes></Routes>; const { user } = useAppSelector((state) => state.user, shallowEqual);
return (
<Routes>
<Route
path="/"
element={
<ProtectedRoute user={user}>
<WrapperLayout />
</ProtectedRoute>
}
></Route>
<Route path="/auth" element={<Auth />} />
</Routes>
);
} }
export default App; export default App;
import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined } from '@ant-design/icons';
import { Button, Layout, Menu, theme } from 'antd';
import { MenuItemType } from 'antd/es/menu/interface';
import { useState } from 'react';
import { Outlet } from 'react-router-dom';
const { Header, Sider, Content } = Layout;
const items: MenuItemType[] = [
{
key: '1',
icon: <UserOutlined />,
label: 'nav 1',
},
];
const WrapperLayout = () => {
const [collapsed, setCollapsed] = useState(false);
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
return (
<Layout style={{ height: '100vh' }}>
<Sider trigger={null} collapsible collapsed={collapsed}>
<div className="demo-logo-vertical" />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']} items={items} />
</Sider>
<Layout>
<Header style={{ padding: 0, background: colorBgContainer }}>
<Button
type="text"
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
onClick={() => setCollapsed(!collapsed)}
style={{
fontSize: '16px',
width: 64,
height: 64,
}}
/>
</Header>
<Content
style={{
margin: '24px 16px',
padding: 24,
minHeight: 280,
background: colorBgContainer,
borderRadius: borderRadiusLG,
}}
>
<Outlet />
</Content>
</Layout>
</Layout>
);
};
export default WrapperLayout;
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { Button, Checkbox, Flex, Form, Input } from 'antd';
export type AuthField = {
username: string;
password: string;
isLogin: boolean;
};
const AuthForm = () => {
const onFinish = (values: AuthField) => {
console.log('Received values of form: ', values);
};
return (
<Form
name="login"
initialValues={{ remember: true }}
style={{ maxWidth: 360 }}
onFinish={onFinish}
>
<Form.Item<AuthField>
name="username"
rules={[{ required: true, message: 'Please input your Username!' }]}
>
<Input prefix={<UserOutlined />} placeholder="Username" />
</Form.Item>
<Form.Item<AuthField>
name="password"
rules={[{ required: true, message: 'Please input your Password!' }]}
>
<Input prefix={<LockOutlined />} type="password" placeholder="Password" />
</Form.Item>
<Form.Item>
<Flex justify="space-between" align="center">
<Form.Item<AuthField> name="isLogin" valuePropName="checked" noStyle>
<Checkbox>Check this if login</Checkbox>
</Form.Item>
</Flex>
</Form.Item>
<Form.Item>
<Button block type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
export default AuthForm;
import React from 'react';
import { Navigate } from 'react-router-dom';
import { IUser } from '../../../types/user';
type ProtectedRouteProps = {
user: IUser | null;
children: React.ReactNode;
};
export const ProtectedRoute = ({ user, children }: ProtectedRouteProps) => {
if (!user) {
return <Navigate to="/auth" replace />;
}
return children;
};
import React from 'react' import React from 'react';
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux' import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom';
import { PersistGate } from 'redux-persist/integration/react' import { PersistGate } from 'redux-persist/integration/react';
import App from './App.tsx' import App from './App.tsx';
import store, { persistor } from './store/index.tsx' import store, { persistor } from './store/index.tsx';
import './styles/main.scss';
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode> <React.StrictMode>
......
import AuthForm from '../../components/ui/form/AuthForm';
import '../../styles/auth.scss';
const Auth = () => {
return (
<div className="Auth">
<AuthForm />
</div>
);
};
export default Auth;
import { configureStore } from '@reduxjs/toolkit' import { configureStore } from '@reduxjs/toolkit';
import { import {
FLUSH, FLUSH,
PAUSE, PAUSE,
...@@ -8,8 +8,9 @@ import { ...@@ -8,8 +8,9 @@ import {
PURGE, PURGE,
REGISTER, REGISTER,
REHYDRATE, REHYDRATE,
} from 'redux-persist' } from 'redux-persist';
import storage from 'redux-persist/lib/storage' import storage from 'redux-persist/lib/storage';
import userReducer from './slices/userSlice';
const persistConfig = { const persistConfig = {
key: 'root', key: 'root',
...@@ -18,11 +19,11 @@ const persistConfig = { ...@@ -18,11 +19,11 @@ const persistConfig = {
whitelist: ['user'], whitelist: ['user'],
}; };
const persistSlice = persistReducer(persistConfig); const persistUser = persistReducer(persistConfig, userReducer);
const store = configureStore({ const store = configureStore({
reducer: { reducer: {
root: persistSlice user: persistUser,
}, },
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ getDefaultMiddleware({
......
import { createSlice } from '@reduxjs/toolkit';
import { IUser } from '../../types/user';
interface State {
user: IUser | null;
error: Error | null;
loading: boolean;
}
const initialState: State = {
user: null,
error: null,
loading: false,
};
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {},
});
export default userSlice.reducer;
.Auth {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
* {
margin: 0;
box-sizing: border-box;
}
export interface IUser {
id: number;
username: string;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment