/**
* Card detail modal - shows full card info with quantity controls.
*/
import React, { useState } from "react";
import {
StyleSheet,
View,
Text,
Image,
Pressable,
ScrollView,
ActivityIndicator,
Alert,
Dimensions,
Platform,
} from "react-native";
import { StatusBar } from "expo-status-bar";
import { useLocalSearchParams, useRouter } from "expo-router";
import { FontAwesome } from "@expo/vector-icons";
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
import { useCurrentUser } from "@/lib/hooks";
const { width: SCREEN_WIDTH } = Dimensions.get("window");
const CARD_WIDTH = SCREEN_WIDTH - 64;
const CARD_HEIGHT = CARD_WIDTH * (88 / 63);
export default function CardDetailModal() {
const router = useRouter();
const params = useLocalSearchParams<{
collectionEntryId: string;
cardId: string;
}>();
// Get authenticated user
const { user } = useCurrentUser();
const userId = user?._id ?? null;
const [isUpdating, setIsUpdating] = useState(false);
// Fetch card details
const card = useQuery(
api.cards.getByScryfallId,
params.cardId ? { scryfallId: params.cardId } : "skip"
);
// Fetch collection entry
const collection = useQuery(
api.collections.getByUser,
userId ? { userId: userId as any } : "skip"
);
const collectionEntry = collection?.find(
(entry) => entry._id === params.collectionEntryId
);
// Mutations
const updateQuantity = useMutation(api.collections.updateQuantity);
const removeCard = useMutation(api.collections.remove);
const handleQuantityChange = async (delta: number) => {
if (!collectionEntry) return;
const newQuantity = collectionEntry.quantity + delta;
if (newQuantity <= 0) {
handleRemove();
return;
}
setIsUpdating(true);
try {
await updateQuantity({
entryId: collectionEntry._id,
quantity: newQuantity,
});
} catch (error) {
console.error("Failed to update quantity:", error);
Alert.alert("Error", "Failed to update quantity");
} finally {
setIsUpdating(false);
}
};
const handleRemove = () => {
Alert.alert(
"Remove Card",
`Remove ${card?.name || "this card"} from your collection?`,
[
{ text: "Cancel", style: "cancel" },
{
text: "Remove",
style: "destructive",
onPress: async () => {
if (!collectionEntry) return;
setIsUpdating(true);
try {
await removeCard({ entryId: collectionEntry._id });
router.back();
} catch (error) {
console.error("Failed to remove card:", error);
Alert.alert("Error", "Failed to remove card");
setIsUpdating(false);
}
},
},
]
);
};
// Loading state
if (!card || !collectionEntry) {
return (
);
}
return (
{/* Card image */}
{card.imageUri ? (
) : (
)}
{/* Card info */}
{card.name}
Set
{card.setCode.toUpperCase()}
Number
{card.collectorNumber}
Rarity
{card.rarity}
{card.artist && (
{card.artist}
)}
{/* Quantity controls */}
Quantity
handleQuantityChange(-1)}
disabled={isUpdating}
>
{isUpdating ? (
) : (
{collectionEntry.quantity}
)}
handleQuantityChange(1)}
disabled={isUpdating}
>
{collectionEntry.isFoil && (
Foil
)}
{/* Added date */}
Added {new Date(collectionEntry.addedAt).toLocaleDateString()}
{/* Actions */}
Remove from Collection
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#1a1a1a",
},
content: {
paddingBottom: 40,
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#1a1a1a",
},
imageContainer: {
alignItems: "center",
paddingTop: 20,
paddingBottom: 24,
},
cardImage: {
width: CARD_WIDTH,
height: CARD_HEIGHT,
borderRadius: 12,
backgroundColor: "#2a2a2a",
},
cardPlaceholder: {
justifyContent: "center",
alignItems: "center",
},
infoContainer: {
paddingHorizontal: 24,
marginBottom: 24,
},
cardName: {
color: "#fff",
fontSize: 24,
fontWeight: "bold",
textAlign: "center",
marginBottom: 16,
},
metaRow: {
flexDirection: "row",
justifyContent: "center",
gap: 24,
},
metaItem: {
alignItems: "center",
},
metaLabel: {
color: "#666",
fontSize: 12,
textTransform: "uppercase",
marginBottom: 4,
},
metaValue: {
color: "#fff",
fontSize: 16,
fontWeight: "600",
},
artistRow: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
gap: 8,
marginTop: 16,
},
artistText: {
color: "#888",
fontSize: 14,
fontStyle: "italic",
},
quantityContainer: {
backgroundColor: "#2a2a2a",
marginHorizontal: 24,
padding: 20,
borderRadius: 12,
alignItems: "center",
marginBottom: 16,
},
quantityLabel: {
color: "#888",
fontSize: 12,
textTransform: "uppercase",
marginBottom: 12,
},
quantityControls: {
flexDirection: "row",
alignItems: "center",
gap: 20,
},
quantityButton: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: "#007AFF",
justifyContent: "center",
alignItems: "center",
},
quantityDisplay: {
width: 60,
alignItems: "center",
},
quantityValue: {
color: "#fff",
fontSize: 28,
fontWeight: "bold",
},
foilBadge: {
flexDirection: "row",
alignItems: "center",
gap: 6,
marginTop: 12,
paddingHorizontal: 12,
paddingVertical: 6,
backgroundColor: "rgba(255,215,0,0.1)",
borderRadius: 6,
},
foilText: {
color: "#FFD700",
fontSize: 12,
fontWeight: "600",
},
addedDate: {
color: "#666",
fontSize: 12,
textAlign: "center",
marginBottom: 24,
},
actions: {
paddingHorizontal: 24,
},
actionButton: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
gap: 8,
padding: 16,
borderRadius: 12,
},
removeButton: {
backgroundColor: "rgba(255,107,107,0.1)",
borderWidth: 1,
borderColor: "rgba(255,107,107,0.3)",
},
removeButtonText: {
color: "#FF6B6B",
fontSize: 16,
fontWeight: "600",
},
});