Backend DevelopmentFrontend DevelopmentVueJs Tutorials

Building Ecommerce Website With Lumen Laravel And Nuxtjs 3: Preparing Admin Panel

Building Ecommerce Website With PHP Lumen Laravel And Nuxtjs

In this article of this series i will prepare the admin panel and how to compose pages and layouts in nuxtjs, then i will add the login page and connect it with the login service.

 

 

If you remember from the first part when we setup two Nuxtjs projects, one project for the website and the other for the admin then we moved the admin project into the website so we will work on the admin project. I selected an html template which uses bootstrap 4 and prepared it for our admin which you can download it from this link.

After downloading the template go to online-shop-frontend/admin/ directory and extract the template files into the static/ folder. Then we need to update nuxt.config.js to load the template css and js files:

online-shop-frontend/admin/nuxt.config.js

export default {
  /*
  ** Nuxt rendering mode
  ** See https://nuxtjs.org/api/configuration-mode
  */
  mode: 'spa',
  /*
  ** Nuxt target
  ** See https://nuxtjs.org/api/configuration-target
  */
  target: 'server',
  /*
  ** Headers of the page
  ** See https://nuxtjs.org/api/configuration-head
  */
  head: {
    title: 'online shop dashboard',
    bodyAttrs: {
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'online shop dashboard' }
    ],
    link: [
      { rel: 'stylesheet', type: 'text/css', href: '/css/font-face.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/vendor/font-awesome-4.7/css/font-awesome.min.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/vendor/font-awesome-5/css/fontawesome-all.min.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/vendor/mdi-font/css/material-design-iconic-font.min.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/vendor/bootstrap-4.1/bootstrap.min.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/vendor/css-hamburgers/hamburgers.min.css' },
      { rel: 'stylesheet', type: 'text/css', href: '/css/theme.css' }
    ],
    script: [
      {
        src: '/vendor/jquery-3.2.1.min.js',
        type: 'text/javascript'
      },
      {
        src: '/vendor/bootstrap-4.1/popper.min.js',
        type: 'text/javascript'
      },
      {
        src: '/vendor/bootstrap-4.1/bootstrap.min.js',
        type: 'text/javascript'
      }
    ]
  },
  /*
  ** Global CSS
  */
  css: [
  ],
  /*
  ** Plugins to load before mounting the App
  ** https://nuxtjs.org/guide/plugins
  */
  plugins: [
  ],
  /*
  ** Auto import components
  ** See https://nuxtjs.org/api/configuration-components
  */
  components: true,
  /*
  ** Nuxt.js dev-modules
  */
  buildModules: [
  ],
  /*
  ** Nuxt.js modules
  */
  modules: [
    // Doc: https://bootstrap-vue.js.org
    // 'bootstrap-vue/nuxt',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
  ],
  /*
  ** Axios module configuration
  ** See https://axios.nuxtjs.org/options
  */
  axios: {
      baseURL: 'http://localhost/online-shop-backend/public/'
  },
  /*
  ** Build configuration
  ** See https://nuxtjs.org/api/configuration-build/
  */
  build: {

  },
  srcDir: __dirname,
  buildDir: '.nuxt/admin'
}

As you see in the head section i load some stylesheets and scripts for our theme. There is one theme script file js/main.js we can’t load it from nuxt.config.js, that’s because this script have to be loaded after the document is fully mounted and loaded, so we load this script from the default layout mounted() hook.

You might notice that that i updated axios baseURL option to the base url of the backend services, this is a nice feature in Nuxtjs so that you only specify the base url once for all requests.

Note that whenever you update nuxt.config.js you need to re-run ‘npm run dev’ command so that the Nuxt server can recognize the updates you made to that file.

Open admin/layouts/default.vue and update it as follows:

<template>
  <div class="page-wrapper">

      <Nuxt />

  </div>
</template>

<script>
    export default {
        mounted() {
          const script = document.createElement("script")
          script.src = "/js/main.js"
          script.type = "text/javascript"
          document.head.appendChild(script)
        }
    }
</script>

<style scoped>

</style>

