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?