Ajout visualisation candidatures Intern et Employee

This commit is contained in:
Romain 2025-04-06 16:03:58 +02:00
parent 0246adcc03
commit 1722e0e6b5
10 changed files with 207 additions and 29 deletions

2
.gitignore vendored
View File

@ -23,5 +23,3 @@
.idea .idea
composer.lock composer.lock
/migrations/

30
composer.lock generated
View File

@ -6249,16 +6249,16 @@
}, },
{ {
"name": "symfony/stimulus-bundle", "name": "symfony/stimulus-bundle",
"version": "v2.23.0", "version": "v2.24.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/stimulus-bundle.git", "url": "https://github.com/symfony/stimulus-bundle.git",
"reference": "254f4e05cbaa349d4ae68b9b2e6a22995e0887f9" "reference": "e09840304467cda3324cc116c7f4ee23c8ff227c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/254f4e05cbaa349d4ae68b9b2e6a22995e0887f9", "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/e09840304467cda3324cc116c7f4ee23c8ff227c",
"reference": "254f4e05cbaa349d4ae68b9b2e6a22995e0887f9", "reference": "e09840304467cda3324cc116c7f4ee23c8ff227c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6298,7 +6298,7 @@
"symfony-ux" "symfony-ux"
], ],
"support": { "support": {
"source": "https://github.com/symfony/stimulus-bundle/tree/v2.23.0" "source": "https://github.com/symfony/stimulus-bundle/tree/v2.24.0"
}, },
"funding": [ "funding": [
{ {
@ -6314,7 +6314,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-01-16T21:55:09+00:00" "time": "2025-03-09T21:10:04+00:00"
}, },
{ {
"name": "symfony/stopwatch", "name": "symfony/stopwatch",
@ -6914,16 +6914,16 @@
}, },
{ {
"name": "symfony/ux-turbo", "name": "symfony/ux-turbo",
"version": "v2.23.0", "version": "v2.24.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/ux-turbo.git", "url": "https://github.com/symfony/ux-turbo.git",
"reference": "db96cf04d70a8c820671ce55530e8bf641ada33f" "reference": "22954300bd0b01ca46f17c7890ea15138d9cf67f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/ux-turbo/zipball/db96cf04d70a8c820671ce55530e8bf641ada33f", "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/22954300bd0b01ca46f17c7890ea15138d9cf67f",
"reference": "db96cf04d70a8c820671ce55530e8bf641ada33f", "reference": "22954300bd0b01ca46f17c7890ea15138d9cf67f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6992,7 +6992,7 @@
"turbo-stream" "turbo-stream"
], ],
"support": { "support": {
"source": "https://github.com/symfony/ux-turbo/tree/v2.23.0" "source": "https://github.com/symfony/ux-turbo/tree/v2.24.0"
}, },
"funding": [ "funding": [
{ {
@ -7008,7 +7008,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-02-06T08:47:30+00:00" "time": "2025-04-04T17:29:20+00:00"
}, },
{ {
"name": "symfony/validator", "name": "symfony/validator",
@ -9903,7 +9903,7 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {},
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
@ -9911,6 +9911,6 @@
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*" "ext-iconv": "*"
}, },
"platform-dev": [], "platform-dev": {},
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

View File

@ -3,8 +3,11 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Employee; use App\Entity\Employee;
use App\Entity\InternApplication;
use App\Form\EmployeeType; use App\Form\EmployeeType;
use App\Repository\AnnouncementRepository;
use App\Repository\EmployeeRepository; use App\Repository\EmployeeRepository;
use App\Repository\InternApplicationRepository;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -14,11 +17,19 @@ use Symfony\Component\Routing\Attribute\Route;
#[Route('/employee')] #[Route('/employee')]
final class EmployeeController extends AbstractController final class EmployeeController extends AbstractController
{ {
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly EmployeeRepository $employeeRepository,
private readonly AnnouncementRepository $announcementRepository,
private readonly InternApplicationRepository $internApplicationRepository
)
{
}
#[Route(name: 'app_employee_index', methods: ['GET'])] #[Route(name: 'app_employee_index', methods: ['GET'])]
public function index(EmployeeRepository $employeeRepository): Response public function index(): Response
{ {
return $this->render('employee/index.html.twig', [ return $this->render('employee/index.html.twig', [
'employees' => $employeeRepository->findAll(), 'employees' => $this->employeeRepository->findAll(),
]); ]);
} }
@ -31,13 +42,13 @@ final class EmployeeController extends AbstractController
} }
#[Route('/{id}/edit', name: 'app_employee_edit', methods: ['GET', 'POST'])] #[Route('/{id}/edit', name: 'app_employee_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Employee $employee, EntityManagerInterface $entityManager): Response public function edit(Request $request, Employee $employee): Response
{ {
$form = $this->createForm(EmployeeType::class, $employee); $form = $this->createForm(EmployeeType::class, $employee);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush(); $this->entityManager->flush();
return $this->redirectToRoute('app_employee_index', [], Response::HTTP_SEE_OTHER); return $this->redirectToRoute('app_employee_index', [], Response::HTTP_SEE_OTHER);
} }
@ -49,13 +60,37 @@ final class EmployeeController extends AbstractController
} }
#[Route('/{id}', name: 'app_employee_delete', methods: ['POST'])] #[Route('/{id}', name: 'app_employee_delete', methods: ['POST'])]
public function delete(Request $request, Employee $employee, EntityManagerInterface $entityManager): Response public function delete(Request $request, Employee $employee): Response
{ {
if ($this->isCsrfTokenValid('delete'.$employee->getId(), $request->getPayload()->getString('_token'))) { if ($this->isCsrfTokenValid('delete'.$employee->getId(), $request->getPayload()->getString('_token'))) {
$entityManager->remove($employee); $this->entityManager->remove($employee);
$entityManager->flush(); $this->entityManager->flush();
} }
return $this->redirectToRoute('app_employee_index', [], Response::HTTP_SEE_OTHER); return $this->redirectToRoute('app_employee_index', [], Response::HTTP_SEE_OTHER);
} }
#[Route('/seeApplications', name: 'app_employee_applications')]
public function seeApplications(): Response
{
$employee = $this->getUser();
if (!$employee instanceof Employee){
throw $this->createAccessDeniedException('Seuls les employés peuvent accéder à cette page.');
}
$company = $employee->getCompany();
$announcements = $this->announcementRepository
->findBy(['company' => $company]);
$applications = $this->internApplicationRepository
->findBy(['announcement' => $announcements]);
return $this->render('employee/applications.html.twig', [
'applications' => $applications,
]);
}
} }

View File

@ -135,6 +135,7 @@ final class InternController extends AbstractController
$internApplication->setIntern($intern); $internApplication->setIntern($intern);
$internApplication->setApplication($announcement); $internApplication->setApplication($announcement);
$internApplication->setApplicationDate(new \DateTime()); $internApplication->setApplicationDate(new \DateTime());
$internApplication->setStatus("En Attente");
$entityManager->persist($internApplication); $entityManager->persist($internApplication);
} }

View File

@ -2,6 +2,9 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\Announcement;
use App\Entity\Intern;
use App\Entity\InternApplication;
use App\Entity\UserApp; use App\Entity\UserApp;
use App\Form\UserAppType; use App\Form\UserAppType;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@ -13,7 +16,7 @@ use Symfony\Component\Routing\Attribute\Route;
class ProfileController extends AbstractController class ProfileController extends AbstractController
{ {
#[Route('/profile', name: 'app_profile')] #[Route('/profile', name: 'app_profile')]
public function profile(): Response public function profile(EntityManagerInterface $entityManager): Response
{ {
$user = $this->getUser(); $user = $this->getUser();
@ -21,8 +24,23 @@ class ProfileController extends AbstractController
throw $this->createAccessDeniedException('Vous devez être connecté pour accéder à cette page.'); throw $this->createAccessDeniedException('Vous devez être connecté pour accéder à cette page.');
} }
if ($user instanceof Intern)
{
$internApplicationRepository = $entityManager->getRepository(InternApplication::class);
$internApplications = $internApplicationRepository->findBy([
'intern' => $user,
]);
return $this->render('profile/index.html.twig', [
'user' => $user,
'applications' => $internApplications
]);
}
return $this->render('profile/index.html.twig', [ return $this->render('profile/index.html.twig', [
'user' => $user, 'user' => $user,
'applications' => []
]); ]);
} }
@ -44,6 +62,21 @@ class ProfileController extends AbstractController
]); ]);
} }
#[Route('/profile/{id}/visit', name: 'app_profile_visit')]
public function visitProfile(EntityManagerInterface $entityManager, int $id): Response
{
$user = $entityManager->getRepository(Intern::class)->find($id);
if (!$user) {
throw $this->createNotFoundException('Utilisateur non trouvé.');
}
return $this->render('profile/index.html.twig', [
'user' => $user,
]);
}
#[Route('profile/pickDegree', name: 'app_profile_pickDegree', methods: ['GET'])] #[Route('profile/pickDegree', name: 'app_profile_pickDegree', methods: ['GET'])]
public function pickDegree(UserApp $userApp): Response public function pickDegree(UserApp $userApp): Response
{ {

View File

@ -23,6 +23,9 @@ class InternApplication
#[ORM\Column(type: Types::DATE_MUTABLE)] #[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $applicationDate = null; private ?\DateTimeInterface $applicationDate = null;
#[ORM\Column(length: 20)]
private ?string $status = null;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -63,4 +66,14 @@ class InternApplication
return $this; return $this;
} }
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): void
{
$this->status = $status;
}
} }

View File

@ -0,0 +1,24 @@
{% extends 'base.html.twig' %}
{% block title %}Liste des Candidatures{% endblock %}
{% block body %}
<h2 class="text-2xl font-bold mb-6">Candidatures reçues</h2>
{% for app in applications %}
<div class="border border-gray-300 rounded-lg p-4 mb-4 shadow-sm bg-white">
<p><strong>Annonce :</strong> {{ app.application.title }}</p>
<p><strong>Candidat :</strong> {{ app.intern.firstName }} {{ app.intern.lastName }}</p>
<p><strong>Date :</strong> {{ app.applicationDate|date('d/m/Y') }}</p>
<p><strong>Statut :</strong> {{ app.status }}</p>
<a href="{{ path('app_profile_visit', { id: app.intern.id }) }}"
class="inline-block mt-2 bg-teal-500 hover:bg-teal-600 text-white px-4 py-2 rounded">
Voir le profil du candidat
</a>
</div>
{% else %}
<p>Aucune candidature pour le moment.</p>
{% endfor %}
{% endblock %}

View File

@ -8,6 +8,12 @@
<p class="text-gray-600">Téléphone : {{ app.user.tel }}</p> <p class="text-gray-600">Téléphone : {{ app.user.tel }}</p>
<p class="text-gray-600">Email : {{ app.user.mail }}</p> <p class="text-gray-600">Email : {{ app.user.mail }}</p>
<a href="{{ path('app_employee_applications') }}"
class="bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded">
Voir les candidatures reçues
</a>
<div class="flex justify-end mt-6"> <div class="flex justify-end mt-6">
<a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full" <a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full"
href="{{ path('app_profile_edit',{id: app.user.id}) }}"> Modifier href="{{ path('app_profile_edit',{id: app.user.id}) }}"> Modifier

View File

@ -37,10 +37,26 @@
<a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full" <a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full"
href="{{ path('app_user_edit',{id: app.user.id}) }}"> Accéder aux favoris href="{{ path('app_user_edit',{id: app.user.id}) }}"> Accéder aux favoris
</a> </a>
<a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full"
href="{{ path('app_user_edit',{id: app.user.id}) }}"> Accéder aux candidatures
</a>
</div> </div>
<h3 class="text-lg font-semibold mt-6">Vos candidatures :</h3>
{% if applications|length > 0 %}
<ul class="space-y-4 mt-2">
{% for appli in applications %}
<div class="border border-gray-300 bg-gray-50 p-4 rounded-lg shadow-sm">
<p><strong>Offre :</strong> {{ appli.application.title }}</p>
<p><strong>Entreprise :</strong> {{ appli.application.company.name }}</p>
<p><strong>Date de candidature :</strong> {{ appli.applicationDate|date('d/m/Y') }}</p>
<p><strong>Statut :</strong> {{ appli.status }}</p>
</div>
{% endfor %}
</ul>
{% else %}
<p class="text-gray-600">Vous n'avez pas encore postulé à une offre.</p>
{% endif %}
<div class="flex justify-end mt-6"> <div class="flex justify-end mt-6">
<a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full" <a class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full"
href="{{ path('app_profile_edit',{id: app.user.id}) }}"> Modifier href="{{ path('app_profile_edit',{id: app.user.id}) }}"> Modifier

View File

@ -0,0 +1,52 @@
{% extends 'base.html.twig' %}
{% block title %}Profil du candidat{% endblock %}
{% block body %}
<div class="max-w-3xl mx-auto mt-8 bg-white p-6 rounded-lg shadow-lg border border-gray-300">
<h2 class="text-2xl font-bold mb-4">Profil du candidat</h2>
<div class="mb-4">
<p><strong>Nom :</strong> {{ user.lastName }}</p>
<p><strong>Prénom :</strong> {{ user.firstName }}</p>
<p><strong>Email :</strong> {{ user.mail }}</p>
<p><strong>Téléphone :</strong> {{ user.tel }}</p>
<p><strong>Adresse :</strong> {{ user.address }}</p>
</div>
<div class="mb-4">
<h3 class="text-xl font-semibold">Diplômes</h3>
<ul class="list-disc list-inside text-gray-800 mt-2">
{% if user.degrees|length > 0 %}
{% for deg in user.degrees %}
<li>
{{ deg.degree.label }} — Obtenu le {{ deg.graduationDate|date('d/m/Y') }}
</li>
{% endfor %}
{% else %}
<p class="text-gray-500 mt-2">Aucun diplôme renseigné.</p>
{% endif %}
</ul>
</div>
<div class="mb-4">
<h3 class="text-xl font-semibold">Compétences</h3>
<ul class="list-disc list-inside text-gray-800 mt-2">
{% if user.skills|length > 0 %}
{% for skill in user.skills %}
<li>{{ skill.label }}</li>
{% endfor %}
{% else %}
<p class="text-gray-500 mt-2">Aucune compétence renseignée.</p>
{% endif %}
</ul>
</div>
<div class="mt-6">
<a href="{{ path('app_index') }}"
class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded-full">
Retour à l'accueil
</a>
</div>
</div>
{% endblock %}