Sekarang, kita akan membuat halaman Cart di e-commerce. Halaman ini akan menangani penambahan produk ke keranjang, menampilkan produk yang telah ditambahkan, serta menghitung total harga. Kita akan menggunakan localStorage atau sessionStorage untuk menyimpan cart di browser, sehingga pengguna bisa menambah produk ke cart meskipun belum login. Setelah checkout, kita akan meminta mereka untuk login.

1. Membuat Cart.vue (Halaman Cart)

Pertama, kita akan membuat halaman untuk menampilkan isi keranjang dan tombol checkout.

resources/js/Pages/Frontend/Cart.vue

<template>
    <div class="min-h-screen flex flex-col bg-gray-50">
      <!-- NAVBAR -->
      <header class="bg-white shadow z-10">
        <div class="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
          <div class="text-2xl font-bold text-gray-800">MyShop</div>
          <nav class="flex items-center space-x-6">
            <Link href="/" class="text-gray-700 hover:text-gray-900 font-medium px-3 py-2 transition-colors">Home</Link>
            <Link href="/categories" class="text-gray-700 hover:text-gray-900 font-medium px-3 py-2 transition-colors">Categories</Link>
            <Link href="/about" class="text-gray-700 hover:text-gray-900 font-medium px-3 py-2 transition-colors">About</Link>
          </nav>
        </div>
      </header>
  
      <main class="flex-1 py-10">
        <div class="max-w-6xl mx-auto px-4">
          <h1 class="text-3xl font-bold text-gray-800 mb-6">Your Cart</h1>
  
          <!-- Cart Items -->
          <div v-if="cartItems.length > 0">
            <div class="space-y-4">
              <div v-for="item in cartItems" :key="item.id" class="flex items-center justify-between p-4 bg-white rounded shadow">
                <div class="flex items-center">
                  <!-- Display product image -->
                  <img :src="`/storage/${item.image}`" alt="Product Image" class="w-16 h-16 object-cover rounded" />
                  <div class="ml-4">
                    <p class="text-lg font-semibold">{{ item.name }}</p>
                    <p class="text-gray-500 text-sm">Price: Rp {{ item.price }}</p>
                  </div>
                </div>
                <div class="flex items-center space-x-4">
                  <!-- Quantity Controls -->
                  <button @click="decreaseQuantity(item.id)" class="px-4 py-2 bg-gray-200 rounded-full hover:bg-gray-300 transition">-</button>
                  <span class="mx-4 text-lg">{{ item.quantity }}</span>
                  <button @click="increaseQuantity(item.id)" class="px-4 py-2 bg-gray-200 rounded-full hover:bg-gray-300 transition">+</button>
                  <!-- Remove Item -->
                  <button @click="removeFromCart(item.id)" class="text-red-500 hover:text-red-700">Remove</button>
                </div>
                <!-- Sub Total for each item -->
                <div class="ml-4 text-sm text-gray-600">Sub Total: Rp {{ item.subTotal }}</div>
              </div>
            </div>
  
            <!-- Total Price -->
            <div class="mt-6 p-4 bg-white rounded shadow">
              <h3 class="font-semibold text-xl">Total Price: Rp {{ totalPrice }}</h3>
              <button @click="checkout" class="w-full py-3 mt-4 bg-blue-600 text-white font-semibold rounded hover:bg-blue-700 transition">
                Proceed to Checkout
              </button>
            </div>
          </div>
  
          <!-- Empty Cart Message -->
          <div v-else class="text-center text-gray-500">
            <p>Your cart is empty. Add some products!</p>
          </div>
        </div>
      </main>
  
      <!-- FOOTER -->
      <footer class="bg-white py-4">
        <div class="max-w-7xl mx-auto px-4 text-center text-gray-600 text-sm">
          &copy; 2024 MyShop. All rights reserved.
        </div>
      </footer>
    </div>
  </template>
  
  <script>
  import { ref, computed } from 'vue';
  import { Link } from '@inertiajs/inertia-vue3';
  
  export default {
    components: { Link },
    setup() {
      // Retrieve the cart from localStorage, or initialize an empty cart
      const cartItems = ref(JSON.parse(localStorage.getItem('cart')) || []);
  
      // Increase quantity
      const increaseQuantity = (productId) => {
        const item = cartItems.value.find(item => item.id === productId);
        if (item) {
          item.quantity++;
          item.subTotal = item.price * item.quantity;  // Update sub total
          updateCart();
        }
      };
  
      // Decrease quantity
      const decreaseQuantity = (productId) => {
        const item = cartItems.value.find(item => item.id === productId);
        if (item && item.quantity > 1) {
          item.quantity--;
          item.subTotal = item.price * item.quantity;  // Update sub total
          updateCart();
        }
      };
  
      // Remove item from cart
      const removeFromCart = (productId) => {
        cartItems.value = cartItems.value.filter(item => item.id !== productId);
        updateCart();
      };
  
      // Update the cart in localStorage
      const updateCart = () => {
        localStorage.setItem('cart', JSON.stringify(cartItems.value));
      };
  
      // Calculate total price
      const totalPrice = computed(() => {
        return cartItems.value.reduce((total, item) => total + item.subTotal, 0);
      });
  
      // Checkout function (could redirect to login if not logged in)
      const checkout = () => {
        if (!localStorage.getItem('user')) {
          alert('Please login to proceed with the checkout.');
          window.location.href = '/login'; // Redirect to login page
        } else {
          window.location.href = '/checkout'; // Proceed to checkout page
        }
      };
  
      // Initialize subTotal for each item
      cartItems.value.forEach(item => {
        item.subTotal = item.price * item.quantity;
      });
  
      return {
        cartItems,
        totalPrice,
        increaseQuantity,
        decreaseQuantity,
        removeFromCart,
        checkout,
      };
    },
  };
  </script>
  
  <style scoped>
  /* Optional styling for cart layout */
  .relative {
    position: relative;
  }
  .object-cover {
    object-fit: cover;
  }
  </style>
  

2. Menambahkan Produk ke Cart dari ProductDetail.vue

Modifikasi tombol "Add to Cart" di ProductDetail.vue yang akan menambahkan produk ke cart saat diklik. Kita menggunakan tombol increase dan decrease agar jumlah yang kita masukkan ke cart bisa diatur. 

  <!-- Quantity Selector -->
  <div class="flex items-center mb-6">
    <button @click="decreaseQuantity" class="px-4 py-2 bg-gray-200 rounded-full hover:bg-gray-300 transition">-</button>
    <span class="mx-4 text-lg">{{ quantity }}</span>
    <button @click="increaseQuantity" class="px-4 py-2 bg-gray-200 rounded-full hover:bg-gray-300 transition">+</button>
  </div>

  <!-- Add to Cart Button -->
  <button @click="addToCart(product)" class="px-6 py-3 bg-blue-600 text-white font-semibold rounded hover:bg-blue-700 transition">
    Add to Cart
  </button>

Buat Function addToCart di ProductDetail.vue

<script>
    import { ref } from 'vue';
    import { Inertia } from '@inertiajs/inertia';
    import { Link } from '@inertiajs/inertia-vue3';

    export default {
    props: {
        product: Object
    },
    components: { Link },
    setup(props) {
        const quantity = ref(1); // Default quantity to 1
        const selectedImage = ref(null);

        // Increase quantity
        const increaseQuantity = () => {
        quantity.value++;
        };

        // Decrease quantity (but never below 1)
        const decreaseQuantity = () => {
        if (quantity.value > 1) {
            quantity.value--;
        }
        };

        // Add product to cart with selected quantity
        const addToCart = (product) => {
        let cart = JSON.parse(localStorage.getItem('cart')) || [];
        const existingItem = cart.find(item => item.id === product.id);

        if (existingItem) {
            existingItem.quantity += quantity.value; // Add the selected quantity to the existing one
        } else {
            cart.push({ ...product, image: product.images[0].image, quantity: quantity.value });
        }

        localStorage.setItem('cart', JSON.stringify(cart));

        // Redirect to the cart page with a success message
        Inertia.get('/cart', {}, {
            preserveState: true,
            onSuccess: () => {
            alert('Product has been added to your cart!');
            }
        });
        };

        return { quantity, increaseQuantity, decreaseQuantity, addToCart, selectedImage };
    }
    };
</script>

3. Tambahkan Routing untuk Cart

Pastikan Anda memiliki route di web.php untuk halaman Cart:

use App\Http\Controllers\FrontendController;

Route::get('/cart', [FrontendController::class, 'cart'])->name('cart');

Dan di FrontendController.php, buat method untuk menampilkan halaman cart:

public function cart()
{
    return Inertia::render('Frontend/Cart');
}

4. Testing

Tambahkan produk ke cart melalui halaman ProductDetail. Bisa klik + dan - untuk menambah jumlah qty untuk dimasukkan ke dalam halaman cart. Jika berhasil, akan menghasilkan seperti berikut:

add to cart

http://localhost:8000/cart

cart