mirror of
https://github.com/block/buzz.git
synced 2026-11-13 21:01:53 +00:00
## Summary - restore direct community member adds in **Settings → Invites** - keep one consolidated entry point: the dialog now supports both adding someone directly and sharing an invite link - accept npub or 64-character hex keys while preserving role hierarchy (owners: Member/Admin; admins: Member only) - verify an npub direct-add publishes the decoded hex key in a kind `9030` NIP-IA event ## Why The Invites consolidation left `AddMemberDialog` without a live mount point, so the existing direct-add capability disappeared even though its mutation path still existed. This reuses that implementation rather than introducing a second one. ## Before and after | Before | After | | --- | --- | | The consolidated dialog only offered a share link; there was no direct-add path. | The same dialog now presents direct add and share-link controls as one invitation flow. | |  |  | <details> <summary>Before: Invites page entry point</summary>  </details> ## Verification - `pnpm --dir desktop build:e2e` - `pnpm exec playwright test tests/e2e/invites-settings-screenshots.spec.ts --project=smoke` — 4 passed - targeted Biome check on modified files - push hook: Desktop check and 3,783 Desktop tests passed - GitHub CI green except Desktop E2E Relay still running at last status snapshot --------- Signed-off-by: Joah Gerstenberg <joah@squareup.com> Signed-off-by: Wes <wesbillman@users.noreply.github.com> Signed-off-by: kenny lopez <klopez4212@gmail.com> Co-authored-by: Joah Gerstenberg <joah@squareup.com> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Co-authored-by: kenny lopez <klopez4212@gmail.com>
89 lines
3.1 KiB
TypeScript
89 lines
3.1 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { installMockBridge } from "../helpers/bridge";
|
|
import { openSettings } from "../helpers/settings";
|
|
|
|
let invitePayloads: Record<string, unknown>[];
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
invitePayloads = [];
|
|
await page.context().grantPermissions(["clipboard-read", "clipboard-write"], {
|
|
origin: "http://127.0.0.1:4173",
|
|
});
|
|
await installMockBridge(page, {
|
|
relayRequiresMembership: true,
|
|
});
|
|
await page.route("**/api/invites", async (route) => {
|
|
invitePayloads.push(route.request().postDataJSON());
|
|
await route.fulfill({
|
|
contentType: "application/json",
|
|
json: {
|
|
code: "qr-download-test",
|
|
expires_at: Math.floor(Date.now() / 1000) + 86_400,
|
|
url: "buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=qr-download-test",
|
|
},
|
|
status: 200,
|
|
});
|
|
});
|
|
});
|
|
|
|
test("copies a freshly minted invite link without showing a URL or QR code", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
await openSettings(page, "community-members");
|
|
await expect(page.getByTestId("settings-community-members")).toBeVisible();
|
|
|
|
await page.getByTestId("community-invite-dialog-trigger").click();
|
|
await expect(page.getByTestId("member-pubkey-input")).toBeVisible();
|
|
await expect(page.getByTestId("member-role")).toHaveCount(0);
|
|
await expect(page.getByTestId("confirm-add-member")).toHaveCount(0);
|
|
await expect(page.getByTestId("invite-link-url")).toHaveCount(0);
|
|
await expect(page.getByTestId("invite-link-qr-code")).toHaveCount(0);
|
|
await expect(page.getByTestId("invite-link-max-uses-trigger")).toHaveText(
|
|
"No limit",
|
|
);
|
|
await page.getByTestId("copy-invite-link").click();
|
|
await expect(page.getByTestId("copy-invite-link")).toContainText("Copied");
|
|
expect(invitePayloads).toEqual([{ ttl_secs: 3 * 24 * 60 * 60 }]);
|
|
|
|
const payload = await page.evaluate(() => {
|
|
const log = (
|
|
window as Window & {
|
|
__BUZZ_E2E_COMMAND_LOG__?: Array<{
|
|
command: string;
|
|
payload: Record<string, unknown> | null;
|
|
}>;
|
|
}
|
|
).__BUZZ_E2E_COMMAND_LOG__;
|
|
return log?.findLast(({ command }) => command === "copy_text_to_clipboard")
|
|
?.payload;
|
|
});
|
|
|
|
expect(payload).toEqual({
|
|
text: "buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=qr-download-test",
|
|
});
|
|
});
|
|
|
|
test("sets a selected invite-use limit", async ({ page }) => {
|
|
await page.goto("/");
|
|
await openSettings(page, "community-members");
|
|
await page.getByTestId("community-invite-dialog-trigger").click();
|
|
|
|
const maxUsesTrigger = page.getByTestId("invite-link-max-uses-trigger");
|
|
await maxUsesTrigger.click();
|
|
await expect(
|
|
page.getByRole("menuitemradio", { name: "No limit" }),
|
|
).toBeVisible();
|
|
await expect(
|
|
page.getByRole("menuitemradio", { name: "25 uses" }),
|
|
).toBeVisible();
|
|
await page.getByTestId("invite-link-max-uses-10").click();
|
|
await expect(maxUsesTrigger).toHaveText("10 uses");
|
|
await page.getByTestId("copy-invite-link").click();
|
|
await expect(page.getByTestId("copy-invite-link")).toContainText("Copied");
|
|
expect(invitePayloads).toEqual([
|
|
{ max_uses: 10, ttl_secs: 3 * 24 * 60 * 60 },
|
|
]);
|
|
});
|