Compare commits

...

2 Commits

Author SHA1 Message Date
gitea-actions
e6819bc68a chore: bump version to v0.1.29
All checks were successful
Auto Tag Develop / tag (push) Successful in 4s
Build Release Artefact / build (push) Successful in 1m11s
2026-03-12 11:30:22 +00:00
6153175ca0 feat : ajout des icons dans la sidebar et redirection après login sur le calendrier
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-03-12 12:30:13 +01:00
6 changed files with 781 additions and 22 deletions

View File

@@ -18,7 +18,10 @@
"Read(//home/m-tristan/.nix-profile/**)",
"Read(//home/m-tristan/.local/bin/**)",
"Bash(env)",
"Bash(ls /home/m-tristan/workspace/SIRH/docker* /home/m-tristan/workspace/SIRH/Makefile 2>/dev/null; cat /home/m-tristan/workspace/SIRH/Makefile 2>/dev/null | grep -E \"\\(phpunit|test|php\\)\" | head -20)"
"Bash(ls /home/m-tristan/workspace/SIRH/docker* /home/m-tristan/workspace/SIRH/Makefile 2>/dev/null; cat /home/m-tristan/workspace/SIRH/Makefile 2>/dev/null | grep -E \"\\(phpunit|test|php\\)\" | head -20)",
"Bash(which python3:*)",
"Bash(sudo apt-get:*)",
"Bash(npx xlsx-cli:*)"
]
}
}

View File

@@ -1,2 +1,2 @@
parameters:
app.version: '0.1.28'
app.version: '0.1.29'

View File

@@ -0,0 +1,484 @@
# RTT : Affichage en heures + Paiement RTT
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Afficher les RTT en heures (plus en jours), permettre le paiement RTT via drawer avec majoration 25%/50%, stocker en BDD et afficher par mois.
**Architecture:** Nouvelle entity `EmployeeRttPayment` (employee, year, month, minutes, rate). Le provider RTT agrège les paiements par mois et les soustrait du disponible. Le frontend ajoute un drawer de saisie et deux lignes par mois (25% / 50%).
**Tech Stack:** Symfony + Doctrine + API Platform (backend), Nuxt 4 + Vue 3 + TypeScript + Tailwind (frontend)
---
## Contexte existant
- **Entity:** `EmployeeRttBalance` dans `src/Entity/EmployeeRttBalance.php` - stocke `openingMinutes` par exercice
- **Provider:** `src/State/EmployeeRttSummaryProvider.php` - calcule `availableMinutes = carry + currentYearRecovery`
- **Service:** `src/Service/Rtt/RttRecoveryComputationService.php` - calcul semaine par semaine
- **Frontend:** `frontend/components/employees/RttTab.vue` - affichage grille mois/semaines
- **DTO backend:** `src/ApiResource/EmployeeRttSummary.php` - champs `availableMinutes`, `weeks[]`
- **DTO frontend:** `frontend/services/dto/employee-rtt-summary.ts`
- Les minutes sont la base de calcul. 1 jour = 7h = 420 minutes.
- Exercice RTT : 1er juin N-1 -> 31 mai N (year = N)
---
### Task 1: Migration - Créer la table `employee_rtt_payments`
**Files:**
- Create: `migrations/Version20260309140000.php`
**Step 1: Créer la migration**
```php
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260309140000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create employee_rtt_payments table for RTT paid hours tracking.';
}
public function up(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE employee_rtt_payments (
id SERIAL PRIMARY KEY,
employee_id INT NOT NULL REFERENCES employees(id) ON DELETE CASCADE,
year INT NOT NULL,
month INT NOT NULL,
minutes INT NOT NULL,
rate VARCHAR(10) NOT NULL,
created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL DEFAULT NOW()
)
SQL);
$this->addSql('CREATE INDEX idx_rtt_payment_employee_year ON employee_rtt_payments (employee_id, year)');
$this->addSql("COMMENT ON TABLE employee_rtt_payments IS 'Paiements RTT par employe, mois et taux de majoration.'");
$this->addSql("COMMENT ON COLUMN employee_rtt_payments.rate IS 'Taux de majoration: 25 ou 50.'");
$this->addSql("COMMENT ON COLUMN employee_rtt_payments.minutes IS 'Minutes RTT payees pour ce mois et ce taux.'");
}
public function down(Schema $schema): void
{
$this->addSql('DROP TABLE employee_rtt_payments');
}
}
```
**Step 2: Exécuter la migration**
Run: `make migrate` ou `docker compose exec php php bin/console doctrine:migrations:migrate --no-interaction`
Expected: Migration exécutée sans erreur
**Step 3: Commit**
```bash
git add migrations/Version20260309140000.php
git commit -m "feat(rtt): add employee_rtt_payments table"
```
---
### Task 2: Entity + Repository `EmployeeRttPayment`
**Files:**
- Create: `src/Entity/EmployeeRttPayment.php`
- Create: `src/Repository/EmployeeRttPaymentRepository.php`
**Step 1: Créer l'entity**
```php
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\EmployeeRttPaymentRepository;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: EmployeeRttPaymentRepository::class)]
#[ORM\Table(name: 'employee_rtt_payments')]
#[ORM\Index(columns: ['employee_id', 'year'], name: 'idx_rtt_payment_employee_year')]
class EmployeeRttPayment
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\ManyToOne(targetEntity: Employee::class)]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
private ?Employee $employee = null;
#[ORM\Column(type: 'integer')]
private int $year = 0;
#[ORM\Column(type: 'integer')]
private int $month = 0;
#[ORM\Column(type: 'integer', options: ['comment' => 'Minutes RTT payees pour ce mois et ce taux.'])]
private int $minutes = 0;
#[ORM\Column(length: 10, options: ['comment' => 'Taux de majoration: 25 ou 50.'])]
private string $rate = '25';
#[ORM\Column(type: 'datetime_immutable')]
private DateTimeImmutable $createdAt;
#[ORM\Column(type: 'datetime_immutable')]
private DateTimeImmutable $updatedAt;
public function __construct()
{
$now = new DateTimeImmutable();
$this->createdAt = $now;
$this->updatedAt = $now;
}
// Getters & setters (getId, getEmployee/setEmployee, getYear/setYear,
// getMonth/setMonth, getMinutes/setMinutes, getRate/setRate, touch)
// Suivre le même pattern que EmployeeLeaveBalance
}
```
**Step 2: Créer le repository**
```php
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\Employee;
use App\Entity\EmployeeRttPayment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<EmployeeRttPayment>
*/
final class EmployeeRttPaymentRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, EmployeeRttPayment::class);
}
/**
* @return list<EmployeeRttPayment>
*/
public function findByEmployeeAndYear(Employee $employee, int $year): array
{
return $this->createQueryBuilder('p')
->andWhere('p.employee = :employee')
->andWhere('p.year = :year')
->setParameter('employee', $employee)
->setParameter('year', $year)
->orderBy('p.month', 'ASC')
->getQuery()
->getResult();
}
}
```
**Step 3: Vérifier le lint**
Run: `docker compose exec php php -l src/Entity/EmployeeRttPayment.php && docker compose exec php php -l src/Repository/EmployeeRttPaymentRepository.php`
Expected: No syntax errors
**Step 4: Commit**
```bash
git add src/Entity/EmployeeRttPayment.php src/Repository/EmployeeRttPaymentRepository.php
git commit -m "feat(rtt): add EmployeeRttPayment entity and repository"
```
---
### Task 3: API Resource + Provider + Processor pour le paiement RTT
**Files:**
- Create: `src/ApiResource/EmployeeRttPaymentInput.php`
- Create: `src/State/EmployeeRttPaymentProvider.php`
- Create: `src/State/EmployeeRttPaymentProcessor.php`
**Step 1: Créer l'API Resource**
Endpoint: `PATCH /employees/{id}/rtt-payments` (ROLE_ADMIN)
Body: `{ "month": 3, "minutes": 120, "rate": "25" }`
```php
// src/ApiResource/EmployeeRttPaymentInput.php
#[ApiResource(
operations: [
new Patch(
uriTemplate: '/employees/{id}/rtt-payments',
security: "is_granted('ROLE_ADMIN')",
provider: EmployeeRttPaymentProvider::class,
processor: EmployeeRttPaymentProcessor::class
),
],
paginationEnabled: false
)]
final class EmployeeRttPaymentInput
{
public int $month = 0;
public int $minutes = 0;
public string $rate = '25';
public ?int $year = null;
}
```
**Step 2: Créer le Provider** (retourne un DTO vide, même pattern que `EmployeeFractionedDaysProvider`)
**Step 3: Créer le Processor**
Logique:
- Valider `rate` in `['25', '50']`, `month` in `[1..12]`, `minutes >= 0`
- Résoudre l'année (même logique exercice RTT que le provider existant)
- Persister un `EmployeeRttPayment`
**Step 4: Vérifier le lint**
**Step 5: Commit**
```bash
git add src/ApiResource/EmployeeRttPaymentInput.php src/State/EmployeeRttPaymentProvider.php src/State/EmployeeRttPaymentProcessor.php
git commit -m "feat(rtt): add PATCH endpoint for RTT payment"
```
---
### Task 4: Modifier le DTO + Provider RTT pour inclure les paiements par mois
**Files:**
- Modify: `src/ApiResource/EmployeeRttSummary.php`
- Modify: `src/State/EmployeeRttSummaryProvider.php`
- Create: `src/Dto/Rtt/RttMonthPayment.php`
- Modify: `frontend/services/dto/employee-rtt-summary.ts`
**Step 1: Créer le DTO mois-paiement**
```php
// src/Dto/Rtt/RttMonthPayment.php
final class RttMonthPayment
{
public function __construct(
public int $month,
public int $paidMinutes25 = 0,
public int $paidMinutes50 = 0,
) {}
}
```
**Step 2: Ajouter au summary backend**
Dans `EmployeeRttSummary.php`, ajouter:
```php
public int $totalPaidMinutes = 0;
/** @var list<RttMonthPayment> */
public array $monthPayments = [];
```
Et modifier `availableMinutes` pour soustraire les paiements:
```php
$summary->availableMinutes = $summary->carryFromPreviousYearMinutes
+ $summary->currentYearRecoveryMinutes
- $summary->totalPaidMinutes;
```
**Step 3: Modifier le provider** pour charger les paiements via le repository et les agréger par mois
Dans `EmployeeRttSummaryProvider::provide()`:
- Charger `$payments = $this->rttPaymentRepository->findByEmployeeAndYear($employee, $year)`
- Agréger par mois + rate pour construire les `RttMonthPayment`
- Calculer `totalPaidMinutes = sum(minutes)`
- Soustraire du `availableMinutes`
**Step 4: Mettre à jour le DTO frontend**
Dans `frontend/services/dto/employee-rtt-summary.ts`:
```typescript
export type RttMonthPayment = {
month: number
paidMinutes25: number
paidMinutes50: number
}
export type EmployeeRttSummary = {
// ... champs existants ...
totalPaidMinutes: number
monthPayments: RttMonthPayment[]
}
```
**Step 5: Commit**
```bash
git commit -m "feat(rtt): include paid hours in RTT summary by month"
```
---
### Task 5: Frontend - Afficher les RTT en heures + lignes payées
**Files:**
- Modify: `frontend/components/employees/RttTab.vue`
**Step 1: Changer l'affichage du header de jours en heures**
Ligne 4 actuelle:
```html
<p>...: {{ formatDays(summary?.availableMinutes ?? 0) }}</p>
```
Remplacer par:
```html
<p>...: {{ formatMinutes(summary?.availableMinutes ?? 0) }}</p>
```
**Step 2: Ajouter les 2 lignes de paiement par mois**
Après la ligne `Heure payée` existante (ligne 33-34), remplacer par 2 lignes distinctes:
```html
<div class="py-[6px] pl-3 border-r border-b border-primary-500">Heure payée 25%</div>
<div class="py-[6px] pl-3 border-b border-primary-500">{{ formatMinutes(getMonthPaid25(month.month)) }}</div>
<div class="py-[6px] pl-3 border-r border-primary-500">Heure payée 50%</div>
<div class="py-[6px] pl-3">{{ formatMinutes(getMonthPaid50(month.month)) }}</div>
```
**Step 3: Ajouter les helpers computed**
```typescript
const paymentsByMonth = computed(() => {
const map = new Map<number, { paid25: number; paid50: number }>()
for (const mp of props.summary?.monthPayments ?? []) {
map.set(mp.month, { paid25: mp.paidMinutes25, paid50: mp.paidMinutes50 })
}
return map
})
const getMonthPaid25 = (month: number) => paymentsByMonth.value.get(month)?.paid25 ?? 0
const getMonthPaid50 = (month: number) => paymentsByMonth.value.get(month)?.paid50 ?? 0
```
**Step 4: Commit**
```bash
git commit -m "feat(rtt): display hours instead of days + paid hours per month"
```
---
### Task 6: Frontend - Drawer de paiement RTT
**Files:**
- Modify: `frontend/components/employees/RttTab.vue`
- Modify: `frontend/services/employee-rtt-summary.ts`
- Modify: `frontend/composables/useEmployeeDetailPage.ts`
- Modify: `frontend/pages/employees/[id].vue`
**Step 1: Ajouter le service API**
Dans `frontend/services/employee-rtt-summary.ts`:
```typescript
export const createRttPayment = async (
employeeId: number,
month: number,
minutes: number,
rate: '25' | '50',
year?: number
) => {
const api = useApi()
const body: Record<string, unknown> = { month, minutes, rate }
if (year) body.year = year
return api.patch(`/employees/${employeeId}/rtt-payments`, body)
}
```
**Step 2: Ajouter au composable**
Dans `useEmployeeDetailPage.ts`:
- Import `createRttPayment`
- Ajouter `submitRttPayment(month, minutes, rate)` qui appelle l'API puis `loadEmployee()`
- Exposer dans le return
**Step 3: Passer l'event dans la page**
Dans `frontend/pages/employees/[id].vue`:
- Destructurer `submitRttPayment`
- Ajouter `@submit-rtt-payment="submitRttPayment"` sur `<EmployeesRttTab>`
**Step 4: Ajouter le drawer dans RttTab.vue**
Même pattern que le drawer fractionnés dans LeaveTab:
- Import `AppDrawer`
- State: `isPaymentDrawerOpen`, `paymentForm: { month, minutes, rate }`
- Bouton "Payer les RTT" ouvre le drawer
- Formulaire avec:
- Select mois (Janvier..Décembre)
- Input number "Nombre d'heures" (step 0.5, converti en minutes au submit)
- Select rate: "25%" / "50%"
- Boutons Annuler / Enregistrer
- Emit `submit-rtt-payment` au submit
**Step 5: Commit**
```bash
git commit -m "feat(rtt): add payment drawer with month/hours/rate fields"
```
---
### Task 7: Documentation fonctionnelle
**Files:**
- Modify: `doc/functional-rules.md`
**Step 1: Mettre à jour la section RTT**
Ajouter après les règles RTT existantes:
- Paiement RTT: saisie RH via `PATCH /employees/{id}/rtt-payments`
- Stocké dans `employee_rtt_payments` (employee, year, month, minutes, rate)
- Les heures payées sont soustraites du disponible RTT
- Affichage: 2 lignes par mois (25% et 50%)
- L'affichage global RTT est en heures (plus en jours)
**Step 2: Commit**
```bash
git commit -m "docs: update functional rules with RTT payment feature"
```
---
## Résumé des fichiers
| Action | Fichier |
|--------|---------|
| Create | `migrations/Version20260309140000.php` |
| Create | `src/Entity/EmployeeRttPayment.php` |
| Create | `src/Repository/EmployeeRttPaymentRepository.php` |
| Create | `src/ApiResource/EmployeeRttPaymentInput.php` |
| Create | `src/State/EmployeeRttPaymentProvider.php` |
| Create | `src/State/EmployeeRttPaymentProcessor.php` |
| Create | `src/Dto/Rtt/RttMonthPayment.php` |
| Modify | `src/ApiResource/EmployeeRttSummary.php` |
| Modify | `src/State/EmployeeRttSummaryProvider.php` |
| Modify | `frontend/services/dto/employee-rtt-summary.ts` |
| Modify | `frontend/services/employee-rtt-summary.ts` |
| Modify | `frontend/components/employees/RttTab.vue` |
| Modify | `frontend/composables/useEmployeeDetailPage.ts` |
| Modify | `frontend/pages/employees/[id].vue` |
| Modify | `doc/functional-rules.md` |

View File

@@ -0,0 +1,273 @@
# Employee Entry Date Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add an `entryDate` field to Employee, automatically populated from `contractStartDate` at creation.
**Architecture:** New nullable `DATE` column on `employees` table. The `EmployeeWriteProcessor` sets `entryDate` from the first contract period's start date during employee creation. Exposed read-only in the API. No fallback needed — existing employees will be updated manually in prod DB.
**Tech Stack:** Symfony/Doctrine (backend), Nuxt/Vue/TypeScript (frontend)
---
## File Structure
| File | Action | Responsibility |
|------|--------|----------------|
| `src/Entity/Employee.php` | Modify | Add `entryDate` column + getter/setter, expose in `employee:read` |
| `src/State/EmployeeWriteProcessor.php` | Modify | Set `entryDate` from `contractStartDate` on creation |
| `migrations/Version20260312120000.php` | Create | Add `entry_date` column to `employees` table |
| `tests/State/EmployeeWriteProcessorTest.php` | Modify | Assert `entryDate` is set on new employee |
| `frontend/services/dto/employee.ts` | Modify | Add `entryDate` field to `Employee` type |
| `frontend/pages/employees/index.vue` | Modify | Display entry date in employee list |
---
## Chunk 1: Backend
### Task 1: Migration
**Files:**
- Create: `migrations/Version20260312120000.php`
- [ ] **Step 1: Create the migration file**
```php
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260312120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add entry_date column to employees table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE employees ADD entry_date DATE DEFAULT NULL COMMENT \'(DC2Type:date_immutable)\'');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE employees DROP entry_date');
}
}
```
- [ ] **Step 2: Run migration**
Run: `php bin/console doctrine:migrations:migrate --no-interaction`
Expected: Migration applied successfully
- [ ] **Step 3: Commit**
```bash
git add migrations/Version20260312120000.php
git commit -m "feat : ajout colonne entry_date sur employees"
```
---
### Task 2: Entity — add `entryDate` property
**Files:**
- Modify: `src/Entity/Employee.php:56-61` (insert after `displayOrder`)
- [ ] **Step 1: Add the column, getter, and setter to Employee entity**
Add after the `displayOrder` property (line 58):
```php
#[ORM\Column(type: 'date_immutable', nullable: true)]
#[Groups(['employee:read'])]
private ?\DateTimeImmutable $entryDate = null;
```
Add getter and setter after `setDisplayOrder()` (after line 167):
```php
public function getEntryDate(): ?\DateTimeImmutable
{
return $this->entryDate;
}
public function setEntryDate(?\DateTimeImmutable $entryDate): self
{
$this->entryDate = $entryDate;
return $this;
}
```
- [ ] **Step 2: Verify schema is in sync**
Run: `php bin/console doctrine:schema:validate`
Expected: OK (or only existing unrelated warnings)
- [ ] **Step 3: Commit**
```bash
git add src/Entity/Employee.php
git commit -m "feat : ajout propriete entryDate sur Employee"
```
---
### Task 3: Set `entryDate` on employee creation
**Files:**
- Modify: `src/State/EmployeeWriteProcessor.php:60-71`
- Modify: `tests/State/EmployeeWriteProcessorTest.php`
- [ ] **Step 1: Write the failing test**
Add `use ApiPlatform\Metadata\Post;` to the imports at the top of the test file (alongside the existing `Delete` and `Patch` imports).
Then add this test method to `EmployeeWriteProcessorTest`:
```php
public function testSetsEntryDateOnNewEmployee(): void
{
$employee = new Employee();
$employee->setFirstName('Jane');
$employee->setLastName('Doe');
$employee->setContractStartDate('2026-04-01');
$employee->setContractNature('CDI');
$contract = new Contract()
->setName('35h')
->setTrackingMode(Contract::TRACKING_TIME)
->setWeeklyHours(35);
$employee->setContract($contract);
$persistProcessor = $this->createMock(ProcessorInterface::class);
$removeProcessor = $this->createStub(ProcessorInterface::class);
$entityManager = $this->createStub(EntityManagerInterface::class);
$periodRepository = $this->createStub(EmployeeContractPeriodReadRepositoryInterface::class);
$changeRequestFactory = new EmployeeContractChangeRequestFactory();
$periodManager = $this->createMock(EmployeeContractPeriodManagerInterface::class);
$persistProcessor
->expects(self::once())
->method('process')
->willReturn($employee);
$periodManager
->expects(self::once())
->method('ensureContractPeriodExists');
$processor = new EmployeeWriteProcessor(
$persistProcessor,
$removeProcessor,
$entityManager,
$periodRepository,
$changeRequestFactory,
$periodManager
);
$processor->process($employee, new Post());
self::assertNotNull($employee->getEntryDate());
self::assertSame('2026-04-01', $employee->getEntryDate()->format('Y-m-d'));
}
```
- [ ] **Step 2: Run test to verify it fails**
Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee`
Expected: FAIL — `entryDate` is null
- [ ] **Step 3: Implement — set entryDate in EmployeeWriteProcessor**
In `src/State/EmployeeWriteProcessor.php`, inside the `if ($isNew)` block (line 60-71), add **before** `return $result;` (line 71):
```php
$data->setEntryDate($startDate);
```
The full block becomes:
```php
if ($isNew) {
$startDate = $changeRequest->contractStartDate ?? new DateTimeImmutable('1970-01-01');
$nature = $changeRequest->contractNature ?? ContractNature::CDI;
$this->periodManager->ensureContractPeriodExists(
employee: $data,
contract: $currentContract,
startDate: $startDate,
endDate: $changeRequest->contractEndDate,
nature: $nature
);
$data->setEntryDate($startDate);
return $result;
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee`
Expected: PASS
- [ ] **Step 5: Run all EmployeeWriteProcessor tests**
Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php`
Expected: All tests pass (no regression)
- [ ] **Step 6: Commit**
```bash
git add src/State/EmployeeWriteProcessor.php tests/State/EmployeeWriteProcessorTest.php
git commit -m "feat : remplissage automatique entryDate a la creation employe"
```
---
## Chunk 2: Frontend
### Task 4: Update frontend DTO and display entry date
**Files:**
- Modify: `frontend/services/dto/employee.ts:14-25`
- Modify: `frontend/pages/employees/index.vue`
- [ ] **Step 1: Add `entryDate` to the Employee DTO**
In `frontend/services/dto/employee.ts:24`, add `entryDate` after `displayOrder`:
```typescript
displayOrder?: number
entryDate?: string | null
```
- [ ] **Step 2: Display entry date in the employee card hover overlay**
In `frontend/pages/employees/index.vue`, inside the hover overlay `<div>` (line 49-54), add a new line after the "Site" line (after line 53):
```vue
<p><strong>Entree :</strong> {{ employee.entryDate ? employee.entryDate.split('-').reverse().join('/') : '-' }}</p>
```
This uses string splitting instead of `new Date()` to avoid timezone parsing issues with date-only strings.
- [ ] **Step 3: Verify in browser**
1. Check the API response for an employee: `GET /api/employees` should include `entryDate` field (confirms backend `employee:read` group works)
2. Open the employee list page, hover over a card — entry date should appear in the overlay
3. Create a new employee, verify the entry date shows the contract start date
4. Existing employees without entry date should show "-"
- [ ] **Step 4: Commit**
```bash
git add frontend/services/dto/employee.ts frontend/pages/employees/index.vue
git commit -m "feat : affichage date d'entree dans la liste employes"
```

View File

@@ -7,68 +7,67 @@
</div>
<nav class="flex-1 px-4 pb-6">
<template v-if="isAdmin">
<NuxtLink
to="/"
class="hidden flex items-center gap-3 px-4 pb-3 pt-6 text-md text-black hover:bg-tertiary-500 hover:text-primary-500 border-t border-secondary-500"
active-class="bg-tertiary-500 text-primary-500 font-bold"
>
Tableau de bord
</NuxtLink>
<NuxtLink
to="/calendar"
class="flex items-center gap-3 px-4 pb-3 pt-6 text-md text-black hover:bg-tertiary-500 hover:text-primary-500 border-t border-secondary-500"
class="flex items-center gap-2 pb-2 pt-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500 border-t border-secondary-500"
:class="route.path.startsWith('/calendar')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Calendrier
<Icon name="mdi:calendar-blank" size="24"/>
<p>Calendrier</p>
</NuxtLink>
</template>
<NuxtLink
to="/hours"
class="flex items-center gap-3 px-4 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
class="flex items-center gap-2 py-2 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
:class="route.path.startsWith('/hours')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Heures
<Icon name="mdi:clock-time-four-outline" size="24"/>
<p>Heures</p>
</NuxtLink>
<template v-if="isAdmin">
<NuxtLink
to="/employees"
class="flex items-center gap-3 px-4 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
class="flex items-center gap-2 py-2 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
:class="route.path.startsWith('/employees')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Employés
<Icon name="mdi:account-group-outline" size="24"/>
<p>Employés</p>
</NuxtLink>
<NuxtLink
to="/sites"
class="flex items-center gap-3 px-4 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
class="flex items-center gap-2 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
:class="route.path.startsWith('/sites')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Sites
<Icon name="mdi:business" size="24"/>
<p>Sites</p>
</NuxtLink>
<NuxtLink
to="/absence-types"
class="flex items-center gap-3 px-4 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
class="flex items-center gap-2 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
:class="route.path.startsWith('/absence-types')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Types d'absence
<Icon name="mdi:umbrella-beach-outline" size="24"/>
<p>Types d'absence</p>
</NuxtLink>
<NuxtLink
to="/users"
class="flex items-center gap-3 px-4 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
class="flex items-center gap-3 py-3 text-md text-black hover:bg-tertiary-500 hover:text-primary-500"
:class="route.path.startsWith('/users')
? 'bg-tertiary-500 text-primary-500 font-bold'
: ''"
>
Utilisateurs
<Icon name="mdi:account-outline" size="24"/>
<p>Utilisateurs</p>
</NuxtLink>
</template>
</nav>

View File

@@ -68,7 +68,7 @@ const handleSubmit = async () => {
try {
await auth.login(username.value, password.value)
await router.push('/')
await router.push('/calendar')
} finally {
isSubmitting.value = false
}