👁️
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

support adding card right away on new list

+74 -20
+25 -6
src/components/list/SaveToListDialog.tsx
··· 15 15 type CollectionList, 16 16 hasCard, 17 17 hasDeck, 18 + type SaveItem, 18 19 } from "@/lib/collection-list-types"; 19 20 import { getConstellationQueryKeys } from "@/lib/constellation-queries"; 20 - import type { OracleId, ScryfallId } from "@/lib/scryfall-types"; 21 21 import { toOracleUri } from "@/lib/scryfall-types"; 22 22 23 - export type SaveItem = 24 - | { type: "card"; scryfallId: ScryfallId; oracleId: OracleId } 25 - | { type: "deck"; deckUri: string }; 26 - 27 23 interface SaveToListDialogProps { 28 24 item: SaveItem; 29 25 itemName?: string; ··· 49 45 }); 50 46 51 47 const createMutation = useCreateCollectionListMutation(); 48 + const queryClient = useQueryClient(); 52 49 53 50 useEffect(() => { 54 51 if (!isOpen) { ··· 75 72 e.preventDefault(); 76 73 if (!newListName.trim()) return; 77 74 75 + const itemUri = 76 + item.type === "card" 77 + ? toOracleUri(item.oracleId) 78 + : (item.deckUri as `at://${string}`); 79 + const queryKeys = getConstellationQueryKeys(itemUri, userDid); 80 + 81 + const previousSaved = queryClient.getQueryData<boolean>( 82 + queryKeys.userSaved, 83 + ); 84 + const previousCount = queryClient.getQueryData<number>(queryKeys.saveCount); 85 + 86 + queryClient.setQueryData<boolean>(queryKeys.userSaved, true); 87 + queryClient.setQueryData<number>( 88 + queryKeys.saveCount, 89 + (old) => (old ?? 0) + 1, 90 + ); 91 + 78 92 createMutation.mutate( 79 - { name: newListName.trim() }, 93 + { name: newListName.trim(), initialItem: item }, 80 94 { 95 + onError: () => { 96 + queryClient.setQueryData<boolean>(queryKeys.userSaved, previousSaved); 97 + queryClient.setQueryData<number>(queryKeys.saveCount, previousCount); 98 + }, 81 99 onSuccess: () => { 82 100 setNewListName(""); 101 + onClose(); 83 102 }, 84 103 }, 85 104 );
+4 -8
src/components/social/SocialStats.tsx
··· 1 1 import { Bookmark } from "lucide-react"; 2 2 import { useState } from "react"; 3 - import type { DeckItemUri } from "@/lib/constellation-queries"; 3 + import type { SaveItem } from "@/lib/collection-list-types"; 4 + import type { SocialItemUri } from "@/lib/constellation-queries"; 4 5 import { useItemSocialStats } from "@/lib/constellation-queries"; 5 - import type { OracleId, OracleUri, ScryfallId } from "@/lib/scryfall-types"; 6 6 import { toOracleUri } from "@/lib/scryfall-types"; 7 7 import { useAuth } from "@/lib/useAuth"; 8 8 import { SaveToListDialog } from "../list/SaveToListDialog"; 9 9 10 - export type SocialItem = 11 - | { type: "card"; scryfallId: ScryfallId; oracleId: OracleId } 12 - | { type: "deck"; deckUri: DeckItemUri }; 13 - 14 10 interface SocialStatsProps { 15 - item: SocialItem; 11 + item: SaveItem; 16 12 itemName?: string; 17 13 showCount?: boolean; 18 14 className?: string; 19 15 } 20 16 21 - function getItemUri(item: SocialItem): OracleUri | DeckItemUri { 17 + function getItemUri(item: SaveItem): SocialItemUri { 22 18 return item.type === "card" ? toOracleUri(item.oracleId) : item.deckUri; 23 19 } 24 20
+36 -6
src/lib/collection-list-queries.ts
··· 3 3 * Provides query options and mutations for saving cards/decks to lists 4 4 */ 5 5 6 - import type { Did } from "@atcute/lexicons"; 6 + import type { Did, ResourceUri } from "@atcute/lexicons"; 7 7 import { 8 8 type InfiniteData, 9 9 infiniteQueryOptions, ··· 26 26 isCardItem, 27 27 isDeckItem, 28 28 type ListItem, 29 + type SaveItem, 29 30 } from "./collection-list-types"; 30 31 import { getPdsForDid } from "./identity"; 31 32 import type { ComDeckbelcherCollectionList } from "./lexicons/index"; ··· 132 133 staleTime: 60 * 1000, 133 134 }); 134 135 136 + interface CreateListParams { 137 + name: string; 138 + initialItem?: SaveItem; 139 + } 140 + 135 141 /** 136 142 * Mutation for creating a new collection list 143 + * Optionally adds an initial item to the list 137 144 */ 138 145 export function useCreateCollectionListMutation() { 139 146 const { agent, session } = useAuth(); 140 147 const queryClient = useQueryClient(); 141 148 142 149 return useMutationWithToast({ 143 - mutationFn: async (list: { name: string }) => { 150 + mutationFn: async ({ name, initialItem }: CreateListParams) => { 144 151 if (!agent || !session) { 145 152 throw new Error("Must be authenticated to create a list"); 146 153 } 147 154 155 + const items: ComDeckbelcherCollectionList.Main["items"] = []; 156 + if (initialItem) { 157 + const addedAt = new Date().toISOString(); 158 + if (initialItem.type === "card") { 159 + items.push({ 160 + $type: "com.deckbelcher.collection.list#cardItem", 161 + addedAt, 162 + ref: { 163 + scryfallUri: toScryfallUri(initialItem.scryfallId), 164 + oracleUri: toOracleUri(initialItem.oracleId), 165 + }, 166 + }); 167 + } else { 168 + items.push({ 169 + $type: "com.deckbelcher.collection.list#deckItem", 170 + addedAt, 171 + deckUri: initialItem.deckUri as ResourceUri, 172 + }); 173 + } 174 + } 175 + 148 176 const result = await createCollectionListRecord(agent, { 149 177 $type: "com.deckbelcher.collection.list", 150 - name: list.name, 151 - items: [], 178 + name, 179 + items, 152 180 createdAt: new Date().toISOString(), 153 181 }); 154 182 ··· 158 186 159 187 return result.data; 160 188 }, 161 - onSuccess: () => { 162 - toast.success("List created"); 189 + onSuccess: (_data, { initialItem }) => { 190 + toast.success( 191 + initialItem ? "List created and item saved" : "List created", 192 + ); 163 193 164 194 if (!session) return; 165 195
+9
src/lib/collection-list-types.ts
··· 4 4 */ 5 5 6 6 import type { ResourceUri } from "@atcute/lexicons"; 7 + import type { DeckItemUri } from "./constellation-queries"; 7 8 import type { ComDeckbelcherCollectionList } from "./lexicons/index"; 8 9 import type { OracleId, ScryfallId } from "./scryfall-types"; 10 + 11 + /** 12 + * Item to save to a list (card or deck) 13 + * Shared by SaveToListDialog and SocialStats 14 + */ 15 + export type SaveItem = 16 + | { type: "card"; scryfallId: ScryfallId; oracleId: OracleId } 17 + | { type: "deck"; deckUri: DeckItemUri }; 9 18 10 19 /** 11 20 * App-side card item with flat typed IDs.