mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-28 18:53:47 +01:00
add DNS Identity settings view
This commit is contained in:
parent
7e388bd214
commit
723668b0fc
@ -6,7 +6,7 @@ import SuperMap from "../classes/super-map";
|
|||||||
|
|
||||||
const parseCache = new SuperMap<string, { name: string; domain: string } | null>(parseNIP05Address);
|
const parseCache = new SuperMap<string, { name: string; domain: string } | null>(parseNIP05Address);
|
||||||
|
|
||||||
export default function useDnsIdentity(address: string | undefined) {
|
export default function useDnsIdentity(address: string | undefined, force = false) {
|
||||||
const parsed = address ? parseCache.get(address) : null;
|
const parsed = address ? parseCache.get(address) : null;
|
||||||
const { value: identity } = useAsync(async () => {
|
const { value: identity } = useAsync(async () => {
|
||||||
if (parsed) return await dnsIdentityLoader.requestIdentity(parsed.name, parsed.domain);
|
if (parsed) return await dnsIdentityLoader.requestIdentity(parsed.name, parsed.domain);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { Button, ButtonGroup, Flex, LinkBox, LinkOverlay, Text } from "@chakra-ui/react";
|
import { Button, ButtonGroup, Flex, LinkBox, LinkOverlay, Text } from "@chakra-ui/react";
|
||||||
import { Link as RouterLink, useLocation } from "react-router-dom";
|
import { Link as RouterLink, useLocation } from "react-router-dom";
|
||||||
import { kinds, nip19 } from "nostr-tools";
|
import { kinds, nip19 } from "nostr-tools";
|
||||||
@ -21,20 +21,11 @@ import { useKind4Decrypt } from "../../hooks/use-kind4-decryption";
|
|||||||
import { truncateId } from "../../helpers/string";
|
import { truncateId } from "../../helpers/string";
|
||||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||||
import useUserMailboxes from "../../hooks/use-user-mailboxes";
|
import useUserMailboxes from "../../hooks/use-user-mailboxes";
|
||||||
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
|
|
||||||
import useUserContacts from "../../hooks/use-user-contacts";
|
import useUserContacts from "../../hooks/use-user-contacts";
|
||||||
import useUserMutes from "../../hooks/use-user-mutes";
|
import useUserMutes from "../../hooks/use-user-mutes";
|
||||||
import SimpleParentView from "../../components/layout/presets/simple-parent-view";
|
import SimpleParentView from "../../components/layout/presets/simple-parent-view";
|
||||||
|
|
||||||
export function useDirectMessagesTimeline(pubkey?: string) {
|
export function useDirectMessagesTimeline(pubkey?: string) {
|
||||||
const userMuteFilter = useClientSideMuteFilter();
|
|
||||||
const eventFilter = useCallback(
|
|
||||||
(event: NostrEvent) => {
|
|
||||||
if (userMuteFilter(event)) return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[userMuteFilter],
|
|
||||||
);
|
|
||||||
const mailboxes = useUserMailboxes(pubkey);
|
const mailboxes = useUserMailboxes(pubkey);
|
||||||
|
|
||||||
return useTimelineLoader(
|
return useTimelineLoader(
|
||||||
@ -46,7 +37,6 @@ export function useDirectMessagesTimeline(pubkey?: string) {
|
|||||||
{ "#p": [pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
{ "#p": [pubkey], kinds: [kinds.EncryptedDirectMessage] },
|
||||||
]
|
]
|
||||||
: undefined,
|
: undefined,
|
||||||
{ eventFilter },
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +105,7 @@ function MessagesHomePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return filtered.sort((a, b) => b.messages[0].created_at - a.messages[0].created_at);
|
return filtered.sort((a, b) => b.messages[0].created_at - a.messages[0].created_at);
|
||||||
}, [messages, account.pubkey, contacts?.length, filter, mutes?.pubkeys]);
|
}, [messages, account.pubkey, contacts?.length, filter, mutes?.pubkeys.size]);
|
||||||
|
|
||||||
const callback = useTimelineCurserIntersectionCallback(loader);
|
const callback = useTimelineCurserIntersectionCallback(loader);
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { useActiveAccount } from "applesauce-react/hooks";
|
import { useActiveAccount } from "applesauce-react/hooks";
|
||||||
|
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
|
||||||
import Database01 from "../../components/icons/database-01";
|
import Database01 from "../../components/icons/database-01";
|
||||||
import { AtIcon, RelayIcon, SearchIcon } from "../../components/icons";
|
import { AtIcon, RelayIcon, SearchIcon } from "../../components/icons";
|
||||||
import Mail02 from "../../components/icons/mail-02";
|
import Mail02 from "../../components/icons/mail-02";
|
||||||
@ -37,7 +39,7 @@ export default function RelaysView() {
|
|||||||
<SimpleNavItem to="/relays/webrtc" leftIcon={<Server05 boxSize={6} />}>
|
<SimpleNavItem to="/relays/webrtc" leftIcon={<Server05 boxSize={6} />}>
|
||||||
WebRTC Relays
|
WebRTC Relays
|
||||||
</SimpleNavItem>
|
</SimpleNavItem>
|
||||||
{nip05?.exists && (
|
{nip05?.status === IdentityStatus.Found && (
|
||||||
<SimpleNavItem to="/relays/nip05" leftIcon={<AtIcon boxSize={6} />}>
|
<SimpleNavItem to="/relays/nip05" leftIcon={<AtIcon boxSize={6} />}>
|
||||||
NIP-05 Relays
|
NIP-05 Relays
|
||||||
</SimpleNavItem>
|
</SimpleNavItem>
|
||||||
|
@ -6,6 +6,7 @@ import { Link as RouterLink } from "react-router-dom";
|
|||||||
|
|
||||||
import RelayFavicon from "../../../components/relay-favicon";
|
import RelayFavicon from "../../../components/relay-favicon";
|
||||||
import SimpleView from "../../../components/layout/presets/simple-view";
|
import SimpleView from "../../../components/layout/presets/simple-view";
|
||||||
|
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
|
||||||
function RelayItem({ url }: { url: string }) {
|
function RelayItem({ url }: { url: string }) {
|
||||||
return (
|
return (
|
||||||
@ -38,7 +39,7 @@ export default function NIP05RelaysView() {
|
|||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{nip05?.relays?.map((url) => <RelayItem key={url} url={url} />)}
|
{nip05?.status === IdentityStatus.Found && nip05?.relays?.map((url) => <RelayItem key={url} url={url} />)}
|
||||||
</SimpleView>
|
</SimpleView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
33
src/views/settings/dns-identity/identity-warning.tsx
Normal file
33
src/views/settings/dns-identity/identity-warning.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Link, Text } from "@chakra-ui/react";
|
||||||
|
import { Identity, IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
import { ExternalLinkIcon } from "../../../components/icons";
|
||||||
|
|
||||||
|
export default function DNSIdentityWarning({ identity, pubkey }: { pubkey: string; identity: Identity }) {
|
||||||
|
switch (identity?.status) {
|
||||||
|
case IdentityStatus.Missing:
|
||||||
|
return <Text color="red.500">Unable to find DNS Identity in nostr.json file</Text>;
|
||||||
|
case IdentityStatus.Error:
|
||||||
|
return (
|
||||||
|
<Text color="yellow.500">
|
||||||
|
Unable to check DNS identity due to CORS error{" "}
|
||||||
|
<Link
|
||||||
|
color="blue.500"
|
||||||
|
href={`https://cors-test.codehappy.dev/?url=${encodeURIComponent(`https://${identity.domain}/.well-known/nostr.json?name=${identity.name}`)}&method=get`}
|
||||||
|
isExternal
|
||||||
|
>
|
||||||
|
Test
|
||||||
|
<ExternalLinkIcon ml="1" />
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
case IdentityStatus.Found:
|
||||||
|
if (identity.pubkey !== pubkey)
|
||||||
|
return (
|
||||||
|
<Text color="red.500" fontWeight="bold">
|
||||||
|
Invalid DNS Identity!
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
170
src/views/settings/dns-identity/index.tsx
Normal file
170
src/views/settings/dns-identity/index.tsx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import {
|
||||||
|
ButtonGroup,
|
||||||
|
Editable,
|
||||||
|
EditableInput,
|
||||||
|
EditablePreview,
|
||||||
|
EditableProps,
|
||||||
|
Heading,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Link,
|
||||||
|
Spinner,
|
||||||
|
Text,
|
||||||
|
useEditableControls,
|
||||||
|
useToast,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { getProfileContent, mergeRelaySets, parseNIP05Address, ProfileContent } from "applesauce-core/helpers";
|
||||||
|
import { CheckIcon, CloseIcon, EditIcon } from "@chakra-ui/icons";
|
||||||
|
import { kinds } from "nostr-tools";
|
||||||
|
import { setContent } from "applesauce-factory/operations";
|
||||||
|
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
import { useAsync } from "react-use";
|
||||||
|
|
||||||
|
import SimpleView from "../../../components/layout/presets/simple-view";
|
||||||
|
import { useActiveAccount, useEventFactory, useEventStore } from "applesauce-react/hooks";
|
||||||
|
import useUserProfile from "../../../hooks/use-user-profile";
|
||||||
|
import dnsIdentityLoader from "../../../services/dns-identity-loader";
|
||||||
|
import WikiLink from "../../../components/markdown/wiki-link";
|
||||||
|
import RawValue from "../../../components/debug-modal/raw-value";
|
||||||
|
import { ExternalLinkIcon } from "../../../components/icons";
|
||||||
|
import useUserMailboxes from "../../../hooks/use-user-mailboxes";
|
||||||
|
import { useWriteRelays } from "../../../hooks/use-client-relays";
|
||||||
|
import { COMMON_CONTACT_RELAYS } from "../../../const";
|
||||||
|
import { usePublishEvent } from "../../../providers/global/publish-provider";
|
||||||
|
|
||||||
|
function EditableControls() {
|
||||||
|
const { isEditing, getSubmitButtonProps, getCancelButtonProps, getEditButtonProps } = useEditableControls();
|
||||||
|
|
||||||
|
return isEditing ? (
|
||||||
|
<ButtonGroup justifyContent="center" size="sm">
|
||||||
|
<IconButton icon={<CheckIcon />} {...getSubmitButtonProps()} aria-label="save" />
|
||||||
|
<IconButton icon={<CloseIcon />} {...getCancelButtonProps()} aria-label="Cancel" />
|
||||||
|
</ButtonGroup>
|
||||||
|
) : (
|
||||||
|
<IconButton size="sm" icon={<EditIcon />} {...getEditButtonProps()} aria-label="Edit" />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditableIdentity() {
|
||||||
|
const factory = useEventFactory();
|
||||||
|
const eventStore = useEventStore();
|
||||||
|
const account = useActiveAccount();
|
||||||
|
const toast = useToast();
|
||||||
|
const publish = usePublishEvent();
|
||||||
|
|
||||||
|
const profile = useUserProfile(account?.pubkey);
|
||||||
|
const mailboxes = useUserMailboxes();
|
||||||
|
const publishRelays = useWriteRelays();
|
||||||
|
|
||||||
|
const onSubmit: EditableProps["onSubmit"] = async (value) => {
|
||||||
|
if (!account) return;
|
||||||
|
try {
|
||||||
|
const metadata = eventStore.getReplaceable(kinds.Metadata, account.pubkey);
|
||||||
|
if (!metadata) throw new Error("Failed to find profile");
|
||||||
|
|
||||||
|
const profile = getProfileContent(metadata);
|
||||||
|
const newProfile = { ...profile, nip05: value };
|
||||||
|
const draft = await factory.modify(metadata, setContent(JSON.stringify(newProfile)));
|
||||||
|
const signed = await account.signEvent(draft);
|
||||||
|
|
||||||
|
await publish("Update NIP-05", signed, mergeRelaySets(publishRelays, mailboxes?.outboxes, COMMON_CONTACT_RELAYS));
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) toast({ status: "error", description: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Editable
|
||||||
|
alignItems="center"
|
||||||
|
defaultValue={profile?.nip05}
|
||||||
|
fontSize="2xl"
|
||||||
|
isPreviewFocusable={false}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
>
|
||||||
|
<EditablePreview mr="2" />
|
||||||
|
{/* Here is the custom input */}
|
||||||
|
<Input as={EditableInput} w="xs" mr="2" />
|
||||||
|
<EditableControls />
|
||||||
|
</Editable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function IdentityDetails({ pubkey, profile }: { pubkey: string; profile: ProfileContent }) {
|
||||||
|
const { value: identity, loading } = useAsync(async () => {
|
||||||
|
if (!profile?.nip05) return null;
|
||||||
|
const parsed = parseNIP05Address(profile.nip05);
|
||||||
|
if (!parsed) return null;
|
||||||
|
return await dnsIdentityLoader.fetchIdentity(parsed.name, parsed.domain);
|
||||||
|
}, [profile?.nip05]);
|
||||||
|
|
||||||
|
const renderDetails = () => {
|
||||||
|
if (!identity) return null;
|
||||||
|
|
||||||
|
switch (identity.status) {
|
||||||
|
case IdentityStatus.Missing:
|
||||||
|
return <Text color="red.500">Unable to find DNS Identity in nostr.json file</Text>;
|
||||||
|
case IdentityStatus.Error:
|
||||||
|
return (
|
||||||
|
<Text color="yellow.500">
|
||||||
|
Unable to check DNS identity due to CORS error{" "}
|
||||||
|
<Link
|
||||||
|
color="blue.500"
|
||||||
|
href={`https://cors-test.codehappy.dev/?url=${encodeURIComponent(`https://${identity.domain}/.well-known/nostr.json?name=${identity.name}`)}&method=get`}
|
||||||
|
isExternal
|
||||||
|
>
|
||||||
|
Test
|
||||||
|
<ExternalLinkIcon ml="1" />
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
case IdentityStatus.Found:
|
||||||
|
if (identity.pubkey !== pubkey)
|
||||||
|
return (
|
||||||
|
<Text color="red.500" fontWeight="bold">
|
||||||
|
Invalid DNS Identity! <CloseIcon />
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
else
|
||||||
|
return (
|
||||||
|
<Text color="green.500" fontWeight="bold">
|
||||||
|
DNS identity matches pubkey <CheckIcon />
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditableIdentity />
|
||||||
|
{renderDetails()}
|
||||||
|
{loading && <Spinner />}
|
||||||
|
<RawValue heading="Your pubkey" value={pubkey} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DnsIdentityView() {
|
||||||
|
const account = useActiveAccount();
|
||||||
|
if (!account) return <Navigate to="/" />;
|
||||||
|
|
||||||
|
const profile = useUserProfile(account.pubkey, undefined, true);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SimpleView title="DNS Identity">
|
||||||
|
{profile?.nip05 ? (
|
||||||
|
<IdentityDetails pubkey={account.pubkey} profile={profile} />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Heading>No DNS identity setup</Heading>
|
||||||
|
<RawValue heading="Your pubkey" value={account.pubkey} />
|
||||||
|
<Text>
|
||||||
|
or read the details on the wiki: <WikiLink topic="nip-05">NIP-05</WikiLink>
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</SimpleView>
|
||||||
|
);
|
||||||
|
}
|
@ -10,6 +10,7 @@ import {
|
|||||||
RelayIcon,
|
RelayIcon,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
SpyIcon,
|
SpyIcon,
|
||||||
|
VerifiedIcon,
|
||||||
} from "../../components/icons";
|
} from "../../components/icons";
|
||||||
import { useActiveAccount } from "applesauce-react/hooks";
|
import { useActiveAccount } from "applesauce-react/hooks";
|
||||||
import Image01 from "../../components/icons/image-01";
|
import Image01 from "../../components/icons/image-01";
|
||||||
@ -56,6 +57,9 @@ export default function SettingsView() {
|
|||||||
<SimpleNavItem to="/settings/search-relays" leftIcon={<SearchIcon boxSize={6} />}>
|
<SimpleNavItem to="/settings/search-relays" leftIcon={<SearchIcon boxSize={6} />}>
|
||||||
Search
|
Search
|
||||||
</SimpleNavItem>
|
</SimpleNavItem>
|
||||||
|
<SimpleNavItem to="/settings/identity" leftIcon={<VerifiedIcon boxSize={6} />}>
|
||||||
|
DNS Identity
|
||||||
|
</SimpleNavItem>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { MouseEventHandler, useCallback, useMemo } from "react";
|
import { MouseEventHandler, useCallback, useMemo } from "react";
|
||||||
import { Button, Card, CardBody, CardHeader, Flex, Heading, SimpleGrid, Text } from "@chakra-ui/react";
|
import { Button, Card, CardBody, CardHeader, Flex, Heading, SimpleGrid, Text } from "@chakra-ui/react";
|
||||||
import { WarningIcon } from "@chakra-ui/icons";
|
import { WarningIcon } from "@chakra-ui/icons";
|
||||||
|
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
import { mergeRelaySets } from "applesauce-core/helpers";
|
||||||
|
|
||||||
import { RECOMMENDED_READ_RELAYS, RECOMMENDED_WRITE_RELAYS } from "../../../const";
|
import { RECOMMENDED_READ_RELAYS, RECOMMENDED_WRITE_RELAYS } from "../../../const";
|
||||||
import AddRelayForm from "./add-relay-form";
|
import AddRelayForm from "./add-relay-form";
|
||||||
@ -10,7 +12,7 @@ import RelayControl from "./relay-control";
|
|||||||
import { getRelaysFromExt } from "../../../helpers/nip07";
|
import { getRelaysFromExt } from "../../../helpers/nip07";
|
||||||
import { useUserDNSIdentity } from "../../../hooks/use-user-dns-identity";
|
import { useUserDNSIdentity } from "../../../hooks/use-user-dns-identity";
|
||||||
import useUserContactRelays from "../../../hooks/use-user-contact-relays";
|
import useUserContactRelays from "../../../hooks/use-user-contact-relays";
|
||||||
import { mergeRelaySets, safeRelayUrls } from "../../../helpers/relay";
|
import { safeRelayUrls } from "../../../helpers/relay";
|
||||||
import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
||||||
import SimpleView from "../../../components/layout/presets/simple-view";
|
import SimpleView from "../../../components/layout/presets/simple-view";
|
||||||
import localSettings from "../../../services/local-settings";
|
import localSettings from "../../../services/local-settings";
|
||||||
@ -108,7 +110,7 @@ export default function AppRelaysView() {
|
|||||||
NIP-65 (Mailboxes)
|
NIP-65 (Mailboxes)
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{nip05?.relays && (
|
{nip05?.status === IdentityStatus.Found && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!nip05.relays) return;
|
if (!nip05.relays) return;
|
||||||
|
@ -15,6 +15,7 @@ import PrivacySettings from "./privacy";
|
|||||||
import LightningSettings from "./lightning";
|
import LightningSettings from "./lightning";
|
||||||
import PerformanceSettings from "./performance";
|
import PerformanceSettings from "./performance";
|
||||||
import AuthenticationSettingsView from "./authentication";
|
import AuthenticationSettingsView from "./authentication";
|
||||||
|
import DnsIdentityView from "./dns-identity";
|
||||||
|
|
||||||
// bakery settings
|
// bakery settings
|
||||||
const BakeryConnectView = lazy(() => import("./bakery/connect"));
|
const BakeryConnectView = lazy(() => import("./bakery/connect"));
|
||||||
@ -41,6 +42,7 @@ export default [
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{ path: "mailboxes", Component: MailboxesView },
|
{ path: "mailboxes", Component: MailboxesView },
|
||||||
|
{ path: "identity", Component: DnsIdentityView },
|
||||||
{ path: "authentication", Component: AuthenticationSettingsView },
|
{ path: "authentication", Component: AuthenticationSettingsView },
|
||||||
{ path: "media-servers", Component: MediaServersView },
|
{ path: "media-servers", Component: MediaServersView },
|
||||||
{ path: "search-relays", Component: SearchRelaysView },
|
{ path: "search-relays", Component: SearchRelaysView },
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
import { ChatIcon } from "@chakra-ui/icons";
|
import { ChatIcon } from "@chakra-ui/icons";
|
||||||
import { parseLNURLOrAddress, parseNIP05Address } from "applesauce-core/helpers";
|
import { parseLNURLOrAddress, parseNIP05Address } from "applesauce-core/helpers";
|
||||||
|
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
||||||
|
|
||||||
import { truncatedId } from "../../../helpers/nostr/event";
|
import { truncatedId } from "../../../helpers/nostr/event";
|
||||||
import { useAdditionalRelayContext } from "../../../providers/local/additional-relay-context";
|
import { useAdditionalRelayContext } from "../../../providers/local/additional-relay-context";
|
||||||
@ -51,45 +52,7 @@ import UserAboutContent from "../../../components/user/user-about-content";
|
|||||||
import UserRecentEvents from "./user-recent-events";
|
import UserRecentEvents from "./user-recent-events";
|
||||||
import { useUserAppSettings } from "../../../hooks/use-user-app-settings";
|
import { useUserAppSettings } from "../../../hooks/use-user-app-settings";
|
||||||
import UserJoinedGroups from "./user-joined-groups";
|
import UserJoinedGroups from "./user-joined-groups";
|
||||||
import { IdentityStatus } from "applesauce-loaders/helpers/dns-identity";
|
import DNSIdentityWarning from "../../settings/dns-identity/identity-warning";
|
||||||
|
|
||||||
function DNSIdentityWarning({ pubkey }: { pubkey: string }) {
|
|
||||||
const metadata = useUserProfile(pubkey);
|
|
||||||
const identity = useUserDNSIdentity(pubkey);
|
|
||||||
const parsed = metadata?.nip05 ? parseNIP05Address(metadata.nip05) : undefined;
|
|
||||||
|
|
||||||
const nip05URL = parsed ? `https://${parsed.domain}/.well-known/nostr.json?name=${parsed.name}` : undefined;
|
|
||||||
|
|
||||||
switch (identity?.status) {
|
|
||||||
case IdentityStatus.Missing:
|
|
||||||
return <Text color="red.500">Unable to find DNS Identity in nostr.json file</Text>;
|
|
||||||
case IdentityStatus.Error:
|
|
||||||
return (
|
|
||||||
<Text color="yellow.500">
|
|
||||||
Unable to check DNS identity due to CORS error{" "}
|
|
||||||
{nip05URL && (
|
|
||||||
<Link
|
|
||||||
color="blue.500"
|
|
||||||
href={`https://cors-test.codehappy.dev/?url=${encodeURIComponent(nip05URL)}&method=get`}
|
|
||||||
isExternal
|
|
||||||
>
|
|
||||||
Test
|
|
||||||
<ExternalLinkIcon ml="1" />
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
case IdentityStatus.Found:
|
|
||||||
if (identity.pubkey !== pubkey)
|
|
||||||
return (
|
|
||||||
<Text color="red.500" fontWeight="bold">
|
|
||||||
Invalid DNS Identity!
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UserAboutTab() {
|
export default function UserAboutTab() {
|
||||||
const expanded = useDisclosure();
|
const expanded = useDisclosure();
|
||||||
@ -108,6 +71,8 @@ export default function UserAboutTab() {
|
|||||||
? `https://${parsedNip05.domain}/.well-known/nostr.json?name=${parsedNip05.name}`
|
? `https://${parsedNip05.domain}/.well-known/nostr.json?name=${parsedNip05.name}`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const identity = useUserDNSIdentity(pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
overflowY="auto"
|
overflowY="auto"
|
||||||
@ -202,7 +167,7 @@ export default function UserAboutTab() {
|
|||||||
<UserDnsIdentity pubkey={pubkey} />
|
<UserDnsIdentity pubkey={pubkey} />
|
||||||
</Link>
|
</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
<DNSIdentityWarning pubkey={pubkey} />
|
{identity && <DNSIdentityWarning identity={identity} pubkey={pubkey} />}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{metadata?.website && (
|
{metadata?.website && (
|
||||||
|
@ -12,6 +12,7 @@ import { EditIcon } from "../../../components/icons";
|
|||||||
import { getPageTopic } from "../../../helpers/nostr/wiki";
|
import { getPageTopic } from "../../../helpers/nostr/wiki";
|
||||||
import GitBranch02 from "../../../components/icons/git-branch-02";
|
import GitBranch02 from "../../../components/icons/git-branch-02";
|
||||||
import useShareableEventAddress from "../../../hooks/use-shareable-event-address";
|
import useShareableEventAddress from "../../../hooks/use-shareable-event-address";
|
||||||
|
import DeleteEventMenuItem from "../../../components/common-menu-items/delete-event";
|
||||||
|
|
||||||
export default function WikiPageMenu({ page, ...props }: { page: NostrEvent } & Omit<MenuIconButtonProps, "children">) {
|
export default function WikiPageMenu({ page, ...props }: { page: NostrEvent } & Omit<MenuIconButtonProps, "children">) {
|
||||||
const account = useActiveAccount();
|
const account = useActiveAccount();
|
||||||
@ -32,6 +33,8 @@ export default function WikiPageMenu({ page, ...props }: { page: NostrEvent } &
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<DeleteEventMenuItem event={page} label="Delete Page" />
|
||||||
|
|
||||||
<ShareLinkMenuItem event={page} />
|
<ShareLinkMenuItem event={page} />
|
||||||
<CopyEmbedCodeMenuItem event={page} />
|
<CopyEmbedCodeMenuItem event={page} />
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user