Now if you run “npm run dev” and go to http://localhost:4000 you will see the admin panel.

 

Preparing Default Layout

Let’s clean up the template and prepare the default layout for our admin panel. The default layout is located in admin/layouts. Open admin/layouts/default.vue and add this code:

admin/layouts/default.vue

<template>
  <div class="page-wrapper">

    <mobile-header></mobile-header>

    <admin-sidebar></admin-sidebar>

    <div class="page-container">

      <admin-header></admin-header>

      <Nuxt />

    </div>

  </div>
</template>

<script>
    import MobileHeader from "../components/partials/MobileHeader";
    import AdminSidebar from "../components/partials/AdminSidebar";
    import AdminHeader from "../components/partials/AdminHeader";

    export default {
        components: {AdminHeader, AdminSidebar, MobileHeader},
        mounted() {
          const script = document.createElement("script")
          script.src = "/js/main.js"
          script.type = "text/javascript"
          document.head.appendChild(script)
        }
    }
</script>

<style scoped>

</style>

We injected some partial components into the main layout, these partial components located in admin/components/partials/ directory.

Partial Components

admin/components/partials/AdminHeader.vue

<template>
    <header class="header-desktop">
      <div class="section__content section__content--p30">
        <div class="container-fluid">
          <div class="header-wrap">
            <form class="form-header" action="" method="POST">
              <input class="au-input au-input--xl" type="text" name="search" placeholder="Search for data...">
              <button class="au-btn--submit" type="submit">
                <i class="zmdi zmdi-search"></i>
              </button>
            </form>
            <div class="header-button">
              <div class="noti-wrap">
                <div class="noti__item js-item-menu">
                  <i class="zmdi zmdi-email"></i>
                  <span class="quantity">1</span>
                  <div class="email-dropdown js-dropdown">
                    <div class="email__title">
                      <p>You have 3 New Emails</p>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-06.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, 3 min ago</span>
                      </div>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-05.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, Yesterday</span>
                      </div>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-04.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, April 12,,2018</span>
                      </div>
                    </div>
                    <div class="email__footer">
                      <a href="#">See all emails</a>
                    </div>
                  </div>
                </div>
                <div class="noti__item js-item-menu">
                  <i class="zmdi zmdi-notifications"></i>
                  <span class="quantity">3</span>
                  <div class="notifi-dropdown js-dropdown">
                    <div class="notifi__title">
                      <p>You have 3 Notifications</p>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c1 img-cir img-40">
                        <i class="zmdi zmdi-email-open"></i>
                      </div>
                      <div class="content">
                        <p>You got a email notification</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c2 img-cir img-40">
                        <i class="zmdi zmdi-account-box"></i>
                      </div>
                      <div class="content">
                        <p>Your account has been blocked</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c3 img-cir img-40">
                        <i class="zmdi zmdi-file-text"></i>
                      </div>
                      <div class="content">
                        <p>You got a new file</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__footer">
                      <a href="#">All notifications</a>
                    </div>
                  </div>
                </div>
              </div>
              <div class="account-wrap">
                <div class="account-item clearfix js-item-menu">
                  <div class="image">
                    <img src="images/icon/avatar-01.jpg" alt="John Doe">
                  </div>
                  <div class="content">
                    <a class="js-acc-btn" href="#">john doe</a>
                  </div>
                  <div class="account-dropdown js-dropdown">
                    <div class="info clearfix">
                      <div class="image">
                        <a href="#">
                          <img src="images/icon/avatar-01.jpg" alt="John Doe">
                        </a>
                      </div>
                      <div class="content">
                        <h5 class="name">
                          <a href="#">john doe</a>
                        </h5>
                        <span class="email">johndoe@example.com</span>
                      </div>
                    </div>
                    <div class="account-dropdown__body">
                      <div class="account-dropdown__item">
                        <a href="#">
                          <i class="zmdi zmdi-account"></i>Account</a>
                      </div>
                    </div>
                    <div class="account-dropdown__footer">
                      <a href="#">
                        <i class="zmdi zmdi-power"></i>Logout</a>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </header>
</template>

