Files
lumina/components/ReactionButton.tsx
2025-02-13 10:57:18 +01:00

136 lines
4.0 KiB
TypeScript

import { useNostrEvents, useNDK } from "@/hooks/useNDK"
import { Button } from "@/components/ui/button"
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
import { ReloadIcon } from "@radix-ui/react-icons"
import ReactionButtonReactionList from "./ReactionButtonReactionList"
import { useState, useEffect, useMemo } from "react"
export default function ReactionButton({ event }: { event: any }) {
const ndk = useNDK()
const loginType = typeof window !== "undefined" ? window.localStorage.getItem("loginType") : null
const loggedInUserPublicKey = typeof window !== "undefined" ? window.localStorage.getItem("pubkey") : null
const [liked, setLiked] = useState(false)
const [likeIcon, setLikeIcon] = useState("")
const { events, isLoading } = useNostrEvents({
filter: {
"#e": [event.id],
kinds: [7],
},
})
const filteredEvents = useMemo(() => {
return events.filter((e) => {
return e.tags.filter((tag) => tag[0] === "e" && tag[1] !== event.id).length === 0
})
}, [events, event.id])
const reactionCount = filteredEvents.length
useEffect(() => {
const userReaction = filteredEvents.find((e) => e.pubkey === loggedInUserPublicKey)
if (userReaction) {
setLiked(true)
setLikeIcon(userReaction.content)
} else {
setLiked(false)
setLikeIcon("")
}
}, [filteredEvents, loggedInUserPublicKey])
const onPost = async (icon: string) => {
const message = icon || "+"
const ndkEvent = ndk.getEvent()
ndkEvent.kind = 7
ndkEvent.tags.push(["e", event.id])
ndkEvent.tags.push(["p", event.pubkey])
ndkEvent.tags.push(["k", event.kind.toString()])
ndkEvent.content = message
ndkEvent.created_at = Math.floor(Date.now() / 1000)
try {
if (loginType === "extension") {
await window.nostr.signEvent(ndkEvent.rawEvent())
} else if (loginType === "amber") {
alert("Signing with Amber is not implemented yet, sorry!")
return
} else if (loginType === "raw_nsec") {
const nsecStr = window.localStorage.getItem("nsec")
if (!nsecStr) throw new Error("No nsec found")
await ndkEvent.sign()
}
await ndkEvent.publish()
setLiked(true)
setLikeIcon(message)
filteredEvents.push(ndkEvent)
} catch (error) {
console.error("Failed to sign/publish event", error)
}
}
return (
<Drawer>
<DrawerTrigger asChild>
<Button variant={liked ? "default" : "outline"}>
{isLoading ? (
<>
<ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> 💜
</>
) : (
<>
{reactionCount} {liked ? likeIcon : "💜"}
</>
)}
</Button>
</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Reactions</DrawerTitle>
</DrawerHeader>
<div className="px-4 grid grid-cols-3">
<Button
variant={liked && likeIcon === "💜" ? "secondary" : "outline"}
className={`mx-1`}
onClick={() => onPost("💜")}
>
💜
</Button>
<Button
variant={liked && likeIcon === "👍" ? "secondary" : "outline"}
className={`mx-1`}
onClick={() => onPost("👍")}
>
👍
</Button>
<Button
variant={liked && likeIcon === "👎" ? "secondary" : "outline"}
className={`mx-1`}
onClick={() => onPost("👎")}
>
👎
</Button>
</div>
<hr className="my-4" />
<ReactionButtonReactionList filteredEvents={filteredEvents} />
<DrawerFooter>
<DrawerClose asChild>
<div>
<Button variant={"secondary"}>Close</Button>
</div>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
)
}