follow button

This commit is contained in:
Alejandro Gomez 2023-06-30 22:33:05 +02:00
parent aa1718a141
commit 57d014410c
No known key found for this signature in database
GPG Key ID: 4DF39E566658C817
4 changed files with 106 additions and 8 deletions

View File

@ -2,7 +2,8 @@ import "./async-button.css";
import { useState } from "react";
import Spinner from "element/spinner";
interface AsyncButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
interface AsyncButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
disabled?: boolean;
onClick(e: React.MouseEvent): Promise<void> | void;
children?: React.ReactNode;
@ -28,8 +29,15 @@ export default function AsyncButton(props: AsyncButtonProps) {
}
return (
<button type="button" disabled={loading || props.disabled} {...props} onClick={handle}>
<span style={{ visibility: loading ? "hidden" : "visible" }}>{props.children}</span>
<button
type="button"
disabled={loading || props.disabled}
{...props}
onClick={handle}
>
<span style={{ visibility: loading ? "hidden" : "visible" }}>
{props.children}
</span>
{loading && (
<span className="spinner-wrapper">
<Spinner />

View File

@ -1,4 +1,66 @@
// todo
export function FollowButton({ pubkey }: { pubkey: string }) {
return <button className="btn btn-primary">Follow</button>;
import { EventKind, EventPublisher } from "@snort/system";
import { useLogin } from "hooks/login";
import useFollows from "hooks/follows";
import AsyncButton from "element/async-button";
import { System } from "index";
export function LoggedInFollowButton({
loggedIn,
pubkey,
}: {
loggedIn: string;
pubkey: string;
}) {
const { contacts, relays } = useFollows(loggedIn, true);
const isFollowing = contacts.find((t) => t.at(1) === pubkey);
async function unfollow() {
const pub = await EventPublisher.nip7();
if (pub) {
const ev = await pub.generic((eb) => {
eb.kind(EventKind.ContactList).content(JSON.stringify(relays));
for (const c of contacts) {
if (c.at(1) !== pubkey) {
eb.tag(c);
}
}
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
}
}
async function follow() {
const pub = await EventPublisher.nip7();
if (pub) {
const ev = await pub.generic((eb) => {
eb.kind(EventKind.ContactList).content(JSON.stringify(relays));
for (const tag of contacts) {
eb.tag(tag);
}
eb.tag(["p", pubkey]);
return eb;
});
console.debug(ev);
System.BroadcastEvent(ev);
}
}
return (
<AsyncButton
type="button"
className="btn btn-primary"
onClick={isFollowing ? unfollow : follow}
>
{isFollowing ? "Unfollow" : "Follow"}
</AsyncButton>
);
}
export function FollowButton({ pubkey }: { pubkey: string }) {
const login = useLogin();
return login?.pubkey ? (
<LoggedInFollowButton loggedIn={login.pubkey} pubkey={pubkey} />
) : null;
}

28
src/hooks/follows.ts Normal file
View File

@ -0,0 +1,28 @@
import { useMemo } from "react";
import { EventKind, ReplaceableNoteStore, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { System } from "index";
export default function useFollows(pubkey: string, leaveOpen = false) {
const sub = useMemo(() => {
const b = new RequestBuilder(`follows:${pubkey.slice(0, 12)}`);
b.withOptions({
leaveOpen,
})
.withFilter()
.authors([pubkey])
.kinds([EventKind.ContactList]);
return b;
}, [pubkey, leaveOpen]);
const { data } = useRequestBuilder<ReplaceableNoteStore>(
System,
ReplaceableNoteStore,
sub
);
const contacts = (data?.tags ?? []).filter((t) => t.at(0) === "p");
const relays = JSON.parse(data?.content ?? "{}");
return { contacts, relays };
}

View File

@ -13,6 +13,7 @@ import { Profile } from "element/profile";
import { Icon } from "element/icon";
import { SendZapsDialog } from "element/send-zap";
import { VideoTile } from "element/video-tile";
import { FollowButton } from "element/follow-button";
import { useProfile } from "hooks/profile";
import useTopZappers from "hooks/top-zappers";
import { Text } from "element/text";
@ -81,8 +82,6 @@ export function ProfilePage() {
}
}
// todo: follow
return (
<div className="profile-page">
<div className="profile-container">
@ -125,6 +124,7 @@ export function ProfilePage() {
targetName={profile?.name || link.id}
/>
)}
<FollowButton pubkey={link.id} />
</div>
<div className="profile-information">
{profile?.name && <h1 className="name">{profile.name}</h1>}