feat: add new account management
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"dependencies": {
|
||||
"@getalby/sdk": "^3.2.3",
|
||||
"@lume/icons": "workspace:^",
|
||||
"@lume/storage": "workspace:^",
|
||||
"@lume/utils": "workspace:^",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
|
||||
@@ -4,8 +4,8 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
export class Ark {
|
||||
public account: CurrentAccount;
|
||||
|
||||
constructor(account: CurrentAccount) {
|
||||
this.account = account;
|
||||
constructor() {
|
||||
this.account = null;
|
||||
}
|
||||
|
||||
public async event_to_bech32(id: string, relays: string[]) {
|
||||
@@ -67,12 +67,12 @@ export class Ark {
|
||||
};
|
||||
}
|
||||
|
||||
public async get_metadata(id: string) {
|
||||
public async get_profile(id: string) {
|
||||
try {
|
||||
const cmd: Metadata = await invoke("get_metadata", { id });
|
||||
const cmd: Metadata = await invoke("get_profile", { id });
|
||||
return cmd;
|
||||
} catch (e) {
|
||||
console.error("failed to get metadata", id);
|
||||
console.error("failed to get profile", id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { cn, editorAtom, editorValueAtom } from "@lume/utils";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import * as Tooltip from "@radix-ui/react-tooltip";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
@@ -31,7 +31,7 @@ export function UserAbout({ className }: { className?: string }) {
|
||||
|
||||
return (
|
||||
<div className={cn("select-text break-p", className)}>
|
||||
{user.about?.trim() || user.bio?.trim() || "No bio"}
|
||||
{user.profile.about?.trim() || "No bio"}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function UserAvatar({ className }: { className?: string }) {
|
||||
/>
|
||||
) : (
|
||||
<Avatar.Image
|
||||
src={user.image}
|
||||
src={user.profile.picture}
|
||||
alt={user.pubkey}
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
|
||||
@@ -15,7 +15,7 @@ export function UserCover({ className }: { className?: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
if (user && !user.banner) {
|
||||
if (user && !user.profile.banner) {
|
||||
return (
|
||||
<div
|
||||
className={cn("bg-gradient-to-b from-sky-400 to-sky-200", className)}
|
||||
@@ -25,7 +25,7 @@ export function UserCover({ className }: { className?: string }) {
|
||||
|
||||
return (
|
||||
<img
|
||||
src={user.banner}
|
||||
src={user.profile.banner}
|
||||
alt="banner"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
|
||||
@@ -17,7 +17,7 @@ export function UserName({ className }: { className?: string }) {
|
||||
|
||||
return (
|
||||
<div className={cn("max-w-[12rem] truncate", className)}>
|
||||
{user.displayName || user.name || "Anon"}
|
||||
{user.profile.display_name || user.profile.name || "Anon"}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
import { VerifiedIcon } from "@lume/icons";
|
||||
import { cn, displayNpub } from "@lume/utils";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useArk } from "../../hooks/useArk";
|
||||
import { useUserContext } from "./provider";
|
||||
|
||||
export function UserNip05({
|
||||
pubkey,
|
||||
className,
|
||||
}: { pubkey: string; className?: string }) {
|
||||
const ark = useArk();
|
||||
export function UserNip05({ className }: { className?: string }) {
|
||||
const user = useUserContext();
|
||||
|
||||
const { isLoading, data: verified } = useQuery({
|
||||
queryKey: ["nip05", user?.nip05],
|
||||
queryKey: ["nip05", user?.profile.nip05],
|
||||
queryFn: async ({ signal }: { signal: AbortSignal }) => {
|
||||
if (!user) return false;
|
||||
if (!user.nip05) return false;
|
||||
return ark.validateNIP05({
|
||||
pubkey,
|
||||
nip05: user.nip05,
|
||||
signal,
|
||||
});
|
||||
if (!user.profile.nip05) return false;
|
||||
return false;
|
||||
},
|
||||
enabled: !!user,
|
||||
});
|
||||
@@ -39,11 +30,11 @@ export function UserNip05({
|
||||
return (
|
||||
<div className="inline-flex items-center gap-1">
|
||||
<p className={cn("text-sm", className)}>
|
||||
{!user?.nip05
|
||||
? displayNpub(pubkey, 16)
|
||||
: user?.nip05?.startsWith("_@")
|
||||
? user?.nip05?.replace("_@", "")
|
||||
: user?.nip05}
|
||||
{!user?.profile.nip05
|
||||
? displayNpub(user.pubkey, 16)
|
||||
: user?.profile.nip05?.startsWith("_@")
|
||||
? user?.profile.nip05?.replace("_@", "")
|
||||
: user?.profile.nip05}
|
||||
</p>
|
||||
{!isLoading && verified ? (
|
||||
<VerifiedIcon className="size-4 text-teal-500" />
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { ReactNode, createContext, useContext } from "react";
|
||||
import { useArk } from "../../hooks/useArk";
|
||||
|
||||
const UserContext = createContext<Metadata>(null);
|
||||
const UserContext = createContext<{ pubkey: string; profile: Metadata }>(null);
|
||||
|
||||
export function UserProvider({
|
||||
pubkey,
|
||||
@@ -11,12 +11,12 @@ export function UserProvider({
|
||||
embed,
|
||||
}: { pubkey: string; children: ReactNode; embed?: string }) {
|
||||
const ark = useArk();
|
||||
const { data: user } = useQuery({
|
||||
const { data: profile } = useQuery({
|
||||
queryKey: ["user", pubkey],
|
||||
queryFn: async () => {
|
||||
if (embed) return JSON.parse(embed) as Metadata;
|
||||
|
||||
const profile = await ark.get_metadata(pubkey);
|
||||
const profile = await ark.get_profile(pubkey);
|
||||
|
||||
if (!profile)
|
||||
throw new Error(
|
||||
@@ -32,7 +32,11 @@ export function UserProvider({
|
||||
retry: 2,
|
||||
});
|
||||
|
||||
return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
|
||||
return (
|
||||
<UserContext.Provider value={{ pubkey, profile }}>
|
||||
{children}
|
||||
</UserContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useUserContext() {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { createContext } from "react";
|
||||
import { type Ark } from "./ark";
|
||||
|
||||
export const LumeContext = createContext<Ark>(undefined);
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useContext } from "react";
|
||||
import { LumeContext } from "../context";
|
||||
import { ArkContext } from "../provider";
|
||||
|
||||
export const useArk = () => {
|
||||
const context = useContext(LumeContext);
|
||||
const context = useContext(ArkContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("Please import Ark Provider to use useArk() hook");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useArk } from "./useArk";
|
||||
|
||||
export function useProfile(pubkey: string) {
|
||||
@@ -10,7 +10,7 @@ export function useProfile(pubkey: string) {
|
||||
} = useQuery({
|
||||
queryKey: ["user", pubkey],
|
||||
queryFn: async () => {
|
||||
const profile = await ark.get_metadata(pubkey);
|
||||
const profile = await ark.get_profile(pubkey);
|
||||
if (!profile)
|
||||
throw new Error(
|
||||
`Cannot get metadata for ${pubkey}, will be retry after 10 seconds`,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { NDKKind, NDKTag } from "@nostr-dev-kit/ndk";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { normalizeRelayUrl } from "nostr-fetch";
|
||||
import { useArk } from "./useArk";
|
||||
|
||||
export function useRelaylist() {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from "./ark";
|
||||
export * from "./context";
|
||||
export * from "./provider";
|
||||
export * from "./hooks/useEvent";
|
||||
export * from "./hooks/useArk";
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import { PropsWithChildren, useEffect, useState } from "react";
|
||||
import { PropsWithChildren, createContext, useMemo } from "react";
|
||||
import { Ark } from "./ark";
|
||||
import { LumeContext } from "./context";
|
||||
|
||||
export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
|
||||
const [ark, setArk] = useState<Ark>(undefined);
|
||||
export const ArkContext = createContext<Ark>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
async function setupArk() {
|
||||
const _ark = new Ark();
|
||||
setArk(_ark);
|
||||
}
|
||||
|
||||
if (!ark) setupArk();
|
||||
}, []);
|
||||
|
||||
return <LumeContext.Provider value={ark}>{children}</LumeContext.Provider>;
|
||||
export const ArkProvider = ({ children }: PropsWithChildren<object>) => {
|
||||
const ark = useMemo(() => new Ark(), []);
|
||||
return <ArkContext.Provider value={ark}>{children}</ArkContext.Provider>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user