Ajax call to create + edit organizations
This commit is contained in:
parent
4f7c1eb5de
commit
d5e1ad057e
|
|
@ -2,17 +2,18 @@ import {Controller} from '@hotwired/stimulus'
|
||||||
// Important: include a build with Ajax + pagination (TabulatorFull is simplest)
|
// Important: include a build with Ajax + pagination (TabulatorFull is simplest)
|
||||||
import {TabulatorFull as Tabulator} from 'tabulator-tables';
|
import {TabulatorFull as Tabulator} from 'tabulator-tables';
|
||||||
import {eyeIconLink, TABULATOR_FR_LANG} from "../js/global.js";
|
import {eyeIconLink, TABULATOR_FR_LANG} from "../js/global.js";
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static values = {
|
static values = {
|
||||||
id: String,
|
id: Number,
|
||||||
activities: Boolean,
|
activities: Boolean,
|
||||||
table: Boolean,
|
table: Boolean,
|
||||||
sadmin: Boolean,
|
sadmin: Boolean,
|
||||||
user: Number
|
user: Number
|
||||||
};
|
};
|
||||||
|
|
||||||
static targets = ["activityList", "emptyMessage"]
|
static targets = ["activityList", "emptyMessage", "modal", "modalTitle", "nameInput", "emailInput", "numberInput", "addressInput"];
|
||||||
connect() {
|
connect() {
|
||||||
if(this.activitiesValue){
|
if(this.activitiesValue){
|
||||||
this.loadActivities();
|
this.loadActivities();
|
||||||
|
|
@ -23,6 +24,10 @@ export default class extends Controller {
|
||||||
if (this.tableValue && this.sadminValue) {
|
if (this.tableValue && this.sadminValue) {
|
||||||
this.table();
|
this.table();
|
||||||
}
|
}
|
||||||
|
if (this.hasModalTarget) {
|
||||||
|
this.modal = new Modal(this.modalTarget);
|
||||||
|
this.currentOrgId = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,4 +158,69 @@ export default class extends Controller {
|
||||||
|
|
||||||
this.activityListTarget.innerHTML = html;
|
this.activityListTarget.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openCreateModal() {
|
||||||
|
this.currentOrgId = null;
|
||||||
|
this.modalTitleTarget.textContent = "Créer une organisation";
|
||||||
|
this.resetForm();
|
||||||
|
this.modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async openEditModal(event) {
|
||||||
|
this.currentOrgId = event.currentTarget.dataset.id;
|
||||||
|
this.modalTitleTarget.textContent = "Modifier l'organisation";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/organization/${this.currentOrgId}`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Fill targets
|
||||||
|
this.nameInputTarget.value = data.name;
|
||||||
|
this.emailInputTarget.value = data.email;
|
||||||
|
this.numberInputTarget.value = data.number || '';
|
||||||
|
this.addressInputTarget.value = data.address || '';
|
||||||
|
|
||||||
|
this.modal.show();
|
||||||
|
} catch (error) {
|
||||||
|
alert("Erreur lors du chargement des données.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitForm(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(event.target);
|
||||||
|
|
||||||
|
const method = this.currentOrgId ? 'PUT' : 'POST';
|
||||||
|
const url = this.currentOrgId ? `/organization/${this.currentOrgId}` : `/organization/`;
|
||||||
|
|
||||||
|
|
||||||
|
if (this.currentOrgId) {
|
||||||
|
formData.append('_method', 'PUT');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
this.modal.hide();
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
const result = await response.json();
|
||||||
|
alert(result.error || "Une erreur est survenue.");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert("Erreur réseau.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetForm() {
|
||||||
|
this.nameInputTarget.value = "";
|
||||||
|
this.emailInputTarget.value = "";
|
||||||
|
this.numberInputTarget.value = "";
|
||||||
|
this.addressInputTarget.value = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?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 Version20260302105113 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 organizations ALTER number DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER bdd_name SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER timestamp_precision SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER deletion_allowed SET NOT 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 organizations ALTER number SET NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER bdd_name DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER timestamp_precision DROP NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE project ALTER deletion_allowed DROP NOT NULL');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,6 @@ namespace App\Controller;
|
||||||
|
|
||||||
use App\Entity\Actions;
|
use App\Entity\Actions;
|
||||||
use App\Entity\Apps;
|
use App\Entity\Apps;
|
||||||
use App\Entity\Roles;
|
|
||||||
use App\Entity\User;
|
|
||||||
use App\Entity\UserOrganizationApp;
|
|
||||||
use App\Entity\UsersOrganizations;
|
use App\Entity\UsersOrganizations;
|
||||||
use App\Form\OrganizationForm;
|
use App\Form\OrganizationForm;
|
||||||
use App\Repository\OrganizationsRepository;
|
use App\Repository\OrganizationsRepository;
|
||||||
|
|
@ -17,12 +14,8 @@ use App\Service\LoggerService;
|
||||||
use App\Service\OrganizationsService;
|
use App\Service\OrganizationsService;
|
||||||
use App\Service\UserOrganizationService;
|
use App\Service\UserOrganizationService;
|
||||||
use App\Service\UserService;
|
use App\Service\UserService;
|
||||||
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
|
|
||||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\NonUniqueResultException;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
@ -82,89 +75,114 @@ class OrganizationController extends AbstractController
|
||||||
return $this->redirectToRoute('app_index');
|
return $this->redirectToRoute('app_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/', name: 'create', methods: ['POST'])]
|
||||||
#[Route(path: '/create', name: 'create', methods: ['GET', 'POST'])]
|
public function create(Request $request): JsonResponse
|
||||||
public function new(Request $request): Response
|
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
|
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
|
||||||
$actingUser = $this->getUser();
|
$actingUser = $this->getUser();
|
||||||
if ($request->isMethod('POST')) {
|
|
||||||
$organization = new Organizations();
|
$data = $request->request->all();
|
||||||
$form = $this->createForm(OrganizationForm::class, $organization);
|
|
||||||
$form->handleRequest($request);
|
// 2. Access file data specifically
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
$logoFile = $request->files->get('logoUrl');
|
||||||
$logoFile = $form->get('logoUrl')->getData();
|
|
||||||
|
$organization = new Organizations();
|
||||||
|
$existingOrg = $this->organizationsRepository->findOneBy(['email' => $data['email']]);
|
||||||
|
if ($existingOrg) {
|
||||||
|
return $this->json(['error' => 'Une organisation avec cet email existe déjà.'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm(OrganizationForm::class, $organization,[
|
||||||
|
'csrf_protection' => false,
|
||||||
|
'allow_extra_fields' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$form->submit(array_merge($data, ['logoUrl' => $logoFile]));
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
try {
|
||||||
if ($logoFile) {
|
if ($logoFile) {
|
||||||
$this->organizationsService->handleLogo($organization, $logoFile);
|
$this->organizationsService->handleLogo($organization, $logoFile);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
$organization->setProjectPrefix($this->organizationsService->generateUniqueProjectPrefix());
|
$organization->setProjectPrefix($this->organizationsService->generateUniqueProjectPrefix());
|
||||||
$this->entityManager->persist($organization);
|
|
||||||
$this->entityManager->flush();
|
$this->entityManager->persist($organization);
|
||||||
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Created");
|
$this->entityManager->flush();
|
||||||
$this->loggerService->logSuperAdmin($actingUser->getUserIdentifier(), $actingUser->getUserIdentifier(), "Organization Created", $organization->getId());
|
|
||||||
$this->actionService->createAction("Create Organization", $actingUser, $organization, $organization->getName());
|
// Loggers...
|
||||||
$this->addFlash('success', 'Organisation crée avec succès.');
|
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Created via ajax");
|
||||||
return $this->redirectToRoute('organization_index');
|
|
||||||
} catch (Exception $e) {
|
return $this->json([
|
||||||
$this->addFlash('danger', 'Erreur lors de la création de l\'organization');
|
'message' => 'Organisation créée avec succès.',
|
||||||
$this->loggerService->logError('Error creating organization', ['acting_user_id' => $actingUser->getUserIdentifier(), 'error' => $e->getMessage()]);
|
'id' => $organization->getId()
|
||||||
}
|
], Response::HTTP_CREATED);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $this->json(['error' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
return $this->render('organization/new.html.twig', [
|
|
||||||
'form' => $form->createView(),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $this->createForm(OrganizationForm::class);
|
// 4. Return specific validation errors to help debugging
|
||||||
return $this->render('organization/new.html.twig', [
|
$errors = [];
|
||||||
'form' => $form->createView(),
|
foreach ($form->getErrors(true) as $error) {
|
||||||
]);
|
$errors[] = $error->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json(['error' => 'Validation failed', 'details' => $errors], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/edit/{id}', name: 'edit', methods: ['GET', 'POST'])]
|
#[Route(path: '/{id}', name: 'edit', methods: ['PUT'])]
|
||||||
public function edit(Request $request, $id): Response
|
public function edit(Request $request, int $id): JsonResponse
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
$actingUser = $this->getUser();
|
$actingUser = $this->getUser();
|
||||||
$organization = $this->organizationsRepository->find($id);
|
$organization = $this->organizationsRepository->find($id);
|
||||||
if (!$organization) {
|
if (!$organization) {
|
||||||
$this->loggerService->logEntityNotFound('Organization', [
|
$this->loggerService->logEntityNotFound('Organization', [
|
||||||
'org_id' => $id,
|
'org_id' => $id,
|
||||||
'message' => 'Organization not found for edit'], $actingUser->getUserIdentifier()
|
'message' => 'Organization not found for get endpoint'
|
||||||
);
|
], $actingUser->getUserIdentifier());
|
||||||
$this->addFlash('danger', 'Erreur, l\'organization est introuvable.');
|
return $this->json(['error' => self::NOT_FOUND], Response::HTTP_NOT_FOUND);
|
||||||
return $this->redirectToRoute('organization_index');
|
|
||||||
}
|
}
|
||||||
|
if (!$this->userService->isAdminOfOrganization($organization) && !$this->isGranted("ROLE_ADMIN")) {
|
||||||
$form = $this->createForm(OrganizationForm::class, $organization);
|
$this->loggerService->logAccessDenied($actingUser->getUserIdentifier());
|
||||||
$form->handleRequest($request);
|
return $this->json(['error' => self::ACCESS_DENIED], Response::HTTP_FORBIDDEN);
|
||||||
|
}
|
||||||
|
$data = $request->request->all();
|
||||||
|
$logoFile = $request->files->get('logoUrl');
|
||||||
|
$form = $this->createForm(OrganizationForm::class, $organization,[
|
||||||
|
'csrf_protection' => false,
|
||||||
|
'allow_extra_fields' => true,
|
||||||
|
]);
|
||||||
|
if ($logoFile) {
|
||||||
|
$form->submit(array_merge($data, ['logoUrl' => $logoFile]), false);
|
||||||
|
}
|
||||||
|
$form->submit(array_merge($request->request->all(), $request->files->all()));
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$logoFile = $form->get('logoUrl')->getData();
|
|
||||||
if ($logoFile) {
|
|
||||||
$this->organizationsService->handleLogo($organization, $logoFile);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
if ($logoFile) {
|
||||||
|
$this->organizationsService->handleLogo($organization, $logoFile);
|
||||||
|
}
|
||||||
$this->entityManager->persist($organization);
|
$this->entityManager->persist($organization);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Edited");
|
|
||||||
if ($this->isGranted("ROLE_SUPER_ADMIN")) {
|
|
||||||
$this->loggerService->logSuperAdmin($actingUser->getUserIdentifier(), $actingUser->getUserIdentifier(), "Organization Edited", $organization->getId());
|
|
||||||
}
|
|
||||||
$this->actionService->createAction("Edit Organization", $actingUser, $organization, $organization->getName());
|
$this->actionService->createAction("Edit Organization", $actingUser, $organization, $organization->getName());
|
||||||
$this->addFlash('success', 'Organisation modifiée avec succès.');
|
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Edited via ajax");
|
||||||
return $this->redirectToRoute('organization_index');
|
return $this->json(['message' => 'Organisation modifiée avec succès.']);
|
||||||
}catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->addFlash('danger', 'Erreur lors de la modification de l\'organization');
|
return $this->json(['error' => $e->getMessage()], 500);
|
||||||
$this->loggerService->logError('Error editing organization', ['acting_user_id' => $actingUser->getUserIdentifier(), 'error' => $e->getMessage()]);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$errors = [];
|
||||||
|
foreach ($form->getErrors(true) as $error) {
|
||||||
|
$errors[] = $error->getMessage();
|
||||||
|
}
|
||||||
|
return $this->json(['error' => 'Validation failed', 'details' => $errors], 400);
|
||||||
}
|
}
|
||||||
return $this->render('organization/edit.html.twig', [
|
|
||||||
'form' => $form->createView(),
|
|
||||||
'organization' => $organization,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[Route(path: '/view/{id}', name: 'show', methods: ['GET'])]
|
#[Route(path: '/view/{id}', name: 'show', methods: ['GET'])]
|
||||||
public function view($id): Response
|
public function view($id): Response
|
||||||
{
|
{
|
||||||
|
|
@ -286,7 +304,7 @@ class OrganizationController extends AbstractController
|
||||||
return $this->redirectToRoute('organization_index');
|
return $this->redirectToRoute('organization_index');
|
||||||
}
|
}
|
||||||
|
|
||||||
// API endpoint to fetch organization data for Tabulator
|
// API endpoint to fetch organizations data for Tabulator
|
||||||
#[Route(path: '/data', name: 'data', methods: ['GET'])]
|
#[Route(path: '/data', name: 'data', methods: ['GET'])]
|
||||||
public function data(Request $request): JsonResponse
|
public function data(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
|
|
@ -325,6 +343,7 @@ class OrganizationController extends AbstractController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ajax route to get users of an organization ( used in select field for admin of an org ) */
|
||||||
#[Route(path: '/{id}/users', name: 'users', methods: ['GET'])]
|
#[Route(path: '/{id}/users', name: 'users', methods: ['GET'])]
|
||||||
public function users($id): JsonResponse{
|
public function users($id): JsonResponse{
|
||||||
$this->denyAccessUnlessGranted("ROLE_USER");
|
$this->denyAccessUnlessGranted("ROLE_USER");
|
||||||
|
|
@ -351,4 +370,32 @@ class OrganizationController extends AbstractController
|
||||||
}, $uos);
|
}, $uos);
|
||||||
return $this->json(['users' => $users]);
|
return $this->json(['users' => $users]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Path used to get data on an organization for the edit modal
|
||||||
|
*/
|
||||||
|
#[Route(path: '/{id}', name: 'get', methods: ['GET'])]
|
||||||
|
public function get(int $id): JsonResponse{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
$actingUser = $this->getUser();
|
||||||
|
$organization = $this->organizationsRepository->find($id);
|
||||||
|
if (!$organization) {
|
||||||
|
$this->loggerService->logEntityNotFound('Organization', [
|
||||||
|
'org_id' => $id,
|
||||||
|
'message' => 'Organization not found for get endpoint'
|
||||||
|
], $actingUser->getUserIdentifier());
|
||||||
|
return $this->json(['error' => self::NOT_FOUND], Response::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (!$this->userService->isAdminOfOrganization($organization) && !$this->isGranted("ROLE_ADMIN")) {
|
||||||
|
$this->loggerService->logAccessDenied($actingUser->getUserIdentifier());
|
||||||
|
return $this->json(['error' => self::ACCESS_DENIED], Response::HTTP_FORBIDDEN);
|
||||||
|
}
|
||||||
|
return $this->json([
|
||||||
|
'id' => $organization->getId(),
|
||||||
|
'name' => $organization->getName(),
|
||||||
|
'email' => $organization->getEmail(),
|
||||||
|
'logoUrl' => $organization->getLogoUrl() ?: null,
|
||||||
|
'active' => $organization->isActive(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class Organizations
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
private ?string $email = null;
|
private ?string $email = null;
|
||||||
|
|
||||||
#[ORM\Column]
|
#[ORM\Column(nullable: true)]
|
||||||
private ?int $number = null;
|
private ?int $number = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
|
|
@ -101,7 +101,7 @@ class Organizations
|
||||||
return $this->number;
|
return $this->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setNumber(int $number): static
|
public function setNumber(?int $number): static
|
||||||
{
|
{
|
||||||
$this->number = $number;
|
$this->number = $number;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
|
@ -17,8 +18,8 @@ class OrganizationForm extends AbstractType
|
||||||
$builder
|
$builder
|
||||||
->add('email', EmailType::class, ['required' => true, 'label' => 'Email*','empty_data' => ''])
|
->add('email', EmailType::class, ['required' => true, 'label' => 'Email*','empty_data' => ''])
|
||||||
->add('name', TextType::class, ['required' => true, 'label' => 'Nom de l\'organisation*','empty_data' => ''])
|
->add('name', TextType::class, ['required' => true, 'label' => 'Nom de l\'organisation*','empty_data' => ''])
|
||||||
->add('address', TextType::class, ['required' => true, 'label' => 'Adresse','empty_data' => ''])
|
->add('address', TextType::class, [ 'label' => 'Adresse','empty_data' => ''])
|
||||||
->add('number', TextType::class, ['required' => true, 'label' => 'Numéro de téléphone','empty_data' => ''])
|
->add('number', IntegerType::class, [ 'label' => 'Numéro de téléphone'])
|
||||||
->add('logoUrl', FileType::class, [
|
->add('logoUrl', FileType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'Logo',
|
'label' => 'Logo',
|
||||||
|
|
|
||||||
|
|
@ -11,38 +11,86 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="card no-header-bg p-3 m-3 border-0">
|
<div class="card no-header-bg p-3 m-3 border-0"
|
||||||
|
data-controller="organization"
|
||||||
|
>
|
||||||
<div class="card-header d-flex justify-content-between align-items-center border-0">
|
<div class="card-header d-flex justify-content-between align-items-center border-0">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h1>Gestion des organisations</h1>
|
<h1>Gestion des organisations</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if is_granted("ROLE_SUPER_ADMIN") %}
|
{% if is_granted("ROLE_SUPER_ADMIN") %}
|
||||||
<a href="{{ path('organization_create') }}" class="btn btn-primary">Ajouter une organisation</a>
|
<button type="button" class="btn btn-primary" data-action="click->organization#openCreateModal">
|
||||||
|
Créer une organisation
|
||||||
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{# New organization modal #}
|
||||||
|
<div class="modal fade" id="createOrganizationModal" tabindex="-1" aria-labelledby="createOrganizationModalLabel"
|
||||||
|
aria-hidden="true"
|
||||||
|
data-organization-target="modal">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="createOrganizationModalLabel">Créer une organisation</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form data-action="submit->organization#createOrganization">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="organizationName" class="form-label">Nom de l'organisation</label>
|
||||||
|
<input type="text" class="form-control" id="organizationName" name="name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="organizationEmail" class="form-label">Email</label>
|
||||||
|
<input class="form-control" id="organizationEmail" type="email" name="email" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="organizationPhone" class="form-label">Téléphone</label>
|
||||||
|
<input class="form-control" type="number" id="organizationPhone" name="phone">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="organizationAddress" class="form-label">Adresse</label>
|
||||||
|
<input class="form-control" id="organizationAddress" name="address">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="organizationLogo">Logo de l'organisation</label>
|
||||||
|
<input type="file" name="logoUrl" id="organizationLogo" class="form-control"
|
||||||
|
accept="image/*">
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
|
Annuler
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Créer l'organisation</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{% if is_granted('ROLE_SUPER_ADMIN') and not hasOrganizations %}
|
||||||
|
|
||||||
|
<div class="div text-center my-5 py-5">
|
||||||
|
<h1 class="my-5 ty-5"> Aucune organisation trouvée. </h1>
|
||||||
|
<a href="{{ path('organization_create') }}" class="btn btn-primary">Créer une
|
||||||
|
organisation</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
{% else %}
|
||||||
{% if is_granted('ROLE_SUPER_ADMIN') and not hasOrganizations %}
|
|
||||||
|
|
||||||
<div class="div text-center my-5 py-5">
|
<div id="tabulator-org"
|
||||||
<h1 class="my-5 ty-5"> Aucune organisation trouvée. </h1>
|
data-controller="organization"
|
||||||
<a href="{{ path('organization_create') }}" class="btn btn-primary">Créer une organisation</a>
|
data-organization-table-value="true"
|
||||||
</div>
|
data-organization-user-value="{{ app.user.getId() }}"
|
||||||
|
data-organization-sadmin-value="{{ is_granted('ROLE_SUPER_ADMIN') ? true : false }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
{% else %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div id="tabulator-org"
|
|
||||||
data-controller="organization"
|
|
||||||
data-organization-table-value="true"
|
|
||||||
data-organization-user-value="{{ app.user.getId() }}"
|
|
||||||
data-organization-sadmin-value="{{ is_granted('ROLE_SUPER_ADMIN') ? true : false }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<div class="modal fade" id="organizationModal" tabindex="-1" data-organization-target="modal">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" data-organization-target="modalTitle">Créer une organisation</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<form data-action="submit->organization#submitForm">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nom de l'organisation</label>
|
||||||
|
<input type="text" name="name" data-organization-target="nameInput" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Email</label>
|
||||||
|
<input type="email" name="email" data-organization-target="emailInput" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Téléphone</label>
|
||||||
|
<input type="text" name="number" data-organization-target="numberInput" class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Adresse</label>
|
||||||
|
<input type="text" name="address" data-organization-target="addressInput" class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Logo</label>
|
||||||
|
<input type="file" name="logoUrl" class="form-control" accept="image/*">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="col d-flex justify-content-between align-items-center">
|
<div class="col d-flex justify-content-between align-items-center" data-controller="organization">
|
||||||
<div class="d-flex ">
|
<div class="d-flex ">
|
||||||
{% if organization.logoUrl %}
|
{% if organization.logoUrl %}
|
||||||
<img src="{{ asset(organization.logoUrl) }}" alt="Organization logo"
|
<img src="{{ asset(organization.logoUrl) }}" alt="Organization logo"
|
||||||
|
|
@ -20,8 +20,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
{% if isSA %}
|
{% if isSA %}
|
||||||
<a href="{{ path('organization_edit', {'id': organization.id}) }}" class="btn btn-primary">Gérer
|
<button type="button"
|
||||||
l'organisation</a>
|
class="btn btn-primary"
|
||||||
|
data-action="click->organization#openEditModal"
|
||||||
|
data-id="{{ organization.id }}">
|
||||||
|
Gérer mon organisation
|
||||||
|
</button>
|
||||||
|
{{ include('organization/organizationModal.html.twig') }}
|
||||||
<form method="POST" action="{{ path('organization_delete', {'id': organization.id}) }}"
|
<form method="POST" action="{{ path('organization_delete', {'id': organization.id}) }}"
|
||||||
onsubmit="return confirm('Vous allez supprimer cette organisation, êtes vous sûre?');"
|
onsubmit="return confirm('Vous allez supprimer cette organisation, êtes vous sûre?');"
|
||||||
style="display: inline-block;">
|
style="display: inline-block;">
|
||||||
|
|
@ -41,8 +46,13 @@
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elseif is_granted("ROLE_ADMIN") %}
|
{% elseif is_granted("ROLE_ADMIN") %}
|
||||||
<a href="{{ path('organization_edit', {'id': organization.id}) }}" class="btn btn-primary">Gérer mon
|
<button type="button"
|
||||||
organisation</a>
|
class="btn btn-primary"
|
||||||
|
data-action="click->organization#openEditModal"
|
||||||
|
data-id="{{ organization.id }}">
|
||||||
|
Gérer mon organisation
|
||||||
|
</button>
|
||||||
|
{{ include('organization/organizationModal.html.twig') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{% extends 'base.html.twig' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
Loading…
Reference in New Issue