Backend DevelopmentFrontend DevelopmentVueJs Tutorials

Building Ecommerce Website With Lumen Laravel And Nuxtjs 15: User Login and Profile

Building Ecommerce Website With PHP Lumen Laravel And Nuxtjs

We have already implemented the login feature when we started to implement the control panel, so we will use the same Apis to implement the login and registration on the website.

 

 

 

Let’s start with Lumen project we will add just one Api to update the user profile, after that we will return to Nuxt project to implement the login and registration pages.

On the Lumen project go to app/Http/Controllers/Auth/LoginController.php and add this method at the end of the controller

function updateProfile(Request $request)
    {
        $user = Auth::user();

        $rules = [
            'name' => 'required|string',
            'email' => 'required|email|unique:users,email,' . $user->id
        ];

        if($request->input('password') != "") {
            $rules['password'] = 'required|min:4|confirmed';
        }

        $validator = Validator::make($request->only('name', 'email', 'password', 'password_confirmation'), $rules);

        if($validator->fails()) {
            return response()->json(['success' => 0, 'message' => 'Please fix these errors', 'errors' => $validator->errors()], 500);
        }

        try {

            $user->name = $request->input('name');
            $user->email = $request->input('email');

            if($request->input('password') != "") {
                $plainPassword = $request->input('password');
                $user->password = app('hash')->make($plainPassword);
            }

            $user->save();

            $token = auth()->tokenById($user->id);

            return response()->json([
                'success' => 1,
                'message' => 'User profile updated successfully!',
                'access_token' => $token,
                'user' => $user
            ]);

        } catch (\Exception $e) {
            //return error message
            return response()->json(['success' => 0, 'message' => 'User profile update failed!'], 409);
        }
    }

Update routes in routes/web.php after this line:

$router->get('/check-login', 'Auth\\LoginController@checkLogin');

Add this route:

$router->post('/update-profile', 'Auth\\LoginController@updateProfile');

That’s it for the Lumen api, let’s now go to the Nuxt project and start working on login and register functionality

 

Login & Register in The Website

On the Nuxt project at first i will update the general store to add some keys to store the login info. Open online-shop-frontend/store/general.js and update as the following:

store/general.js

import { HomeApis } from '../api/home';
import {ShopApi} from "../api/shop";
import {CategoryApi} from "../api/category";

export const state = () => ({
  categoriesTree: [],
  shop: {
    products: [],
    page: 1,
    brandsByCategory: []
  },
  shop_filter: {
    categoryId: '',
    brand_id: '',
    from_price: '',
    to_price: '',
    keyword: ''
  },
  category: {},
  auth: {
    is_logged: false,
    user_data: {},
    auth_token: ""
  }
});

export const mutations = {
  setCategoryTree(state, data) {
    state.categoriesTree = data;
  },
  setProducts(state, data) {
    state.shop.products = data;
  },
  setPage(state, page) {
    state.shop.page = page;
  },
  setBrandsByCategory(state, brands) {
    state.shop.brandsByCategory = brands;
  },
  setCategoryId(state, categoryId) {
    state.shop_filter.categoryId = categoryId;
  },
  setBrand(state, brandId) {
    state.shop_filter.brand_id = brandId;
  },
  setFromPrice(state, price) {
    state.shop_filter.from_price = price;
  },
  setToPrice(state, price) {
    state.shop_filter.to_price = price;
  },
  setKeyword(state, keyword) {
    state.shop_filter.keyword = keyword;
  },
  setCategory(state, category) {
    state.category = category;
  },
  setAuthData(state, data) {
    state.auth[data.key] = data.value;
  }
};

export const actions = {
  fetchCategoryTree({commit}) {
    HomeApis.getCategoryMenuTree(this.$axios).then(res => {
      commit('setCategoryTree', res);
    });
  },
  async fetchShopProducts({commit, state}) {

    let searchParams = [];

    if(state.shop.page && parseInt(state.shop.page) >= 1 ) {
      searchParams.push("page=" + parseInt(state.shop.page));
    }

    if(state.shop_filter.categoryId && parseInt(state.shop_filter.categoryId) > 0) {
      searchParams.push("category_id=" + parseInt(state.shop_filter.categoryId));
    }

    if(state.shop_filter.brand_id && parseInt(state.shop_filter.brand_id) > 0) {
      searchParams.push("brand_id=" + parseInt(state.shop_filter.brand_id));
    }

    if(state.shop_filter.from_price) {
      searchParams.push("from_price=" + state.shop_filter.from_price);
    }

    if(state.shop_filter.to_price) {
      searchParams.push("to_price=" + state.shop_filter.to_price);
    }

    if(state.shop_filter.keyword) {
      searchParams.push("keyword=" + state.shop_filter.keyword);
    }

    const response = await ShopApi.search(this.$axios, searchParams.join("&"));
    commit('setProducts', response.products);
  },
  async fetchBrandsByCategory({commit}, categoryId) {
    const response = await ShopApi.getBrandsByCategory(this.$axios, categoryId);

    commit('setBrandsByCategory', response.brands);
  },
  async fetchCategory({commit}, categoryId) {
    const response = await CategoryApi.getById(this.$axios, categoryId);

    commit('setCategory', response.category);

    return new Promise( (resolve) => {
      resolve(response.category);
    });
  },
  resetShopFilter({commit}) {
    commit('setPage', 1);
    commit('setCategoryId', "");
    commit('setBrand', "");
    commit('setFromPrice', "");
    commit('setToPrice', "");
    commit('setKeyword', "");
    commit('setBrandsByCategory', []);
  },
  storeAuthData({commit}, {auth_token, user_data}) {
    commit('setAuthData', {key: 'is_logged', value: true});
    commit('setAuthData', {key: 'auth_token', value: auth_token});
    commit('setAuthData', {key: 'user_data', value: user_data});
  },
  resetAuthData({commit}) {
    commit('setAuthData', {key: 'is_logged', value: false});
    commit('setAuthData', {key: 'auth_token', value: ""});
    commit('setAuthData', {key: 'user_data', value: {}});
  }
}

I added the auth object in the store function to store these keys (is_logged, user_data, auth_token). is_logged is a boolean to indicate whether the user is authenticated or not, user_data store use info like name, email. auth_token store the authentication token. Note that we will also store these data in browser local storage.

Also i added setAuthData() to the mutations object and two actions which are storeAuthData() and resetAuthData().

 

Now open pages/login.vue and update with this code:

pages/login.vue

<template>
  <section id="form" style="margin-top: 60px !important;"><!--form-->
    <div class="container">
      <div class="row">
        <div class="col-sm-4 col-sm-offset-1">
          <FrontLogin></FrontLogin>
        </div>
        <div class="col-sm-1">
          <h2 class="or">OR</h2>
        </div>
        <div class="col-sm-4">
          <FrontRegister></FrontRegister>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
    import FrontLogin from "../components/login-components/FrontLogin";
    import FrontRegister from "../components/login-components/FrontRegister";

    export default {
      name: "LoginPage",
      components: {
        FrontRegister,
        FrontLogin
      },
      head() {
        return {
          title: 'Online Shop | Login',
          meta: [
            {
              hid: 'description',
              name: 'description',
              content: 'Login Page'
            }
          ]
        }
      },
      mounted() {
        if(this.$store.state.general.auth.is_logged) {
          this.$router.push("/");
        }
      }
    }
</script>

As you see i extracted the login and register forms into two separate components, let’s create these so in components/ folder create login-components/ folder and create these files which are FrontLogin.vue and FrontRegister.vue

components/login-components/FrontRegister.vue

