This repository has no description
0

Configure Feed

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

semble / src / webapp / features / home / components / recentCollections / RecentCollections.tsx
7.0 kB 258 lines
1'use client'; 2 3import CollectionCard from '@/features/collections/components/collectionCard/CollectionCard'; 4import CollectionCardSkeleton from '@/features/collections/components/collectionCard/Skeleton.CollectionCard'; 5import CreateCollectionDrawer from '@/features/collections/components/createCollectionDrawer/CreateCollectionDrawer'; 6import useMyCollections from '@/features/collections/lib/queries/useMyCollections'; 7import useOpenCollectionsWithContributor from '@/features/collections/lib/queries/useOpenCollectionsWithContributor'; 8import useFollowingCollections from '@/features/follows/lib/queries/useFollowingCollections'; 9import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; 10import { 11 Stack, 12 Button, 13 Text, 14 SimpleGrid, 15 Group, 16 Title, 17 ActionIcon, 18} from '@mantine/core'; 19import { Suspense, useState } from 'react'; 20import { BiCollection } from 'react-icons/bi'; 21import { FiPlus } from 'react-icons/fi'; 22import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings'; 23import { LinkButton } from '@/components/link/MantineLink'; 24 25type CollectionFilter = 'mine' | 'following' | 'contributed'; 26 27function CollectionsListSkeleton() { 28 return ( 29 <SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="xs"> 30 {Array.from({ length: 4 }).map((_, i) => ( 31 <CollectionCardSkeleton key={i} /> 32 ))} 33 </SimpleGrid> 34 ); 35} 36 37function MyCollectionsList({ 38 onCreateCollection, 39 settings, 40}: { 41 onCreateCollection: () => void; 42 settings: ReturnType<typeof useUserSettings>['settings']; 43}) { 44 const { data: collectionsData } = useMyCollections({ limit: 4 }); 45 const collections = 46 collectionsData.pages.flatMap((page) => page.collections) ?? []; 47 48 if (collections.length === 0) { 49 return ( 50 <Stack align="center" gap="xs"> 51 <Text fz="h3" fw={600} c="gray"> 52 No collections 53 </Text> 54 <Button 55 onClick={onCreateCollection} 56 variant="light" 57 color="gray" 58 size="md" 59 rightSection={<FiPlus size={22} />} 60 > 61 Create your first collection 62 </Button> 63 </Stack> 64 ); 65 } 66 67 return ( 68 <SimpleGrid 69 cols={ 70 settings.collectionView !== 'grid' 71 ? { base: 1 } 72 : { base: 1, sm: 2, lg: 4 } 73 } 74 spacing="xs" 75 > 76 {collections.map((collection) => ( 77 <CollectionCard key={collection.id} collection={collection} /> 78 ))} 79 </SimpleGrid> 80 ); 81} 82 83function FollowingCollectionsList({ 84 identifier, 85 settings, 86}: { 87 identifier: string; 88 settings: ReturnType<typeof useUserSettings>['settings']; 89}) { 90 const { data: collectionsData } = useFollowingCollections({ 91 identifier, 92 limit: 4, 93 }); 94 const collections = 95 collectionsData.pages.flatMap((page) => page.collections) ?? []; 96 97 if (collections.length === 0) { 98 return ( 99 <Stack align="center" gap="xs"> 100 <Text fz="h3" fw={600} c="gray"> 101 Not following any collections 102 </Text> 103 </Stack> 104 ); 105 } 106 107 return ( 108 <SimpleGrid 109 cols={ 110 settings.collectionView !== 'grid' 111 ? { base: 1 } 112 : { base: 1, sm: 2, lg: 4 } 113 } 114 spacing="xs" 115 > 116 {collections.map((collection) => ( 117 <CollectionCard key={collection.id} collection={collection} /> 118 ))} 119 </SimpleGrid> 120 ); 121} 122 123function ContributedCollectionsList({ 124 identifier, 125 settings, 126}: { 127 identifier: string; 128 settings: ReturnType<typeof useUserSettings>['settings']; 129}) { 130 const { data: collectionsData } = useOpenCollectionsWithContributor({ 131 identifier, 132 limit: 4, 133 }); 134 const collections = 135 collectionsData.pages.flatMap((page) => page.collections) ?? []; 136 137 if (collections.length === 0) { 138 return ( 139 <Stack align="center" gap="xs"> 140 <Text fz="h3" fw={600} c="gray"> 141 No collections contributed to 142 </Text> 143 </Stack> 144 ); 145 } 146 147 return ( 148 <SimpleGrid 149 cols={ 150 settings.collectionView !== 'grid' 151 ? { base: 1 } 152 : { base: 1, sm: 2, lg: 4 } 153 } 154 spacing="xs" 155 > 156 {collections.map((collection) => ( 157 <CollectionCard key={collection.id} collection={collection} /> 158 ))} 159 </SimpleGrid> 160 ); 161} 162 163export default function RecentCollections() { 164 const { settings } = useUserSettings(); 165 const [showCollectionDrawer, setShowCollectionDrawer] = useState(false); 166 const [filter, setFilter] = useState<CollectionFilter>('mine'); 167 const { data: profile } = useMyProfile(); 168 169 const viewAllHref = { 170 mine: `/profile/${profile.handle}/collections`, 171 following: `/profile/${profile.handle}/network/collections-following`, 172 contributed: `/profile/${profile.handle}/network/contributed-to`, 173 }[filter]; 174 175 return ( 176 <Stack> 177 <Group justify="space-between"> 178 <Group gap="xs"> 179 <BiCollection size={22} /> 180 <Title order={2}>Collections</Title> 181 </Group> 182 <Group gap="xs"> 183 {filter === 'mine' && ( 184 <ActionIcon 185 variant="light" 186 color="blue" 187 size={38} 188 radius={'xl'} 189 onClick={() => setShowCollectionDrawer(true)} 190 aria-label="Create collection" 191 > 192 <FiPlus size={18} /> 193 </ActionIcon> 194 )} 195 <LinkButton variant="light" color="blue" href={viewAllHref}> 196 View all 197 </LinkButton> 198 </Group> 199 </Group> 200 201 <Group gap={'xs'}> 202 <Button 203 variant={filter === 'mine' ? 'filled' : 'light'} 204 color="gray" 205 size="xs" 206 radius={'md'} 207 onClick={() => setFilter('mine')} 208 > 209 My Collections 210 </Button> 211 <Button 212 variant={filter === 'following' ? 'filled' : 'light'} 213 color="gray" 214 size="xs" 215 radius={'md'} 216 onClick={() => setFilter('following')} 217 > 218 Following 219 </Button> 220 <Button 221 variant={filter === 'contributed' ? 'filled' : 'light'} 222 color="gray" 223 size="xs" 224 radius={'md'} 225 onClick={() => setFilter('contributed')} 226 > 227 Contributed to 228 </Button> 229 </Group> 230 231 <Suspense fallback={<CollectionsListSkeleton />}> 232 {filter === 'mine' && ( 233 <MyCollectionsList 234 onCreateCollection={() => setShowCollectionDrawer(true)} 235 settings={settings} 236 /> 237 )} 238 {filter === 'following' && ( 239 <FollowingCollectionsList 240 identifier={profile.handle} 241 settings={settings} 242 /> 243 )} 244 {filter === 'contributed' && ( 245 <ContributedCollectionsList 246 identifier={profile.handle} 247 settings={settings} 248 /> 249 )} 250 </Suspense> 251 252 <CreateCollectionDrawer 253 isOpen={showCollectionDrawer} 254 onClose={() => setShowCollectionDrawer(false)} 255 /> 256 </Stack> 257 ); 258}