fixation beton

This commit is contained in:
bourgoino 2024-12-09 15:47:20 +01:00
parent a0e50bf187
commit 579a56c53f
15 changed files with 353 additions and 194 deletions

View File

@ -1,48 +0,0 @@
<?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 Version20241017125351 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 user_id_seq CASCADE');
$this->addSql('CREATE SEQUENCE "userApp_id_seq" INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE "userApp" (id INT NOT NULL, nickname VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, tel VARCHAR(255) NOT NULL, address VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NICKNAME ON "userApp" (nickname)');
$this->addSql('ALTER TABLE employee DROP CONSTRAINT fk_5d9f75a1bf396750');
$this->addSql('ALTER TABLE intern DROP CONSTRAINT fk_a5795f36bf396750');
$this->addSql('DROP TABLE employee');
$this->addSql('DROP TABLE "user"');
$this->addSql('DROP TABLE intern');
}
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 SEQUENCE "userApp_id_seq" CASCADE');
$this->addSql('CREATE SEQUENCE user_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE employee (id INT NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE "user" (id INT NOT NULL, nickname VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, tel VARCHAR(255) NOT NULL, address VARCHAR(255) NOT NULL, mail VARCHAR(255) NOT NULL, discriminator VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE UNIQUE INDEX uniq_identifier_nickname ON "user" (nickname)');
$this->addSql('CREATE TABLE intern (id INT NOT NULL, cover_letter TEXT NOT NULL, resume VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('ALTER TABLE employee ADD CONSTRAINT fk_5d9f75a1bf396750 FOREIGN KEY (id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE intern ADD CONSTRAINT fk_a5795f36bf396750 FOREIGN KEY (id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('DROP TABLE "userApp"');
}
}

View File

@ -11,74 +11,95 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/announcement', name: 'app_announcement')]
class AnnouncementController extends AbstractController
#[Route('/announcement')]
final class AnnouncementController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly AnnouncementRepository $announcementRepository
)
#[Route('/', name: 'app_announcement_index', methods: ['GET'])]
public function index(Request $request, AnnouncementRepository $announcementRepository): Response
{
$showNonValidated = $request->query->get('show_non_validated') === '1';
$announcements = $showNonValidated
? $announcementRepository->findBy(['status' => 'notVerified'])
: $announcementRepository->findAll();
return $this->render('announcement/index.html.twig', [
'announcements' => $announcements,
'showNonValidated' => $showNonValidated,
]);
}
#[Route('/add', name: '_add')]
public function addAnnouncement(Request $request): Response
#[Route('/new', name: 'app_announcement_new', methods: ['GET', 'POST'])]
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$announcement = new Announcement();
$form = $this->createForm(AnnouncementType::class, $announcement);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
//met la date de création de l'annonce au moment où le formulaire est envoyé
if ($form->isSubmitted() && $form->isValid()) {
$announcement->setCreationDate(new \DateTime());
$announcement->setStatus('notVerified');
$entityManager->persist($announcement);
$entityManager->flush();
$this->entityManager->persist($announcement);
$this->entityManager->flush();
$this->addFlash('success', 'Annonce créée avec succès.');
return $this->redirectToRoute('app_announcement_list');
return $this->redirectToRoute('app_announcement_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('announcement/add.html.twig', [
'announcementForm' => $form,
return $this->render('announcement/new.html.twig', [
'announcement' => $announcement,
'form' => $form,
]);
}
#[Route('/list', name: '_list')]
public function list(): Response
#[Route('/{id}', name: 'app_announcement_show', methods: ['GET'])]
public function show(Announcement $announcement): Response
{
$announcements = $this->announcementRepository->findAll();
return $this->render('announcement/list.html.twig', [
'announcements' => $announcements,
return $this->render('announcement/show.html.twig', [
'announcement' => $announcement,
]);
}
#[Route('/update/{id}', name: '_update')]
public function update(int $id, Request $request): Response
#[Route('/{id}/edit', name: 'app_announcement_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Announcement $announcement, EntityManagerInterface $entityManager): Response
{
$announcement = $this->announcementRepository->find($id);
$form = $this->createForm(AnnouncementType::class, $announcement);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
$this->entityManager->persist($announcement);
$this->entityManager->flush();
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute('app_announcement_index', [], Response::HTTP_SEE_OTHER);
}
return $this->render('announcement/add.html.twig', [
'formAdd' => $form,
return $this->render('announcement/edit.html.twig', [
'announcement' => $announcement,
'form' => $form,
]);
}
#[Route('/delete/{id}', name: '_delete')]
public function delete(int $id): Response
#[Route('/{id}', name: 'app_announcement_delete', methods: ['POST'])]
public function delete(Request $request, Announcement $announcement, EntityManagerInterface $entityManager): Response
{
$announcement = $this->announcementRepository->find($id);
$this->entityManager->remove($announcement);
$this->entityManager->flush();
if ($this->isCsrfTokenValid('delete'.$announcement->getId(), $request->getPayload()->getString('_token'))) {
$entityManager->remove($announcement);
$entityManager->flush();
}
return $this->redirectToRoute('app_announcement_list');
return $this->redirectToRoute('app_announcement_index', [], Response::HTTP_SEE_OTHER);
}
#[Route('/{id}/validate', name: 'app_announcement_validate', methods: ['POST'])]
public function validate(Request $request, Announcement $announcement, EntityManagerInterface $entityManager): Response
{
if ($announcement->getStatus() !== 'Verified')
{
$announcement->setStatus('Verified');
$entityManager->flush();
}
return $this->redirectToRoute('app_announcement_show',
['id' => $announcement->getId()], Response::HTTP_SEE_OTHER);
}
}

View File

@ -27,7 +27,13 @@ class Announcement
private ?Company $company = null;
#[ORM\Column(nullable: false)]
private ?string $status = null;
private ?string $status = "notVerfied";
#[ORM\Column(nullable: false)]
private ?string $date = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $creationDate = null;
/**
* @var ?Collection<int, InternApplication>
@ -41,9 +47,6 @@ class Announcement
#[ORM\OneToMany(targetEntity: InternFavorite::class, mappedBy: 'announcement')]
private ?Collection $favoritesInterns;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $creationDate = null;
public function __construct()
{
$this->applicants = new ArrayCollection();
@ -96,7 +99,7 @@ class Announcement
return $this->status;
}
public function setStatus(?string $status): static
public function setStatus(?string $status): self
{
$this->status = $status;
@ -174,4 +177,16 @@ class Announcement
return $this;
}
public function getDate(): ?string
{
return $this->date;
}
public function setDate(string $date): self
{
$this->date = $date;
return $this;
}
}

View File

@ -10,7 +10,7 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class AnnouncementType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
@ -20,13 +20,12 @@ class AnnouncementType extends AbstractType
->add('description')
->add('company', EntityType::class, [
'class' => Company::class,
'choice_label' => 'id',
'choice_label' => 'name',
])
->add('status', EntityType::class, [
'class' => Status::class,
'choice_label' => 'id',
->add('date', TextType::class, [
'label' => 'Date de stage',
'required' => true,
])
->add('submit', SubmitType::class)
;
}

View File

@ -0,0 +1,4 @@
<form method="post" action="{{ path('app_announcement_delete', {'id': announcement.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ announcement.id) }}">
<button class="btn">Delete</button>
</form>

View File

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View File

@ -1,4 +0,0 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ form(announcementForm) }}
{% endblock %}

View File

@ -0,0 +1,63 @@
{% extends 'base.html.twig' %}
{% block title %}Modifier l'Annonce{% endblock %}
{% block body %}
<div class="container mx-auto p-6">
<h1 class="text-3xl font-bold text-center mb-6">Modifier l'Annonce</h1>
<div class="max-w-4xl mx-auto bg-white p-6 rounded-lg shadow-lg">
<form method="post" action="{{ path('app_announcement_edit', { id: announcement.id }) }}" class="space-y-6">
{{ form_start(form) }}
<div class="mb-4">
<!-- Nom de l'entreprise -->
<label for="announcement_company" class="block text-gray-700 font-semibold">Entreprise</label>
<div>
{{ form_widget(form.company, {'attr': {'class': 'w-full p-3 border rounded-md'}}) }}
</div>
</div>
<!-- Titre de l'annonce -->
<div class="mb-4">
<label for="announcement_title" class="block text-gray-700 font-semibold">Titre de l'annonce</label>
<div>
{{ form_widget(form.title, {'attr': {'class': 'w-full p-3 border rounded-md'}}) }}
</div>
</div>
<!-- Description -->
<div>
<label for="announcement_description" class="block text-gray-700 font-semibold">Description</label>
<div>
{{ form_widget(form.description, { 'attr': { 'class': 'w-full p-3 border rounded-md' } }) }}
</div>
</div>
<!-- Date du stage -->
<div>
<label for="announcement_date" class="block text-gray-700 font-semibold">Date du stage</label>
<div>
{{ form_widget(form.date, { 'attr': { 'class': 'w-full p-3 border rounded-md' } }) }}
</div>
</div>
<!-- Submit Button -->
<div class="text-center">
<button type="submit" class="bg-teal-500 text-white px-6 py-3 rounded-md hover:bg-teal-600">
Enregistrer les modifications
</button>
</div>
{{ form_end(form) }}
</form>
</div>
<!-- Bouton Retour -->
<div class="mt-4">
<a href="{{ path('app_announcement_index') }}" class="text-teal-500 flex items-center">
<i class="fas fa-arrow-left mr-2"></i>Retour à la liste des annonces
</a>
</div>
</div>
{% endblock %}

View File

@ -1,20 +1,78 @@
{% extends 'base.html.twig' %}
{% block title %}Hello AnnouncementController!{% endblock %}
{% block title %}Liste des Annonces{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="container mx-auto p-6">
<h1 class="text-3xl font-bold mb-6 text-center">Liste des Annonces</h1>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
<!-- Formulaire pour afficher uniquement les annonces non validées -->
<form method="get" class="mb-6 text-center">
<label class="flex items-center justify-center space-x-2">
<input
type="checkbox"
name="show_non_validated"
value="1"
{% if showNonValidated %}checked{% endif %}
class="rounded text-teal-500"
>
<span class="text-gray-700">Afficher uniquement les annonces non validées</span>
</label>
<button type="submit" class="ml-4 bg-teal-500 text-white px-4 py-2 rounded mt-2">
Appliquer
</button>
</form>
This friendly message is coming from:
<ul>
<li>Your controller at <code>C:/Users/csese/Romain/Phpstorm_projets/ProjetHegreSphere/hegresphere/src/Controller/AnnouncementController.php</code></li>
<li>Your template at <code>C:/Users/csese/Romain/Phpstorm_projets/ProjetHegreSphere/hegresphere/templates/announcement/index.html.twig</code></li>
</ul>
</div>
<!-- Bouton pour créer une annonce -->
<div class="text-center mb-6">
<a href="{{ path('app_announcement_new') }}" class="bg-teal-500 text-white px-6 py-3 rounded-md hover:bg-teal-600">
Créer une annonce
</a>
</div>
<!-- Liste des annonces -->
<div class="max-w-4xl mx-auto">
{% for announcement in announcements %}
<div class="bg-white p-6 rounded-lg shadow mb-4 relative">
<!-- Statut en haut à droite -->
<div class="absolute top-4 right-4">
{% if announcement.status == 'notVerified' %}
<span class="text-red-500 font-semibold">Non validée</span>
{% else %}
<span class="text-green-500 font-semibold">Validée</span>
{% endif %}
</div>
<!-- Titre de l'annonce -->
<h2 class="text-3xl font-semibold mb-2">{{ announcement.title }}</h2>
<!-- Nom de l'entreprise -->
<p class="text-gray-600 mb-2">{{ announcement.company.name }}</p>
<div class="text-gray-500 text-sm mb-4">
<!-- Date du stage -->
<div class="mb-2">
<i class="fas fa-calendar-alt mr-1"></i>
<span>Date du stage : {{ announcement.date }}</span>
</div>
<!-- Adresse de l'entreprise -->
<div>
<i class="fas fa-map-marker-alt mr-1"></i>
<span>{{ announcement.company.address }}</span>
</div>
</div>
<!-- Lien vers la page de détails -->
<a href="{{ path('app_announcement_show', { id: announcement.id }) }}"
class="bg-teal-500 text-white px-4 py-2 rounded">
Détails
</a>
</div>
{% else %}
<p class="text-center text-gray-500">Aucune annonce disponible.</p>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -1,26 +0,0 @@
{% extends 'base.html.twig' %}
{% block title %}Bienvenue sur Hegreshpere{% endblock %}
{% block body %}
<script src="{{ asset('js/map.js') }}"></script>
<style>
#map {
height: 500px; /* Ajuste la taille selon tes besoins */
margin-bottom: 20px;
}
</style>
<h1> Liste des annonces</h1>
<div id="map"></div> <!-- Conteneur pour la carte -->
{% for ann in announcements %}
<h2> {{ ann.title }} </h2>
<h3> {{ ann.company.name }} </h3>
<p> {{ ann.description }} </p>
------------------------------
<p> {{ ann.creationDate|date("d-m-y") }} </p>
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends 'base.html.twig' %}
{% block title %}Créer une Annonce{% endblock %}
{% block body %}
<div class="container mx-auto p-6">
<h1 class="text-3xl font-bold mb-4">Créer une Annonce</h1>
{{ form_start(form) }}
<div class="mb-4">
{{ form_label(form.title) }}
{{ form_widget(form.title, {'attr': {'class': 'form-input w-full p-2 rounded border'}}) }}
</div>
<div class="mb-4">
{{ form_label(form.description) }}
{{ form_widget(form.description, {'attr': {'class': 'form-input w-full p-2 rounded border'}}) }}
</div>
<div class="mb-4">
{{ form_label(form.date) }}
{{ form_widget(form.date, {'attr': {'class': 'form-input w-full p-2 rounded border'}}) }}
</div>
<div class="mb-4">
{{ form_label(form.company) }}
{{ form_widget(form.company, {'attr': {'class': 'form-input w-full p-2 rounded border'}}) }}
</div>
<button type="submit" class="bg-teal-500 text-white px-4 py-2 rounded">
Créer l'annonce
</button>
{{ form_end(form) }}
</div>
{% endblock %}

View File

@ -0,0 +1,77 @@
{% extends 'base.html.twig' %}
{% block title %}Détails de l'Annonce{% endblock %}
{% block body %}
<div class="container mx-auto p-6">
<h1 class="text-3xl font-bold mb-6">Détails de l'Annonce</h1>
<!-- Détails de l'annonce -->
<div class="bg-white p-6 rounded-lg shadow mb-4">
<!-- Titre de l'annonce -->
<h2 class="text-3xl font-semibold mb-2">{{ announcement.title }}</h2>
<!-- Nom de l'entreprise -->
<p class="text-gray-600 mb-2">{{ announcement.company.name }}</p>
<div class="text-gray-500 text-sm mb-4">
<!-- Date du stage -->
<div class="mb-2">
<i class="fas fa-calendar-alt mr-1"></i>
<span>Date du stage : {{ announcement.date }}</span>
</div>
<!-- Adresse de l'entreprise -->
<div>
<i class="fas fa-map-marker-alt mr-1"></i>
<span>{{ announcement.company.address }}</span>
</div>
</div>
<!-- Description du stage -->
<div class="mb-4">
<strong>Description du stage : </strong>
<p>{{ announcement.description }}</p>
</div>
<!-- Statut de l'annonce -->
<div class="mb-4">
<strong>Statut : </strong>
<span class="text-sm {% if announcement.status == 'notVerified' %}text-red-500{% else %}text-green-500{% endif %}">
{% if announcement.status == 'notVerified' %}
Non validée
{% else %}
Validée
{% endif %}
</span>
</div>
<!-- Date de création -->
<div class="mb-4">
<strong>Date de création : </strong>
<span>{{ announcement.creationDate | date('d/m/Y') }}</span>
</div>
<!-- Boutons Modifier et Valider -->
<div class="mt-4 flex space-x-4">
<a href="{{ path('app_announcement_edit', { id: announcement.id }) }}"
class="bg-teal-500 text-white px-4 py-2 rounded hover:bg-teal-600">
Modifier l'annonce
</a>
{% if announcement.status == 'notVerified' %}
<form method="post" action="{{ path('app_announcement_validate', { id: announcement.id }) }}">
<button type="submit" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">
Valider l'annonce
</button>
</form>
{% endif %}
</div>
</div>
<!-- Bouton de retour à la liste -->
<a href="{{ path('app_announcement_index') }}" class="text-teal-500 flex items-center mb-4">
<i class="fas fa-arrow-left mr-2"></i>Retour à la liste des annonces
</a>
</div>
{% endblock %}

View File

@ -27,8 +27,8 @@
</div>
<nav class="space-x-20">
<a class="hover:text-teal-400" href="{{ path('app_index') }}">Accueil</a>
<a class="hover:text-teal-400" href="{{ path('app_announcement_list') }}">Stages</a>
<a class="hover:text-teal-400" href="{{ path('app_index') }}">FAQ</a>
<a class="hover:text-teal-400" href="{{ path('app_announcement_index') }}">Stages</a>
<a class="hover:text-teal-400" href="{{ path('app_faq_index') }}">FAQ</a>
<a class="hover:text-teal-400" href="{{ path('app_index') }}">Messagerie</a>
</nav>
<div>
@ -57,7 +57,7 @@
<h3 class="text-white text-lg font-bold mb-4">Liens utiles</h3>
<ul class="space-y-2">
<li><a href="{{ path('app_index') }}" class="hover:text-teal-400">Accueil</a></li>
<li><a href="{{ path('app_announcement_list') }}" class="hover:text-teal-400">Liste des stages</a></li>
<li><a href="{{ path('app_announcement_index') }}" class="hover:text-teal-400">Liste des stages</a></li>
<li><a href="{{ path('app_index') }}" class="hover:text-teal-400">Contact</a></li>
<li><a href="{{ path('app_index') }}" class="hover:text-teal-400">Mentions légales</a></li>
</ul>

View File

@ -26,23 +26,24 @@
</div>
<div class="mt-6 flex justify-between">
<a href="{{ path('app_faq_index') }}" class="text-teal-500 hover:text-teal-700">
<!-- Bouton Retour à la liste -->
<a href="{{ path('app_faq_index') }}" class="text-teal-500 hover:text-teal-700 text-lg">
<i class="fas fa-arrow-left"></i> Retour à la liste des FAQs
</a>
<a href="{{ path('app_faq_edit', {'id': faq.id}) }}" class="text-yellow-500 hover:text-yellow-700">
<i class="fas fa-edit"></i> Modifier cette FAQ
</a>
</div>
<div class="mt-6">
<form method="post" action="{{ path('app_faq_delete', {'id': faq.id}) }}" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ faq.id) }}">
<button type="submit" class="text-red-500 hover:text-red-700">
<i class="fas fa-trash-alt"></i> Supprimer cette question
</button>
</form>
<!-- Boutons Modifier et Supprimer -->
<div class="flex items-center space-x-4">
<a href="{{ path('app_faq_edit', {'id': faq.id}) }}" class="text-yellow-500 hover:text-yellow-700 text-lg">
<i class="fas fa-edit"></i> Modifier cette FAQ
</a>
<form method="post" action="{{ path('app_faq_delete', {'id': faq.id}) }}" style="display:inline;">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ faq.id) }}">
<button type="submit" class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg">
<i class="fas fa-trash-alt"></i> Supprimer
</button>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -37,40 +37,4 @@
</div>
</div>
</section>
<section class="container mx-auto py-12">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold">Propositions de stages </h2>
<a class="text-teal-500 hover:underline" href="{{ path('app_announcement_list') }}">Voir tout</a>
</div>
<div class="space-y-6">
{# Loop over recent offers (replace with dynamic data)
{% for offer in recent_offers %}
<div class="bg-white p-6 rounded-lg shadow flex justify-between items-center">
<div class="flex items-center space-x-4">
<div class="text-gray-500 text-sm">{{ offer.time_ago }}</div>
<div>
<h3 class="text-lg font-bold">{{ offer.title }}</h3>
<p class="text-gray-600">{{ offer.company }}</p>
<div class="flex items-center space-x-2 text-gray-500 text-sm mt-2">
<span class="flex items-center">
<i class="fas fa-briefcase mr-1"></i> {{ offer.category }}
</span>
<span class="flex items-center">
<i class="fas fa-clock mr-1"></i> {{ offer.type }}
</span>
<span class="flex items-center">
<i class="fas fa-dollar-sign mr-1"></i> {{ offer.salary }}
</span>
<span class="flex items-center">
<i class="fas fa-map-marker-alt mr-1"></i> {{ offer.location }}
</span>
</div>
</div>
</div>
<button class="bg-teal-500 hover:bg-teal-600 text-white py-2 px-4 rounded">Détails de l'offre</button>
</div>
{% endfor %}#}
</div>
</section>
{% endblock %}