/public/mix-manifest.json
/public/css
/public/js
+/public/vendor
/storage
/vendor
/.idea
use App\Models\Page;
+use App\Models\Product;
use Cubist\Backpack\app\Http\Controllers\CubistFrontController;
use Cubist\Backpack\app\Magic\PageData;
use Illuminate\Http\Request;
});
}
+ public function cart(Request $request) {
+
+ $request->validate([
+ 'action' => 'required|string', // add/update/delete
+ 'id' => 'required|numeric',
+ 'quantity' => 'numeric',
+ ]);
+
+ $id = $request->input('id');
+ $quantity = $request->input('quantity', 1);
+
+ // Cart items stored as an array with IDs as keys and quantities as values
+ // Get existing session or an empty array
+ $cart_items = $request->session()->get('cart_items', []);
+
+ switch($request->input('action')) {
+
+ case 'add':
+ // If the item already exists in the cart, increment the quantity
+ if (isset($cart_items[$id])) {
+ $cart_items[$id] += $quantity;
+ } else {
+ $cart_items[$id] = $quantity;
+ }
+ break;
+
+ case 'update':
+ $cart_items[$id] = $quantity;
+ break;
+
+ case 'delete':
+ unset($cart_items[$id]);
+ break;
+ }
+
+ // Save back to the session
+ $request->session()->put('cart_items', $cart_items);
+
+ return Product::getCartData();
+ }
+
// Subscribe to newsletter via MailChimp API
public function newsletter(Request $request)
{
parent::__construct($attributes);
}
+ // Define relationship with Product Types
+ public function type()
+ {
+ return $this->belongsTo('App\Models\ProductType', 'product_type');
+ }
+
public function setFields()
{
parent::setFields();
}
return $res;
}
+
+
+ /**
+ * Custom accessor to return fallback image
+ * by accessing $product->image_fallback...
+ */
+ public function getImageFallbackAttribute() {
+ return asset('images/product-details/product-placeholder.svg');
+ }
+
+ /**
+ * Custom accessor to return main product image (or fallback)
+ * by accessing $product->image...
+ */
+ public function getImageAttribute() {
+ if ($this->images) {
+
+ $image = $this->getFirstMediaUrl($this->images);
+
+ if ($image) {
+ return $image;
+ }
+ }
+
+ return $this->image_fallback;
+ }
+
+
+ /**
+ * Fetch selected product data for use in cart Vue component
+ * @return array
+ */
+ public static function getCartData() {
+
+ $cart_items = session('cart_items', []);
+
+ $cart_data = [];
+ $products = self::with('media')->whereIn('id', array_keys($cart_items))->get();
+
+ foreach ($products as $product) {
+ $cart_data[] = [
+ 'id' => $product->id,
+ 'name' => $product->name,
+ 'category' => $product->type->name,
+ 'quantity' => $cart_items[$product->id],
+ 'image' => $product->image,
+ ];
+ }
+
+ return $cart_data;
+ }
+
}
'tab' => $tab,
]);
+ $this->addField(['name' => 'form_button_text',
+ 'type' => 'Text',
+ 'label' => 'Texte du bouton',
+ 'tab' => $tab]);
+
$this->addField(['name' => 'form_confirmation',
'type' => 'Text',
'label' => 'Message de confirmation',
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.4 13"><path d="M5.9 13L0 7.1l1.4-1.4 4.5 4.4L16 0l1.4 1.4z"/></svg>
},
mounted() {
- eventBus.$on('update-item-quantity', update => {
- const index = this.items.findIndex((item) => item.id == update.id);
- this.items[index].quantity = update.quantity;
+
+ eventBus.$on('add-item', data => {
+ data.action = 'add';
+ this.saveCart(data);
+ });
+
+ eventBus.$on('update-item', data => {
+ data.action = 'update';
+ this.saveCart(data);
});
eventBus.$on('delete-item', id => {
- const index = this.items.findIndex((item) => item.id == id);
- this.items.splice(index, 1);
+ this.saveCart({
+ action: 'delete',
+ id: id
+ });
});
},
methods: {
+ saveCart(data) {
+ let root = this;
+
+ axios.post('/ajax/cart', data)
+ .then(function(response) {
+ console.log('Cart updated');
+ console.table(response.data);
+ root.items = response.data;
+ })
+ .catch(function(error) {
+ console.error('Error saving cart!', error);
+ });
+ },
+
openCart() {
document.body.classList.add('cart-open');
},
props: {
items: {
- type: Object,
+ type: Array,
required: true,
}
},
--- /dev/null
+<template>
+ <button class="btn" @click="addToCart" :class="{'btn-no-hover bg-navy' : isAdded }" :disabled="isAdded">
+ <span class="btn-text relative">
+ <span :class="{'opacity-0': isAdded}">
+ <slot></slot>
+ </span>
+ <span class="absolute top-0 left-0 w-full h-full flex items-center justify-center" v-if="isAdded">
+ <slot name="success-message"></slot>
+ </span>
+ </span>
+ </button>
+</template>
+
+<script>
+
+ export default {
+ name: "CartAdd",
+
+ props: {
+ productId: {
+ type: Number,
+ required: true,
+ }
+ },
+
+ data() {
+ return {
+ isAdded: false,
+ };
+ },
+
+ methods: {
+ addToCart() {
+ eventBus.$emit('add-item', {
+ id: this.productId,
+ quantity: 1,
+ });
+ this.isAdded = true;
+ }
+ }
+ }
+</script>
+
+<style scoped>
+
+</style>
methods: {
updateQuantity(newValue, oldValue) {
- eventBus.$emit('update-item-quantity', {
+ eventBus.$emit('update-item', {
id: this.item.id,
quantity: newValue,
});
&-text
@apply z-10 relative
+ &-no-hover:before
+ display: none
+
&:hover:before
transform: scaleX(1)
opacity: 1
<div class="text-block {{ $class }} {{ $padding }}">
+ {{ $preTitle ?? '' }}
+
@isset($title)
<{{ $titleTag }} class="{{ $titleClass }}">{{ $title }}</{{ $titleTag }}>
@endisset
<body class="template-{{ $view_name }} {{ $body_class ?? '' }} font-body text-grey-dark">
@include('cubist::body.begin')
-@php
- if (config('features.quote')) {
- //#### Generate temporary cart data
- $cart_items = [];
- for ($i = 0; $i < 6; $i++) {
- $cart_items[$i] = [
- 'id' => $i + 1,
- 'quantity' => rand(1, 15),
- 'name' => 'Modèle '. rand(1000, 1500),
- 'category' => 'Capteur de force',
- 'image' => '/storage/products/'. rand(1,6) .'.png',
- ];
- }
- } else {
- $cart_items = [];
- }
-@endphp
-
-<div id="app" class="flex flex-col min-h-screen" data-cart-items='@json($cart_items)'>
+<div id="app" class="flex flex-col min-h-screen" data-cart-items='@json(\App\Models\Product::getCartData())'>
@include('partials.header')
{{-- Nested divs to allow grey backgrounds of columns to match the height of their content instead of total height --}}
<div v-if="cartItemCount > 0">
- <cart :items='items' class="cart-page bg-grey-100 p-1v"></cart>
+ <cart :items='items' class="cart-page bg-grey-100 p-1v pb-0 overflow-hidden"></cart>
</div>
<div>
@section('content')
<content class="pt-1v">
- <text-block title-class="h1 text-6xl" title-tag="h1">
- <slot name="title">
- {{$product->name}}
+ <text-block title-class="h1 text-6xl" title-tag="h1" :title="$product->name">
+ <slot name="preTitle">
+ <div class="text-navy text-bold font-display text-xl -mb-2">Ref: {{ $product->reference }}</div>
</slot>
</text-block>
@if(config('features.quote'))
- <link-button href="#" class="align-middle">{{__('Ajouter à ma sélection')}}</link-button>
+ <cart-add :product-id="{{ $product->id }}" class="align-middle">
+ {{__('Ajouter à ma sélection')}}
+
+ <template v-slot:success-message>
+ @svg('tick', 'w-4 mr-3') {{ __('Produit ajouté') }}
+ </template>
+ </cart-add>
<span class="font-display text-lg inline-block align-middle rounded-full border-grey-dark border-2 h-8 w-8 text-center ml-6">?</span>
@endif
{{-- Image holder --}}
<div class="product-img-holder">
<div class="product-img"
- style="background-image: url({{$rel->getImageUrl('images','',asset('images/product-details/product-placeholder.svg')) }})"></div>
+ style="background-image: url({{ $rel->getEntity()->image }})"></div>
</div>
{{-- Product details --}}
<a href="{{ $product_URL }}">
<div class="product-img-holder">
<div class="product-img"
- style="background-image: url({{$product->getImageUrl('images','',asset('images/product-details/product-placeholder.svg')) }})"></div>
+ style="background-image: url({{ $product->getEntity()->image }})"></div>
</div>
</a>
@endforeach
</div>
- <div class="form-endmessage mt-5 text-grey-dark">
+ <div class="form-endmessage my-6 text-grey-dark text-sm">
@markdown($global->get('form_privacy'))
</div>
<div class="flex justify-between items-center xs:flex-col-reverse">
<span class="text-grey-dark xs:self-start xs:mt-5">*{{__('Champs obligatoires')}}</span>
<button type="submit" class="btn btn-custom xs:w-full"
- data-sending="{{__('Envoi en cours')}}">{{__('Envoyer')}}</button>
+ data-sending="{{__('Envoi en cours')}}">{{ $page->get('form_button_text', __('Envoyer')) }}</button>
</div>
</form>
</div>
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+lodash@^4.17.15:
+ version "4.17.15"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
+ integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+
loglevel@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.2.tgz#668c77948a03dbd22502a3513ace1f62a80cc372"