diff --git a/migrations/Version20260121132344.php b/migrations/Version20260121132344.php new file mode 100644 index 0000000..1855159 --- /dev/null +++ b/migrations/Version20260121132344.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE product ADD description TEXT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE product DROP description'); + } +} diff --git a/migrations/Version20260121132406.php b/migrations/Version20260121132406.php new file mode 100644 index 0000000..efa4712 --- /dev/null +++ b/migrations/Version20260121132406.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE product ADD qt INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE product DROP qt'); + } +} diff --git a/src/Entity/Product.php b/src/Entity/Product.php index faca38d..1109cbe 100644 --- a/src/Entity/Product.php +++ b/src/Entity/Product.php @@ -6,6 +6,7 @@ use App\Repository\ProductRepository; use Cocur\Slugify\Slugify; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\HttpFoundation\File\File; use Vich\UploaderBundle\Mapping\Attribute\Uploadable; @@ -68,6 +69,12 @@ class Product #[ORM\OneToMany(targetEntity: ProductReserve::class, mappedBy: 'product')] private Collection $productReserves; + #[ORM\Column(type: Types::TEXT, nullable: true)] + private ?string $description = null; + + #[ORM\Column(nullable: true)] + private ?int $qt = null; + public function __construct() { $this->devisLines = new ArrayCollection(); @@ -285,4 +292,28 @@ class Product return $this; } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getQt(): ?int + { + return $this->qt; + } + + public function setQt(?int $qt): static + { + $this->qt = $qt; + + return $this; + } } diff --git a/src/Form/ProductType.php b/src/Form/ProductType.php index 348e39c..0faa1f3 100644 --- a/src/Form/ProductType.php +++ b/src/Form/ProductType.php @@ -10,6 +10,7 @@ use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\TelType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -27,9 +28,21 @@ class ProductType extends AbstractType 'label' => 'Reference du produit', 'required' => true, ]) - ->add('category',TextType::class,[ + ->add('description',TextareaType::class,[ + 'label' => 'Description du produit', + 'required' => false, + ]) + ->add('category',ChoiceType::class,[ 'label' => 'Catégorie du produit', 'required' => true, + 'choices' => [ + '2-7 Ans' =>'2-7 ans', + '3-15 Ans' =>'3-15 ans', + '3-99 Ans' =>'3-99 ans', + 'Barnums' =>'barnums', + 'Alimentaire' =>'alimentaire', + 'Options' =>'options', + ] ]) ->add('caution',NumberType::class,[ 'label' => 'Caution du produit', diff --git a/templates/dashboard/products/add.twig b/templates/dashboard/products/add.twig index 957068e..62587b6 100644 --- a/templates/dashboard/products/add.twig +++ b/templates/dashboard/products/add.twig @@ -73,6 +73,21 @@ {{ form_widget(form.ref, {'attr': {'placeholder': 'REF-000', 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white font-mono focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5'}}) }} + {# À placer juste après le bloc Référence Interne #} +
+ {{ form_label(form.description, 'Description détaillée', {'label_attr': {'class': 'text-[10px] font-black text-slate-500 uppercase tracking-[0.2em] ml-1 mb-2 block'}}) }} + {{ form_widget(form.description, { + 'attr': { + 'class': 'w-full bg-slate-900/50 border-white/5 rounded-2xl text-white focus:ring-blue-500/20 focus:border-blue-500 transition-all py-3.5 px-5 min-h-[150px]', + 'placeholder': 'Décrivez les dimensions, la capacité, les points forts...' + } + }) }} + {% if form_errors(form.description) %} +
+ {{ form_errors(form.description) }} +
+ {% endif %} +
diff --git a/templates/revervation/catalogue.twig b/templates/revervation/catalogue.twig index c836031..6db50a4 100644 --- a/templates/revervation/catalogue.twig +++ b/templates/revervation/catalogue.twig @@ -40,8 +40,8 @@ {% set categories_list = [ - {'id': '3-15 ans', 'label': '3-15 ANS', 'hover': 'hover:border-blue-600 hover:text-blue-600'}, {'id': '2-7 ans', 'label': '2-7 ANS', 'hover': 'hover:border-amber-500 hover:text-amber-500'}, + {'id': '3-15 ans', 'label': '3-15 ANS', 'hover': 'hover:border-blue-600 hover:text-blue-600'}, {'id': '3-99 ans', 'label': '3-99 ANS', 'hover': 'hover:border-indigo-600 hover:text-indigo-600'}, {'id': 'barnums', 'label': 'BARNUMS', 'hover': 'hover:border-slate-800 hover:text-slate-800'}, {'id': 'alimentaire', 'label': 'ALIMENTAIRE', 'hover': 'hover:border-rose-500 hover:text-rose-500'}, diff --git a/templates/revervation/home.twig b/templates/revervation/home.twig index d1f6ad4..91aee8b 100644 --- a/templates/revervation/home.twig +++ b/templates/revervation/home.twig @@ -155,7 +155,7 @@
- + Réserver ce bonheur
diff --git a/templates/revervation/produit.twig b/templates/revervation/produit.twig index 86d92dd..c7eb8c6 100644 --- a/templates/revervation/produit.twig +++ b/templates/revervation/produit.twig @@ -1,7 +1,41 @@ {% extends 'revervation/base.twig' %} +{# --- SEO DYNAMIQUE & META-DONNÉES --- #} {% block title %}{{ product.name }} - Location Ludikevent{% endblock %} +{% block description %} + Louez {{ product.name }} chez Ludikevent. Idéal pour les enfants ({{ product.category }}), + cette structure est disponible à partir de {{ product.priceDay }}€ la journée. + {{ product.description|striptags|slice(0, 150) }}... + Vérifiez la disponibilité en ligne ! +{% endblock %} +{% block jsonld %} + +{% endblock %} {% block breadcrumb_json %} ,{ "@type": "ListItem", @@ -17,6 +51,7 @@ {% endblock %} {% block body %} + {# --- TRACKING ÉVÉNEMENT --- #}
@@ -78,8 +113,8 @@
{# Prix principal #} -
f - {{ product.priceDay }}€ +
+ {{ product.priceDay }}€ La première journée
@@ -91,6 +126,11 @@
+ {# --- DESCRIPTION --- #} +
+ {{ product.description|raw }} +
+
{# Badge Âge #} @@ -116,7 +156,7 @@
- {# --- ACTION --- #} + {# --- ACTION FINALE --- #}
@@ -132,7 +172,7 @@
- {# --- SECTION SUGGESTIONS --- #} + {# --- SECTION SUGGESTIONS (CROSS-SELLING) --- #}