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 / components / urlCardActions / UrlCardActions.tsx
8.6 kB 274 lines
1'use client'; 2 3import { 4 type UrlCard, 5 type Collection, 6 type User, 7 CollectionAccessType, 8} from '@/api-client'; 9import { ActionIcon, Button, CopyButton, Group, Menu } from '@mantine/core'; 10import { Fragment, useState } from 'react'; 11import { FiPlus } from 'react-icons/fi'; 12import { BsThreeDots, BsTrash2Fill } from 'react-icons/bs'; 13import RemoveCardFromCollectionModal from '../removeCardFromCollectionModal/RemoveCardFromCollectionModal'; 14import RemoveCardFromLibraryModal from '../removeCardFromLibraryModal/RemoveCardFromLibraryModal'; 15import AddCardToModal from '@/features/cards/components/addCardToModal/AddCardToModal'; 16import { MdIosShare, MdOutlineStickyNote2 } from 'react-icons/md'; 17import NoteCardModal from '@/features/notes/components/noteCardModal/NoteCardModal'; 18import { useAuth } from '@/hooks/useAuth'; 19import { IoMdCheckmark } from 'react-icons/io'; 20import { notifications } from '@mantine/notifications'; 21import { BiCopy } from 'react-icons/bi'; 22import { CardSaveAnalyticsContext } from '@/features/analytics/types'; 23import { TbPlugConnected } from 'react-icons/tb'; 24import AddConnectionModal from '@/features/connections/components/addConnectionModal/AddConnectionModal'; 25import { AiOutlineDisconnect } from 'react-icons/ai'; 26import { useWebHaptics } from 'web-haptics/react'; 27 28interface Props { 29 id: string; 30 cardContent: UrlCard['cardContent']; 31 cardCount: number; 32 cardAuthor?: User; 33 authorHandle?: string; 34 note?: UrlCard['note']; 35 currentCollection?: Collection; 36 urlLibraryCount: number; 37 urlIsInLibrary: boolean; 38 urlIsConnected?: boolean; 39 urlConnectionCount: number; 40 viaCardId?: string; 41 semblePageUrl?: string; 42 analyticsContext?: CardSaveAnalyticsContext; 43} 44 45export default function UrlCardActions(props: Props) { 46 const { isAuthenticated, user } = useAuth(); 47 48 const userId = user?.id; 49 const userHandle = user?.handle; 50 51 const isAuthor = 52 !!user && 53 (props.authorHandle 54 ? userHandle === props.authorHandle 55 : userId === props.cardAuthor?.id); 56 57 const isOpenCollection = 58 props.currentCollection?.accessType === CollectionAccessType.OPEN; 59 60 const isCardAdder = userId === props.cardAuthor?.id; 61 const isCollectionOwner = userId === props.currentCollection?.author.id; 62 63 const canRemoveFromOpenCollection = 64 !!user && isOpenCollection && (isCardAdder || isCollectionOwner); 65 66 const canRemoveFromLibrary = isAuthor && props.urlIsInLibrary; 67 68 const [showNoteModal, setShowNoteModal] = useState(false); 69 const [showRemoveFromCollectionModal, setShowRemoveFromCollectionModal] = 70 useState(false); 71 const [showRemoveFromLibaryModal, setShowRemoveFromLibraryModal] = 72 useState(false); 73 const [showAddToModal, setShowAddToModal] = useState(false); 74 const [showAddConnectionModal, setShowAddConnectionModal] = useState(false); 75 76 const { trigger } = useWebHaptics(); 77 78 if (!isAuthenticated) { 79 return null; 80 } 81 82 return ( 83 <Fragment> 84 <Group justify="space-between"> 85 <Group gap={'xs'}> 86 <Button 87 variant="light" 88 color={'gray'} 89 size="xs" 90 radius={'xl'} 91 leftSection={ 92 props.urlLibraryCount > 0 ? ( 93 props.urlIsInLibrary ? ( 94 <IoMdCheckmark size={18} /> 95 ) : ( 96 <FiPlus size={18} /> 97 ) 98 ) : undefined 99 } 100 onClick={(e) => { 101 e.stopPropagation(); 102 trigger(); 103 setShowAddToModal(true); 104 }} 105 > 106 {props.urlLibraryCount ? ( 107 props.urlLibraryCount 108 ) : props.urlIsInLibrary ? ( 109 <IoMdCheckmark size={18} /> 110 ) : ( 111 <FiPlus size={18} /> 112 )} 113 </Button> 114 <Button 115 variant="light" 116 color="gray" 117 c={props.urlIsConnected ? 'green' : 'gray'} 118 size="xs" 119 radius={'xl'} 120 leftSection={ 121 props.urlConnectionCount > 0 ? ( 122 <TbPlugConnected size={15} /> 123 ) : undefined 124 } 125 onClick={(e) => { 126 e.stopPropagation(); 127 trigger(); 128 setShowAddConnectionModal(true); 129 }} 130 > 131 {props.urlConnectionCount ? ( 132 props.urlConnectionCount 133 ) : ( 134 <TbPlugConnected size={15} /> 135 )} 136 </Button> 137 138 {props.note && ( 139 <ActionIcon 140 variant="light" 141 color="gray" 142 radius={'xl'} 143 onClick={(e) => { 144 e.stopPropagation(); 145 setShowNoteModal(true); 146 }} 147 > 148 <MdOutlineStickyNote2 /> 149 </ActionIcon> 150 )} 151 </Group> 152 153 <Menu shadow="sm"> 154 <Menu.Target> 155 <ActionIcon 156 variant="light" 157 color={'gray'} 158 radius={'xl'} 159 onClick={(e) => e.stopPropagation()} 160 > 161 <BsThreeDots size={18} /> 162 </ActionIcon> 163 </Menu.Target> 164 <Menu.Dropdown> 165 <CopyButton value={props.cardContent.url}> 166 {({ copy }) => ( 167 <Menu.Item 168 leftSection={<BiCopy />} 169 onClick={(e) => { 170 e.stopPropagation(); 171 copy(); 172 notifications.show({ 173 message: 'Link copied!', 174 position: 'top-center', 175 }); 176 }} 177 > 178 Copy link 179 </Menu.Item> 180 )} 181 </CopyButton> 182 183 <CopyButton 184 value={`${process.env.NEXT_PUBLIC_APP_URL}/url?id=${props.cardContent.url}`} 185 > 186 {({ copy }) => ( 187 <Menu.Item 188 leftSection={<MdIosShare />} 189 onClick={(e) => { 190 e.stopPropagation(); 191 copy(); 192 notifications.show({ 193 message: 'Semble link copied!', 194 position: 'top-center', 195 }); 196 }} 197 > 198 Share Semble page 199 </Menu.Item> 200 )} 201 </CopyButton> 202 203 {props.currentCollection && 204 (isAuthor || canRemoveFromOpenCollection) && ( 205 <Menu.Item 206 leftSection={<AiOutlineDisconnect />} 207 onClick={(e) => { 208 e.stopPropagation(); 209 setShowRemoveFromCollectionModal(true); 210 }} 211 > 212 Remove from this collection 213 </Menu.Item> 214 )} 215 {canRemoveFromLibrary && ( 216 <Menu.Item 217 color="red" 218 leftSection={<BsTrash2Fill />} 219 onClick={(e) => { 220 e.stopPropagation(); 221 setShowRemoveFromLibraryModal(true); 222 }} 223 > 224 Remove from library 225 </Menu.Item> 226 )} 227 </Menu.Dropdown> 228 </Menu> 229 </Group> 230 231 <AddCardToModal 232 isOpen={showAddToModal} 233 onClose={() => setShowAddToModal(false)} 234 url={props.cardContent.url} 235 cardContent={props.cardContent} 236 cardId={props.id} 237 note={props.note?.text} 238 isInYourLibrary={props.urlIsInLibrary} 239 urlLibraryCount={props.urlLibraryCount} 240 viaCardId={props.viaCardId} 241 analyticsContext={props.analyticsContext} 242 /> 243 244 <AddConnectionModal 245 isOpen={showAddConnectionModal} 246 onClose={() => setShowAddConnectionModal(false)} 247 sourceUrl={props.cardContent.url} 248 targetUrl={props.semblePageUrl} 249 /> 250 251 <NoteCardModal 252 isOpen={showNoteModal} 253 onClose={() => setShowNoteModal(false)} 254 note={props.note} 255 cardContent={props.cardContent} 256 cardAuthor={props.cardAuthor} 257 /> 258 259 {props.currentCollection && ( 260 <RemoveCardFromCollectionModal 261 isOpen={showRemoveFromCollectionModal} 262 onClose={() => setShowRemoveFromCollectionModal(false)} 263 cardId={props.id} 264 collectionId={props.currentCollection.id} 265 /> 266 )} 267 <RemoveCardFromLibraryModal 268 isOpen={showRemoveFromLibaryModal} 269 onClose={() => setShowRemoveFromLibraryModal(false)} 270 cardId={props.id} 271 /> 272 </Fragment> 273 ); 274}