feat: ✨ Closes #46

Add orders filter with: a search bar, date filters
This commit is contained in:
Jérémy Munsch 2024-05-15 16:58:17 +02:00
parent f15e722588
commit 3a3d993d7c
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
12 changed files with 547 additions and 143 deletions

View file

@ -9,6 +9,7 @@ use Illuminate\Support\Facades\Mail;
use App\Mail\OrderStatusMail;
use App\Models\Customers;
use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
@ -22,11 +23,55 @@ class OrdersController extends Controller
*/
public function index(SortOrders $request)
{
$orders = $this->filterOrders($request);
$query = $this->sortOrders($request);
$orders = $orders->paginate(10);
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$query,
$search,
function (Builder $q) use ($search) {
$q->orWhereHas('timeslot.magasin', function (Builder $q) use ($search) {
$q->where('name', 'LIKE', "%{$search}%");
});
},
'reference'
);
}
$searchFields = \implode(', ', [
trans('Référence, Point de retrait'),
]);
return view('bo.orders.index', compact('orders'));
// * Dates Filter
if (!empty($request->input('date-order-start'))) {
if (!empty($request->input('date-order-end'))) {
$query->whereBetween('date', [
$request->input('date-order-start'),
$request->input('date-order-end'),
]);
} else {
$query->where('date', $request->input('date-order-start'));
}
}
if (!empty($request->input('date-retrait-start'))) {
if (!empty($request->input('date-retrait-end'))) {
$query->whereHas('timeslot', function (Builder $q) use ($request) {
$q->whereBetween('day', [
$request->input('date-retrait-start'),
$request->input('date-retrait-end'),
]);
});
} else {
$query->whereHas('timeslot', function (Builder $q) use ($request) {
$q->where('day', $request->input('date-retrait-start'));
});
}
}
$orders = $query->paginate(10);
return view('bo.orders.index', compact('orders', 'searchFields'));
}
/**
@ -37,16 +82,34 @@ class OrdersController extends Controller
*/
public function today(SortOrders $request)
{
$orders = $this->filterOrders($request);
$query = $this->sortOrders($request);
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$query,
$search,
function (Builder $q) use ($search) {
$q->orWhereHas('timeslot.magasin', function (Builder $q) use ($search) {
$q->where('name', 'LIKE', "%{$search}%");
});
},
'reference'
);
}
$searchFields = \implode(', ', [
trans('Référence, Point de retrait'),
]);
// Filter today.
$today = CarbonImmutable::now()->startOfDay();
$orders = $orders->whereHas('timeslot', function ($q) use ($today) {
$today = CarbonImmutable::now()->startOfDay();
$query = $query->whereHas('timeslot', function ($q) use ($today) {
$q->where('day', $today);
});
$orders = $orders->get();
return view('bo.orders.index', compact('orders', 'today'));
$orders = $query->get();
return view('bo.orders.index', compact('orders', 'today', 'searchFields'));
}
/**
@ -55,51 +118,51 @@ class OrdersController extends Controller
* @param Request $request
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function filterOrders(Request $request)
protected function sortOrders(Request $request)
{
$orders = Order::query();
$query = Order::query();
if ($request->rst) {
if ($request->input('rst')) {
Session::remove('orders.sort_col');
Session::remove('orders.sort_way');
}
if ($request->sort_col) {
Session::put('orders.sort_col', $request->sort_col);
if ($request->input('sort_col')) {
Session::put('orders.sort_col', $request->input('sort_col'));
Session::save();
}
if ($request->sort_way) {
Session::put('orders.sort_way', $request->sort_way);
if ($request->input('sort_way')) {
Session::put('orders.sort_way', $request->input('sort_way'));
Session::save();
}
if (Session::has('orders.sort_col') and Session::has('orders.sort_way')) {
switch (Session::get('orders.sort_col')) {
case 'date':
$orders = $orders->orderBy('date', Session::get('orders.sort_way'));
$query = $query->orderBy('date', Session::get('orders.sort_way'));
break;
case 'status_id':
$orders = $orders->orderBy('status_id', Session::get('orders.sort_way'));
$query = $query->orderBy('status_id', Session::get('orders.sort_way'));
break;
case 'magasin_id':
$orders = $orders->select('orders.*');
$orders = $orders->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
$orders = $orders->leftJoin('magasins', 'timeslots.magasin_id', '=', 'magasins.id');
$orders = $orders->orderBy('magasins.id', Session::get('orders.sort_way'));
$query = $query->select('orders.*');
$query = $query->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
$query = $query->leftJoin('magasins', 'timeslots.magasin_id', '=', 'magasins.id');
$query = $query->orderBy('magasins.id', Session::get('orders.sort_way'));
break;
case 'date_retrait':
$orders = $orders->select('orders.*');
$orders = $orders->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
$orders = $orders->orderBy('timeslots.day', Session::get('orders.sort_way'));
$orders = $orders->orderBy('timeslots.time', Session::get('orders.sort_way'));
$query = $query->select('orders.*');
$query = $query->leftJoin('timeslots', 'timeslots.order_id', '=', 'orders.id');
$query = $query->orderBy('timeslots.day', Session::get('orders.sort_way'));
$query = $query->orderBy('timeslots.time', Session::get('orders.sort_way'));
break;
case 'customer_id':
$orders = $orders->orderBy('customer_id', Session::get('orders.sort_way'));
$query = $query->orderBy('customer_id', Session::get('orders.sort_way'));
break;
}//end switch
}//end if
} //end switch
} //end if
return $orders;
return $query;
}
/**

View file

@ -2,14 +2,140 @@
namespace App\Http\Controllers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
class Controller extends BaseController
{
use AuthorizesRequests;
use DispatchesJobs;
use ValidatesRequests;
/**
* Build Search query on specified fields
* splitting search into words or using whole sentence
*
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
* @param string $search The query string.
* @param callable $searchQuery The query string.
* @param string ...$fields Either a simple array or a string
* in case of a string the two fields
* would be concatenate to make the search.
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function searchQuery(
Builder $query,
string $search,
callable $searchQuery = null,
string ...$fields
): Builder {
if (count($fields)) {
// Search using words.
$words = explode(' ', $search);
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
foreach ($words as $word) {
if (!strlen($word)) {
continue;
}
$this->searchOnFields($query, $word, $fields);
} //end foreach
// Search whole using whole sentence.
$this->searchOnFields($query, $search, $fields);
if ($searchQuery) {
$searchQuery($query);
}
});
} //end if
return $query;
}
/**
* Build query search on all fields
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param array $fields
* @return \Illuminate\Database\Eloquent\Builder
*/
private function searchOnFields(
Builder $query,
string $search,
array $fields
): Builder {
$table = $query->getModel()->getTable();
foreach ($fields as $field) {
$field = str_replace('?', '\?', $field);
if (is_array($field)) {
$query->orWhereRaw(
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
return "`$table`.`$q`";
})->implode(', \' \', ')),
['%' . htmlspecialchars($search) . '%']
);
return $query;
}
// Get models woth enum's label.
if (is_array($this->getSearchValue($query, $search, $field))) {
foreach ($this->getSearchValue($query, $search, $field) as $array) {
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($array->value) . '%']
);
}
return $query;
}
// Get models with relation's name/label.
if (Str::endsWith($field, '_id')) {
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
$queryRelation->where('name', 'like', '%' . $search . '%');
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
$queryRelation->where('label', 'like', '%' . $search . '%');
}
});
return $query;
}
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
);
} //end foreach
return $query;
}
/**
* Get the search value (on string or Enum).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param string $field
* @return string|array
*/
protected function getSearchValue(Builder $query, string $search, string $field)
{
$cast = $query->getModel()->getCasts()[$field] ?? null;
if (
count($query->getModel()->getCasts()) and // Check if the model has casts.
// Check if there is cast about specific field.
is_string($cast) and
class_exists($cast) and
// Check if the cast is an enum.
in_array(\Kwaadpepper\Enum\BaseEnum::class, class_parents(\App\Enums\PriceShowingMode::class))
) {
/** @var \Kwaadpepper\Enum\BaseEnum $cast */
// @phpstan-ignore-next-line
$cases = collect($cast::toArray());
$enum = $cases->filter(function ($item) use ($search) {
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
});
return $enum->toArray();
} else {
return $search;
}
}
}

View file

@ -23,8 +23,35 @@ class SortOrders extends FormRequest
*/
public function rules()
{
return [
$rules = [
'sort_way' => 'sometimes|in:asc,desc',
];
if ($this->routeIs('bo.orders')) {
$rules = array_merge($rules, [
'date-order-start' =>
'required_with:date-order-end|nullable|date_format:Y-m-d|before:date-order-end',
'date-order-end' => 'nullable|date_format:Y-m-d|after:date-order-start',
'date-retrait-start' =>
'required_with:date-retrait-end|nullable|date_format:Y-m-d|before:date-retrait-end',
'date-retrait-end' => 'nullable|date_format:Y-m-d|after:date-retrait-end',
]);
}
return $rules;
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'date-order-start' => trans('Date de commande'),
'date-order-end' => trans('Jusqu\'au'),
'date-retrait-start' => trans('Date de retrait'),
'date-retrait-end' => trans('Jusqu\'au'),
];
}
}

4
resources/js/app.js vendored
View file

@ -1,6 +1,8 @@
require('./bootstrap');
require('@fancyapps/fancybox');
import Vue from 'vue'
import Vue from 'vue';
import "./orderFilters";
// Vuex
// import Vuex from 'vuex';

View file

@ -7,12 +7,12 @@ window._ = require('lodash');
*/
window.axios = require('axios');
import Popper from 'popper.js'
import tippy, {createSingleton} from 'tippy.js';
import Popper from 'popper.js';
import tippy, { createSingleton } from 'tippy.js';
//window.Popper = require('popper.js').default;
window.$ = window.jQuery = require('jquery');
//require('@fortawesome/fontawesome-free/js/all');
require('bootstrap');
const bootstrap = require('bootstrap');
window.Popper = Popper;
window.tippy = tippy;
window.createSingleton = createSingleton;
@ -40,3 +40,15 @@ window.axios.defaults.headers.common = {
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
// forceTLS: true
// });
setTimeout(() => {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => {
// * VUE 2 removes title attributes
const label = tooltipTriggerEl.getAttribute('arial-label');
if (label) {
tooltipTriggerEl.setAttribute('title', label);
}
return new bootstrap.Tooltip(tooltipTriggerEl);
});
}, 2000);

