This repository has no description
0

Configure Feed

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

semble / src / webapp / features / cards / containers / cardsContainerContent / CardsContainerContent.tsx
3.6 kB 116 lines
1import { CardSortField, SortOrder, UrlType } from '@semble/types'; 2import CardsContainerSkeleton from '../cardsContainer/Skeleton.CardsContainer'; 3import CardsContainerError from '../cardsContainer/Error.CardsContainer'; 4import { Container, Grid } from '@mantine/core'; 5import ProfileEmptyTab from '@/features/profile/components/profileEmptyTab/ProfileEmptyTab'; 6import InfiniteScroll from '@/components/contentDisplay/infiniteScroll/InfiniteScroll'; 7import UrlCard from '../../components/urlCard/UrlCard'; 8import useCards from '../../lib/queries/useCards'; 9import { useNavbarContext } from '@/providers/navbar'; 10import { FaRegNoteSticky } from 'react-icons/fa6'; 11import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings'; 12import { useSearchParams, usePathname } from 'next/navigation'; 13import { CardSaveSource } from '@/features/analytics/types'; 14 15interface Props { 16 handle: string; 17} 18 19const sortOrderMap: Record<CardSortField, SortOrder> = { 20 [CardSortField.UPDATED_AT]: SortOrder.DESC, 21 [CardSortField.CREATED_AT]: SortOrder.ASC, 22 [CardSortField.LIBRARY_COUNT]: SortOrder.DESC, 23}; 24 25export default function CardsContainerContent(props: Props) { 26 const pathname = usePathname(); 27 const { desktopOpened } = useNavbarContext(); 28 const { settings } = useUserSettings(); 29 30 const searchParams = useSearchParams(); 31 const selectedUrlType = searchParams.get('type') as UrlType; 32 33 const sortBy = 34 (searchParams.get('sort') as CardSortField) ?? CardSortField.UPDATED_AT; 35 36 const { 37 data, 38 error, 39 fetchNextPage, 40 hasNextPage, 41 isFetchingNextPage, 42 isPending, 43 } = useCards({ 44 didOrHandle: props.handle, 45 sortBy: sortBy, 46 sortOrder: sortOrderMap[sortBy], 47 urlType: selectedUrlType, 48 }); 49 50 const allCards = data?.pages.flatMap((page) => page.cards ?? []) ?? []; 51 52 if (isPending) { 53 return <CardsContainerSkeleton />; 54 } 55 56 if (error) { 57 return <CardsContainerError />; 58 } 59 60 if (allCards.length === 0) { 61 return ( 62 <Container px="xs" py={'xl'} size="xl"> 63 <ProfileEmptyTab 64 message={selectedUrlType ? `No ${selectedUrlType} cards` : 'No cards'} 65 icon={FaRegNoteSticky} 66 /> 67 </Container> 68 ); 69 } 70 71 return ( 72 <InfiniteScroll 73 dataLength={allCards.length} 74 hasMore={!!hasNextPage} 75 isInitialLoading={isPending} 76 isLoading={isFetchingNextPage} 77 loadMore={fetchNextPage} 78 > 79 <Grid gutter="xs"> 80 {allCards.map((card) => ( 81 <Grid.Col 82 key={card.id} 83 span={{ 84 base: 12, 85 xs: settings.cardView !== 'grid' ? 12 : desktopOpened ? 12 : 6, 86 sm: settings.cardView !== 'grid' ? 12 : desktopOpened ? 6 : 4, 87 md: settings.cardView !== 'grid' ? 12 : 4, 88 lg: settings.cardView !== 'grid' ? 12 : 3, 89 }} 90 > 91 <UrlCard 92 id={card.id} 93 url={card.url} 94 uri={card.uri} 95 cardContent={card.cardContent} 96 note={card.note} 97 authorHandle={props.handle} 98 cardAuthor={card.author} 99 urlLibraryCount={card.urlLibraryCount} 100 urlIsInLibrary={card.urlInLibrary} 101 viaCardId={card.id} 102 analyticsContext={{ 103 saveSource: CardSaveSource.PROFILE, 104 activeFilters: { 105 urlType: selectedUrlType, 106 sort: sortBy, 107 }, 108 pagePath: pathname, 109 }} 110 /> 111 </Grid.Col> 112 ))} 113 </Grid> 114 </InfiniteScroll> 115 ); 116}