chore: add husky pre-commit hook and lint-staged configuration
- Created a pre-commit hook in .husky to run lint-staged. - Added .lintstagedrc.mjs to format frontend files with Prettier and apply Spotless to backend Java files. - Introduced .prettierignore to exclude specific directories from formatting.
This commit is contained in:
1 parent
5d2d85aa8c
commit
878da155bd
564 files changed
+61467
-47179
No files matched your search
@@ -1,67 +1,67 @@
|
||||
:host {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
display: block;
|
||||
min-width: 0;
|
||||
}
|
||||
.notice-form {
|
||||
padding: 1.25rem;
|
||||
border: 1px solid var(--border, #dfe3e6);
|
||||
border-radius: 1rem;
|
||||
background: var(--surface, #fff);
|
||||
padding: 1.25rem;
|
||||
border: 1px solid var(--border, #dfe3e6);
|
||||
border-radius: 1rem;
|
||||
background: var(--surface, #fff);
|
||||
}
|
||||
h2 {
|
||||
margin-block-start: 0;
|
||||
margin-block-start: 0;
|
||||
}
|
||||
.notice-form > p,
|
||||
small {
|
||||
color: var(--text-muted, #5f6368);
|
||||
color: var(--text-muted, #5f6368);
|
||||
}
|
||||
fieldset {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
.field-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
|
||||
gap: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
label:not(.confirmation-field) {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
min-width: 0;
|
||||
}
|
||||
input,
|
||||
select {
|
||||
min-width: 0;
|
||||
min-height: 2.75rem;
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
min-height: 2.75rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.confirmation-field {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.65rem;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.65rem;
|
||||
min-width: 0;
|
||||
}
|
||||
.confirmation-field input {
|
||||
flex: 0 0 auto;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.missing-evidence-warning {
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: var(--surface-soft, #f6f7f8);
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: var(--surface-soft, #f6f7f8);
|
||||
}
|
||||
.missing-evidence-warning p {
|
||||
margin-block-start: 0;
|
||||
color: var(--text-muted, #5f6368);
|
||||
margin-block-start: 0;
|
||||
color: var(--text-muted, #5f6368);
|
||||
}
|
||||
input:focus-visible,
|
||||
select:focus-visible {
|
||||
outline: 2px solid var(--accent, #236b5d);
|
||||
outline-offset: 0.15rem;
|
||||
outline: 2px solid var(--accent, #236b5d);
|
||||
outline-offset: 0.15rem;
|
||||
}
|
||||
.operation-error {
|
||||
color: var(--danger, #b42318);
|
||||
color: var(--danger, #b42318);
|
||||
}
|
||||
@@ -1,67 +1,71 @@
|
||||
<section class="notice-form" aria-labelledby="notice-form-title">
|
||||
<h2 id="notice-form-title">Enregistrer un congé</h2>
|
||||
<p>Les dates sont enregistrées comme des dates civiles dans le fuseau {{ timeZone() }}.</p>
|
||||
<form
|
||||
[formRoot]="noticeForm"
|
||||
[attr.aria-busy]="submitting()"
|
||||
(submit)="submit(); $event.preventDefault()"
|
||||
>
|
||||
<fieldset [disabled]="submitting()">
|
||||
<div class="field-grid">
|
||||
<label>
|
||||
<span>Date de réception</span>
|
||||
<input type="date" [formField]="noticeForm.receivedOn" />
|
||||
</label>
|
||||
<label>
|
||||
<span>Départ demandé</span>
|
||||
<input type="date" [formField]="noticeForm.requestedDepartureOn" />
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
<span>Mode de remise</span>
|
||||
<select [formField]="noticeForm.deliveryMode">
|
||||
<option value="">Choisissez un mode</option>
|
||||
@for (mode of deliveryModes; track mode.value) {
|
||||
<option [value]="mode.value">{{ mode.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
@if (model().deliveryMode === 'OTHER') {
|
||||
<label>
|
||||
<span>Mode de remise utilisé</span>
|
||||
<input type="text" [formField]="noticeForm.otherDeliveryMode" />
|
||||
</label>
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.nonStandardDeliveryConfirmed" />
|
||||
<span>Je confirme avoir vérifié ce mode de remise non standard.</span>
|
||||
</label>
|
||||
}
|
||||
@if (lateRegistration()) {
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.lateRegistrationConfirmed" />
|
||||
<span>Je confirme enregistrer aujourd’hui un congé reçu à une date passée.</span>
|
||||
</label>
|
||||
}
|
||||
<label>
|
||||
<span>Preuve (facultative, tout format)</span>
|
||||
<input class="notice-evidence" type="file" (change)="selectEvidence($event)" />
|
||||
<small>{{ evidence()?.name ?? 'Aucun fichier sélectionné' }}</small>
|
||||
</label>
|
||||
@if (!evidence()) {
|
||||
<div class="missing-evidence-warning">
|
||||
<p>Aucun justificatif ne sera associé à ce congé lors de son enregistrement.</p>
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.missingEvidenceConfirmed" />
|
||||
<span>Je confirme enregistrer ce congé sans justificatif.</span>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
@if (validationError() || operationError()) {
|
||||
<p class="operation-error" role="alert">{{ validationError() || operationError() }}</p>
|
||||
}
|
||||
<button mat-flat-button type="submit" [disabled]="submitting()">
|
||||
{{ submitting() ? 'Enregistrement…' : 'Enregistrer le congé' }}
|
||||
</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
<h2 id="notice-form-title">Enregistrer un congé</h2>
|
||||
<p>Les dates sont enregistrées comme des dates civiles dans le fuseau {{ timeZone() }}.</p>
|
||||
<form
|
||||
[formRoot]="noticeForm"
|
||||
[attr.aria-busy]="submitting()"
|
||||
(submit)="submit(); $event.preventDefault()"
|
||||
>
|
||||
<fieldset [disabled]="submitting()">
|
||||
<div class="field-grid">
|
||||
<label>
|
||||
<span>Date de réception</span>
|
||||
<input type="date" [formField]="noticeForm.receivedOn" />
|
||||
</label>
|
||||
<label>
|
||||
<span>Départ demandé</span>
|
||||
<input type="date" [formField]="noticeForm.requestedDepartureOn" />
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
<span>Mode de remise</span>
|
||||
<select [formField]="noticeForm.deliveryMode">
|
||||
<option value="">Choisissez un mode</option>
|
||||
@for (mode of deliveryModes; track mode.value) {
|
||||
<option [value]="mode.value">{{ mode.label }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
@if (model().deliveryMode === 'OTHER') {
|
||||
<label>
|
||||
<span>Mode de remise utilisé</span>
|
||||
<input type="text" [formField]="noticeForm.otherDeliveryMode" />
|
||||
</label>
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.nonStandardDeliveryConfirmed" />
|
||||
<span>Je confirme avoir vérifié ce mode de remise non standard.</span>
|
||||
</label>
|
||||
}
|
||||
@if (lateRegistration()) {
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.lateRegistrationConfirmed" />
|
||||
<span
|
||||
>Je confirme enregistrer aujourd’hui un congé reçu à une date passée.</span
|
||||
>
|
||||
</label>
|
||||
}
|
||||
<label>
|
||||
<span>Preuve (facultative, tout format)</span>
|
||||
<input class="notice-evidence" type="file" (change)="selectEvidence($event)" />
|
||||
<small>{{ evidence()?.name ?? 'Aucun fichier sélectionné' }}</small>
|
||||
</label>
|
||||
@if (!evidence()) {
|
||||
<div class="missing-evidence-warning">
|
||||
<p>Aucun justificatif ne sera associé à ce congé lors de son enregistrement.</p>
|
||||
<label class="confirmation-field">
|
||||
<input type="checkbox" [formField]="noticeForm.missingEvidenceConfirmed" />
|
||||
<span>Je confirme enregistrer ce congé sans justificatif.</span>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
@if (validationError() || operationError()) {
|
||||
<p class="operation-error" role="alert">
|
||||
{{ validationError() || operationError() }}
|
||||
</p>
|
||||
}
|
||||
<button mat-flat-button type="submit" [disabled]="submitting()">
|
||||
{{ submitting() ? 'Enregistrement…' : 'Enregistrer le congé' }}
|
||||
</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</section>
|
||||
@@ -3,117 +3,119 @@ import { vi } from 'vitest';
|
||||
import { LeaseEndNoticeForm } from './lease-end-notice-form';
|
||||
|
||||
describe('LeaseEndNoticeForm', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
|
||||
it('requires explicit confirmations for a late registration and OTHER delivery', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'Europe/Paris');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-18',
|
||||
requestedDepartureOn: '2026-08-18',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
fixture.detectChanges();
|
||||
it('requires explicit confirmations for a late registration and OTHER delivery', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'Europe/Paris');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-18',
|
||||
requestedDepartureOn: '2026-08-18',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.querySelector('input[type="text"]').maxLength).toBe(200);
|
||||
expect(fixture.nativeElement.querySelector('input[type="text"]').maxLength).toBe(200);
|
||||
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain('enregistrement tardif');
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain('enregistrement tardif');
|
||||
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
lateRegistrationConfirmed: true,
|
||||
}));
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain('mode de remise non standard');
|
||||
});
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
lateRegistrationConfirmed: true,
|
||||
}));
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain(
|
||||
'mode de remise non standard',
|
||||
);
|
||||
});
|
||||
|
||||
it('emits civil dates, timezone and arbitrary evidence without converting the day', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'America/Los_Angeles');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
const requested = vi.fn();
|
||||
fixture.componentInstance.noticeRequested.subscribe(requested);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
missingEvidenceConfirmed: true,
|
||||
}));
|
||||
const evidence = new File(['photo'], 'preuve.jpg', { type: 'image/jpeg' });
|
||||
const input = fixture.nativeElement.querySelector('.notice-evidence');
|
||||
Object.defineProperty(input, 'files', { value: { item: () => evidence } });
|
||||
input.dispatchEvent(new Event('change'));
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.model().missingEvidenceConfirmed).toBe(false);
|
||||
expect(fixture.nativeElement.querySelector('.missing-evidence-warning')).toBeNull();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: true,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
it('emits civil dates, timezone and arbitrary evidence without converting the day', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'America/Los_Angeles');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
const requested = vi.fn();
|
||||
fixture.componentInstance.noticeRequested.subscribe(requested);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
missingEvidenceConfirmed: true,
|
||||
}));
|
||||
const evidence = new File(['photo'], 'preuve.jpg', { type: 'image/jpeg' });
|
||||
const input = fixture.nativeElement.querySelector('.notice-evidence');
|
||||
Object.defineProperty(input, 'files', { value: { item: () => evidence } });
|
||||
input.dispatchEvent(new Event('change'));
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.model().missingEvidenceConfirmed).toBe(false);
|
||||
expect(fixture.nativeElement.querySelector('.missing-evidence-warning')).toBeNull();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: true,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
|
||||
fixture.componentInstance.submit();
|
||||
fixture.componentInstance.submit();
|
||||
|
||||
expect(requested).toHaveBeenCalledWith({
|
||||
timeZone: 'America/Los_Angeles',
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: true,
|
||||
missingEvidenceConfirmed: false,
|
||||
evidence,
|
||||
});
|
||||
expect(input.getAttribute('accept')).toBeNull();
|
||||
});
|
||||
expect(requested).toHaveBeenCalledWith({
|
||||
timeZone: 'America/Los_Angeles',
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'OTHER',
|
||||
otherDeliveryMode: 'Remise par le gardien',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: true,
|
||||
missingEvidenceConfirmed: false,
|
||||
evidence,
|
||||
});
|
||||
expect(input.getAttribute('accept')).toBeNull();
|
||||
});
|
||||
|
||||
it('requires and sends an explicit attestation when no evidence is selected', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'Europe/Paris');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
const requested = vi.fn();
|
||||
fixture.componentInstance.noticeRequested.subscribe(requested);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'HAND_DELIVERY',
|
||||
otherDeliveryMode: '',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
it('requires and sends an explicit attestation when no evidence is selected', () => {
|
||||
const fixture = TestBed.createComponent(LeaseEndNoticeForm);
|
||||
fixture.componentRef.setInput('timeZone', 'Europe/Paris');
|
||||
fixture.componentRef.setInput('today', '2026-07-19');
|
||||
fixture.componentRef.setInput('submitting', false);
|
||||
const requested = vi.fn();
|
||||
fixture.componentInstance.noticeRequested.subscribe(requested);
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.model.set({
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'HAND_DELIVERY',
|
||||
otherDeliveryMode: '',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain('sans justificatif');
|
||||
fixture.componentInstance.submit();
|
||||
expect(fixture.componentInstance.validationError()).toContain('sans justificatif');
|
||||
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
missingEvidenceConfirmed: true,
|
||||
}));
|
||||
fixture.componentInstance.submit();
|
||||
expect(requested).toHaveBeenCalledWith({
|
||||
timeZone: 'Europe/Paris',
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'HAND_DELIVERY',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: true,
|
||||
});
|
||||
});
|
||||
fixture.componentInstance.model.update((model) => ({
|
||||
...model,
|
||||
missingEvidenceConfirmed: true,
|
||||
}));
|
||||
fixture.componentInstance.submit();
|
||||
expect(requested).toHaveBeenCalledWith({
|
||||
timeZone: 'Europe/Paris',
|
||||
receivedOn: '2026-07-19',
|
||||
requestedDepartureOn: '2026-08-19',
|
||||
deliveryMode: 'HAND_DELIVERY',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,90 +5,92 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { NoticeDeliveryMode, RecordNoticeRequest } from '../../services/lease-end.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-lease-end-notice-form',
|
||||
imports: [FormsModule, FormField, FormRoot, MatButtonModule],
|
||||
templateUrl: './lease-end-notice-form.html',
|
||||
styleUrl: './lease-end-notice-form.css',
|
||||
selector: 'app-lease-end-notice-form',
|
||||
imports: [FormsModule, FormField, FormRoot, MatButtonModule],
|
||||
templateUrl: './lease-end-notice-form.html',
|
||||
styleUrl: './lease-end-notice-form.css',
|
||||
})
|
||||
export class LeaseEndNoticeForm {
|
||||
readonly timeZone = input.required<string>();
|
||||
readonly today = input.required<string>();
|
||||
readonly submitting = input.required<boolean>();
|
||||
readonly operationError = input('');
|
||||
readonly noticeRequested = output<RecordNoticeRequest>();
|
||||
readonly model = signal({
|
||||
receivedOn: '',
|
||||
requestedDepartureOn: '',
|
||||
deliveryMode: '' as NoticeDeliveryMode | '',
|
||||
otherDeliveryMode: '',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
readonly noticeForm = form(this.model, (fields) => {
|
||||
maxLength(fields.otherDeliveryMode, 200);
|
||||
});
|
||||
readonly evidence = signal<File | null>(null);
|
||||
readonly validationError = signal('');
|
||||
readonly lateRegistration = computed(
|
||||
() => this.model().receivedOn !== '' && this.model().receivedOn < this.today(),
|
||||
);
|
||||
readonly deliveryModes = [
|
||||
{ value: 'REGISTERED_LETTER', label: 'Lettre recommandée avec avis de réception' },
|
||||
{ value: 'BAILIFF', label: 'Acte d’un commissaire de justice' },
|
||||
{ value: 'HAND_DELIVERY', label: 'Remise en main propre contre récépissé' },
|
||||
{ value: 'OTHER', label: 'Autre mode' },
|
||||
] as const satisfies readonly { value: NoticeDeliveryMode; label: string }[];
|
||||
readonly timeZone = input.required<string>();
|
||||
readonly today = input.required<string>();
|
||||
readonly submitting = input.required<boolean>();
|
||||
readonly operationError = input('');
|
||||
readonly noticeRequested = output<RecordNoticeRequest>();
|
||||
readonly model = signal({
|
||||
receivedOn: '',
|
||||
requestedDepartureOn: '',
|
||||
deliveryMode: '' as NoticeDeliveryMode | '',
|
||||
otherDeliveryMode: '',
|
||||
lateRegistrationConfirmed: false,
|
||||
nonStandardDeliveryConfirmed: false,
|
||||
missingEvidenceConfirmed: false,
|
||||
});
|
||||
readonly noticeForm = form(this.model, (fields) => {
|
||||
maxLength(fields.otherDeliveryMode, 200);
|
||||
});
|
||||
readonly evidence = signal<File | null>(null);
|
||||
readonly validationError = signal('');
|
||||
readonly lateRegistration = computed(
|
||||
() => this.model().receivedOn !== '' && this.model().receivedOn < this.today(),
|
||||
);
|
||||
readonly deliveryModes = [
|
||||
{ value: 'REGISTERED_LETTER', label: 'Lettre recommandée avec avis de réception' },
|
||||
{ value: 'BAILIFF', label: 'Acte d’un commissaire de justice' },
|
||||
{ value: 'HAND_DELIVERY', label: 'Remise en main propre contre récépissé' },
|
||||
{ value: 'OTHER', label: 'Autre mode' },
|
||||
] as const satisfies readonly { value: NoticeDeliveryMode; label: string }[];
|
||||
|
||||
selectEvidence(event: Event): void {
|
||||
const input = event.target;
|
||||
const evidence = input instanceof HTMLInputElement ? (input.files?.item(0) ?? null) : null;
|
||||
this.evidence.set(evidence);
|
||||
if (evidence) {
|
||||
this.model.update((model) => ({ ...model, missingEvidenceConfirmed: false }));
|
||||
}
|
||||
if (input instanceof HTMLInputElement) input.value = '';
|
||||
}
|
||||
selectEvidence(event: Event): void {
|
||||
const input = event.target;
|
||||
const evidence = input instanceof HTMLInputElement ? (input.files?.item(0) ?? null) : null;
|
||||
this.evidence.set(evidence);
|
||||
if (evidence) {
|
||||
this.model.update((model) => ({ ...model, missingEvidenceConfirmed: false }));
|
||||
}
|
||||
if (input instanceof HTMLInputElement) input.value = '';
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
if (this.submitting()) return;
|
||||
const model = this.model();
|
||||
if (!model.receivedOn || !model.requestedDepartureOn || !model.deliveryMode) {
|
||||
this.validationError.set('Renseignez les deux dates et le mode de remise du congé.');
|
||||
return;
|
||||
}
|
||||
if (this.lateRegistration() && !model.lateRegistrationConfirmed) {
|
||||
this.validationError.set('Confirmez cet enregistrement tardif avant de continuer.');
|
||||
return;
|
||||
}
|
||||
if (model.deliveryMode === 'OTHER' && !model.otherDeliveryMode.trim()) {
|
||||
this.validationError.set('Décrivez le mode de remise utilisé.');
|
||||
return;
|
||||
}
|
||||
if (model.deliveryMode === 'OTHER' && !model.nonStandardDeliveryConfirmed) {
|
||||
this.validationError.set('Confirmez le mode de remise non standard avant de continuer.');
|
||||
return;
|
||||
}
|
||||
if (!this.evidence() && !model.missingEvidenceConfirmed) {
|
||||
this.validationError.set(
|
||||
'Confirmez l’enregistrement de ce congé sans justificatif avant de continuer.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.validationError.set('');
|
||||
const evidence = this.evidence();
|
||||
this.noticeRequested.emit({
|
||||
timeZone: this.timeZone(),
|
||||
receivedOn: model.receivedOn,
|
||||
requestedDepartureOn: model.requestedDepartureOn,
|
||||
deliveryMode: model.deliveryMode,
|
||||
...(model.deliveryMode === 'OTHER'
|
||||
? { otherDeliveryMode: model.otherDeliveryMode.trim() }
|
||||
: {}),
|
||||
lateRegistrationConfirmed: this.lateRegistration(),
|
||||
nonStandardDeliveryConfirmed: model.deliveryMode === 'OTHER',
|
||||
missingEvidenceConfirmed: evidence === null,
|
||||
...(evidence ? { evidence } : {}),
|
||||
});
|
||||
}
|
||||
submit(): void {
|
||||
if (this.submitting()) return;
|
||||
const model = this.model();
|
||||
if (!model.receivedOn || !model.requestedDepartureOn || !model.deliveryMode) {
|
||||
this.validationError.set('Renseignez les deux dates et le mode de remise du congé.');
|
||||
return;
|
||||
}
|
||||
if (this.lateRegistration() && !model.lateRegistrationConfirmed) {
|
||||
this.validationError.set('Confirmez cet enregistrement tardif avant de continuer.');
|
||||
return;
|
||||
}
|
||||
if (model.deliveryMode === 'OTHER' && !model.otherDeliveryMode.trim()) {
|
||||
this.validationError.set('Décrivez le mode de remise utilisé.');
|
||||
return;
|
||||
}
|
||||
if (model.deliveryMode === 'OTHER' && !model.nonStandardDeliveryConfirmed) {
|
||||
this.validationError.set(
|
||||
'Confirmez le mode de remise non standard avant de continuer.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!this.evidence() && !model.missingEvidenceConfirmed) {
|
||||
this.validationError.set(
|
||||
'Confirmez l’enregistrement de ce congé sans justificatif avant de continuer.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.validationError.set('');
|
||||
const evidence = this.evidence();
|
||||
this.noticeRequested.emit({
|
||||
timeZone: this.timeZone(),
|
||||
receivedOn: model.receivedOn,
|
||||
requestedDepartureOn: model.requestedDepartureOn,
|
||||
deliveryMode: model.deliveryMode,
|
||||
...(model.deliveryMode === 'OTHER'
|
||||
? { otherDeliveryMode: model.otherDeliveryMode.trim() }
|
||||
: {}),
|
||||
lateRegistrationConfirmed: this.lateRegistration(),
|
||||
nonStandardDeliveryConfirmed: model.deliveryMode === 'OTHER',
|
||||
missingEvidenceConfirmed: evidence === null,
|
||||
...(evidence ? { evidence } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user