30
resources/js/orderFilters.js vendored Normal file
View file

@ -0,0 +1,30 @@
document.addEventListener("DOMContentLoaded", function () {
const tagListToSwitchDisplay = ["date-order", "date-retrait"];
tagListToSwitchDisplay.forEach(function (tag) {
/** @type {NodeListOf<HMTLElement>} */
const elementListToSwitchDisplay = document.querySelectorAll(
`[data-toggle="${tag}-end"]`
);
/** @type {HTMLElement|null} */
const toggleSwitchElement = document.getElementById(`${tag}-switch`);
if (!toggleSwitchElement) {
return;
}
// * Force switch on if end is filled with a date
elementListToSwitchDisplay.forEach((el) => {
toggleSwitchElement.checked = el.value?.length ? true : false;
});
const displaySwitch = () => {
elementListToSwitchDisplay.forEach((el) => {
if (toggleSwitchElement.checked) {
el.classList.remove("d-none");
} else {
el.classList.add("d-none");
}
});
};
displaySwitch();
toggleSwitchElement.addEventListener("change", displaySwitch);
});
});

View file

@ -10,3 +10,16 @@
.display-flex {
display: flex !important;
}
.w-md-auto {
width: 100% !important;
/** Equivalent to @include media-breakpoint-up(md) */
@media (min-width: 768px) {
width: auto !important;
}
}
.flex-50 {
flex-basis: 50% !important;
}

View file