<template>
  <div class="signup-form"><!--sign up form-->
    <h2>New User Signup!</h2>
    <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="register()">
      <input type="text" placeholder="Name" name="name" v-model="register_data.name" />
      <input type="email" placeholder="Email Address" name="email" v-model="register_data.email"/>
      <input type="password" placeholder="Password" name="password" v-model="register_data.password" />
      <input type="password" placeholder="Password Confirmation" name="password_confirmation" v-model="register_data.password_confirmation" />
      <button type="submit" class="btn btn-default">Signup</button>
    </form>
  </div><!--/sign up form-->
</template>

<script>
    export default {
        name: "FrontRegister",
        data() {
          return {
            register_data: {
              name: "",
              email: "",
              password: "",
              password_confirmation: ""
            },
            error_message: '',
            validation_errors: []
          }
        },
        methods: {
          register() {
            this.validation_errors = [];
            this.error_message = '';

            this.clearStorage();

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

              this.saveIntoStorage(response);

              this.$store.dispatch('general/storeAuthData', {auth_token: response.access_token, user_data: response.user});

              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));
          }
        }
    }
</script>

components/login-components/FrontLogin.vue

<template>
  <div class="login-form"><!--login form-->
    <h2>Login to your account</h2>
    <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()">
      <input type="email" name="email" placeholder="Email Address" v-model="login_data.email" />
      <input type="password" name="password" placeholder="Password" v-model="login_data.password" />
      <button type="submit" class="btn btn-default">Login</button>
    </form>
  </div>
</template>

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

            this.clearStorage();

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

              this.saveIntoStorage(response);

              this.$store.dispatch('general/storeAuthData', {auth_token: response.access_token, user_data: response.user});

              this.onAfterLogin(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));
          },
          onAfterLogin(res) {
            // todo (we will use this when working with the shopping cart)
          }
        }
    }
</script>

As shown above these two forms like the same we did when working with the login form in the admin panel. In the register form i submit the data to api/register endpoint then on success i store the data into localstorage and also in the store and redirect the user to the homepage while on failure i show error message and validation errors. 

The same also is done in the login form we store the data into localstorage and store, in addition i added onAfterLogin() method in the login component, this method body is empty for now, we will update it when working with the shopping cart.

To prevent the user from accessing the login page while he is already authenticated, i added a simple check in the mounted() hook as shown above to redirect the user to the homepage.

Now to try this functionality register and login with sample account, then inspect the browser console you will see that the data is stored into the local storage and the vuex store. The next step is to update the header component to hide the login link and display a logout link in case of user is already authenticated.

 

Updating The Header

components/partials/FrontHeader.vue

<template>
  <header id="header"><!--header-->

    <div class="header-middle"><!--header-middle-->
      <div class="container">
        <div class="row">
          <div class="col-sm-4">
            <div class="logo pull-left">
              <nuxt-link to="/"><img src="/images/home/logo.png" alt="" /></nuxt-link>
            </div>
          </div>
          <div class="col-sm-8">
            <div class="shop-menu pull-right">
              <ul class="nav navbar-nav">
                <li><nuxt-link to="/account"><i class="fa fa-user"></i> Account</nuxt-link></li>
                <li><a href="#"><i class="fa fa-star"></i> Wishlist</a></li>
                <li><a href="#"><i class="fa fa-list"></i> My Orders</a></li>
                <li><nuxt-link to="/cart"><i class="fa fa-shopping-cart"></i> Cart</nuxt-link></li>
                <li v-if="!this.isLogged"><nuxt-link to="/login"><i class="fa fa-sign-in"></i> Login</nuxt-link></li>
                <li v-if="this.isLogged"><a href="#" v-on:click.prevent="signout()"><i class="fa fa-sign-out"></i> Sign out</a></li>
              </ul>
            </div>
          </div>
        </div>
      </div>
    </div><!--/header-middle-->

    <div class="header-bottom"><!--header-bottom-->
      <div class="container">
        <div class="row">
          <div class="col-sm-9">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
            </div>
            <div class="mainmenu pull-left">
              <ul class="nav navbar-nav collapse navbar-collapse">
                <li><nuxt-link to="/" :class="{active: this.$route.path === '/'}">Home</nuxt-link></li>
                <li><nuxt-link to="/shop" :class="{active: this.$route.path.indexOf('shop') !== -1}">Shop</nuxt-link></li>
                <li class="dropdown">
                  <a href="#">Categories<i class="fa fa-angle-down"></i></a>
                  <CategoryTree v-if="this.categoriesTree.length" :dataTree="categoriesTree"></CategoryTree>
                </li>
                <li><nuxt-link to="/contactus" :class="{active: this.$route.path.indexOf('contactus') !== -1}">Contact</nuxt-link></li>
              </ul>
            </div>
          </div>
          <div class="col-sm-3">
            <form method="get" @submit.prevent="search()">
              <div class="search_box pull-right">
                <input type="text" name="keyword" placeholder="Search" v-model="keyword" />
              </div>
            </form>
          </div>
        </div>
      </div>
    </div><!--/header-bottom-->
  </header>
