Add search functionality to user collections in Community and TradeCreator components

This commit is contained in:
Matthieu
2025-11-24 16:33:17 +01:00
parent 0780976661
commit bab6367181
2 changed files with 210 additions and 187 deletions

View File

@@ -62,6 +62,7 @@ export default function Community() {
const [selectedUserCollection, setSelectedUserCollection] = useState<CollectionItem[]>([]); const [selectedUserCollection, setSelectedUserCollection] = useState<CollectionItem[]>([]);
const [loadingCollection, setLoadingCollection] = useState(false); const [loadingCollection, setLoadingCollection] = useState(false);
const [showTradeCreator, setShowTradeCreator] = useState(false); const [showTradeCreator, setShowTradeCreator] = useState(false);
const [userCollectionSearch, setUserCollectionSearch] = useState('');
// Friends state // Friends state
const [friendsSubTab, setFriendsSubTab] = useState<FriendsSubTab>('list'); const [friendsSubTab, setFriendsSubTab] = useState<FriendsSubTab>('list');
@@ -382,13 +383,17 @@ export default function Community() {
// ============ USER COLLECTION VIEW ============ // ============ USER COLLECTION VIEW ============
if (selectedUser) { if (selectedUser) {
const filteredUserCollection = selectedUserCollection.filter(({ card }) =>
card.name.toLowerCase().includes(userCollectionSearch.toLowerCase())
);
return ( return (
<div className="bg-gray-900 text-white min-h-screen"> <div className="bg-gray-900 text-white min-h-screen">
{/* Header */} {/* Header */}
<div className="sticky top-0 bg-gray-900/95 backdrop-blur border-b border-gray-800 p-3 z-10"> <div className="sticky top-0 bg-gray-900/95 backdrop-blur border-b border-gray-800 p-3 z-10">
<div className="flex items-center justify-between gap-2"> <div className="flex items-center justify-between gap-2 mb-3">
<button <button
onClick={() => { setSelectedUser(null); setSelectedUserCollection([]); }} onClick={() => { setSelectedUser(null); setSelectedUserCollection([]); setUserCollectionSearch(''); }}
className="flex items-center gap-1 text-blue-400 text-sm min-w-0" className="flex items-center gap-1 text-blue-400 text-sm min-w-0"
> >
<ChevronLeft size={20} /> <ChevronLeft size={20} />
@@ -403,6 +408,25 @@ export default function Community() {
<span className="hidden sm:inline">Trade</span> <span className="hidden sm:inline">Trade</span>
</button> </button>
</div> </div>
{/* Search input */}
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={16} />
<input
type="text"
value={userCollectionSearch}
onChange={(e) => setUserCollectionSearch(e.target.value)}
placeholder="Search cards..."
className="w-full pl-9 pr-8 py-2 bg-gray-700 border border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
{userCollectionSearch && (
<button
onClick={() => setUserCollectionSearch('')}
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-white"
>
<X size={16} />
</button>
)}
</div>
</div> </div>
{/* Collection Grid */} {/* Collection Grid */}
@@ -413,9 +437,11 @@ export default function Community() {
</div> </div>
) : selectedUserCollection.length === 0 ? ( ) : selectedUserCollection.length === 0 ? (
<p className="text-gray-400 text-center py-12">Empty collection</p> <p className="text-gray-400 text-center py-12">Empty collection</p>
) : filteredUserCollection.length === 0 ? (
<p className="text-gray-400 text-center py-12">No cards match "{userCollectionSearch}"</p>
) : ( ) : (
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2"> <div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2">
{selectedUserCollection.map(({ card, quantity }) => ( {filteredUserCollection.map(({ card, quantity }) => (
<div key={card.id} className="relative"> <div key={card.id} className="relative">
<img <img
src={card.image_uris?.small || card.image_uris?.normal} src={card.image_uris?.small || card.image_uris?.normal}

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { X, ArrowLeftRight, ArrowRight, ArrowLeft, Minus, Send, Gift, Loader2, Check } from 'lucide-react'; import { X, ArrowLeftRight, ArrowRight, ArrowLeft, Minus, Send, Gift, Loader2, Search } from 'lucide-react';
import { useAuth } from '../contexts/AuthContext'; import { useAuth } from '../contexts/AuthContext';
import { useToast } from '../contexts/ToastContext'; import { useToast } from '../contexts/ToastContext';
import { getUserCollection, getCardsByIds } from '../services/api'; import { getUserCollection, getCardsByIds } from '../services/api';
@@ -11,6 +11,153 @@ interface CollectionItem {
quantity: number; quantity: number;
} }
interface SelectedCard {
card: Card;
quantity: number;
maxQuantity: number;
}
// ============ MOVED OUTSIDE TO PREVENT RE-RENDER ============
interface CollectionGridProps {
items: CollectionItem[];
selectedCards: Map<string, SelectedCard>;
onAdd: (card: Card, maxQty: number) => void;
onRemove: (cardId: string) => void;
emptyMessage: string;
selectionColor: 'green' | 'blue';
searchValue: string;
onSearchChange: (value: string) => void;
searchPlaceholder: string;
}
function CollectionGrid({
items,
selectedCards,
onAdd,
onRemove,
emptyMessage,
selectionColor,
searchValue,
onSearchChange,
searchPlaceholder,
}: CollectionGridProps) {
const ringColor = selectionColor === 'green' ? 'ring-green-500' : 'ring-blue-500';
const badgeColor = selectionColor === 'green' ? 'bg-green-600' : 'bg-blue-500';
const filteredItems = items.filter(({ card }) =>
card.name.toLowerCase().includes(searchValue.toLowerCase())
);
return (
<div className="space-y-3">
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={16} />
<input
type="text"
value={searchValue}
onChange={(e) => onSearchChange(e.target.value)}
placeholder={searchPlaceholder}
className="w-full pl-9 pr-8 py-2 bg-gray-700 border border-gray-600 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
{searchValue && (
<button
onClick={() => onSearchChange('')}
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-white"
>
<X size={16} />
</button>
)}
</div>
{items.length === 0 ? (
<p className="text-gray-400 text-center py-8">{emptyMessage}</p>
) : filteredItems.length === 0 ? (
<p className="text-gray-400 text-center py-8">No cards match "{searchValue}"</p>
) : (
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-2">
{filteredItems.map(({ card, quantity }) => {
const selected = selectedCards.get(card.id);
const remainingQty = quantity - (selected?.quantity || 0);
return (
<div
key={card.id}
className={`relative cursor-pointer rounded-lg overflow-hidden transition active:scale-95 ${
selected ? `ring-2 ${ringColor}` : 'active:ring-2 active:ring-gray-500'
}`}
onClick={() => remainingQty > 0 && onAdd(card, quantity)}
>
<img
src={card.image_uris?.small || card.image_uris?.normal}
alt={card.name}
className={`w-full h-auto ${remainingQty === 0 ? 'opacity-50' : ''}`}
/>
<div className="absolute top-1 right-1 bg-gray-900/80 text-white text-[10px] px-1 py-0.5 rounded">
{remainingQty}/{quantity}
</div>
{selected && (
<button
onClick={(e) => {
e.stopPropagation();
onRemove(card.id);
}}
className={`absolute bottom-1 left-1 ${badgeColor} text-white text-[10px] px-1.5 py-0.5 rounded flex items-center gap-0.5`}
>
+{selected.quantity}
<Minus size={10} />
</button>
)}
</div>
);
})}
</div>
)}
</div>
);
}
interface SelectedCardsSummaryProps {
cards: Map<string, SelectedCard>;
onRemove: (cardId: string) => void;
label: string;
emptyLabel: string;
color: 'green' | 'blue';
}
function SelectedCardsSummary({ cards, onRemove, label, emptyLabel, color }: SelectedCardsSummaryProps) {
const bgColor = color === 'green' ? 'bg-green-900/50' : 'bg-blue-900/50';
const textColor = color === 'green' ? 'text-green-400' : 'text-blue-400';
return (
<div>
<h4 className={`text-xs font-semibold ${textColor} mb-1`}>{label}:</h4>
{cards.size === 0 ? (
<p className="text-gray-500 text-xs">{emptyLabel}</p>
) : (
<div className="flex flex-wrap gap-1">
{Array.from(cards.values()).map((item) => (
<div
key={item.card.id}
className={`flex items-center gap-1 ${bgColor} px-1.5 py-0.5 rounded text-xs`}
>
<span className="truncate max-w-[80px]">{item.card.name}</span>
<span className={textColor}>x{item.quantity}</span>
<button
onClick={() => onRemove(item.card.id)}
className="text-red-400 active:text-red-300"
>
<Minus size={12} />
</button>
</div>
))}
</div>
)}
</div>
);
}
// ============ MAIN COMPONENT ============
interface TradeCreatorProps { interface TradeCreatorProps {
receiverId: string; receiverId: string;
receiverUsername: string; receiverUsername: string;
@@ -19,12 +166,6 @@ interface TradeCreatorProps {
onTradeCreated: () => void; onTradeCreated: () => void;
} }
interface SelectedCard {
card: Card;
quantity: number;
maxQuantity: number;
}
type MobileStep = 'want' | 'give' | 'review'; type MobileStep = 'want' | 'give' | 'review';
export default function TradeCreator({ export default function TradeCreator({
@@ -41,20 +182,19 @@ export default function TradeCreator({
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
// Mobile step state
const [isGiftMode, setIsGiftMode] = useState(false); const [isGiftMode, setIsGiftMode] = useState(false);
const [mobileStep, setMobileStep] = useState<MobileStep>('want'); const [mobileStep, setMobileStep] = useState<MobileStep>('want');
// Cards I'm offering (from my collection)
const [myOfferedCards, setMyOfferedCards] = useState<Map<string, SelectedCard>>(new Map()); const [myOfferedCards, setMyOfferedCards] = useState<Map<string, SelectedCard>>(new Map());
// Cards I want (from their collection)
const [wantedCards, setWantedCards] = useState<Map<string, SelectedCard>>(new Map()); const [wantedCards, setWantedCards] = useState<Map<string, SelectedCard>>(new Map());
const [myCollectionSearch, setMyCollectionSearch] = useState('');
const [theirCollectionSearch, setTheirCollectionSearch] = useState('');
useEffect(() => { useEffect(() => {
loadMyCollection(); loadMyCollection();
}, [user]); }, [user]);
// When gift mode is toggled, adjust mobile step
useEffect(() => { useEffect(() => {
if (isGiftMode) { if (isGiftMode) {
setWantedCards(new Map()); setWantedCards(new Map());
@@ -186,7 +326,6 @@ export default function TradeCreator({
const isGift = myOfferedCards.size > 0 && wantedCards.size === 0; const isGift = myOfferedCards.size > 0 && wantedCards.size === 0;
const isRequest = myOfferedCards.size === 0 && wantedCards.size > 0; const isRequest = myOfferedCards.size === 0 && wantedCards.size > 0;
// Mobile navigation
const goToNextStep = () => { const goToNextStep = () => {
if (mobileStep === 'want') setMobileStep('give'); if (mobileStep === 'want') setMobileStep('give');
else if (mobileStep === 'give') setMobileStep('review'); else if (mobileStep === 'give') setMobileStep('review');
@@ -197,123 +336,8 @@ export default function TradeCreator({
else if (mobileStep === 'give' && !isGiftMode) setMobileStep('want'); else if (mobileStep === 'give' && !isGiftMode) setMobileStep('want');
}; };
const canGoNext = () => {
if (mobileStep === 'want') return true; // Can skip wanting cards (request nothing)
if (mobileStep === 'give') return true; // Can skip giving cards (gift request)
return false;
};
const canSubmit = myOfferedCards.size > 0 || wantedCards.size > 0; const canSubmit = myOfferedCards.size > 0 || wantedCards.size > 0;
// Collection grid component
const CollectionGrid = ({
items,
selectedCards,
onAdd,
onRemove,
emptyMessage,
selectionColor,
}: {
items: CollectionItem[];
selectedCards: Map<string, SelectedCard>;
onAdd: (card: Card, maxQty: number) => void;
onRemove: (cardId: string) => void;
emptyMessage: string;
selectionColor: 'green' | 'blue';
}) => {
if (items.length === 0) {
return <p className="text-gray-400 text-center py-8">{emptyMessage}</p>;
}
const ringColor = selectionColor === 'green' ? 'ring-green-500' : 'ring-blue-500';
const badgeColor = selectionColor === 'green' ? 'bg-green-600' : 'bg-blue-500';
return (
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-2">
{items.map(({ card, quantity }) => {
const selected = selectedCards.get(card.id);
const remainingQty = quantity - (selected?.quantity || 0);
return (
<div
key={card.id}
className={`relative cursor-pointer rounded-lg overflow-hidden transition active:scale-95 ${
selected ? `ring-2 ${ringColor}` : 'active:ring-2 active:ring-gray-500'
}`}
onClick={() => remainingQty > 0 && onAdd(card, quantity)}
>
<img
src={card.image_uris?.small || card.image_uris?.normal}
alt={card.name}
className={`w-full h-auto ${remainingQty === 0 ? 'opacity-50' : ''}`}
/>
<div className="absolute top-1 right-1 bg-gray-900/80 text-white text-[10px] px-1 py-0.5 rounded">
{remainingQty}/{quantity}
</div>
{selected && (
<button
onClick={(e) => {
e.stopPropagation();
onRemove(card.id);
}}
className={`absolute bottom-1 left-1 ${badgeColor} text-white text-[10px] px-1.5 py-0.5 rounded flex items-center gap-0.5`}
>
+{selected.quantity}
<Minus size={10} />
</button>
)}
</div>
);
})}
</div>
);
};
// Selected cards summary component
const SelectedCardsSummary = ({
cards,
onRemove,
label,
emptyLabel,
color,
}: {
cards: Map<string, SelectedCard>;
onRemove: (cardId: string) => void;
label: string;
emptyLabel: string;
color: 'green' | 'blue';
}) => {
const bgColor = color === 'green' ? 'bg-green-900/50' : 'bg-blue-900/50';
const textColor = color === 'green' ? 'text-green-400' : 'text-blue-400';
return (
<div>
<h4 className={`text-xs font-semibold ${textColor} mb-1`}>{label}:</h4>
{cards.size === 0 ? (
<p className="text-gray-500 text-xs">{emptyLabel}</p>
) : (
<div className="flex flex-wrap gap-1">
{Array.from(cards.values()).map((item) => (
<div
key={item.card.id}
className={`flex items-center gap-1 ${bgColor} px-1.5 py-0.5 rounded text-xs`}
>
<span className="truncate max-w-[80px]">{item.card.name}</span>
<span className={textColor}>x{item.quantity}</span>
<button
onClick={() => onRemove(item.card.id)}
className="text-red-400 active:text-red-300"
>
<Minus size={12} />
</button>
</div>
))}
</div>
)}
</div>
);
};
// Loading state
if (loading) { if (loading) {
return ( return (
<div className="fixed inset-0 bg-black/80 z-50 flex items-center justify-center"> <div className="fixed inset-0 bg-black/80 z-50 flex items-center justify-center">
@@ -328,7 +352,6 @@ export default function TradeCreator({
{/* ============ MOBILE VIEW ============ */} {/* ============ MOBILE VIEW ============ */}
<div className="flex flex-col h-full md:hidden"> <div className="flex flex-col h-full md:hidden">
{/* Mobile Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-700"> <div className="flex items-center justify-between p-3 border-b border-gray-700">
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
<ArrowLeftRight size={20} className="text-blue-400 flex-shrink-0" /> <ArrowLeftRight size={20} className="text-blue-400 flex-shrink-0" />
@@ -339,7 +362,6 @@ export default function TradeCreator({
</button> </button>
</div> </div>
{/* Gift Toggle */}
<div className="p-3 border-b border-gray-700"> <div className="p-3 border-b border-gray-700">
<label className="flex items-center gap-3 cursor-pointer"> <label className="flex items-center gap-3 cursor-pointer">
<div <div
@@ -356,44 +378,29 @@ export default function TradeCreator({
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Gift size={18} className={isGiftMode ? 'text-purple-400' : 'text-gray-400'} /> <Gift size={18} className={isGiftMode ? 'text-purple-400' : 'text-gray-400'} />
<span className={isGiftMode ? 'text-purple-400' : 'text-gray-400'}> <span className={`text-sm ${isGiftMode ? 'text-purple-400' : 'text-gray-400'}`}>
This is a gift (I don't want anything back) Gift (I don't want anything back)
</span> </span>
</div> </div>
</label> </label>
</div> </div>
{/* Step Indicator */}
<div className="flex items-center justify-center gap-2 p-2 bg-gray-900/50"> <div className="flex items-center justify-center gap-2 p-2 bg-gray-900/50">
{!isGiftMode && ( {!isGiftMode && (
<> <>
<div <div className={`w-2 h-2 rounded-full ${mobileStep === 'want' ? 'bg-blue-500' : 'bg-gray-600'}`} />
className={`w-2 h-2 rounded-full ${mobileStep === 'want' ? 'bg-blue-500' : 'bg-gray-600'}`} <span className={`text-xs ${mobileStep === 'want' ? 'text-blue-400' : 'text-gray-500'}`}>I Want</span>
/>
<span className={`text-xs ${mobileStep === 'want' ? 'text-blue-400' : 'text-gray-500'}`}>
I Want
</span>
<ArrowRight size={14} className="text-gray-500" /> <ArrowRight size={14} className="text-gray-500" />
</> </>
)} )}
<div <div className={`w-2 h-2 rounded-full ${mobileStep === 'give' ? 'bg-green-500' : 'bg-gray-600'}`} />
className={`w-2 h-2 rounded-full ${mobileStep === 'give' ? 'bg-green-500' : 'bg-gray-600'}`} <span className={`text-xs ${mobileStep === 'give' ? 'text-green-400' : 'text-gray-500'}`}>I Give</span>
/>
<span className={`text-xs ${mobileStep === 'give' ? 'text-green-400' : 'text-gray-500'}`}>
I Give
</span>
<ArrowRight size={14} className="text-gray-500" /> <ArrowRight size={14} className="text-gray-500" />
<div <div className={`w-2 h-2 rounded-full ${mobileStep === 'review' ? 'bg-purple-500' : 'bg-gray-600'}`} />
className={`w-2 h-2 rounded-full ${mobileStep === 'review' ? 'bg-purple-500' : 'bg-gray-600'}`} <span className={`text-xs ${mobileStep === 'review' ? 'text-purple-400' : 'text-gray-500'}`}>Review</span>
/>
<span className={`text-xs ${mobileStep === 'review' ? 'text-purple-400' : 'text-gray-500'}`}>
Review
</span>
</div> </div>
{/* Mobile Content */}
<div className="flex-1 overflow-y-auto p-3"> <div className="flex-1 overflow-y-auto p-3">
{/* Step: Want (their collection) */}
{mobileStep === 'want' && !isGiftMode && ( {mobileStep === 'want' && !isGiftMode && (
<div> <div>
<h3 className="text-sm font-semibold text-blue-400 mb-3"> <h3 className="text-sm font-semibold text-blue-400 mb-3">
@@ -406,19 +413,18 @@ export default function TradeCreator({
onRemove={removeFromWanted} onRemove={removeFromWanted}
emptyMessage="Their collection is empty" emptyMessage="Their collection is empty"
selectionColor="blue" selectionColor="blue"
searchValue={theirCollectionSearch}
onSearchChange={setTheirCollectionSearch}
searchPlaceholder="Search their cards..."
/> />
</div> </div>
)} )}
{/* Step: Give (my collection) */}
{mobileStep === 'give' && ( {mobileStep === 'give' && (
<div> <div>
<h3 className="text-sm font-semibold text-green-400 mb-3"> <h3 className="text-sm font-semibold text-green-400 mb-3">
Select cards to {isGiftMode ? 'gift' : 'offer'} Select cards to {isGiftMode ? 'gift' : 'offer'}
</h3> </h3>
{myCollection.length === 0 ? (
<p className="text-gray-400 text-center py-8">Your collection is empty</p>
) : (
<CollectionGrid <CollectionGrid
items={myCollection} items={myCollection}
selectedCards={myOfferedCards} selectedCards={myOfferedCards}
@@ -426,17 +432,16 @@ export default function TradeCreator({
onRemove={removeFromOffer} onRemove={removeFromOffer}
emptyMessage="Your collection is empty" emptyMessage="Your collection is empty"
selectionColor="green" selectionColor="green"
searchValue={myCollectionSearch}
onSearchChange={setMyCollectionSearch}
searchPlaceholder="Search my cards..."
/> />
)}
</div> </div>
)} )}
{/* Step: Review */}
{mobileStep === 'review' && ( {mobileStep === 'review' && (
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-sm font-semibold text-purple-400">Review Trade</h3> <h3 className="text-sm font-semibold text-purple-400">Review Trade</h3>
{/* Summary */}
<div className="bg-gray-900/50 rounded-lg p-3 space-y-3"> <div className="bg-gray-900/50 rounded-lg p-3 space-y-3">
<SelectedCardsSummary <SelectedCardsSummary
cards={myOfferedCards} cards={myOfferedCards}
@@ -455,8 +460,6 @@ export default function TradeCreator({
/> />
)} )}
</div> </div>
{/* Message */}
<div> <div>
<label className="text-xs text-gray-400 mb-1 block">Message (optional)</label> <label className="text-xs text-gray-400 mb-1 block">Message (optional)</label>
<input <input
@@ -471,9 +474,7 @@ export default function TradeCreator({
)} )}
</div> </div>
{/* Mobile Footer */}
<div className="border-t border-gray-700 p-3 flex gap-2"> <div className="border-t border-gray-700 p-3 flex gap-2">
{/* Back button */}
{(mobileStep !== 'want' && !isGiftMode) || (mobileStep !== 'give' && isGiftMode) ? ( {(mobileStep !== 'want' && !isGiftMode) || (mobileStep !== 'give' && isGiftMode) ? (
<button <button
onClick={goToPrevStep} onClick={goToPrevStep}
@@ -492,7 +493,6 @@ export default function TradeCreator({
</button> </button>
)} )}
{/* Next/Submit button */}
{mobileStep === 'review' ? ( {mobileStep === 'review' ? (
<button <button
onClick={handleSubmit} onClick={handleSubmit}
@@ -532,7 +532,6 @@ export default function TradeCreator({
{/* ============ DESKTOP VIEW ============ */} {/* ============ DESKTOP VIEW ============ */}
<div className="hidden md:flex md:flex-col h-full"> <div className="hidden md:flex md:flex-col h-full">
{/* Desktop Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-700"> <div className="flex items-center justify-between p-4 border-b border-gray-700">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<ArrowLeftRight size={24} className="text-blue-400" /> <ArrowLeftRight size={24} className="text-blue-400" />
@@ -551,9 +550,7 @@ export default function TradeCreator({
/> />
</div> </div>
<Gift size={16} className={isGiftMode ? 'text-purple-400' : 'text-gray-400'} /> <Gift size={16} className={isGiftMode ? 'text-purple-400' : 'text-gray-400'} />
<span className={`text-sm ${isGiftMode ? 'text-purple-400' : 'text-gray-400'}`}> <span className={`text-sm ${isGiftMode ? 'text-purple-400' : 'text-gray-400'}`}>Gift mode</span>
Gift mode
</span>
</label> </label>
</div> </div>
<button onClick={onClose} className="p-2 hover:bg-gray-700 rounded-lg transition"> <button onClick={onClose} className="p-2 hover:bg-gray-700 rounded-lg transition">
@@ -561,13 +558,9 @@ export default function TradeCreator({
</button> </button>
</div> </div>
{/* Desktop Content */}
<div className="flex-1 overflow-hidden flex"> <div className="flex-1 overflow-hidden flex">
{/* My Collection (Left) */}
<div className="flex-1 p-4 border-r border-gray-700 overflow-y-auto"> <div className="flex-1 p-4 border-r border-gray-700 overflow-y-auto">
<h3 className="text-lg font-semibold mb-3 text-green-400"> <h3 className="text-lg font-semibold mb-3 text-green-400">My Collection (I give)</h3>
My Collection (I give)
</h3>
<CollectionGrid <CollectionGrid
items={myCollection} items={myCollection}
selectedCards={myOfferedCards} selectedCards={myOfferedCards}
@@ -575,10 +568,12 @@ export default function TradeCreator({
onRemove={removeFromOffer} onRemove={removeFromOffer}
emptyMessage="Your collection is empty" emptyMessage="Your collection is empty"
selectionColor="green" selectionColor="green"
searchValue={myCollectionSearch}
onSearchChange={setMyCollectionSearch}
searchPlaceholder="Search my cards..."
/> />
</div> </div>
{/* Their Collection (Right) */}
{!isGiftMode && ( {!isGiftMode && (
<div className="flex-1 p-4 overflow-y-auto"> <div className="flex-1 p-4 overflow-y-auto">
<h3 className="text-lg font-semibold mb-3 text-blue-400"> <h3 className="text-lg font-semibold mb-3 text-blue-400">
@@ -591,12 +586,14 @@ export default function TradeCreator({
onRemove={removeFromWanted} onRemove={removeFromWanted}
emptyMessage="Their collection is empty" emptyMessage="Their collection is empty"
selectionColor="blue" selectionColor="blue"
searchValue={theirCollectionSearch}
onSearchChange={setTheirCollectionSearch}
searchPlaceholder="Search their cards..."
/> />
</div> </div>
)} )}
</div> </div>
{/* Desktop Footer */}
<div className="border-t border-gray-700 p-4"> <div className="border-t border-gray-700 p-4">
<div className="flex gap-6 mb-4"> <div className="flex gap-6 mb-4">
<SelectedCardsSummary <SelectedCardsSummary