Skip to content
Snippets Groups Projects
Commit 4dabbbdb authored by Sofiane Lasri's avatar Sofiane Lasri
Browse files

Merge branch '16-ajouter-conditions-generales-de-vente' into 'master'

Resolve "Ajouter conditions générales de vente"

Closes #16

See merge request !55
parents 5b53b618 b67a372e
No related branches found
No related tags found
1 merge request!55Resolve "Ajouter conditions générales de vente"
Pipeline #1004 passed
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\TermsSection;
use App\Models\Translation;
use App\Models\TranslationKey;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
class TermsSectionController extends Controller
{
protected array $headerRoutes = [
[
'route' => 'admin.terms.index',
'label' => 'Liste des sections',
'icon' => 'list',
],
[
'route' => 'admin.terms.create',
'label' => 'Créer une section',
'icon' => 'plus',
],
];
public function index(): View
{
$sections = TermsSection::with(['contentTranslationKey.translations'])->get();
return view('admin.terms.index', [
'headerRoutes' => $this->headerRoutes,
'sections' => $sections,
]);
}
public function createPage(): View
{
return view('admin.terms.edit', [
'title' => 'Créer une section',
'headerRoutes' => $this->headerRoutes,
]);
}
public function editPage(Request $request, int $id): View
{
$request->validate([
'lang' => 'sometimes|string|in:fr,en',
]);
$lang = $request->input('lang', 'fr');
$section = TermsSection::findOrFail($id);
$content = $section->contentTranslationKey->getTranslation($lang);
$active = $section->active;
return view('admin.terms.edit', [
'title' => 'Modifier une section',
'headerRoutes' => $this->headerRoutes,
'section' => $section,
'content' => $content,
'lang' => $lang,
'active' => $active,
]);
}
public function store(Request $request): RedirectResponse
{
$request->validate([
'lang' => 'required|string|in:fr,en',
'content' => 'required|string',
'active' => 'sometimes|string|in:on',
]);
$contentTranslationKey = TranslationKey::create(['key' => 'terms_content_'.Str::uuid()]);
Translation::create([
'translation_key_id' => $contentTranslationKey->id,
'locale' => $request->input('lang'),
'text' => $request->input('content'),
]);
$section = TermsSection::create([
'content_translation_key_id' => $contentTranslationKey->id,
'active' => false,
]);
$this->updateActiveStatus($section, $request->has('active'));
$section->save();
return redirect()->route('admin.terms.index')->with('success', 'Section créée avec succès.');
}
public function update(Request $request, int $id): RedirectResponse
{
$request->validate([
'lang' => 'required|string|in:fr,en',
'content' => 'required|string',
'active' => 'sometimes|string|in:on',
]);
$section = TermsSection::findOrFail($id);
Translation::updateOrCreate(
['translation_key_id' => $section->contentTranslationKey->id, 'locale' => $request->input('lang')],
['text' => $request->input('content')]
);
$this->updateActiveStatus($section, $request->has('active'));
$section->save();
return redirect()->route('admin.terms.edit', [
'section' => $section->id,
'lang' => $request->input('lang'),
])->with('success', 'Section mise à jour avec succès.');
}
public function delete(int $id): RedirectResponse
{
$section = TermsSection::findOrFail($id);
$section->delete();
return redirect()->route('admin.terms.index')->with('success', 'Section supprimée avec succès.');
}
private function updateActiveStatus(TermsSection $section, bool $active): void
{
if ($active) {
TermsSection::where('id', '!=', $section->id)->update(['active' => false]);
$section->active = true;
} else {
$section->active = false;
}
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class TermsSection extends Model
{
use HasFactory;
protected $fillable = [
'active',
'content_translation_key_id',
];
public function contentTranslationKey(): BelongsTo
{
return $this->belongsTo(TranslationKey::class, 'content_translation_key_id');
}
protected function casts(): array
{
return [
'active' => 'boolean',
];
}
}
......@@ -39,6 +39,11 @@
'route' => 'admin.about.index',
'icon' => 'info',
],
[
'title' => 'Conditions générales de vente',
'route' => 'admin.terms.index',
'icon' => 'file-contract',
],
],
],
];
<?php
namespace Database\Factories;
use App\Models\TermsSection;
use App\Models\TranslationKey;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
class TermsSectionFactory extends Factory
{
protected $model = TermsSection::class;
public function definition(): array
{
return [
'active' => $this->faker->boolean(),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
'content_translation_key_id' => TranslationKey::factory(),
];
}
}
<?php
use App\Models\TranslationKey;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('terms_sections', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(TranslationKey::class, 'content_translation_key_id');
$table->boolean('active');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('terms_sections');
}
};
@extends('layouts.admin', ['title' => $title, 'headerRoutes' => $headerRoutes])
@section('content')
<div class="grid">
<div class="g-col-12 g-col-md-6">
<h5>Information</h5>
<p>Gérez les conditions générales de vente.</p>
<form action="{{ !empty($section) ? route('admin.terms.update', $section->id) : route('admin.terms.store') }}"
method="post">
@csrf
@if(!empty($section))
@method('PUT')
@endif
<x-bs.select id="lang-select" label="Langue" name="lang"
:options="['fr' => 'Français', 'en' => 'Anglais']"
class="mb-3" :selected="old('lang', $lang ?? 'fr')"/>
<x-admin.markdown-editor label="Contenu" name="content" class="mb-3"
:value="old('content', $content ?? '')"
required/>
<x-bs.checkbox name="active" label="Activer cette section" :checked="old('active', $active ?? false)"
class="mb-3"/>
<x-bs.button type="submit">Enregistrer</x-bs.button>
</form>
@if (!empty($errors) && $errors->any())
<x-bs.alert type="danger" class="mt-3">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</x-bs.alert>
@endif
@if (session('success'))
<x-bs.alert type="success" class="mt-3">
{{ session('success') }}
</x-bs.alert>
@endif
</div>
</div>
@endsection
@pushonce('scripts')
<script type="text/javascript">
const langSelect = document.getElementById('lang-select');
const url = new URL(window.location.href);
if (url.pathname.endsWith('/edit') && !url.searchParams.has('lang') && langSelect) {
url.searchParams.set('lang', langSelect.value);
window.location.href = url.toString();
}
if (url.pathname.endsWith('/edit') && langSelect) {
langSelect.addEventListener('change', function () {
url.searchParams.set('lang', langSelect.value);
window.location.href = url.toString();
});
}
</script>
@endpushonce
@extends('layouts.admin', ['title' => 'Conditions Générales', 'headerRoutes' => $headerRoutes])
@section('content')
<h5>Information</h5>
<p>Gérez les sections des Conditions Générales de Vente.</p>
@if (session('success'))
<x-bs.alert type="success" class="mt-3">
{{ session('success') }}
</x-bs.alert>
@endif
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Contenu (Français)</th>
<th scope="col">Contenu (Anglais)</th>
<th scope="col">Active</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
@foreach($sections as $section)
<tr>
<th scope="row">{{ $section->id }}</th>
<td>{{ Str::limit($section->contentTranslationKey->getTranslation('fr'), 50) }}</td>
<td>{{ Str::limit($section->contentTranslationKey->getTranslation('en'), 50) }}</td>
<td>{{ $section->active ? 'Oui' : 'Non' }}</td>
<td>
<x-bs.button size="sm" tag="a" href="{{ route('admin.terms.edit', $section->id) }}"
variant="primary">
Modifier
</x-bs.button>
<x-bs.button href="{{ route('admin.terms.delete', $section->id) }}" size="sm" tag="a"
variant="danger">
Supprimer
</x-bs.button>
</td>
</tr>
@endforeach
@if($sections->isEmpty())
<tr>
<td colspan="5" class="text-center">Aucune section trouvée. {{ \Spatie\Emoji\Emoji::desert() }}</td>
</tr>
@endif
</tbody>
</table>
@endsection
......@@ -8,6 +8,7 @@
use App\Http\Controllers\Admin\PrestationController;
use App\Http\Controllers\Admin\SettingsController;
use App\Http\Controllers\Admin\SocialMediaLinksController;
use App\Http\Controllers\Admin\TermsSectionController;
use App\Http\Controllers\Public\IndexController;
use App\Http\Controllers\Public\PortfolioController;
use App\Http\Controllers\Public\PrestationController as PublicPrestationController;
......@@ -123,6 +124,16 @@
Route::put('/{event}', [EventController::class, 'update'])->name('update');
Route::get('/{event}/delete', [EventController::class, 'delete'])->name('delete');
});
Route::prefix('terms')->name('terms.')->group(function () {
Route::get('/', [TermsSectionController::class, 'index'])->name('index');
Route::get('/create', [TermsSectionController::class, 'createPage'])->name('create');
Route::post('/', [TermsSectionController::class, 'store'])->name('store');
Route::get('/{section}/edit', [TermsSectionController::class, 'editPage'])->name('edit');
Route::put('/{section}', [TermsSectionController::class, 'update'])->name('update');
Route::get('/{section}/delete', [TermsSectionController::class, 'delete'])->name('delete');
});
});
Route::get('/logout', function () {
......
<?php
namespace Tests\Feature\Controller;
use App\Http\Controllers\Admin\TermsSectionController;
use App\Models\TermsSection;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use PHPUnit\Framework\Attributes\CoversClass;
use Tests\TestCase;
#[CoversClass(TermsSectionController::class)]
class TermsSectionTest extends TestCase
{
use RefreshDatabase, WithoutMiddleware;
public function test_it_can_list_terms_sections()
{
TermsSection::factory()->count(3)->create();
$response = $this->get(route('admin.terms.index'));
$response->assertStatus(200);
$response->assertViewIs('admin.terms.index');
$this->assertCount(3, $response->viewData('sections'));
}
public function test_it_can_create_a_terms_section()
{
$data = [
'lang' => 'fr',
'content' => 'Contenu des CGV',
'active' => 'on',
];
$response = $this->post(route('admin.terms.store'), $data);
$response->assertRedirect(route('admin.terms.index'));
$this->assertDatabaseHas('translations', ['text' => 'Contenu des CGV']);
$this->assertDatabaseHas('terms_sections', ['active' => true]);
}
public function test_it_can_update_a_terms_section()
{
$section = TermsSection::factory()->create();
$data = [
'lang' => 'fr',
'content' => 'Nouveau contenu',
'active' => 'on',
];
$response = $this->put(route('admin.terms.update', $section->id), $data);
$response->assertRedirect();
$this->assertDatabaseHas('translations', ['text' => 'Nouveau contenu']);
$this->assertDatabaseHas('terms_sections', ['active' => true]);
}
public function test_it_can_delete_a_terms_section()
{
$section = TermsSection::factory()->create();
$response = $this->get(route('admin.terms.delete', $section->id));
$response->assertRedirect(route('admin.terms.index'));
$this->assertDatabaseMissing('terms_sections', ['id' => $section->id]);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment