diff --git a/package.json b/package.json index dc8794f0..87afad84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "impro", - "version": "0.18.197", + "version": "0.18.198", "type": "module", "scripts": { "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve", diff --git a/src/css/style.css b/src/css/style.css index d0915c59..42247399 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -7440,7 +7440,7 @@ context-menu-item-group > context-menu-item > button { flex-direction: column-reverse; } -.modal-dialog-button.confirm-button.is-pending { +.modal-dialog-button.is-pending { display: inline-flex; align-items: center; justify-content: center; @@ -7449,7 +7449,7 @@ context-menu-item-group > context-menu-item > button { opacity: 1; } -.modal-dialog-button.confirm-button .loading-spinner { +.modal-dialog-button .loading-spinner { width: 14px; height: 14px; border-width: 2px; diff --git a/src/js/modals/choice.modal.js b/src/js/modals/choice.modal.js index 77d974af..67f18492 100644 --- a/src/js/modals/choice.modal.js +++ b/src/js/modals/choice.modal.js @@ -2,6 +2,8 @@ import { html } from "/js/lib/lit-html.js"; import { Modal } from "/js/modals/modal.js"; class ChoiceModal extends Modal { + #pendingValue = null; + get className() { return "bottom-sheet text-modal confirm-modal choice-modal compact"; } @@ -10,9 +12,30 @@ class ChoiceModal extends Modal { return { "data-testid": "choice-modal" }; } - render({ dismiss, props: { message, title, choices } }) { + canDismiss() { + return this.#pendingValue === null; + } + + render({ dismiss, update, props: { message, title, choices, onChoose } }) { + const pendingValue = this.#pendingValue; + const isPending = pendingValue !== null; + const handleChoice = async (choice) => { + if (!onChoose) { + dismiss(choice.value); + return; + } + this.#pendingValue = choice.value; + update(); + try { + await onChoose(choice.value); + dismiss(choice.value); + } catch { + this.#pendingValue = null; + update(); + } + }; return html` - `, root, diff --git a/tests/e2e/specs/views/settingsNotifications.view.test.js b/tests/e2e/specs/views/settingsNotifications.view.test.js index 8f9b6809..76c5a322 100644 --- a/tests/e2e/specs/views/settingsNotifications.view.test.js +++ b/tests/e2e/specs/views/settingsNotifications.view.test.js @@ -280,7 +280,7 @@ test.describe("Settings > Notifications view", () => { // handoff return has none — so it must be asked for on this press. await page .locator( - '[data-testid="confirm-modal"] [data-testid="modal-confirm-button"]', + '[data-testid="choice-modal"] [data-testid="modal-choice-without-previews"]', ) .click(); @@ -292,6 +292,60 @@ test.describe("Settings > Notifications view", () => { notificationService.authUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), ), ); + expect(new URL(page.url()).searchParams.get("chat_previews")).toBe("0"); + }); + + test("message previews are chosen from the same prompt", async ({ + page, + }) => { + const mockServer = new MockServer(); + mockServer.setNotificationServiceDid(notificationService.did); + await mockServer.setup(page); + await stubNotificationPermission(page, { initial: "default" }); + await login(page); + await page.goto("/settings/notifications"); + + const toggle = page.locator('[data-testid="push-notifications-toggle"]'); + await expect(toggle).not.toHaveAttribute("disabled", "", { + timeout: 10000, + }); + await toggle.click(); + await page + .locator( + '[data-testid="choice-modal"] [data-testid="modal-choice-with-previews"]', + ) + .click(); + + await expect(page).toHaveURL( + new RegExp( + notificationService.authUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), + ), + ); + expect(new URL(page.url()).searchParams.get("chat_previews")).toBe("1"); + }); + + test("cancelling the prompt asks for no permission", async ({ page }) => { + const mockServer = new MockServer(); + mockServer.setNotificationServiceDid(notificationService.did); + await mockServer.setup(page); + await stubNotificationPermission(page, { initial: "default" }); + await login(page); + await page.goto("/settings/notifications"); + + const toggle = page.locator('[data-testid="push-notifications-toggle"]'); + await expect(toggle).not.toHaveAttribute("disabled", "", { + timeout: 10000, + }); + await toggle.click(); + await page + .locator( + '[data-testid="choice-modal"] [data-testid="modal-choice-cancel"]', + ) + .click(); + + await expect(page.locator('[data-testid="choice-modal"]')).toHaveCount(0); + expect(await page.evaluate(() => window.__permissionRequests)).toBe(0); + await expect(page).toHaveURL(/\/settings\/notifications$/); }); test("a denied prompt stops before the handoff", async ({ page }) => { @@ -312,7 +366,7 @@ test.describe("Settings > Notifications view", () => { await toggle.click(); await page .locator( - '[data-testid="confirm-modal"] [data-testid="modal-confirm-button"]', + '[data-testid="choice-modal"] [data-testid="modal-choice-without-previews"]', ) .click();