mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 19:46:34 +00:00
fix errors
This commit is contained in:
parent
332dbf608d
commit
8a92813211
@ -3,40 +3,42 @@ import { DEFAULT_AVATAR } from "@stores/constants";
|
|||||||
import { useProfile } from "@utils/hooks/useProfile";
|
import { useProfile } from "@utils/hooks/useProfile";
|
||||||
import { shortenKey } from "@utils/shortenKey";
|
import { shortenKey } from "@utils/shortenKey";
|
||||||
|
|
||||||
export function User({ pubkey }: { pubkey: string }) {
|
export function User({
|
||||||
const { status, user } = useProfile(pubkey);
|
pubkey,
|
||||||
|
fallback,
|
||||||
|
}: { pubkey: string; fallback?: string }) {
|
||||||
|
const { status, user } = useProfile(pubkey, fallback);
|
||||||
|
|
||||||
|
if (status === "loading") {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative h-10 w-10 shrink-0 rounded-md bg-zinc-800 animate-pulse" />
|
||||||
|
<div className="flex w-full flex-1 flex-col items-start gap-1 text-start">
|
||||||
|
<span className="w-1/2 h-4 rounded bg-zinc-800 animate-pulse" />
|
||||||
|
<span className="w-1/3 h-3 rounded bg-zinc-800 animate-pulse" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{status === "loading" ? (
|
<div className="relative h-10 w-10 shrink rounded-md">
|
||||||
<>
|
<Image
|
||||||
<div className="relative h-11 w-11 shrink-0 rounded-md bg-zinc-800 animate-pulse" />
|
src={user.picture || user.image}
|
||||||
<div className="flex w-full flex-1 flex-col items-start gap-1 text-start">
|
fallback={DEFAULT_AVATAR}
|
||||||
<span className="w-1/2 h-4 rounded bg-zinc-800 animate-pulse" />
|
alt={pubkey}
|
||||||
<span className="w-1/3 h-3 rounded bg-zinc-800 animate-pulse" />
|
className="h-10 w-10 rounded-md object-cover"
|
||||||
</div>
|
/>
|
||||||
</>
|
</div>
|
||||||
) : (
|
<div className="flex w-full flex-1 flex-col items-start text-start">
|
||||||
<>
|
<span className="truncate font-medium leading-tight text-zinc-100">
|
||||||
<div className="relative h-11 w-11 shrink rounded-md">
|
{user.name || user.displayName || user.display_name}
|
||||||
<Image
|
</span>
|
||||||
src={user.image}
|
<span className="text-base leading-tight text-zinc-400">
|
||||||
fallback={DEFAULT_AVATAR}
|
{user.nip05?.toLowerCase() || shortenKey(pubkey)}
|
||||||
alt={pubkey}
|
</span>
|
||||||
className="h-11 w-11 rounded-md object-cover"
|
</div>
|
||||||
decoding="async"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full flex-1 flex-col items-start text-start">
|
|
||||||
<span className="truncate font-medium leading-tight text-zinc-100">
|
|
||||||
{user.displayName || user.name}
|
|
||||||
</span>
|
|
||||||
<span className="text-base leading-tight text-zinc-400">
|
|
||||||
{user.nip05?.toLowerCase() || shortenKey(pubkey)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { AvatarUploader } from "@shared/avatarUploader";
|
import { AvatarUploader } from "@shared/avatarUploader";
|
||||||
|
import { BannerUploader } from "@shared/bannerUploader";
|
||||||
import { LoaderIcon } from "@shared/icons";
|
import { LoaderIcon } from "@shared/icons";
|
||||||
import { Image } from "@shared/image";
|
import { Image } from "@shared/image";
|
||||||
import { DEFAULT_AVATAR } from "@stores/constants";
|
import { DEFAULT_AVATAR } from "@stores/constants";
|
||||||
import { useOnboarding } from "@stores/onboarding";
|
import { useOnboarding } from "@stores/onboarding";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
@ -11,32 +12,36 @@ export function CreateStep2Screen() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const createProfile = useOnboarding((state: any) => state.createProfile);
|
const createProfile = useOnboarding((state: any) => state.createProfile);
|
||||||
|
|
||||||
const [image, setImage] = useState(DEFAULT_AVATAR);
|
const [picture, setPicture] = useState(DEFAULT_AVATAR);
|
||||||
|
const [banner, setBanner] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
setValue,
|
|
||||||
formState: { isDirty, isValid },
|
formState: { isDirty, isValid },
|
||||||
} = useForm();
|
} = useForm();
|
||||||
|
|
||||||
const onSubmit = (data: any) => {
|
const onSubmit = (data: any) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const profile = { ...data, name: data.displayName };
|
const profile = {
|
||||||
|
...data,
|
||||||
|
username: data.name,
|
||||||
|
display_name: data.name,
|
||||||
|
bio: data.about,
|
||||||
|
};
|
||||||
createProfile(profile);
|
createProfile(profile);
|
||||||
// redirect to step 3
|
// redirect to next step
|
||||||
navigate("/auth/create/step-3");
|
setTimeout(
|
||||||
|
() => navigate("/auth/create/step-3", { replace: true }),
|
||||||
|
1200,
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
console.log("error");
|
console.log("error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setValue("picture", image);
|
|
||||||
}, [setValue, image]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-md">
|
<div className="mx-auto w-full max-w-md">
|
||||||
<div className="mb-8 text-center">
|
<div className="mb-8 text-center">
|
||||||
@ -44,55 +49,84 @@ export function CreateStep2Screen() {
|
|||||||
Create your profile
|
Create your profile
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900 p-5">
|
<div className="w-full rounded-xl border-t border-zinc-800/50 bg-zinc-900 overflow-hidden">
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4">
|
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col mb-0">
|
||||||
<input
|
<input
|
||||||
type={"hidden"}
|
type={"hidden"}
|
||||||
{...register("picture")}
|
{...register("picture")}
|
||||||
value={image}
|
value={picture}
|
||||||
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col gap-1">
|
<input
|
||||||
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
type={"hidden"}
|
||||||
Avatar
|
{...register("banner")}
|
||||||
</label>
|
value={banner}
|
||||||
<div className="relative inline-flex h-36 w-full items-center justify-center overflow-hidden rounded-lg border border-zinc-900 bg-zinc-950">
|
className="relative h-10 w-full rounded-lg border border-black/5 px-3 py-2 shadow-input shadow-black/5 !outline-none placeholder:text-zinc-400 dark:bg-zinc-800 dark:text-zinc-100 dark:shadow-black/10 dark:placeholder:text-zinc-500"
|
||||||
|
/>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="relative w-full h-44 bg-zinc-800">
|
||||||
<Image
|
<Image
|
||||||
src={image}
|
src={banner}
|
||||||
fallback={DEFAULT_AVATAR}
|
fallback="https://void.cat/d/QY1myro5tkHVs2nY7dy74b.jpg"
|
||||||
alt="avatar"
|
alt="user's banner"
|
||||||
className="relative z-10 h-11 w-11 rounded-md"
|
className="h-full w-full object-cover"
|
||||||
/>
|
/>
|
||||||
<div className="absolute bottom-3 right-3 z-10">
|
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10 w-full h-full">
|
||||||
<AvatarUploader valueState={setImage} />
|
<BannerUploader setBanner={setBanner} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="px-4 mb-5">
|
||||||
|
<div className="z-10 relative h-14 w-14 -mt-7">
|
||||||
|
<Image
|
||||||
|
src={picture}
|
||||||
|
fallback={DEFAULT_AVATAR}
|
||||||
|
alt="user's avatar"
|
||||||
|
className="h-14 w-14 object-cover ring-2 ring-zinc-900 rounded-lg"
|
||||||
|
/>
|
||||||
|
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10 w-full h-full">
|
||||||
|
<AvatarUploader setPicture={setPicture} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-4 px-4 pb-4">
|
||||||
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
<div className="flex flex-col gap-1">
|
||||||
Display Name *
|
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
||||||
</label>
|
Name *
|
||||||
<input
|
</label>
|
||||||
type={"text"}
|
<input
|
||||||
{...register("displayName", {
|
type={"text"}
|
||||||
required: true,
|
{...register("name", {
|
||||||
minLength: 4,
|
required: true,
|
||||||
})}
|
minLength: 4,
|
||||||
spellCheck={false}
|
})}
|
||||||
className="relative h-10 w-full rounded-lg px-3 py-2 !outline-none bg-zinc-800 text-zinc-100 placeholder:text-zinc-500"
|
spellCheck={false}
|
||||||
/>
|
className="relative h-10 w-full rounded-lg px-3 py-2 !outline-none bg-zinc-800 text-zinc-100 placeholder:text-zinc-500"
|
||||||
</div>
|
/>
|
||||||
<div className="flex flex-col gap-1">
|
</div>
|
||||||
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
<div className="flex flex-col gap-1">
|
||||||
Bio
|
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
||||||
</label>
|
Bio
|
||||||
<textarea
|
</label>
|
||||||
{...register("about")}
|
<textarea
|
||||||
spellCheck={false}
|
{...register("about")}
|
||||||
className="resize-none relative h-20 w-full rounded-lg px-3 py-2 !outline-none bg-zinc-800 text-zinc-100 placeholder:text-zinc-500"
|
spellCheck={false}
|
||||||
/>
|
className="resize-none relative h-20 w-full rounded-lg px-3 py-2 !outline-none bg-zinc-800 text-zinc-100 placeholder:text-zinc-500"
|
||||||
</div>
|
/>
|
||||||
<div>
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<label className="text-sm font-semibold uppercase tracking-wider text-zinc-400">
|
||||||
|
Website
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type={"text"}
|
||||||
|
{...register("website", {
|
||||||
|
required: false,
|
||||||
|
})}
|
||||||
|
spellCheck={false}
|
||||||
|
className="relative h-10 w-full rounded-lg px-3 py-2 !outline-none bg-zinc-800 text-zinc-100 placeholder:text-zinc-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!isDirty || !isValid}
|
disabled={!isDirty || !isValid}
|
||||||
|
@ -3,13 +3,13 @@ import { updateAccount } from "@libs/storage";
|
|||||||
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||||
import { CheckCircleIcon, LoaderIcon } from "@shared/icons";
|
import { CheckCircleIcon, LoaderIcon } from "@shared/icons";
|
||||||
import { RelayContext } from "@shared/relayProvider";
|
import { RelayContext } from "@shared/relayProvider";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useAccount } from "@utils/hooks/useAccount";
|
import { useAccount } from "@utils/hooks/useAccount";
|
||||||
import { arrayToNIP02 } from "@utils/transform";
|
import { arrayToNIP02 } from "@utils/transform";
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const initialList = [
|
const INITIAL_LIST = [
|
||||||
{
|
{
|
||||||
pubkey: "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2",
|
pubkey: "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2",
|
||||||
},
|
},
|
||||||
@ -117,6 +117,13 @@ export function CreateStep4Screen() {
|
|||||||
const [follows, setFollows] = useState([]);
|
const [follows, setFollows] = useState([]);
|
||||||
|
|
||||||
const { account } = useAccount();
|
const { account } = useAccount();
|
||||||
|
const { status, data } = useQuery(["trending-profiles"], async () => {
|
||||||
|
const res = await fetch("https://api.nostr.band/v0/trending/profiles");
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error("Error");
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
});
|
||||||
|
|
||||||
// toggle follow state
|
// toggle follow state
|
||||||
const toggleFollow = (pubkey: string) => {
|
const toggleFollow = (pubkey: string) => {
|
||||||
@ -140,7 +147,7 @@ export function CreateStep4Screen() {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const tags = arrayToNIP02(follows);
|
const tags = arrayToNIP02([...follows, account.pubkey]);
|
||||||
const signer = new NDKPrivateKeySigner(account.privkey);
|
const signer = new NDKPrivateKeySigner(account.privkey);
|
||||||
ndk.signer = signer;
|
ndk.signer = signer;
|
||||||
|
|
||||||
@ -154,7 +161,7 @@ export function CreateStep4Screen() {
|
|||||||
event.publish();
|
event.publish();
|
||||||
|
|
||||||
// update
|
// update
|
||||||
update.mutate(follows);
|
update.mutate([...follows, account.pubkey]);
|
||||||
|
|
||||||
// redirect to next step
|
// redirect to next step
|
||||||
setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
|
setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
|
||||||
@ -163,6 +170,8 @@ export function CreateStep4Screen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const list = data ? data.profiles.concat(INITIAL_LIST) : [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-md">
|
<div className="mx-auto w-full max-w-md">
|
||||||
<div className="mb-8 text-center">
|
<div className="mb-8 text-center">
|
||||||
@ -179,27 +188,34 @@ export function CreateStep4Screen() {
|
|||||||
</span>{" "}
|
</span>{" "}
|
||||||
plebs
|
plebs
|
||||||
</div>
|
</div>
|
||||||
<div className="scrollbar-hide flex h-96 flex-col overflow-y-auto py-2">
|
{status === "loading" ? (
|
||||||
{initialList.map((item: { pubkey: string }, index: number) => (
|
<div className="py-2 px-4 w-full h-11 inline-flex items-center justify-center">
|
||||||
<button
|
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-zinc-100" />
|
||||||
key={`item-${index}`}
|
</div>
|
||||||
type="button"
|
) : (
|
||||||
onClick={() => toggleFollow(item.pubkey)}
|
<div className="scrollbar-hide flex h-96 flex-col overflow-y-auto py-2">
|
||||||
className="inline-flex transform items-center justify-between bg-zinc-900 px-4 py-2 hover:bg-zinc-800 active:translate-y-1"
|
{list.map(
|
||||||
>
|
(item: { pubkey: string; profile: { content: string } }) => (
|
||||||
<User pubkey={item.pubkey} />
|
<button
|
||||||
{follows.includes(item.pubkey) && (
|
key={item.pubkey}
|
||||||
<div>
|
type="button"
|
||||||
<CheckCircleIcon
|
onClick={() => toggleFollow(item.pubkey)}
|
||||||
width={16}
|
className="inline-flex transform items-center justify-between bg-zinc-900 px-4 py-2 hover:bg-zinc-800 active:translate-y-1"
|
||||||
height={16}
|
>
|
||||||
className="text-green-400"
|
<User
|
||||||
|
pubkey={item.pubkey}
|
||||||
|
fallback={item.profile?.content}
|
||||||
/>
|
/>
|
||||||
</div>
|
{follows.includes(item.pubkey) && (
|
||||||
)}
|
<div>
|
||||||
</button>
|
<CheckCircleIcon className="w-4 h-4 text-green-400" />
|
||||||
))}
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{follows.length >= 10 && (
|
{follows.length >= 10 && (
|
||||||
<button
|
<button
|
||||||
|
@ -38,7 +38,7 @@ export function ImportStep2Screen() {
|
|||||||
const followsList = setToArray(follows);
|
const followsList = setToArray(follows);
|
||||||
|
|
||||||
// update
|
// update
|
||||||
update.mutate(followsList);
|
update.mutate([...followsList, account.pubkey]);
|
||||||
|
|
||||||
// redirect to next step
|
// redirect to next step
|
||||||
setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
|
setTimeout(() => navigate("/auth/onboarding", { replace: true }), 1200);
|
||||||
@ -47,8 +47,6 @@ export function ImportStep2Screen() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(account);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-md">
|
<div className="mx-auto w-full max-w-md">
|
||||||
<div className="mb-8 text-center">
|
<div className="mb-8 text-center">
|
||||||
|
@ -9,6 +9,7 @@ import { NoteSkeleton } from "@shared/notes/skeleton";
|
|||||||
import { TitleBar } from "@shared/titleBar";
|
import { TitleBar } from "@shared/titleBar";
|
||||||
import { User } from "@shared/user";
|
import { User } from "@shared/user";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { useAccount } from "@utils/hooks/useAccount";
|
||||||
import { parser } from "@utils/parser";
|
import { parser } from "@utils/parser";
|
||||||
|
|
||||||
export function ThreadBlock({ params }: { params: any }) {
|
export function ThreadBlock({ params }: { params: any }) {
|
||||||
@ -16,6 +17,7 @@ export function ThreadBlock({ params }: { params: any }) {
|
|||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const { account } = useAccount();
|
||||||
const { status, data } = useQuery(["thread", params.content], async () => {
|
const { status, data } = useQuery(["thread", params.content], async () => {
|
||||||
const res = await getNoteByID(params.content);
|
const res = await getNoteByID(params.content);
|
||||||
res["content"] = parser(res);
|
res["content"] = parser(res);
|
||||||
@ -55,7 +57,12 @@ export function ThreadBlock({ params }: { params: any }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 bg-zinc-900 rounded-md">
|
<div className="mt-3 bg-zinc-900 rounded-md">
|
||||||
<NoteReplyForm rootID={params.content} />
|
{account && (
|
||||||
|
<NoteReplyForm
|
||||||
|
rootID={params.content}
|
||||||
|
userPubkey={account.pubkey}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -60,7 +60,7 @@ export function AvatarUploader({ setPicture }: { setPicture: any }) {
|
|||||||
className="w-full h-full inline-flex items-center justify-center bg-zinc-900/40"
|
className="w-full h-full inline-flex items-center justify-center bg-zinc-900/40"
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<LoaderIcon className="h-6 w-6 animate-spintext-zinc-100" />
|
<LoaderIcon className="h-6 w-6 animate-spin text-zinc-100" />
|
||||||
) : (
|
) : (
|
||||||
<PlusIcon className="h-6 w-6 text-zinc-100" />
|
<PlusIcon className="h-6 w-6 text-zinc-100" />
|
||||||
)}
|
)}
|
||||||
|
@ -60,7 +60,7 @@ export function BannerUploader({ setBanner }: { setBanner: any }) {
|
|||||||
className="w-full h-full inline-flex items-center justify-center bg-zinc-900/40"
|
className="w-full h-full inline-flex items-center justify-center bg-zinc-900/40"
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<LoaderIcon className="h-8 w-8 animate-spintext-zinc-100" />
|
<LoaderIcon className="h-8 w-8 animate-spin text-zinc-100" />
|
||||||
) : (
|
) : (
|
||||||
<PlusIcon className="h-8 w-8 text-zinc-100" />
|
<PlusIcon className="h-8 w-8 text-zinc-100" />
|
||||||
)}
|
)}
|
||||||
|
@ -2,16 +2,16 @@ import { usePublish } from "@libs/ndk";
|
|||||||
import { Button } from "@shared/button";
|
import { Button } from "@shared/button";
|
||||||
import { Image } from "@shared/image";
|
import { Image } from "@shared/image";
|
||||||
import { DEFAULT_AVATAR, FULL_RELAYS } from "@stores/constants";
|
import { DEFAULT_AVATAR, FULL_RELAYS } from "@stores/constants";
|
||||||
import { useAccount } from "@utils/hooks/useAccount";
|
|
||||||
import { useProfile } from "@utils/hooks/useProfile";
|
import { useProfile } from "@utils/hooks/useProfile";
|
||||||
|
import { shortenKey } from "@utils/shortenKey";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export function NoteReplyForm({ rootID }: { rootID: string }) {
|
export function NoteReplyForm({
|
||||||
|
rootID,
|
||||||
|
userPubkey,
|
||||||
|
}: { rootID: string; userPubkey: string }) {
|
||||||
const publish = usePublish();
|
const publish = usePublish();
|
||||||
|
const { status, user } = useProfile(userPubkey);
|
||||||
const { account } = useAccount();
|
|
||||||
const { status, user } = useProfile(account.npub);
|
|
||||||
|
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
@ -45,9 +45,9 @@ export function NoteReplyForm({ rootID }: { rootID: string }) {
|
|||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
<div className="relative h-9 w-9 shrink-0 rounded">
|
<div className="relative h-9 w-9 shrink-0 rounded">
|
||||||
<Image
|
<Image
|
||||||
src={user?.image}
|
src={user.image}
|
||||||
fallback={DEFAULT_AVATAR}
|
fallback={DEFAULT_AVATAR}
|
||||||
alt={account.npub}
|
alt={userPubkey}
|
||||||
className="h-9 w-9 rounded-md bg-white object-cover"
|
className="h-9 w-9 rounded-md bg-white object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -56,7 +56,7 @@ export function NoteReplyForm({ rootID }: { rootID: string }) {
|
|||||||
Reply as
|
Reply as
|
||||||
</p>
|
</p>
|
||||||
<p className="leading-none text-sm font-medium text-zinc-100">
|
<p className="leading-none text-sm font-medium text-zinc-100">
|
||||||
{user?.nip05 || user?.name}
|
{user.nip05 || user.name || shortenKey(userPubkey)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import { NDKUser } from "@nostr-dev-kit/ndk";
|
||||||
import { RelayContext } from "@shared/relayProvider";
|
import { RelayContext } from "@shared/relayProvider";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
export function useProfile(pubkey: string) {
|
export function useProfile(pubkey: string, fallback?: string) {
|
||||||
const ndk = useContext(RelayContext);
|
const ndk = useContext(RelayContext);
|
||||||
const {
|
const {
|
||||||
status,
|
status,
|
||||||
@ -12,10 +13,15 @@ export function useProfile(pubkey: string) {
|
|||||||
} = useQuery(
|
} = useQuery(
|
||||||
["user", pubkey],
|
["user", pubkey],
|
||||||
async () => {
|
async () => {
|
||||||
const user = ndk.getUser({ hexpubkey: pubkey });
|
if (fallback) {
|
||||||
await user.fetchProfile();
|
const profile = JSON.parse(fallback);
|
||||||
|
return profile;
|
||||||
|
} else {
|
||||||
|
const user = ndk.getUser({ hexpubkey: pubkey });
|
||||||
|
await user.fetchProfile();
|
||||||
|
|
||||||
return user.profile;
|
return user.profile;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
|
Loading…
Reference in New Issue
Block a user