Strapi blog logo
  • Product

      Why Strapi?Content ArchitectureRoadmapIntegrationsTry live demo
      OverviewContent Types BuilderCustomizable APIMedia LibraryRoles & Permissions
      Discover Strapi Enterprise EditionDiscover our partners
  • Pricing

  • Solutions

      Static WebsitesMobile ApplicationsCorporate websitesEditorial SitesEcommerce
      Delivery HeroL'EquipeSociete GeneralePixelDustBanco International
      Discover all our user stories
  • Community

      CommunityWrite for the communityWall of LoveStrapi Conf 2021
      SlackGitHubYoutubeCommunity Forum
      Meet the Strapi Community StarsDiscover the Strapi Showcase
  • Resources

      BlogStartersNewsroomSupport
      Strapi AcademyTutorialsVideos GuidesWebinars
      The Guide to Headless CMS Strapi Community Forum
  • Docs

      Getting StartedContent APIConfigurationInstallationDeploymentMigration
      Getting StartedContent ManagerContent-Types BuilderUsers, Roles & PermissionsPlugins
      Developer DocumentationStrapi User Guide

Looking for our logo ?

Logo Brand download
Download Logo Pack
See more Strapi assets
Strapi blog logo
  • Product

    Product

    • Why Strapi?
    • Content Architecture
    • Roadmap
    • Integrations
    • Try live demo

    Features

    • Overview
    • Content Types Builder
    • Customizable API
    • Media Library
    • Roles & Permissions
    • Discover Strapi Enterprise Edition
    • Discover our partners
    Features cover

    Unlock the full potential of content management

    See all features
    Strapi Enterprise Edition

    Discover the advanced features included in Strapi Enterprise Edition.

    Get Started
  • Pricing
  • Solutions

    Solutions

    • Static Websites
    • Mobile Applications
    • Corporate websites
    • Editorial Sites
    • Ecommerce

    Stories

    • Delivery Hero
    • L'Equipe
    • Societe Generale
    • PixelDust
    • Banco International
    • Discover all our user stories
    Delivery Hero team

    Delivery Hero manages their partner portal with Strapi.

    Read their story
    turn 10 studios website

    How 1minus1 delivered a creative website for Turn10 Studios 25% faster with Strapi

    Discover their story
  • Community

    Community

    • Community
    • Write for the community
    • Wall of Love
    • Strapi Conf 2021

    Resources

    • Slack
    • GitHub
    • Youtube
    • Community Forum
    • Meet the Strapi Community Stars
    • Discover the Strapi Showcase
    Strapi Conf

    The first Strapi Global User Conference.

    Register now
    Write for the community

    Contribute on educational content for the community

    Discover the program
  • Resources

    Resources

    • Blog
    • Starters
    • Newsroom
    • Support

    Learning

    • Strapi Academy
    • Tutorials
    • Videos Guides
    • Webinars
    • The Guide to Headless CMS
    • Strapi Community Forum
    Introducing Strapi Academy

    Everything you need to know to master Strapi.

    Go to the academy
    Strapi Repository on GitHub

    Get started with the Strapi repository

    Go to repository
  • Docs

    Developers

    • Getting Started
    • Content API
    • Configuration
    • Installation
    • Deployment
    • Migration

    User Guide

    • Getting Started
    • Content Manager
    • Content-Types Builder
    • Users, Roles & Permissions
    • Plugins
    • Developer Documentation
    • Strapi User Guide
    Install Strapi

    Install Strapi locally or wherever you need.

    Get Started
    Migration Guides Strapi

    Using a previous version of Strapi? Migrate to the latest.

    Read Guides
Get Started
Back to articles

Deliveroo clone with Nuxt.js, GraphQL, Strapi and Stripe (5/7)

cooking-a-deliveroo-clone-with-nuxt-vue-js-graphql-strapi-and-stripe-shopping-card-part-5-7
  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email
Pierre Burgy

Pierre Burgy

Tutorial illustration

This tutorial is part of the Β« Cooking a Deliveroo clone with Nuxt (Vue.js), GraphQL, Strapi and Stripe Β»:

  • πŸ‘‹ Intro
  • πŸ—οΈ Setup (part 1)
  • 🏠 Restaurants (part 2)
  • πŸ” Dishes (part 3)
  • πŸ” Authentication (part 4)
  • πŸ›’ Shopping Cart (part 5) - current
  • πŸ’΅ Order and Checkout (part 6)
  • πŸš€ Bonus: Deploy (part 7)
  • πŸ‘ Conclusion

Note: the source code is available on GitHub: https://github.com/strapi/strapi-tutorials/tree/master/tutorials/deliveroo-clone-nuxt-strapi-tutorial.

Shopping cart

Shopping cart

All of these dishes look so tasty! What if you could add some of them in a shopping cart?

  • Create a new store named cart.js and copy/paste the following code:

./frontend/store/cart.js

import Cookies from 'js-cookie'

export const state = () => ({
  items: []
})

export const mutations = {
  setItems(state, items) {
    state.items = items
  },
  add(state, item) {
    const record = state.items.find(i => i.id === item.id)

    if (!record) {
      state.items.push({
        quantity: 1,
        ...item
      })
    } else {
      record.quantity++
    }
    Cookies.set('cart', state.items)
  },
  remove(state, item) {
    const record = state.items.find(i => i.id === item.id)

    if (record.quantity > 1) {
      record.quantity--
    } else {
      const index = state.items.findIndex(i => i.id === item.id)
      state.items.splice(index, 1)
    }
    Cookies.set('cart', state.items)
  },
  emptyList(state) {
    state.items = []
    Cookies.set('cart', state.items)
  }
}

export const getters = {
  items: state => {
    return state.items
  },
  price: state => {
    return state.items.reduce(
      (accumulator, item) => accumulator + item.price * item.quantity,
      0
    )
  },
  numberOfItems: state => {
    return state.items.reduce(
      (accumulator, item) => accumulator + item.quantity,
      0
    )
  }
}

To make sure the items stay in the cart even after page reload, you will are also use cookies. So you need to update the nuxtInitServer function:

  • Update the index.js store to get the following:

/frontend/store/index.js

import cookieparser from 'cookieparser'

export const actions = {
  nuxtServerInit({ commit }, { req }) {
    let user = null
    let cart = []
    if (req && req.headers && req.headers.cookie) {
      const parsed = cookieparser.parse(req.headers.cookie)
      user = (parsed.user && JSON.parse(parsed.user)) || null
      cart = (parsed.cart && JSON.parse(parsed.cart)) || []
    }

    commit('auth/setUser', user)
    commit('cart/setItems', cart)
  }
}

Now you want to add the cart to your pages. To do so you are going to create a Cartcomponent that will be used in your restaurants/_id.vue and your future orders/checkout.vue

  • Update the _id.vue file to get the following code:

/frontend/pages/restaurants/_id.vue

<template>
<div>

  <a class="uk-button uk-button-primary uk-margin" @click="$router.go(-1)"><span uk-icon="arrow-left"></span> go back</a>

  <client-only>
  <div uk-grid>
      <div class="uk-width-1-3@m">

        // Left card displaying dishes
        <div v-for="dish in restaurant.dishes" class="uk-margin">
            <div class="uk-card uk-card-default">
                <div class="uk-card-media-top">
                    <img :src="'http://localhost:1337/' + dish.image.url" alt="" />
                </div>
                <div class="uk-card-body">
                    <h3 class="uk-card-title">{{ dish.name }} <span class="uk-badge">{{ dish.price }}€</span></h3>
                    <p>{{ dish.description }}</p>
                </div>
                <div class="uk-card-footer">
                  <button class="uk-button uk-button-primary" @click="addToCart(dish)">Add to cart</button>
                </div>
            </div>
        </div>

      </div>


      // Right card displaying you cart
      <div class="uk-width-expand@m">
          // Call a Cart component
          <Cart />
      </div>
  </div>

  </client-only>
