forked from Kieran/zap.stream
follow button
This commit is contained in:
parent
aa1718a141
commit
57d014410c
@ -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 />
|
||||
|
@ -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
28
src/hooks/follows.ts
Normal 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 };
|
||||
}
|
@ -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>}
|
||||
|
Loading…
Reference in New Issue
Block a user