3.4 Xây dựng MainLayout (ok)
C:\Users\Administrator\Desktop\start\src\routes\index.tsx
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import HomeRoutes from './HomeRoutes';
import LoginRoutes from './LoginRoutes';
function Routes() {
return (
<Router>
<HomeRoutes />
<LoginRoutes />
</Router>
)
}
export default Routes;
C:\Users\Administrator\Desktop\start\src\routes\HomeRoutes.tsx
import React from 'react';
import { Switch } from 'react-router-dom';
import { PATH } from './../constants/paths';
import Home from './../pages/Home';
import AuthenticatedGuard from './../guards/AuthenticatedGuard';
function HomeRoutes() {
return (
<Switch>
<AuthenticatedGuard exact={true} path={PATH.HOME} component={Home} />
</Switch>
)
}
export default HomeRoutes;
C:\Users\Administrator\Desktop\start\src\routes\LoginRoutes.tsx
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { PATH } from './../constants/paths';
import Login from './../pages/Login';
function LoginRoutes() {
return (
<Switch>
<Route path={PATH.LOGIN} component={Login} />
</Switch>
)
}
export default LoginRoutes;
C:\Users\Administrator\Desktop\start\src\pages\Home\index.tsx
import React from 'react';
import MainLayout from './../../layouts/MainLayout';
function Home() {
return (
<MainLayout>
<h2 className="mb-4">Home</h2>
</MainLayout>
)
}
export default Home;
C:\Users\Administrator\Desktop\start\src\pages\Login\index.tsx
import React, { useState } from 'react';
const Login = () => {
return (
<div className="container">
<div className="min-vh-100 row">
<div className="col-md-6 m-auto">
<form className="p-5 rounded-sm shadow text-center border">
<h2>Login</h2>
<p className="text-muted">Please enter your login and password!</p>
<input type="text" placeholder="Username" className="form-control form-control-lg mb-4"/>
<input type="password" placeholder="Password" className="form-control form-control-lg mb-4" />
<button type="submit" className="btn btn-block btn-info btn-lg">Login</button>
</form>
</div>
</div>
</div>
)
}
export default Login;
C:\Users\Administrator\Desktop\start\src\guards\AuthenticatedGuard\index.tsx
import React, { Component } from 'react';
import { Route, RouteProps, Redirect, RouteComponentProps } from 'react-router-dom';
import { connect } from 'react-redux';
import * as interfaces from './../../interface';
function AuthenticatedGuard(props: interfaces.Props) {
const { isAuthenticated, component: Component, ...rest } = props;
return (
<Route {...rest}
render = { props => {
if (!isAuthenticated) {
return <Redirect to="/login" />
}
return <Component {...props} />
}}
/>
)
}
const mapStateToProps = (state: any) => ({
isAuthenticated: true
})
const mapDispatchToProps = (dispatch: any) => ({
})
export default connect(mapStateToProps, mapDispatchToProps)(AuthenticatedGuard);
C:\Users\Administrator\Desktop\start\src\interface\index.tsx
import React, {ReactNode} from 'react';
import { RouteProps, RouteComponentProps } from 'react-router-dom';
export interface ReqLogin {
username: string
password: string
}
export interface Res {
data: any
message: string
}
export interface ResLoginApi extends Res {
data: {
access_token: string
}
}
export interface ReduxProps {
isAuthenticated: boolean
}
export interface Props extends ReduxProps, RouteProps {
component: React.ComponentType < RouteComponentProps >
}
export interface ActionRedux {
type: any
payload?: any
}
export interface ResLogin extends ActionRedux {
}
export interface PropsNodes {
children: ReactNode
}
export interface Product {
id: string
name: string
quantity: number
price: number
}
export interface ResGetProductApi extends Res {
data: {
products: Product[]
}
}
export interface ResGetProduct extends ActionRedux {
payload: ResGetProductApi
}
export interface ResGetProductItemApi extends Res {
data: {
product: Product
}
}
export interface ResGetProductItem extends ActionRedux {
payload: ResGetProductItemApi
}
C:\Users\Administrator\Desktop\start\src\reducer\login.tsx
import * as types from './../constants/login';
import produce from 'immer';
const initialState = {
loading: false
}
export const loginReducer = (state = initialState, action:any) =>
produce(state, draft => {
switch (action.type) {
case types.LOGIN_REQUESTED:
draft.loading = true
break
case types.LOGIN_SUCCESS:
draft.loading = false
break
case types.LOGIN_FAILED:
draft.loading = false
break
default:
return state
}
})
C:\Users\Administrator\Desktop\start\src\reducer\app.tsx
import * as types from './../constants/login';
import produce from 'immer';
const initialState = {
isAuthenticated: false,
closeSideNav: false
}
export const AppReducer = (state = initialState, action:any) =>
produce(state, draft => {
switch (action.type) {
case types.LOGOUT:
localStorage.removeItem('token')
draft.isAuthenticated = false
break
case types.LOGIN_SUCCESS:
draft.isAuthenticated = true
break
default:
return state
}
})
C:\Users\Administrator\Desktop\start\src\layouts\MainLayout.tsx
import React, { ReactNode } from 'react';
import Header from './../components/Header'
import SideNav from './../components/SideNav';
interface Props {
children: ReactNode
}
function MainLayout(props: Props) {
const { children } = props
return (
<div className="wrapper d-flex align-items-stretch">
<SideNav />
<main className="flex-grow-1 mw-100 overflow-auto min-vh-100">
<Header />
<div className="content mt-3 p-3">{children}</div>
</main>
</div>
)
}
export default MainLayout;
C:\Users\Administrator\Desktop\start\public\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app"/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
C:\Users\Administrator\Desktop\start\src\components\Header\index.tsx
import React from 'react';
import { LogoutIcon } from './Header.styles';
import { PATH } from './../../constants/paths';
import { useHistory } from 'react-router-dom';
import * as interfaces from './../../interface';
const Header = () => {
return (
<header className="d-flex bg-light justify-content-between p-3 shadow-sm">
<button className="btn btn-primary">
<svg
xmlns="http://www.w3.org/2000/svg"
height="20"
viewBox="0 -53 384 384"
width="20"
>
<g>
<path
d="m368 154.667969h-352c-8.832031 0-16-7.167969-16-16s7.167969-16 16-16h352c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16zm0 0"
data-original="#000000"
data-old_color="#000000"
/>
<path
d="m368 32h-352c-8.832031 0-16-7.167969-16-16s7.167969-16 16-16h352c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16zm0 0"
data-original="#000000"
data-old_color="#000000"
/>
<path
d="m368 277.332031h-352c-8.832031 0-16-7.167969-16-16s7.167969-16 16-16h352c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16zm0 0"
data-original="#000000"
data-old_color="#000000"
/>
</g>
</svg>
</button>
<LogoutIcon className="btn btn-outline-secondary">
Logout
</LogoutIcon>
</header>
)
}
export default Header;
C:\Users\Administrator\Desktop\start\src\components\SideNav\index.tsx
import React from 'react';
import { NavLink } from 'react-router-dom';
import { Footer, Logo, Menu, Nav } from './SideNav.styles';
import { PATH } from './../../constants/paths';
import home from './../../assets/images/home.svg'
import list from './../../assets/images/list.svg'
function SideNav() {
return (
<Nav className="close">
<h1>
<Logo href="https://xdevclass.com/" target="_blank" rel="noopener noreferrer" className="text-white">X</Logo>
</h1>
<Menu className="list-unstyled mb-5">
<li>
<NavLink exact to={PATH.HOME}> <img src={home} alt="" /> <span>Home</span></NavLink>
</li>
<li>
<NavLink to={PATH.PRODUCT}><img src={list} alt="" /><span>Product</span></NavLink>
</li>
</Menu>
<Footer>
<p>
Copyright ©{new Date().getFullYear()} All rights reserved | This template is made with by
<a href="https://xdevclass.com/" target="_blank" rel="noopener noreferrer" className="ml-1 text-white">XdevClass</a>
</p>
</Footer>
</Nav>
)
}
export default SideNav;
Last updated
Was this helpful?