Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Voir cette série
Shop : les pages
Samedi 8 février 2025 16:09

Nous avons bien avancé avec les paramètres de notre boutique dans les articles précédents. Nous avons besoin de donner des informations à nos clients : conditions générales de vente, mentions légales, politique de confidentialité... Il nous faut donc pouvoir créer et modifier des pages contenant ces informations.

Vous pouvez trouver le code dans ce dépôt Github.

Conception du tableau de gestion des pages

Le tableau

Pour faciliter la gestion des pages, nous allons créer un tableau. Ce tableau rassemblera les informations clés de chaque page en un coup d'œil, permettant aux administrateurs de gérer efficacement le contenu. Voici les éléments que nous inclurons dans notre tableau :

  • Titre
  • Slug

En plus de ces informations de base, nous allons envisager d'ajouter une fonctionnalité supplémentaire pour améliorer l'expérience utilisateur :

  • Suppression d'une page

Un composant pour le tableau

Il nous faut maintenant un composant Volt pour afficher le tableau :

php artisan make:volt admin/parameters/pages/index --class

Avec ce code :

<?php

use Livewire\Volt\Component;
use Livewire\Attributes\{Layout, Title};
use App\Models\Page;
use Mary\Traits\Toast;

new 
#[Title('Pages')] 
#[Layout('components.layouts.admin')] 
class extends Component
{
    use Toast;
    
    public array $sortBy = [
        'column' => 'title',
        'direction' => 'asc',
    ];

    public function headers(): array
    {
        return [
            ['key' => 'title', 'label' => __('Title')],
            ['key' => 'slug', 'label' => __('Slug')],
        ];
    }

    public function deletePage(Page $page): void
    {
        $page->delete();
        $this->success(__('Page deleted successfully.'));
    }

    public function with(): array
	{
		return [
            'pages' => Page::orderBy(...array_values($this->sortBy))->get(),			
			'headers' => $this->headers(),
		];
	}
   
}; ?>

<div>
    <x-header title="{{ __('Pages') }}" separator progress-indicator>
        <x-slot:actions>
            <x-button 
                icon="s-building-office-2" 
                label="{{ __('Dashboard') }}" 
                class="btn-outline lg:hidden" 
                link="{{ route('admin') }}" 
            />
            <x-button 
                icon="o-plus" 
                label="{!! __('Create a new page') !!}" 
                link="/admin/pages/create" 
                spinner 
                class="btn-primary" 
            />
        </x-slot:actions>
    </x-header>

    <x-card>
        <x-table 
            striped 
            :headers="$headers" 
            :rows="$pages" 
            :sort-by="$sortBy" 
            link="/admin/pages/{id}/edit"
        >
            @scope('actions', $page)
                <x-popover>
                    <x-slot:trigger>
                        <x-button 
                            icon="o-trash" 
                            wire:click="deletePage({{ $page->id }})" 
                            wire:confirm="{{ __('Are you sure you want to delete this page?') }}" 
                            spinner 
                            class="text-red-500 btn-ghost btn-sm" 
                        />
                    </x-slot:trigger>
                    <x-slot:content class="pop-small">
                        @lang('Delete')
                    </x-slot:content>
                </x-popover>
            @endscope
        </x-table>
    </x-card>
</div>

On ajoute ces traductions :

"Create a new page": "Création d'une nouvelle page",
"Page created successfully.": "Page crée avec succès.",
"Are you sure you want to delete this page?": "Voulez-vous vraiment supprimer cette page ?",
"Page deleted successfully.": "Page supprimée avec succès.",

La route

On ajoute une route pour l'atteindre :

Volt::route('/pages', 'admin.parameters.pages.index')->name('admin.parameters.pages.index');

La navigation

On ajoute un lien dans la barre latérale de l'administration :

 <x-menu-item title="{{ __('Pages') }}" icon="o-document-duplicate" link="{{ route('admin.parameters.pages.index') }}" />

Et on a notre tableau :

Un formulaire pour les pages

On va avoir un formulaire commun pour la création et la modification d'une page. On ajoute une vue partielle pour ce formulaire :

Avec ce simple code :

<x-form wire:submit="save">
    <x-input 
        label="{{ __('Title') }}" 
        wire:model.live.lazy="title" 
        required 
        placeholder="{!! __('Enter page title') !!}" 
    />
    
    <x-input 
        label="{{ __('Slug') }}" 
        wire:model="slug" 
        required 
        placeholder="{{ __('Enter unique slug') }}" 
    />

    <x-editor 
        wire:model="text" 
        label="{{ __('Text') }}" 
        :config="config('tinymce.config_page')" 
        folder="photos" 
    />

    <x-slot:actions>
        <x-button 
            label="{{ __('Save') }}" 
            icon="o-paper-airplane" 
            spinner="save" 
            type="submit" 
            class="btn-primary" 
        />
    </x-slot:actions>
</x-form>

On a une configuration spécifique pour TinyMCE (config.tinymce) :

return [
	...
	'config_page' => [
		'language'       => env('APP_TINYMCE_LOCALE', 'en_US'),
		'plugins'        => 'codesample fullscreen',
		'toolbar'        => 'undo redo style | fontfamily fontsize | alignleft aligncenter alignright alignjustify | bullist numlist | copy cut paste pastetext | hr | codesample | link image quicktable | fullscreen',
		'toolbar_sticky' => true,
		'min_height'     => 1000,
		'license_key'    => 'gpl',
		'valid_elements' => '*[*]',
	],
];

Et on ajoute une traduction :

"Enter page title": "Entrez le titre de la page",

Un trait pour les éléments communs

De la même manière, on va avoir des éléments PHP communs pour la création et la modification d'une page, on crée un trait :

On va y placer les propriétés, une petite fonction et les règles de validation :

<?php

namespace App\Traits;
use Illuminate\Support\Str;

trait ManagePage 
{
    public string $title = '';
    public string $slug = '';
    public string $text = '';

    public function updatedTitle(): void
    {
        $this->slug = Str::slug($this->title);
    }
    
    protected function validatePageData(array $additionalData = []): array
    {
        $pageId = property_exists($this, 'page') && isset($this->page->id) 
            ? ',' . $this->page->id 
            : '';

        $rules = [
            'title' => "required|string|max:100|unique:pages,title{$pageId}",
            'slug' => "required|string|max:50|unique:pages,slug{$pageId}|regex:/^[a-z0-9-]+$/",
            'text' => 'required|string|max:65535',
        ];

        return $this->validate(array_merge($rules, $additionalData));
    }
}

La création d'une page

On crée le composant pour la création d'une page :

php artisan make:volt admin/parameters/pages/create --class

Avec la création précédemment de la vue pour le formulaire et le trait, le code devient bien plus léger dans ce composant :

<?php

use Livewire\Volt\Component;
use Livewire\Attributes\{Layout, Title};
use App\Models\Page;
use Mary\Traits\Toast;
use App\Traits\ManagePage;

new 
#[Title('Page creation')] 
#[Layout('components.layouts.admin')] 
class extends Component
{
    use Toast, ManagePage;

    public function save(): void
    {
        $data = $this->validatePageData();

        Page::create($data);

        $this->success(__('Page created successfully.'), redirectTo: '/admin/pages');
    }
   
}; ?>

<div>
    <x-header title="{!! __('Pages') !!}" separator progress-indicator >
        <x-slot:actions>
            <x-button 
                icon="s-building-office-2" 
                label="{{ __('Dashboard') }}" 
                class="btn-outline lg:hidden" 
                link="{{ route('admin') }}" 
            />
        </x-slot:actions>
    </x-header>
    <x-card title="{!! __('Create a new page') !!}">
        @include('livewire.admin.parameters.pages.form')
    </x-card>
</div>

On ajoute la route :

Volt::route('/states/create', 'admin.parameters.states.create')->name('admin.parameters.states.create');

Une traduction :

"Text": "Texte",

On obtient ce simple formulaire :

J'en suis là !

Vérifiez que tout fonctionne correctement, en particulier la validation.

La modification d'une page

On crée le composant pour la modification d'une page :

php artisan make:volt admin/parameters/pages/edit --class

Avec aussi un code simple :

<?php

use Livewire\Volt\Component;
use Livewire\Attributes\{Layout, Title};
use App\Models\Page;
use Mary\Traits\Toast;
use App\Traits\ManagePage;

new 
#[Title('Page edition')] 
#[Layout('components.layouts.admin')] 
class extends Component
{
    use Toast, ManagePage;
    
    public Page $page;

    public function mount(Page $page): void
    {
        $this->page = $page;
        $this->fill($this->page);
    }

    public function save(): void
    {
        $data = $this->validatePageData();

        $this->page->update($data);

        $this->success(__('Page updated successfully.'), redirectTo: '/admin/pages');
    }
  
}; ?>

<div>
    <x-header title="{!! __('Pages') !!}" separator progress-indicator>
        <x-slot:actions>
            <x-button 
                icon="s-building-office-2" 
                label="{{ __('Dashboard') }}" 
                class="btn-outline lg:hidden" 
                link="{{ route('admin') }}" 
            />
        </x-slot:actions>
    </x-header>
    <x-card title="{!! __('Edit a page') !!}">
        @include('livewire.admin.parameters.pages.form')
    </x-card>
</div>

On ajoute la route :

Volt::route('/pages/{page}/edit', 'admin.parameters.pages.edit')->name('admin.parameters.pages.edit');

Des traductions :

"Edit a page": "Modification d'une page",
"Page updated successfully.": "Page mise à jour avec succès.",

On a le même formulaire que pour la création, mais renseigné avec les données de la page sélectionnée :

Conclusion

On en a fini avec la gestion des pages. Dans la prochaine étape, on s'occupera des frais de port.



Par bestmomo

Nombre de commentaires : 2

Article précédent : Shop : les pays
Article suivant : Shop : les frais de port