Message
Refactor Code Notifications
This commit is contained in:
parent
ae5b2d4105
commit
a861e75538
22 changed files with 927 additions and 77 deletions
21
app/Casts/NiceDate.php
Normal file
21
app/Casts/NiceDate.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class NiceDate implements CastsAttributes
|
||||
{
|
||||
public function get($model, $key, $value, $attributes)
|
||||
{
|
||||
$value = Carbon::parse($value);
|
||||
return $value->isToday() ?
|
||||
$value->format('H:i') : $value->format('Y/m/d H:i');
|
||||
}
|
||||
|
||||
public function set($model, $key, $value, $attributes)
|
||||
{
|
||||
return Carbon::parse($value)->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self exchange()
|
||||
* @method static self reduction()
|
||||
|
|
|
|||
|
|
@ -2,22 +2,30 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Casts\NiceDate;
|
||||
use App\Enums\NotificationType;
|
||||
use App\Http\Requests\DeleteMessagesRequest;
|
||||
use App\Http\Requests\SendMessageRequest;
|
||||
use App\Http\Requests\SurveyAnswersRequest;
|
||||
use App\Http\Requests\UpdateInfosRequest;
|
||||
use App\Models\Articles;
|
||||
use App\Models\ArticlesCategories;
|
||||
use App\Models\Customers;
|
||||
use App\Models\Message;
|
||||
use App\Models\Notifications;
|
||||
use App\Models\Reductions;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use RuntimeException;
|
||||
use Snipe\BanBuilder\CensorWords;
|
||||
|
||||
class ClubController extends Controller
|
||||
{
|
||||
public function index(ArticlesCategories $category)
|
||||
{
|
||||
$this->getNotifications();
|
||||
$reductions = Reductions::where([
|
||||
['end_date_broadcast', '>', now()],
|
||||
['status', 1]
|
||||
|
|
@ -35,19 +43,15 @@ class ClubController extends Controller
|
|||
|
||||
$nbCustomers = Customers::count();
|
||||
|
||||
$notifications = 0;
|
||||
if (Auth::guard('customer')->check()) {
|
||||
$notifications = $this->getNotifications(Auth::guard('customer')->user());
|
||||
}
|
||||
|
||||
// Cas de catégorie d'article
|
||||
$category = $category->id ?? null;
|
||||
|
||||
return view('front.club.index', compact('montantReductions', 'nbCustomers', 'articles', 'categories', 'notifications', 'category'));
|
||||
return view('front.club.index', compact('montantReductions', 'nbCustomers', 'articles', 'categories', 'category'));
|
||||
}
|
||||
|
||||
public function infos()
|
||||
{
|
||||
$this->getNotifications();
|
||||
$customer = Auth::guard('customer')->user();
|
||||
if (!$customer)
|
||||
abort(404);
|
||||
|
|
@ -60,8 +64,7 @@ class ClubController extends Controller
|
|||
$crmInfos = $crmCustomer->user;
|
||||
$birthDate = explode('-', $crmInfos->birth_date);
|
||||
|
||||
$notifications = $this->getNotifications($customer);
|
||||
return view('front.club.informations', compact('customer', 'notifications', 'crmInfos', 'birthDate'));
|
||||
return view('front.club.informations', compact('customer', 'crmInfos', 'birthDate'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -93,25 +96,17 @@ class ClubController extends Controller
|
|||
return redirect()->route('account.infos')->with('success', __("Vos informations ont bien été enregistrées."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the number of notifications the current authenticated user has
|
||||
* @param Customer $customer The user whose number of notifications we want to retrieve
|
||||
*/
|
||||
private function getNotifications()
|
||||
{
|
||||
return Auth::guard('customer')->check() ? Notifications::count() - Auth::guard('customer')->user()->notifications_read()->count() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the notifications page
|
||||
*/
|
||||
public function notifications()
|
||||
{
|
||||
$notificationsList = Notifications::orderBy('created_at', 'DESC')->with('notifiable')->get();
|
||||
$this->getNotifications();
|
||||
$notificationsIds = Notifications::pluck('id')->toArray();
|
||||
Auth::guard('customer')->user()->notifications_read()->sync($notificationsIds);
|
||||
$notifications = $this->getNotifications();
|
||||
return view('front.club.notifications', compact('notifications', 'notificationsList'));
|
||||
/** @var \App\Models\Customers */
|
||||
$customer = Auth::guard('customer')->user();
|
||||
$customer->readNotifications()->sync($notificationsIds);
|
||||
return view('front.club.notifications');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -119,10 +114,9 @@ class ClubController extends Controller
|
|||
*/
|
||||
public function cart()
|
||||
{
|
||||
$this->getNotifications();
|
||||
$products = Auth::guard('customer')->user()->products;
|
||||
$notifications = $this->getNotifications();
|
||||
|
||||
return view('front.club.cart', compact('products', 'notifications'));
|
||||
return view('front.club.cart', compact('products'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -130,10 +124,9 @@ class ClubController extends Controller
|
|||
*/
|
||||
public function favoritesRecipes()
|
||||
{
|
||||
$this->getNotifications();
|
||||
$recipes = Auth::guard('customer')->user()->recipes;
|
||||
$notifications = $this->getNotifications();
|
||||
|
||||
return view('front.club.favorites-recipes', compact('recipes', 'notifications'));
|
||||
return view('front.club.favorites-recipes', compact('recipes'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -141,12 +134,12 @@ class ClubController extends Controller
|
|||
*/
|
||||
public function reductions()
|
||||
{
|
||||
$notifications = $this->getNotifications();
|
||||
$this->getNotifications();
|
||||
// TODO: get url from MesBr class
|
||||
/** @var \App\Lib\MesBR */
|
||||
$mesBR = app('mesBr');
|
||||
$urlReductions = "https://www.mesbr.eu/?refsite=" . config('app.REF_SITE') . "&refcamp=" . config('app.REF_CAMP') . "&hash=" . Auth::guard('customer')->user()->hashcode . "&now=" . time();
|
||||
return view('front.club.reductions', compact('urlReductions', 'notifications'));
|
||||
return view('front.club.reductions', compact('urlReductions'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -156,8 +149,7 @@ class ClubController extends Controller
|
|||
*/
|
||||
public function article(Articles $publishedArticle)
|
||||
{
|
||||
$notifications = $this->getNotifications();
|
||||
|
||||
$this->getNotifications();
|
||||
// Check si le customer connecté a déjà répondu
|
||||
$alreadyAnswered = false;
|
||||
if (Auth::guard('customer')->check()) {
|
||||
|
|
@ -179,7 +171,6 @@ class ClubController extends Controller
|
|||
return view('front.club.article', compact(
|
||||
'publishedArticle',
|
||||
'categories',
|
||||
'notifications',
|
||||
'linkedArticles',
|
||||
'alreadyAnswered'
|
||||
));
|
||||
|
|
@ -207,4 +198,75 @@ class ClubController extends Controller
|
|||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
$this->getNotifications();
|
||||
/** @var \App\Models\Customers */
|
||||
$customer = Auth::guard('customer')->user();
|
||||
$conversations = $customer->conversations();
|
||||
return view('front.club.messages', compact('conversations'));
|
||||
}
|
||||
|
||||
public function sendMessage(SendMessageRequest $request)
|
||||
{
|
||||
$customer = Customers::where('username', $request->to)->firstOrFail();
|
||||
$message = new Message($request->all());
|
||||
$message->to = $customer->id;
|
||||
$message->from = Auth::guard('customer')->user()->id;
|
||||
$censor = new CensorWords();
|
||||
try {
|
||||
$censor->setDictionary(['en-us', 'en-uk', config('app.locale')]);
|
||||
} catch (RuntimeException $e) {
|
||||
$censor->setDictionary(['en-us', 'en-uk', 'fr']);
|
||||
}
|
||||
$message->message = $censor->censorString($message->message)['clean'];
|
||||
$message->saveOrFail();
|
||||
return response()->json($message->load(['toCustomer' => function ($q) {
|
||||
$q->select(['id', 'username', 'created_at']);
|
||||
}, 'fromCustomer' => function ($q) {
|
||||
$q->select(['id', 'username', 'created_at']);
|
||||
}]));
|
||||
}
|
||||
|
||||
public function deleteMessage(DeleteMessagesRequest $request)
|
||||
{
|
||||
/** @var \App\Models\Customers */
|
||||
$customer = Auth::guard('customer')->user();
|
||||
$message = Message::findOrFail($request->message);
|
||||
$conversations = (object)$customer->conversations();
|
||||
foreach ($conversations as $conversation) {
|
||||
$conversation = (object)$conversation;
|
||||
if ($conversation->id != $message->id) {
|
||||
continue;
|
||||
}
|
||||
/** @var \App\Models\Message $message */
|
||||
foreach ($conversation->messages as $message) {
|
||||
if ($message->from == $customer->id) {
|
||||
$message->hide_from = true;
|
||||
}
|
||||
if ($message->to == $customer->id) {
|
||||
$message->hide_to = true;
|
||||
}
|
||||
if ($message->hide_to && $message->hide_from) {
|
||||
$message->delete();
|
||||
} else {
|
||||
$message->saveOrFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
return response()->json();
|
||||
}
|
||||
|
||||
private function getNotifications()
|
||||
{
|
||||
if (!Auth::guard('customer')->check()) {
|
||||
return;
|
||||
}
|
||||
/** @var \App\Models\Customers */
|
||||
$customer = Auth::guard('customer')->user();
|
||||
$notifications = $customer->getAllNotifications();
|
||||
View::share('notifications', count($notifications));
|
||||
View::share('notificationsList', $notifications);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ class ContactController extends Controller
|
|||
$user = null;
|
||||
$status = $request->session()->get('status');
|
||||
$type = $type ?? ContactFormType::none();
|
||||
return view('front.contact.contact', compact('type', 'user', 'status'));
|
||||
$username = $request->username ?? '';
|
||||
return view('front.contact.contact', compact('type', 'user', 'status', 'username'));
|
||||
}
|
||||
|
||||
public function contactSubmit(ContactFormRequest $request)
|
||||
|
|
@ -53,6 +54,11 @@ class ContactController extends Controller
|
|||
return back()->withInput()->with('status', false);
|
||||
}
|
||||
|
||||
public function reportCustomer(Request $request)
|
||||
{
|
||||
return $this->contact($request, ContactFormType::abuse());
|
||||
}
|
||||
|
||||
public function proposeRecipe(Request $request)
|
||||
{
|
||||
return $this->contact($request, ContactFormType::recipe());
|
||||
|
|
|
|||
31
app/Http/Requests/DeleteMessagesRequest.php
Normal file
31
app/Http/Requests/DeleteMessagesRequest.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class DeleteMessagesRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::guard('customer')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => 'required|exists:messages,id'
|
||||
];
|
||||
}
|
||||
}
|
||||
32
app/Http/Requests/SendMessageRequest.php
Normal file
32
app/Http/Requests/SendMessageRequest.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class SendMessageRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::guard('customer')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => 'required|string|max:255|min:10',
|
||||
'to' => 'required|exists:customers,username'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,10 @@ namespace App\Models;
|
|||
|
||||
use App\Exceptions\CrmException;
|
||||
use App\Http\Resources\CustomerCrmResource;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class Customers extends Authenticatable
|
||||
{
|
||||
|
|
@ -28,7 +30,70 @@ class Customers extends Authenticatable
|
|||
return $this->belongsToMany(Products::class, 'cart', 'customer_id', 'product_id');
|
||||
}
|
||||
|
||||
public function notifications_read() {
|
||||
public function messages()
|
||||
{
|
||||
return $this->hasMany(Message::class, 'to');
|
||||
}
|
||||
|
||||
public function sentMessages()
|
||||
{
|
||||
return $this->hasMany(Message::class, 'from');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get conversations with messages sorted by time
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function conversations(): array
|
||||
{
|
||||
$dateSort = function ($a, $b) {
|
||||
return Carbon::parse($a->created_at)->timestamp < Carbon::parse($b->created_at)->timestamp;
|
||||
};
|
||||
$messageFilter = function ($item) {
|
||||
return $item->all();
|
||||
};
|
||||
$messageWith = [
|
||||
'fromCustomer' => function ($q) {
|
||||
$q->select(['id', 'username', 'created_at']);
|
||||
},
|
||||
'toCustomer' => function ($q) {
|
||||
$q->select(['id', 'username', 'created_at']);
|
||||
}
|
||||
];
|
||||
/**
|
||||
* Hack workaround https://github.com/livewire/livewire/issues/1054
|
||||
*/
|
||||
$sentM = $this->sentMessages()->with($messageWith)->get()
|
||||
->groupBy('toCustomer.username')->map($messageFilter);
|
||||
$receivedM = $this->messages()->where('hide_to', false)->with($messageWith)->get()
|
||||
->groupBy('fromCustomer.username')->map($messageFilter);
|
||||
return $receivedM->mapWithKeys(function ($messagesArray, $fromUsername) use ($sentM, $dateSort) {
|
||||
$responses = collect(\array_merge($sentM->get($fromUsername) ?? [], $messagesArray))->sort($dateSort);
|
||||
$last = $responses->first();
|
||||
return [$fromUsername => [
|
||||
'to' => $fromUsername,
|
||||
'id' => $last->id,
|
||||
'date' => $last->created_at,
|
||||
'preview' => Str::limit($last->message, 15),
|
||||
'messages' => $responses->values()->all()
|
||||
]];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
public function notifications()
|
||||
{
|
||||
return $this->belongsToMany(Notifications::class);
|
||||
}
|
||||
|
||||
public function getAllNotifications()
|
||||
{
|
||||
return Notifications::where('customer_id', $this->id)
|
||||
->orWhere('customer_id', null)->with('notifiable')->get();
|
||||
}
|
||||
|
||||
public function readNotifications()
|
||||
{
|
||||
return $this->belongsToMany(Notifications::class, 'notifications_read', 'customer_id', 'notification_id');
|
||||
}
|
||||
|
||||
|
|
@ -131,21 +196,25 @@ class Customers extends Authenticatable
|
|||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return collect(array_merge(
|
||||
parent::toArray(),
|
||||
(array)$this->apiData
|
||||
))->intersectByKeys([
|
||||
'email' => '',
|
||||
'firstname' => '',
|
||||
'lastname' => '',
|
||||
'address' => '',
|
||||
'address2' => '',
|
||||
'postcode' => '',
|
||||
'birth_date' => '',
|
||||
'city' => '',
|
||||
'country' => '',
|
||||
'opt_in' => '',
|
||||
'phone' => ''
|
||||
])->toArray();
|
||||
if ($this->crm_id) {
|
||||
return collect(array_merge(
|
||||
parent::toArray(),
|
||||
(array)$this->apiData
|
||||
))->intersectByKeys([
|
||||
'email' => '',
|
||||
'firstname' => '',
|
||||
'lastname' => '',
|
||||
'address' => '',
|
||||
'address2' => '',
|
||||
'postcode' => '',
|
||||
'birth_date' => '',
|
||||
'city' => '',
|
||||
'country' => '',
|
||||
'opt_in' => '',
|
||||
'phone' => ''
|
||||
])->toArray();
|
||||
} else {
|
||||
return parent::toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
app/Models/Message.php
Normal file
27
app/Models/Message.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Casts\NiceDate;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Message extends Model
|
||||
{
|
||||
protected $casts = [
|
||||
'created_at' => NiceDate::class,
|
||||
];
|
||||
protected $fillable = [
|
||||
'message',
|
||||
'to'
|
||||
];
|
||||
|
||||
public function toCustomer()
|
||||
{
|
||||
return $this->belongsTo(Customers::class, 'to');
|
||||
}
|
||||
|
||||
public function fromCustomer()
|
||||
{
|
||||
return $this->belongsTo(Customers::class, 'from');
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,4 @@ class Notifications extends Model
|
|||
public function notifiable() {
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function notifications_read() {
|
||||
return $this->belongsToMany(Customers::class, 'notifications_read', 'notification_id', 'customer_id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@
|
|||
"laravel/ui": "^2.1",
|
||||
"mews/purifier": "^3.3",
|
||||
"league/csv": "^9.6",
|
||||
"riverskies/laravel-mobile-detect": "^1.3"
|
||||
"riverskies/laravel-mobile-detect": "^1.3",
|
||||
"snipe/banbuilder": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
class AddCustomerIdToNotificationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('notifications', function (Blueprint $table) {
|
||||
$table->foreignId('customer_id')->nullable()->after('content');
|
||||
$table->foreign('customer_id')->references('id')->on('customers')->cascadeOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('notifications', function (Blueprint $table) {
|
||||
$table->dropForeign(['customer_id']);
|
||||
$table->dropColumn(['customer_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
class CreateMessagesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('messages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->string('message', 255);
|
||||
$table->boolean('hide_from')->default(false);
|
||||
$table->boolean('hide_to')->default(false);
|
||||
|
||||
$table->foreignId('from')->nullable();
|
||||
$table->foreign('from')->references('id')->on('customers')->cascadeOnDelete();
|
||||
$table->foreignId('to')->nullable();
|
||||
$table->foreign('to')->references('id')->on('customers')->cascadeOnDelete();
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('messages');
|
||||
}
|
||||
}
|
||||
187
resources/js/components/fo/mon-compte/messages.vue
Normal file
187
resources/js/components/fo/mon-compte/messages.vue
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<template>
|
||||
<div class="message-bloc clearfix">
|
||||
<aside class="aside-bloc">
|
||||
<div class="input-recherche input-group" data-children-count="1">
|
||||
<input ref="filterInput" @keyup="filterConversations($event)" type="text" class="field-text" :placeholder="__('Rechercher...')">
|
||||
<span @click="clearFilter($event)" class="addon-btn"><i class="icon-croix"></i></span>
|
||||
<button class="btn-submit"><i class="icon-loupe"></i></button>
|
||||
</div>
|
||||
<div class="scroll-bloc">
|
||||
<div class="inner-wrap">
|
||||
<ul class="list-contact">
|
||||
<li class="msg-non-lu" v-for="(conversation, name) of conversations" v-bind:key="name" @click="showConversation(conversation, $event)">
|
||||
<a href="#" class="popup-trigger clearfix">
|
||||
<i class="icon-faq-contact"></i>
|
||||
<div class="wrap-text">
|
||||
<h3>
|
||||
<span class="auteur">{{ conversation.to }}</span>
|
||||
<span class="date-publication">{{ conversation.date }}</span>
|
||||
</h3>
|
||||
<p class="msg-preview">{{ conversation.preview }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li v-if="!Object.keys(conversations).length">
|
||||
<a href="#" class="popup-trigger clearfix" v-on:click.prevent>
|
||||
<i class="icon-faq-contact"></i>
|
||||
<div class="wrap-text">
|
||||
<h3>
|
||||
<span class="auteur">{{ __('Pas de message') }}</span>
|
||||
</h3>
|
||||
<p class="msg-preview"></p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="main-message hidden-xs">
|
||||
<div class="scroll-bloc">
|
||||
<div class="inner-wrap">
|
||||
<ul class="list-message" data-simplebar>
|
||||
<li class="msg-item" v-for="message of activeConversation.messages" v-bind:key="message.id">
|
||||
<h3>
|
||||
<span class="auteur">{{ message.from_customer.username }}</span>
|
||||
<span class="date-publication">{{ message.created_at }}</span>
|
||||
</h3>
|
||||
<div class="msg-txt">
|
||||
<p>{{ message.message }}</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="form" class="reponse-bloc display-none">
|
||||
<div ref="formErrors" class="error-msg display-none"><p></p></div>
|
||||
<fieldset data-children-count="1">
|
||||
<textarea v-model="message" cols="20" rows="10" :placeholder="__('Votre message...')"></textarea>
|
||||
</fieldset>
|
||||
<div class="bottom-bloc">
|
||||
<p class="link">
|
||||
<a @click="reportAbuse($event)" href="#" :title="__('Signaler un abus')">{{ __('Signaler un abus') }}</a>
|
||||
|
|
||||
<a @click="deleteConversation($event)" class="message-delete-btn" href="#" :title="__('Supprimer cette conversation')">{{ __('Supprimer cette conversation') }}</a>
|
||||
</p>
|
||||
<i ref="loading" class="fas fa-spinner fa-pulse display-none"></i>
|
||||
<button ref="submit" class="btn btn-red btn-arronded-20 reply-btn" :title="__('Répondre')" @click="sendMessage">{{ __('Répondre') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
this.conversations = JSON.parse(this.dbconversations);
|
||||
this.orig_conversations = this.conversations;
|
||||
},
|
||||
props: [
|
||||
'dbconversations'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
conversations: {},
|
||||
orig_conversations: {},
|
||||
activeConversation: {},
|
||||
message: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filterConversations(e) {
|
||||
if(!e.currentTarget.value.length) {
|
||||
this.$set(this, 'conversations', this.orig_conversations);
|
||||
return;
|
||||
}
|
||||
let out = {};
|
||||
for(let key in this.conversations) {
|
||||
let conversation = this.conversations[key];
|
||||
if(conversation.to.toLowerCase().indexOf(e.currentTarget.value) !== -1) {
|
||||
out[key] = conversation;
|
||||
continue;
|
||||
}
|
||||
if(conversation.preview.toLowerCase().indexOf(e.currentTarget.value) !== -1) {
|
||||
out[key] = conversation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.$set(this, 'conversations', out);
|
||||
},
|
||||
clearFilter(e) {
|
||||
e.preventDefault();
|
||||
this.$set(this, 'conversations', this.orig_conversations);
|
||||
this.$refs.filterInput.value ="";
|
||||
},
|
||||
reportAbuse(e) {
|
||||
e.preventDefault();
|
||||
if(!this.activeConversation.id) {
|
||||
return;
|
||||
}
|
||||
window.location.href = this.route('reportCustomer') + '?username='+this.activeConversation.to;
|
||||
},
|
||||
showConversation(conversation, e) {
|
||||
e.preventDefault();
|
||||
this.$refs.form.classList.remove('display-none');
|
||||
for(let li of document.querySelectorAll('.list-contact > li')) {
|
||||
li.classList.remove('active');
|
||||
}
|
||||
e.currentTarget.classList.add('active');
|
||||
this.activeConversation = conversation;
|
||||
},
|
||||
setMessage(message) {
|
||||
this.activeConversation.messages.unshift(message);
|
||||
this.$set(this, 'message', '');
|
||||
},
|
||||
deleteConversation(e) {
|
||||
e.preventDefault();
|
||||
axios.post(this.route('deleteMessage'), { message: this.activeConversation.id })
|
||||
.catch((error) => {
|
||||
console.error('Error', error.message);
|
||||
})
|
||||
.then(() => {
|
||||
delete this.conversations[this.activeConversation.to];
|
||||
delete this.orig_conversations[this.activeConversation.to];
|
||||
this.$set(this, 'activeConversation', {});
|
||||
});
|
||||
},
|
||||
sendMessage(e) {
|
||||
e.preventDefault();
|
||||
this.$refs.submit.disabled = true;
|
||||
this.$refs.loading.classList.remove('display-none');
|
||||
axios.post(this.route('sendMessage'), { message: this.message, to: this.activeConversation.to })
|
||||
.then((response) => {
|
||||
this.$refs.submit.disabled = false;
|
||||
this.$refs.formErrors.classList.add('display-none');
|
||||
this.setMessage(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 422:
|
||||
this.$refs.formErrors.classList.remove('display-none');
|
||||
this.$refs.formErrors.childNodes[0].innerText = _.flatten(_.map(error.response.data.errors, (val, key) => {
|
||||
return '\n' + val.join('\n');
|
||||
}));
|
||||
break;
|
||||
default:
|
||||
this.$refs.formErrors.classList.remove('display-none');
|
||||
this.$refs.formErrors.childNodes[0].innerText = this.__('Une erreur est survenue');
|
||||
console.error(this.__('Une erreur est survenue'));
|
||||
alert(this.__('Une erreur est survenue'));
|
||||
document.location.reload();
|
||||
}
|
||||
} else if (error.request) {
|
||||
console.error(error.request);
|
||||
} else {
|
||||
console.error('Error', error.message);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.$refs.submit.disabled = false;
|
||||
this.$refs.loading.classList.add('display-none');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -33,5 +33,7 @@
|
|||
"send": "Envoyer",
|
||||
"civilty": "Civilité",
|
||||
"message_contact_send": "Votre message a été envoyé avec succès.",
|
||||
"message_contact_failed": "Une erreur est survenue durant l'envoi de votre message. Veuillez réessayer ultèrieurement."
|
||||
"message_contact_failed": "Une erreur est survenue durant l'envoi de votre message. Veuillez réessayer ultèrieurement.",
|
||||
"report_abuse": "Signaler un abus",
|
||||
"report_abuse_message" : "Je souhaite signaler le message de :username car cet utilisateur ne respecte pas les conditions d'utilisation du Club des Gaulois.\n\nCordialement"
|
||||
}
|
||||
|
|
|
|||
2
resources/sass/front/pages/_contact.scss
vendored
2
resources/sass/front/pages/_contact.scss
vendored
|
|
@ -1,5 +1,5 @@
|
|||
.content.contact {
|
||||
max-width: inherit;
|
||||
max-width: inherit !important;
|
||||
|
||||
aside {
|
||||
float: left;
|
||||
|
|
|
|||
2
resources/sass/front/pages/_error.scss
vendored
2
resources/sass/front/pages/_error.scss
vendored
|
|
@ -1,5 +1,5 @@
|
|||
.content.error {
|
||||
max-width: inherit;
|
||||
max-width: inherit !important;
|
||||
background-image: url('~@/images/commun/404.jpg');
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
|
|
|
|||
283
resources/sass/front/pages/club/messages.scss
vendored
Normal file
283
resources/sass/front/pages/club/messages.scss
vendored
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
.content.messages {
|
||||
.message-bloc {
|
||||
border: 1px solid #dfd2c7;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
@include min-width($tablet) {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
.aside-bloc {
|
||||
background-color: #fbf8f5;
|
||||
border-right: 1px solid #dfd2c7;
|
||||
width: 100%;
|
||||
@include min-width($tablet) {
|
||||
height: inherit;
|
||||
//-webkit-flex-basis: 295px;
|
||||
//flex-basis: 295px;
|
||||
width: 295px;
|
||||
}
|
||||
.scroll-bloc {
|
||||
height: 450px;
|
||||
@include min-width($tablet) {
|
||||
width: 295px !important;
|
||||
}
|
||||
}
|
||||
.list-contact {
|
||||
li {
|
||||
border-top: 1px solid #dfd2c7;
|
||||
&.msg-non-lu {
|
||||
.icon-faq-contact {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
&.active, &:hover {
|
||||
background-color: #1e5ba1;
|
||||
color: #fff;
|
||||
h3 {
|
||||
color: #fff;
|
||||
.date-publication { color: #fff; }
|
||||
}
|
||||
p { color: #fff; }
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
padding: 20px 18px;
|
||||
width: 100%;
|
||||
@include min-width($tablet) {
|
||||
padding: 20px 13px;
|
||||
}
|
||||
&.active, &:hover {
|
||||
background-color: #1e5ba1;
|
||||
color: #fff;
|
||||
h3 {
|
||||
color: #fff;
|
||||
.date-publication { color: #fff; }
|
||||
}
|
||||
p { color: #fff; }
|
||||
}
|
||||
}
|
||||
.icon-faq-contact {
|
||||
color: #fab818;
|
||||
float: left;
|
||||
font-size: 19px;
|
||||
margin-right: 15px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.wrap-text {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
display: flex;
|
||||
color: #1e5ba1;
|
||||
font-family: 'Catamaran-Bold';
|
||||
font-size: 18px;
|
||||
line-height: 100%;
|
||||
.date-publication {
|
||||
color: #ab9d8e;
|
||||
font-size: 13px;
|
||||
margin-left: auto;
|
||||
}
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
.auteur {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
p {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
.input-recherche {
|
||||
background: #fff;
|
||||
border: 1px solid #dfd2c7;
|
||||
display: flex;
|
||||
height: 50px;
|
||||
line-height: 48px;
|
||||
margin: 24px;
|
||||
padding: 10px 14px;
|
||||
width: auto;
|
||||
input {
|
||||
background: inherit;
|
||||
border: none;
|
||||
color: #999595;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.field-text {
|
||||
display: table-cell;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.btn-submit {
|
||||
cursor:pointer;
|
||||
background: inherit;
|
||||
border: none;
|
||||
color: #bcafa1;
|
||||
display: table-cell;
|
||||
height: 26px;
|
||||
vertical-align: middle;
|
||||
padding: 0 8px;
|
||||
width: 26px;
|
||||
flex-basis: 26px;
|
||||
i {
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
.addon-btn {
|
||||
cursor: pointer;
|
||||
line-height: 1.2;
|
||||
padding: 8px;
|
||||
vertical-align: middle;
|
||||
i {
|
||||
color: #e0d2c5;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-message {
|
||||
background-color: #f8f2ed;
|
||||
height: inherit;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.scroll-bloc {
|
||||
height: 340px;
|
||||
overflow: auto;
|
||||
}
|
||||
.inner-wrap {
|
||||
padding: 25px 8px 25px 18px;
|
||||
@include min-width($tablet) {
|
||||
padding: 25px 20px 25px 30px;
|
||||
}
|
||||
}
|
||||
.list-message {
|
||||
.msg-item {
|
||||
margin-bottom: 25px;
|
||||
&:last-child { margin-bottom: 0; }
|
||||
@include min-width($tablet) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
color: #1e5ba1;
|
||||
display: flex;
|
||||
font-family: 'Catamaran-Bold';
|
||||
font-size: 18px;
|
||||
line-height: 100%;
|
||||
margin-bottom: 14px;
|
||||
@include min-width($tablet) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
.date-publication {
|
||||
color: #ab9d8e;
|
||||
font-size: 15px;
|
||||
margin-left: auto;
|
||||
@include min-width($tablet) {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.msg-txt {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
padding: 20px;
|
||||
@include min-width($tablet) {
|
||||
padding: 20px 25px;
|
||||
}
|
||||
}
|
||||
p {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
.reponse-bloc {
|
||||
background-color: #1e5ba1;
|
||||
border-radius: 0 0 3px 0;
|
||||
//bottom: 0;
|
||||
//left: 0;
|
||||
margin-top: 20px;
|
||||
padding: 30px;
|
||||
//position: absolute;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
fieldset {
|
||||
display: block;
|
||||
}
|
||||
textarea {
|
||||
color: #999595;
|
||||
font-family: 'Catamaran-Regular';
|
||||
font-size: 1.5em;
|
||||
height: 100px;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
resize:none;
|
||||
&::-webkit-input-placeholder { color: #999595; }
|
||||
&::-moz-placeholder { color: #999595; }
|
||||
&:-ms-input-placeholder { color: #999595; }
|
||||
&:-moz-placeholder { color: #999595; }
|
||||
@include min-width($tablet) {
|
||||
height: 78px;
|
||||
}
|
||||
}
|
||||
p {
|
||||
color: #fff;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
.bottom-bloc {
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
@include min-width($tablet) {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
svg {
|
||||
font-size: 2em;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
.link {
|
||||
color: #f9b719;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
@include min-width($tablet) {
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
a {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
text-decoration: underline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
text-transform: uppercase;
|
||||
&:disabled {
|
||||
background-color: #200000;
|
||||
}
|
||||
@include min-width($tablet) {
|
||||
margin-left: auto;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
resources/sass/main.scss
vendored
1
resources/sass/main.scss
vendored
|
|
@ -62,5 +62,6 @@
|
|||
@import "front/pages/club/index";
|
||||
@import "front/pages/club/content";
|
||||
@import "front/pages/club/article";
|
||||
@import "front/pages/club/messages";
|
||||
@import "front/pages/club/boutique/index";
|
||||
@import "front/pages/club/boutique/validated";
|
||||
|
|
|
|||
48
resources/views/front/club/messages.blade.php
Normal file
48
resources/views/front/club/messages.blade.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
@extends('layouts.app')
|
||||
@section('title', 'Club des Gaulois mes notifications')
|
||||
@section('description', "Soyez averti de nouvelles activités sur le Club des Gaulois via des alertes : forum, message, nouveautés, sondage")
|
||||
|
||||
@section('sub_header')
|
||||
<div class="sub_header sub_header_club">
|
||||
<div class="content">
|
||||
@include('front.club.modules.customerToolbar')
|
||||
<div class="title-club-account">
|
||||
<p>
|
||||
<img src="{{ asset('assets/images/club/logo-leclub.png') }}" alt="{{ __('Le Club des Gaulois - Le Gaulois') }}">
|
||||
{{ __('Mes messages') }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- TODO : GESTION IMG SI MOBILE -->
|
||||
<img src="{{ asset('assets/images/club/bandeau-club-dsktp.png') }}" alt="{{ __('Le club des Gaulois - Le Gaulois') }}" class="img-club">
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
@include('front.club.modules.quicklink', ['top' => true])
|
||||
<section class="content-page-club">
|
||||
<div class="messages content">
|
||||
<div class="inner-size">
|
||||
<h1>
|
||||
<i class="icon-messages"></i>
|
||||
<span>{{ __('Mes messages') }}</span>
|
||||
</h1>
|
||||
<h2 class="notif-sub-title">{{ __('Vos messages facilement accessibles grâce à la barre de recherche.') }}</h2>
|
||||
<messages dbconversations='@json($conversations)'></messages>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@push('scriptsConstants')
|
||||
<script>
|
||||
window._locale = '{{ app()->getLocale() }}';
|
||||
window._translations = @json(cache(sprintf('translations.%s', app()->getLocale())));
|
||||
window._asset = '{{ asset('') }}';
|
||||
window._routes = {
|
||||
'reportCustomer': '{{ route('account.reportCustomer') }}',
|
||||
'sendMessage': '{{ route('account.sendMessage') }}',
|
||||
'deleteMessage': '{{ route('account.deleteMessage') }}'
|
||||
};
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
@else
|
||||
<h4>{{ __('question_concern')}} :</h4>
|
||||
@endif
|
||||
@if($type->equals(ContactFormType::complain()) or $type->equals(ContactFormType::recipe()))
|
||||
@if($type->equals(ContactFormType::complain()) or $type->equals(ContactFormType::recipe()) or $type->equals(ContactFormType::abuse()))
|
||||
<input type="text" class="display-none" name="type" value="{{ $type->value }}" readonly />
|
||||
@else
|
||||
<div class="styled-select">
|
||||
|
|
@ -123,7 +123,9 @@
|
|||
__('Temps de préparation'),
|
||||
__('Temps de cuisson'),
|
||||
__('Difficulté')
|
||||
) !!}@endif</textarea>
|
||||
) !!}@endif @if($type->equals(ContactFormType::abuse())){{
|
||||
__('report_abuse_message', ['username' => $username ?? ''])
|
||||
}}@endif</textarea>
|
||||
@if($errors->default->has('message'))<small class="text-danger">{{ implode('<br>', $errors->default->get('message')) }}</small>@endif
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<a href="{{ route('home') }}" class="btn btn-red btn-arronded-20 text-uppercase">{{ __('Retour à l\'accueil') }}</a>
|
||||
</div>
|
||||
@else
|
||||
@if(!$type->equals(ContactFormType::complain()) and !$type->equals(ContactFormType::recipe()))
|
||||
@if(!$type->equals(ContactFormType::complain()) and !$type->equals(ContactFormType::recipe()) and !$type->equals(ContactFormType::abuse()))
|
||||
<p class="text-white">{{ __('Si vous désirez plutôt envoyer une réclamation utilisez ce lien') }}<br>
|
||||
<a href="{{ route('product-request') }}" class="btn btn-red btn-arronded-20 text-uppercase">{{ __('Envoyer une réclamation') }}</a></p>
|
||||
<br>
|
||||
|
|
|
|||
|
|
@ -234,19 +234,22 @@ Route::prefix('/le-club-des-gaulois')
|
|||
});
|
||||
|
||||
Route::prefix('/mon-compte')
|
||||
->name('account.')
|
||||
->middleware('auth:customer')
|
||||
->group(function () {
|
||||
Route::get('/mes-informations', 'ClubController@infos')->name('infos');
|
||||
Route::post('/mes-informations', 'ClubController@updateInfos')->name('update-infos');
|
||||
Route::post('/mes-informations/change-password', 'CustomerController@changePasswordWhenAuthenticated')->name('change-password');
|
||||
Route::get('/notifications', 'ClubController@notifications')->name('notifications');
|
||||
Route::get('/messages', function () {
|
||||
die('Mes messages');
|
||||
})->name('messages');
|
||||
Route::get('/recettes-favorites', 'ClubController@favoritesRecipes')->name('favs-recipes');
|
||||
Route::post('/recettes-favorites/{recipe}/set-status/{status}', 'CustomerController@setFavoriteRecipe')
|
||||
->name('set-favs-recipes');
|
||||
Route::get('/liste-de-courses', 'ClubController@cart')->name('cart');
|
||||
Route::post('/liste-de-courses/{product}/{status}', 'CustomerController@setItemInCart')->name('set-cart');
|
||||
});
|
||||
->name('account.')
|
||||
->middleware('auth:customer')
|
||||
->group(function () {
|
||||
Route::redirect('/', '/mon-compte/mes-informations');
|
||||
Route::get('/mes-informations', 'ClubController@infos')->name('infos');
|
||||
Route::post('/mes-informations', 'ClubController@updateInfos')->name('update-infos');
|
||||
Route::post('/mes-informations/change-password', 'CustomerController@changePasswordWhenAuthenticated')
|
||||
->name('change-password');
|
||||
Route::get('/notifications', 'ClubController@notifications')->name('notifications');
|
||||
Route::get('/messages', 'ClubController@messages')->name('messages');
|
||||
Route::post('/messages/send', 'ClubController@sendMessage')->name('sendMessage');
|
||||
Route::post('/messages/delete', 'ClubController@deleteMessage')->name('deleteMessage');
|
||||
Route::get('/messages/report', 'ContactController@reportCustomer')->name('reportCustomer');
|
||||
Route::get('/recettes-favorites', 'ClubController@favoritesRecipes')->name('favs-recipes');
|
||||
Route::post('/recettes-favorites/{recipe}/set-status/{status}', 'CustomerController@setFavoriteRecipe')
|
||||
->name('set-favs-recipes');
|
||||
Route::get('/liste-de-courses', 'ClubController@cart')->name('cart');
|
||||
Route::post('/liste-de-courses/{product}/{status}', 'CustomerController@setItemInCart')->name('set-cart');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue