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