</template>

<script>
    import CategoryTree from '../../components/partials/CategoryTree';
    export default {
        name: "FrontHeader",
        components: {CategoryTree},
        data() {
          return {
            keyword: ""
          }
        },
        computed: {
          categoriesTree() {
            return this.$store.state.general.categoriesTree;
          },
          isLogged() {
            return this.$store.state.general.auth.is_logged;
          }
        },
        methods: {
          search() {
            // reset shop filter
            this.$store.dispatch('general/resetShopFilter');

            this.$store.commit('general/setKeyword', this.keyword);

            this.$router.push({ path: "/search", query: {keyword: this.keyword}});

            this.$store.dispatch('general/fetchShopProducts');
          },
          signout() {
            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.$store.dispatch('general/resetAuthData');

                this.onAfterSignout();

                this.$router.push('/');
              }
            }).catch(err => {
              console.log(err.response);
              this.onAfterSignout();
            });
          },
          onAfterSignout() {
            // todo when implementing the cart
          }
        },
        mounted() {
          this.$store.dispatch('general/fetchCategoryTree');
        }
    }
</script>

<style scoped>
  .search_box input {
    font-size: 18px;
    color: #424040;
  }
</style>

As shown i added a logout link that will be displayed when user is logged, now if you login with a valid account the login link will be hidden and the logout link will be shown. Upon clicking the logout link the login data is destroyed and the login link is shown.

 

Persisting User Login Data

There is still a problem if the user login and refresh the page the header login link will be displayed, that’s because we need to check when the application first load to retrieve the local storage data and set the store again, we will do this in default layout

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

<template>
  <div>

    <FrontHeader></FrontHeader>

    <Nuxt />

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

<style>

</style>
<script>
  import FrontHeader from "../components/partials/FrontHeader";
  import FrontFooter from "../components/partials/FrontFooter";

  export default {
    components: {FrontFooter, FrontHeader},
    methods: {
      isAuthenticated() {
        if(process.browser) {
          const user = JSON.parse(localStorage.getItem('user_data'));
          if (localStorage.getItem('is_authenticated') === "1" && localStorage.getItem("auth_token") != null && user.id) {
            this.$store.dispatch('general/storeAuthData', {auth_token: localStorage.getItem("auth_token"), user_data: user});
          } else {
            this.$store.dispatch('general/resetAuthData');

            // todo when implemeting cart
          }
        }
      },
      checkUserLogin() {
        if(process.browser) {
          // send request to check if the user is logged
          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.$store.dispatch('general/resetAuthData');

                // todo when implemeting cart

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

              this.$store.dispatch('general/resetAuthData');

              // todo when implemeting cart

              this.$router.push("/");
            });
          } else {
            this.$store.dispatch('general/resetAuthData');
          }
        }
      }
    },
    mounted() {
      this.isAuthenticated();

      const verify = setInterval(this.checkUserLogin, 8000);

      if(!this.$store.state.general.auth.is_logged || !this.$store.state.general.auth.auth_token) {
        clearInterval(verify);
      }
      
    }
  }
