```
✨ feat(security): Ajoute la route de déconnexion et configure la redirection. ✨ feat(Dto/Ag): Crée les DTOs AgType, AgMembersType et AgOrderType. ✨ feat(Controller/Admin): Implémente la gestion des AG (CRUD complet). ✨ feat(templates/admin): Ajoute les templates pour la gestion des AG. ```
This commit is contained in:
@@ -27,7 +27,8 @@ security:
|
||||
entry_point: App\Security\AuthenticationEntryPoint
|
||||
custom_authenticator:
|
||||
- App\Security\LoginFormAuthenticator
|
||||
|
||||
logout:
|
||||
target: app_logout
|
||||
|
||||
# Configuration des algorithmes de hachage des mots de passe.
|
||||
# Symfony choisira automatiquement le meilleur algorithme par défaut si non spécifié,
|
||||
|
||||
39
migrations/Version20251123150147.php
Normal file
39
migrations/Version20251123150147.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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 Version20251123150147 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 main (id SERIAL NOT NULL, president_id INT DEFAULT NULL, secretaire_id INT DEFAULT NULL, ag_date_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, locate VARCHAR(255) NOT NULL, locate_zipcode VARCHAR(255) NOT NULL, locate_city VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_BF28CD64B40A33C7 ON main (president_id)');
|
||||
$this->addSql('CREATE INDEX IDX_BF28CD64A90F02B2 ON main (secretaire_id)');
|
||||
$this->addSql('COMMENT ON COLUMN main.ag_date_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE main ADD CONSTRAINT FK_BF28CD64B40A33C7 FOREIGN KEY (president_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE main ADD CONSTRAINT FK_BF28CD64A90F02B2 FOREIGN KEY (secretaire_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
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 main DROP CONSTRAINT FK_BF28CD64B40A33C7');
|
||||
$this->addSql('ALTER TABLE main DROP CONSTRAINT FK_BF28CD64A90F02B2');
|
||||
$this->addSql('DROP TABLE main');
|
||||
}
|
||||
}
|
||||
58
migrations/Version20251123150400.php
Normal file
58
migrations/Version20251123150400.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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 Version20251123150400 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('DROP SEQUENCE main_id_seq CASCADE');
|
||||
$this->addSql('CREATE TABLE ag_main (id SERIAL NOT NULL, president_id INT DEFAULT NULL, secretaire_id INT DEFAULT NULL, ag_date_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, locate VARCHAR(255) NOT NULL, locate_zipcode VARCHAR(255) NOT NULL, locate_city VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_8173EDAFB40A33C7 ON ag_main (president_id)');
|
||||
$this->addSql('CREATE INDEX IDX_8173EDAFA90F02B2 ON ag_main (secretaire_id)');
|
||||
$this->addSql('COMMENT ON COLUMN ag_main.ag_date_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('CREATE TABLE ag_main_member (id SERIAL NOT NULL, member_id INT DEFAULT NULL, main_id INT DEFAULT NULL, is_voted_allow BOOLEAN NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_7979FD617597D3FE ON ag_main_member (member_id)');
|
||||
$this->addSql('CREATE INDEX IDX_7979FD61627EA78A ON ag_main_member (main_id)');
|
||||
$this->addSql('ALTER TABLE ag_main ADD CONSTRAINT FK_8173EDAFB40A33C7 FOREIGN KEY (president_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE ag_main ADD CONSTRAINT FK_8173EDAFA90F02B2 FOREIGN KEY (secretaire_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE ag_main_member ADD CONSTRAINT FK_7979FD617597D3FE FOREIGN KEY (member_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE ag_main_member ADD CONSTRAINT FK_7979FD61627EA78A FOREIGN KEY (main_id) REFERENCES ag_main (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE main DROP CONSTRAINT fk_bf28cd64a90f02b2');
|
||||
$this->addSql('ALTER TABLE main DROP CONSTRAINT fk_bf28cd64b40a33c7');
|
||||
$this->addSql('DROP TABLE main');
|
||||
}
|
||||
|
||||
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('CREATE SEQUENCE main_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||
$this->addSql('CREATE TABLE main (id SERIAL NOT NULL, president_id INT DEFAULT NULL, secretaire_id INT DEFAULT NULL, ag_date_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, locate VARCHAR(255) NOT NULL, locate_zipcode VARCHAR(255) NOT NULL, locate_city VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX idx_bf28cd64a90f02b2 ON main (secretaire_id)');
|
||||
$this->addSql('CREATE INDEX idx_bf28cd64b40a33c7 ON main (president_id)');
|
||||
$this->addSql('COMMENT ON COLUMN main.ag_date_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE main ADD CONSTRAINT fk_bf28cd64a90f02b2 FOREIGN KEY (secretaire_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE main ADD CONSTRAINT fk_bf28cd64b40a33c7 FOREIGN KEY (president_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE ag_main DROP CONSTRAINT FK_8173EDAFB40A33C7');
|
||||
$this->addSql('ALTER TABLE ag_main DROP CONSTRAINT FK_8173EDAFA90F02B2');
|
||||
$this->addSql('ALTER TABLE ag_main_member DROP CONSTRAINT FK_7979FD617597D3FE');
|
||||
$this->addSql('ALTER TABLE ag_main_member DROP CONSTRAINT FK_7979FD61627EA78A');
|
||||
$this->addSql('DROP TABLE ag_main');
|
||||
$this->addSql('DROP TABLE ag_main_member');
|
||||
}
|
||||
}
|
||||
35
migrations/Version20251123150802.php
Normal file
35
migrations/Version20251123150802.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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 Version20251123150802 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 main_order (id SERIAL NOT NULL, title VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('ALTER TABLE ag_main ADD closed_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
|
||||
$this->addSql('COMMENT ON COLUMN ag_main.closed_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
}
|
||||
|
||||
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('DROP TABLE main_order');
|
||||
$this->addSql('ALTER TABLE ag_main DROP closed_at');
|
||||
}
|
||||
}
|
||||
36
migrations/Version20251123150833.php
Normal file
36
migrations/Version20251123150833.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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 Version20251123150833 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('DROP SEQUENCE main_order_id_seq CASCADE');
|
||||
$this->addSql('CREATE TABLE ag_order (id SERIAL NOT NULL, title VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('DROP TABLE main_order');
|
||||
}
|
||||
|
||||
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('CREATE SEQUENCE main_order_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||
$this->addSql('CREATE TABLE main_order (id SERIAL NOT NULL, title VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('DROP TABLE ag_order');
|
||||
}
|
||||
}
|
||||
36
migrations/Version20251123151054.php
Normal file
36
migrations/Version20251123151054.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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 Version20251123151054 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 ag_order ADD main_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE ag_order ADD CONSTRAINT FK_F9A1D380627EA78A FOREIGN KEY (main_id) REFERENCES ag_main (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_F9A1D380627EA78A ON ag_order (main_id)');
|
||||
}
|
||||
|
||||
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 ag_order DROP CONSTRAINT FK_F9A1D380627EA78A');
|
||||
$this->addSql('DROP INDEX IDX_F9A1D380627EA78A');
|
||||
$this->addSql('ALTER TABLE ag_order DROP main_id');
|
||||
}
|
||||
}
|
||||
32
migrations/Version20251123152416.php
Normal file
32
migrations/Version20251123152416.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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 Version20251123152416 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 ag_main ADD is_closed BOOLEAN 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 ag_main DROP is_closed');
|
||||
}
|
||||
}
|
||||
35
migrations/Version20251123160153.php
Normal file
35
migrations/Version20251123160153.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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 Version20251123160153 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 ag_main_vote (id SERIAL NOT NULL, member_id INT DEFAULT NULL, role VARCHAR(255) NOT NULL, pour INT NOT NULL, contre INT NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_A5781BDE7597D3FE ON ag_main_vote (member_id)');
|
||||
$this->addSql('ALTER TABLE ag_main_vote ADD CONSTRAINT FK_A5781BDE7597D3FE FOREIGN KEY (member_id) REFERENCES members (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
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 ag_main_vote DROP CONSTRAINT FK_A5781BDE7597D3FE');
|
||||
$this->addSql('DROP TABLE ag_main_vote');
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,14 @@
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Dto\Ag\AgMembersType;
|
||||
use App\Dto\Ag\AgOrderType;
|
||||
use App\Dto\Ag\AgType;
|
||||
use App\Entity\Account;
|
||||
use App\Entity\AccountResetPasswordRequest;
|
||||
use App\Entity\Ag\Main;
|
||||
use App\Entity\Ag\MainMember;
|
||||
use App\Entity\Ag\MainOrder;
|
||||
use App\Entity\Members;
|
||||
use App\Entity\MembersCotisations;
|
||||
use App\Entity\Products;
|
||||
@@ -11,6 +17,7 @@ use App\Form\MembersType;
|
||||
use App\Form\ProductsType;
|
||||
use App\Form\RequestPasswordConfirmType;
|
||||
use App\Form\RequestPasswordRequestType;
|
||||
use App\Repository\Ag\MainRepository;
|
||||
use App\Repository\MembersCotisationsRepository;
|
||||
use App\Repository\MembersRepository;
|
||||
use App\Repository\ProductsRepository;
|
||||
@@ -223,17 +230,99 @@ class AdminController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/account', name: 'admin_accounts_list', options: ['sitemap' => false], methods: ['GET'])]
|
||||
public function adminAccount(): Response
|
||||
|
||||
#[Route(path: '/admin/ag', name: 'admin_ag', options: ['sitemap' => false], methods: ['GET'])]
|
||||
public function adminAg(MainRepository $mainRepository): Response
|
||||
{
|
||||
return $this->render('admin/dashboard.twig', [
|
||||
|
||||
return $this->render('admin/ag.twig', [
|
||||
'ags' => $mainRepository->findBy([],['agDateAt'=>'DESC']),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/ag', name: 'admin_ag', options: ['sitemap' => false], methods: ['GET'])]
|
||||
public function adminAg(): Response
|
||||
#[Route(path: '/admin/ag/new', name: 'admin_ag_new', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function adminAgNew(Request $request,EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
return $this->render('admin/ag.twig', [
|
||||
$ag = new Main();
|
||||
$form = $this->createForm(AgType::class,$ag);
|
||||
$form->handleRequest($request);
|
||||
if($form->isSubmitted() && $form->isValid()){
|
||||
$entityManager->persist($ag);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag');
|
||||
}
|
||||
return $this->render('admin/ag/new.twig', [
|
||||
'ag' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/admin/ag/{id}', name: 'admin_ag_edit', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function adminAgeDIT(?Main $ag,Request $request,EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$form = $this->createForm(AgType::class,$ag);
|
||||
$form->handleRequest($request);
|
||||
if($form->isSubmitted() && $form->isValid()){
|
||||
$entityManager->persist($ag);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag_edit',['id'=>$ag->getId()]);
|
||||
}
|
||||
|
||||
$agOrder = new MainOrder();
|
||||
$agOrder->setMain($ag);
|
||||
$formOrder = $this->createForm(AgOrderType::class,$agOrder);
|
||||
$formOrder->handleRequest($request);
|
||||
if($formOrder->isSubmitted() && $formOrder->isValid()){
|
||||
$entityManager->persist($agOrder);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag_edit',['id'=>$agOrder->getId()]);
|
||||
}
|
||||
|
||||
$agMembers = new MainMember();
|
||||
$agMembers->setMain($ag);
|
||||
$formMember = $this->createForm(AgMembersType::class,$agMembers);
|
||||
$formMember->handleRequest($request);
|
||||
if($formMember->isSubmitted() && $formMember->isValid()){
|
||||
$rf = $entityManager->getRepository(Members::class)->find($request->request->all()['ag_members']['member']);
|
||||
|
||||
$agMembers->setMember($rf);
|
||||
$t = new \DateTime();
|
||||
$tz = new \DateTime();
|
||||
$tz->modify('+1 year');
|
||||
$isValid = $agMembers->getMember()->getMembersCotisations()->filter(function (MembersCotisations $membersCotisations) use ($t,$tz) {
|
||||
return ($membersCotisations->getStartdATE()->format('Y') == $t->format('Y')) && ($membersCotisations->getEndDate()->format('Y') == $tz->format('Y'));
|
||||
})->first();
|
||||
$agMembers->setIsVotedAllow($isValid instanceof MembersCotisations);
|
||||
$entityManager->persist($agMembers);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag_edit',['id'=>$ag->getId()]);
|
||||
}
|
||||
if($request->query->has('idMember')) {
|
||||
$agMembers = $entityManager->getRepository(MainMember::class)->find($request->query->get('idMember'));
|
||||
$entityManager->remove($agMembers);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag_edit',['id'=>$ag->getId()]);
|
||||
}
|
||||
if($request->query->has('orderId')) {
|
||||
$agOders = $entityManager->getRepository(MainOrder::class)->find($request->query->get('orderId'));
|
||||
$entityManager->remove($agOders);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag_edit',['id'=>$ag->getId()]);
|
||||
}
|
||||
return $this->render('admin/ag/edit.twig', [
|
||||
'ag' => $form->createView(),
|
||||
'agMain' => $ag,
|
||||
'agMembers' => $formMember->createView(),
|
||||
'agOrder' => $formOrder->createView(),
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/admin/ag/delete/{id}', name: 'admin_ag_delete', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function adminAgDelete(?Main $ag,Request $request,EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
foreach ($ag->getMainMembers() as $member)
|
||||
$entityManager->remove($member);
|
||||
foreach ($ag->getOrders() as $order)
|
||||
$entityManager->remove($order);
|
||||
$entityManager->remove($ag);
|
||||
$entityManager->flush();
|
||||
return $this->redirectToRoute('admin_ag');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,11 @@ class SecurityController extends AbstractController
|
||||
'last_username' => $authenticationUtils->getLastUsername(),
|
||||
'error' => $authenticationUtils->getLastAuthenticationError(),
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/logout', name: 'app_logout', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function logout(): Response
|
||||
{
|
||||
|
||||
}
|
||||
#[Route(path: '/mot-de-passe-oublie', name: 'app_forgot_password', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function forgotPassword(Request $request,EventDispatcherInterface $eventDispatcher): Response
|
||||
|
||||
53
src/Dto/Ag/AgMembersType.php
Normal file
53
src/Dto/Ag/AgMembersType.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto\Ag;
|
||||
|
||||
use App\Entity\Ag\Main;
|
||||
use App\Entity\Ag\MainMember;
|
||||
use App\Entity\Members;
|
||||
use App\Repository\MembersRepository;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class AgMembersType extends AbstractType
|
||||
{
|
||||
public function __construct(private MembersRepository $membersRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
/** @var Main $main */
|
||||
$main = $options['data']->getMain();
|
||||
$choices = [];
|
||||
|
||||
foreach ($this->membersRepository->findAll() as $member) {
|
||||
$present = $main->getMainMembers()->filter(function (MainMember $mainMember) use ($member) {
|
||||
return $member->getId() == $mainMember->getMember()->getId();
|
||||
})->first();
|
||||
if(!$present instanceof MainMember) {
|
||||
$choices[$member->getPseudo()] = $member->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$builder
|
||||
->add('member', ChoiceType::class, [
|
||||
'label' => 'Membre',
|
||||
'choices' => $choices,
|
||||
'mapped' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefault('data_class',MainMember::class);
|
||||
}
|
||||
}
|
||||
48
src/Dto/Ag/AgOrderType.php
Normal file
48
src/Dto/Ag/AgOrderType.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto\Ag;
|
||||
|
||||
use App\Entity\Ag\Main;
|
||||
use App\Entity\Ag\MainMember;
|
||||
use App\Entity\Ag\MainOrder;
|
||||
use App\Entity\Members;
|
||||
use App\Repository\MembersRepository;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
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;
|
||||
|
||||
class AgOrderType extends AbstractType
|
||||
{
|
||||
public function __construct(private MembersRepository $membersRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
|
||||
|
||||
$builder
|
||||
->add('title', TextType::class, [
|
||||
'label' => 'Titre',
|
||||
'required' => true,
|
||||
])
|
||||
|
||||
->add('description', TextareaType::class, [
|
||||
'label' => 'Description',
|
||||
'required' => false
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefault('data_class',MainOrder::class);
|
||||
}
|
||||
}
|
||||
70
src/Dto/Ag/AgType.php
Normal file
70
src/Dto/Ag/AgType.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto\Ag;
|
||||
|
||||
use App\Entity\Ag\Main;
|
||||
use App\Entity\Members;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class AgType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('agDateAt',DateTimeType::class,[
|
||||
'label' => 'Date de l\'Assemblée Générale',
|
||||
'required' => true,
|
||||
])
|
||||
->add('type',ChoiceType::class,[
|
||||
'label' => 'Type de l\'AG',
|
||||
'required' => true,
|
||||
'choices' => [
|
||||
'Ordinaire' => 'Ordinaire',
|
||||
'Extraordinaire' => 'Extraordinaire'
|
||||
]
|
||||
])
|
||||
->add('locate',TextType::class,[
|
||||
'label' => 'Adresse',
|
||||
'required' => true,
|
||||
])
|
||||
->add('locateCity',TextType::class,[
|
||||
'label' => 'Ville',
|
||||
'required' => true,
|
||||
])
|
||||
->add('locateZipcode',TextType::class,[
|
||||
'label' => 'Code postal',
|
||||
'required' => true,
|
||||
])
|
||||
->add('president',EntityType::class,[
|
||||
'label' => 'President de la scéance',
|
||||
'class' => Members::class,
|
||||
'choice_label' => function (Members $member) {
|
||||
return $member->getPseudo()." - ".$member->getRole();
|
||||
}
|
||||
])
|
||||
->add('secretaire',EntityType::class,[
|
||||
'label' => 'Secretaire de la scéance',
|
||||
'class' => Members::class,
|
||||
'choice_label' => function (Members $member) {
|
||||
return $member->getPseudo()." - ".$member->getRole();
|
||||
}
|
||||
])
|
||||
->add('closedAt',DateTimeType::class,[
|
||||
'label' => 'Date de cloture',
|
||||
'required' => true,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefault('data_class',Main::class);
|
||||
}
|
||||
}
|
||||
237
src/Entity/Ag/Main.php
Normal file
237
src/Entity/Ag/Main.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity\Ag;
|
||||
|
||||
use App\Entity\Members;
|
||||
use App\Repository\Ag\MainRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MainRepository::class)]
|
||||
#[ORM\Table(name: 'ag_main')]
|
||||
class Main
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?\DateTimeImmutable $agDateAt = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'ag_president')]
|
||||
private ?Members $president = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'secretaire')]
|
||||
private ?Members $secretaire = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $locate = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $locateZipcode = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $locateCity = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $type = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, MainMember>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: MainMember::class, mappedBy: 'main')]
|
||||
private Collection $mainMembers;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $closedAt = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, MainOrder>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: MainOrder::class, mappedBy: 'main')]
|
||||
private Collection $orders;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $isClosed = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mainMembers = new ArrayCollection();
|
||||
$this->orders = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getAgDateAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->agDateAt;
|
||||
}
|
||||
|
||||
public function setAgDateAt(\DateTimeImmutable $agDateAt): static
|
||||
{
|
||||
$this->agDateAt = $agDateAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPresident(): ?Members
|
||||
{
|
||||
return $this->president;
|
||||
}
|
||||
|
||||
public function setPresident(?Members $president): static
|
||||
{
|
||||
$this->president = $president;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSecretaire(): ?Members
|
||||
{
|
||||
return $this->secretaire;
|
||||
}
|
||||
|
||||
public function setSecretaire(?Members $secretaire): static
|
||||
{
|
||||
$this->secretaire = $secretaire;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLocate(): ?string
|
||||
{
|
||||
return $this->locate;
|
||||
}
|
||||
|
||||
public function setLocate(string $locate): static
|
||||
{
|
||||
$this->locate = $locate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLocateZipcode(): ?string
|
||||
{
|
||||
return $this->locateZipcode;
|
||||
}
|
||||
|
||||
public function setLocateZipcode(string $locateZipcode): static
|
||||
{
|
||||
$this->locateZipcode = $locateZipcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLocateCity(): ?string
|
||||
{
|
||||
return $this->locateCity;
|
||||
}
|
||||
|
||||
public function setLocateCity(string $locateCity): static
|
||||
{
|
||||
$this->locateCity = $locateCity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(string $type): static
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, MainMember>
|
||||
*/
|
||||
public function getMainMembers(): Collection
|
||||
{
|
||||
return $this->mainMembers;
|
||||
}
|
||||
|
||||
public function addMainMember(MainMember $mainMember): static
|
||||
{
|
||||
if (!$this->mainMembers->contains($mainMember)) {
|
||||
$this->mainMembers->add($mainMember);
|
||||
$mainMember->setMain($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeMainMember(MainMember $mainMember): static
|
||||
{
|
||||
if ($this->mainMembers->removeElement($mainMember)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($mainMember->getMain() === $this) {
|
||||
$mainMember->setMain(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClosedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->closedAt;
|
||||
}
|
||||
|
||||
public function setClosedAt(?\DateTimeImmutable $closedAt): static
|
||||
{
|
||||
$this->closedAt = $closedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, MainOrder>
|
||||
*/
|
||||
public function getOrders(): Collection
|
||||
{
|
||||
return $this->orders;
|
||||
}
|
||||
|
||||
public function addOrder(MainOrder $order): static
|
||||
{
|
||||
if (!$this->orders->contains($order)) {
|
||||
$this->orders->add($order);
|
||||
$order->setMain($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeOrder(MainOrder $order): static
|
||||
{
|
||||
if ($this->orders->removeElement($order)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($order->getMain() === $this) {
|
||||
$order->setMain(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isClosed(): ?bool
|
||||
{
|
||||
return $this->isClosed;
|
||||
}
|
||||
|
||||
public function setIsClosed(?bool $isClosed): static
|
||||
{
|
||||
$this->isClosed = $isClosed;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
67
src/Entity/Ag/MainMember.php
Normal file
67
src/Entity/Ag/MainMember.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity\Ag;
|
||||
|
||||
use App\Entity\Members;
|
||||
use App\Repository\Ag\MainMemberRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MainMemberRepository::class)]
|
||||
#[ORM\Table(name: 'ag_main_member')]
|
||||
class MainMember
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'mainMembers')]
|
||||
private ?Members $member = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $isVotedAllow = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'mainMembers')]
|
||||
private ?Main $main = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMember(): ?Members
|
||||
{
|
||||
return $this->member;
|
||||
}
|
||||
|
||||
public function setMember(?Members $member): static
|
||||
{
|
||||
$this->member = $member;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isVotedAllow(): ?bool
|
||||
{
|
||||
return $this->isVotedAllow;
|
||||
}
|
||||
|
||||
public function setIsVotedAllow(bool $isVotedAllow): static
|
||||
{
|
||||
$this->isVotedAllow = $isVotedAllow;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMain(): ?Main
|
||||
{
|
||||
return $this->main;
|
||||
}
|
||||
|
||||
public function setMain(?Main $main): static
|
||||
{
|
||||
$this->main = $main;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
66
src/Entity/Ag/MainOrder.php
Normal file
66
src/Entity/Ag/MainOrder.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity\Ag;
|
||||
|
||||
use App\Repository\Ag\MainOrderRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MainOrderRepository::class)]
|
||||
#[ORM\Table(name: 'ag_order')]
|
||||
class MainOrder
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $title = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $description = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'orders')]
|
||||
private ?Main $main = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTitle(): ?string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): static
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): static
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMain(): ?Main
|
||||
{
|
||||
return $this->main;
|
||||
}
|
||||
|
||||
public function setMain(?Main $main): static
|
||||
{
|
||||
$this->main = $main;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
82
src/Entity/Ag/MainVote.php
Normal file
82
src/Entity/Ag/MainVote.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity\Ag;
|
||||
|
||||
use App\Entity\Members;
|
||||
use App\Repository\Ag\MainVoteRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MainVoteRepository::class)]
|
||||
#[ORM\Table(name: 'ag_main_vote')]
|
||||
class MainVote
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'agVotes')]
|
||||
private ?Members $member = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $role = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $pour = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?int $contre = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMember(): ?Members
|
||||
{
|
||||
return $this->member;
|
||||
}
|
||||
|
||||
public function setMember(?Members $member): static
|
||||
{
|
||||
$this->member = $member;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRole(): ?string
|
||||
{
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
public function setRole(string $role): static
|
||||
{
|
||||
$this->role = $role;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPour(): ?int
|
||||
{
|
||||
return $this->pour;
|
||||
}
|
||||
|
||||
public function setPour(int $pour): static
|
||||
{
|
||||
$this->pour = $pour;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContre(): ?int
|
||||
{
|
||||
return $this->contre;
|
||||
}
|
||||
|
||||
public function setContre(int $contre): static
|
||||
{
|
||||
$this->contre = $contre;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Ag\Main;
|
||||
use App\Entity\Ag\MainMember;
|
||||
use App\Entity\Ag\MainVote;
|
||||
use App\Repository\MembersRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -67,9 +70,37 @@ class Members
|
||||
#[ORM\Column(length: 255,nullable: true)]
|
||||
private ?string $Email = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Main>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Main::class, mappedBy: 'president')]
|
||||
private Collection $ag_president;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Main>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Main::class, mappedBy: 'secretaire')]
|
||||
private Collection $secretaire;
|
||||
|
||||
/**
|
||||
* @var Collection<int, MainMember>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: MainMember::class, mappedBy: 'member')]
|
||||
private Collection $mainMembers;
|
||||
|
||||
/**
|
||||
* @var Collection<int, MainVote>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: MainVote::class, mappedBy: 'member')]
|
||||
private Collection $agVotes;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->membersCotisations = new ArrayCollection();
|
||||
$this->ag_president = new ArrayCollection();
|
||||
$this->secretaire = new ArrayCollection();
|
||||
$this->mainMembers = new ArrayCollection();
|
||||
$this->agVotes = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -342,4 +373,124 @@ class Members
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Main>
|
||||
*/
|
||||
public function getAgPresident(): Collection
|
||||
{
|
||||
return $this->ag_president;
|
||||
}
|
||||
|
||||
public function addAgPresident(Main $agPresident): static
|
||||
{
|
||||
if (!$this->ag_president->contains($agPresident)) {
|
||||
$this->ag_president->add($agPresident);
|
||||
$agPresident->setPresident($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAgPresident(Main $agPresident): static
|
||||
{
|
||||
if ($this->ag_president->removeElement($agPresident)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($agPresident->getPresident() === $this) {
|
||||
$agPresident->setPresident(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Main>
|
||||
*/
|
||||
public function getSecretaire(): Collection
|
||||
{
|
||||
return $this->secretaire;
|
||||
}
|
||||
|
||||
public function addSecretaire(Main $secretaire): static
|
||||
{
|
||||
if (!$this->secretaire->contains($secretaire)) {
|
||||
$this->secretaire->add($secretaire);
|
||||
$secretaire->setSecretaire($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSecretaire(Main $secretaire): static
|
||||
{
|
||||
if ($this->secretaire->removeElement($secretaire)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($secretaire->getSecretaire() === $this) {
|
||||
$secretaire->setSecretaire(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, MainMember>
|
||||
*/
|
||||
public function getMainMembers(): Collection
|
||||
{
|
||||
return $this->mainMembers;
|
||||
}
|
||||
|
||||
public function addMainMember(MainMember $mainMember): static
|
||||
{
|
||||
if (!$this->mainMembers->contains($mainMember)) {
|
||||
$this->mainMembers->add($mainMember);
|
||||
$mainMember->setMember($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeMainMember(MainMember $mainMember): static
|
||||
{
|
||||
if ($this->mainMembers->removeElement($mainMember)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($mainMember->getMember() === $this) {
|
||||
$mainMember->setMember(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, MainVote>
|
||||
*/
|
||||
public function getAgVotes(): Collection
|
||||
{
|
||||
return $this->agVotes;
|
||||
}
|
||||
|
||||
public function addAgVote(MainVote $agVote): static
|
||||
{
|
||||
if (!$this->agVotes->contains($agVote)) {
|
||||
$this->agVotes->add($agVote);
|
||||
$agVote->setMember($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAgVote(MainVote $agVote): static
|
||||
{
|
||||
if ($this->agVotes->removeElement($agVote)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($agVote->getMember() === $this) {
|
||||
$agVote->setMember(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
43
src/Repository/Ag/MainMemberRepository.php
Normal file
43
src/Repository/Ag/MainMemberRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Ag;
|
||||
|
||||
use App\Entity\Ag\MainMember;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<MainMember>
|
||||
*/
|
||||
class MainMemberRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, MainMember::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return MainMember[] Returns an array of MainMember objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('m.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?MainMember
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
43
src/Repository/Ag/MainOrderRepository.php
Normal file
43
src/Repository/Ag/MainOrderRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Ag;
|
||||
|
||||
use App\Entity\Ag\MainOrder;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<MainOrder>
|
||||
*/
|
||||
class MainOrderRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, MainOrder::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return MainOrder[] Returns an array of MainOrder objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('m.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?MainOrder
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
43
src/Repository/Ag/MainRepository.php
Normal file
43
src/Repository/Ag/MainRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Ag;
|
||||
|
||||
use App\Entity\Ag\Main;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Main>
|
||||
*/
|
||||
class MainRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Main::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Main[] Returns an array of Main objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('m.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Main
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
43
src/Repository/Ag/MainVoteRepository.php
Normal file
43
src/Repository/Ag/MainVoteRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Ag;
|
||||
|
||||
use App\Entity\Ag\MainVote;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<MainVote>
|
||||
*/
|
||||
class MainVoteRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, MainVote::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return MainVote[] Returns an array of MainVote objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('m.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?MainVote
|
||||
// {
|
||||
// return $this->createQueryBuilder('m')
|
||||
// ->andWhere('m.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -51,6 +51,6 @@ class AuthenticationEntryPoint implements AuthenticationEntryPointInterface
|
||||
);
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->urlGenerator->generate('frontend_login'));
|
||||
return new RedirectResponse($this->urlGenerator->generate('app_login'));
|
||||
}
|
||||
}
|
||||
|
||||
79
templates/admin/ag.twig
Normal file
79
templates/admin/ag.twig
Normal file
@@ -0,0 +1,79 @@
|
||||
{% extends 'admin/base.twig' %}
|
||||
{% block title %}AG (Assemblée Générale){% endblock %}
|
||||
{% block page_title %}AG (Assemblée Générale){% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="p-4 sm:p-6 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 min-h-screen">
|
||||
|
||||
<div class="flex justify-between items-center mb-6 border-b pb-2 border-gray-200 dark:border-gray-700">
|
||||
<h1 class="text-2xl font-bold">Liste des AG</h1>
|
||||
|
||||
{# NOUVEAU BOUTON: CRÉER UNE AG #}
|
||||
<a href="{{ path('admin_ag_new') }}"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
|
||||
+ Créer une AG
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% for ag in ags %}
|
||||
<div class="mb-6 p-4 border rounded-lg shadow-md bg-gray-50 dark:bg-gray-700 dark:border-gray-600 hover:shadow-lg transition duration-300">
|
||||
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="text-lg font-semibold text-indigo-600 dark:text-indigo-400">
|
||||
{{ ag.agDateAt|date('d/m/Y H:i') }}
|
||||
<span class="ml-2 px-3 py-1 text-xs font-medium rounded-full
|
||||
{% if ag.type == 'Extraordinaire' %}
|
||||
bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300
|
||||
{% else %}
|
||||
bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300
|
||||
{% endif %}">
|
||||
{{ ag.type }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-sm">
|
||||
<strong>Président:</strong> {{ ag.president.pseudo }} /
|
||||
<strong>Secrétaire:</strong> {{ ag.secretaire.pseudo }}
|
||||
</p>
|
||||
|
||||
<div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
|
||||
<strong>Lieu:</strong> {{ ag.locate }}
|
||||
{{ ag.locateZipcode }} {{ ag.locateCity }}
|
||||
</div>
|
||||
|
||||
<div class="mt-3 pt-3 border-t border-gray-200 dark:border-gray-600 text-sm">
|
||||
<p>
|
||||
<strong>Membres principaux:</strong> <span class="font-medium">{{ ag.mainMembers.count }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Ordres du jour:</strong> <span class="font-medium">{{ ag.orders.count }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if ag.closed == false or ag.closed == null %}
|
||||
{# Bloc Actions: SUPPRIMER / MODIFIER #}
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-600 flex space-x-3">
|
||||
|
||||
{# Bouton Modifier #}
|
||||
<a href="{{ path('admin_ag_edit', {'id': ag.id}) }}"
|
||||
class="inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Modifier
|
||||
</a>
|
||||
|
||||
{# Bouton Supprimer #}
|
||||
<form method="POST" action="{{ path('admin_ag_delete', {'id': ag.id}) }}" onsubmit="return confirm('Êtes-vous sûr de vouloir supprimer cette Assemblée Générale ?');">
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
|
||||
Supprimer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
176
templates/admin/ag/edit.twig
Normal file
176
templates/admin/ag/edit.twig
Normal file
@@ -0,0 +1,176 @@
|
||||
{% extends 'admin/base.twig' %}
|
||||
{% block title %}AG (Assemblée Générale){% endblock %}
|
||||
{% block page_title %}AG (Assemblée Générale){% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="p-4 sm:p-6 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 min-h-screen">
|
||||
|
||||
{# Titre Principal (Créer / Modifier) #}
|
||||
<h1 class="text-2xl font-bold mb-6 border-b pb-2 border-gray-200 dark:border-gray-700">
|
||||
{% if ag.vars.value.id is defined and ag.vars.value.id is not null %}
|
||||
Modifier l'Assemblée Générale
|
||||
{% else %}
|
||||
Créer une nouvelle Assemblée Générale
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
{% form_theme ag 'form_admin.twig' %}
|
||||
|
||||
{# ============================================== #}
|
||||
{# FORMULAIRE 1: DÉTAILS DE L'AG (Non répété ici) #}
|
||||
{# ============================================== #}
|
||||
{{ form_start(ag, {'attr': {'class': 'space-y-6 mb-10'}}) }}
|
||||
|
||||
{# Section 1: Détails de l'AG #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Détails de l'AG</h2>
|
||||
{{ form_row(ag.agDateAt) }}
|
||||
{{ form_row(ag.closedAt) }}
|
||||
{{ form_row(ag.type) }}
|
||||
<div class="md:col-span-1"></div>
|
||||
</div>
|
||||
|
||||
{# Section 2: Localisation #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Lieu</h2>
|
||||
{{ form_row(ag.locate) }}
|
||||
{{ form_row(ag.locateZipcode) }}
|
||||
{{ form_row(ag.locateCity) }}
|
||||
</div>
|
||||
|
||||
{# Section 3: Rôles #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Rôles</h2>
|
||||
{{ form_row(ag.president) }}
|
||||
{{ form_row(ag.secretaire) }}
|
||||
</div>
|
||||
|
||||
{# Boutons d'action pour le formulaire AG #}
|
||||
<div class="flex justify-end space-x-4 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<a href="{{ path('admin_ag') }}"
|
||||
class="inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md shadow-sm text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Annuler
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Enregistrer l'AG
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(ag) }}
|
||||
|
||||
{# ============================================== #}
|
||||
{# BLOC GESTION DES MEMBRES (Non répété ici) #}
|
||||
{# ============================================== #}
|
||||
<div class="mt-10 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<h2 class="text-xl font-bold mb-4 text-gray-900 dark:text-gray-100">Ajouter/Gérer les membres</h2>
|
||||
|
||||
{% form_theme agMembers 'form_admin.twig' %}
|
||||
|
||||
{{ form_start(agMembers, {'attr': {'class': 'space-y-4 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700 mb-6'}}) }}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-end">
|
||||
<div class="md:col-span-2">{{ form_row(agMembers.member) }}</div>
|
||||
<div class="md:col-span-1">
|
||||
<button type="submit" class="w-full inline-flex justify-center items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Ajouter le membre
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(agMembers) }}
|
||||
|
||||
{# LISTE DES MEMBRES ACTUELS #}
|
||||
{% if ag.vars.value.mainMembers is defined and ag.vars.value.mainMembers|length > 0 %}
|
||||
<h3 class="text-lg font-semibold mt-8 mb-4 border-b pb-2 text-gray-700 dark:text-gray-300">
|
||||
Liste des Membres Principaux ({{ ag.vars.value.mainMembers|length }})
|
||||
</h3>
|
||||
<ul class="space-y-3">
|
||||
{% for memberAg in ag.vars.value.mainMembers %}
|
||||
<li class="flex justify-between items-center p-3 rounded-md bg-white dark:bg-gray-800 shadow border border-gray-200 dark:border-gray-700">
|
||||
<span class="text-gray-900 dark:text-gray-100 font-medium">
|
||||
{{ memberAg.member.pseudo }} - <span class="text-sm font-normal text-gray-600 dark:text-gray-400">{{ memberAg.member.role }}</span>
|
||||
</span>
|
||||
<form method="POST" action="{{ path('admin_ag_edit',{id:ag.vars.value.id,idMember:memberAg.id}) }}" onsubmit="return confirm('Êtes-vous sûr de vouloir retirer {{ memberAg.member.pseudo }} de cette AG ?');">
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-3 py-1 text-xs font-medium rounded-md text-white bg-red-500 hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition duration-150">
|
||||
Supprimer
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="mt-4 p-4 text-center text-gray-500 dark:text-gray-400 border border-dashed rounded-lg">
|
||||
Aucun membre principal n'est encore rattaché à cette Assemblée Générale.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# ============================================== #}
|
||||
{# BLOC ORDRES DU JOUR (ODJ) #}
|
||||
{# ============================================== #}
|
||||
<div class="mt-10 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<h2 class="text-xl font-bold mb-4 text-gray-900 dark:text-gray-100">Ajouter un Ordre du Jour</h2>
|
||||
|
||||
{% form_theme agOrder 'form_admin.twig' %}
|
||||
|
||||
{# FORMULAIRE D'AJOUT D'ODJ #}
|
||||
{{ form_start(agOrder, {'attr': {'class': 'space-y-4 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700 mb-6'}}) }}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{{ form_row(agOrder.title) }}
|
||||
<div class="md:col-span-1 hidden md:block"></div>
|
||||
</div>
|
||||
|
||||
{{ form_row(agOrder.description) }}
|
||||
|
||||
<div class="flex justify-end pt-2">
|
||||
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-teal-600 hover:bg-teal-700 dark:bg-teal-500 dark:hover:bg-teal-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-500">
|
||||
Ajouter l'Ordre du Jour
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(agOrder) }}
|
||||
|
||||
{# LISTE DES ORDRES DU JOUR ACTUELS #}
|
||||
{% if ag.vars.value.orders is defined and ag.vars.value.orders|length > 0 %}
|
||||
<h3 class="text-lg font-semibold mt-8 mb-4 border-b pb-2 text-gray-700 dark:text-gray-300">
|
||||
Ordres du Jour ({{ ag.vars.value.orders|length }})
|
||||
</h3>
|
||||
|
||||
<ul class="space-y-3">
|
||||
{% for order in ag.vars.value.orders %}
|
||||
<li class="p-4 rounded-md bg-white dark:bg-gray-800 shadow border border-gray-200 dark:border-gray-700">
|
||||
|
||||
<div class="flex justify-between items-start">
|
||||
<span class="text-gray-900 dark:text-gray-100 font-medium text-base">
|
||||
{{ loop.index }}. {{ order.title }}
|
||||
</span>
|
||||
|
||||
{# Formulaire de Suppression de l'ODJ #}
|
||||
<form method="POST" action="{{ path('admin_ag_edit', {'id': agMain.id, 'orderId': order.id}) }}" onsubmit="return confirm('Êtes-vous sûr de vouloir supprimer cet Ordre du Jour : {{ order.title }} ?');">
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-3 py-1 text-xs font-medium rounded-md text-white bg-red-500 hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition duration-150 ml-4">
|
||||
Supprimer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400 whitespace-pre-line">
|
||||
{{ order.description|default('Aucune description fournie.') }}
|
||||
</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="mt-4 p-4 text-center text-gray-500 dark:text-gray-400 border border-dashed rounded-lg">
|
||||
Aucun Ordre du Jour n'a encore été défini pour cette Assemblée Générale.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
70
templates/admin/ag/new.twig
Normal file
70
templates/admin/ag/new.twig
Normal file
@@ -0,0 +1,70 @@
|
||||
{% extends 'admin/base.twig' %}
|
||||
{% block title %}AG (Assemblée Générale){% endblock %}
|
||||
{% block page_title %}AG (Assemblée Générale){% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="p-4 sm:p-6 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 min-h-screen">
|
||||
|
||||
<h1 class="text-2xl font-bold mb-6 border-b pb-2 border-gray-200 dark:border-gray-700">
|
||||
{% if ag.vars.value.id is defined and ag.vars.value.id is not null %}
|
||||
Modifier l'Assemblée Générale
|
||||
{% else %}
|
||||
Créer une nouvelle Assemblée Générale
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
{# Le formulaire doit utiliser le thème 'form_admin.twig' pour le style #}
|
||||
{% form_theme ag 'form_admin.twig' %}
|
||||
|
||||
{{ form_start(ag, {'attr': {'class': 'space-y-6'}}) }}
|
||||
|
||||
{# Section 1: Informations principales et dates (Grid Layout) #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Détails de l'AG</h2>
|
||||
|
||||
{{ form_row(ag.agDateAt) }}
|
||||
{{ form_row(ag.closedAt) }}
|
||||
{{ form_row(ag.type) }}
|
||||
{# Ce champ est seul sur la deuxième colonne pour l'exemple #}
|
||||
<div class="md:col-span-1"></div>
|
||||
</div>
|
||||
|
||||
{# Section 2: Localisation (Grid Layout) #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Lieu</h2>
|
||||
|
||||
{{ form_row(ag.locate) }}
|
||||
{{ form_row(ag.locateZipcode) }}
|
||||
{{ form_row(ag.locateCity) }}
|
||||
</div>
|
||||
|
||||
{# Section 3: Rôles (Simple Layout) #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-4 border rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||
|
||||
<h2 class="col-span-full text-lg font-semibold text-gray-700 dark:text-gray-200 mb-2">Rôles</h2>
|
||||
|
||||
{{ form_row(ag.president) }}
|
||||
{{ form_row(ag.secretaire) }}
|
||||
</div>
|
||||
|
||||
{# Boutons d'action #}
|
||||
<div class="flex justify-end space-x-4 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
|
||||
{# Bouton Annuler/Retour #}
|
||||
<a href="{{ path('admin_ag') }}"
|
||||
class="inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md shadow-sm text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Annuler
|
||||
</a>
|
||||
|
||||
{# Bouton Soumettre/Enregistrer #}
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 dark:bg-indigo-500 dark:hover:bg-indigo-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
Enregistrer l'AG
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(ag) }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -26,9 +26,9 @@ Elle défilera donc avec le reste du contenu de la page.
|
||||
L'overflow-y-auto n'est plus nécessaire ici car c'est le <body> qui gère le scroll. -->
|
||||
|
||||
<aside id="sidebar" class="w-64 bg-gray-800 text-white flex-shrink-0 transition-transform duration-300 transform -translate-x-full md:translate-x-0 z-40">
|
||||
<div class="p-6">
|
||||
<a href="{{ path('app_home') }}" target="_blank" class="p-6 block">
|
||||
<h1 class="text-3xl font-bold tracking-wider">E-Cosplay</h1>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<nav class="mt-8">
|
||||
<!-- Dashboard -->
|
||||
@@ -60,19 +60,9 @@ L'overflow-y-auto n'est plus nécessaire ici car c'est le <body> qui gère le sc
|
||||
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.523 5.754 18 7.5 18s3.332.477 4.5 1.247m0-13C13.168 5.477 14.754 5 16.5 5s3.332.477 4.5 1.253v13C19.832 18.523 18.246 18 16.5 18s-3.332.477-4.5 1.247"></path></svg>
|
||||
AG (Assemblée Générale)
|
||||
</a>
|
||||
|
||||
{# Le lien Paramètres a été supprimé #}
|
||||
|
||||
{# Ajoutez d'autres liens ici #}
|
||||
</nav>
|
||||
|
||||
|
||||
</aside>
|
||||
|
||||
<!-- 2. Contenu Principal et Navigation Supérieure -->
|
||||
|
||||
<!-- Le conteneur principal reste flex-col et prend l'espace restant -->
|
||||
|
||||
<div id="main-content" class="flex flex-col flex-1">
|
||||
|
||||
<!-- 2.1. Navbar (Barre de Navigation Supérieure) - bg-gray-800 -->
|
||||
|
||||
@@ -223,7 +223,11 @@
|
||||
tabindex="-1">
|
||||
{{ 'logged_admin'|trans }}
|
||||
</a>
|
||||
|
||||
<a href="{{ path('app_logout') }}"
|
||||
class="block px-4 py-2 text-sm text-red-600 hover:bg-gray-100" role="menuitem"
|
||||
tabindex="-1">
|
||||
{{ 'logout_link'|trans }}
|
||||
</a>
|
||||
{% else %}
|
||||
{# Afficher la connexion si non connecté #}
|
||||
<a href="{{ path('app_login') }}"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{# ---------- ROW ---------- #}
|
||||
{% block form_row %}
|
||||
{# La ROW est le conteneur du label, du widget et des erreurs. #}
|
||||
<div class="mb-5">
|
||||
<div class="mb-0">
|
||||
{{ form_label(form) }}
|
||||
<div class="mt-1">
|
||||
{{ form_widget(form) }}
|
||||
|
||||
Reference in New Issue
Block a user