This repository has no description
0

Configure Feed

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

feat: add collection filters to recent collections

+214 -49
+208 -49
src/webapp/features/home/components/recentCollections/RecentCollections.tsx
··· 1 1 'use client'; 2 2 3 3 import CollectionCard from '@/features/collections/components/collectionCard/CollectionCard'; 4 + import CollectionCardSkeleton from '@/features/collections/components/collectionCard/Skeleton.CollectionCard'; 4 5 import CreateCollectionDrawer from '@/features/collections/components/createCollectionDrawer/CreateCollectionDrawer'; 5 6 import useMyCollections from '@/features/collections/lib/queries/useMyCollections'; 7 + import useOpenCollectionsWithContributor from '@/features/collections/lib/queries/useOpenCollectionsWithContributor'; 8 + import useFollowingCollections from '@/features/follows/lib/queries/useFollowingCollections'; 6 9 import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; 7 10 import { 8 11 Stack, ··· 13 16 Title, 14 17 ActionIcon, 15 18 } from '@mantine/core'; 16 - import { Fragment, useState } from 'react'; 19 + import { Suspense, useState } from 'react'; 17 20 import { BiCollection } from 'react-icons/bi'; 18 21 import { FiPlus } from 'react-icons/fi'; 19 22 import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings'; 20 23 import { LinkButton } from '@/components/link/MantineLink'; 21 24 25 + type CollectionFilter = 'mine' | 'following' | 'contributed'; 26 + 27 + function 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 + 37 + function 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 + 83 + function 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 + 123 + function 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 + 22 163 export default function RecentCollections() { 23 164 const { settings } = useUserSettings(); 24 165 const [showCollectionDrawer, setShowCollectionDrawer] = useState(false); 166 + const [filter, setFilter] = useState<CollectionFilter>('mine'); 25 167 const { data: profile } = useMyProfile(); 26 - const { data: collectionsData } = useMyCollections({ limit: 4 }); 27 - const collections = 28 - collectionsData.pages.flatMap((page) => page.collections) ?? []; 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]; 29 174 30 175 return ( 31 176 <Stack> ··· 35 180 <Title order={2}>Collections</Title> 36 181 </Group> 37 182 <Group gap="xs"> 38 - <ActionIcon 39 - variant="light" 40 - color="blue" 41 - size={38} 42 - radius={'xl'} 43 - onClick={() => setShowCollectionDrawer(true)} 44 - aria-label="Create collection" 45 - > 46 - <FiPlus size={18} /> 47 - </ActionIcon> 48 - <LinkButton 49 - variant="light" 50 - color="blue" 51 - href={`/profile/${profile.handle}/collections`} 52 - > 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}> 53 196 View all 54 197 </LinkButton> 55 198 </Group> 56 199 </Group> 57 200 58 - {collections.length > 0 ? ( 59 - <SimpleGrid 60 - cols={ 61 - settings.collectionView !== 'grid' 62 - ? { base: 1 } 63 - : { base: 1, sm: 2, lg: 4 } 64 - } 65 - spacing="xs" 201 + <Group gap={'xs'}> 202 + <Button 203 + variant={filter === 'mine' ? 'filled' : 'light'} 204 + color="gray" 205 + size="xs" 206 + onClick={() => setFilter('mine')} 66 207 > 67 - {collections.map((collection) => ( 68 - <CollectionCard key={collection.id} collection={collection} /> 69 - ))} 70 - </SimpleGrid> 71 - ) : ( 72 - <Fragment> 73 - <Stack align="center" gap="xs"> 74 - <Text fz="h3" fw={600} c="gray"> 75 - No collections 76 - </Text> 77 - <Button 78 - onClick={() => setShowCollectionDrawer(true)} 79 - variant="light" 80 - color="gray" 81 - size="md" 82 - rightSection={<FiPlus size={22} />} 83 - > 84 - Create your first collection 85 - </Button> 86 - </Stack> 87 - </Fragment> 88 - )} 208 + Mine 209 + </Button> 210 + <Button 211 + variant={filter === 'following' ? 'filled' : 'light'} 212 + color="gray" 213 + size="xs" 214 + onClick={() => setFilter('following')} 215 + > 216 + Following 217 + </Button> 218 + <Button 219 + variant={filter === 'contributed' ? 'filled' : 'light'} 220 + color="gray" 221 + size="xs" 222 + onClick={() => setFilter('contributed')} 223 + > 224 + Contributed to 225 + </Button> 226 + </Group> 227 + 228 + <Suspense fallback={<CollectionsListSkeleton />}> 229 + {filter === 'mine' && ( 230 + <MyCollectionsList 231 + onCreateCollection={() => setShowCollectionDrawer(true)} 232 + settings={settings} 233 + /> 234 + )} 235 + {filter === 'following' && ( 236 + <FollowingCollectionsList 237 + identifier={profile.handle} 238 + settings={settings} 239 + /> 240 + )} 241 + {filter === 'contributed' && ( 242 + <ContributedCollectionsList 243 + identifier={profile.handle} 244 + settings={settings} 245 + /> 246 + )} 247 + </Suspense> 89 248 90 249 <CreateCollectionDrawer 91 250 isOpen={showCollectionDrawer}
+6
src/webapp/features/home/components/recentCollections/Skeleton.RecentCollections.tsx
··· 16 16 </Group> 17 17 </Group> 18 18 19 + <Group gap="xs"> 20 + <Skeleton w={56} h={30} radius={'xl'} /> 21 + <Skeleton w={82} h={30} radius={'xl'} /> 22 + <Skeleton w={110} h={30} radius={'xl'} /> 23 + </Group> 24 + 19 25 <SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="xs"> 20 26 {Array.from({ length: 4 }).map((_, i) => ( 21 27 <CollectionCardSkeleton key={i} />