Browse Source

modifications sur le planning et modèle pour disponibilités

garthh 3 weeks ago
parent
commit
bb3ff241d8

+ 0 - 1
assets/controllers/datatables_controller.js

@@ -6,7 +6,6 @@ export default class extends Controller {
   async connect() {
     console.log('Stimulus: datatable détecté');
 
-
     // Vérifie si DataTable a déjà été initialisé via un attribut
     if (this.element.dataset.datatableInitialized === 'true') {
       console.log('Déjà initialisé — on ne refait rien');

+ 60 - 0
assets/controllers/planning_controller.js

@@ -0,0 +1,60 @@
+import { Controller } from '@hotwired/stimulus';
+
+export default class extends Controller {
+
+    connect() {
+        console.log("Stimulus: contrôleur de planning actif");
+
+        this.arrows = this.element.querySelectorAll('[data-id]');
+        this.showAll = this.element.querySelector('[data-store]');
+        this.containers = document.querySelectorAll('.period-panel');
+
+        this.arrows.forEach(arrow => {
+            arrow.addEventListener('click', (event) => {
+                event.preventDefault();
+                this.activatePanel(arrow);
+            });
+        });
+
+        this.showAll.addEventListener('click', (event)=> {
+            event.preventDefault();
+            this.togglePanels();
+        }) 
+    }
+
+    activatePanel(selectedPanel) {
+        const targetId = selectedPanel.dataset.id;
+
+        // Affichage du bon bloc
+        this.containers.forEach(container => {
+            if (container.id === targetId) {
+                container.classList.remove('is-hidden');
+                this.showAll.dataset.store = container.id;
+
+            } else {
+                container.classList.add('is-hidden');
+            }
+        });
+    }
+
+    togglePanels() {
+        if (this.showAll.dataset.action == "show") {
+            this.containers.forEach(container => {
+                container.classList.remove('is-hidden');
+                this.showAll.dataset.action = "hide";
+                this.showAll.innerHTML = 'Cacher les autres périodes';
+            });
+        } else {
+            this.containers.forEach(container => {
+                if (container.id === this.showAll.dataset.store) {
+                    container.classList.remove('is-hidden');
+                } else {
+                    container.classList.add('is-hidden');
+                }
+            });
+            this.showAll.dataset.action = "show";
+            this.showAll.innerHTML = 'Afficher toutes les périodes à la suite';            
+        }
+        
+    }
+}

+ 8 - 65
assets/styles/app.css

@@ -49,59 +49,6 @@
 
 /* Styles pour les plannings */
 
-/* Style par défaut pour les cellules
-.planning-cell {
-  display: flex;
-  align-items: center;       
-  justify-content: center;  
-  height: 3rem;             
-  text-align: center;
-  padding: 0.5rem;
-  box-sizing: border-box;
-  overflow: hidden;        
-  white-space: nowrap;       
-  text-overflow: ellipsis;  
-}
-
-/* Style pour les cellules d'entête 
-.planning-cell-heading {
-    background: black;
-    color: white;
-    font-weight: bold;
-    border-bottom: 1px solid white;
-}
-
-/* Style pour les cellules pleine largeur (ex. en-tête de périodes)
-.planning-cell-wide {
-    background: lightgray;
-    border-bottom: 1px solid white;
-
-}
-
-/* Style pour les cellules disponibles 
-.planning-cell-free {
-    border-bottom: 1px solid lightgray;
-
-}
-
-/* Style pour les cellules vérouillées 
-.planning-cell-locked {
-    background-color: gray;
-    color: white;
-    border-bottom: 1px solid lightgray;
-
-}
-
-/* Style pour les cellules masquées 
-.planning-cell-hidden {
-    background-color: none;
-    border-bottom: 1px solid lightgray;
-}
-
-
-
-
-
 /* Base styles for all planning cells */
 
 :root {
@@ -109,13 +56,9 @@
 }
 
 .planning-cell {
-  height: calc(4rem * var(--height-multiplier)); }
-
-.planning-cell {
+  height: calc(4rem * var(--height-multiplier));
   display: flex;
   align-items: center;
-  /*justify-content: center;*/
-
   padding: 0.5rem;
   box-sizing: border-box;
   overflow: hidden;
@@ -134,12 +77,16 @@
 }
 
 /* Wide header cells (e.g., time columns) */
-.planning-cell-wide {
-  font-weight: 500;
+.planning-cell-period {
+  font-weight: 600;
   border-bottom: 1px solid #ccc;
   z-index: 0;
 }
 
+.planning-cell-force-large {
+  width: 100%;
+}
+
 /* Free (available) slot */
 .planning-cell-free {
   border-bottom: 1px solid #ccc;
@@ -153,11 +100,7 @@
   border-bottom: 1px solid #ccc;
   z-index: 0;
   justify-content: center;
-  background-image: url('data:image/svg+xml;utf8,\
-<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" fill="none" stroke="%23ccc" stroke-width="1" stroke-opacity="0.66">\
-<path d="M0 8 L8 0"/>\
-</svg>');
-    );
+  background-image: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" fill="none" stroke="%23ccc" stroke-width="1" stroke-opacity="0.66"><path d="M0 8 L8 0"/></svg>');
 }
 
 /* Hidden slot */

+ 37 - 0
migrations/Version20250810044833.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20250810044833 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE TABLE availability (id INT AUTO_INCREMENT NOT NULL, event_id BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid)\', gamemaster_id BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid)\', period_id INT NOT NULL, start_on DATETIME NOT NULL, end_on DATETIME NOT NULL, available TINYINT(1) NOT NULL, INDEX IDX_3FB7A2BF71F7E88B (event_id), INDEX IDX_3FB7A2BF96376157 (gamemaster_id), INDEX IDX_3FB7A2BFEC8B7ADE (period_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+        $this->addSql('ALTER TABLE availability ADD CONSTRAINT FK_3FB7A2BF71F7E88B FOREIGN KEY (event_id) REFERENCES event (id)');
+        $this->addSql('ALTER TABLE availability ADD CONSTRAINT FK_3FB7A2BF96376157 FOREIGN KEY (gamemaster_id) REFERENCES gamemaster (id)');
+        $this->addSql('ALTER TABLE availability ADD CONSTRAINT FK_3FB7A2BFEC8B7ADE FOREIGN KEY (period_id) REFERENCES period (id)');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE availability DROP FOREIGN KEY FK_3FB7A2BF71F7E88B');
+        $this->addSql('ALTER TABLE availability DROP FOREIGN KEY FK_3FB7A2BF96376157');
+        $this->addSql('ALTER TABLE availability DROP FOREIGN KEY FK_3FB7A2BFEC8B7ADE');
+        $this->addSql('DROP TABLE availability');
+    }
+}

+ 31 - 0
migrations/Version20250810045142.php

@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20250810045142 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE availability CHANGE id id BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid)\'');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE availability CHANGE id id INT AUTO_INCREMENT NOT NULL');
+    }
+}

+ 120 - 0
src/Entity/Availability.php

@@ -0,0 +1,120 @@
+<?php
+
+namespace App\Entity;
+
+use App\Repository\AvailabilityRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use Doctrine\DBAL\Types\Types;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Bridge\Doctrine\Types\UuidType;
+use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
+use Symfony\Component\Uid\Uuid;
+
+#[ORM\Entity(repositoryClass: AvailabilityRepository::class)]
+class Availability
+{
+    #[ORM\Id]
+    #[ORM\Column(type: UuidType::NAME, unique: true)]
+    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
+    #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
+    private ?Uuid $id = null;
+
+    #[ORM\ManyToOne(inversedBy: 'availabilities')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Event $event = null;
+
+    #[ORM\ManyToOne(inversedBy: 'availabilities')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Gamemaster $gamemaster = null;
+
+    #[ORM\ManyToOne(inversedBy: 'availabilities')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?Period $period = null;
+
+    #[ORM\Column]
+    private ?\DateTime $startOn = null;
+
+    #[ORM\Column]
+    private ?\DateTime $endOn = null;
+
+    #[ORM\Column]
+    private ?bool $available = null;
+
+    public function getId(): ?Uuid
+    {
+        return $this->id;
+    }
+
+    public function getEvent(): ?Event
+    {
+        return $this->event;
+    }
+
+    public function setEvent(?Event $event): static
+    {
+        $this->event = $event;
+
+        return $this;
+    }
+
+    public function getGamemaster(): ?Gamemaster
+    {
+        return $this->gamemaster;
+    }
+
+    public function setGamemaster(?Gamemaster $gamemaster): static
+    {
+        $this->gamemaster = $gamemaster;
+
+        return $this;
+    }
+
+    public function getPeriod(): ?Period
+    {
+        return $this->period;
+    }
+
+    public function setPeriod(?Period $period): static
+    {
+        $this->period = $period;
+
+        return $this;
+    }
+
+    public function getStartOn(): ?\DateTime
+    {
+        return $this->startOn;
+    }
+
+    public function setStartOn(\DateTime $startOn): static
+    {
+        $this->startOn = $startOn;
+
+        return $this;
+    }
+
+    public function getEndOn(): ?\DateTime
+    {
+        return $this->endOn;
+    }
+
+    public function setEndOn(\DateTime $endOn): static
+    {
+        $this->endOn = $endOn;
+
+        return $this;
+    }
+
+    public function isAvailable(): ?bool
+    {
+        return $this->available;
+    }
+
+    public function setAvailable(bool $available): static
+    {
+        $this->available = $available;
+
+        return $this;
+    }
+}

+ 37 - 0
src/Entity/Event.php

@@ -95,6 +95,12 @@ class Event
     #[ORM\OneToMany(targetEntity: PartyRequest::class, mappedBy: 'event', orphanRemoval: true)]
     private Collection $partyRequests;
 
+    /**
+     * @var Collection<int, Availability>
+     */
+    #[ORM\OneToMany(targetEntity: Availability::class, mappedBy: 'event', orphanRemoval: true)]
+    private Collection $availabilities;
+
     public function __construct()
     {
         $this->spaces = new ArrayCollection();
@@ -104,6 +110,7 @@ class Event
         $this->gameAssigned = new ArrayCollection();
         $this->parties = new ArrayCollection();
         $this->partyRequests = new ArrayCollection();
+        $this->availabilities = new ArrayCollection();
     }
 
     public function getId(): ?Uuid
@@ -440,4 +447,34 @@ class Event
 
         return $this;
     }
+
+    /**
+     * @return Collection<int, Availability>
+     */
+    public function getAvailabilities(): Collection
+    {
+        return $this->availabilities;
+    }
+
+    public function addAvailability(Availability $availability): static
+    {
+        if (!$this->availabilities->contains($availability)) {
+            $this->availabilities->add($availability);
+            $availability->setEvent($this);
+        }
+
+        return $this;
+    }
+
+    public function removeAvailability(Availability $availability): static
+    {
+        if ($this->availabilities->removeElement($availability)) {
+            // set the owning side to null (unless already changed)
+            if ($availability->getEvent() === $this) {
+                $availability->setEvent(null);
+            }
+        }
+
+        return $this;
+    }
 }

+ 37 - 0
src/Entity/Gamemaster.php

@@ -72,11 +72,18 @@ class Gamemaster
     #[ORM\OneToMany(targetEntity: Party::class, mappedBy: 'gamemaster')]
     private Collection $parties;
 
+    /**
+     * @var Collection<int, Availability>
+     */
+    #[ORM\OneToMany(targetEntity: Availability::class, mappedBy: 'gamemaster', orphanRemoval: true)]
+    private Collection $availabilities;
+
     public function __construct()
     {
         $this->gamesCanMaster = new ArrayCollection();
         $this->eventsAssignedTo = new ArrayCollection();
         $this->parties = new ArrayCollection();
+        $this->availabilities = new ArrayCollection();
     }
 
     public function getId(): ?Uuid
@@ -295,5 +302,35 @@ class Gamemaster
         return $this;
     }
 
+    /**
+     * @return Collection<int, Availability>
+     */
+    public function getAvailabilities(): Collection
+    {
+        return $this->availabilities;
+    }
+
+    public function addAvailability(Availability $availability): static
+    {
+        if (!$this->availabilities->contains($availability)) {
+            $this->availabilities->add($availability);
+            $availability->setGamemaster($this);
+        }
+
+        return $this;
+    }
+
+    public function removeAvailability(Availability $availability): static
+    {
+        if ($this->availabilities->removeElement($availability)) {
+            // set the owning side to null (unless already changed)
+            if ($availability->getGamemaster() === $this) {
+                $availability->setGamemaster(null);
+            }
+        }
+
+        return $this;
+    }
+
 
 }

+ 43 - 0
src/Entity/Period.php

@@ -3,6 +3,8 @@
 namespace App\Entity;
 
 use App\Repository\PeriodRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
 
 #[ORM\Entity(repositoryClass: PeriodRepository::class)]
@@ -26,6 +28,17 @@ class Period
     #[ORM\Column(nullable: true)]
     private ?bool $locked = null;
 
+    /**
+     * @var Collection<int, Availability>
+     */
+    #[ORM\OneToMany(targetEntity: Availability::class, mappedBy: 'period', orphanRemoval: true)]
+    private Collection $availabilities;
+
+    public function __construct()
+    {
+        $this->availabilities = new ArrayCollection();
+    }
+
     public function getId(): ?int
     {
         return $this->id;
@@ -78,4 +91,34 @@ class Period
 
         return $this;
     }
+
+    /**
+     * @return Collection<int, Availability>
+     */
+    public function getAvailabilities(): Collection
+    {
+        return $this->availabilities;
+    }
+
+    public function addAvailability(Availability $availability): static
+    {
+        if (!$this->availabilities->contains($availability)) {
+            $this->availabilities->add($availability);
+            $availability->setPeriod($this);
+        }
+
+        return $this;
+    }
+
+    public function removeAvailability(Availability $availability): static
+    {
+        if ($this->availabilities->removeElement($availability)) {
+            // set the owning side to null (unless already changed)
+            if ($availability->getPeriod() === $this) {
+                $availability->setPeriod(null);
+            }
+        }
+
+        return $this;
+    }
 }

+ 43 - 0
src/Repository/AvailabilityRepository.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\Availability;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @extends ServiceEntityRepository<Availability>
+ */
+class AvailabilityRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, Availability::class);
+    }
+
+    //    /**
+    //     * @return Availability[] Returns an array of Availability objects
+    //     */
+    //    public function findByExampleField($value): array
+    //    {
+    //        return $this->createQueryBuilder('a')
+    //            ->andWhere('a.exampleField = :val')
+    //            ->setParameter('val', $value)
+    //            ->orderBy('a.id', 'ASC')
+    //            ->setMaxResults(10)
+    //            ->getQuery()
+    //            ->getResult()
+    //        ;
+    //    }
+
+    //    public function findOneBySomeField($value): ?Availability
+    //    {
+    //        return $this->createQueryBuilder('a')
+    //            ->andWhere('a.exampleField = :val')
+    //            ->setParameter('val', $value)
+    //            ->getQuery()
+    //            ->getOneOrNullResult()
+    //        ;
+    //    }
+}

+ 101 - 99
templates/components/Planning.html.twig

@@ -3,7 +3,7 @@
 {% set cols = event.getSpaces()|length +1 %}
 
 {# début du block de grille #}
-<div class="block">
+<div class="block" {{ stimulus_controller('planning') }}>
     {# Nombre de colonnes = nombre d'espaces + colonne d'intro #}
     <div class="fixed-grid has-{{ cols }}-cols">
         <div class="grid is-gap-0">
@@ -17,114 +17,116 @@
                 {{ space.name }}
             </div>
             {% endfor %}
+        </div>
+    </div>
+
+    {# On ajoute les horaires période par période #}
+    {% set i=0 %}
+    {% for period in event.getPeriods() %}
+    <div class="fixed-grid has-{{ cols }}-cols period-panel{% if i>0 %} is-hidden{% endif %}" id="#period-{{ period.id }}">
+        <div class="grid is-gap-0">
+            <div class="cell planning-cell planning-cell-period is-col-span-{{ cols }} has-text-centered">
+                {% if i > 0 %}<span class="icon period-controler" data-id="#period-{{ event.getPeriods()[i-1].id }}"><twig:ux:icon name='bi:arrow-left-circle'/></span>{% endif %}<div class="planning-cell-force-large has-text-centered">Période du {{ period.startOn|date('d/m/Y \\d\\e H:i', app_timezone) }} à {{ period.endOn|date('H:i', app_timezone) }}</div>{% if i+1 < event.getPeriods()|length %}<span class="icon period-controler"  data-id="#period-{{ event.getPeriods()[i+1].id }}"><twig:ux:icon name='bi:arrow-right-circle'/></span>{% endif %}
+                {% set i=i+1 %}
+            </div>
 
-            {# On ajoute les horaires période par période #}
-            {% for period in event.getPeriods() %}
-                <div class="cell planning-cell planning-cell-wide is-col-span-{{ cols }}">
-                    Période du {{ period.startOn|date('d/m/Y H:i', app_timezone) }} à {{ period.endOn|date('H:i', app_timezone) }}
-                </div>
+            {# On affiche tous les slots de la période, space par space #}
+            {% for dateRef in this.getDateOrdered(period) %}
+            <div class="cell planning-cell planning-cell-heading">
+                {{ dateRef|date('H:i', app_timezone) }}
+            </div>
+                {% for space in event.getSpaces() %}
+                {# extraction du slot de cet espace, ce moment et cette période #}
+                {% set thisSlot = this.getThisSlotInfo(dateRef, space, period) %}
 
-                {# On affiche tous les slots de la période, space par space #}
-                {% for dateRef in this.getDateOrdered(period) %}
-                    <div class="cell planning-cell planning-cell-heading">
-                        {{ dateRef|date('H:i', app_timezone) }}
+                {# --CASE1-- si le slot est Indisponible #}
+                {% if thisSlot.unavailable %}
+                    {% if displayLocked %}
+                    <div class="cell planning-cell planning-cell-locked  has-text-centered" data-id="{{ thisSlot.id }}">
+                        <div class="icon"><twig:ux:icon name="bi:lock-fill" /></div>
+                    </div>
+                    {% else %}
+                    <div class="cell planning-cell planning-cell-locked">
                     </div>
-                    {% for space in event.getSpaces() %}
-                        {# extraction du slot de cet espace, ce moment et cette période #}
-                        {# set thisSlot = this.getThisSlot(dateRef, space, period) #}
-                        {% set thisSlot = this.getThisSlotInfo(dateRef, space, period) %}
+                    {% endif %}
+                {% endif %}
 
-                        {# si le slot est Indisponible #}
-                        {% if thisSlot.unavailable %}
-                            {% if displayLocked %}
-                            <div class="cell planning-cell planning-cell-locked  has-text-centered" data-id="{{ thisSlot.id }}">
-                                <div class="icon"><twig:ux:icon name="bi:lock-fill" /></div>
-                            </div>
-                            {% else %}
-                            <div class="cell planning-cell planning-cell-locked">
+                {# --CASE2 -- si une partie est sur le slot #}
+                {% if thisSlot.party  %}
+                    {% if thisSlot.party.isValidated or displayUnvalidates %}
+                        {% if thisSlot == thisSlot.party.slots[0] %}
+                        {# Premier slot d'une partie ou partie non validée #}
+                        <div class="cell planning-cell planning-cell-game-parent">
+                            <div class="planning-cell-game {% if thisSlot.party.getSeatsLeft < 1 %}planning-cell-game-isfull {% endif %}{% if pathFullSlot %} open-modal" href="{{ path(pathFullSlot, {id: thisSlot.id}) }}"{% else %}"{% endif %} style="height: {{ thisSlot.party.slots|length * 4 * app_hmult }}rem !important">
+                                {# Carte "jeu" DEBUT #}
+                                <div class="card has-background-primary-45 has-text-primary-45-invert" style="{% if thisSlot.party.game.picture %}background-image: url('/images/games/{{ thisSlot.party.game.picture }}');{% endif %} height: {{ thisSlot.party.slots|length * 4 * app_hmult - 0.7 }}rem !important; {% if not thisSlot.party.isValidated %}filter:grayscale(1) opacity(0.3);{% endif %};">
+                                    <div class="card-header">
+                                        <div class="media">
+                                            <div class="media-left">
+                                                <figure class="image is-48x48">
+                                                    {% if thisSlot.party.gamemaster.picture %}
+                                                    <img class="is-rounded" src="/images/gamemasters/{{ thisSlot.party.gamemaster.picture }}"  />
+                                                    {% else %}
+                                                    <twig:ux:icon name="bi:person-fill"/>
+                                                    {% endif %}
+                                                </figure>
+                                            </div>
+                                        </div>
+                                        <div class="media-content">
+                                            <small class="has-text-grey-darker">{{ thisSlot.party.gamemaster.preferedName }}</small><br/>
+                                            <span class="title is-6 has-text-primary-45-invert">{{ thisSlot.party.game.name }}</span>
+                                        </div>
+                                    </div>
+                                    <div class="card-content">
+                                        <p><span class="tag is-dark m-1">Places : {{ thisSlot.party.getSeatsLeft }}/{{ thisSlot.party.getMaxParticipants }}</span></p>
+                                        {% if thisSlot.party.gamemasterIsAuthor %}<p><span class="tag is-warning m-1">partie animée par l'auteur</span></p>{% endif %}
+                                        <p>{% for genre in thisSlot.party.game.genre %}<span class="tag is-info m-1">{{ genre.genre }}</span>{% endfor %}</p>
+                                    </div>
+                                    {% if pathFullSlot %}</a>{% endif %}
+                                </div>                             
+                                {# Carte "jeu" FIN #}
                             </div>
-                            {% endif %}
+                        </div>
+                        {% else %}
+                        {# Slot suivant d'une partie #}
+                        <div class="cell planning-cell planning-cell-game-parent">
+                        </div>
                         {% endif %}
-                        {# si une partie est sur le slot #}
-                        {% if thisSlot.party  %}
-                            {% if thisSlot.party.isValidated or displayUnvalidates %}
-                                {% if thisSlot == thisSlot.party.slots[0] %}
-                                {# Premier slot d'une partie ou partie non validée #}
-                                <div class="cell planning-cell planning-cell-game-parent">
-                                    <div class="planning-cell-game {% if thisSlot.party.getSeatsLeft < 1 %}planning-cell-game-isfull {% endif %}{% if pathFullSlot %} open-modal" href="{{ path(pathFullSlot, {id: thisSlot.id}) }}"{% else %}"{% endif %} style="height: {{ thisSlot.party.slots|length * 4 * app_hmult }}rem !important">
-                                      {# Carte "jeu" DEBUT #}
-                                        <div class="card has-background-primary-45 has-text-primary-45-invert" style="{% if thisSlot.party.game.picture %}background-image: url('/images/games/{{ thisSlot.party.game.picture }}');{% endif %} height: {{ thisSlot.party.slots|length * 4 * app_hmult - 0.7 }}rem !important; {% if not thisSlot.party.isValidated %}filter:grayscale(1) opacity(0.3);{% endif %};">
-                                            
-                                                <div class="card-header">
-                                                    <div class="media">
-                                                        <div class="media-left">
-                                                            <figure class="image is-48x48">
-                                                                
-                                                                {% if thisSlot.party.gamemaster.picture %}
-                                                                <img class="is-rounded" src="/images/gamemasters/{{ thisSlot.party.gamemaster.picture }}"  />
-                                                                {% else %}
-                                                                <twig:ux:icon name="bi:person-fill"/>
-                                                                {% endif %}
-                                                                
-                                                            </figure>
-                                                        </div>
-                                                    </div>
-                                                        <div class="media-content">
-                                                            <small class="hax-text-grey-light">{{ thisSlot.party.gamemaster.preferedName }}</small><br/>
-                                                            <span class="title is-6 has-text-primary-45-invert">{{ thisSlot.party.game.name }}</span>
-                                                            
-                                                        </div>
+                    {% else %}
+                        {# Partie non validée masquée #}
+                        <div class="cell planning-cell planning-cell-free">
+                        </div>
+                    {% endif %}
+                {% endif %}
+                {# --CASE3-- si le slot est disponible et sans partie #}
+                {% if not thisSlot.unavailable and not thisSlot.party %}
+                    {% if pathEmptySlot %}
+                    <a href="{{ path(pathEmptySlot, {id: thisSlot.id}) }}"  class="open-modal">
+                        <div class="cell planning-cell planning-cell-free has-text-centered" data-id="{{ thisSlot.id }}">
+                            <div class="icon"><twig:ux:icon name="bi:plus-circle" /></div>
+                        </div>
+                    </a>
+                    {% elseif displayLocked %}
+                    <div class="cell planning-cell planning-cell-free has-text-centered" data-id="{{ thisSlot.id }}">
+                        <div class="icon"><twig:ux:icon name="bi:unlock-fill" /></div>
+                    </div>
+                    {% else %}
+                    <div class="cell planning-cell planning-cell-free" data-id="{{ thisSlot.id }}">
+                    </div>                            
+                    {% endif %}
 
-                                                </div>
-                                                <div class="card-content">
-                                                    <p><span class="tag is-dark m-1">Places : {{ thisSlot.party.getSeatsLeft }}/{{ thisSlot.party.getMaxParticipants }}</span></p>
-                                                    {% if thisSlot.party.gamemasterIsAuthor %}<p><span class="tag is-warning m-1">partie animée par l'auteur</span></p>{% endif %}
-                                                    <p>{% for genre in thisSlot.party.game.genre %}<span class="tag is-info m-1">{{ genre.genre }}</span>{% endfor %}</p>
-                                                    
-                                                </div>
+                {% endif %}               
 
-                                            {% if pathFullSlot %}</a>{% endif %}
-                                        </div>                             
-                                      {# Carte "jeu" FIN #}
-                                    </div>
-                                </div>
-                                {% else %}
-                                {# Slot suivant d'une partie #}
-                                <div class="cell planning-cell planning-cell-game-parent">
-                                </div>
-                                {% endif %}
-                            {% else %}
-                                {# Partie non validée masquée #}
-                                <div class="cell planning-cell planning-cell-free">
-                                </div>
-                            {% endif %}
-                        {% endif %}
-                        {# si le slot est disponible et sans partie #}
-                        {% if not thisSlot.unavailable and not thisSlot.party %}
-                            {% if pathEmptySlot %}
-                            <a href="{{ path(pathEmptySlot, {id: thisSlot.id}) }}"  class="open-modal">
-                            <div class="cell planning-cell planning-cell-free has-text-centered" data-id="{{ thisSlot.id }}">
-                                <div class="icon"><twig:ux:icon name="bi:plus-circle" /></div>
-                            </div>
-                            </a>
-                            {% elseif displayLocked %}
-                            <div class="cell planning-cell planning-cell-free has-text-centered" data-id="{{ thisSlot.id }}">
-                                <div class="icon"><twig:ux:icon name="bi:unlock-fill" /></div>
-                            </div>
-                            {% else %}
-                            <div class="cell planning-cell planning-cell-free" data-id="{{ thisSlot.id }}">
-                                
-                            </div>                            
-                            {% endif %}
+            {% endfor %}
+        
+        {% endfor %}
+        </div>
+    </div>
 
-                        {% endif %}               
+    {% endfor %}
 
-                    {% endfor %}
-                {% endfor %}
+{# fin du block de grille #}
 
-            {% endfor %}
+<div class="has-text-centered"><p data-store="#period-1" data-action="show" class="button">Afficher toutes les périodes à la suite</p></div>
 
-{# fin du block de grille #}
-        </div>
-    </div>
 </div>