Merge branch 'club' into le-gaulois-2024
This commit is contained in:
commit
af81e6919f
15 changed files with 559 additions and 605 deletions
|
|
@ -16,6 +16,7 @@ use Illuminate\Contracts\Database\Eloquent\Builder;
|
|||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Lottery;
|
||||
|
||||
class MessageController extends Controller
|
||||
{
|
||||
|
|
@ -28,19 +29,6 @@ class MessageController extends Controller
|
|||
{
|
||||
/** @var \App\Models\Customer */
|
||||
$customer = Auth::guard('club')->user();
|
||||
$conversations = $customer->conversations();
|
||||
$ids = collect($conversations)->pluck('to_id');
|
||||
$block_list = BlockList::query()
|
||||
->whereHas('customer', fn (Builder $q) => $q->where('id', $customer->id))
|
||||
->whereIn('blocked_id', $ids)->get();
|
||||
|
||||
// * Sort In reverse order messages
|
||||
$conversations = collect($conversations)->map(function (array $conversation) {
|
||||
$conversation['messages'] = collect($conversation['messages'])
|
||||
->sort(fn (Message $a, Message $b) => $a->created_at->timestamp < $b->created_at->timestamp)
|
||||
->values()->all();
|
||||
return $conversation;
|
||||
})->all();
|
||||
|
||||
$unread_messages_count = Message::query()
|
||||
->whereHas('toCustomer', fn (Builder $q) => $q->where('id', $customer->id))
|
||||
|
|
@ -48,12 +36,43 @@ class MessageController extends Controller
|
|||
->count();
|
||||
|
||||
return view('club.pages.messages.index', compact(
|
||||
'conversations',
|
||||
'block_list',
|
||||
'unread_messages_count'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch conversations and block list
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function conversations(): JsonResponse
|
||||
{
|
||||
/** How many message to keey in a conversation */
|
||||
$messagesToKeepInConversations = 25;
|
||||
/** @var \App\Models\Customer */
|
||||
$customer = Auth::guard('club')->user();
|
||||
$conversations = $customer->conversations();
|
||||
$ids = collect($conversations)->pluck('to_id');
|
||||
$block_list = BlockList::query()
|
||||
->whereHas('customer', fn (Builder $q) => $q->where('id', $customer->id))
|
||||
->whereIn('blocked_id', $ids)->get();
|
||||
|
||||
// * Sort In reverse order messages
|
||||
$conversations = collect($conversations)
|
||||
->map(function (array $conversation) use ($messagesToKeepInConversations) {
|
||||
$sortFn = fn (Message $a, Message $b) => $a->created_at->timestamp < $b->created_at->timestamp;
|
||||
// * Limit messages per conversations
|
||||
Lottery::odds(1, 20)
|
||||
->winner(fn () => collect($conversation['messages'])
|
||||
// @phpstan-ignore-next-line
|
||||
->sort($sortFn)->splice($messagesToKeepInConversations)
|
||||
->each(fn (Message $message) => $message->delete()))
|
||||
->choose();
|
||||
return $conversation;
|
||||
})->all();
|
||||
return response()->json(compact('conversations', 'block_list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to a user
|
||||
*
|
||||
|
|
@ -75,7 +94,7 @@ class MessageController extends Controller
|
|||
NotificationType::message,
|
||||
route('club.messages.index', ['m' => $message->id]),
|
||||
$message,
|
||||
$customer
|
||||
$toCustomer
|
||||
));
|
||||
return response()->json($message->load(['toCustomer' => function (Builder $q) {
|
||||
$q->select(['id', 'username', 'created_at']);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class SendMessageRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => 'required|string|max:255|min:10',
|
||||
'message' => 'required|string|max:255|min:5',
|
||||
'to' => [
|
||||
'required',
|
||||
Rule::exists('customers', 'username'),
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class Customer extends Authenticatable implements MustVerifyEmail
|
|||
*/
|
||||
public function conversations(): array
|
||||
{
|
||||
$dateSort = fn (Message $a, Message $b) => $a->created_at->timestamp < $b->created_at->timestamp;
|
||||
$dateSort = fn (Message $a, Message $b) => $a->created_at->timestamp > $b->created_at->timestamp;
|
||||
$messageFilter = fn (Collection $item) => $item->all();
|
||||
$messageWith = [
|
||||
'fromCustomer' => fn (Builder $q) => $q->select(['id', 'username', 'created_at']),
|
||||
|
|
@ -142,6 +142,7 @@ class Customer extends Authenticatable implements MustVerifyEmail
|
|||
->groupBy('fromCustomer.username')->map($messageFilter)->toBase();
|
||||
|
||||
$output = $receivedM->mapWithKeys(function (array $messagesArray, string $fromUsername) use (&$sentM, $dateSort) {
|
||||
// @phpstan-ignore-next-line
|
||||
$responses = collect(\array_merge($sentM->pull($fromUsername) ?? [], $messagesArray))->sort($dateSort);
|
||||
$last = $responses->last();
|
||||
return [$fromUsername => collect([
|
||||
|
|
|
|||
103
package-lock.json
generated
103
package-lock.json
generated
|
|
@ -20,6 +20,7 @@
|
|||
"@types/bootstrap": "^5.2.7",
|
||||
"@types/node": "^20.8.2",
|
||||
"@types/toastify-js": "^1.12.1",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"@types/vue-select": "^3.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.36.2",
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
"resolve-url-loader": "^5.0.0",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"sass": "latest",
|
||||
"simplebar-vue": "^2.3.5",
|
||||
"slugify": "^1.6.6",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order",
|
||||
|
|
@ -57,6 +59,7 @@
|
|||
"ts-loader": "^9.3.1",
|
||||
"typescript": ">=3.3.1 <5.2.0",
|
||||
"typescript-eslint": "latest",
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"vite": "^4.5.1",
|
||||
"vite-plugin-babel": "latest",
|
||||
"vite-plugin-checker": "latest",
|
||||
|
|
@ -1246,6 +1249,21 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz",
|
||||
"integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash-es": {
|
||||
"version": "4.17.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/minimatch": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
|
||||
|
|
@ -1285,6 +1303,12 @@
|
|||
"integrity": "sha512-9RjLlbAHMSaae/KZNHGv19VG4gcLIm3YjvacCXBtfMfYn26h76YP5oxXI8k26q4iKXCB9LNfv18lsoS0JnFPTg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/ua-parser-js": {
|
||||
"version": "0.7.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.39.tgz",
|
||||
"integrity": "sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/vue-select": {
|
||||
"version": "3.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/vue-select/-/vue-select-3.16.8.tgz",
|
||||
|
|
@ -5272,6 +5296,12 @@
|
|||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
|
|
@ -6720,6 +6750,56 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simplebar-core": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/simplebar-core/-/simplebar-core-1.2.6.tgz",
|
||||
"integrity": "sha512-H5NYU+O+uvqOH5VXw3+lgoc1vTI6jL8LOZJsw4xgRpV7uIPjRpmLPdz0TrouxwKHBhpVLzVIlyKhaRLelIThMw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21"
|
||||
}
|
||||
},
|
||||
"node_modules/simplebar-vue": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/simplebar-vue/-/simplebar-vue-2.3.5.tgz",
|
||||
"integrity": "sha512-LCRpDfJ4nNNHoZK2h5HEhu3BXoLQkQOMzzcHngCb2GN7uVu22dwXW+Kel2f3MDhZgPR2abcTMMtRrRjK3ge0Yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"simplebar-core": "^1.2.6",
|
||||
"vue-demi": "^0.13.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": ">=2.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/simplebar-vue/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
|
|
@ -8220,6 +8300,29 @@
|
|||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "1.0.38",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz",
|
||||
"integrity": "sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
"@types/bootstrap": "^5.2.7",
|
||||
"@types/node": "^20.8.2",
|
||||
"@types/toastify-js": "^1.12.1",
|
||||
"@types/ua-parser-js": "^0.7.39",
|
||||
"@types/vue-select": "^3.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.36.2",
|
||||
|
|
@ -52,6 +53,7 @@
|
|||
"resolve-url-loader": "^5.0.0",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"sass": "latest",
|
||||
"simplebar-vue": "^2.3.5",
|
||||
"slugify": "^1.6.6",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order",
|
||||
|
|
@ -65,6 +67,7 @@
|
|||
"ts-loader": "^9.3.1",
|
||||
"typescript": ">=3.3.1 <5.2.0",
|
||||
"typescript-eslint": "latest",
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"vite": "^4.5.1",
|
||||
"vite-plugin-babel": "latest",
|
||||
"vite-plugin-checker": "latest",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -8,9 +8,11 @@ import {
|
|||
faCircleInfo,
|
||||
faCircleNotch,
|
||||
faCircleXmark,
|
||||
faEllipsisVertical,
|
||||
faEnvelope,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faLocationArrow,
|
||||
faMagnifyingGlass,
|
||||
faTriangleExclamation,
|
||||
faXmark
|
||||
|
|
@ -41,5 +43,7 @@ library.add(faSquareCheck);
|
|||
library.add(faMagnifyingGlass);
|
||||
library.add(faArrowRightArrowLeft);
|
||||
library.add(faEnvelope);
|
||||
library.add(faEllipsisVertical);
|
||||
library.add(faLocationArrow);
|
||||
|
||||
dom.watch();
|
||||
|
|
|
|||
|
|
@ -18,17 +18,17 @@ export default class Ajax {
|
|||
toast.methods.errorNotify(trans.methods.__("La valeur saisie est incorrecte :message", {
|
||||
"message": errorMessage
|
||||
}));
|
||||
return Promise.reject();
|
||||
return;
|
||||
}
|
||||
if (error!.response!.status === 401) {
|
||||
toast.methods.errorNotify(trans.methods.__("Vous devez vous reconnecter"));
|
||||
console.warn(trans.methods.__("Vous devez vous reconnecter"));
|
||||
return Promise.reject();
|
||||
return;
|
||||
}
|
||||
if (error!.response!.status === 419) {
|
||||
toast.methods.errorNotify(trans.methods.__("La page vas devoir être rechargée"));
|
||||
setTimeout(() => window.location.reload(), 2000);
|
||||
return Promise.reject();
|
||||
return;
|
||||
}
|
||||
if (error!.response) {
|
||||
console.error(error.response.data);
|
||||
|
|
@ -39,6 +39,6 @@ export default class Ajax {
|
|||
console.error("Error", error.message);
|
||||
}
|
||||
toast.methods.errorNotify(errorMessage);
|
||||
return Promise.reject();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
<li class="nav-item">
|
||||
<a class="btn btn-link text-tertiary position-relative p-1" href="{{ route('club.notifications.index') }}">
|
||||
@include('club.icons.cloche')
|
||||
@if ($notifications_count)
|
||||
@if (!empty($notifications_count))
|
||||
<span class="position-absolute start-85 translate-middle badge rounded-pill bg-danger top-15">
|
||||
{{ $notifications_count }}
|
||||
<span class="visually-hidden">{{ __('Nouvelles notifications') }}</span>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<span class="nav-icon">@include('club.icons.cloche')</span>
|
||||
<a class="nav-link" href="{{ route('club.notifications.index') }}"
|
||||
title="{{ __('Go to page :page', ['page' => 'Notifications']) }}">{{ __('Notifications') }}</a>
|
||||
@if ($notifications_count)
|
||||
@if (!empty($notifications_count))
|
||||
<span class="nav-notification ms-auto">
|
||||
<span class="visually-hidden">{{ __('Nouvelles notifications') }}</span>
|
||||
<span>{{ $notifications_count }}</span>
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@
|
|||
<div class="col">
|
||||
@php
|
||||
$data = [
|
||||
'block_list' => $block_list,
|
||||
'conversations' => $conversations,
|
||||
'currentUserId' => auth('club')->user()->id,
|
||||
];
|
||||
@endphp
|
||||
@dump($data)
|
||||
<div id="messages-chat" data-json='@json($data)'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<div class="col-12 mb-3 text-center">
|
||||
<span class="header-icon position-relative mb-3">
|
||||
@include('club.icons.cloche')
|
||||
@if ($notifications_count)
|
||||
@if (!empty($notifications_count))
|
||||
<span class="position-absolute start-100 translate-middle bg-danger border-light rounded-circle top-0 border px-2 py-1">
|
||||
<span class="visually-hidden">{{ __('Nouvelles notifications') }}</span>
|
||||
<span>{{ $notifications_count }}</span>
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@
|
|||
@auth('club')
|
||||
<span class="d-none d-sm-inline position-relative ms-3 py-1">
|
||||
<i class="fa-regular fa-user fs-4"></i>
|
||||
@if (!empty($notifications_count))
|
||||
<span class="position-absolute start-100 translate-middle badge rounded-pill text-bg-danger top-0 px-1">
|
||||
{{ $notifications_count }}
|
||||
<span class="visually-hidden">{{ __('Notifications') }}</span>
|
||||
</span>
|
||||
@endif
|
||||
</span>
|
||||
@endauth
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,10 @@
|
|||
'{{ route('fo.products.search.submeat', ['model_slug' => 'MODELSLUG', 'child_slug' => 'CHILDSLUG']) }}';
|
||||
window.__SYSTEM._routes['club.departaimants.save-state'] = '{{ route('club.departaimants.save-state', ['collectiontype' => 'TYPE']) }}';
|
||||
window.__SYSTEM._routes['club.departaimants.search'] = '{{ route('club.departaimants.search', ['collectiontype' => 'TYPE']) }}';
|
||||
window.__SYSTEM._routes['club.messages.conversations'] = '{{ route('club.messages.conversations') }}';
|
||||
window.__SYSTEM._routes['club.messages.send'] = '{{ route('club.messages.send') }}';
|
||||
window.__SYSTEM._routes['club.messages.delete'] = '{{ route('club.messages.delete') }}';
|
||||
window.__SYSTEM._routes['club.messages.toggle-block'] = '{{ route('club.messages.toggle-block', ['status' => 'STATUS']) }}';
|
||||
// FIXME: Contact report customer
|
||||
window.__SYSTEM._routes['club.messages.report-customer'] = '{{ route('fo.contact.show') }}';
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ Route::name('club.')->prefix('club')->group(function () {
|
|||
|
||||
Route::prefix('/messages')->name('messages.')->group(function () {
|
||||
Route::get('/', [MessageController::class, 'index'])->name('index');
|
||||
Route::get('/conversations', [MessageController::class, 'conversations'])->name('conversations');
|
||||
Route::post('send', [MessageController::class, 'send'])->name('send');
|
||||
Route::delete('delete', [MessageController::class, 'delete'])->name('delete');
|
||||
Route::post('block/{status}', [MessageController::class, 'toggleBlock'])->name('toggle-block');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue