Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Voir cette série
Shop : états de commande
Vendredi 7 février 2025 16:34

Nous avons commencé à coder les paramètres de notre boutique dans l'article précédent. Les états de commande constituent une donnée essentielle pour le suivi, pour savoir si le règlement a été effectué, si l'expédition a eu lieu, s'il y a eu une annulation. En gros, c'est la vie d'une commande. On va dans cet article gérer ces états, les modifier et les créer. C'est évidemment une tâche qu'on ne fait en principe qu'une fois à l'installation de la boutique, mais il n'est pas exclu qu'on ajoute un état après coup.

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

Conception du tableau de gestion des états

Le tableau

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

  • Nom
  • Slug
  • Couleur
  • Indice

La notion d'indice est importante, elle marque une hiérarchie dans les étapes de la commande et permet facilement de ne proposer que les options possibles à chaque étape.

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

  • Suppression de l'état

Un composant pour le tableau

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

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

Avec ce code :

<?php

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

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

    public function headers(): array
    {
        return [
            ['key' => 'name', 'label' => __('Name')],
            ['key' => 'slug', 'label' => __('Slug')],
            ['key' => 'color', 'label' => __('Color')],
            ['key' => 'indice', 'label' => __('Index')],
        ];
    }

    public function deleteState(State $state): void
    {
        $state->delete();
        $this->success(__('State deleted successfully.'));
    }

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

<div>
    <x-header title="{{ __('Order status') }}" 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 state') !!}" 
                link="/admin/states/create" 
                spinner 
                class="btn-primary" 
            />
        </x-slot:actions>
    </x-header>

    <x-card>
        <x-table 
            striped 
            :headers="$headers" 
            :rows="$states" 
            :sort-by="$sortBy" 
            link="/admin/states/{id}/edit"
        >
            @scope('cell_color', $state)
                <x-badge value="   " class="px-6 py-2 bg-{{ $state->color }}-400" />
            @endscope

            @scope('actions', $state)
                <x-popover>
                    <x-slot:trigger>
                        <x-button 
                            icon="o-trash" 
                            wire:click="deleteState({{ $state->id }})" 
                            wire:confirm="{{ __('Are you sure you want to delete this state?') }}" 
                            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 :

"Color": "Couleur",
"Are you sure you want to delete this state?": "Voulez-vous vraiment supprimer cet état ?",
"Create a new state": "Création d'un nouvel état de commande",

La route

On ajoute une route pour l'atteindre :

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

La navigation

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

<x-menu-item title="{{ __('Order status') }}" icon="m-eye" link="{{ route('admin.parameters.states.index') }}" />

Une petite traduction :

"Order status": "Etats de commande",

Et on a notre tableau :

Un formulaire pour les états

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

Avec ce simple code :

<x-form wire:submit="save">
    <x-input 
        label="{{ __('Name') }}" 
        wire:model="name" 
        required 
        placeholder="{!! __('Enter state name') !!}" 
    />
    
    <x-input 
        label="{{ __('Slug') }}" 
        wire:model="slug" 
        required 
        placeholder="{{ __('Enter unique slug') }}" 
    />

    <x-input 
        type="number" 
        label="{{ __('Indice') }}" 
        wire:model="indice" 
        required 
    />
    
    <x-select 
        label="{{ __('Color') }}" 
        wire:model="color" 
        :options="$colors" 
        required 
    />

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

Évidemment d'autres traductions :

"Enter state name": "Entrez le nom de l'etat de commande",
"Enter unique slug": "Entrez un slug unique",

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'un état, on crée un trait :

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

<?php

namespace App\Traits;

trait ManageState 
{
    public string $name;
    public string $slug;
    public string $color = 'blue';
    public string $indice = '0';
    
    public function with(): array
    {
        return [
            'colors' => [
                [ 'name' => __('Blue'), 'id' => 'blue' ],
                [ 'name' => __('Red'), 'id' => 'red' ],
                [ 'name' => __('Green'), 'id' => 'green' ],
                [ 'name' => __('Gray'), 'id' => 'gray' ],
            ],
        ];
    }

    protected function validateStateData(array $additionalData = []): array
    {
        $stateId = property_exists($this, 'state') && isset($this->state->id) 
            ? ',' . $this->state->id 
            : '';

        $rules = [
            'name' => "required|string|max:100|unique:states,name{$stateId}",
            'slug' => "required|string|max:50|unique:states,slug{$stateId}|regex:/^[a-z0-9-]+$/",
            'color' => 'required|string|max:20|in:blue,red,green,gray',
            'indice' => 'required|numeric|min:0|max:20',
        ];

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

On a besoin de traductions pour les couleurs :

"Blue": "Bleu",
"Red": "Rouge",
"Green": "Vert",
"Gray": "Gris",

La création d'un état

On crée le composant pour la création d'un état :

php artisan make:volt admin/parameters/states/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\State;
use Mary\Traits\Toast;
use App\Traits\ManageState;

new 
#[Title('State creation')] 
#[Layout('components.layouts.admin')] 
class extends Component
{
    use Toast, ManageState;
    
    public State $state;

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

        State::create($data);

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

<div>
    <x-header title="{!! __('Order status') !!}" 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 state') !!}">
        @include('livewire.admin.parameters.states.form')
    </x-card>
</div>

On ajoute la route :

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

Une traduction :

"State created successfully.": "Etat créé avec succès.",

On obtient ce simple formulaire :

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

La modification d'un état

On crée le composant pour la modification d'un état :

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

Avec aussi un code simple :

<?php

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

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

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

    public function save(): void
    {
        $data = $this->validateStateData();
        
        $this->state->update($data);

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

<div>
    <x-header title="{!! __('Order status') !!}" 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="{!! __('Modifying a state') !!}">
        @include('livewire.admin.parameters.states.form')
    </x-card>
</div>

On ajoute la route :

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

Des traductions :

"Modifying a state": "Modification d'un état de commande",
"State updated successfully.": "Etat mis à jour avec succès.",

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

Conclusion

On en a fini avec la gestion des états. Dans la prochaine étape, on s'occupera des pays.



Par bestmomo

Aucun commentaire

Article précédent : Shop : la boutique
Article suivant : Shop : les pays