<script>
    export default {
        name: "admin-header"
    }
</script>

admin/components/partials/AdminSidebar.vue

<template>
  <aside class="menu-sidebar d-none d-lg-block">
    <div class="logo">
      <a href="#">
        Online <strong>Shop</strong>
      </a>
    </div>
    <div class="menu-sidebar__content js-scrollbar1 ps">
      <nav class="navbar-sidebar">
        <nav-menu ulclass="list-unstyled navbar__list"></nav-menu>
      </nav>
      <div class="ps__rail-x" style="left: 0px; bottom: 0px;"><div class="ps__thumb-x" tabindex="0" style="left: 0px; width: 0px;"></div></div><div class="ps__rail-y" style="top: 0px; right: 0px;"><div class="ps__thumb-y" tabindex="0" style="top: 0px; height: 0px;"></div></div></div>
  </aside>
</template>

<script>
    import NavMenu from "./NavMenu";
    export default {
        name: "admin-sidebar",
      components: {NavMenu}
    }
</script>

<style scoped>
  .logo a {
    color: #6c757d;
    font-size: 31px;
  }
</style>

admin/components/partials/MobileHeader.vue

<template>
  <header class="header-mobile d-block d-lg-none">
    <div class="header-mobile__bar">
      <div class="container-fluid">
        <div class="header-mobile-inner">
          <a class="logo" href="#">
            Online <strong>Shop</strong>
          </a>
          <button class="hamburger hamburger--slider" type="button">
                            <span class="hamburger-box">
                                <span class="hamburger-inner"></span>
                            </span>
          </button>
        </div>
      </div>
    </div>
    <nav class="navbar-mobile">
      <div class="container-fluid">
        <nav-menu ulclass="navbar-mobile__list list-unstyled"></nav-menu>
      </div>
    </nav>
  </header>
</template>

<script>
    import NavMenu from "./NavMenu";
    export default {
        name: "mobile-header",
      components: {NavMenu}
    }
</script>

<style scoped>
  a.logo {
    color: #6c757d;
    font-size: 31px;
  }
</style>

admin/components/partials/NavMenu.vue

<template>
  <ul :class="ulclass">
    <li class="active">
      <a href="#">
        <i class="fas fa-tachometer-alt"></i>Dashboard</a>
    </li>
    <li>
      <a href="#">
        <i class="fas fa-list"></i>Categories</a>
    </li>
    <li>
      <a href="#">
        <i class="fas fa-television"></i>Brands</a>
    </li>
    <li>
      <a href="#">
        <i class="fas fa-shopping-cart"></i>Products</a>
    </li>
    <li>
      <a href="#">
        <i class="fas fa-gears"></i>Orders</a>
    </li>
    <li> 
        <a href="#"> <i class="fas fa-gears"></i>Pending Orders</a> 
    </li>
    <li>
      <a href="#">
        <i class="fas fa-users"></i>Users</a>
    </li>
    <li>
      <a href="#">
        <i class="fas fa-sign-out-alt"></i>Logout</a>
    </li>
  </ul>
</template>

<script>
    export default {
        name: "nav-menu",
        props: ['ulclass']
    }
</script>

<style scoped>

</style>

Also let’s update the homepage of the admin panel, so open admin/pages/index.vue and add this code:

admin/pages/index.vue

<template>
  <div class="main-content">
    <div class="section__content section__content--p30">
      <div class="container-fluid">
        <div class="row">
          <div class="col-md-12">
            <div class="overview-wrap">
              <h2 class="title-1">overview</h2>
            </div>
          </div>
        </div>
        <div class="row m-t-25">
          <div class="col-sm-6 col-lg-3">
            <div class="overview-item overview-item--c1">
              <div class="overview__inner">
                <div class="overview-box clearfix">
                  <div class="icon">
                    <i class="zmdi zmdi-account-o"></i>
                  </div>
                  <div class="text">
                    <h2>10368</h2>
                    <span>members online</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="col-sm-6 col-lg-3">
            <div class="overview-item overview-item--c2">
              <div class="overview__inner">
                <div class="overview-box clearfix">
                  <div class="icon">
                    <i class="zmdi zmdi-shopping-cart"></i>
                  </div>
                  <div class="text">
                    <h2>388,688</h2>
                    <span>items solid</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="col-sm-6 col-lg-3">
            <div class="overview-item overview-item--c3">
              <div class="overview__inner">
                <div class="overview-box clearfix">
                  <div class="icon">
                    <i class="zmdi zmdi-calendar-note"></i>
                  </div>
                  <div class="text">
                    <h2>1,086</h2>
                    <span>this week</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="col-sm-6 col-lg-3">
            <div class="overview-item overview-item--c4">
              <div class="overview__inner">
                <div class="overview-box clearfix">
                  <div class="icon">
                    <i class="zmdi zmdi-money"></i>
                  </div>
                  <div class="text">
                    <h2>$1,060,386</h2>
                    <span>total earnings</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: "index"
  }
</script>

<style scoped>

</style>

At this point refresh the page and you will see the updated template along with the sidebar links we will work with in future lessons.

 

Login Page

Let’s finish this part by preparing the login page and connecting it with the login service we have done previously in lumen. Note that only users who have assigned the flag “is_super_admin=1” is allowed to access the dashboard.

 

I will create a new layout for the login page in admin/layouts:

admin/layouts/login.vue

<template>
    <div class="page-wrapper">
      <div class="page-content--bge5">
        <div class="container">

          <div class="login-wrap">
            <div class="login-content">
              <div class="login-logo">
                <a href="#">
                  <strong>Online Shop</strong> Admin Login
                </a>
              </div>

              <Nuxt/>

            </div>
          </div>
        </div>
      </div>
    </div>
</template>

<script>
    export default {
        name: "login"
    }
</script>

<style scoped>
  .login-logo a {
    color: #6c757d;
    font-size: 31px;
  }
</style>

Next create the login page in admin/pages with the code below:

admin/pages/login.vue

<template>
  <div class="login-form">
    <div class="alert alert-danger" v-if="this.error_message">{{ this.error_message }}</div>
    <div class="alert alert-danger" v-for="item in this.validation_errors" :key="item">{{ item }}</div>
    <form action="#" method="post" @submit.prevent="login()">
      <div class="form-group">
        <label>Email Address</label>
        <input class="au-input au-input--full" type="email" name="email" placeholder="Email" v-model="login_data.email">
      </div>
      <div class="form-group">
        <label>Password</label>
        <input class="au-input au-input--full" type="password" name="password" placeholder="Password" v-model="login_data.password">
      </div>
      <button class="au-btn au-btn--block au-btn--green m-b-20" type="submit">sign in</button>
    </form>
  </div>
</template>

<script>
    export default {
        data() {
          return {
            login_data: {
              email: '',
              password: ''
            },
            error_message: '',
            validation_errors: []
          }
        },
        name: "login",
        layout: "login",
        methods: {
          login() {
            this.validation_errors = [];
            this.error_message = '';

            this.$axios.$post('api/login', this.login_data).then(response => {
              this.$router.push('/');
            }).catch(error => {
              this.error_message = error.response.data.message;

              if(error.response.data.errors) {
                for(let key in error.response.data.errors) {
                  this.validation_errors.push(error.response.data.errors[key][0]);
                }
              }
            });
          }
        }
    }
</script>

<style scoped>

</style>

As you see above this is a simple login form which has two fields email and password, i binded these fields with that local component state from the data() function, then i added a login() method which will be fired on form submit. I utitlize Nuxt axios module to make http calls to server side. In this case i redirect the user to the dashboard if login success otherwise we display a error message as long as validation errors if found.

To try this navigate to http://localhost:4000/login you should see the login page, try to play with it.

 

 

Protecting Pages With Middleware

There is still one problem already exist with the login form above is that the user can access any page despite he is login or not, so we need to persist the login details using some mechanism like local storage, secondly we need to tell the application to prevent access to protected pages and redirect the user to login page if this happens.

The most preferred way to deny access to certain pages is using Nuxt middleware. The middleware is a normal function that act like a filter that executes with every request so for example in the middleware we can check if the local storage contains an access token in this case we proceed otherwise we redirect the user to the login page.

Auth Middleware

Create a new javascript file name it auth.js in admin/middleware directory with the following code:

admin/middleware/auth.js

export default function({redirect}) {

  if(localStorage.getItem('is_authenticated') === null || localStorage.getItem('auth_token') === null || localStorage.getItem('user_data') === null) {
    redirect('/login');
  } else {
    let user = localStorage.getItem('user_data');
    user = JSON.parse(user);
    if(user.is_super_admin !== 1) {

      localStorage.removeItem('auth_token');
      localStorage.removeItem('is_authenticated');
      localStorage.removeItem('user_data');

      redirect('/login');
    }
  }
}

The middleware is a javscript function as shown in this code. I checked for some variables in the local storage to be not null. In this case i redirect to login page. Also i check for is_super_admin flag, this is important to prevent nonadmin users from accessing the admin panel.

To use this middleware in any component we need to protect supply the middleware property as shown, let’s apply it to admin/pages/index.vue

export default {
    name: "index",
    middleware: "auth"
  }

 

Now we need to update the login page to store login details on local storage. Open pages/login.vue and update the login function like this:

methods: {
          login() {
            this.validation_errors = [];
            this.error_message = '';

            this.clearStorage();

            this.$axios.$post('api/login', this.login_data).then(response => {

              this.saveIntoStorage(response);

              this.$router.push('/');
            }).catch(error => {
              this.error_message = error.response.data.message;

              if(error.response.data.errors) {
                for(let key in error.response.data.errors) {
                  this.validation_errors.push(error.response.data.errors[key][0]);
                }
              }
            });
          },
          clearStorage() {
            localStorage.removeItem('is_authenticated');
            localStorage.removeItem('auth_token');
            localStorage.removeItem('user_data');
          },
          saveIntoStorage(response) {
            localStorage.setItem('is_authenticated', 1);
            localStorage.setItem('auth_token', response.access_token);
            localStorage.setItem('user_data', JSON.stringify(response.user));
          }
        }

That’s it, now try to visit the admin homepage it will redirect you to the login screen, by supplying valid data you will get access as usual.

 

Check User Login Periodically

At this stage we are fine but there is one issue is that the access token has an expiration time so we need to run a periodic function to check if the user is logged in otherwise redirecting him to login screen, this is acheived in the default layout

admin/layouts/Default.vue

mounted() {
          const script = document.createElement("script")
          script.src = "/js/main.js"
          script.type = "text/javascript"
          document.head.appendChild(script);

          this.checkUserLogin();
        },
methods: {
          checkUserLogin() {
            // send request to check if the user is logged otherwise redirect him to login screen
                if(localStorage.getItem('auth_token') !== null && localStorage.getItem('auth_token') !== undefined) {
                  this.$axios.setHeader('Authorization', "Bearer " + localStorage.getItem('auth_token'));

                  this.$axios.$get('api/check-login').then(response => {
                    if (response.success !== 1) {

                      localStorage.removeItem('auth_token');
                      localStorage.removeItem('is_authenticated');
                      localStorage.removeItem('user_data');

                      this.$router.push('/login');
                    }
                  }).catch(err => {
                    localStorage.removeItem('auth_token');
                    localStorage.removeItem('is_authenticated');
                    localStorage.removeItem('user_data');

                    this.$router.push('/login');
                  });
                }
          }
        }

As you see i added a simple function to send a request in case there is auth token in local storage, i called this function from the mounted() life cycle hook. Then if the server responds with unauthorized we redirect the user to login screen and erase the local storage data.

 

User Details & Signing Out

Open admin/components/AdminHeader.vue to add the logout function and display the currently logged user details in the template header.

admin/components/AdminHeader.vue

<template>
    <header class="header-desktop">
      <div class="section__content section__content--p30">
        <div class="container-fluid">
          <div class="header-wrap">
            <form class="form-header" action="" method="POST">
              <input class="au-input au-input--xl" type="text" name="search" placeholder="Search for data...">
              <button class="au-btn--submit" type="submit">
                <i class="zmdi zmdi-search"></i>
              </button>
            </form>
            <div class="header-button">
              <div class="noti-wrap">
                <div class="noti__item js-item-menu">
                  <i class="zmdi zmdi-email"></i>
                  <span class="quantity">1</span>
                  <div class="email-dropdown js-dropdown">
                    <div class="email__title">
                      <p>You have 3 New Emails</p>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-06.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, 3 min ago</span>
                      </div>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-05.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, Yesterday</span>
                      </div>
                    </div>
                    <div class="email__item">
                      <div class="image img-cir img-40">
                        <img src="images/icon/avatar-04.jpg" alt="Cynthia Harvey">
                      </div>
                      <div class="content">
                        <p>Meeting about new dashboard...</p>
                        <span>Cynthia Harvey, April 12,,2018</span>
                      </div>
                    </div>
                    <div class="email__footer">
                      <a href="#">See all emails</a>
                    </div>
                  </div>
                </div>
                <div class="noti__item js-item-menu">
                  <i class="zmdi zmdi-notifications"></i>
                  <span class="quantity">3</span>
                  <div class="notifi-dropdown js-dropdown">
                    <div class="notifi__title">
                      <p>You have 3 Notifications</p>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c1 img-cir img-40">
                        <i class="zmdi zmdi-email-open"></i>
                      </div>
                      <div class="content">
                        <p>You got a email notification</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c2 img-cir img-40">
                        <i class="zmdi zmdi-account-box"></i>
                      </div>
                      <div class="content">
                        <p>Your account has been blocked</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__item">
                      <div class="bg-c3 img-cir img-40">
                        <i class="zmdi zmdi-file-text"></i>
                      </div>
                      <div class="content">
                        <p>You got a new file</p>
                        <span class="date">April 12, 2018 06:50</span>
                      </div>
                    </div>
                    <div class="notifi__footer">
                      <a href="#">All notifications</a>
                    </div>
                  </div>
                </div>
              </div>
              <div class="account-wrap">
                <div class="account-item clearfix js-item-menu">
                  <div class="image">
                    <img src="images/icon/avatar-01.jpg" alt="John Doe">
                  </div>
                  <div class="content">
                    <a class="js-acc-btn" href="#">{{ getUserData().name }}</a>
                  </div>
                  <div class="account-dropdown js-dropdown">
                    <div class="info clearfix">
                      <div class="image">
                        <a href="#">
                          <img src="images/icon/avatar-01.jpg" alt="John Doe">
                        </a>
                      </div>
                      <div class="content">
                        <h5 class="name">
                          <a href="#">{{ getUserData().name }}</a>
                        </h5>
                        <span class="email">{{ getUserData().email }}</span>
                      </div>
                    </div>
                    <div class="account-dropdown__body">
                      <div class="account-dropdown__item">
                        <a href="#">
                          <i class="zmdi zmdi-account"></i>Account</a>
                      </div>
                    </div>
                    <div class="account-dropdown__footer">
                      <a href="#" v-on:click.prevent="logout()">
                        <i class="zmdi zmdi-power"></i>Logout</a>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </header>
</template>

<script>
    export default {
        name: "admin-header",
        methods: {
          getUserData() {
            return JSON.parse(localStorage.getItem("user_data"));
          },
          logout() {
            this.$axios.setHeader('Authorization', "Bearer " + localStorage.getItem('auth_token'));
            this.$axios.get('/api/logout').then(response => {
              if(response.data.success) {

                localStorage.removeItem('auth_token');
                localStorage.removeItem('is_authenticated');
                localStorage.removeItem('user_data');

                this.$router.push('/login');
              }
            }).catch(err => {
              console.log(err.response);
            });
          }
        }
    }
</script>

The logout() function makes an http request the logout api on the server, the most important thing here is to pass the access token as an authorization header. On successful logout i remove the login details from local storage and redirect back to the login screen

 

 

Continue to Part4: Categories CRUD

 

3.7 3 votes
Article Rating

What's your reaction?

Excited
0
Happy
1
Not Sure
0
Confused
1

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments