diff --git a/packages/app/src/Components/User/FollowButton.tsx b/packages/app/src/Components/User/FollowButton.tsx
index bcb3efec..9d87f951 100644
--- a/packages/app/src/Components/User/FollowButton.tsx
+++ b/packages/app/src/Components/User/FollowButton.tsx
@@ -2,7 +2,7 @@ import { HexKey } from "@snort/system";
import { FormattedMessage } from "react-intl";
import AsyncButton from "@/Components/Button/AsyncButton";
-import useEventPublisher from "@/Hooks/useEventPublisher";
+import useFollowsControls from "@/Hooks/useFollowControls";
import useLogin from "@/Hooks/useLogin";
import { parseId } from "@/Utils";
@@ -14,32 +14,18 @@ export interface FollowButtonProps {
}
export default function FollowButton(props: FollowButtonProps) {
const pubkey = parseId(props.pubkey);
- const { publisher, system } = useEventPublisher();
- const { follows, readonly } = useLogin(s => ({ follows: s.follows, readonly: s.readonly }));
- const isFollowing = follows.item.includes(pubkey);
+ const readonly = useLogin(s => s.readonly);
+ const control = useFollowsControls();
+ const isFollowing = control.isFollowing(pubkey);
const baseClassname = props.className ? `${props.className} ` : "";
- async function follow(pubkey: HexKey) {
- if (publisher) {
- const ev = await publisher.contactList([pubkey, ...follows.item].map(a => ["p", a]));
- system.BroadcastEvent(ev);
- }
- }
-
- async function unfollow(pubkey: HexKey) {
- if (publisher) {
- const ev = await publisher.contactList(follows.item.filter(a => a !== pubkey).map(a => ["p", a]));
- system.BroadcastEvent(ev);
- }
- }
-
return (
{
e.stopPropagation();
- await (isFollowing ? unfollow(pubkey) : follow(pubkey));
+ await (isFollowing ? control.removeFollow([pubkey]) : control.addFollow([pubkey]));
}}>
{isFollowing ? : }
diff --git a/packages/app/src/Components/User/FollowListBase.tsx b/packages/app/src/Components/User/FollowListBase.tsx
index 2b8663e6..7fbc49a1 100644
--- a/packages/app/src/Components/User/FollowListBase.tsx
+++ b/packages/app/src/Components/User/FollowListBase.tsx
@@ -1,12 +1,10 @@
-import { dedupe } from "@snort/shared";
import { HexKey } from "@snort/system";
import { ReactNode, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import ProfilePreview from "@/Components/User/ProfilePreview";
-import useEventPublisher from "@/Hooks/useEventPublisher";
+import useFollowsControls from "@/Hooks/useFollowControls";
import useLogin from "@/Hooks/useLogin";
-import { setFollows } from "@/Utils/Login";
import AsyncButton from "../Button/AsyncButton";
import messages from "../messages";
@@ -30,19 +28,13 @@ export default function FollowListBase({
actions,
profileActions,
}: FollowListBaseProps) {
- const { publisher, system } = useEventPublisher();
- const { id, follows } = useLogin(s => ({ id: s.id, follows: s.follows }));
+ const control = useFollowsControls();
const login = useLogin();
const profilePreviewOptions = useMemo(() => ({ about: showAbout, profileCards: true }), [showAbout]);
async function followAll() {
- if (publisher) {
- const newFollows = dedupe([...pubkeys, ...follows.item]);
- const ev = await publisher.contactList(newFollows.map(a => ["p", a]));
- setFollows(id, newFollows, ev.created_at);
- await system.BroadcastEvent(ev);
- }
+ await control.addFollow(pubkeys);
}
return (
diff --git a/packages/app/src/Hooks/useFollowControls.ts b/packages/app/src/Hooks/useFollowControls.ts
new file mode 100644
index 00000000..1adbf59f
--- /dev/null
+++ b/packages/app/src/Hooks/useFollowControls.ts
@@ -0,0 +1,42 @@
+import { dedupe } from "@snort/shared";
+import { useMemo } from "react";
+
+import useEventPublisher from "./useEventPublisher";
+import useLogin from "./useLogin";
+
+/**
+ * Simple hook for adding / removing follows
+ */
+export default function useFollowsControls() {
+ const { publisher, system } = useEventPublisher();
+ const { follows, relays } = useLogin(s => ({ follows: s.follows.item, readonly: s.readonly, relays: s.relays.item }));
+
+ return useMemo(() => {
+ const publishList = async (newList: Array) => {
+ if (publisher) {
+ const ev = await publisher.contactList(
+ newList.map(a => ["p", a]),
+ relays,
+ );
+ system.BroadcastEvent(ev);
+ }
+ };
+
+ return {
+ isFollowing: (pk: string) => {
+ return follows.includes(pk);
+ },
+ addFollow: async (pk: Array) => {
+ const newList = dedupe([...follows, ...pk]);
+ await publishList(newList);
+ },
+ removeFollow: async (pk: Array) => {
+ const newList = follows.filter(a => !pk.includes(a));
+ await publishList(newList);
+ },
+ setFollows: async (pk: Array) => {
+ await publishList(dedupe(pk));
+ },
+ };
+ }, [follows, relays, publisher, system]);
+}
diff --git a/packages/app/src/Pages/settings/tools/prune-follows.tsx b/packages/app/src/Pages/settings/tools/prune-follows.tsx
index fc404aa8..61483b63 100644
--- a/packages/app/src/Pages/settings/tools/prune-follows.tsx
+++ b/packages/app/src/Pages/settings/tools/prune-follows.tsx
@@ -6,9 +6,9 @@ import { FormattedMessage, FormattedNumber } from "react-intl";
import AsyncButton from "@/Components/Button/AsyncButton";
import ProfileImage from "@/Components/User/ProfileImage";
import useEventPublisher from "@/Hooks/useEventPublisher";
+import useFollowsControls from "@/Hooks/useFollowControls";
import useLogin from "@/Hooks/useLogin";
import { Day } from "@/Utils/Const";
-import { setFollows } from "@/Utils/Login";
import { FollowsRelayHealth } from "./follows-relay-health";
@@ -18,13 +18,14 @@ const enum PruneStage {
}
export function PruneFollowList() {
- const { id, follows } = useLogin(s => ({ id: s.id, follows: s.follows }));
- const { publisher, system } = useEventPublisher();
+ const { follows } = useLogin(s => ({ id: s.id, follows: s.follows }));
+ const { system } = useEventPublisher();
const uniqueFollows = dedupe(follows.item);
const [status, setStatus] = useState();
const [progress, setProgress] = useState(0);
const [lastPost, setLastPosts] = useState>();
const [unfollow, setUnfollow] = useState>([]);
+ const followControls = useFollowsControls();
async function fetchLastPosts() {
setStatus(PruneStage.FetchLastPostTimestamp);
@@ -74,12 +75,7 @@ export function PruneFollowList() {
}, [uniqueFollows, unfollow]);
async function publishFollowList() {
- const newFollows = newFollowList.map(a => ["p", a]) as Array<[string, string]>;
- if (publisher) {
- const ev = await publisher.contactList(newFollows);
- await system.BroadcastEvent(ev);
- setFollows(id, newFollowList, ev.created_at * 1000);
- }
+ await followControls.setFollows(newFollowList);
}
function getStatus() {
diff --git a/packages/app/src/Utils/Login/Functions.ts b/packages/app/src/Utils/Login/Functions.ts
index 078cac50..2497b87f 100644
--- a/packages/app/src/Utils/Login/Functions.ts
+++ b/packages/app/src/Utils/Login/Functions.ts
@@ -122,8 +122,10 @@ export async function generateNewLogin(
const publisher = EventPublisher.privateKey(privateKey);
// Create new contact list following self and site account
- const contactList = [publicKey, ...CONFIG.signUp.defaultFollows.map(a => bech32ToHex(a))].map(a => ["p", a]);
- const ev = await publisher.contactList(contactList);
+ const contactList = [publicKey, ...CONFIG.signUp.defaultFollows.map(a => bech32ToHex(a))].map(a => ["p", a]) as Array<
+ [string, string]
+ >;
+ const ev = await publisher.contactList(contactList, newRelays);
system.BroadcastEvent(ev);
// Create relay metadata event
diff --git a/packages/system/src/event-publisher.ts b/packages/system/src/event-publisher.ts
index 5210df36..1a366abb 100644
--- a/packages/system/src/event-publisher.ts
+++ b/packages/system/src/event-publisher.ts
@@ -257,9 +257,12 @@ export class EventPublisher {
return await this.#sign(eb);
}
- async contactList(tags: Array<[string, string]>) {
+ async contactList(tags: Array<[string, string]>, relays?: Record) {
const eb = this.#eb(EventKind.ContactList);
tags.forEach(a => eb.tag(a));
+ if (relays) {
+ eb.content(JSON.stringify(relays));
+ }
return await this.#sign(eb);
}