protected $_modelNamespace = 'App\Models\Panier';
protected $_routeURL = 'selection';
protected $_singular = 'Panier';
- protected $_plural = 'Paniers';
+ protected $_plural = 'PaniersEnregistres';
protected $_clonable = true;
protected $_bulk = true;
protected $_oneInstance= false;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Arr;
class AjaxController extends CubistFrontController
{
return false;
}
- public function storepanier(Request $request) {
+ public function storecart(Request $request) {
$validation = [
'name' => 'required|string|max:255',
'addresses' => 'required',
'products' => 'required',
- 'userId' => 'required|numeric'
+ 'user_id' => 'required|numeric'
];
$data = $this->validation_form($request, $validation);
- $panier = new Panier($data);
- $panier->save();
- return 'ok';
+ $lastCartId = $request->session()->get('last_selection');
+
+ //
+ $lastCartRefs = $lastCartId ? Panier::find($lastCartId)->getReferences() : [];
+ $currentCartRef = Panier::getRefs($data['products']);
+ $intersect = $lastCartRefs ? array_intersect($currentCartRef,$lastCartRefs) : [];
+
+ /**
+ *
+ */
+ $options = Product::getOptionsByProductsId($data['products']);
+
+ $opt = [];
+ $total = [];
+
+ foreach ($currentCartRef as $keyRefs => $refs) {
+ foreach (explode("/", $refs) as $key => $ref) {
+ $key -= 1;
+ if ($key > -1) {
+ $opt_ = array_filter($options[$keyRefs][$key]["options"], function ($n) use ($ref) {
+ return $n["ref"] === $ref;
+ });
+ $opt_ = array_values($opt_);
+ $opt[$refs][] = $opt_[0]["sale_price"];
+ }
+ }
+
+ $quantity = intval($data['products'][$keyRefs]["quantity"]);
+ $basicSellingPrice = $data['products'][$keyRefs]["basic_selling_price"];
+
+ $totalOptionsPrice = $basicSellingPrice ? array_reduce($opt[$refs], function ($carry, $item) {
+ return $carry + $item;
+ }) : 0;
+
+ $basicPriceByProductId = $data['products'][$keyRefs]["basic_selling_price"];
+ $price = floatval(($basicPriceByProductId + $totalOptionsPrice) * $quantity);
+ $data['products'][$keyRefs]["price"] = $total[] = $price;
+ }
+
+ $ht = array_reduce($total, function($carry, $item) { return $carry + $item; });
+ $ht += ($total > 1000) ? 20 : 0;
+ $tva = $ht * 0.2;
+ $ttc = $ht + $tva;
+ $data['total'] = $ttc;
+
+ //
+ $data['addresses'] = json_encode($data['addresses']);
+ $data['products'] = json_encode($data['products']);
+
+ if(sizeof($lastCartRefs) !== sizeof($intersect) ||
+ (sizeof($lastCartRefs) === sizeof($intersect) && sizeof($currentCartRef) != sizeof($lastCartRefs)) ) {
+ $panier = Panier::firstOrCreate($data);
+ $panier->save();
+ // Save back to the session with the latest cart id
+ $id = $panier->getOriginal('id');
+ $request->session()->put('last_selection', $id);
+ } else {
+ Panier::where('id', $lastCartRefs)->update($data);
+ }
+
+ return __('Le panier a été enregistré avec succès !');
+ }
+
+ public function deleteSavedcart(Request $request) {
+ $request->validate([
+ 'id' => 'required|numeric',
+ ]);
+ $id = $request->input('id');
+
+ $cart = Panier::find($id);
+
+ $cart->delete();
+ }
+
+ public function updateNameSavedcart(Request $request) {
+ $request->validate([
+ 'id' => 'required|numeric',
+ 'text' => 'required|max:255'
+ ]);
+ $id = $request->input('id');
+ $text = $request->input('text');
+
+ $cart = Panier::find($id);
+
+ $cart->name = $text;
+
+ $cart->save();
+ }
+
+ public function savedCartToCurrent(Request $request) {
+
+ //$this->cart()
}
}
{
if (($request->path() === "se-connecter") && Auth::guard('web-clients')->check()) {
return redirect('/');
- }
-
- if (($request->path() === "mon-compte") && !Auth::guard('web-clients')->check()) {
+ }elseif($request->path() !== "se-connecter" && !Auth::guard('web-clients')->check()) {
return redirect('/se-connecter');
}
'label' => 'Produits',
'type' => 'Text',
'column' => true
+ ],
+ [
+ 'name' => 'total',
+ 'type' => 'Text'
]
];
}
protected $_options = ['name' => 'selection',
'singular' => 'Panier',
- 'plural' => 'Paniers'];
+ 'plural' => 'PaniersEnregistres'];
public function setFields()
{
$this->addField($fields);
}
}
+
+ public static function getRefs($products) {
+ $refs = array_map(function ($n) {
+ return $n["ref"] ?? $n["reference"];
+ }, $products);
+
+ return $refs;
+ }
+
+ public function getReferences(){
+ $panier = $this->toArray();
+ $products = json_decode($panier['products'], true);
+
+ $refs = self::getRefs($products);
+
+ return $refs;
+ }
+
+ public static function getAllCart() {
+ return Panier::all()->toArray();
+ }
}
$cart_items = session('cart_items', []);
self::$_cart_data = [];
+ $cart_items_id = array_map(function($n){ return $n['id']; }, $cart_items);
+
+
if (count($cart_items) > 0) {
+ $productsSellingBasicPrice = self::whereIn('id', $cart_items_id)
+ ->select('id','basic_selling_price')
+ ->get()
+ ->toArray();
+
+ foreach ($cart_items as $key => &$values) {
+ $id = $values["id"];
+ $getCartItem = array_values(array_filter($productsSellingBasicPrice, function($n) use($id) { return $n['id'] === $id; }));
+ $values["basic_selling_price"] = floatval($getCartItem[0]["basic_selling_price"]) ?? 0;
+ }
+
self::$_cart_data = $cart_items;
}
}
-
return self::$_cart_data;
}
+ public function getOptions() {
+ return json_decode($this['json'], true);
+ }
+
+ public static function getOptionsByProductsId($products) {
+ $options = Product::whereIn('id', array_column($products, 'id'))
+ ->select('id','json')
+ ->get()
+ ->groupBy('id')
+ ->map(function ($group) {
+ return $group->pluck('json')->toArray();
+ })
+ ->toArray();
+
+ return array_map(function($n) use($options) {
+ return json_decode($options[$n['id']][0],true);
+ }, $products
+ );
+ }
public static function getFilteredProducts($product_type, $filter_values = [])
{
BladeX::component('components.news-item'); // <news-item :item="$newsItem"> ... </news-item>
BladeX::component('components.address-form'); // <address-form> ... </address-form>
BladeX::component('components.modal-confirm'); // <modal-confirm> ... </modal-confirm>
+ BladeX::component('components.btn-delete'); // <btn-delete> ... </btn-delete>
} catch (\Exception $e) {
}
--- /dev/null
+<?php
+
+
+namespace App\Templates;
+
+
+class PaniersEnregistres extends Base
+{
+ public function getName()
+ {
+ return 'Paniers enregistrés';
+ }
+
+ public function init()
+ {
+ parent::init();
+ }
+}
price: '',
ref: '',
statusConfig: false,
- statusText: ''
+ statusText: '',
+ //
+ nameSaved: {}
},
beforeMount() {
mounted() {
eventBus.$on('add-item', data => {
data.action = 'add';
- data.ref = this.ref;
+ data.ref = this.ref ?? data.ref;
data.price = this.price;
this.saveCart(data);
});
}
}
},
+ animateDelete(el, parent = null) {
+ el.animate([
+ { opacity: 1 },
+ { opacity: 0 }
+ ],
+ {
+ duration: 1000
+ }
+ );
+ setTimeout(() => {
+ parent ? el.parentElement.remove() : el.remove()
+ }, 1000)
+ },
checkEmailExist() {
let root = this,
data = {
if(response.data)
root.addresses = response.data
- form_.animate([
- { opacity: 1 },
- { opacity: 0 }
- ],
- {
- duration: 1000
- }
- );
- setTimeout(() => {
- form_.parentElement.remove()
- }, 1000)
+ root.animateDelete(form_, true)
})
.catch(function (error) {
}
/**
*
*/
- storePanier() {
+ storeCart() {
let root = this,
data = {
name: "Panier du "+document.querySelector('[name="now"]').dataset.content,
- userId: this.user.id,
+ user_id: this.user.id,
addresses: this.addresses,
products: this.items
}
- axios.post('/ajax/storepanier', data)
+ axios.post('/ajax/storecart', data)
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
+ },
+ toggleName(event) {
+ const id = event.target.dataset.input,
+ editText = event.target.dataset.edittext,
+ defaultText = event.target.dataset.defaulttext,
+ el = document.getElementById('cart-name-'+id)
+
+ if(el.value.length > 0)
+ var state = el.classList.toggle("readonly")
+
+ if(!state) {
+ el.focus()
+ el.removeAttribute('readonly')
+ event.target.innerText = editText
+ } else {
+ axios.post('/ajax/updateNameSavedcart', {id: id, text: el.value})
+ .then(function (response) {
+ event.target.innerText = defaultText
+ el.setAttribute('readonly', 'readonly')
+ })
+ .catch(function (error) {
+ })
+ }
+ },
+ removeSavedCart(event) {
+ const id = event.target.dataset.id ?? event.target.parentElement.dataset.id,
+ el = document.getElementById('cart-saved-'+id),
+ root = this
+
+ axios.post('/ajax/deleteSavedcart', {id: id})
+ .then(function (response) {
+ root.animateDelete(el)
+ })
+ .catch(function (error) {
+ })
+ },
+ savedCartToCurrent() {
+ const data = {
+
+ }
}
},
/**
$(this).addClass('btn-no-hover').addClass('bg-navy');
$(this).find('.add').addClass('hidden');
$(this).find('.added').removeClass('hidden').addClass('inline-flex');
- var id = parseInt($(this).attr('data-product-id'));
+ var id = parseInt($(this).attr('data-product-id')),
+ ref = $(this).attr('data-ref')
+
eventBus.$emit('add-item', {
id: id,
quantity: 1,
+ ref: ref
});
clearTimeout(time);
body
min-width: 320px
-p:not(:last-child)
+p:not(:last-child):not(.no-m)
margin-bottom: 1.5em
// Layout containers
+below(850px)
grid-fallback(1)
+
+//
+.cartsave
+ &:not(:last-child)
+ margin-bottom: 24px
+ &-name
+ padding: 46px 0 26px
+ input
+ padding: 10px
+ width: 100%
+ max-width: 100%
+ &.readonly
+ background: none
+ cursor: default
+ outline: none
+ padding: 0
+
+ &-products
+ padding: 24px 0
+ border-top: 1px solid theme('colors.light-b')
+ border-bottom: 1px solid theme('colors.light-b')
+
+ .grid:not(:last-child)
+ margin-bottom: 24px
+
+ &-grid
+ grid-template-columns: 96px 1fr !important
+
+ &-footer
+ padding: 48px 0
+
+ .product
+ &-thumbnail
+ height: 96px
--- /dev/null
+<button class="flex items-center" data-id="{{ $id }}" @click="removeSavedCart">
+ @svg('icon-trash')
+ <span class="ml-3">{{ $slot }}</span>
+</button>
-<button data-product-id="{{ $id }}" class="btn cart-add" :class="{ 'pointer-events-none bg-grey-disabled' : (!isNaN(price) && !statusConfig) || (price && !user) }">
+<button data-ref="{{ $reference }}" data-product-id="{{ $id }}" class="btn cart-add" :class="{ 'pointer-events-none bg-grey-disabled' : (!isNaN(price) && !statusConfig) || (price && !user) }">
<span class="btn-text relative">
<span class="add">
@if(isset($price))
{{-- Nested divs to allow grey backgrounds of columns to match the height of their content instead of total height --}}
<div>
<cart :items='items' :sendevents="false" class="bg-grey-100 p-1v pb-0 overflow-hidden"></cart>
- <div class="bg-grey-100 p-1v pt-0">
+
+ <div class="bg-grey-100 p-1v pt-0" v-cloak v-if="cartItemCount === cartItemHasPriceCount">
<div class="cart-shipping-fees text-navy">
{{ __('Frais de ports') }} : <span v-cloak>@{{ total > 1000 ? '20€' : '0€' }}</span>
</div>
<p class="text-2xl text-navy">{{ __('Total TTC') }} : <span v-cloak>@{{ totalTTC }}</span></p>
</div>
</div>
- <button class="cart-valid-command btn btn-custom xs:w-full">
+ <button class="cart-valid-command btn btn-custom xs:w-full" v-cloak v-if="cartItemCount === cartItemHasPriceCount">
{{ __('Valider la commande') }}
</button>
<div class="cart-links">
- <a href="#">{{ __('Obtenir un devis officiel') }}</a><br>
- <a href="#" @click.prevent="storePanier()">{{ __('Enregistrer ce panier') }}</a>
+ <a href="#" v-cloak v-if="cartItemCount === cartItemHasPriceCount">{{ __('Obtenir un devis officiel') }}</a><br>
+ <a href="#" @click.prevent="storeCart()">{{ __('Enregistrer ce panier') }}</a>
</div>
- <div class="text-sm">
+ <div class="text-sm" v-cloak v-if="cartItemCount === cartItemHasPriceCount">
En nous transmettant votre demande, vous acceptez que PM Instrumentation traite vos données
personnelles dans le but de vous offrir un service de qualité. Pour plus d’information sur la
protection de vos données à caractère personnel, vous pouvez consulter la page
--- /dev/null
+@extends('layouts/app')
+
+@section('content')
+ <full-width padding="pb-3v">
+ <content>
+ <text-block :title="$page->title" title-tag="h1" />
+
+ @foreach(\App\Models\Panier::getAllCart() as $cart)
+ <div id="cart-saved-{{ $cart['id'] }}" class="cartsave bg-grey-200 pr-2v pl-2v">
+ <div class="cartsave-name">
+ <div>
+ <textarea id="cart-name-{{ $cart['id'] }}" class="readonly" value="{{ $cart['name'] }}" readonly />
+ </div>
+ <a href="#" data-input="{{ $cart['id'] }}" class="inline-block animated-underline" data-defaulttext="{{ __('Editer le nom du panier') }}" data-edittext="{{ __('Sauvegarder le nom du panier') }}" @click.prevent.self="toggleName">
+ {{ __('Editer le nom du panier') }}
+ </a>
+ </div>
+ <div class="cartsave-products">
+ @foreach(json_decode($cart['products'], true) as $key => $product)
+ <grid gap="md" class="sm:grid-cols-1 cartsave-grid">
+ <div class="product-thumbnail bg-center bg-contain bg-no-repeat" style='background-image : url("{{ $product['image'] }}")'>
+ </div>
+ <div class="product-infos flex justify-between items-center">
+ <div>
+ <p class="no-m">{{ $product['ref'] }}</p>
+ <p class="no-m text-navy">{{ $product['name'] }}</p>
+ @isset($product['basic_selling_price'])
+ @if(floatval($product['basic_selling_price']))
+ <p class="no-m">{{ __('Prix unitaire') }} <span class="text-navy">{{
+ $product['basic_selling_price'] }} € HT</span>
+ </p>
+ @endif
+ @endisset
+ <p class="no-m">{{ __('Quantité') }} : <span class="text-navy">{{$product['quantity']}}</span></p>
+ </div>
+ <div class="product-price">
+ @if(floatval($product['price']))
+ <p class="no-m">{{ $product['price'] }}€ HT</p>
+ @else
+ <p class="text-navy">
+ N/A
+ <span
+ data-tooltip="{{__('Prix sur devis.')}}"
+ class="font-display text-lg inline-block align-middle rounded-full border-grey-dark border-2 h-8 w-8 text-center ml-3">?</span>
+ </p>
+ @endif
+ </div>
+ </div>
+ </grid>
+ @endforeach
+ </div>
+ <div class="cartsave-footer <?php echo $cart['total'] ? 'pt-6' : 'pt-12' ?>">
+ @isset($cart['total'])
+ <div class="text-right pb-6">
+ <p class="no-m">{{ __('Montant Total') }}</p>
+ <p class="no-m">{{ $cart['total'] }}€ HT</p>
+ </div>
+ @endisset
+ <div class="flex justify-between items-center">
+ <button class="flex items-center" data-id="{{ $cart['id'] }}" @click.stop="removeSavedCart">
+ @svg('icon-trash')
+ <span class="ml-3">{{ __('Supprimer ce panier') }}</span>
+ </button>
+
+ <div class="flex items-center">
+ <a href="" class="animated-underline mr-10 xs:mr-0">{{ __('Modifier ce panier') }}</a>
+ @isset($cart['total'])
+ <a href="" class="btn">{{ __('Passer commande') }}</a>
+ @else
+ <a href="" class="btn">{{ __('Demander un devis') }}</a>
+ @endisset
+ </div>
+ </div>
+ </div>
+ </div>
+ @endforeach
+ </content>
+ </full-width>
+@endsection
@endauth
@if(config('features.quote'))
- <cart-add :id="$product->id" :price="$product->basic_selling_price"></cart-add>
+ <cart-add :id="$product->id" :reference="$product->reference" :price="$product->basic_selling_price"></cart-add>
<span
data-tooltip="{{__('Ajoutez un ou plusieurs produits à votre sélection, ajustez les quantités et obtenez un devis.')}}"
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>
</link-button>
<div class="text-center">
<a href="" class="animated-underline mt-5 inline-block w-100">{{ __('Obtenir un devis officiel') }}</a><br>
- <a href="" class="animated-underline mt-5 inline-block">{{ __('Enregistrer ce panier') }}</a>
+ <a href="" class="animated-underline mt-5 inline-block" @click.prevent="storeCart()">{{ __('Enregistrer ce panier') }}</a>
</div>
</div>
</div>
</a>
</li>
<li class="{{ Request::is('panier-enregistré') ? "active" : '' }}">
- <a href="">
+ <a href="/paniers-enregistres">
<span>{{ __('Panier enregistrés') }}</span>
</a>
</li>
{{$product->get('name')}}
</div>
@if(config('features.quote'))
- <cart-add :id="$product->id"></cart-add>
+ <cart-add :id="$product->id" :reference="$product->reference"></cart-add>
@endif
<div class="links mt-4">
<div class="link">
//add specific name to be simple to add active class
//add middleware to secure this specific page
Route::any('{page}', 'PageController@catchall')->where(
- ['page' => '\b(se-connecter|mon-compte)\b']
+ ['page' => '\b(se-connecter|mon-compte|paniers-enregistres)\b']
)->name('client')->middleware('client');
Route::any('{page}/{subs?}', 'PageController@catchall')