7 changed files with 179 additions and 55 deletions
@ -0,0 +1,77 @@ |
|||||||
|
import { TDraftEvent } from '@common/types' |
||||||
|
import { Button } from '@renderer/components/ui/button' |
||||||
|
import { useFetchFollowings } from '@renderer/hooks' |
||||||
|
import { useNostr } from '@renderer/providers/NostrProvider' |
||||||
|
import dayjs from 'dayjs' |
||||||
|
import { Loader } from 'lucide-react' |
||||||
|
import { kinds } from 'nostr-tools' |
||||||
|
import { useMemo, useState } from 'react' |
||||||
|
|
||||||
|
export default function FollowButton({ pubkey }: { pubkey: string }) { |
||||||
|
const { pubkey: accountPubkey, publish } = useNostr() |
||||||
|
const { followings, followListEvent, refresh } = useFetchFollowings(accountPubkey) |
||||||
|
const [updating, setUpdating] = useState(false) |
||||||
|
const isFollowing = useMemo(() => followings.includes(pubkey), [followings, pubkey]) |
||||||
|
|
||||||
|
if (!accountPubkey || pubkey === accountPubkey) return null |
||||||
|
|
||||||
|
const follow = async (e: React.MouseEvent) => { |
||||||
|
e.stopPropagation() |
||||||
|
if (isFollowing) return |
||||||
|
|
||||||
|
setUpdating(true) |
||||||
|
const newFollowListEvent: TDraftEvent = { |
||||||
|
kind: kinds.Contacts, |
||||||
|
content: followListEvent?.content ?? '', |
||||||
|
created_at: dayjs().unix(), |
||||||
|
tags: (followListEvent?.tags ?? []).concat([['p', pubkey]]) |
||||||
|
} |
||||||
|
console.log(newFollowListEvent) |
||||||
|
try { |
||||||
|
await publish(newFollowListEvent) |
||||||
|
await refresh() |
||||||
|
} catch (error) { |
||||||
|
console.error(error) |
||||||
|
} finally { |
||||||
|
setUpdating(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const unfollow = async (e: React.MouseEvent) => { |
||||||
|
e.stopPropagation() |
||||||
|
if (!isFollowing || !followListEvent) return |
||||||
|
|
||||||
|
setUpdating(true) |
||||||
|
const newFollowListEvent: TDraftEvent = { |
||||||
|
kind: kinds.Contacts, |
||||||
|
content: followListEvent.content ?? '', |
||||||
|
created_at: dayjs().unix(), |
||||||
|
tags: followListEvent.tags.filter( |
||||||
|
([tagName, tagValue]) => tagName !== 'p' || tagValue !== pubkey |
||||||
|
) |
||||||
|
} |
||||||
|
try { |
||||||
|
await publish(newFollowListEvent) |
||||||
|
await refresh() |
||||||
|
} catch (error) { |
||||||
|
console.error(error) |
||||||
|
} finally { |
||||||
|
setUpdating(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return isFollowing ? ( |
||||||
|
<Button |
||||||
|
className="w-20 min-w-20 rounded-full" |
||||||
|
variant="secondary" |
||||||
|
onClick={unfollow} |
||||||
|
disabled={updating} |
||||||
|
> |
||||||
|
{updating ? <Loader className="animate-spin" /> : 'Unfollow'} |
||||||
|
</Button> |
||||||
|
) : ( |
||||||
|
<Button className="w-20 min-w-20 rounded-full" onClick={follow} disabled={updating}> |
||||||
|
{updating ? <Loader className="animate-spin" /> : 'Follow'} |
||||||
|
</Button> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
import { generateImageByPubkey } from '@renderer/lib/pubkey' |
||||||
|
import { useEffect, useMemo, useState } from 'react' |
||||||
|
|
||||||
|
export default function ProfileBanner({ |
||||||
|
pubkey, |
||||||
|
banner, |
||||||
|
className |
||||||
|
}: { |
||||||
|
pubkey: string |
||||||
|
banner?: string |
||||||
|
className?: string |
||||||
|
}) { |
||||||
|
const defaultBanner = useMemo(() => generateImageByPubkey(pubkey), [pubkey]) |
||||||
|
const [bannerUrl, setBannerUrl] = useState(banner || defaultBanner) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (banner) { |
||||||
|
setBannerUrl(banner) |
||||||
|
} else { |
||||||
|
setBannerUrl(defaultBanner) |
||||||
|
} |
||||||
|
}, [defaultBanner, banner]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<img |
||||||
|
src={bannerUrl} |
||||||
|
alt={`${pubkey} banner`} |
||||||
|
className={className} |
||||||
|
onError={() => setBannerUrl(defaultBanner)} |
||||||
|
/> |
||||||
|
) |
||||||
|
} |
||||||
Loading…
Reference in new issue