Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion desktop/src/features/communities/ui/WelcomeSetup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from "react";
import { Check, Copy } from "lucide-react";

import { HostedCommunityOnboarding } from "@/features/communities/ui/HostedCommunityOnboarding";
import { useCommunityOnboarding } from "@/features/onboarding/communityOnboarding";
Expand All @@ -12,6 +13,9 @@ import {
type OnboardingTransitionDirection,
OnboardingSlideTransition,
} from "@/features/onboarding/ui/OnboardingSlideTransition";
import { useIdentityQuery } from "@/shared/api/hooks";
import { writeTextToClipboard } from "@/shared/lib/clipboard";
import { pubkeyToNpub } from "@/shared/lib/nostrUtils";
import { useSystemColorScheme } from "@/shared/theme/useSystemColorScheme";
import { Button } from "@/shared/ui/button";
import { Card } from "@/shared/ui/card";
Expand Down Expand Up @@ -41,8 +45,18 @@ export function WelcomeSetup({
// we only navigate to the hosted stage once sign-in completes, so the page
// behind the modal never changes out from under the user.
const [isHostedSignInOpen, setIsHostedSignInOpen] = React.useState(false);
const [copiedNpub, setCopiedNpub] = React.useState(false);
const communityOnboarding = useCommunityOnboarding();
const identityQuery = useIdentityQuery();
const systemColorScheme = useSystemColorScheme();
const npub = identityQuery.data?.pubkey
? pubkeyToNpub(identityQuery.data.pubkey)
: "";
const npubError = identityQuery.error
? identityQuery.error instanceof Error
? identityQuery.error.message
: "Could not load your public key."
: null;

const showPage = React.useCallback(
(nextPage: WelcomeSetupPage, direction?: OnboardingTransitionDirection) => {
Expand Down Expand Up @@ -243,7 +257,7 @@ export function WelcomeSetup({
: "Enter the invite link or community URL you received."}
</p>
</div>
<div className="flex w-full flex-1 items-center justify-center">
<div className="flex w-full flex-1 flex-col items-center justify-center gap-16">
<InviteRedeemForm
error={null}
isRedeeming={false}
Expand All @@ -255,6 +269,52 @@ export function WelcomeSetup({
placeholder="Invite link or community URL"
variant="onboarding-spotlight"
/>
{page === "join" ? (
<div className="w-full max-w-[560px] text-left">
<p className="text-sm font-medium text-foreground">
Joining a private community?
</p>
<p className="mt-2 text-sm leading-6 text-foreground/75">
Some communities need the owner to add you before you can
join. Copy your public ID and send it to the community
owner.
</p>
<div className="mt-4 flex items-center gap-3 rounded-xl border border-foreground/10 bg-background/35 px-4 py-3">
<code
className="min-w-0 flex-1 truncate font-mono text-xs text-foreground/80"
data-testid="welcome-join-npub"
>
{npub || "Loading…"}
</code>
<Button
aria-label="Copy public ID"
className="h-9 shrink-0 rounded-full px-3"
disabled={!npub}
onClick={() => {
void writeTextToClipboard(npub).then(() => {
setCopiedNpub(true);
window.setTimeout(() => setCopiedNpub(false), 1500);
});
}}
size="sm"
type="button"
variant="outline"
>
{copiedNpub ? (
<Check className="h-4 w-4" aria-hidden="true" />
) : (
<Copy className="h-4 w-4" aria-hidden="true" />
)}
<span>{copiedNpub ? "Copied" : "Copy"}</span>
</Button>
</div>
{npubError ? (
<p className="mt-3 text-sm text-destructive">
{npubError}
</p>
) : null}
</div>
) : null}
</div>
</OnboardingSlideTransition>
)}
Expand Down
5 changes: 5 additions & 0 deletions desktop/tests/e2e/onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,11 @@ test("first-community choices route join, create, owner, and member intents", as
await expect(
page.getByRole("heading", { name: "Join a community" }),
).toBeVisible();
await expect(page.getByText("Joining a private community?")).toBeVisible();
await expect(page.getByTestId("welcome-join-npub")).toBeVisible();
await expect(
page.getByRole("button", { name: "Copy public ID" }),
).toBeVisible();
await accessInput.fill("https://default.example.com/invite/abc123");
await expect(page.getByTestId("invite-redeem-submit")).toBeEnabled();
});
Expand Down