diff --git a/assets/styles/app.css b/assets/styles/app.css index 46885ee..686d1c8 100755 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -5,21 +5,3 @@ @source '../../vendor/tales-from-a-dev/flowbite-bundle/templates/**/*.html.twig'; @custom-variant dark (@media (prefers-color-scheme: dark)); - -/* - The default border color has changed to `currentColor` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. -*/ -@layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentColor); - } -} diff --git a/composer.json b/composer.json index 72a2218..cd4485b 100755 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "symfony/twig-bundle": "7.2.*", "symfony/uid": "7.2.*", "symfony/ux-dropzone": "^2.23.0", - "symfony/ux-icons": "^2.23.0", + "symfony/ux-icons": "^2.23", "symfony/ux-turbo": "^2.23.0", "symfony/ux-twig-component": "^2.23.0", "symfony/validator": "7.2.*", diff --git a/composer.lock b/composer.lock index 5f4cbe8..8b8bb2a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "03d94385bcbb64b3bf80357c56e137b0", + "content-hash": "1d09b12a04dca26002dc08d1ee5a0f7a", "packages": [ { "name": "composer/semver", diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php index f11892a..18dce73 100644 --- a/src/Controller/ProfileController.php +++ b/src/Controller/ProfileController.php @@ -4,13 +4,28 @@ declare(strict_types=1); namespace App\Controller; +use App\DTO\EmailDTO; +use App\DTO\PasswordDTO; use App\Entity\User; +use App\Form\EmailFormType; +use App\Form\PasswordFormType; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; class ProfileController extends AbstractController { + public function __construct( + private readonly EntityManagerInterface $entityManager, + private readonly UserPasswordHasherInterface $passwordHasher, + ) + { + } + #[Route('/profile', name: 'app_profile')] #[IsGranted('ROLE_USER')] public function index() @@ -19,8 +34,75 @@ class ProfileController extends AbstractController * @var User $user */ $user = $this->getUser(); + return $this->render('profile/index.html.twig', [ 'user' => $user, ]); } + + #[Route('/profile/edit/email', name: 'app_profile_email_edit')] + #[IsGranted('ROLE_USER')] + public function editEmail(Request $request): Response + { + $emailDTO = new EmailDTO(); + $form = $this->createForm(EmailFormType::class, $emailDTO); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** + * @var User $user + */ + $user = $this->getUser(); + + if ($this->passwordHasher->isPasswordValid($user, $emailDTO->password)) { + $user->setEmail($emailDTO->email); + $this->entityManager->flush(); + + $this->addFlash('success', 'Votre adresse email a bien été modifiée.'); + + return $this->redirectToRoute('app_profile'); + } + + $this->addFlash('error', 'Le mot de passe est incorrect.'); + } + + return $this->render('profile/edit_email.html.twig', [ + 'form' => $form->createView(), + ]); + } + + + + #[Route('/profile/edit/password', name: 'app_profile_password_edit')] + #[IsGranted('ROLE_USER')] + public function editPassword(Request $request): Response + { + $passwordDTO = new PasswordDTO(); + $form = $this->createForm(PasswordFormType::class, $passwordDTO); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** + * @var User $user + */ + $user = $this->getUser(); + + if ($this->passwordHasher->isPasswordValid($user, $passwordDTO->password)) { + $user->setPassword($this->passwordHasher->hashPassword($user, $passwordDTO->newPassword)); + $this->entityManager->flush(); + + $this->addFlash('success', 'Votre mot de passe a bien été modifiée.'); + + return $this->redirectToRoute('app_profile'); + } + + $this->addFlash('error', 'Le mot de passe est incorrect.'); + } + + return $this->render('profile/edit_password.html.twig', [ + 'form' => $form->createView(), + ]); + } } diff --git a/src/DTO/EmailDTO.php b/src/DTO/EmailDTO.php new file mode 100644 index 0000000..7b116ad --- /dev/null +++ b/src/DTO/EmailDTO.php @@ -0,0 +1,15 @@ +add('email', EmailType::class, [ + 'label' => 'Nouvelle adresse email', + 'attr' => [ + 'placeholder' => 'Nouvelle adresse email', + 'autocomplete' => 'new-email', + ], + ]) + ->add('password', PasswordType::class, [ + 'label' => 'Mot de passe actuel', + 'attr' => [ + 'placeholder' => 'Mot de passe actuel', + 'autocomplete' => 'new-password', + ] + ]) + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => EmailDTO::class, + 'attr' => [ + 'autocomplete' => 'off', + ] + ]); + } +} diff --git a/src/Form/PasswordFormType.php b/src/Form/PasswordFormType.php new file mode 100644 index 0000000..8cd16e6 --- /dev/null +++ b/src/Form/PasswordFormType.php @@ -0,0 +1,51 @@ +add('password', PasswordType::class, [ + 'label' => 'Mot de passe actuel', + 'attr' => [ + 'placeholder' => 'Mot de passe actuel', + 'autocomplete' => 'old-password', + ], + 'required' => true, + ]) + ->add('newPassword', RepeatedType::class, [ + 'type' => PasswordType::class, + 'first_options' => ['label' => 'Nouveau mot de passe'], + 'attr' => [ + 'autocomplete' => 'new-password', + ], + 'second_options' => ['label' => 'Confirmer le mot de passe'], + 'required' => true, + 'invalid_message' => 'Les mots de passe ne correspondent pas.', + ]) + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => PasswordDTO::class, + ]); + } +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..aa17d40 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,15 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./vendor/tales-from-a-dev/flowbite-bundle/templates/**/*.html.twig", + "./assets/**/*.js", + "./templates/**/*.html.twig", + ], + theme: { + extend: {}, + }, + plugins: [ + require('flowbite/plugin') + ], + darkMode: 'media', +} \ No newline at end of file diff --git a/templates/profile/edit_email.html.twig b/templates/profile/edit_email.html.twig new file mode 100644 index 0000000..a209d1b --- /dev/null +++ b/templates/profile/edit_email.html.twig @@ -0,0 +1,15 @@ +{% extends 'base.html.twig' %} + +{% block body %} +