feat ✨ : add buttons for read notifs
This commit is contained in:
parent
efd8871020
commit
cf07ca6a6e
8 changed files with 514 additions and 31 deletions
|
|
@ -3,6 +3,9 @@
|
|||
namespace App\Http\Controllers\Club;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Club\Notifications\DeleteNotificationsRequest;
|
||||
use App\Models\Notification;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\View as FacadesView;
|
||||
|
||||
class NotificationController extends Controller
|
||||
|
|
@ -16,7 +19,10 @@ class NotificationController extends Controller
|
|||
{
|
||||
/** @var \App\Models\Customer $customerModel */
|
||||
$customerModel = auth('club')->user();
|
||||
$notificationModels = $customerModel->notifications()->orderBy('created_at', 'DESC')->get();
|
||||
$notificationModels = $customerModel->notifications()
|
||||
->whereNotIn('id', $customerModel->readNotifications()->pluck('notification_id'))
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
return view('club.pages.notifications.index', compact('notificationModels'));
|
||||
}
|
||||
|
||||
|
|
@ -29,4 +35,41 @@ class NotificationController extends Controller
|
|||
{
|
||||
return response()->json(FacadesView::shared('notifications_count', 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete notification from list
|
||||
* @param Notification $notification
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Notification $notification): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
/** @var \App\Models\Customer $customer */
|
||||
$customer = Auth::guard('club')->user();
|
||||
|
||||
$customer->readNotifications()->syncWithoutDetaching($notification->id);
|
||||
session()->flash('success', __('Notification supprimée.'));
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete notification from list
|
||||
* @param \App\Http\Requests\Club\Notifications\DeleteNotificationsRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroyMultiple(DeleteNotificationsRequest $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
/** @var \App\Models\Customer $customer */
|
||||
$customer = Auth::guard('club')->user();
|
||||
|
||||
$customer->readNotifications()->syncWithoutDetaching($request->validated('ids'));
|
||||
|
||||
$count = count($request->validated(('ids')));
|
||||
|
||||
session()->flash('success', trans_choice(
|
||||
'{1} Notification supprimée.|[2,*] :count notifications supprimées.',
|
||||
$count,
|
||||
['count' => $count]
|
||||
));
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Club\Notifications;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class DeleteNotificationsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('club')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'ids' => ['required', 'array', 'min:2'],
|
||||
'ids.*' => ['integer', 'exists:notifications,id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -25,3 +25,126 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------Style for deleting notification in notification list page -------------------
|
||||
// Checkbox custom
|
||||
|
||||
.notif-checkbox-icon {
|
||||
display: inline-flex;
|
||||
width: 1.25rem;;
|
||||
height: 1.25rem;;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid #adb5bd;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, border-color 0.15s ease;
|
||||
|
||||
&::after {
|
||||
display: block;
|
||||
width: 0.65rem;
|
||||
height: 0.4rem;
|
||||
border-bottom: 2.5px solid #fff;
|
||||
border-left: 2.5px solid #fff;
|
||||
margin-top: -2px;
|
||||
content: '';
|
||||
transform: rotate(-45deg) scale(0);
|
||||
transform-origin: center;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
border-color: $color-danger;
|
||||
background: $color-danger;
|
||||
|
||||
&::after {
|
||||
transform: rotate(-45deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-indeterminate {
|
||||
border-color: $color-danger;
|
||||
background: $color-danger;
|
||||
|
||||
&::after {
|
||||
width: 0.65rem;
|
||||
height: 0;
|
||||
border-bottom: 2.5px solid #fff;
|
||||
margin-top: 0;
|
||||
transform: rotate(0deg) scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// display checkbox near notif
|
||||
|
||||
.notif-checkbox-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: width 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
// delete single
|
||||
|
||||
.notif-delete-wrapper {
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
transition: width 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-delete-single {
|
||||
display: inline-flex;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: #dc3545;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Mode select all
|
||||
|
||||
#notifications-list {
|
||||
&.selection-mode {
|
||||
.notif-checkbox-wrapper {
|
||||
width: 1.8rem;
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.notification-item-wrapper {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-notification {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// hide sigle delete
|
||||
.notif-delete-wrapper {
|
||||
width: 0;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import "./utilities/vue-club";
|
|||
|
||||
// PARTIALS
|
||||
import "./partials/layout";
|
||||
import './partials/delete-notifications'
|
||||
|
||||
// CUSTOM
|
||||
import "./base/common";
|
||||
|
|
|
|||
205
resources/ts/club/partials/delete-notifications.ts
Normal file
205
resources/ts/club/partials/delete-notifications.ts
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
import sweetalert from "../../modules/sweetalertConfirm";
|
||||
import trans from "../../modules/trans";
|
||||
|
||||
interface NotificationsElements {
|
||||
list: HTMLElement;
|
||||
toolbar: HTMLElement;
|
||||
btnToggle: HTMLButtonElement;
|
||||
btnCancel: HTMLButtonElement;
|
||||
btnDelete: HTMLButtonElement;
|
||||
selectedCount: HTMLElement;
|
||||
selectAllBox: HTMLElement;
|
||||
}
|
||||
|
||||
// connect with elements
|
||||
function resolveElements(): NotificationsElements | null {
|
||||
const list = document.getElementById('notifications-list');
|
||||
const toolbar = document.getElementById('selection-toolbar');
|
||||
const btnToggle = document.getElementById('btn-toggle-selection');
|
||||
const btnCancel = document.getElementById('btn-cancel-selection');
|
||||
const btnDelete = document.getElementById('btn-delete-selected');
|
||||
const selectedCount = document.getElementById('selected-count');
|
||||
const selectAllBox = document.getElementById('select-all-checkbox');
|
||||
|
||||
if (!list || !toolbar || !btnToggle || !btnCancel || !btnDelete || !selectedCount || !selectAllBox) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
list,
|
||||
toolbar,
|
||||
btnToggle: btnToggle as HTMLButtonElement,
|
||||
btnCancel: btnCancel as HTMLButtonElement,
|
||||
btnDelete: btnDelete as HTMLButtonElement,
|
||||
selectedCount,
|
||||
selectAllBox,
|
||||
};
|
||||
}
|
||||
|
||||
// selectors
|
||||
|
||||
function getBoxes(list: HTMLElement): HTMLElement[] {
|
||||
return [...list.querySelectorAll<HTMLElement>('.notif-checkbox-icon[data-id]')];
|
||||
}
|
||||
|
||||
function getChecked(list: HTMLElement): HTMLElement[] {
|
||||
return getBoxes(list).filter(b => b.classList.contains('is-checked'));
|
||||
}
|
||||
|
||||
function getCsrfToken(): string {
|
||||
return document.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')?.content ?? '';
|
||||
}
|
||||
|
||||
// Toolbar
|
||||
|
||||
function updateToolbar(els: NotificationsElements): void {
|
||||
const { list, btnDelete, selectedCount, selectAllBox } = els;
|
||||
const checked = getChecked(list);
|
||||
const total = getBoxes(list).length;
|
||||
|
||||
selectedCount.textContent = String(checked.length);
|
||||
btnDelete.classList.toggle('d-none', checked.length < 1);
|
||||
|
||||
selectAllBox.classList.remove('is-checked', 'is-indeterminate');
|
||||
|
||||
if (total > 0 && checked.length === total) {
|
||||
selectAllBox.classList.add('is-checked');
|
||||
selectAllBox.setAttribute('aria-checked', 'true');
|
||||
} else if (checked.length > 0) {
|
||||
selectAllBox.classList.add('is-indeterminate');
|
||||
selectAllBox.setAttribute('aria-checked', 'mixed');
|
||||
} else {
|
||||
selectAllBox.setAttribute('aria-checked', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
// Mode select all
|
||||
|
||||
// Enable mode
|
||||
function enterSelectionMode(els: NotificationsElements): void {
|
||||
els.list.classList.add('selection-mode');
|
||||
els.toolbar.classList.remove('d-none');
|
||||
els.toolbar.classList.add('d-flex');
|
||||
els.btnToggle.classList.add('d-none');
|
||||
}
|
||||
|
||||
// Disable mode
|
||||
function exitSelectionMode(els: NotificationsElements): void {
|
||||
els.list.classList.remove('selection-mode');
|
||||
els.toolbar.classList.add('d-none');
|
||||
els.toolbar.classList.remove('d-flex');
|
||||
els.btnToggle.classList.remove('d-none');
|
||||
|
||||
getBoxes(els.list).forEach(b => {
|
||||
b.classList.remove('is-checked');
|
||||
b.setAttribute('aria-checked', 'false');
|
||||
});
|
||||
|
||||
els.selectAllBox.classList.remove('is-checked', 'is-indeterminate');
|
||||
els.selectAllBox.setAttribute('aria-checked', 'false');
|
||||
updateToolbar(els);
|
||||
}
|
||||
|
||||
// call Ajax
|
||||
function fetchDelete(url: string, body: object | null = null): Promise<Response> {
|
||||
return fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': getCsrfToken(),
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
...(body ? { body: JSON.stringify(body) } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
//delete one by one
|
||||
function deleteSingle(btn: HTMLButtonElement, els: NotificationsElements): void {
|
||||
sweetalert.methods.confirm(
|
||||
'Supprimer cette notification ?',
|
||||
'',
|
||||
btn,
|
||||
() => {
|
||||
fetchDelete(btn.dataset.url!)
|
||||
.then(r => { if (!r.ok) throw new Error(); })
|
||||
.then(() => window.location.reload())
|
||||
.catch(() => sweetalert.methods.alert('Une erreur est survenue.', '', null, null, { icon: 'error' }));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// delete multiple
|
||||
function deleteSelected(els: NotificationsElements): void {
|
||||
const { list, btnDelete } = els;
|
||||
const checked = getChecked(list);
|
||||
|
||||
const count = checked.length;
|
||||
const message = count === 1
|
||||
? trans.methods.__('Une notification sera supprimée.')
|
||||
: trans.methods.__(':count notifications seront supprimées.').replace(':count', String(count));
|
||||
|
||||
sweetalert.methods.confirm(
|
||||
trans.methods.__('Supprimer les notifications sélectionnées ?'),
|
||||
message,
|
||||
btnDelete,
|
||||
() => {
|
||||
fetchDelete(btnDelete.dataset.url!, { ids: checked.map(b => b.dataset.id!) })
|
||||
.then(r => { if (!r.ok) throw new Error(); return r.json(); })
|
||||
.then(() => window.location.reload())
|
||||
.catch(() => sweetalert.methods.alert('Une erreur est survenue.', '', null, null, { icon: 'error' }));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// init
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const els = resolveElements();
|
||||
if (!els) return;
|
||||
|
||||
const { list, btnToggle, btnCancel, btnDelete, selectAllBox } = els;
|
||||
|
||||
btnToggle.addEventListener('click', () => enterSelectionMode(els));
|
||||
btnCancel.addEventListener('click', () => exitSelectionMode(els));
|
||||
btnDelete.addEventListener('click', () => deleteSelected(els));
|
||||
|
||||
selectAllBox.addEventListener('click', (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
const boxes = getBoxes(list);
|
||||
const allChecked = getChecked(list).length === boxes.length && boxes.length > 0;
|
||||
boxes.forEach(b => {
|
||||
b.classList.toggle('is-checked', !allChecked);
|
||||
b.setAttribute('aria-checked', String(!allChecked));
|
||||
});
|
||||
updateToolbar(els);
|
||||
});
|
||||
|
||||
selectAllBox.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); selectAllBox.click(); }
|
||||
});
|
||||
|
||||
list.addEventListener('click', (e: MouseEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
||||
// delete single
|
||||
const deleteBtn = target.closest<HTMLButtonElement>('.btn-delete-single');
|
||||
if (deleteBtn) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
deleteSingle(deleteBtn, els);
|
||||
return;
|
||||
}
|
||||
|
||||
// when mode select all active select all div
|
||||
if (!list.classList.contains('selection-mode')) return;
|
||||
|
||||
const wrapper = target.closest<HTMLElement>('.notification-item-wrapper');
|
||||
if (!wrapper) return;
|
||||
|
||||
const box = wrapper.querySelector<HTMLElement>('.notif-checkbox-icon[data-id]');
|
||||
if (!box) return;
|
||||
|
||||
const checked = box.classList.toggle('is-checked');
|
||||
box.setAttribute('aria-checked', String(checked));
|
||||
updateToolbar(els);
|
||||
});
|
||||
});
|
||||
|
|
@ -31,13 +31,56 @@
|
|||
<div class="col">
|
||||
@if (!$notificationModels->count())
|
||||
<span class="d-block h3 text-center">{{ __('Pas de nouvelles notifications') }}</span>
|
||||
@else
|
||||
<div class="d-flex align-items-center justify-content-between mb-3 px-1 gap-2 flex-wrap">
|
||||
|
||||
<button id="btn-toggle-selection" type="button" class="btn btn-outline-secondary">
|
||||
<i class="fa-solid fa-circle-check me-2" aria-hidden="true"></i>
|
||||
{{ __('Sélectionner') }}
|
||||
</button>
|
||||
|
||||
<div id="selection-toolbar" class="d-none align-items-center gap-3 flex-wrap">
|
||||
|
||||
<label class="d-flex align-items-center gap-2 mb-0 user-select-none" style="cursor:pointer;">
|
||||
<span
|
||||
class="notif-checkbox-icon"
|
||||
id="select-all-checkbox"
|
||||
role="checkbox"
|
||||
aria-checked="false"
|
||||
tabindex="0"
|
||||
aria-label="{{ __('Tout sélectionner') }}"
|
||||
></span>
|
||||
<span>{{ __('Tout sélectionner') }}</span>
|
||||
</label>
|
||||
|
||||
<button
|
||||
id="btn-delete-selected"
|
||||
class="btn btn-danger d-none"
|
||||
type="button"
|
||||
data-url="{{ route('club.notifications.delete-multiple') }}"
|
||||
data-confirm-bulk="{{ __('Supprimer les :count notifications sélectionnées ?') }}"
|
||||
data-error-message="{{ __('Une erreur est survenue.') }}"
|
||||
>
|
||||
<i class="fa-solid fa-xmark me-2" aria-hidden="true"></i>
|
||||
{{ __('Supprimer') }}
|
||||
<span class="badge bg-white text-danger ms-2" id="selected-count">0</span>
|
||||
</button>
|
||||
|
||||
<button id="btn-cancel-selection" type="button" class="btn btn-link text-secondary p-0">
|
||||
{{ __('Annuler') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="notifications-list">
|
||||
@foreach ($notificationModels as $notificationModel)
|
||||
@include('club.partials.card-notification', [
|
||||
'outterClass' => 'w-100 my-3',
|
||||
'notification' => $notificationModel,
|
||||
])
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($notificationModels as $notificationModel)
|
||||
@include('club.partials.card-notification', [
|
||||
'outterClass' => 'w-100 my-3',
|
||||
'notification' => $notificationModel,
|
||||
])
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -9,31 +9,63 @@
|
|||
default => throw $unhandled_type_exception,
|
||||
};
|
||||
@endphp
|
||||
<a href="{{ $notification->content }}" title="{{ __('Go to page :page', ['page' => $message_tag]) }}" @class([
|
||||
'card-notification text-bg-secondary rounded-4 text-decoration-none px-md-5 py-3',
|
||||
$outterClass ?? '',
|
||||
])>
|
||||
<div class="notification-image px-3 text-center">
|
||||
@switch($notification->notifiable_type)
|
||||
@case(\App\Models\Message::class)
|
||||
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/club/departaimant-sarthe.png') }}"
|
||||
title="{{ __('Un magnet Départaimants de la Sarthe') }}" alt="{{ __('Magnet') }}">
|
||||
@break
|
||||
|
||||
@default
|
||||
@php throw $unhandled_type_exception; @endphp
|
||||
@endswitch
|
||||
<div class="notification-item-wrapper d-flex align-items-center gap-2 {{ $outterClass ?? '' }}">
|
||||
|
||||
{{-- Checkbox --}}
|
||||
<div class="notif-checkbox-wrapper">
|
||||
<span
|
||||
class="notif-checkbox-icon"
|
||||
data-id="{{ $notification->id }}"
|
||||
role="checkbox"
|
||||
aria-checked="false"
|
||||
tabindex="-1"
|
||||
aria-label="{{ __('Sélectionner cette notification') }}"
|
||||
></span>
|
||||
</div>
|
||||
<div class="notification-content">
|
||||
<div>
|
||||
<div class="d-inline-flex flex-column flex-sm-row flex-wrap align-items-center pb-2">
|
||||
<span class="text-bg-white rounded-pill px-2 py-1 text-center">{{ str($message_tag)->ucFirst() }}</span>
|
||||
<span class="pt-1 pt-sm-0 px-sm-2">{{ $notification->created_at_nice_date }}</span>
|
||||
|
||||
<a href="{{ $notification->content }}" title="{{ __('Go to page :page', ['page' => $message_tag]) }}"
|
||||
class="card-notification text-bg-secondary rounded-4 text-decoration-none px-md-5 py-3 flex-grow-1">
|
||||
|
||||
<div class="notification-image px-3 text-center">
|
||||
@switch($notification->notifiable_type)
|
||||
@case(\App\Models\Message::class)
|
||||
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/club/departaimant-sarthe.png') }}"
|
||||
title="{{ __('Un magnet Départaimants de la Sarthe') }}" alt="{{ __('Magnet') }}">
|
||||
@break
|
||||
|
||||
@default
|
||||
@php throw $unhandled_type_exception; @endphp
|
||||
@endswitch
|
||||
</div>
|
||||
|
||||
<div class="notification-content">
|
||||
<div>
|
||||
<div class="d-inline-flex flex-column flex-sm-row flex-wrap align-items-center pb-2">
|
||||
<span class="text-bg-white rounded-pill px-2 py-1 text-center">{{ str($message_tag)->ucFirst() }}</span>
|
||||
<span class="pt-1 pt-sm-0 px-sm-2">{{ $notification->created_at_nice_date }}</span>
|
||||
</div>
|
||||
<p class="m-0">{{ $message_label }}</p>
|
||||
</div>
|
||||
<div class="pe-3">
|
||||
<i class="fa-solid fa-chevron-left fa-xl fa-flip-horizontal" aria-hidden="true"></i>
|
||||
</div>
|
||||
<p class="m-0">{{ $message_label }}</p>
|
||||
</div>
|
||||
<div class="pe-3">
|
||||
<i class="fa-solid fa-chevron-left fa-xl fa-flip-horizontal" aria-hidden="true"></i>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- delete button --}}
|
||||
<div class="notif-delete-wrapper flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-delete-single btn-secondary"
|
||||
data-url="{{ route('club.notifications.delete', $notification->id) }}"
|
||||
data-confirm="{{ __('Supprimer cette notification ?') }}"
|
||||
data-error-message="{{ __('Une erreur est survenue.') }}"
|
||||
title="{{ __('Supprimer cette notification') }}"
|
||||
>
|
||||
<i class="fa-solid fa-xmark fa-sm" aria-hidden="true"></i>
|
||||
<span class="visually-hidden">{{ __('Supprimer') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ Route::name('club.')->prefix('club')->group(function () {
|
|||
Route::get('la-quete', [QuestController::class, 'index'])->name('quests.index');
|
||||
Route::get('les-jeux', [GameController::class, 'index'])->name('games.index');
|
||||
|
||||
// * NOTIFICATIONS
|
||||
Route::delete('/notifications/{notification}', [NotificationController::class, 'destroy'])
|
||||
->name('notifications.delete');
|
||||
Route::delete('/notifications', [NotificationController::class, 'destroyMultiple'])
|
||||
->name('notifications.delete-multiple');
|
||||
|
||||
|
||||
// * NEWS CLUB
|
||||
Route::get('articles/{news_club_slug}', [SurveyController::class, 'show'])->name('news.show');
|
||||
Route::post('sondage/{news_club}/reponse', [SurveyController::class, 'store'])->name('surveys.store');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue