diff --git a/app/Http/Controllers/Bo/OrdersController.php b/app/Http/Controllers/Bo/OrdersController.php index 9d17106..757f90f 100644 --- a/app/Http/Controllers/Bo/OrdersController.php +++ b/app/Http/Controllers/Bo/OrdersController.php @@ -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; } /** diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index ce1176d..0964a0d 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -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; + } + } } diff --git a/app/Http/Requests/SortOrders.php b/app/Http/Requests/SortOrders.php index 7ede937..2f24186 100644 --- a/app/Http/Requests/SortOrders.php +++ b/app/Http/Requests/SortOrders.php @@ -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'), + ]; } } diff --git a/resources/js/app.js b/resources/js/app.js index df4a97c..8ee0337 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,6 +1,8 @@ require('./bootstrap'); require('@fancyapps/fancybox'); -import Vue from 'vue' +import Vue from 'vue'; + +import "./orderFilters"; // Vuex // import Vuex from 'vuex'; diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index b7f769c..ea9fc1c 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -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); diff --git a/resources/js/orderFilters.js b/resources/js/orderFilters.js new file mode 100644 index 0000000..ccd1812 --- /dev/null +++ b/resources/js/orderFilters.js @@ -0,0 +1,30 @@ +document.addEventListener("DOMContentLoaded", function () { + const tagListToSwitchDisplay = ["date-order", "date-retrait"]; + + tagListToSwitchDisplay.forEach(function (tag) { + /** @type {NodeListOf} */ + 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); + }); +}); diff --git a/resources/sass/_classes.scss b/resources/sass/_classes.scss index 703c7d2..e175ff6 100644 --- a/resources/sass/_classes.scss +++ b/resources/sass/_classes.scss @@ -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; +} diff --git a/resources/sass/_popup.scss b/resources/sass/_popup.scss index b2aa29f..f07e629 100644 --- a/resources/sass/_popup.scss +++ b/resources/sass/_popup.scss @@ -32,7 +32,7 @@ //tooltips - .tooltip { + .tooltip:not(.bs-tooltip-auto) { background: #333; color: white; font-weight: bold; diff --git a/resources/views/bo/modules/search-bar-orders.blade.php b/resources/views/bo/modules/search-bar-orders.blade.php new file mode 100644 index 0000000..e2c0447 --- /dev/null +++ b/resources/views/bo/modules/search-bar-orders.blade.php @@ -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 +
+
+
+ + @if (request()->sort_col) + + @endif + @if (request()->sort_way) + + @endif + @if (request()->rangefilter) + + @endif + @if (request()->group) + + @endif + + + +
+
+
diff --git a/resources/views/bo/orders/index.blade.php b/resources/views/bo/orders/index.blade.php index 2d09e9b..0c63654 100644 --- a/resources/views/bo/orders/index.blade.php +++ b/resources/views/bo/orders/index.blade.php @@ -1,77 +1,157 @@ @extends('layouts.bo-layout') @section('content') -
-

Commandes @if (isset($today)) à retirer aujourd'hui @endif

+
+

Commandes @if (isset($today)) + à retirer aujourd'hui + @endif +

@if (session('success')) {{ session('success') }} @endif
- - - - - - - - - - - - - @foreach ($orders as $order) - - - - - - - - - - - @endforeach - -
Client  - @include('bo.modules.sorter', ['colname' => 'customer_id', 'list' => 'orders']) - Référence - Date  - @include('bo.modules.sorter', ['colname' => 'date', 'list' => 'orders']) - Total en €Date de retrait  - @include('bo.modules.sorter', ['colname' => 'date_retrait', 'list' => 'orders']) - - Point de retrait  - @include('bo.modules.sorter', ['colname' => 'magasin_id', 'list' => 'orders']) - - Statut  - @include('bo.modules.sorter', ['colname' => 'status_id', 'list' => 'orders']) - Réinitialiser le tri
- {{-- - Infos Client - --}} - Infos Client - {{$order->reference}}{{\Carbon\Carbon::parse($order->date)->format('d/m/Y')}}{{number_format($order->total, 2, ',', ' ')}}€ - @if (!empty($order->timeslot)) - {{$order->timeslot->day}} {{$order->timeslot->time}} - @endif - - @if (!empty($order->timeslot)) - {{-- - {{$order->timeslot->magasin->name}} - --}} - {{$order->timeslot->magasin->name}} - @endif - {{$order->status->label}} - {{-- L'id du status 6 est le status "Retirée", la dernière étape d'une commande --}} - - @if ($order->status_id < 6 && $order->status_id >=3 ) - - @endif - @if ($order->status_id < 6) - - @endif -
- @if($orders instanceof \Illuminate\Pagination\LengthAwarePaginator ) +
+ @include('bo.modules.search-bar-orders') + @if (request()->routeIs('bo.orders')) +
+
+
+ {{ __('Date de commande') }} +
+
+ input('date-order-switch')) ? true : false) checked @endif> + +
+
+ + + + +
+ @include('modules.input-error', ['inputName' => 'date-order-start']) + @include('modules.input-error', ['inputName' => 'date-order-end']) +
+
+
+ {{ __('Date de retrait') }} +
+
+ input('date-retrait-switch')) ? true : false) checked @endif> + +
+
+ + + + +
+ @include('modules.input-error', ['inputName' => 'date-retrait-start']) + @include('modules.input-error', ['inputName' => 'date-retrait-end']) +
+
+ + @push('scripts') + + @endpush + @endif +
+
+
+ {{ __('Obligatoire') }} +
+
+
+ + + + + + + + + + + + + @foreach ($orders as $order) + + + + + + + + + + + @endforeach + +
{{ __('Client') }}  + @include('bo.modules.sorter', ['colname' => 'customer_id', 'list' => 'orders']) + {{ __('Référence') }} + {{ __('Date commande') }}  + @include('bo.modules.sorter', ['colname' => 'date', 'list' => 'orders']) + {{ __('Total en €') }}{{ __('Date de retrait') }}  + @include('bo.modules.sorter', ['colname' => 'date_retrait', 'list' => 'orders']) + + {{ __('Point de retrait') }}  + @include('bo.modules.sorter', ['colname' => 'magasin_id', 'list' => 'orders']) + + {{ __('Statut') }}  + @include('bo.modules.sorter', ['colname' => 'status_id', 'list' => 'orders']) + Réinitialiser + le + tri
+ {{-- + Infos Client + --}} + Infos Client + {{ $order->reference }}{{ \Carbon\Carbon::parse($order->date)->format('d/m/Y') }}{{ number_format($order->total, 2, ',', ' ') }}€ + @if (!empty($order->timeslot)) + {{ optional($order->timeslot->day)->format('d/m/Y') }} + {{ optional($order->timeslot->time)->format('H:i') }} + @endif + + @if (!empty($order->timeslot)) + {{-- + {{$order->timeslot->magasin->name}} + --}} + {{ $order->timeslot->magasin->name }} + @endif + {{ $order->status->label }} + {{-- L'id du status 6 est le status "Retirée", la dernière étape d'une commande --}} + + @if ($order->status_id < 6 && $order->status_id >= 3) + + @endif + @if ($order->status_id < 6) + + @endif +
+
+ @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(''); @@ -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(''); diff --git a/resources/views/layouts/bo-layout.blade.php b/resources/views/layouts/bo-layout.blade.php index 842b512..e720962 100644 --- a/resources/views/layouts/bo-layout.blade.php +++ b/resources/views/layouts/bo-layout.blade.php @@ -178,5 +178,6 @@
@yield('scripts') + @stack('scripts') diff --git a/resources/views/modules/input-error.blade.php b/resources/views/modules/input-error.blade.php new file mode 100644 index 0000000..8f09499 --- /dev/null +++ b/resources/views/modules/input-error.blade.php @@ -0,0 +1,9 @@ +@if ($errors->has($inputName)) +
+ {{ implode(',', Arr::flatten(Arr::wrap($errors->get($inputName)))) }} +
+@endif +@if (isset($helper)) + {{ $helper }} +@endif