Dont require login for profile and note views

This commit is contained in:
hzrd149 2023-06-05 12:22:54 -04:00
parent 780491aa6c
commit 2aa6ec5678
30 changed files with 249 additions and 126 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Dont require login for profile and note views

View File

@ -37,37 +37,12 @@ import UserMediaTab from "./views/user/media";
// code split search view because QrScanner library is 400kB
const SearchView = React.lazy(() => import("./views/search"));
const RequireCurrentAccount = ({ children }: { children: JSX.Element }) => {
let location = useLocation();
const loading = useSubject(accountService.loading);
const account = useSubject(accountService.current);
if (loading) {
return (
<Flex alignItems="center" height="100%" gap="4" direction="column">
<Flex gap="4" grow="1" alignItems="center">
<Spinner />
<Text>Loading Accounts</Text>
</Flex>
<Button variant="link" margin="4" onClick={() => deleteDatabase()}>
Stuck loading? clear cache
</Button>
</Flex>
);
}
if (!account) return <Navigate to="/login" state={{ from: location.pathname }} replace />;
return children;
};
const RootPage = () => (
<RequireCurrentAccount>
<Page>
<Suspense fallback={<Spinner />}>
<Outlet />
</Suspense>
</Page>
</RequireCurrentAccount>
<Page>
<Suspense fallback={<Spinner />}>
<Outlet />
</Suspense>
</Page>
);
const router = createBrowserRouter([

View File

@ -18,7 +18,7 @@ export function QuoteRepostButton({ event }: { event: NostrEvent }) {
onClick={handleClick}
aria-label="Quote repost"
title="Quote repost"
isDisabled={account.readonly}
isDisabled={account?.readonly ?? true}
/>
);
}

View File

@ -45,7 +45,7 @@ export default function ReactionButton({ note, ...props }: { note: NostrEvent }
handleClick(input);
};
const isLiked = reactions.some((event) => event.pubkey === account.pubkey);
const isLiked = !!account && reactions.some((event) => event.pubkey === account.pubkey);
return (
// <Popover placement="bottom" trigger="hover" openDelay={500}>

View File

@ -13,6 +13,12 @@ export function ReplyButton({ event }: { event: NostrEvent }) {
const reply = () => openModal(buildReply(event));
return (
<IconButton icon={<ReplyIcon />} title="Reply" aria-label="Reply" onClick={reply} isDisabled={account.readonly} />
<IconButton
icon={<ReplyIcon />}
title="Reply"
aria-label="Reply"
onClick={reply}
isDisabled={account?.readonly ?? true}
/>
);
}

View File

@ -30,6 +30,7 @@ export function RepostButton({ event }: { event: NostrEvent }) {
const handleClick = async () => {
try {
if (!account) throw new Error("not logged in");
setLoading(true);
const draftRepost = buildRepost(event);
const repost = await signingService.requestSignature(draftRepost, account);
@ -50,7 +51,7 @@ export function RepostButton({ event }: { event: NostrEvent }) {
onClick={onOpen}
aria-label="Repost Note"
title="Repost Note"
isDisabled={account.readonly}
isDisabled={account?.readonly ?? true}
isLoading={loading}
/>
{isOpen && (

View File

@ -43,6 +43,7 @@ export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuI
const deleteNote = useCallback(async () => {
try {
if (!account) throw new Error("not logged in");
setDeleting(true);
const deleteEvent = buildDeleteEvent([event.id], reason);
const signed = await signingService.requestSignature(deleteEvent, account);
@ -75,7 +76,7 @@ export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuI
Copy Note ID
</MenuItem>
)}
{account.pubkey === event.pubkey && (
{account?.pubkey === event.pubkey && (
<MenuItem icon={<TrashIcon />} color="red.500" onClick={deleteModal.onOpen}>
Delete Note
</MenuItem>

View File

@ -26,7 +26,7 @@ export default function NoteZapButton({ note, ...props }: { note: NostrEvent } &
}, [zaps]);
const { isOpen, onOpen, onClose } = useDisclosure();
const hasZapped = parsedZaps.some((zapRequest) => zapRequest.request.pubkey === account.pubkey);
const hasZapped = !!account && parsedZaps.some((zapRequest) => zapRequest.request.pubkey === account.pubkey);
const tipAddress = metadata?.lud06 || metadata?.lud16;
const invoicePaid = () => eventZapsService.requestZaps(note.id, clientRelaysService.getReadUrls(), true);

View File

@ -1,8 +1,8 @@
import React, { PropsWithChildren, useContext } from "react";
import { NostrEvent } from "../../types/nostr-event";
import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useUserContacts } from "../../hooks/use-user-contacts";
import { useCurrentAccount } from "../../hooks/use-current-account";
import clientFollowingService from "../../services/client-following";
import useSubject from "../../hooks/use-subject";
const TrustContext = React.createContext<boolean>(false);
@ -18,11 +18,9 @@ export function TrustProvider({
const parentTrust = useContext(TrustContext);
const account = useCurrentAccount();
const readRelays = useReadRelayUrls();
const contacts = useUserContacts(account.pubkey, readRelays);
const following = contacts?.contacts || [];
const following = useSubject(clientFollowingService.following).map((p) => p[1]);
const isEventTrusted = trust || (!!event && (event.pubkey === account.pubkey || following.includes(event.pubkey)));
const isEventTrusted = trust || (!!event && (event.pubkey === account?.pubkey || following.includes(event.pubkey)));
return <TrustContext.Provider value={parentTrust || isEventTrusted}>{children}</TrustContext.Provider>;
}

View File

@ -5,7 +5,7 @@ import { useCurrentAccount } from "../../hooks/use-current-account";
import accountService from "../../services/account";
import { ConnectedRelays } from "../connected-relays";
import { ChatIcon, FeedIcon, LogoutIcon, NotificationIcon, ProfileIcon, RelayIcon, SearchIcon } from "../icons";
import { ProfileButton } from "../profile-button";
import ProfileLink from "./profile-link";
import AccountSwitcher from "./account-switcher";
export default function DesktopSideNav() {
@ -19,7 +19,7 @@ export default function DesktopSideNav() {
<Avatar src="/apple-touch-icon.png" size="sm" />
<Heading size="md">noStrudel</Heading>
</Flex>
<ProfileButton />
<ProfileLink />
<AccountSwitcher />
<Button onClick={() => navigate("/")} leftIcon={<FeedIcon />}>
Home
@ -42,10 +42,12 @@ export default function DesktopSideNav() {
<Button onClick={() => navigate("/settings")} leftIcon={<SettingsIcon />}>
Settings
</Button>
<Button onClick={() => accountService.logout()} leftIcon={<LogoutIcon />}>
Logout
</Button>
{account.readonly && (
{account && (
<Button onClick={() => accountService.logout()} leftIcon={<LogoutIcon />}>
Logout
</Button>
)}
{account?.readonly && (
<Text color="red.200" textAlign="center">
Readonly Mode
</Text>

View File

@ -1,9 +1,9 @@
import { Flex, IconButton, useDisclosure } from "@chakra-ui/react";
import { Avatar, Flex, IconButton, useDisclosure } from "@chakra-ui/react";
import { useContext, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useCurrentAccount } from "../../hooks/use-current-account";
import { PostModalContext } from "../../providers/post-modal-provider";
import { ChatIcon, HomeIcon, NotificationIcon, PlusCircleIcon, SearchIcon } from "../icons";
import { ChatIcon, FeedIcon, HomeIcon, NotificationIcon, PlusCircleIcon, SearchIcon } from "../icons";
import { UserAvatar } from "../user-avatar";
import MobileSideDrawer from "./mobile-side-drawer";
@ -19,7 +19,11 @@ export default function MobileBottomNav() {
return (
<>
<Flex flexShrink={0} gap="2" padding="2" alignItems="center">
<UserAvatar pubkey={account.pubkey} size="sm" onClick={onOpen} />
{account ? (
<UserAvatar pubkey={account.pubkey} size="sm" onClick={onOpen} noProxy />
) : (
<Avatar size="sm" src="/apple-touch-icon.png" onClick={onOpen} cursor="pointer" />
)}
<IconButton icon={<HomeIcon />} aria-label="Home" onClick={() => navigate("/")} flexGrow="1" size="md" />
<IconButton
icon={<SearchIcon />}
@ -36,7 +40,7 @@ export default function MobileBottomNav() {
}}
variant="solid"
colorScheme="brand"
isDisabled={account.readonly}
isDisabled={account?.readonly ?? true}
/>
<IconButton icon={<ChatIcon />} aria-label="Messages" onClick={() => navigate(`/dm`)} flexGrow="1" size="md" />
<IconButton

View File

@ -1,4 +1,5 @@
import {
Avatar,
Button,
Drawer,
DrawerBody,
@ -10,32 +11,36 @@ import {
Flex,
Text,
} from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { getUserDisplayName } from "../../helpers/user-metadata";
import { useCurrentAccount } from "../../hooks/use-current-account";
import { useUserMetadata } from "../../hooks/use-user-metadata";
import accountService from "../../services/account";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import { ConnectedRelays } from "../connected-relays";
import { HomeIcon, LogoutIcon, ProfileIcon, RelayIcon, SearchIcon, SettingsIcon } from "../icons";
import { UserAvatar } from "../user-avatar";
import { UserLink } from "../user-link";
import AccountSwitcher from "./account-switcher";
import { useCurrentAccount } from "../../hooks/use-current-account";
import accountService from "../../services/account";
export default function MobileSideDrawer({ ...props }: Omit<DrawerProps, "children">) {
const navigate = useNavigate();
const account = useCurrentAccount();
const metadata = useUserMetadata(account.pubkey);
return (
<Drawer placement="left" {...props}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>
<Flex gap="2">
<UserAvatar pubkey={account.pubkey} size="sm" />
<UserLink pubkey={account.pubkey} />
</Flex>
<DrawerHeader px="4" py="4">
{account ? (
<Flex gap="2">
<UserAvatar pubkey={account.pubkey} size="sm" noProxy />
<UserLink pubkey={account.pubkey} />
</Flex>
) : (
<Flex gap="2">
<Avatar src="/apple-touch-icon.png" size="sm" />
<Text m={0}>Nostrudel</Text>
</Flex>
)}
</DrawerHeader>
<DrawerBody padding={0} overflowY="auto" overflowX="hidden">
<AccountSwitcher />
@ -55,9 +60,15 @@ export default function MobileSideDrawer({ ...props }: Omit<DrawerProps, "childr
<Button onClick={() => navigate("/settings")} leftIcon={<SettingsIcon />}>
Settings
</Button>
<Button onClick={() => accountService.logout()} leftIcon={<LogoutIcon />}>
Logout
</Button>
{account ? (
<Button onClick={() => accountService.logout()} leftIcon={<LogoutIcon />}>
Logout
</Button>
) : (
<Button as={RouterLink} to="/login" colorScheme="brand">
Login
</Button>
)}
<ConnectedRelays />
</Flex>
</DrawerBody>

View File

@ -0,0 +1,40 @@
import { Box, Button, LinkBox, Text } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { UserAvatar } from "../user-avatar";
import { useUserMetadata } from "../../hooks/use-user-metadata";
import { Bech32Prefix, normalizeToBech32 } from "../../helpers/nip19";
import { truncatedId } from "../../helpers/nostr-event";
import { useCurrentAccount } from "../../hooks/use-current-account";
function ProfileButton() {
const account = useCurrentAccount()!;
const metadata = useUserMetadata(account.pubkey);
return (
<LinkBox
as={RouterLink}
to={`/u/${normalizeToBech32(account.pubkey, Bech32Prefix.Pubkey)}`}
display="flex"
gap="2"
overflow="hidden"
>
<UserAvatar pubkey={account.pubkey} noProxy />
<Box>
<Text fontWeight="bold">{metadata?.name}</Text>
<Text>{truncatedId(normalizeToBech32(account.pubkey) ?? "")}</Text>
</Box>
</LinkBox>
);
}
export default function ProfileLink() {
const account = useCurrentAccount();
if (account) return <ProfileButton />;
else
return (
<Button as={RouterLink} to="/login" state={{ from: location.pathname }} colorScheme="brand">
Login
</Button>
);
}

View File

@ -1,28 +0,0 @@
import { Box, LinkBox, Text } from "@chakra-ui/react";
import { Link } from "react-router-dom";
import { UserAvatar } from "./user-avatar";
import { useUserMetadata } from "../hooks/use-user-metadata";
import { Bech32Prefix, normalizeToBech32 } from "../helpers/nip19";
import { truncatedId } from "../helpers/nostr-event";
import { useCurrentAccount } from "../hooks/use-current-account";
export const ProfileButton = () => {
const { pubkey } = useCurrentAccount();
const metadata = useUserMetadata(pubkey);
return (
<LinkBox
as={Link}
to={`/u/${normalizeToBech32(pubkey, Bech32Prefix.Pubkey)}`}
display="flex"
gap="2"
overflow="hidden"
>
<UserAvatar pubkey={pubkey} noProxy />
<Box>
<Text fontWeight="bold">{metadata?.name}</Text>
<Text>{truncatedId(normalizeToBech32(pubkey) ?? "")}</Text>
</Box>
</LinkBox>
);
};

View File

@ -2,8 +2,6 @@ import { Button, ButtonProps } from "@chakra-ui/react";
import { useCurrentAccount } from "../hooks/use-current-account";
import useSubject from "../hooks/use-subject";
import clientFollowingService from "../services/client-following";
import { useAsync } from "react-use";
import { NostrRequest } from "../classes/nostr-request";
import clientRelaysService from "../services/client-relays";
import { useUserContacts } from "../hooks/use-user-contacts";
@ -30,8 +28,14 @@ export const UserFollowButton = ({
};
return (
<Button colorScheme="brand" {...props} isLoading={savingDraft} onClick={toggleFollow} isDisabled={account.readonly}>
{isFollowing ? "Unfollow" : userContacts?.contacts.includes(account.pubkey) ? "Follow Back" : "Follow"}
<Button
colorScheme="brand"
{...props}
isLoading={savingDraft}
onClick={toggleFollow}
isDisabled={account?.readonly ?? true}
>
{isFollowing ? "Unfollow" : account && userContacts?.contacts.includes(account.pubkey) ? "Follow Back" : "Follow"}
</Button>
);
};

View File

@ -2,7 +2,5 @@ import accountService from "../services/account";
import useSubject from "./use-subject";
export function useCurrentAccount() {
const account = useSubject(accountService.current);
if (!account) throw Error("no account");
return account;
return useSubject(accountService.current);
}

View File

@ -0,0 +1,44 @@
import { Link, useLocation } from "react-router-dom";
import useSubject from "../hooks/use-subject";
import accountService from "../services/account";
import { Button, Flex, Heading, Spinner, Text } from "@chakra-ui/react";
import { deleteDatabase } from "../services/db";
import { ExternalLinkIcon } from "../components/icons";
export default function RequireCurrentAccount({ children }: { children: JSX.Element }) {
let location = useLocation();
const loading = useSubject(accountService.loading);
const account = useSubject(accountService.current);
if (loading) {
return (
<Flex alignItems="center" height="100%" gap="4" direction="column">
<Flex gap="4" grow="1" alignItems="center">
<Spinner />
<Text>Loading Accounts</Text>
</Flex>
<Button variant="link" margin="4" onClick={() => deleteDatabase()}>
Stuck loading? clear cache
</Button>
</Flex>
);
}
if (!account)
return (
<Flex direction="column" w="full" h="full" alignItems="center" justifyContent="center" gap="4">
<Heading size="md">You must be logged in to use this view</Heading>
<Button
as={Link}
to="/login"
state={{ from: location.pathname }}
colorScheme="brand"
rightIcon={<ExternalLinkIcon />}
>
Login
</Button>
</Flex>
);
return children;
}

View File

@ -4,7 +4,7 @@ import { AppSettings } from "./user-app-settings";
export type Account = {
pubkey: string;
readonly?: boolean;
readonly: boolean;
relays?: string[];
secKey?: ArrayBuffer;
iv?: Uint8Array;

View File

@ -10,6 +10,14 @@ import signingService from "./signing";
export type RelayDirectory = Record<string, { read: boolean; write: boolean }>;
const DEFAULT_RELAYS = [
{ url: "wss://relay.damus.io", mode: RelayMode.READ },
{ url: "wss://nostr.wine", mode: RelayMode.READ },
{ url: "wss://relay.snort.social", mode: RelayMode.READ },
{ url: "wss://eden.nostr.land", mode: RelayMode.READ },
{ url: "wss://nos.lol", mode: RelayMode.READ },
];
class ClientRelayService {
bootstrapRelays = new Set<string>();
relays = new PersistentSubject<RelayConfig[]>([]);
@ -19,9 +27,10 @@ class ClientRelayService {
constructor() {
let lastSubject: Subject<ParsedUserRelays> | undefined;
accountService.current.subscribe((account) => {
this.relays.next([]);
if (!account) return;
if (!account) {
this.relays.next(DEFAULT_RELAYS);
return;
} else this.relays.next([]);
if (account.relays) {
this.bootstrapRelays.clear();

View File

@ -19,6 +19,7 @@ import { DraftNostrEvent, NostrEvent } from "../../types/nostr-event";
import DecryptPlaceholder from "./decrypt-placeholder";
import { EmbedableContent } from "../../helpers/embeds";
import { embedImages, embedLinks, embedNostrLinks, embedVideos } from "../../components/embed-types";
import RequireCurrentAccount from "../../providers/require-current-account";
function MessageContent({ event, text }: { event: NostrEvent; text: string }) {
let content: EmbedableContent = [text];
@ -33,7 +34,7 @@ function MessageContent({ event, text }: { event: NostrEvent; text: string }) {
}
function Message({ event }: { event: NostrEvent } & Omit<CardProps, "children">) {
const account = useCurrentAccount();
const account = useCurrentAccount()!;
const isOwnMessage = account.pubkey === event.pubkey;
return (
@ -55,7 +56,7 @@ function Message({ event }: { event: NostrEvent } & Omit<CardProps, "children">)
);
}
export default function DirectMessageChatView() {
function DirectMessageChatPage() {
const { key } = useParams();
if (!key) return <Navigate to="/" />;
const pubkey = normalizeToHex(key);
@ -131,3 +132,10 @@ export default function DirectMessageChatView() {
</Flex>
);
}
export default function DirectMessageChatView() {
return (
<RequireCurrentAccount>
<DirectMessageChatPage />
</RequireCurrentAccount>
);
}

View File

@ -25,6 +25,7 @@ import { useUserMetadata } from "../../hooks/use-user-metadata";
import directMessagesService from "../../services/direct-messages";
import { ExternalLinkIcon } from "../../components/icons";
import { useIsMobile } from "../../hooks/use-is-mobile";
import RequireCurrentAccount from "../../providers/require-current-account";
function ContactCard({ pubkey }: { pubkey: string }) {
const subject = useMemo(() => directMessagesService.getUserMessages(pubkey), [pubkey]);
@ -48,7 +49,7 @@ function ContactCard({ pubkey }: { pubkey: string }) {
);
}
function DirectMessagesView() {
function DirectMessagesPage() {
const isMobile = useIsMobile();
const [from, setFrom] = useState(moment().subtract(2, "days"));
const conversations = useSubject(directMessagesService.conversations);
@ -121,4 +122,10 @@ function DirectMessagesView() {
);
}
export default DirectMessagesView;
export default function DirectMessagesView() {
return (
<RequireCurrentAccount>
<DirectMessagesPage />
</RequireCurrentAccount>
);
}

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo } from "react";
import { useMemo } from "react";
import { Button, Flex, Spinner } from "@chakra-ui/react";
import moment from "moment";
import { Note } from "../../components/note";
@ -11,6 +11,7 @@ import userContactsService, { UserContacts } from "../../services/user-contacts"
import { PersistentSubject } from "../../classes/subject";
import useSubject from "../../hooks/use-subject";
import { useThrottle } from "react-use";
import RequireCurrentAccount from "../../providers/require-current-account";
class DiscoverContacts {
pubkey: string;
@ -59,9 +60,9 @@ class DiscoverContacts {
}
}
export default function DiscoverTab() {
function DiscoverTabBody() {
useAppTitle("discover");
const account = useCurrentAccount();
const account = useCurrentAccount()!;
const relays = useReadRelayUrls();
const discover = useMemo(() => new DiscoverContacts(account.pubkey, relays), [account.pubkey, relays.join("|")]);
@ -86,3 +87,11 @@ export default function DiscoverTab() {
</Flex>
);
}
export default function DiscoverTab() {
return (
<RequireCurrentAccount>
<DiscoverTabBody />
</RequireCurrentAccount>
);
}

View File

@ -11,9 +11,10 @@ import { PostModalContext } from "../../providers/post-modal-provider";
import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useCurrentAccount } from "../../hooks/use-current-account";
import RepostNote from "../../components/note/repost-note";
import RequireCurrentAccount from "../../providers/require-current-account";
export default function FollowingTab() {
const account = useCurrentAccount();
function FollowingTabBody() {
const account = useCurrentAccount()!;
const readRelays = useReadRelayUrls();
const { openModal } = useContext(PostModalContext);
const contacts = useUserContacts(account.pubkey, readRelays);
@ -55,3 +56,11 @@ export default function FollowingTab() {
</Flex>
);
}
export default function FollowingTab() {
return (
<RequireCurrentAccount>
<FollowingTabBody />
</RequireCurrentAccount>
);
}

View File

@ -72,7 +72,7 @@ export default function LoginNsecView() {
const pubkey = getPublicKey(hexKey);
const encrypted = await signingService.encryptSecKey(hexKey);
accountService.addAccount({ pubkey, relays: [relayUrl], ...encrypted });
accountService.addAccount({ pubkey, relays: [relayUrl], ...encrypted, readonly: false });
clientRelaysService.bootstrapRelays.add(relayUrl);
accountService.switchAccount(pubkey);
};

View File

@ -42,7 +42,7 @@ export default function LoginStartView() {
relays = ["wss://relay.damus.io", "wss://relay.snort.social", "wss://nostr.wine"];
}
accountService.addAccount({ pubkey, relays, useExtension: true });
accountService.addAccount({ pubkey, relays, useExtension: true, readonly: false });
}
accountService.switchAccount(pubkey);

View File

@ -1,7 +1,6 @@
import { Button, Card, CardBody, CardHeader, Flex, Spinner, Text } from "@chakra-ui/react";
import moment from "moment";
import { memo } from "react";
import { useNavigate } from "react-router-dom";
import { UserAvatar } from "../../components/user-avatar";
import { UserLink } from "../../components/user-link";
import { convertTimestampToDate } from "../../helpers/date";
@ -10,6 +9,7 @@ import { useCurrentAccount } from "../../hooks/use-current-account";
import { useTimelineLoader } from "../../hooks/use-timeline-loader";
import { NostrEvent } from "../../types/nostr-event";
import { NoteLink } from "../../components/note-link";
import RequireCurrentAccount from "../../providers/require-current-account";
const Kind1Notification = ({ event }: { event: NostrEvent }) => (
<Card size="sm" variant="outline">
@ -35,9 +35,9 @@ const NotificationItem = memo(({ event }: { event: NostrEvent }) => {
return <>Unknown event type {event.kind}</>;
});
const NotificationsView = () => {
function NotificationsPage() {
const readRelays = useReadRelayUrls();
const account = useCurrentAccount();
const account = useCurrentAccount()!;
const { events, loading, loadMore } = useTimelineLoader(
"notifications",
readRelays,
@ -60,6 +60,12 @@ const NotificationsView = () => {
{loading ? <Spinner ml="auto" mr="auto" mt="8" mb="8" /> : <Button onClick={() => loadMore()}>Load More</Button>}
</Flex>
);
};
}
export default NotificationsView;
export default function NotificationsView() {
return (
<RequireCurrentAccount>
<NotificationsPage />
</RequireCurrentAccount>
);
}

View File

@ -49,7 +49,7 @@ type MetadataFormProps = {
};
const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
const account = useCurrentAccount();
const account = useCurrentAccount()!;
const isMobile = useIsMobile();
const {
register,
@ -189,7 +189,7 @@ export const ProfileEditView = () => {
const writeRelays = useWriteRelayUrls();
const readRelays = useReadRelayUrls();
const toast = useToast();
const account = useCurrentAccount();
const account = useCurrentAccount()!;
const metadata = useUserMetadata(account.pubkey, readRelays, true);
const defaultValues = useMemo<FormData>(

View File

@ -1,5 +1,10 @@
import RequireCurrentAccount from "../../providers/require-current-account";
import { ProfileEditView } from "./edit";
export default function ProfileView() {
return <ProfileEditView />;
return (
<RequireCurrentAccount>
<ProfileEditView />
</RequireCurrentAccount>
);
}

View File

@ -26,8 +26,9 @@ import useSubject from "../../hooks/use-subject";
import { RelayStatus } from "../../components/relay-status";
import { normalizeRelayUrl } from "../../helpers/url";
import { RelayScoreBreakdown } from "../../components/relay-score-breakdown";
import RequireCurrentAccount from "../../providers/require-current-account";
export default function RelaysView() {
function RelaysPage() {
const relays = useSubject(clientRelaysService.relays);
const toast = useToast();
@ -152,3 +153,11 @@ export default function RelaysView() {
</Flex>
);
}
export default function RelaysView() {
return (
<RequireCurrentAccount>
<RelaysPage />
</RequireCurrentAccount>
);
}

View File

@ -29,7 +29,7 @@ export default function Header({
const npub = normalizeToBech32(pubkey, Bech32Prefix.Pubkey);
const account = useCurrentAccount();
const isSelf = pubkey === account.pubkey;
const isSelf = pubkey === account?.pubkey;
return (
<Flex direction="column" gap="2" px="2" pt="2">