@ -32,7 +32,7 @@
//tooltips
.tooltip {
.tooltip:not(.bs-tooltip-auto) {
background: #333;
color: white;
font-weight: bold;

View file

@ -0,0 +1,39 @@
@php
$iArgs = [];
if (request()->sort_col) {
$iArgs['sort_col'] = request()->sort_col;
}
if (request()->search) {
$iArgs['search'] = request()->sort_way;
}
@endphp
<div class="row mb-3">
<div class="col-12 g-0">
<div class="input-group pt-3">
<label class="input-group-text" for="searchField">{{ $searchFields }}</label>
@if (request()->sort_col)
<input class="d-none" name="sort_col" type="text" value="{{ request()->sort_col }}">
@endif
@if (request()->sort_way)
<input class="d-none" name="sort_way" type="text" value="{{ request()->sort_way }}">
@endif
@if (request()->rangefilter)
<input class="d-none" name="rangefilter" type="text" value="{{ request()->rangefilter }}">
@endif
@if (request()->group)
<input class="d-none" name="group" type="text" value="{{ request()->group }}">
@endif
<input class="form-control" id="searchField" name="search" type="search" value="{{ request()->search }}"
placeholder="{{ __('Rechercher un élement') }}" />
<button class="btn btn-primary" data-bs-toggle="tooltip" type="submit" title="{{ __('Lancer la recherche') }}"
aria-label="{{ __('Lancer la recherche') }}">
<i class="fas fa-search"></i>
</button>
<button class="btn btn-danger" id="searchbar-delete" data-bs-toggle="tooltip" type="button"
title="{{ __('Effacer la recherche') }}" aria-label="{{ __('Effacer la recherche') }}">
<i class="fas fa-backspace"></i>
</button>
</div>
</div>
</div>

View file

@ -1,77 +1,157 @@
@extends('layouts.bo-layout')
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Commandes @if (isset($today)) à retirer aujourd'hui @endif</h1>
<div class="d-flex justify-content-between flex-md-nowrap align-items-center border-bottom mb-3 flex-wrap pb-2 pt-3">
<h1 class="h2">Commandes @if (isset($today))
à retirer aujourd'hui
@endif
</h1>
@if (session('success'))
<span class="float-center text-success">{{ session('success') }}</span>
@endif
</div>
<table class="table">
<thead>
<th scope="col">Client&nbsp;
@include('bo.modules.sorter', ['colname' => 'customer_id', 'list' => 'orders'])
</th>
<th scope="col">Référence</th>
<th scope="col">
Date&nbsp;
@include('bo.modules.sorter', ['colname' => 'date', 'list' => 'orders'])
</th>
<th scope="col">Total en €</th>
<th scope="col">Date de retrait&nbsp;
@include('bo.modules.sorter', ['colname' => 'date_retrait', 'list' => 'orders'])
</th>
<th scope="col">
Point de retrait&nbsp;
@include('bo.modules.sorter', ['colname' => 'magasin_id', 'list' => 'orders'])
</th>
<th scope="col">
Statut&nbsp;
@include('bo.modules.sorter', ['colname' => 'status_id', 'list' => 'orders'])
</th>
<th><a href="{{ route(Route::currentRouteName(), ['rst' => 1]) }}" class="float-right btn btn-sm btn-dark mr-2">Réinitialiser le tri</a></th>
</thead>
<tbody>
@foreach ($orders as $order)
<tr>
<td>
{{--<a data-fancybox data-trigger="customer-info" data-type="ajax" data-src="{{ route('bo.get-customer-info', $order->customer->id) }}" data-src="#customer-info" href="javascript:;">
Infos Client
</a>--}}
<a class="ajax-tippy-cust" id="tippy-{{$order->customer->id}}" data-custid="{{$order->customer->id}}" href="javascript:">Infos Client</a>
</td>
<td>{{$order->reference}}</td>
<td>{{\Carbon\Carbon::parse($order->date)->format('d/m/Y')}}</td>
<td>{{number_format($order->total, 2, ',', ' ')}}€</td>
<td>
@if (!empty($order->timeslot))
{{$order->timeslot->day}} {{$order->timeslot->time}}
@endif
</td>
<td>
@if (!empty($order->timeslot))
{{--<a data-fancybox data-trigger="magasin-info" data-type="ajax" data-src="{{ route('bo.get-magasin-info', $order->timeslot->magasin->id) }}" data-src="#magasin-info" href="javascript:;">
{{$order->timeslot->magasin->name}}
</a>--}}
<a class="ajax-tippy-shop" id="shop-{{$order->timeslot->magasin->id}}" data-shopid="{{$order->timeslot->magasin->id}}" href="javascript:">{{$order->timeslot->magasin->name}}</a>
@endif
</td>
<td>{{$order->status->label}}</td>
<td class="text-center">
{{-- L'id du status 6 est le status "Retirée", la dernière étape d'une commande --}}
<a href="{{route('bo.order-detail', $order->reference)}}" class="btn btn-sm btn-primary"><i class="fas fa-info"></i></a>
@if ($order->status_id < 6 && $order->status_id >=3 )
<a href="{{route('bo.change-order-status', $order->reference)}}" class="btn btn-sm btn-primary"><i class="fas fa-forward"></i></a>
@endif
@if ($order->status_id < 6)
<a href="{{route('bo.cancel-order', $order->reference)}}" class="btn btn-sm btn-danger" onclick="return confirm('Êtes-vous sûr(e) ?')"><i class="fas fa-times"></i></a>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
@if($orders instanceof \Illuminate\Pagination\LengthAwarePaginator )
<form class="container-fluid" id="searchForm" action="/{{ request()->path() }}">
@include('bo.modules.search-bar-orders')
@if (request()->routeIs('bo.orders'))
<div class="row mb-1">
<div class="col-xl-6 g-0">
<div class="input-group mb-2">
<span class="input-group-text">{{ __('Date de commande') }}</span>
<div class="input-group-text">
<div class="form-check form-switch">
<input class="form-check-input" id="date-order-switch" name="date-order-switch" type="checkbox" value="1"
role="switch" @if (old('date-order-switch', request()->input('date-order-switch')) ? true : false) checked @endif>
<label class="form-check-label" data-bs-toggle="tooltip" for="date-order-switch"
title="{{ __('Rechercher en utilisant une plage de dates') }}">{{ __('Plage') }}</label>
</div>
</div>
<label class="input-group-text" for="date-order-start">{{ __('Du') }}</label>
<input class="form-control w-md-auto" id="date-order-start" name="date-order-start" type="date"
value="{{ old('date-order-start', request()->input('date-order-start')) }}">
<label class="input-group-text d-none flex-50" data-toggle="date-order-end"
for="date-order-end">{{ __('Jusqu\'au') }}</label>
<input class="form-control d-none w-md-auto" id="date-order-end" name="date-order-end" data-toggle="date-order-end"
type="date" value="{{ old('date-order-end', request()->input('date-order-end')) }}">
</div>
@include('modules.input-error', ['inputName' => 'date-order-start'])
@include('modules.input-error', ['inputName' => 'date-order-end'])
</div>
<div class="col">
<div class="input-group mb-2">
<span class="input-group-text">{{ __('Date de retrait') }}</span>
<div class="input-group-text">
<div class="form-check form-switch">
<input class="form-check-input" id="date-retrait-switch" name="date-retrait-switch" type="checkbox"
value="1" role="switch" @if (old('date-retrait-switch', request()->input('date-retrait-switch')) ? true : false) checked @endif>
<label class="form-check-label" data-bs-toggle="tooltip" for="date-retrait-switch"
title="{{ __('Rechercher en utilisant une plage de dates') }}">{{ __('Plage') }}</label>
</div>
</div>
<label class="input-group-text" for="date-retrait-start">{{ __('Du') }}</label>
<input class="form-control w-md-auto" id="date-retrait-start" name="date-retrait-start" type="date"
value="{{ old('date-retrait-start', request()->input('date-retrait-start')) }}">
<label class="input-group-text d-none flex-50" data-toggle="date-retrait-end"
for="date-retrait-end">{{ __('Jusqu\'au') }}</label>
<input class="form-control d-none w-md-auto" id="date-retrait-end" name="date-retrait-end"
data-toggle="date-retrait-end" type="date"
value="{{ old('date-retrait-end', request()->input('date-retrait-end')) }}">
</div>
@include('modules.input-error', ['inputName' => 'date-retrait-start'])
@include('modules.input-error', ['inputName' => 'date-retrait-end'])
</div>
</div>
@push('scripts')
<script @if (!empty($nonce)) nonce="{{ $nonce }} @endif">
document.getElementById('searchbar-delete').addEventListener('click', function(e) {
e.preventDefault();
window.location = '/{{ request()->path() }}';
});
</script>
@endpush
@endif
</form>
<div class="row mb-3">
<div class="col">
<span class="fw-bold">{{ __('Obligatoire') }}</span>
</div>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<th scope="col"><span>{{ __('Client') }}</span>&nbsp;
@include('bo.modules.sorter', ['colname' => 'customer_id', 'list' => 'orders'])
</th>
<th scope="col">{{ __('Référence') }}</th>
<th scope="col">
<span>{{ __('Date commande') }}</span>&nbsp;
@include('bo.modules.sorter', ['colname' => 'date', 'list' => 'orders'])
</th>
<th scope="col">{{ __('Total en €') }}</th>
<th scope="col"><span>{{ __('Date de retrait') }}</span>&nbsp;
@include('bo.modules.sorter', ['colname' => 'date_retrait', 'list' => 'orders'])
</th>
<th scope="col">
<span>{{ __('Point de retrait') }}</span>&nbsp;
@include('bo.modules.sorter', ['colname' => 'magasin_id', 'list' => 'orders'])
</th>
<th scope="col">
<span>{{ __('Statut') }}</span>&nbsp;
@include('bo.modules.sorter', ['colname' => 'status_id', 'list' => 'orders'])
</th>
<th><a class="btn btn-sm btn-dark float-right mr-2" href="{{ route(Route::currentRouteName(), ['rst' => 1]) }}">Réinitialiser
le
tri</a></th>
</thead>
<tbody>
@foreach ($orders as $order)
<tr>
<td>
{{-- <a data-fancybox data-trigger="customer-info" data-type="ajax" data-src="{{ route('bo.get-customer-info', $order->customer->id) }}" data-src="#customer-info" href="javascript:;">
Infos Client
</a> --}}
<a class="ajax-tippy-cust" id="tippy-{{ $order->customer->id }}" data-custid="{{ $order->customer->id }}"
href="javascript:">Infos Client</a>
</td>
<td>{{ $order->reference }}</td>
<td>{{ \Carbon\Carbon::parse($order->date)->format('d/m/Y') }}</td>
<td>{{ number_format($order->total, 2, ',', ' ') }}€</td>
<td>
@if (!empty($order->timeslot))
{{ optional($order->timeslot->day)->format('d/m/Y') }}
{{ optional($order->timeslot->time)->format('H:i') }}
@endif
</td>
<td>
@if (!empty($order->timeslot))
{{-- <a data-fancybox data-trigger="magasin-info" data-type="ajax" data-src="{{ route('bo.get-magasin-info', $order->timeslot->magasin->id) }}" data-src="#magasin-info" href="javascript:;">
{{$order->timeslot->magasin->name}}
</a> --}}
<a class="ajax-tippy-shop" id="shop-{{ $order->timeslot->magasin->id }}"
data-shopid="{{ $order->timeslot->magasin->id }}"
href="javascript:">{{ $order->timeslot->magasin->name }}</a>
@endif
</td>
<td>{{ $order->status->label }}</td>
<td class="text-center">
{{-- L'id du status 6 est le status "Retirée", la dernière étape d'une commande --}}
<a class="btn btn-sm btn-primary" href="{{ route('bo.order-detail', $order->reference) }}"><i
class="fas fa-info"></i></a>
@if ($order->status_id < 6 && $order->status_id >= 3)
<a class="btn btn-sm btn-primary" href="{{ route('bo.change-order-status', $order->reference) }}"><i
class="fas fa-forward"></i></a>
@endif
@if ($order->status_id < 6)
<a class="btn btn-sm btn-danger" href="{{ route('bo.cancel-order', $order->reference) }}"
onclick="return confirm('Êtes-vous sûr(e) ?')"><i class="fas fa-times"></i></a>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@if ($orders instanceof \Illuminate\Pagination\LengthAwarePaginator)
{{ $orders->appends($_GET)->links() }}
@endif
@endsection
@ -86,11 +166,11 @@
var _fetchingCustInfo = false;
function loadCustInfo(element) {
if(!_fetchingCustInfo) {
if(typeof customerInfo[element.dataset.custid] === 'undefined') {
if (!_fetchingCustInfo) {
if (typeof customerInfo[element.dataset.custid] === 'undefined') {
//fetch only if we don't already have the data
_fetchingCustInfo = true;
return fetch('/bo/customer-info/'+element.dataset.custid+'/json')
return fetch('/bo/customer-info/' + element.dataset.custid + '/json')
.then(response => {
return response.json();
})
@ -106,12 +186,14 @@
return;
}
} else {
setTimeout(function () {loadCustInfo(element)}, 250);
setTimeout(function() {
loadCustInfo(element)
}, 250);
}
}
clientLinks = $('.ajax-tippy-cust');
clientLinks.each(function(index,element){
clientLinks.each(function(index, element) {
return loadCustInfo(element);
});
@ -132,10 +214,10 @@
},
onShow(instance) {
if (instance._isFetching || instance._src || instance._error) {
return;
return;
}
if(typeof tippyCustContents[instance._custID] === 'undefined') {
if (typeof tippyCustContents[instance._custID] === 'undefined') {
//carry on
} else {
instance.setContent(tippyCustContents[instance._custID]);
@ -143,22 +225,22 @@
}
instance._isFetching = true;
fetch('/bo/customer-info/'+instance._custID+'/tippy')
.then(response => {
return response.text();
})
.then(data => {
instance.setContent(data);
//save for reusability
tippyCustContents[instance._custID] = data;
})
.catch((error) => {
// Fallback if the network request failed
instance.setContent(`Request failed. ${error}`);
})
.finally(() => {
instance._isFetching = false;
});
fetch('/bo/customer-info/' + instance._custID + '/tippy')
.then(response => {
return response.text();
})
.then(data => {
instance.setContent(data);
//save for reusability
tippyCustContents[instance._custID] = data;
})
.catch((error) => {
// Fallback if the network request failed
instance.setContent(`Request failed. ${error}`);
})
.finally(() => {
instance._isFetching = false;
});
},
onHidden(instance) {
instance.setContent('<i class="fas fa-circle-notch fa-spin"></i>');
@ -185,10 +267,10 @@
},
onShow(instance) {
if (instance._isFetching || instance._src || instance._error) {
return;
return;
}
if(typeof tippyShopContents[instance._shopID] === 'undefined') {
if (typeof tippyShopContents[instance._shopID] === 'undefined') {
//carry on
} else {
instance.setContent(tippyShopContents[instance._shopID]);
@ -196,22 +278,22 @@
}
instance._isFetching = true;
fetch('/bo/magasin-info/'+instance._shopID+'/tippy')
.then(response => {
return response.text();
})
.then(data => {
instance.setContent(data);
//save for reusability
tippyShopContents[instance._shopID] = data;
})
.catch((error) => {
// Fallback if the network request failed
instance.setContent(`Request failed. ${error}`);
})
.finally(() => {
instance._isFetching = false;
});
fetch('/bo/magasin-info/' + instance._shopID + '/tippy')
.then(response => {
return response.text();
})
.then(data => {
instance.setContent(data);
//save for reusability
tippyShopContents[instance._shopID] = data;
})
.catch((error) => {
// Fallback if the network request failed
instance.setContent(`Request failed. ${error}`);
})
.finally(() => {
instance._isFetching = false;
});
},
onHidden(instance) {
instance.setContent('<i class="fas fa-circle-notch fa-spin"></i>');

View file

@ -178,5 +178,6 @@
</div>
<script src="/b-o/js/app.js"></script>
@yield('scripts')
@stack('scripts')
</body>
</html>

View file

@ -0,0 +1,9 @@
@if ($errors->has($inputName))
<div class="col-12">
<small class="text-danger">{{ implode(',', Arr::flatten(Arr::wrap($errors->get($inputName)))) }}</small>
</div>
@endif
@if (isset($helper))
<small class="form-text text-body-secondary"
@if (isset($helperId)) id="{{ $helperId }}" @endif>{{ $helper }}</small>
@endif