From b17396a2d96ab01c1d93dc7f0fbfa9059d620914 Mon Sep 17 00:00:00 2001
From: csauder <christophe.sauder@viaevista.fr>
Date: Fri, 12 Jan 2024 15:18:14 +0100
Subject: [PATCH] :sparkles: Edition de bureau via un formulaire moche

---
 composer.json                           |  3 +-
 config/bootstrap.php                    |  2 -
 config/container.php                    |  6 ++-
 config/routes.php                       |  7 +++
 public/assets/script.js                 | 43 ++++++++++++++++
 public/assets/style.css                 | 62 +++++++++++++++++++++++
 src/Console/CreateDatabaseCommand.php   |  6 +++
 src/Console/PopulateDatabaseCommand.php | 28 +++++------
 src/Controller/OfficeController.php     | 66 +++++++++++++++++++++++++
 src/Models/Company.php                  |  3 ++
 view/company/index.twig                 |  3 ++
 view/layout.twig                        | 13 +++++
 view/office/form.twig                   | 37 ++++++++++++++
 13 files changed, 261 insertions(+), 18 deletions(-)
 create mode 100644 src/Controller/OfficeController.php
 create mode 100644 view/office/form.twig

diff --git a/composer.json b/composer.json
index 65c5c82..c5203bc 100644
--- a/composer.json
+++ b/composer.json
@@ -9,7 +9,8 @@
         "slim/twig-view": "^3.3",
         "slim/flash": "^0.4.0",
         "illuminate/database": "^10.40",
-        "symfony/console": "^7.0"
+        "symfony/console": "^7.0",
+        "ext-http": "*"
     },
     "autoload": {
         "psr-4": {
diff --git a/config/bootstrap.php b/config/bootstrap.php
index 29fd374..3302c82 100644
--- a/config/bootstrap.php
+++ b/config/bootstrap.php
@@ -12,8 +12,6 @@ $containerBuilder->addDefinitions(__DIR__ . '/container.php');
 $container = $containerBuilder->build();
 
 $app = $container->get(App::class);
-$app->addRoutingMiddleware();
-$app->add(TwigMiddleware::createFromContainer($app));
 
 (require __DIR__ . '/routes.php')($app);
 
diff --git a/config/container.php b/config/container.php
index 4ffe6ec..cb0173f 100644
--- a/config/container.php
+++ b/config/container.php
@@ -5,6 +5,7 @@ use Slim\Factory\AppFactory;
 use Slim\Middleware\ErrorMiddleware;
 use Psr\Container\ContainerInterface;
 use Slim\Views\Twig;
+use Slim\Views\TwigMiddleware;
 
 return [
     'settings' => function () {
@@ -22,7 +23,10 @@ return [
     App::class => function (ContainerInterface $container) {
         $container->get('db');
         AppFactory::setContainer($container);
-        return AppFactory::create();
+        $app =  AppFactory::create();
+        $app->addRoutingMiddleware();
+        $app->add(TwigMiddleware::createFromContainer($app));
+        return $app;
     },
     ErrorMiddleware::class => function (ContainerInterface $container) {
         $app = $container->get(App::class);
diff --git a/config/routes.php b/config/routes.php
index 0fa6d09..c36ed6f 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -3,9 +3,16 @@
 use Slim\App;
 use App\Controller\CompanyController;
 use App\Controller\HomeController;
+use App\Controller\OfficeController;
 
 return function (App $app) {
     // On gère la route "par défaut" de l'application
     $app->get('/', HomeController::class . ':index');
+
+    // CompanyController
     $app->get('/company/{id}', CompanyController::class . ':index');
+
+    // OfficeController
+    $app->get('/office/{id}/edit', OfficeController::class . ':editGet');
+    $app->post('/office/{id}/edit', OfficeController::class . ':editPost');
 };
diff --git a/public/assets/script.js b/public/assets/script.js
index e69de29..a7ee801 100644
--- a/public/assets/script.js
+++ b/public/assets/script.js
@@ -0,0 +1,43 @@
+const modal = document.querySelector('#modal-wrapper');
+const modalContent = document.querySelector('#modal-content');
+const modalTitle = document.querySelector('#modal-title');
+
+function openModal() {
+modal.classList.add('active');
+}
+
+function closeModal() {
+    modal.classList.remove('active')
+    modalContent.innerHTML = ""
+}
+
+function loadModalContent(url, title) {
+fetch(url)
+.then(response => response.text())
+.then(data => {
+modalContent.innerHTML = data;
+modalTitle.innerHTML = title;
+openModal()
+})
+.catch(error => console.log(error))
+}
+
+// On gère la fermeture du modal
+function init() {
+
+document.querySelector('#close-modal').addEventListener("click", closeModal)
+document.addEventListener('keydown', event => {
+    if (event.key == 'Escape') closeModal();
+
+})
+
+document.querySelector('.offices-list').addEventListener('click', event => {
+    if (event.target.classList.contains('office-edit')) {
+        loadModalContent(`/office/${event.target.dataset.officeId}/edit`, 'Édition du bureau')
+    }
+})
+
+}
+
+
+document.addEventListener('DOMContentLoaded', init)
diff --git a/public/assets/style.css b/public/assets/style.css
index dccb62a..83b83ca 100644
--- a/public/assets/style.css
+++ b/public/assets/style.css
@@ -79,3 +79,65 @@ html, body {
     width: 60px;
     color: var(--accent-color);
 }
+
+.button, button, input[type="submit"] {
+    background: var(--main-color);
+    color: var(--main-bg-color);
+    border-radius: 2px;
+    border: none;
+    padding: 0.5em 1em;
+    cursor: pointer;
+    transition: all 0.2s ease-in-out;
+}
+
+.button:hover, button:hover, input[type="submit"]:hover {
+    background: var(--accent-color);
+}
+
+.button:active, button:active, input[type="submit"]:active {
+    transform: scale(0.95);
+}
+
+.text-center {
+    text-align: center;
+}
+
+.modal-wrapper {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 100;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0,0,0,0.5);
+    display: none;
+    justify-content: center;
+    align-items: center;
+}
+
+#modal {
+    background-color: var(--main-bg-color);
+    padding: 1em ;
+    border-radius: 5px;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+    width: 80%;
+    max-width: 600px;
+}
+
+.modal-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 1em;
+}
+
+.modal-content {
+    margin-bottom: 1em;
+}
+
+.active {
+    display: flex;
+}
+
+
+
diff --git a/src/Console/CreateDatabaseCommand.php b/src/Console/CreateDatabaseCommand.php
index bc0fa5c..1899520 100644
--- a/src/Console/CreateDatabaseCommand.php
+++ b/src/Console/CreateDatabaseCommand.php
@@ -42,6 +42,8 @@ class CreateDatabaseCommand extends Command
     email   VARCHAR(255)                  ,
     website VARCHAR(255)                  ,
     image   VARCHAR(255)                  ,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     head_office_id INT                    ,
     PRIMARY KEY (id)
 );
@@ -59,6 +61,8 @@ class CreateDatabaseCommand extends Command
     email      VARCHAR(255)               ,
     phone      VARCHAR(255)               ,
     company_id INT                NOT NULL,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     PRIMARY KEY (id),
     FOREIGN KEY (company_id) REFERENCES companies (id)
 );
@@ -74,6 +78,8 @@ class CreateDatabaseCommand extends Command
     email      VARCHAR(255)               ,
     phone      VARCHAR(255)               ,
     job_title  VARCHAR(255)               ,
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     PRIMARY KEY (id),
     FOREIGN KEY (office_id) REFERENCES offices (id)
 );
diff --git a/src/Console/PopulateDatabaseCommand.php b/src/Console/PopulateDatabaseCommand.php
index 8c8fbde..baaaeef 100644
--- a/src/Console/PopulateDatabaseCommand.php
+++ b/src/Console/PopulateDatabaseCommand.php
@@ -42,26 +42,26 @@ class PopulateDatabaseCommand extends Command
 
 
         $db->getConnection()->statement("INSERT INTO `companies` VALUES
-    (1,'Stack Exchange','0601010101','stack@exchange.com','https://stackexchange.com/','https://i.stack.imgur.com/UPdHB.jpg',null),
-    (2,'Google','0602020202','contact@google.com','https://www.google.com','https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Google_office_%284135991953%29.jpg/800px-Google_office_%284135991953%29.jpg?20190722090506',null)
+    (1,'Stack Exchange','0601010101','stack@exchange.com','https://stackexchange.com/','https://i.stack.imgur.com/UPdHB.jpg', now(), now(), null),
+    (2,'Google','0602020202','contact@google.com','https://www.google.com','https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Google_office_%284135991953%29.jpg/800px-Google_office_%284135991953%29.jpg?20190722090506',now(), now(), null)
         ");
 
         $db->getConnection()->statement("INSERT INTO `offices` VALUES
-    (1,'Bureau de Nancy','1 rue Stanistlas','Nancy','54000','France','nancy@stackexchange.com',NULL,1),
-    (2,'Burea de Vandoeuvre','46 avenue Jeanne d\'Arc','Vandoeuvre','54500','France',NULL,NULL,1),
-    (3,'Siege sociale','2 rue de la primatiale','Paris','75000','France',NULL,NULL,2),
-    (4,'Bureau Berlinois','192 avenue central','Berlin','12277','Allemagne',NULL,NULL,2)
+    (1,'Bureau de Nancy','1 rue Stanistlas','Nancy','54000','France','nancy@stackexchange.com',NULL,1, now(), now()),
+    (2,'Burea de Vandoeuvre','46 avenue Jeanne d\'Arc','Vandoeuvre','54500','France',NULL,NULL,1, now(), now()),
+    (3,'Siege sociale','2 rue de la primatiale','Paris','75000','France',NULL,NULL,2, now(), now()),
+    (4,'Bureau Berlinois','192 avenue central','Berlin','12277','Allemagne',NULL,NULL,2, now(), now())
         ");
 
         $db->getConnection()->statement("INSERT INTO `employees` VALUES
-    (1,'Camille','La Chenille',1,'camille.la@chenille.com',NULL,'Ingénieur'),
-    (2,'Albert','Mudhat',2,'albert.mudhat@aqume.net',NULL,'Superviseur'),
-    (3,'Sylvie','Tesse',3,'sylive.tesse@factice.local',NULL,'PDG'),
-    (4,'John','Doe',4,'john.doe@generique.org',NULL,'Testeur'),
-    (5,'Jean','Bon',1,'jean@test.com',NULL,'Developpeur'),
-    (6,'Anais','Dufour',2,'anais@aqume.net',NULL,'DBA'),
-    (7,'Sylvain','Poirson',3,'sylvain@factice.local',NULL,'Administrateur réseau'),
-    (8,'Telma','Thiriet',4,'telma@generique.org',NULL,'Juriste')
+     (1,'Camille','La Chenille',1,'camille.la@chenille.com',NULL,'Ingénieur', now(), now()),
+     (2,'Albert','Mudhat',2,'albert.mudhat@aqume.net',NULL,'Superviseur', now(), now()),
+     (3,'Sylvie','Tesse',3,'sylive.tesse@factice.local',NULL,'PDG', now(), now()),
+     (4,'John','Doe',4,'john.doe@generique.org',NULL,'Testeur', now(), now()),
+     (5,'Jean','Bon',1,'jean@test.com',NULL,'Developpeur', now(), now()),
+     (6,'Anais','Dufour',2,'anais@aqume.net',NULL,'DBA', now(), now()),
+     (7,'Sylvain','Poirson',3,'sylvain@factice.local',NULL,'Administrateur réseau', now(), now()),
+     (8,'Telma','Thiriet',4,'telma@generique.org',NULL,'Juriste', now(), now())
         ");
 
         $db->getConnection()->statement("update companies set head_office_id = 1 where id = 1;");
diff --git a/src/Controller/OfficeController.php b/src/Controller/OfficeController.php
new file mode 100644
index 0000000..1cde511
--- /dev/null
+++ b/src/Controller/OfficeController.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Controller;
+
+use App\Models\Company;
+use App\Models\Office;
+use http\Exception\InvalidArgumentException;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Exception\HttpNotFoundException;
+
+
+class OfficeController extends DefaultController
+{
+    public function editGet(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    {
+       $office = $this->findOfficeById($request);
+
+        return $this->twig->render($response, 'office/form.twig', ['office' => $office]);
+    }
+
+    public function editPost(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    {
+        $office = $this->findOfficeById($request);
+        $officeQuery = $request->getParsedBody();
+        if ($officeQuery['officeName'] !== null && $officeQuery['officeName'] !== $office->name) {
+            $office->name = $officeQuery['officeName'];
+        }
+        if ($officeQuery['officeAddress'] !== null && $officeQuery['officeAddress'] !== $office->address) {
+            $office->address = $officeQuery['officeAddress'];
+        }
+        if ($officeQuery['officeCity'] !== null && $officeQuery['officeCity'] !== $office->city) {
+            $office->city = $officeQuery['officeCity'];
+        }
+        if ($officeQuery['officeZipCode'] !== null && $officeQuery['officeZipCode'] !== $office->zip_code) {
+            $office->zip_code = $officeQuery['officeZipCode'];
+        }
+        if ($officeQuery['officeCountry'] !== null && $officeQuery['officeCountry'] !== $office->country) {
+            $office->country = $officeQuery['officeCountry'];
+        }
+        if ($officeQuery['officeEmail'] !== null && $officeQuery['officeEmail'] !== $office->email) {
+            $office->email = $officeQuery['officeEmail'];
+        }
+        if ($officeQuery['officePhone'] !== null && $officeQuery['officePhone'] !== $office->phone) {
+            $office->phone = $officeQuery['officePhone'];
+        }
+        $office->save();
+        return $response->withStatus(302)->withHeader('Location', '/company/' . $office->company->id);
+    }
+
+
+    private function findOfficeById(ServerRequestInterface $request): Office
+    {
+        $officeId = $request->getAttribute('id');
+        // On vérifie que l'id est bien un int
+        if (!is_numeric($officeId)) {
+            throw new InvalidArgumentException('Invalid office id format');
+        }
+
+        $office = Office::find($request->getAttribute('id'));
+        if (!$office) {
+            throw new HttpNotFoundException($request);
+        }
+        return $office;
+    }
+}
diff --git a/src/Models/Company.php b/src/Models/Company.php
index 1327b4f..2763e4c 100644
--- a/src/Models/Company.php
+++ b/src/Models/Company.php
@@ -7,6 +7,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\Relations\HasOne;
 
+/**
+ * @method static find($id)
+ */
 class Company extends Model
 {
     protected $table = 'companies';
diff --git a/view/company/index.twig b/view/company/index.twig
index 273d4ca..96ecc12 100644
--- a/view/company/index.twig
+++ b/view/company/index.twig
@@ -10,6 +10,9 @@
 		{% for office in company.offices %}
 			<div class="office">
 				<h2>{{ office.name }}</h2>
+				<div class="text-center">
+					<button class="office-edit" data-office-id="{{ office.id }}">✏️&nbsp;&nbsp;Éditer</button>
+				</div>
 				<p>Siège social: {{ office.headOffice ? 'Oui' : 'Non' }}</p>
 				<p>Adresse: {{ office.getFullAddressAttribute() }}</p>
 				<div>
diff --git a/view/layout.twig b/view/layout.twig
index 3235bf2..e46caf8 100644
--- a/view/layout.twig
+++ b/view/layout.twig
@@ -12,6 +12,19 @@
 <body>
 {% block body %}{% endblock %}
 
+
+<div id="modal-wrapper" class="modal-wrapper">
+	<div id="modal">
+		<div class="modal-header">
+			<h2 id="modal-title">Titre</h2>
+			<button id="close-modal">X</button>
+		</div>
+		<div id="modal-content">
+			Bonjour
+		</div>
+	</div>
+</div>
+
 {% block scripts %}
 	<script src="/assets/script.js"></script>
 {% endblock %}
diff --git a/view/office/form.twig b/view/office/form.twig
new file mode 100644
index 0000000..54f60bd
--- /dev/null
+++ b/view/office/form.twig
@@ -0,0 +1,37 @@
+<form id="officeForm" method="post" action="/office/{{ office.id }}/edit">
+	<div>
+		<label for="officeID">ID du bureau</label>
+		<input type="text" name="office ID" id="officeID" value="{{ office.id }}" disabled/>
+	</div>
+	<div>
+		<label for="officeName">Nom du bureau</label>
+		<input type="text" maxlength="255" name="officeName" id="officeName" value="{{ office.name }}" />
+	</div>
+	<div>
+		<label for="officeAddress">Adresse</label>
+		<input type="text" maxlength="255" name="officeAddress" id="officeAddress" value="{{ office.address }}" />
+	</div>
+	<div>
+		<label for="officeCity">Ville</label>
+		<input type="text" maxlength="255" name="officeCity" id="officeCity" value="{{ office.city }}" />
+	</div>
+	<div>
+		<label for="officeZipCode">Code Postal</label>
+		<input type="text" maxlength="255" name="officeZipCode" id="officeZipCode" value="{{ office.zip_code }}" />
+	</div>
+	<div>
+		<label for="officeCountry">Pays</label>
+		<input type="text" maxlength="255" name="officeCountry" id="officeCountry" value="{{ office.country }}" />
+	</div>
+	<div>
+		<label for="officeEmail">Email</label>
+		<input type="email" maxlength="255" name="officeEmail" id="officeEmail" value="{{ office.email }}" />
+	</div>
+	<div>
+		<label for="officePhone">Telephone</label>
+		<input type="tel" maxlength="255" name="officePhone" id="officePhone" value="{{ office.phone }}" />
+	</div>
+	<div>
+		<input type="submit" value="Enregistrer" />
+	</div>
+</form>
-- 
GitLab