feat(landlord-profile): enhance profile completion dialog and form layout
This commit is contained in:
1 parent
12316b8604
commit
62d0f171f4
6 files changed
+81
-11
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { expect, Page, test } from '@playwright/test';
|
||||
import { expect, Locator, Page, test } from '@playwright/test';
|
||||
|
||||
async function mockUser(page: Page, authenticated: boolean, completeProfile = true): Promise<void> {
|
||||
await page.unroute('**/api/user');
|
||||
@@ -43,6 +43,27 @@ async function expectNoHorizontalOverflow(page: Page): Promise<void> {
|
||||
expect(hasHorizontalOverflow).toBe(false);
|
||||
}
|
||||
|
||||
async function expectNoScrollbars(locator: Locator): Promise<void> {
|
||||
const scrollableElements = await locator.evaluate((element) => {
|
||||
return [element, ...element.querySelectorAll<HTMLElement>('*')]
|
||||
.filter((candidate) => {
|
||||
const { overflowX, overflowY } = getComputedStyle(candidate);
|
||||
const hasHorizontalScrollbar =
|
||||
(overflowX === 'auto' || overflowX === 'scroll') &&
|
||||
candidate.scrollWidth > candidate.clientWidth;
|
||||
const hasVerticalScrollbar =
|
||||
(overflowY === 'auto' || overflowY === 'scroll') &&
|
||||
candidate.scrollHeight > candidate.clientHeight;
|
||||
return hasHorizontalScrollbar || hasVerticalScrollbar;
|
||||
})
|
||||
.map(
|
||||
(candidate) =>
|
||||
`${candidate.tagName.toLowerCase()}.${candidate.getAttribute('class') ?? ''}`,
|
||||
);
|
||||
});
|
||||
expect(scrollableElements).toEqual([]);
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await mockUser(page, false);
|
||||
});
|
||||
@@ -74,13 +95,34 @@ test('requires a newly connected landlord to complete their profile', async ({ p
|
||||
|
||||
const dialog = page.getByRole('dialog');
|
||||
await expect(dialog.getByRole('heading', { name: 'Complétez votre profil' })).toBeVisible();
|
||||
await expectNoHorizontalOverflow(page);
|
||||
await expectNoScrollbars(dialog);
|
||||
await page.keyboard.press('Escape');
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.getByRole('button', { name: 'Déconnexion' })).toBeVisible();
|
||||
const logoutButton = dialog.getByRole('button', { name: 'Déconnexion' });
|
||||
const saveButton = dialog.getByRole('button', { name: 'Enregistrer le profil' });
|
||||
await expect(logoutButton).toBeVisible();
|
||||
await expect(saveButton).toBeVisible();
|
||||
|
||||
const [logoutBox, saveBox, actionBox, surfaceBox] = await Promise.all([
|
||||
logoutButton.boundingBox(),
|
||||
saveButton.boundingBox(),
|
||||
dialog.locator('.profile-actions').boundingBox(),
|
||||
dialog.locator('.mat-mdc-dialog-surface').boundingBox(),
|
||||
]);
|
||||
if (!logoutBox || !saveBox || !actionBox || !surfaceBox) {
|
||||
throw new Error('Profile dialog actions must be measurable.');
|
||||
}
|
||||
expect(logoutBox.x).toBeCloseTo(actionBox.x, 1);
|
||||
expect(saveBox.x + saveBox.width).toBeCloseTo(actionBox.x + actionBox.width, 1);
|
||||
expect(Math.abs(logoutBox.y - saveBox.y)).toBeLessThan(8);
|
||||
expect(surfaceBox.y + surfaceBox.height - (actionBox.y + actionBox.height)).toBeGreaterThanOrEqual(
|
||||
16,
|
||||
);
|
||||
|
||||
await dialog.getByLabel('Téléphone').fill('+33612345678');
|
||||
await dialog.getByLabel('Adresse postale').fill('1 rue des Lilas, Lyon');
|
||||
await dialog.getByRole('button', { name: 'Enregistrer le profil' }).click();
|
||||
await saveButton.click();
|
||||
|
||||
await expect(dialog).toBeHidden();
|
||||
await expect(page.getByTestId('primary-navigation')).toBeVisible();
|
||||
|
||||
+2
-3
@@ -3,9 +3,8 @@
|
||||
width: min(36rem, calc(100vw - 3rem));
|
||||
max-width: 100%;
|
||||
gap: var(--space-4, 1rem);
|
||||
max-height: 75vh;
|
||||
overscroll-behavior-y: contain;
|
||||
container-type: inline-size;
|
||||
padding-inline: var(--space-6, 1.5rem);
|
||||
padding-block-end: var(--space-6, 1.5rem);
|
||||
}
|
||||
|
||||
.profile-dialog-content > p,
|
||||
|
||||
+18
-5
@@ -1,5 +1,5 @@
|
||||
<h2 mat-dialog-title>Complétez votre profil</h2>
|
||||
<mat-dialog-content class="profile-dialog-content">
|
||||
<div class="profile-dialog-content">
|
||||
<p>Vos coordonnées sont nécessaires pour créer vos baux et vos quittances.</p>
|
||||
|
||||
@if (profileStatus() === 'loading') {
|
||||
@@ -13,13 +13,26 @@
|
||||
</div>
|
||||
} @else {
|
||||
<app-landlord-profile-form
|
||||
class="profile-completion-form"
|
||||
[profile]="profile()"
|
||||
[saving]="saving()"
|
||||
[saveError]="error()"
|
||||
(saveRequested)="save($event)"
|
||||
/>
|
||||
>
|
||||
<button
|
||||
profile-form-secondary-action
|
||||
mat-button
|
||||
type="button"
|
||||
(click)="logout()"
|
||||
[disabled]="saving()"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
</app-landlord-profile-form>
|
||||
}
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
</div>
|
||||
@if (profileStatus() !== 'ready') {
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button type="button" (click)="logout()" [disabled]="saving()">Déconnexion</button>
|
||||
</mat-dialog-actions>
|
||||
</mat-dialog-actions>
|
||||
}
|
||||
@@ -3,6 +3,11 @@
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
:host(.profile-completion-form) {
|
||||
--mat-button-text-horizontal-padding: var(--space-1, 0.25rem);
|
||||
--mat-button-filled-horizontal-padding: var(--space-1, 0.25rem);
|
||||
}
|
||||
|
||||
.profile-form {
|
||||
display: grid;
|
||||
gap: var(--space-4, 1rem);
|
||||
@@ -32,6 +37,12 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
:host(.profile-completion-form) .profile-actions {
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-1, 0.25rem);
|
||||
}
|
||||
|
||||
@container (min-width: 32rem) {
|
||||
.profile-fields {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
/></mat-form-field>
|
||||
</fieldset>
|
||||
<div class="profile-actions">
|
||||
<ng-content select="[profile-form-secondary-action]" />
|
||||
<button mat-flat-button type="submit" class="primary-action">
|
||||
@if (saving()) {
|
||||
<mat-spinner diameter="18" aria-hidden="true" /> Enregistrement…
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
@include mat.core();
|
||||
|
||||
.mat-mdc-dialog-surface:has(app-landlord-profile-completion-dialog) {
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
@include mat.theme(
|
||||
|
||||
Reference in new issue
Block a user