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,18 +1,18 @@
|
||||
:host {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
.tenant-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
@media (min-width: 700px) {
|
||||
.tenant-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
.tenant-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1180px) {
|
||||
.tenant-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.tenant-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
@@ -1,96 +1,124 @@
|
||||
@if (!showForm()) {
|
||||
<section class="page-section">
|
||||
<header class="page-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Dossiers</p>
|
||||
<h1>Mes locataires</h1>
|
||||
<p>Contacts, pièces jointes et accès rapide aux baux associés.</p>
|
||||
</div>
|
||||
<button mat-flat-button type="button" class="primary-action" (click)="openAddForm()">
|
||||
<span aria-hidden="true">+</span> Ajouter un locataire
|
||||
</button>
|
||||
</header>
|
||||
<div class="content-region" [attr.aria-busy]="workspace.tenantLoadState().loading">
|
||||
@if (!workspace.tenantLoadState().loaded && workspace.tenantLoadState().loading) {
|
||||
<div class="tenant-grid" aria-label="Chargement des locataires">
|
||||
@for (placeholder of [1, 2, 3]; track placeholder) {
|
||||
<article class="skeleton-card" aria-hidden="true">
|
||||
<span class="skeleton-line skeleton-line-short"></span>
|
||||
<span class="skeleton-line skeleton-line-title"></span>
|
||||
<span class="skeleton-line"></span>
|
||||
<span class="skeleton-line skeleton-line-medium"></span>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
} @else if (!workspace.tenantLoadState().loaded && workspace.tenantLoadState().error) {
|
||||
<article class="load-error" role="alert">
|
||||
<h2>Chargement impossible</h2>
|
||||
<p>{{ workspace.tenantLoadState().error }}</p>
|
||||
<button mat-stroked-button type="button" (click)="workspace.loadTenants()">
|
||||
Réessayer
|
||||
</button>
|
||||
</article>
|
||||
} @else {
|
||||
@if (workspace.tenantLoadState().loading) {
|
||||
<mat-progress-bar mode="indeterminate" aria-label="Actualisation des locataires" />
|
||||
}
|
||||
@if (workspace.tenantLoadState().error) {
|
||||
<div class="refresh-error" role="alert">
|
||||
<p>{{ workspace.tenantLoadState().error }}</p>
|
||||
<button mat-button type="button" (click)="workspace.loadTenants()">Réessayer</button>
|
||||
</div>
|
||||
}
|
||||
@if (workspace.tenants().length === 0) {
|
||||
<article class="empty-state">
|
||||
<p class="eyebrow">Premier dossier</p>
|
||||
<h2>Aucun locataire enregistré</h2>
|
||||
<p>Centralisez ici les coordonnées et pièces jointes utiles de vos locataires.</p>
|
||||
<button mat-stroked-button type="button" (click)="openAddForm()">
|
||||
Ajouter un locataire
|
||||
</button>
|
||||
</article>
|
||||
} @else {
|
||||
<div class="tenant-grid">
|
||||
@for (tenant of workspace.tenants(); track tenant.id) {
|
||||
<app-tenant-card
|
||||
[tenant]="tenant"
|
||||
[attachmentError]="
|
||||
tenant.id ? (workspace.tenantAttachmentErrors()[tenant.id] ?? '') : ''
|
||||
"
|
||||
[uploading]="tenant.id ? workspace.uploadingTenantIds().has(tenant.id) : false"
|
||||
[uploadProgress]="
|
||||
tenant.id ? (workspace.tenantUploadProgress()[tenant.id] ?? null) : null
|
||||
"
|
||||
[deleting]="!!tenant.id && workspace.deletingTenantIds().has(tenant.id)"
|
||||
[deleteError]="tenant.id ? (workspace.tenantDeleteErrors()[tenant.id] ?? '') : ''"
|
||||
[deletingAttachmentIds]="workspace.deletingAttachmentIds()"
|
||||
[attachmentDeleteErrors]="workspace.attachmentDeleteErrors()"
|
||||
[downloadingAttachmentIds]="workspace.downloadingAttachmentIds()"
|
||||
[attachmentDownloadErrors]="workspace.attachmentDownloadErrors()"
|
||||
(editRequested)="openEditForm($event)"
|
||||
(deleteRequested)="workspace.deleteTenant($event)"
|
||||
(attachmentUploadRequested)="
|
||||
workspace.uploadTenantAttachment($event.tenantId, $event.file)
|
||||
"
|
||||
(attachmentDownloadRequested)="
|
||||
workspace.downloadTenantAttachment($event.tenantId, $event.attachment)
|
||||
"
|
||||
(attachmentDeleteRequested)="
|
||||
workspace.deleteTenantAttachment($event.tenantId, $event.attachment)
|
||||
"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
<section class="page-section">
|
||||
<header class="page-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Dossiers</p>
|
||||
<h1>Mes locataires</h1>
|
||||
<p>Contacts, pièces jointes et accès rapide aux baux associés.</p>
|
||||
</div>
|
||||
<button mat-flat-button type="button" class="primary-action" (click)="openAddForm()">
|
||||
<span aria-hidden="true">+</span> Ajouter un locataire
|
||||
</button>
|
||||
</header>
|
||||
<div class="content-region" [attr.aria-busy]="workspace.tenantLoadState().loading">
|
||||
@if (!workspace.tenantLoadState().loaded && workspace.tenantLoadState().loading) {
|
||||
<div class="tenant-grid" aria-label="Chargement des locataires">
|
||||
@for (placeholder of [1, 2, 3]; track placeholder) {
|
||||
<article class="skeleton-card" aria-hidden="true">
|
||||
<span class="skeleton-line skeleton-line-short"></span>
|
||||
<span class="skeleton-line skeleton-line-title"></span>
|
||||
<span class="skeleton-line"></span>
|
||||
<span class="skeleton-line skeleton-line-medium"></span>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
} @else if (!workspace.tenantLoadState().loaded && workspace.tenantLoadState().error) {
|
||||
<article class="load-error" role="alert">
|
||||
<h2>Chargement impossible</h2>
|
||||
<p>{{ workspace.tenantLoadState().error }}</p>
|
||||
<button mat-stroked-button type="button" (click)="workspace.loadTenants()">
|
||||
Réessayer
|
||||
</button>
|
||||
</article>
|
||||
} @else {
|
||||
@if (workspace.tenantLoadState().loading) {
|
||||
<mat-progress-bar
|
||||
mode="indeterminate"
|
||||
aria-label="Actualisation des locataires"
|
||||
/>
|
||||
}
|
||||
@if (workspace.tenantLoadState().error) {
|
||||
<div class="refresh-error" role="alert">
|
||||
<p>{{ workspace.tenantLoadState().error }}</p>
|
||||
<button mat-button type="button" (click)="workspace.loadTenants()">
|
||||
Réessayer
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@if (workspace.tenants().length === 0) {
|
||||
<article class="empty-state">
|
||||
<p class="eyebrow">Premier dossier</p>
|
||||
<h2>Aucun locataire enregistré</h2>
|
||||
<p>
|
||||
Centralisez ici les coordonnées et pièces jointes utiles de vos
|
||||
locataires.
|
||||
</p>
|
||||
<button mat-stroked-button type="button" (click)="openAddForm()">
|
||||
Ajouter un locataire
|
||||
</button>
|
||||
</article>
|
||||
} @else {
|
||||
<div class="tenant-grid">
|
||||
@for (tenant of workspace.tenants(); track tenant.id) {
|
||||
<app-tenant-card
|
||||
[tenant]="tenant"
|
||||
[attachmentError]="
|
||||
tenant.id
|
||||
? (workspace.tenantAttachmentErrors()[tenant.id] ?? '')
|
||||
: ''
|
||||
"
|
||||
[uploading]="
|
||||
tenant.id
|
||||
? workspace.uploadingTenantIds().has(tenant.id)
|
||||
: false
|
||||
"
|
||||
[uploadProgress]="
|
||||
tenant.id
|
||||
? (workspace.tenantUploadProgress()[tenant.id] ?? null)
|
||||
: null
|
||||
"
|
||||
[deleting]="
|
||||
!!tenant.id && workspace.deletingTenantIds().has(tenant.id)
|
||||
"
|
||||
[deleteError]="
|
||||
tenant.id
|
||||
? (workspace.tenantDeleteErrors()[tenant.id] ?? '')
|
||||
: ''
|
||||
"
|
||||
[deletingAttachmentIds]="workspace.deletingAttachmentIds()"
|
||||
[attachmentDeleteErrors]="workspace.attachmentDeleteErrors()"
|
||||
[downloadingAttachmentIds]="workspace.downloadingAttachmentIds()"
|
||||
[attachmentDownloadErrors]="workspace.attachmentDownloadErrors()"
|
||||
(editRequested)="openEditForm($event)"
|
||||
(deleteRequested)="workspace.deleteTenant($event)"
|
||||
(attachmentUploadRequested)="
|
||||
workspace.uploadTenantAttachment($event.tenantId, $event.file)
|
||||
"
|
||||
(attachmentDownloadRequested)="
|
||||
workspace.downloadTenantAttachment(
|
||||
$event.tenantId,
|
||||
$event.attachment
|
||||
)
|
||||
"
|
||||
(attachmentDeleteRequested)="
|
||||
workspace.deleteTenantAttachment(
|
||||
$event.tenantId,
|
||||
$event.attachment
|
||||
)
|
||||
"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
} @else {
|
||||
<app-tenant-form
|
||||
[tenant]="editingTenant()"
|
||||
[saving]="workspace.tenantSaving(editingTenant()?.id)"
|
||||
[saveError]="workspace.tenantSaveError(editingTenant()?.id)"
|
||||
(cancelled)="closeForm()"
|
||||
(submitted)="saveTenant($event)"
|
||||
/>
|
||||
<app-tenant-form
|
||||
[tenant]="editingTenant()"
|
||||
[saving]="workspace.tenantSaving(editingTenant()?.id)"
|
||||
[saveError]="workspace.tenantSaveError(editingTenant()?.id)"
|
||||
(cancelled)="closeForm()"
|
||||
(submitted)="saveTenant($event)"
|
||||
/>
|
||||
}
|
||||
@@ -3,36 +3,39 @@ import { TenantsPage } from './tenants-page';
|
||||
import { WorkspaceService } from '../../services/workspace.service';
|
||||
|
||||
describe('TenantsPage', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: WorkspaceService,
|
||||
useValue: { loadTenants: () => undefined, clearTenantSaveError: () => undefined },
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: WorkspaceService,
|
||||
useValue: {
|
||||
loadTenants: () => undefined,
|
||||
clearTenantSaveError: () => undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
it('opens and closes the focused tenant form module', () => {
|
||||
const fixture = TestBed.createComponent(TenantsPage);
|
||||
const component = fixture.componentInstance;
|
||||
it('opens and closes the focused tenant form module', () => {
|
||||
const fixture = TestBed.createComponent(TenantsPage);
|
||||
const component = fixture.componentInstance;
|
||||
|
||||
component.openAddForm();
|
||||
expect(component.showForm()).toBe(true);
|
||||
expect(component.editingTenant()).toBeNull();
|
||||
component.openAddForm();
|
||||
expect(component.showForm()).toBe(true);
|
||||
expect(component.editingTenant()).toBeNull();
|
||||
|
||||
component.openEditForm({
|
||||
id: 'tenant-1',
|
||||
firstName: 'Camille',
|
||||
lastName: 'Martin',
|
||||
email: 'camille@example.com',
|
||||
phone: '',
|
||||
address: '',
|
||||
});
|
||||
expect(component.editingTenant()?.id).toBe('tenant-1');
|
||||
component.openEditForm({
|
||||
id: 'tenant-1',
|
||||
firstName: 'Camille',
|
||||
lastName: 'Martin',
|
||||
email: 'camille@example.com',
|
||||
phone: '',
|
||||
address: '',
|
||||
});
|
||||
expect(component.editingTenant()?.id).toBe('tenant-1');
|
||||
|
||||
component.closeForm();
|
||||
expect(component.showForm()).toBe(false);
|
||||
});
|
||||
component.closeForm();
|
||||
expect(component.showForm()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -7,36 +7,36 @@ import { TenantCard } from '../tenant-card/tenant-card';
|
||||
import { TenantForm, TenantSaveRequest } from '../tenant-form/tenant-form';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tenants-page',
|
||||
imports: [MatButtonModule, MatProgressBarModule, TenantCard, TenantForm],
|
||||
templateUrl: './tenants-page.html',
|
||||
styleUrl: './tenants-page.css',
|
||||
selector: 'app-tenants-page',
|
||||
imports: [MatButtonModule, MatProgressBarModule, TenantCard, TenantForm],
|
||||
templateUrl: './tenants-page.html',
|
||||
styleUrl: './tenants-page.css',
|
||||
})
|
||||
export class TenantsPage {
|
||||
readonly workspace = inject(WorkspaceService);
|
||||
readonly workspace = inject(WorkspaceService);
|
||||
|
||||
readonly showForm = signal(false);
|
||||
readonly editingTenant = signal<Tenant | null>(null);
|
||||
readonly showForm = signal(false);
|
||||
readonly editingTenant = signal<Tenant | null>(null);
|
||||
|
||||
constructor() {
|
||||
this.workspace.loadTenants();
|
||||
}
|
||||
constructor() {
|
||||
this.workspace.loadTenants();
|
||||
}
|
||||
|
||||
openAddForm(): void {
|
||||
this.workspace.clearTenantSaveError();
|
||||
this.editingTenant.set(null);
|
||||
this.showForm.set(true);
|
||||
}
|
||||
openEditForm(tenant: Tenant): void {
|
||||
this.workspace.clearTenantSaveError(tenant.id);
|
||||
this.editingTenant.set(tenant);
|
||||
this.showForm.set(true);
|
||||
}
|
||||
closeForm(): void {
|
||||
this.showForm.set(false);
|
||||
this.editingTenant.set(null);
|
||||
}
|
||||
saveTenant(request: TenantSaveRequest): void {
|
||||
this.workspace.saveTenant(request.tenant, request.tenantId, () => this.closeForm());
|
||||
}
|
||||
openAddForm(): void {
|
||||
this.workspace.clearTenantSaveError();
|
||||
this.editingTenant.set(null);
|
||||
this.showForm.set(true);
|
||||
}
|
||||
openEditForm(tenant: Tenant): void {
|
||||
this.workspace.clearTenantSaveError(tenant.id);
|
||||
this.editingTenant.set(tenant);
|
||||
this.showForm.set(true);
|
||||
}
|
||||
closeForm(): void {
|
||||
this.showForm.set(false);
|
||||
this.editingTenant.set(null);
|
||||
}
|
||||
saveTenant(request: TenantSaveRequest): void {
|
||||
this.workspace.saveTenant(request.tenant, request.tenantId, () => this.closeForm());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user