Scrapboard.org client
1import {
2 Dialog,
3 DialogClose,
4 DialogContent,
5 DialogDescription,
6 DialogFooter,
7 DialogHeader,
8 DialogTitle,
9 DialogTrigger,
10} from "@/components/ui/dialog";
11import { useAuth } from "@/lib/hooks/useAuth";
12import { useState } from "react";
13import { Button } from "./ui/button";
14import { PostView } from "@atproto/api/dist/client/types/app/bsky/feed/defs";
15import { LoaderCircle } from "lucide-react";
16import { useBoardsStore } from "@/lib/stores/boards";
17import { BoardsPicker } from "./BoardPicker";
18import { toast } from "sonner";
19import { AtUri } from "@atproto/api";
20import { LIST_COLLECTION, LIST_ITEM_COLLECTION } from "@/constants";
21import { FeedItem } from "./Feed";
22import { useCurrentBoard } from "@/lib/stores/useCurrentBoard";
23import { useBoardItemsStore } from "@/lib/stores/boardItems";
24
25export function UnsaveButton({
26 post,
27 image,
28}: {
29 post: PostView;
30 image: number;
31}) {
32 const { agent } = useAuth();
33 const [isLoading, setLoading] = useState(false);
34 const [isOpen, setOpen] = useState(false);
35 const { removeBoardItem, boardItems } = useBoardItemsStore();
36
37 if (agent == null) return <div>not logged in :(</div>;
38 return (
39 <Dialog open={isOpen} onOpenChange={setOpen}>
40 <DialogTrigger asChild>
41 <span
42 onClick={(e) => {
43 e.stopPropagation();
44 }}
45 className="cursor-pointer"
46 >
47 <Button size="sm" className="cursor-pointer">
48 Remove
49 </Button>
50 </span>
51 </DialogTrigger>
52
53 <DialogContent>
54 <DialogHeader>
55 <DialogTitle>Remove from board?</DialogTitle>
56 <DialogDescription>
57 Are you sure you want to remove this from your board?
58 </DialogDescription>
59 </DialogHeader>
60 <DialogFooter>
61 <DialogClose>
62 <Button className="cursor-pointer">Cancel</Button>
63 </DialogClose>
64 <Button
65 onClick={async (e) => {
66 e.stopPropagation(); // Optional, but safe
67
68 setLoading(true);
69 try {
70 const postRkey = AtUri.make(post.uri).rkey;
71 const record = boardItems
72 .entries()
73 .find((e) => AtUri.make(e[1].url).rkey == postRkey);
74 if (!record)
75 return toast(
76 "Couldn't find post. You might be viewing stale data."
77 );
78
79 const rkey = record[0];
80 console.log("using rkey", rkey, "and record", record);
81 const result = await agent.com.atproto.repo.deleteRecord({
82 collection: LIST_ITEM_COLLECTION,
83 rkey,
84 repo: agent.assertDid,
85 });
86
87 if (result?.success) {
88 removeBoardItem(rkey);
89 toast("Removed from board");
90 setOpen(false);
91 } else {
92 toast("Failed to remove");
93 }
94 } finally {
95 setLoading(false);
96 }
97 }}
98 className="cursor-pointer"
99 variant="destructive"
100 >
101 {isLoading && <LoaderCircle className="animate-spin ml-2" />}
102 Remove
103 </Button>
104 </DialogFooter>
105 </DialogContent>
106 </Dialog>
107 );
108}