</div>
</template>

<script>
import { mapMutations } from 'vuex'
import Cart from '~/components/Cart.vue'
import restaurantQuery from '~/apollo/queries/restaurant/restaurant'

export default {
  data() {
    return {
      restaurant: Object
    }
  },
  apollo: {
    restaurant: {
      prefetch: true,
      query: restaurantQuery,
      variables () {
        return { id: this.$route.params.id }
      }
    }
  },
  components: {
    Cart
  },
  methods:{
    ...mapMutations({
      addToCart: 'cart/add',
      removeFromCart: 'cart/remove'
    }),
  }
}
</script>

As you may see, you imported a Cart component. In fact you want to reuse this component in two pages: restaurants/index.vue and orders/checkout.vue that you'll create soon

  • Create a /frontend/components/Cart.vue and copy/paste the following code:
<template>
<div class="uk-card uk-card-default uk-card-body uk-margin" uk-sticky="offset: 20; bottom: true">
  <img src="https://assets-ouch.icons8.com/preview/125/6414b067-ba59-46ef-8693-4e190aa466c7.png" class="uk-align-center" height="250" width="250" alt="" />

  <div v-if="price > 0">

    <table class="uk-table uk-table-striped uk-table-small uk-table-responsive">
        <thead>
            <tr>
                <th>Name</th>
                <th>Price (unit)</th>
                <th>Quantity</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="dish in selectedDishes">
                <td class="uk-width-1-2">{{ dish.name }}</td>
                <td class="uk-table-shrink">{{ dish.price }}€</td>
                <td class="uk-table-shrink">{{ dish.quantity }}</td>
                <td>
                  <a class="uk-margin-left"><span class="uk-badge" @click="addToCart(dish)">+</span></a>
                  <a><span class="uk-badge" style="background: #f0506e;" @click="removeFromCart(dish)">-</span></a>
                </td>

            </tr>
        </tbody>
    </table>

    <button class="uk-button uk-button-primary" name="button">Process to checkout ({{ price }}€)</button>
  </div>

</div>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  methods:{
    ...mapMutations({
      addToCart: 'cart/add',
      removeFromCart: 'cart/remove'
    })
  },
  computed: {
    id() {
      return this.$route.params.id
    },
    selectedDishes() {
      return this.$store.getters['cart/items']
    },
    price() {
      return this.$store.getters['cart/price']
    },
    numberOfItems() {
      return this.$store.getters['cart/numberOfItems']
    }
  }
}
</script>

Good job! You can now add dishes to your cart, check it out!

πŸ’΅ In the next section, you will learn how to setup Stripe for checkout and create orders: https://blog.strapi.io/cooking-a-deliveroo-clone-with-nuxt-vue-js-graphql-strapi-and-stripe-order-and-checkout-part-6-7.

  • Share on facebook
  • Share on linkedin
  • Share on twitter
  • Share by email

Unleash content.

Read the docs
Get Started

Strapi is the most popular open-source Headless CMS. Strapi gives developers the freedom to use their favorite tools and frameworks while allowing editors to easily manage their content and distribute it anywhere.

Product

  • Why Strapi?
  • Content Architecture
  • Features
  • Enterprise Edition
  • Partner Program
  • Roadmap
  • Support
  • Integrations
  • Try live demo

Resources

  • How to get started
  • Meet the community
  • Tutorials
  • API documentation
  • GitHub repository
  • Starters
  • Strapi vs Wordpress
  • The Guide to headless CMS

Integrations

  • Gatsby CMS
  • React CMS
  • Vue.js CMS
  • Nuxt.js CMS
  • Next.js CMS
  • Angular CMS
  • Gridsome CMS
  • Jekyll CMS
  • 11ty CMS
  • Svelte CMS
  • Sapper CMS
  • Ruby CMS
  • Python CMS

Company

  • About us
  • Blog
  • Careers
  • Contact
  • Newsroom
  • Β© 2021, Strapi
  • LicenseTermsPrivacy