Difference between revisions of "Creating Admin Portal Project in React"

From Logic Wiki
Jump to: navigation, search
 
(5 intermediate revisions by the same user not shown)
Line 106: Line 106:
 
and replace '''<a''' with '''<Link''' and '''href''' with '''to'''. ie:
 
and replace '''<a''' with '''<Link''' and '''href''' with '''to'''. ie:
 
  <Link to="/product">
 
  <Link to="/product">
 +
== Http Client - Preparation ==
 +
install Axios
 +
npm i axios
 +
install Toastify
 +
npm i react-toastify
 +
in app.js import Toastfy and css file and add a tag for container
 +
import {ToastContainer} from "react-toastify";
 +
import "react-toastify/dist/ReactToastify.css";
 +
 +
  render() {
 +
    return (
 +
      <div className="App">
 +
        <ToastContainer/>
 +
....
 +
=== Creating httpService.js ===
 +
create a folder "services" and within this folder create a file names "httpService.js"
 +
<pre class="brush:js;">
 +
import axios from "axios";
 +
import { toast } from "react-toastify";
 +
import log from "./logService.js";
 +
 +
axios.interceptors.response.use(null, error => {
 +
  const expectedError =
 +
    error.response &&
 +
    error.response.status >= 400 &&
 +
    error.response.status < 500;
 +
  if (!expectedError) {
 +
    logger.log(error);
 +
    toast.error("An unexpected error occured.");
 +
  }
 +
 +
  return Promise.reject(error);
 +
});
 +
 +
export default {
 +
  get: axios.get,
 +
  post: axios.post,
 +
  put: axios.put,
 +
  delete: axios.delete
 +
};
 +
 +
</pre>
 +
here we use interceptor for responses and capture any unexpected errors. display them in a toaster and send a copy to logService which is basically doing nothing at the moment.
 +
==== logService ====
 +
<pre class="brush:js;">
 +
function init() {}
 +
 +
function log(error) {
 +
  console.log(error);
 +
}
 +
 +
export default {
 +
  init,
 +
  log
 +
};
 +
 +
</pre>
 +
It is not functional but keep it as a placeholder for future.
 +
 +
=== Config.json ===
 +
create a config.json file in the root to keep config elements in it. ie :
 +
<pre>
 +
{
 +
  "loginApiEndpoint": "http://localhost:10795",
 +
  "apiEndpoint": "http://localhost:20795"
 +
}
 +
 +
</pre>
 +
 +
 +
== Authentication & Authorisation ==
 +
=== Login Form ===
 +
==== input.jsx ====
 +
Instead of repeating input fields and validations etc. we can create an input component and reuse it when we need it.
 +
# create a folder '''common'''
 +
# create a file '''input.jsx'''
 +
The content of input.jsx is
 +
<pre class="brush:js;">
 +
import React from "react";
 +
 +
const Input = ({ name, label, value, error, onChange }) => {
 +
  return (
 +
    <div className="form-group">
 +
      <label htmlFor={name}>{label}</label>
 +
      <input
 +
        id={name}`
 +
        name={name}
 +
        type="text"
 +
        className="form-control"
 +
        autoFocus
 +
        onChange={onChange}
 +
        value={value}
 +
      />
 +
      {error && <div className="alert alert-danger">{error}</div>}
 +
    </div>
 +
  );
 +
};
 +
 +
export default Input;
 +
 +
</pre>
 +
==== loginForm.jsx ====
 +
<pre class="brush:js;">
 +
import React, { Component } from "react";
 +
import "./loginForm.css";
 +
import Input from "../common/input";
 +
 +
 +
</pre>
 +
=== Authentication Service ===
 +
Create "'''authService.js'''" in the '''services''' folder
 +
<pre class="brush:js;">
 +
import http from "./httpService";
 +
import { loginApiEndpoint } from "../config.json"
 +
 +
const apiEndpoint = loginApiEndpoint + "/api/Login";
 +
 +
export function login(email, password) {
 +
    return http.post(apiEndpoint, {Email:email, Password:password, Group:"Administrator"})
 +
}
 +
</pre>

Latest revision as of 14:47, 28 December 2018


Starting a project

Setting Up The Environment

  • install node
  • install create-react-app
npm i -g create-react-app

install VS Code

  • install VS Code
  • install VS Code snippets - Click Extensions icon on the left sidebar and search and install
    • Simple React Snippets by Burke Holland
    • Prettier by Esben Petersen
      • Set Format on Save
    • Auto Import by Sergey Korenuk

in VS Code go to File / Preferences / Settings and add the line below in UserSettings section

 "editor.formatOnSave":true

Creating React App

Go to the project folder

npx create-react-app adminportal
cd adminportal

adminportal is lowercase because [Create React App] doesn't like capitals

Installing Bootstrap

npm i bootstrap@4.1.1

go to ./src/index.js and add this line

import 'bootstrap/dist/css/bootstrap.css';

Install reactstrap

npm install --save reactstrap

Check it's site for more details

https://reactstrap.github.io/

Installing & Using FontAwesome Icons

npm i --save @fortawesome/fontawesome-svg-core 
npm i --save @fortawesome/free-solid-svg-icons 
npm i --save @fortawesome/react-fontawesome

Then in your app, import and add an icon to the Library:App.js

import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faIgloo } from '@fortawesome/free-solid-svg-icons'

library.add(faIgloo)

Lastly, use the component and icon in your JSX:

 import React from 'react'
 import { faSearch } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 
 export const Food = () => (
  <div>
     <FontAwesomeIcon icon={faSearch} />
  </div>
 )

https://scotch.io/tutorials/using-font-awesome-5-with-react

Install nodemon

it restarts the application when file contents changes.

npm install --save-dev nodemon

Usage

npx nodemon index.js

Coding

Routing

install router

npm i react-router-dom

in index.js file add this line

import { BrowserRouter } from "react-router-dom";

and wrap <App/> with <BrowserRouter> like below

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

in App.js import Route & Switch

import { Route, Switch } from "react-router-dom";

and add these lines to render()

    return (
      <div className="App">
        <TopBar />
        <SideBar />
        <header className="App-header">
          <div className="content">
            <Switch>
              <Route path="/admin" component={Admin} />
            </Switch>
          </div>
        </header>
      </div>
    );

So in this scenario there is one top bar and a left side bar. They are static. The rest of the screen (div with className="content") will be different in every page.

Switch is for stopping rendering to go to next Route which matches the satisfying criteria. Like:

if the first route is path="/admin" and the second route is "/" without a switch here it will render both of them back to back.

Links

In sideBar component when I click a link it normalyy reload the whole page as it uses <a> tag to prevent this import Link

import {Link} from "react-router-dom";

and replace <a with <Link and href with to. ie:

<Link to="/product">

Http Client - Preparation

install Axios

npm i axios

install Toastify

npm i react-toastify

in app.js import Toastfy and css file and add a tag for container

import {ToastContainer} from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

 render() {
   return (
       <ToastContainer/>
....

Creating httpService.js

create a folder "services" and within this folder create a file names "httpService.js"

import axios from "axios";
import { toast } from "react-toastify";
import log from "./logService.js";

axios.interceptors.response.use(null, error => {
  const expectedError =
    error.response &&
    error.response.status >= 400 &&
    error.response.status < 500;
  if (!expectedError) {
    logger.log(error);
    toast.error("An unexpected error occured.");
  }

  return Promise.reject(error);
});

export default {
  get: axios.get,
  post: axios.post,
  put: axios.put,
  delete: axios.delete
};

here we use interceptor for responses and capture any unexpected errors. display them in a toaster and send a copy to logService which is basically doing nothing at the moment.

logService

function init() {}

function log(error) {
  console.log(error);
}

export default {
  init,
  log
};

It is not functional but keep it as a placeholder for future.

Config.json

create a config.json file in the root to keep config elements in it. ie :

{
  "loginApiEndpoint": "http://localhost:10795",
  "apiEndpoint": "http://localhost:20795"
}


Authentication & Authorisation

Login Form

input.jsx

Instead of repeating input fields and validations etc. we can create an input component and reuse it when we need it.

  1. create a folder common
  2. create a file input.jsx

The content of input.jsx is

import React from "react";

const Input = ({ name, label, value, error, onChange }) => {
  return (
    <div className="form-group">
      <label htmlFor={name}>{label}</label>
      <input
        id={name}`
        name={name}
        type="text"
        className="form-control"
        autoFocus
        onChange={onChange}
        value={value}
      />
      {error && <div className="alert alert-danger">{error}</div>}
    </div>
  );
};

export default Input;

loginForm.jsx

import React, { Component } from "react";
import "./loginForm.css";
import Input from "../common/input";


Authentication Service

Create "authService.js" in the services folder

import http from "./httpService";
import { loginApiEndpoint } from "../config.json"

const apiEndpoint = loginApiEndpoint + "/api/Login";

export function login(email, password) { 
    return http.post(apiEndpoint, {Email:email, Password:password, Group:"Administrator"})
}