mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
The "restore storage/wallet from Nostr" confirm was popping over the guided tour (both fire on login). Gate the restore dialog behind a "tour gate": - maybeOfferOnboardingTour opens the gate synchronously when the tour will run (shouldOfferOnboarding), before its own start delay — so ordering can't race. The tour offer is now called before the restore offer on login. - launchBitvidTour gains an onEnd(status) hook (fires on finish AND skip); startOnboardingTour closes the gate on end, and also closes it if the tour never starts (logged out, no eligible steps) so restore can't hang. - The restore prompt's confirm now awaits whenOnboardingTourInactive() before showing — the remote existence check still runs in parallel, only the dialog is held back. No tour → gate stays closed → restore behaves as before. Co-Authored-By: Claude Opus 4.8 <[email protected]>
106 lines
3.3 KiB
JavaScript
106 lines
3.3 KiB
JavaScript
// bitvid's first-run guided tour (docs/onboarding-plan.md): the step script fed
|
|
// into the generic tourEngine. Anchors use existing stable selectors (ids +
|
|
// data-testid added for e2e), and steps whose anchor is absent in the current
|
|
// layout are skipped automatically by the engine.
|
|
|
|
import { createTour } from "./tourEngine.js";
|
|
import {
|
|
shouldOfferOnboarding,
|
|
markOnboarding,
|
|
} from "../../services/onboardingService.js";
|
|
|
|
export function buildBitvidTourSteps({ openProfilePane } = {}) {
|
|
const open = (pane) => () => {
|
|
try {
|
|
openProfilePane?.(pane);
|
|
} catch (error) {
|
|
// best-effort deep link
|
|
}
|
|
};
|
|
|
|
return [
|
|
{
|
|
id: "welcome",
|
|
title: "Welcome to bitvid 👋",
|
|
body:
|
|
"bitvid is decentralized video on Nostr — your identity, follows, and videos belong to you, not a platform. Here's a quick tour (30 seconds).",
|
|
},
|
|
{
|
|
id: "feeds",
|
|
target: "#sidebar",
|
|
placement: "right", // full-height column — popover beside it, not below
|
|
title: "Your feeds",
|
|
body:
|
|
"Recent shows the newest videos across the network. For You learns from what you watch, and Trending ranks by views. Switch any time from this sidebar.",
|
|
},
|
|
{
|
|
id: "subscriptions",
|
|
target: "#subscriptionsLink",
|
|
title: "Follow creators",
|
|
body:
|
|
"Subscribe to channels you like and they'll fill this feed. Your follow list is a Nostr list — it travels with your account to any client.",
|
|
},
|
|
{
|
|
id: "upload",
|
|
target: '[data-testid="upload-button"]',
|
|
title: "Post your own videos",
|
|
body:
|
|
"Upload to your own storage (Cloudflare R2, S3, B2) or paste a link to a video hosted anywhere. bitvid adds WebTorrent peer-to-peer streaming on top automatically.",
|
|
},
|
|
{
|
|
id: "profile",
|
|
target: '[data-testid="profile-button"]',
|
|
title: "Everything else lives here",
|
|
body:
|
|
"Your profile menu holds relays, direct messages, storage, your wallet, moderation settings — and this tour, if you ever want it again.",
|
|
},
|
|
{
|
|
id: "finish",
|
|
title: "You're set 🎉",
|
|
body:
|
|
"Two optional power-ups: connect storage so you can upload videos, and connect a Lightning wallet (NWC) so you can zap creators.",
|
|
actions: [
|
|
{ label: "Set up storage", onClick: open("storage"), variant: "ghost" },
|
|
{ label: "Connect wallet", onClick: open("wallet"), variant: "ghost" },
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
// Launch the tour for a pubkey. `force` (the "Take the tour" button) ignores the
|
|
// once-per-account flag. Returns true when the tour actually started.
|
|
export function launchBitvidTour({
|
|
pubkey,
|
|
openProfilePane,
|
|
document: doc,
|
|
force = false,
|
|
onEnd,
|
|
} = {}) {
|
|
if (!force && !shouldOfferOnboarding(pubkey)) {
|
|
return false;
|
|
}
|
|
|
|
// Fire onEnd on both finish and skip so callers can release anything they
|
|
// deferred for the tour's duration (e.g. the settings-restore prompt).
|
|
const end = (status) => {
|
|
markOnboarding(pubkey, status);
|
|
try {
|
|
onEnd?.(status);
|
|
} catch (error) {
|
|
// best-effort
|
|
}
|
|
};
|
|
|
|
const tour = createTour({
|
|
steps: buildBitvidTourSteps({ openProfilePane }),
|
|
document: doc,
|
|
onFinish: () => end("completed"),
|
|
onSkip: () => end("skipped"),
|
|
});
|
|
|
|
const started = Boolean(tour?.start());
|
|
return started;
|
|
}
|
|
|
|
export default launchBitvidTour;
|