finish relay manegament screen

This commit is contained in:
Ren Amamiya 2023-10-01 09:02:14 +07:00
parent 11ed618a7f
commit 674e5f0339
4 changed files with 192 additions and 28 deletions

View File

@ -1,29 +1,84 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query';
import { useCallback } from 'react';
import { VList } from 'virtua';
import { useNDK } from '@libs/ndk/provider';
import {
ArticleNote,
FileNote,
NoteWrapper,
Repost,
TextNote,
UnknownNote,
} from '@shared/notes';
export function RelayEventList({ relayUrl }: { relayUrl: string }) {
const { fetcher } = useNDK();
const { status, data } = useQuery(
['relay-event'],
async () => {
const url = 'wss://' + relayUrl;
const events = await fetcher.fetchLatestEvents(
[relayUrl],
[url],
{
kinds: [NDKKind.Text, NDKKind.Repost, 1063, NDKKind.Article],
},
100
);
return events as unknown as NDKEvent[];
},
{ refetchOnWindowFocus: false }
);
const renderItem = useCallback(
(event: NDKEvent) => {
switch (event.kind) {
case NDKKind.Text:
return (
<NoteWrapper key={event.id} event={event}>
<TextNote />
</NoteWrapper>
);
case NDKKind.Repost:
return <Repost key={event.id} event={event} />;
case 1063:
return (
<NoteWrapper key={event.id} event={event}>
<FileNote />
</NoteWrapper>
);
case NDKKind.Article:
return (
<NoteWrapper key={event.id} event={event}>
<ArticleNote />
</NoteWrapper>
);
default:
return (
<NoteWrapper key={event.id} event={event}>
<UnknownNote />
</NoteWrapper>
);
}
},
[data]
);
return (
<div>
<p>TODO</p>
<div className="h-full">
<div className="mx-auto w-full max-w-[500px]">
{status === 'loading' ? (
<div>Loading...</div>
) : (
<VList className="scrollbar-hide h-full">
<div className="h-10" />
{data.map((item) => renderItem(item))}
<div className="h-16" />
</VList>
)}
</div>
</div>
);
}

View File

@ -22,7 +22,12 @@ export function RelayList() {
async () => {
return await getAllRelaysByUsers();
},
{ refetchOnWindowFocus: false }
{
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
staleTime: Infinity,
}
);
const inspectRelay = (relayUrl: string) => {

View File

@ -1,14 +1,39 @@
import { Suspense } from 'react';
import { Await, useLoaderData } from 'react-router-dom';
import { Await, useLoaderData, useNavigate, useParams } from 'react-router-dom';
import { LoaderIcon } from '@shared/icons';
import { ArrowLeftIcon, LoaderIcon } from '@shared/icons';
import { User } from '@shared/user';
import { RelayEventList } from './components/relayEventList';
export function RelayScreen() {
const { url } = useParams();
const data: { relay?: { [key: string]: string } } = useLoaderData();
const navigate = useNavigate();
const getSoftwareName = (url: string) => {
const filename = url.substring(url.lastIndexOf('/') + 1);
return filename.replace('.git', '');
};
const titleCase = (s: string) => {
return s
.replace(/^[-_]*(.)/, (_, c) => c.toUpperCase())
.replace(/[-_]+(.)/g, (_, c) => ' ' + c.toUpperCase());
};
return (
<div className="grid h-full w-full grid-cols-3">
<div className="col-span-2 border-r border-white/5"></div>
<div className="col-span-2 border-r border-white/5">
<div className="inline-flex h-16 w-full items-center gap-2.5 border-b border-white/5 px-3">
<button type="button" onClick={() => navigate(-1)}>
<ArrowLeftIcon className="h-5 w-5 text-white/70 hover:text-white" />
</button>
<h3 className="font-semibold text-white">Global events</h3>
</div>
<RelayEventList relayUrl={url} />
</div>
<div className="col-span-1">
<div className="inline-flex h-16 w-full items-center border-b border-white/5 px-3">
<h3 className="font-semibold text-white">Information</h3>
@ -31,25 +56,104 @@ export function RelayScreen() {
}
>
{(resolvedRelay) => (
<div className="flex flex-col gap-2">
<p>
<span className="font-semibold">Name</span> : {resolvedRelay.name}
</p>
<p>
<span className="font-semibold">Description</span> :{' '}
{resolvedRelay.description}
</p>
<p>
<span className="font-semibold">Contact</span> :{' '}
{resolvedRelay.contact}
</p>
<p>
<span className="font-semibold">Software</span> : [open website]
</p>
<p>
<span className="font-semibold">Version</span> :{' '}
{resolvedRelay.version}
</p>
<div className="flex flex-col gap-5">
<div>
<h3 className="font-semibold leading-tight text-white">
{resolvedRelay.name}
</h3>
<p className="text-sm font-medium text-white/70">
{resolvedRelay.description}
</p>
</div>
{resolvedRelay.pubkey ? (
<div className="flex flex-col gap-1">
<h5 className="text-sm font-semibold text-white/70">Owner:</h5>
<div className="w-full rounded-lg bg-white/10 px-2 py-2">
<User pubkey={resolvedRelay.pubkey} variant="simple" />
</div>
</div>
) : null}
{resolvedRelay.contact ? (
<div>
<h5 className="text-sm font-semibold text-white/70">Contact:</h5>
<a
href={`mailto:${resolvedRelay.contact}`}
target="_blank"
className="underline after:content-['_↗'] hover:text-fuchsia-500"
rel="noreferrer"
>
mailto:{resolvedRelay.contact}
</a>
</div>
) : null}
<div>
<h5 className="text-sm font-semibold text-white/70">Software:</h5>
<a
href={resolvedRelay.software}
target="_blank"
rel="noreferrer"
className="underline after:content-['_↗'] hover:text-fuchsia-500"
>
{getSoftwareName(resolvedRelay.software) +
' - ' +
resolvedRelay.version}
</a>
</div>
<div>
<h5 className="text-sm font-semibold text-white/70">
Supported NIPs:
</h5>
<div className="mt-2 grid grid-cols-7 gap-2">
{resolvedRelay.supported_nips.map((item: string) => (
<a
key={item}
href={`https://nips.be/${item}`}
target="_blank"
rel="noreferrer"
className="inline-flex aspect-square h-full w-full items-center justify-center rounded-lg bg-white/10 text-sm font-medium hover:bg-fuchsia-500"
>
{item}
</a>
))}
</div>
</div>
{resolvedRelay.limitation ? (
<div>
<h5 className="text-sm font-semibold text-white/70">Limitation</h5>
<div className="flex flex-col gap-2 divide-y divide-white/5">
{Object.keys(resolvedRelay.limitation).map((key, index) => {
return (
<div
key={index}
className="flex items-baseline justify-between pt-2"
>
<p className="text-sm font-medium text-white">
{titleCase(key)}:
</p>
<p className="text-sm font-medium text-white/70">
{resolvedRelay.limitation[key].toString()}
</p>
</div>
);
})}
</div>
</div>
) : null}
{resolvedRelay.payments_url ? (
<div className="flex flex-col gap-1">
<a
href={resolvedRelay.payments_url}
target="_blank"
rel="noreferrer"
className="inline-flex h-10 w-full items-center justify-center rounded-lg bg-fuchsia-500 text-sm font-medium hover:bg-fuchsia-600"
>
Open payment website
</a>
<span className="text-center text-xs text-white/70">
You need to make a payment to connect this relay
</span>
</div>
) : null}
</div>
)}
</Await>

View File

@ -277,7 +277,7 @@ export const User = memo(function User({
<HoverCard.Root>
<div className="relative z-10 flex items-start gap-3">
<HoverCard.Trigger asChild>
<Avatar.Root className="shrink-0">
<Avatar.Root className="h-10 w-10 shrink-0">
<Avatar.Image
src={user?.picture || user?.image}
alt={pubkey}