This repository has no description
0

Configure Feed

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

semble / src / webapp / components / AddToCollectionModal.tsx
4.4 kB 169 lines
1'use client'; 2 3import { useState, useEffect, useMemo } from 'react'; 4import { getAccessToken } from '@/services/auth'; 5import { ApiClient } from '@/api-client/ApiClient'; 6import { Button, Group, Modal, Stack, Text } from '@mantine/core'; 7import { CollectionSelector } from './CollectionSelector'; 8 9interface Collection { 10 id: string; 11 name: string; 12 description?: string; 13 cardCount: number; 14 authorId: string; 15} 16 17interface AddToCollectionModalProps { 18 cardId: string; 19 isOpen: boolean; 20 onClose: () => void; 21 onSuccess?: () => void; 22} 23 24export function AddToCollectionModal({ 25 cardId, 26 isOpen, 27 onClose, 28 onSuccess, 29}: AddToCollectionModalProps) { 30 const [selectedCollectionIds, setSelectedCollectionIds] = useState<string[]>( 31 [], 32 ); 33 const [submitting, setSubmitting] = useState(false); 34 const [error, setError] = useState(''); 35 const [card, setCard] = useState<any>(null); 36 const [loading, setLoading] = useState(false); 37 38 // Create API client instance 39 const apiClient = new ApiClient( 40 process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', 41 () => getAccessToken(), 42 ); 43 44 // Get existing collections for this card 45 const existingCollections = useMemo(() => { 46 if (!card) return []; 47 return card.collections || []; 48 }, [card]); 49 50 useEffect(() => { 51 if (isOpen) { 52 fetchCard(); 53 } 54 }, [isOpen, cardId]); 55 56 const fetchCard = async () => { 57 try { 58 setLoading(true); 59 setError(''); 60 const response = await apiClient.getUrlCardView(cardId); 61 setCard(response); 62 } catch (error: any) { 63 console.error('Error fetching card:', error); 64 setError(error.message || 'Failed to load card details'); 65 } finally { 66 setLoading(false); 67 } 68 }; 69 70 const handleSubmit = async () => { 71 if (selectedCollectionIds.length === 0) { 72 setError('Please select at least one collection'); 73 return; 74 } 75 76 setSubmitting(true); 77 setError(''); 78 79 try { 80 // Add card to all selected collections in a single request 81 await apiClient.addCardToCollection({ 82 cardId, 83 collectionIds: selectedCollectionIds, 84 }); 85 86 // Success 87 onSuccess?.(); 88 onClose(); 89 setSelectedCollectionIds([]); 90 } catch (error: any) { 91 console.error('Error adding card to collections:', error); 92 setError(error.message || 'Failed to add card to collections'); 93 } finally { 94 setSubmitting(false); 95 } 96 }; 97 98 const handleClose = () => { 99 if (!submitting) { 100 onClose(); 101 setSelectedCollectionIds([]); 102 setError(''); 103 } 104 }; 105 106 if (!isOpen) return null; 107 108 return ( 109 <Modal 110 opened={isOpen} 111 onClose={handleClose} 112 title="Add to Collections" 113 centered 114 size="md" 115 > 116 <Stack p="sm"> 117 {loading ? ( 118 <Text size="sm" c="dimmed" ta="center" py="md"> 119 Loading card details... 120 </Text> 121 ) : error ? ( 122 <Stack align="center"> 123 <Text c="red">{error}</Text> 124 <Button onClick={fetchCard} variant="outline" size="sm"> 125 Try Again 126 </Button> 127 </Stack> 128 ) : ( 129 <> 130 <CollectionSelector 131 apiClient={apiClient} 132 selectedCollectionIds={selectedCollectionIds} 133 onSelectionChange={setSelectedCollectionIds} 134 existingCollections={existingCollections} 135 disabled={submitting} 136 showCreateOption={true} 137 placeholder="Search collections to add..." 138 /> 139 140 {error && ( 141 <Text c="red" size="sm"> 142 {error} 143 </Text> 144 )} 145 146 <Group gap={'xs'} grow> 147 <Button 148 onClick={handleSubmit} 149 disabled={submitting || selectedCollectionIds.length === 0} 150 loading={submitting} 151 > 152 {submitting 153 ? 'Adding...' 154 : `Add to ${selectedCollectionIds.length} Collection${selectedCollectionIds.length !== 1 ? 's' : ''}`} 155 </Button> 156 <Button 157 variant="outline" 158 onClick={handleClose} 159 disabled={submitting} 160 > 161 Cancel 162 </Button> 163 </Group> 164 </> 165 )} 166 </Stack> 167 </Modal> 168 ); 169}