FAQ CRUDs

This commit is contained in:
Noah Lancien 2023-08-22 09:18:39 +02:00
parent d604cf64b6
commit db4db55fe9
24 changed files with 947 additions and 117 deletions

View file

@ -3,57 +3,170 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\FaqQuestions\StoreFaqQuestionRequest;
use App\Http\Requests\Bo\FaqQuestions\UpdateFaqQuestionRequest;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class FaqQuestionsController extends Controller
{
public function index()
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
$questions = FaqQuestion::all();
for ($i = 0; $i < count($questions); $i++) {
$questions[$i]['toggle'] = false;
/** @var \Illuminate\Database\Eloquent\Builder $faqQuestionModels */
$faqQuestionModels = FaqQuestion::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$faqQuestionModels,
$search,
null,
'question',
'answer'
);
}
$themes = FaqTheme::all();
return view('bo.faq-questions.index', compact('questions', 'themes'));
$searchFields = \sprintf(
'%s, %s ...',
Str::ucfirst(__('validation.attributes.question')),
__('validation.attributes.answer'),
);
/** Sort columns with a query */
$this->sortQuery($faqQuestionModels);
/** Custom pagination */
$faqQuestionModels = $this->customPaginate($faqQuestionModels, $request->pagination);
return view('bo.pages.faq-questions.index', compact('faqQuestionModels', 'search', 'searchFields'));
}
public function destroy(Request $request)
/**
* Show the form for creating a new resource.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Contracts\View\View
*/
public function create(FaqQuestion $faqQuestion): \Illuminate\Contracts\View\View
{
if ($request->id !== null) {
$question = FaqQuestion::findOrFail($request->id);
$question->delete();
}
$faqThemeModels = FaqTheme::all();
return view('bo.pages.faq-questions.create', [
'faqQuestionModel' => $faqQuestion,
'faqThemeModels' => $faqThemeModels
]);
}
public function saveDatas(Request $request)
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\FaqQuestions\StoreFaqQuestionRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreFaqQuestionRequest $request): \Illuminate\Http\RedirectResponse
{
$questions = $request->questions;
for ($i = 0; $i < count($questions); $i++) {
if (isset($questions[$i]["id"])) {
$q = FaqQuestion::findOrFail($questions[$i]["id"]);
$q->question = $questions[$i]["question"];
$q->answer = $questions[$i]["answer"];
$q->positive_vote = $questions[$i]["positive_vote"];
$q->negative_vote = $questions[$i]["negative_vote"];
$q->theme_id = $questions[$i]["theme_id"];
$q->save();
} else {
$t = FaqQuestion::updateOrCreate(
[
'question' => $questions[$i]["question"],
'answer' => $questions[$i]["answer"],
'positive_vote' => $questions[$i]["positive_vote"],
'negative_vote' => $questions[$i]["negative_vote"],
'theme_id' => $questions[$i]["theme_id"]
]
);
$questions[$i]["id"] = $t->id;
return DB::transaction(function () use ($request) {
$faqQuestion = new FaqQuestion();
$faqQuestion->fill($request->validated());
if ($faqQuestion->saveOrFail()) {
return redirect()
->route('bo.faq-questions.edit', $faqQuestion)
->with(
'success',
trans(
'crud.messages.has_been_created',
['model' => trans_choice('models.classes.faq-questions', 1)]
)
);
}
}//end for
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
return $questions;
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Contracts\View\View
*/
public function edit(FaqQuestion $faqQuestion): \Illuminate\Contracts\View\View
{
$faqThemeModels = FaqTheme::all();
return view('bo.pages.faq-questions.edit', [
'faqQuestionModel' => $faqQuestion,
'faqThemeModels' => $faqThemeModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\FaqQuestions\UpdateFaqQuestionRequest $request
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
UpdateFaqQuestionRequest $request,
FaqQuestion $faqQuestion
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $faqQuestion) {
$faqQuestion->fill($request->validated());
if ($faqQuestion->saveOrFail()) {
return redirect()
->route(
'bo.faq-questions.edit',
$faqQuestion
)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(FaqQuestion $faqQuestion): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($faqQuestion) {
if ($faqQuestion->deleteOrFail()) {
return redirect()
->route('bo.faq-questions.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
}

View file

@ -3,49 +3,167 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\FaqQuestion;
use App\Http\Requests\Bo\FaqThemes\StoreFaqThemeRequest;
use App\Http\Requests\Bo\FaqThemes\UpdateFaqThemeRequest;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class FaqThemesController extends Controller
{
public function index()
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
$themes = FaqTheme::all();
return view('bo.faq-themes.index', compact('themes'));
}
/** @var \Illuminate\Database\Eloquent\Builder $faqThemeModels */
$faqThemeModels = FaqTheme::query();
public function destroy(Request $request)
{
$deleteOk = 0;
if (FaqQuestion::where('theme_id', $request->id)->count() > 0) {
$deleteOk = 1;
} elseif ($request->id !== null) {
$theme = FaqTheme::findOrFail($request->id);
$theme->delete();
} else {
$deleteOk = 2;
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$faqThemeModels,
$search,
null,
'question',
'answer'
);
}
$searchFields = \sprintf(
'%s, %s ...',
Str::ucfirst(__('validation.attributes.question')),
__('validation.attributes.answer'),
);
return $deleteOk;
/** Sort columns with a query */
$this->sortQuery($faqThemeModels);
/** Custom pagination */
$faqThemeModels = $this->customPaginate($faqThemeModels, $request->pagination);
return view('bo.pages.faq-themes.index', compact('faqThemeModels', 'search', 'searchFields'));
}
public function saveDatas(Request $request)
/**
* Show the form for creating a new resource.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Contracts\View\View
*/
public function create(FaqTheme $faqTheme): \Illuminate\Contracts\View\View
{
$themes = $request->themes;
return view('bo.pages.faq-themes.create', [
'faqThemeModel' => $faqTheme,
]);
}
for ($i = 0; $i < count($themes); $i++) {
if (isset($themes[$i]["id"])) {
$t = FaqTheme::findOrFail($themes[$i]["id"]);
$t->name = $themes[$i]["name"];
$t->save();
} else {
$t = FaqTheme::updateOrCreate(['name' => $themes[$i]["name"]]);
$themes[$i]["id"] = $t->id;
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\FaqThemes\StoreFaqThemeRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreFaqThemeRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$faqTheme = new FaqTheme();
$faqTheme->fill($request->validated());
if ($faqTheme->saveOrFail()) {
return redirect()
->route('bo.faq-themes.edit', $faqTheme)
->with(
'success',
trans(
'crud.messages.has_been_created',
['model' => trans_choice('models.classes.faq-themes', 1)]
)
);
}
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
return $themes;
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Contracts\View\View
*/
public function edit(FaqTheme $faqTheme): \Illuminate\Contracts\View\View
{
return view('bo.pages.faq-themes.edit', [
'faqThemeModel' => $faqTheme,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\FaqThemes\UpdateFaqThemeRequest $request
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
UpdateFaqThemeRequest $request,
FaqTheme $faqTheme
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $faqTheme) {
$faqTheme->fill($request->validated());
if ($faqTheme->saveOrFail()) {
return redirect()
->route(
'bo.faq-themes.edit',
$faqTheme
)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(FaqTheme $faqTheme): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($faqTheme) {
if ($faqTheme->questions()->count() === 0) {
if ($faqTheme->deleteOrFail()) {
return redirect()
->route('bo.faq-themes.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
}
}
return redirect()
->back()
->with('error', __(
'crud.messages.cannot_be_deleted',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Http\Requests\Bo\FaqQuestions;
use Illuminate\Foundation\Http\FormRequest;
class StoreFaqQuestionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'question' => 'required|string|min:3|max:255',
'answer' => 'required|string|min:3|max:255',
'theme_id' => 'required|exists:faq_themes,id',
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'question' => trans('Question'),
'answer' => trans('Réponse'),
'theme_id' => trans('Thème associé'),
];
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\FaqQuestions;
class UpdateFaqQuestionRequest extends StoreFaqQuestionRequest
{
}

View file

@ -0,0 +1,42 @@
<?php
namespace App\Http\Requests\Bo\FaqThemes;
use Illuminate\Foundation\Http\FormRequest;
class StoreFaqThemeRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|min:3|max:255'
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'name' => trans('Nom'),
];
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\FaqThemes;
class UpdateFaqThemeRequest extends StoreFaqThemeRequest
{
}

View file

@ -12,34 +12,18 @@ class FaqQuestion extends Model
* @var array
*/
protected $fillable = [
'question', 'answer', 'positive_vote',
'negative_vote', 'theme_id'
'question',
'answer',
'theme_id'
];
/**
* Theme relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function theme()
{
return $this->belongsTo(FaqTheme::class, 'theme_id');
}
/**
* get Utility
* @return float|integer
*/
public function getUtilityAttribute()
{
$pourcent = 0;
if (
$this->positive_vote !== null && $this->negative_vote !== null && $this->positive_vote >= $this->negative_vote && $this->positive_vote > 0 && $this->negative_vote > 0
) {
$ratio = $this->negative_vote / $this->positive_vote;
$pourcent = ceil((1 - $ratio) * 100);
}
return $pourcent;
}
}

View file

@ -22,6 +22,7 @@ class FaqTheme extends Model
/**
* Question relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function questions()

View file

@ -17,8 +17,6 @@ class CreateFaqQuestions extends Migration
$table->id();
$table->string('question');
$table->text('answer');
$table->unsignedInteger('positive_vote')->nullable();
$table->unsignedInteger('negative_vote')->nullable();
$table->foreignId('theme_id')->constrained('faq_themes');
$table->timestamps();
});

View file

@ -3,6 +3,8 @@
return [
'classes' => [
'bannedips' => 'IP bannies',
'contents' => 'contenus',
'contents' => 'Contenus',
'faq-questions' => 'Question pour la FAQ|Questions pour la FAQ',
'faq-themes' => 'Thème pour la FAQ|Thèmes pour la FAQ',
]
];

View file

@ -177,5 +177,8 @@ return [
'ip' => 'IP',
'value' => 'valeur',
'question' => 'question',
'answer' => 'réponse',
'theme' => 'thème',
],
];

View file

@ -1,11 +0,0 @@
@extends('bo.layout')
@section('content')
@php
$data = [
'dbdatas' => $questions,
'dbthemes' => $themes
]
@endphp
<div id="faqQuestionsComponent" data-json='@json($data)'></div>
@endsection

View file

@ -1,6 +0,0 @@
@extends('bo.layout')
@section('content')
@php $data = ['dbdatas' => $themes]; @endphp
<div id="faqThemesComponent" data-json='@json($data)'></div>
@endsection

View file

@ -105,10 +105,10 @@
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdownFaq">
<li>
<a class="dropdown-item" href="{{route('bo.faq-themes')}}">{{ __('Thèmes') }}</a>
<a class="dropdown-item" href="{{route('bo.faq-themes.index')}}">{{ __('Thèmes') }}</a>
</li>
<li>
<a class="dropdown-item" href="{{route('bo.faq-questions')}}">{{ __('Questions') }}</a>
<a class="dropdown-item" href="{{route('bo.faq-questions.index')}}">{{ __('Questions') }}</a>
</li>
</ul>
</li>

View file

@ -0,0 +1,46 @@
@extends('bo.layout', ['brParam' => $faqQuestionModel])
@section('title', __('Création d\'une :model', ['model' => trans_choice('models.classes.faq-questions', 1)]))
@section('description', __('Création d\'une toute nouvelle :model', ['model' => trans_choice('models.classes.faq-questions', 1)]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
<div class="d-flex flex-row align-items-center">
<a href="{{ route('bo.faq-questions.index') }}"
class="btn btn-primary text-decoration-none m-0 me-2"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.faq-questions', 2)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('breadcrumbs.breadcrumb-body', ['brParam' => $faqQuestionModel])
</div>
<div class="mb-2 mb-md-0">
<button id="formSubmitClone"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
<form action="{{ route('bo.faq-questions.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.faq-questions.form-inputs')
<div class="row mt-3">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,62 @@
@extends('bo.layout', ['brParam' => $faqQuestionModel])
@section('title', __('Édition d\'une :model', ['model' => trans_choice('models.classes.faq-questions', 1)]))
@section('description', __('Édition d\'une :model déjà existante', ['model' => trans_choice('models.classes.faq-questions', 1)]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
<div class="d-flex flex-row align-items-start">
<a href="{{ route('bo.faq-questions.index') }}"
class="btn btn-primary text-decoration-none m-0 me-2"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.faq-questions', 2)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('breadcrumbs.breadcrumb-body', ['brParam' => $faqQuestionModel])
</div>
<div class="mb-2 mb-md-0">
<form action="{{ route('bo.faq-questions.destroy', $faqQuestionModel->id) }}"
method="POST"
class="confirmDeleteTS">
@csrf
@method('DELETE')
<div class="btn-group" role="group">
<button id="formSubmitClone"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
<button type="submit"
class="btn btn-danger"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.delete_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
<i class="fa-solid fa-trash"></i>
</button>
</div>
</form>
</div>
</div>
<form action="{{ route('bo.faq-questions.update', $faqQuestionModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.faq-questions.form-inputs')
<div class="row">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,96 @@
<div class="row">
{{-- QUESTION --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.question')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'faqQuestionQuestion',
'label' => __(':field à intégrer à la faq', [
'field' => Str::ucfirst(__('validation.attributes.question')),
]),
'hasWordCounter' => true,
'name' => 'question',
'required' => true,
'model' => $faqQuestionModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field', [
'field' => Str::ucfirst(__('validation.attributes.question')),
]),
'min' => 3,
'max' => 255
]),
'placeholder' => __(':field à intégrer à la faq', [
'field' => Str::ucfirst(__('validation.attributes.question')),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- ANSWER --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.question')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'faqQuestionAnswer',
'label' => __(':field à la question', [
'field' => Str::ucfirst(__('validation.attributes.answer')),
]),
'hasWordCounter' => true,
'name' => 'answer',
'required' => true,
'model' => $faqQuestionModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field', [
'field' => Str::ucfirst(__('validation.attributes.answer')),
]),
'min' => 3,
'max' => 255
]),
'placeholder' => __(':field à la question', [
'field' => Str::ucfirst(__('validation.attributes.answer')),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- THEME_ID --}}
<div class="col-12 col-md-6 pb-3">
<fieldset class="border bg-white h-100 p-3">
<legend>{{ __('Thème') }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.bigint-foreign-id', [
'id' => 'faqQuestionTheme',
'label' => __('crud.minicrud.associated', ['entity' => trans_choice('models.classes.faq-themes', 1)]),
'name' => 'theme_id',
'size' => 5,
'model' => $faqQuestionModel ?? null,
'associatedModels' => $faqThemeModels,
'foreignLabel' => 'name',
'helper' => __('crud.minicrud.select', ['entity' => trans_choice('models.classes.faq-themes', 1)]),
])
</div>
</div>
</fieldset>
</div>
</div>
@push('scripts')
<script>
document.addEventListener("DOMContentLoaded", () => {
// Submit button clone.
const submit = document.getElementById('formSubmit')
submitClone = document.getElementById('formSubmitClone');
submitClone.addEventListener('click', (event) => {
event.preventDefault();
submit.click('');
})
});
</script>
@endpush

View file

@ -0,0 +1,68 @@
@extends('bo.layout')
@section('title', trans_choice('models.classes.faq-questions', 2))
@section('description', __('Liste de toutes les :model', ['model' => trans_choice('models.classes.faq-questions', 2)]))
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center">
@include('breadcrumbs.breadcrumb-body')
<a href="{{ route('bo.faq-questions.create') }}"
class="btn btn-primary float-right"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.create_model', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
@include('bo.modules.search-bar')
<table class="table table-hover">
@if (count($faqQuestionModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'question' => Str::ucfirst(__('validation.attributes.question')),
'answer' => Str::ucfirst(__('validation.attributes.answer')),
'theme_id' => Str::ucfirst(__('validation.attributes.theme')),
],
])
</thead>
<tbody>
@foreach ($faqQuestionModels as $faqQuestionModel)
<tr class="list-item border-bottom">
<td class="text-center align-middle">{{ $faqQuestionModel->question }}</td>
<td class="text-center align-middle">{{ $faqQuestionModel->answer }}</td>
<td class="text-center align-middle">{{ $faqQuestionModel->theme->name }}</td>
<td class="text-end align-middle">
<form action="{{ route('bo.faq-questions.destroy', $faqQuestionModel->id) }}"
method="POST"
class="btn-group confirmDeleteTS"
novalidate>
<a class="btn btn-sm btn-primary"
href="{{ route('bo.faq-questions.edit', $faqQuestionModel) }}"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.actions.update') }}">
<i class="fa-solid fa-pencil"></i>
</a>
@csrf
@method('DELETE')
<button type="submit"
class="btn btn-sm btn-danger"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.actions.delete') }}">
<i class="fa-solid fa-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
@else
<tr>
<td class="text-center fw-bold border-0">{{ __('crud.other.no_model_found', ['model' => trans_choice('models.classes.faq-questions', 1)]) }}</td>
</tr>
@endif
</table>
{!! $faqQuestionModels->links() !!}
@endsection

View file

@ -0,0 +1,46 @@
@extends('bo.layout', ['brParam' => $faqThemeModel])
@section('title', __('Création d\'une :model', ['model' => trans_choice('models.classes.faq-themes', 1)]))
@section('description', __('Création d\'une toute nouvelle :model', ['model' => trans_choice('models.classes.faq-themes', 1)]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
<div class="d-flex flex-row align-items-center">
<a href="{{ route('bo.faq-themes.index') }}"
class="btn btn-primary text-decoration-none m-0 me-2"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.faq-themes', 2)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('breadcrumbs.breadcrumb-body', ['brParam' => $faqThemeModel])
</div>
<div class="mb-2 mb-md-0">
<button id="formSubmitClone"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
<form action="{{ route('bo.faq-themes.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@include('bo.pages.faq-themes.form-inputs')
<div class="row mt-3">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,62 @@
@extends('bo.layout', ['brParam' => $faqThemeModel])
@section('title', __('Édition d\'une :model', ['model' => trans_choice('models.classes.faq-themes', 1)]))
@section('description', __('Édition d\'une :model déjà existante', ['model' => trans_choice('models.classes.faq-themes', 1)]))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-3">
<div class="d-flex flex-row align-items-start">
<a href="{{ route('bo.faq-themes.index') }}"
class="btn btn-primary text-decoration-none m-0 me-2"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.list_all', ['model' => trans_choice('models.classes.faq-themes', 2)]) }}">
<i class="fa-solid fa-arrow-left"></i>
</a>
@include('breadcrumbs.breadcrumb-body', ['brParam' => $faqThemeModel])
</div>
<div class="mb-2 mb-md-0">
<form action="{{ route('bo.faq-themes.destroy', $faqThemeModel->id) }}"
method="POST"
class="confirmDeleteTS">
@csrf
@method('DELETE')
<div class="btn-group" role="group">
<button id="formSubmitClone"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
<button type="submit"
class="btn btn-danger"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.delete_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
<i class="fa-solid fa-trash"></i>
</button>
</div>
</form>
</div>
</div>
<form action="{{ route('bo.faq-themes.update', $faqThemeModel->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
@include('bo.pages.faq-themes.form-inputs')
<div class="row">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.save_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
{{ __('crud.actions.save') }}
</button>
</div>
</div>
</form>
@endsection

View file

@ -0,0 +1,48 @@
<div class="row">
{{-- NAME --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ Str::ucfirst(__('validation.attributes.name')) }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.varchar', [
'id' => 'faqThemeName',
'label' => __(':field du :model', [
'field' => Str::ucfirst(__('validation.attributes.name')),
'model' => trans_choice('models.classes.faq-themes', 1),
]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $faqThemeModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field', [
'field' => Str::ucfirst(__('validation.attributes.question')),
]),
'min' => 3,
'max' => 255
]),
'placeholder' => __(':field du :model', [
'field' => Str::ucfirst(__('validation.attributes.name')),
'model' => trans_choice('models.classes.faq-themes', 1),
]),
])
</div>
</div>
</fieldset>
</div>
</div>
@push('scripts')
<script>
document.addEventListener("DOMContentLoaded", () => {
// Submit button clone.
const submit = document.getElementById('formSubmit')
submitClone = document.getElementById('formSubmitClone');
submitClone.addEventListener('click', (event) => {
event.preventDefault();
submit.click('');
})
});
</script>
@endpush

View file

@ -0,0 +1,64 @@
@extends('bo.layout')
@section('title', trans_choice('models.classes.faq-themes', 2))
@section('description', __('Liste de toutes les :model', ['model' => trans_choice('models.classes.faq-themes', 2)]))
@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center">
@include('breadcrumbs.breadcrumb-body')
<a href="{{ route('bo.faq-themes.create') }}"
class="btn btn-primary float-right"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.helpers.create_model', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
@include('bo.modules.search-bar')
<table class="table table-hover">
@if (count($faqThemeModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
'name' => Str::ucfirst(__('validation.attributes.name')),
],
])
</thead>
<tbody>
@foreach ($faqThemeModels as $faqThemeModel)
<tr class="list-item border-bottom">
<td class="text-center align-middle">{{ $faqThemeModel->name }}</td>
<td class="text-end align-middle">
<form action="{{ route('bo.faq-themes.destroy', $faqThemeModel->id) }}"
method="POST"
class="btn-group confirmDeleteTS"
novalidate>
<a class="btn btn-sm btn-primary"
href="{{ route('bo.faq-themes.edit', $faqThemeModel->id) }}"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.actions.update') }}">
<i class="fa-solid fa-pencil"></i>
</a>
@csrf
@method('DELETE')
<button type="submit"
class="btn btn-sm btn-danger"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="{{ __('crud.actions.delete') }}">
<i class="fa-solid fa-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
@else
<tr>
<td class="text-center fw-bold border-0">{{ __('crud.other.no_model_found', ['model' => trans_choice('models.classes.faq-themes', 1)]) }}</td>
</tr>
@endif
</table>
{!! $faqThemeModels->links() !!}
@endsection

View file

@ -1,6 +1,9 @@
<?php
use App\Models\BannedIp;
use App\Models\Content;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use Diglactic\Breadcrumbs\Breadcrumbs;
use Diglactic\Breadcrumbs\Generator;
@ -16,3 +19,38 @@ Breadcrumbs::for('bo.bannedips.edit', function (Generator $trail, BannedIp $bann
$trail->parent('bo.bannedips.index');
$trail->push(__('crud.actions.edit'), route('bo.bannedips.edit', $bannedip->id));
});
// * CONTENTS
Breadcrumbs::for('bo.contents.index', function (Generator $trail) {
$trail->push(__('models.classes.contents'), route('bo.contents.index'));
});
Breadcrumbs::for('bo.contents.edit', function (Generator $trail, Content $content) {
$trail->parent('bo.contents.index');
$trail->push(__('crud.actions.edit'), route('bo.contents.edit', $content->id));
});
// * FAQ - QUESTIONS
Breadcrumbs::for('bo.faq-questions.index', function (Generator $trail) {
$trail->push(trans_choice('models.classes.faq-questions', 2), route('bo.faq-questions.index'));
});
Breadcrumbs::for('bo.faq-questions.create', function (Generator $trail) {
$trail->parent('bo.faq-questions.index');
$trail->push(__('crud.actions.create'), route('bo.faq-questions.create'));
});
Breadcrumbs::for('bo.faq-questions.edit', function (Generator $trail, FaqQuestion $faqQuestion) {
$trail->parent('bo.faq-questions.index');
$trail->push(__('crud.actions.edit'), route('bo.faq-questions.edit', $faqQuestion->id));
});
// * FAQ - THEMES
Breadcrumbs::for('bo.faq-themes.index', function (Generator $trail) {
$trail->push(trans_choice('models.classes.faq-themes', 2), route('bo.faq-themes.index'));
});
Breadcrumbs::for('bo.faq-themes.create', function (Generator $trail) {
$trail->parent('bo.faq-themes.index');
$trail->push(__('crud.actions.create'), route('bo.faq-themes.create'));
});
Breadcrumbs::for('bo.faq-themes.edit', function (Generator $trail, FaqTheme $faqTheme) {
$trail->parent('bo.faq-themes.index');
$trail->push(__('crud.actions.edit'), route('bo.faq-themes.edit', $faqTheme->id));
});

View file

@ -36,13 +36,17 @@ Route::prefix('bo')
});
Route::middleware(['auth:backend', 'is-admin', 'is-super-admin'])
->group(function () {
// * BANNED IPS.
// * BANNED IPS
Route::resource('/bannedips', BannedIpController::class)->except('show');
// * CONTENTS.
// * CONTENTS
Route::resource('/contents', ContentController::class)
->only(['index', 'edit', 'update'])
->withoutMiddleware('htmlsanitize')
->middleware(['htmlsanitize:value']);
// * FAQ - THEMES
Route::resource('/faq-themes', FaqThemesController::class)->except('show');
// * FAQ - QUESTIONS
Route::resource('/faq-questions', FaqQuestionsController::class)->except('show');
// TODO RESTE A FAIRE :.
Route::get('/', [DashboardController::class, 'index'])
@ -69,14 +73,6 @@ Route::prefix('bo')
->withoutMiddleware('is-super-admin');
Route::post('/ajax/save-codes-ean', [CodesEANController::class, 'saveDatas'])
->withoutMiddleware('is-super-admin');
// FAQ - Thèmes.
Route::get('/faq-themes', [FaqThemesController::class, 'index'])->name('faq-themes');
Route::post('/ajax/delete-faq-theme', [FaqThemesController::class, 'destroy']);
Route::post('/ajax/save-faq-theme', [FaqThemesController::class, 'saveDatas']);
// FAQ - Questions.
Route::get('/faq-questions', [FaqQuestionsController::class, 'index'])->name('faq-questions');
Route::post('/ajax/delete-faq-question', [FaqQuestionsController::class, 'destroy']);
Route::post('/ajax/save-faq-question', [FaqQuestionsController::class, 'saveDatas']);
// Codes uniques.
Route::get('/codes', [CodesController::class, 'index'])->name('codes');
Route::post('/codes', [CodesController::class, 'generate'])->name('generate-codes');