feat: ✨ add answers filter on single optins

This commit is contained in:
Alexis Gousseau 2025-07-23 17:14:51 +02:00
parent 89609454ad
commit 7cfe36b40f
No known key found for this signature in database
GPG key ID: 4A614CB3DBBA2406
6 changed files with 129 additions and 48 deletions

View file

@ -3,8 +3,9 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\Answer;
use App\Models\Question;
use App\Models\SingleOptin;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
@ -19,14 +20,17 @@ class SingleOptinController extends Controller
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $query */
$query = SingleOptin::query();
$query = SingleOptin::query()
->when(
$request->filled('brand'),
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
)
->when(
$request->filled('answer'),
fn($q) => $q->whereHas('answers', fn($q) => $q->where('id', $request->answer))
);
if ($request->brand) {
$query = $query->whereHas('brand', function (Builder $q) use ($request) {
$q->where('id', $request->brand);
});
}
if ($request->search) {
if ($request->filled('search')) {
$this->searchQuery(
$query,
$request->search,
@ -36,16 +40,28 @@ class SingleOptinController extends Controller
}
$this->sortQuery($query);
$searchFields = trans('E-mail');
$query->with('brand');
$query->with(['brand']);
/** @var \Illuminate\Pagination\AbstractPaginator */
$singleoptinModels = $this->paginate($query);
$searchFields = trans('E-mail');
return view('bo.pages.singleoptins.index', compact('singleoptinModels', 'searchFields'));
if ($request->filled('brand')) {
$questionModels = Question::where('brand_id', $request->brand)->get();
if ($request->filled('question')) {
$answerModels = Answer::where('question_id', $request->question)->get();
}
}
return view('bo.pages.singleoptins.index', [
'singleoptinModels' => $singleoptinModels,
'searchFields' => $searchFields,
'questionModels' => $questionModels ?? null,
'answerModels' => $answerModels ?? null,
]);
}
/**
* Remove the specified resource from storage.
*

View file

@ -16,7 +16,7 @@ import "./base/common";
// CUSTOM
import "./pages/customer.delete";
import "./pages/data.delete";
import "./pages/search-bar-brand";
import "./pages/search-bar";
import "./pages/service.index";
import "./pages/stats";
import "./pages/statsExport";

View file

@ -1,11 +0,0 @@
const brandSelect = document.getElementById("brandSelect") as HTMLSelectElement;
if (brandSelect) {
brandSelect.addEventListener("change", function () {
if (brandSelect.value !== "0") {
const url = new URL(location.href);
url.searchParams.set("brand", brandSelect.value);
url.searchParams.delete("rst");
location.assign(url.search);
}
});
}

View file

@ -0,0 +1,30 @@
enum FilterKey {
Brand = "brand",
Question = "question",
Answer = "answer",
}
function setupFilterListener(selectId: string, paramKey: FilterKey): void {
const select = document.getElementById(selectId) as HTMLSelectElement | null;
if (!select) return;
select.addEventListener("change", () => {
const value = select.value;
if (value !== "0") {
const url = new URL(location.href);
url.searchParams.set(paramKey, value);
url.searchParams.delete("rst");
location.assign(url.search);
}
});
}
const filterMap: Record<string, FilterKey> = {
brandSelect: FilterKey.Brand,
questionSelect: FilterKey.Question,
answerSelect: FilterKey.Answer,
};
Object.entries(filterMap).forEach(([selectId, paramKey]) => {
setupFilterListener(selectId, paramKey);
});

View file

@ -1,26 +1,72 @@
<form action="{{ request()->fullUrlWithQuery(['rst' => null]) }}">
<div class="input-group mb-3">
<label class="input-group-text" for="brandSelect">{{ __('Filter par Marque') }}</label>
<select class="form-select" id="brandSelect">
<option value="0" @if (!request()->brand) selected @endif>{{ __('Sélectionnez une marque..') }}</option>
@foreach (\App\Models\Brand::all() as $brand)
<option value="{{ $brand->id }}" @if (request()->brand == "$brand->id") selected @endif>{{ $brand->name }}</option>
@php
$selectedBrand = request()->brand;
$selectedQuestion = request()->question;
$selectedAnswer = request()->answer;
$search = request()->search;
$sortCol = request()->sort_col;
$sortWay = request()->sort_way;
@endphp
<form action="{{ request()->fullUrlWithQuery(['rst' => null]) }}" class="row gx-2">
<div class="col-12 col-lg-6">
{{-- BRAND SELECT --}}
<select class="form-select mb-1" id="brandSelect">
<option value="0" @selected(!$selectedBrand)>{{ __('Sélectionnez une marque...') }}</option>
@foreach (\App\Models\Brand::all() as $brand)
<option value="{{ $brand->getKey() }}" @selected($selectedBrand == $brand->getKey())>
{{ $brand->name }}
</option>
@endforeach
</select>
{{-- QUESTION SELECT --}}
@if (request()->routeIs('bo.single_optins.index') && $selectedBrand && $questionModels)
<select class="form-select mb-1" id="questionSelect">
<option value="0" @selected(!$selectedQuestion)>{{ __('Sélectionnez une question...') }}</option>
@foreach ($questionModels as $question)
<option value="{{ $question->getKey() }}" @selected($selectedQuestion == $question->getKey())>
{{ $question->question }}
</option>
@endforeach
</select>
@endif
{{-- ANSWER SELECT --}}
@if ($selectedQuestion && $answerModels)
<select class="form-select mb-1" id="answerSelect">
<option value="0" @selected(!$selectedAnswer)>{{ __('Sélectionnez une réponse...') }}</option>
@foreach ($answerModels as $answer)
<option value="{{ $answer->getKey() }}" @selected($selectedAnswer == $answer->getKey())>
{{ $answer->answer }}
</option>
@endforeach
</select>
@endif
</div>
<div class="col-12 col-lg-6 d-flex justify-content-center align-items-start">
<div class="input-group">
{{-- SEARCH FIELD --}}
<label class="input-group-text" for="searchField">{{ $searchFields }}</label>
<input class="form-control" id="searchField" name="search" type="search" value="{{ $search }}"
placeholder="Recherche.." />
{{-- HIDDEN INPUTS --}}
<input type="hidden" name="sort_col" type="text" value="{{ $sortCol }}">
<input type="hidden" name="sort_way" type="text" value="{{ $sortWay }}">
@foreach (['brand' => $selectedBrand, 'question' => $selectedQuestion, 'answer' => $selectedAnswer] as $key => $val)
@if ($val)
<input type="hidden" name="{{ $key }}" type="text" value="{{ $val }}">
@endif
@endforeach
</select>
<div class="input-group-text bg-warning text-bg-warning">🔍🠚</div>
<label class="input-group-text" for="searchField">{{ $searchFields }}</label>
<input class="form-control" id="searchField" name="search" type="search" value="{{ request()->search }}"
placeholder="Recherche.." />
<input class="d-none" name="sort_col" type="text" value="{{ request()->sort_col }}" />
<input class="d-none" name="sort_way" type="text" value="{{ request()->sort_way }}" />
@if (request()->brand)
<input class="d-none" name="brand" type="hidden" value="{{ request()->brand }}" />
@endif
<button class="btn btn-primary" data-bs-toggle="tooltip" type="submit" title="{{ __('Lancer la recherche') }}">
<i class="fas fa-search"></i>
</button>
<a class="btn btn-danger" data-bs-toggle="tooltip"
href="{{ request()->fullUrlWithQuery(['rst' => 'true', 'search' => null, 'brand' => null]) }}"
{{-- ACTION BUTTONS --}}
<button class="btn btn-primary" data-bs-toggle="tooltip" type="submit"
title="{{ __('Lancer la recherche') }}">
<i class="fas fa-search"></i>
</button>
</div>
<a class="btn btn-danger ms-2" data-bs-toggle="tooltip"
href="{{ request()->fullUrlWithQuery(['rst' => 'true', 'search' => null, 'brand' => null, 'question' => null, 'answer' => null]) }}"
title="{{ __('Supprimer la recherche') }}">
<i class="fas fa-backspace"></i>
</a>

View file

@ -11,7 +11,7 @@
<div class="row mb-3">
<div class="col-12">
<form id="searchForm" action="/{{ request()->path() }}">
<div class="input-group pt-3">
<div class="input-group">
<label class="input-group-text" for="searchField">{{ $searchFields }}</label>
@if(request()->sort_col)
<input class="d-none" type="text" name="sort_col" value="{{ request()->sort_col }}">