</script>

In mounted() hook i invoked a method isAuthenticated() to check if the user is authenticated by retrieveing the user data from local storage, if there is user data then we save it into the store otherwise we clear the store. Also i added another method checkUserLogin() the same as the admin panel to run every 8 seconds to validate the auth token.

Now if you login again and refresh the page the app will work as expected.

 

Auth Middleware

To prevent access to protected pages we will create a simple middleware in the middleware/ directory to check if there is an auth token or user data and thereby to redirect the user to the login page

middleware/auth.js

export default function({redirect}) {
  if(process.browser) {
    if (localStorage.getItem('is_authenticated') === null || localStorage.getItem('auth_token') === null || localStorage.getItem('user_data') === null) {
      redirect('/login');
    }
  }
}

Now if you need to prevent access to any protected page just specify the middleware:auth. From these protected pages which we will implement in the next section which are the profile pages.

 

The Profile & Edit Profile Pages

Let’s create two pages in the pages/ directory:

  • account.vue
  • edit-account.vue

Open account.vue and add this code snippet:

<template>
  <div class="container">
    <div class="bg">
      <div class="row">
        <div class="col-sm-12">
          <h2 class="title text-left">My Profile</h2>
        </div>
      </div>

      <div class="row">

        <div class="col-md-3">
          <account-sidebar></account-sidebar>
        </div>

        <div class="col-sm-9 col-md-9">
          <div class="well well-sm">
            <div class="row">
              <div class="col-sm-12">
                <h4>
                  {{ user_data.name ? user_data.name : "" }}</h4>

                <ul>
                  <li title="email"><i class="glyphicon glyphicon-envelope"></i> {{ user_data.email ? user_data.email : "" }}</li>
                  <li title="date joined"><i class="glyphicon glyphicon-gift"></i> {{ user_data.created_at ? this.getFormattedDate(user_data.created_at) : "" }}</li>
                </ul>

                <nuxt-link to="/edit-account" class="btn btn-primary"><i class="fa fa-edit"></i> Edit Profile</nuxt-link>

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

<script>
    import AccountSidebar from "../components/account-components/AccountSidebar";
    
    export default {
        name: "MyAccount",
      components: {
          AccountSidebar
      },
      middleware: "auth",
        computed: {
          user_data() {
            return this.$store.state.general.auth.user_data;
          }
        },
        head() {
          return {
            title: "My Profile",
            meta: [
              {
                hid: 'description',
                name: 'description',
                content: 'My Profile'
              }
            ]
          }
        },
        methods: {
          getFormattedDate(date) {
            return new Date(date).toISOString().slice(0,10);
          }
        }
    }
</script>

Also open edit-account.vue and add this code:

<template>
  <section id="form" style="margin-top: 60px !important;"><!--form-->
    <div class="container">
      <div class="row">

        <div class="col-md-3">
          <account-sidebar></account-sidebar>
        </div>

        <div class="col-sm-9 col-md-9">
          <div class="signup-form" style="margin-top: 0 !important;">
            <h2>Edit Profile</h2>
            <div class="alert alert-success" v-if="this.success_message">{{ this.success_message }}</div>
            <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="updateProfile()">
              <input type="text" placeholder="Name" name="name" v-model="user_data.name" />
              <input type="email" placeholder="Email Address" name="email" v-model="user_data.email"/>

              <a href="#" class="btn btn-info pull-right" @click.prevent="togglePasswordUpdate()">
                Change Password
              </a>

              <div v-if="this.changePassword" style="margin-top: 7px">
                <input type="password" placeholder="Password" name="password" v-model="user_data.password" />
                <input type="password" placeholder="Password Confirmation" name="password_confirmation" v-model="user_data.password_confirmation" />
              </div>

              <button type="submit" class="btn btn-primary" style="margin-top: 20px"><i class="fa fa-save"></i> Save</button>
            </form>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
    import AccountSidebar from "../components/account-components/AccountSidebar";
    export default {
      name: "EditAccountPage",
      components: {
          AccountSidebar
      },
      middleware: "auth",
        data() {
          return {
            user_data: {
              name: "",
              email: "",
              password: "",
              password_confirmation: ""
            },
            error_message: '',
            success_message: '',
            validation_errors: [],
            changePassword: false
          }
        },
        head() {
          return {
            title: "Edit My Profile",
            meta: [
              {
                hid: 'description',
                name: 'description',
                content: 'Edit My Profile'
              }
            ]
          }
        },
        methods: {
          updateProfile() {
            this.error_message = "";
            this.success_message = "";
            this.validation_errors = [];

            this.$axios.setHeader('Authorization', "Bearer " + localStorage.getItem('auth_token'));
            this.$axios.$post('/api/update-profile', this.user_data).then(response => {

              this.success_message = response.message;

              localStorage.setItem('is_authenticated', 1);
              localStorage.setItem('auth_token', response.access_token);
              localStorage.setItem('user_data', JSON.stringify(response.user));

              this.$store.dispatch('general/storeAuthData', {auth_token: response.access_token, user_data: response.user});

            }).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]);
                }
              }
            });
          },
          togglePasswordUpdate() {
            this.changePassword = !this.changePassword;
          }
        },
        mounted() {

          setTimeout(() => {
            this.user_data.name = this.$store.state.general.auth.user_data.name;
            this.user_data.email = this.$store.state.general.auth.user_data.email;
          }, 300);
        }
    }
</script>

<style scoped>

</style>

The account page displays the user details and edit-account page display a form to edit the user profile. Note that we specified the middleware: auth in every page to prevent access to this page.

In the left side i display a sidebar with some links to enable the user to navigate to different account sections like the profile, shipping addresses, orders, etc. This sidebar is specified by <account-sidebar /> component, we will create this component below.

When updating the user profile we set the data into the store again and save it into local storage.

Now create this component into components/account-components/AccountSidebar.vue

<template>
  <ul class="nav nav-pills nav-stacked">
    <li role="presentation" :class="{active: this.$route.path.indexOf('account') !== -1}"><n-link to="/account"><i class="fa fa-user"></i> Account</n-link></li>
    <li role="presentation" :class="{active: this.$route.path.indexOf('shipping-addresses') !== -1}"><n-link to="/shipping-addresses"><i class="fa fa-map-marker"></i> Shipping Addresses</n-link></li>
    <li role="presentation" :class="{active: this.$route.path.indexOf('orders') !== -1}"><n-link to="/orders"><i class="fa fa-list"></i> My Orders</n-link></li>
    <li role="presentation" :class="{active: this.$route.path.indexOf('wishlist') !== -1}"><n-link to="/wishlist"><i class="fa fa-star"></i> My Wishlist</n-link></li>
    <li role="presentation"><a href="#" @click.prevent="signout()"><i class="fa fa-sign-out"></i> Sign out</a></li>
  </ul>
</template>

<script>
    export default {
        name: "AccountSidebar",
        methods: {
          signout() {
            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.$store.dispatch('general/resetAuthData');

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

<style scoped>
  a {
    color: #FE980F !important;
  }
  .nav-pills>li.active>a, .nav-pills>li.active>a:hover, .nav-pills>li.active>a:focus {
    background-color: #FE980F;
    color: #fff !important;
  }
  a:hover, a:focus {
    color: #fff !important;
  }
  .nav>li>a:hover, .nav>li>a:focus {
    background-color: #FE980F !important;
  }
</style>

As shown in every link i check if the current route matches this page then we update the link active class and the final link when clicked signout the user.

 

Continue to Part16: Shopping Cart Apis

 

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments