Skip to content

Commit

Permalink
client-web: initial handling of 2 or more relays
Browse files Browse the repository at this point in the history
  • Loading branch information
franzos committed Aug 23, 2023
1 parent b6a65f3 commit 2f1cb32
Show file tree
Hide file tree
Showing 37 changed files with 1,143 additions and 742 deletions.
2 changes: 2 additions & 0 deletions client-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.15.0",
"uuid": "^9.0.0",
"zustand": "^4.4.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
Expand Down
4 changes: 1 addition & 3 deletions client-web/src/components/bottom-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,19 @@ export function BottomBar() {
if (diff > 0) {
setLastCount(current);
const newEvents = relayEvents.slice(-diff);
console.log(newEvents);
for (const event of newEvents) {
let description = "";
if (event.data[0] === RELAY_MESSAGE_TYPE.NOTICE) {
description = event.data[1];
} else if (event.data[0] === RELAY_MESSAGE_TYPE.OK) {
description = `${event.data[2]}. Event ${event.data[1]}: ${event.data[3]}`;
} else if (event.data[0] === RELAY_MESSAGE_TYPE.EOSE) {
description = `${event.data[1]}`;
description = `Loaded all requested events for subscription ${event.data[1]}`;
} else if (event.data[0] === RELAY_MESSAGE_TYPE.COUNT) {
description = `Relay ${event.data[1]}: ${JSON.stringify(
event.data[2]
)} events`;
}
console.log(description);
if (description !== "") {
toast({
title: `Relay ${event.data[0]}`,
Expand Down
16 changes: 11 additions & 5 deletions client-web/src/components/connect-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function ConnectModal({ isOpen, onClose }: ConnectModalProps) {
);
const [newRelayUrl, setNewRelayUrl] = useState<string>("");
const [loadingRelaysNos2x, setLoadingRelaysNos2x] = useState<boolean>(false);
const [isBusy, setIsBusy] = useState<boolean>(false);
const toast = useToast();

const relaysFromExtention = async (retryCount?: number) => {
Expand Down Expand Up @@ -90,6 +91,13 @@ export function ConnectModal({ isOpen, onClose }: ConnectModalProps) {
}
};

const connect = async () => {
setIsBusy(true);
await useNClient.getState().connect(initialRelayUrls);
setIsBusy(false);
onClose();
};

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
Expand Down Expand Up @@ -189,11 +197,9 @@ export function ConnectModal({ isOpen, onClose }: ConnectModalProps) {
<ModalFooter>
<Button
colorScheme="green"
disabled={initialRelayUrls.length === 0}
onClick={async () => {
await useNClient.getState().connect(initialRelayUrls);
onClose();
}}
isDisabled={initialRelayUrls.length === 0}
isLoading={isBusy}
onClick={connect}
>
Connect
</Button>
Expand Down
13 changes: 10 additions & 3 deletions client-web/src/components/create-event-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,17 @@ export const CreateEventForm = () => {
const [publicKeyTags] = useNClient((state) => [
state.newEvent?.hasPublicKeyTags(),
]);
const [userRelayId, setUserRelayId] = useState<string>("");

useEffect(() => {
const loadUser = async () => {
const foundUsers = [];
if (publicKeyTags) {
for (const key of publicKeyTags) {
for (const tags of publicKeyTags) {
if (tags.length === 2) {
setUserRelayId(tags[1]);
}
const key = tags[0];
const user = await useNClient.getState().getUser(key);
if (user) {
foundUsers.push(user);
Expand Down Expand Up @@ -120,7 +125,9 @@ export const CreateEventForm = () => {
}

try {
const evId = await useNClient.getState().signAndSendEvent(newEvent);
const evId = await useNClient.getState().signAndSendEvent({
event: newEvent,
});
if (evId) {
toast({
title: "Success",
Expand Down Expand Up @@ -216,7 +223,7 @@ export const CreateEventForm = () => {
<FormLabel>Type: {translateNameToLabel(newEventName)}</FormLabel>

{users.map((user) => (
<User user={user} key={user.pubkey} />
<User user={user} key={user.pubkey} relayId={userRelayId} />
))}
</FormControl>
<FormControl marginBottom={4}>
Expand Down
39 changes: 33 additions & 6 deletions client-web/src/components/event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export function Event({
event,
reactions,
reposts,
eventRelayIds,
}: EventProps) {
const [isReady] = useNClient((state) => [
state.connected && state.keystore !== "none",
Expand Down Expand Up @@ -86,13 +87,26 @@ export function Event({
onOpen();
};

const newReply = () => {
const newReply = async () => {
const relays = await useNClient.getState().getRelays();
const relay = relays.find((r) => r.id === eventRelayIds[0]);
if (!relay) {
toast({
title: "Error",
description: `Relay ${eventRelayIds[0]} not found`,
status: "error",
duration: 5000,
isClosable: true,
});
return;
}
const ev = NewShortTextNoteResponse({
text: "",
inResponseTo: {
id: event.id,
pubkey: event.pubkey,
},
relayUrl: relay.url,
});
useNClient.getState().setNewEvent(ev);
useNClient.getState().setNewEventName("NewShortTextNoteResponse");
Expand Down Expand Up @@ -126,7 +140,9 @@ export function Event({
}

try {
const evId = await useNClient.getState().signAndSendEvent(ev);
const evId = await useNClient.getState().signAndSendEvent({
event: ev,
});
if (evId) {
toast({
title: "Success",
Expand All @@ -135,9 +151,17 @@ export function Event({
duration: 5000,
isClosable: true,
});
useNClient.getState().requestInformation("events", [event.id], {
timeout: 10000,
});
useNClient.getState().requestInformation(
{
source: "events",
idsOrKeys: [evId],
relayId: eventRelayIds[0],
},
{
timeout: 10000,
timeoutAt: Date.now() + 10000,
}
);
}
} catch (e) {
let error = "";
Expand Down Expand Up @@ -237,7 +261,10 @@ export function Event({
</Text>
</CardBody>
<CardFooter p={4}>
<ActionButtons />
<HStack>
<ActionButtons />
<Text>Relay {eventRelayIds[0].substring(0, 5)}...</Text>
</HStack>
</CardFooter>
</Card>

Expand Down
8 changes: 6 additions & 2 deletions client-web/src/components/events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,21 @@ export function Events(props: {
user={event.user}
reactions={event.reactions}
reposts={event.reposts}
eventRelayUrls={event.eventRelayUrls}
eventRelayIds={event.eventRelayIds}
key={event.event.id}
userComponent={
props && props.userComponent ? (
event.user ? (
<props.userComponent user={event.user} />
<props.userComponent
user={event.user}
relayId={event.eventRelayIds[0]}
/>
) : (
<props.userComponent
user={{
pubkey: event.event.pubkey,
}}
relayId={event.eventRelayIds[0]}
/>
)
) : undefined
Expand Down
9 changes: 7 additions & 2 deletions client-web/src/components/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import { Link } from "react-router-dom";

export function User({
user,
relayId,
hideFollow,
}: {
user: UserBase;
relayId: string;
hideFollow?: boolean;
}) {
const [following] = useNClient((state) => [
Expand All @@ -28,7 +30,7 @@ export function User({
const name = data && data.name ? data.name : "Anonymous";
const picture = data && data.picture ? data.picture : "/no-image.png";

const profileLink = `/p/${user.pubkey}`;
const profileLink = `/p/${relayId}/${user.pubkey}`;

return (
<Flex>
Expand All @@ -49,7 +51,10 @@ export function User({
onClick={() =>
following
? useNClient.getState().unfollowUser(user.pubkey)
: useNClient.getState().followUser(user.pubkey)
: useNClient.getState().followUser({
pubkey: user.pubkey,
relayId,
})
}
>
{following ? "Unfollow" : "Follow"}
Expand Down
14 changes: 13 additions & 1 deletion client-web/src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ export const MAX_EVENTS = 25;
export const DEFAULT_RELAYS = {
"wss://nos.lol": {
read: true,
write: true,
write: false,
},
"wss://nostr.wine": {
read: true,
write: false,
},
// "wss://nostr.plebchain.org": {
// read: true,
// write: false,
// },
// "wss://nostr.einundzwanzig.space": {
// read: true,
// write: false,
// },
};
7 changes: 6 additions & 1 deletion client-web/src/layouts/primary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ export function PrimaryLayout() {
state.eventsPublishingQueue.length,
]);
const [subscriptionsCount, setSubscriptionsCount] = useState<number>(0);
const [followingUsers, setFollowingUsers] = useState<NUserBase[]>([]);
const [followingUsers, setFollowingUsers] = useState<
{
user: NUserBase;
relayIds: string[];
}[]
>([]);
const [relaysCount, setRelaysCount] = useState<number>(0);

const { isOpen, onOpen, onClose } = useDisclosure();
Expand Down
2 changes: 1 addition & 1 deletion client-web/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<Route path="/subscriptions" element={<SubscriptionsRoute />} />
<Route path="/relays" element={<RelaysRoute />} />
<Route path="/queue" element={<PublishingQueueRoute />} />
<Route path="/p/:pubkey" element={<UserProfileRoute />} />
<Route path="/p/:relayid/:pubkey" element={<UserProfileRoute />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
1 change: 0 additions & 1 deletion client-web/src/routes/account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export function AccountRoute() {

const generateKeypair = () => {
const keypair = generateClientKeys();
console.log(keypair);
useNClient.getState().setKeyStore({
keystore: "localstore",
publicKey: keypair.publicKey,
Expand Down
15 changes: 12 additions & 3 deletions client-web/src/routes/following.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { NUserBase } from "@nostr-ts/common";
import { User } from "../components/user";

export function FollowingRoute() {
const [followingUsers, setFollowingUsers] = useState<NUserBase[]>([]);
const [followingUsers, setFollowingUsers] = useState<
{
user: NUserBase;
relayIds: string[];
}[]
>([]);

const initDone = useRef<boolean>(false);

Expand All @@ -26,9 +31,13 @@ export function FollowingRoute() {
<Heading size="lg">Following</Heading>
{followingUsers.length > 0 ? (
<>
{followingUsers.map((user) => (
{followingUsers.map((item) => (
<Box mb="3">
<User user={user} key={user.pubkey} />
<User
user={item.user}
key={item.user.pubkey}
relayId={item.relayIds[0]}
/>
</Box>
))}
</>
Expand Down
17 changes: 14 additions & 3 deletions client-web/src/routes/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Heading, Box, Text, Grid } from "@chakra-ui/react";
import { NEVENT_KIND, NFilters, NUserBase } from "@nostr-ts/common";
import {
CLIENT_MESSAGE_TYPE,
NEVENT_KIND,
NFilters,
NUserBase,
} from "@nostr-ts/common";
import { useState, useEffect } from "react";
import { useNClient } from "../state/client";
import { NUser } from "@nostr-ts/web";
Expand All @@ -16,8 +21,9 @@ export function UserProfileRoute() {
]);
const [user, setUser] = useState<NUserBase | null>(null);

const params = useParams<{ pubkey: string }>();
const params = useParams<{ pubkey: string; relayid: string }>();
const pubkey = params.pubkey || "";
const relayId = params.relayid || "";

const view = `profile-${pubkey}`;
const defaultFilters = new NFilters({
Expand Down Expand Up @@ -51,10 +57,15 @@ export function UserProfileRoute() {
}

await useNClient.getState().count({
type: CLIENT_MESSAGE_TYPE.COUNT,
filters: new NFilters({
kinds: [3],
"#p": [pubkey],
}),
options: {
timeout: 10000,
timeoutAt: Date.now() + 10000,
},
});
};
init();
Expand All @@ -79,7 +90,7 @@ export function UserProfileRoute() {
<Box maxHeight="80vh" overflowY="auto">
<Box>
<Heading size="lg">Profile</Heading>
{user && <User user={user} />}
{user && <User user={user} relayId={relayId} />}
</Box>
<Box>
{connected ? (
Expand Down
Loading

0 comments on commit 2f1cb32

Please sign in to comment.