A social knowledge tool for researchers built on ATProto

feat: note deletion

+152 -41
+2
src/webapp/features/cards/components/addCardToModal/AddCardToModalContent.tsx
··· 130 130 thumbnailUrl={metadata.imageUrl} 131 131 title={metadata.title} 132 132 note={isMyCard ? note : cardStatus.data.card?.note?.text} 133 + noteId={cardStatus.data.card?.note?.id} 133 134 onUpdateNote={setNote} 135 + onClose={props.onClose} 134 136 /> 135 137 136 138 <CollectionSelector
+91 -35
src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx
··· 12 12 } from '@mantine/core'; 13 13 import Link from 'next/link'; 14 14 import { Dispatch, SetStateAction, useState } from 'react'; 15 - import { UrlCard } from '@/api-client'; 16 15 import { getDomain } from '@/lib/utils/link'; 16 + import useRemoveCardFromLibrary from '../../lib/mutations/useRemoveCardFromLibrary'; 17 + import { notifications } from '@mantine/notifications'; 17 18 18 19 interface Props { 19 20 url: string; 20 21 thumbnailUrl?: string; 21 22 title?: string; 22 23 note?: string; 24 + noteId?: string; 23 25 onUpdateNote: Dispatch<SetStateAction<string | undefined>>; 26 + onClose: () => void; 24 27 } 25 28 26 29 export default function CardToBeAddedPreview(props: Props) { 30 + const [showDeleteWarning, setShowDeleteWarning] = useState(false); 27 31 const [noteMode, setNoteMode] = useState(false); 28 32 const [note, setNote] = useState(props.note); 29 33 const domain = getDomain(props.url); 34 + 35 + const removeNote = useRemoveCardFromLibrary(); 36 + 37 + const handleDeleteNote = () => { 38 + if (!props.noteId) return; 39 + 40 + removeNote.mutate(props.noteId, { 41 + onError: () => { 42 + notifications.show({ 43 + message: 'Could not delete note.', 44 + position: 'top-center', 45 + }); 46 + }, 47 + onSettled: () => { 48 + props.onClose(); 49 + }, 50 + }); 51 + }; 30 52 31 53 if (noteMode) { 32 54 return ( ··· 76 98 } 77 99 78 100 return ( 79 - <Card withBorder component="article" p={'xs'} radius={'lg'}> 80 - <Stack> 81 - <Group gap={'sm'} justify="space-between"> 82 - {props.thumbnailUrl && ( 83 - <AspectRatio ratio={1 / 1} flex={0.1}> 84 - <Image 85 - src={props.thumbnailUrl} 86 - alt={`${props.url} social preview image`} 87 - radius={'md'} 88 - w={50} 89 - h={50} 90 - /> 91 - </AspectRatio> 92 - )} 93 - <Stack gap={0} flex={0.9}> 94 - <Tooltip label={props.url}> 95 - <Anchor 96 - component={Link} 97 - href={props.url} 98 - target="_blank" 99 - c={'gray'} 100 - lineClamp={1} 101 - onClick={(e) => e.stopPropagation()} 102 - > 103 - {domain} 104 - </Anchor> 105 - </Tooltip> 106 - {props.title && ( 107 - <Text fw={500} lineClamp={1}> 108 - {props.title} 109 - </Text> 101 + <Stack gap={'xs'}> 102 + <Card withBorder component="article" p={'xs'} radius={'lg'}> 103 + <Stack> 104 + <Group gap={'sm'} justify="space-between"> 105 + {props.thumbnailUrl && ( 106 + <AspectRatio ratio={1 / 1} flex={0.1}> 107 + <Image 108 + src={props.thumbnailUrl} 109 + alt={`${props.url} social preview image`} 110 + radius={'md'} 111 + w={50} 112 + h={50} 113 + /> 114 + </AspectRatio> 110 115 )} 111 - </Stack> 116 + <Stack gap={0} flex={0.9}> 117 + <Tooltip label={props.url}> 118 + <Anchor 119 + component={Link} 120 + href={props.url} 121 + target="_blank" 122 + c={'gray'} 123 + lineClamp={1} 124 + onClick={(e) => e.stopPropagation()} 125 + > 126 + {domain} 127 + </Anchor> 128 + </Tooltip> 129 + {props.title && ( 130 + <Text fw={500} lineClamp={1}> 131 + {props.title} 132 + </Text> 133 + )} 134 + </Stack> 135 + </Group> 136 + </Stack> 137 + </Card> 138 + {showDeleteWarning ? ( 139 + <Group justify="space-between" gap={'xs'}> 140 + <Text>Delete note?</Text> 141 + <Group gap={'xs'}> 142 + <Button color="red" onClick={handleDeleteNote}> 143 + Delete 144 + </Button> 145 + <Button 146 + variant="light" 147 + color="gray" 148 + onClick={() => setShowDeleteWarning(false)} 149 + > 150 + Cancel 151 + </Button> 152 + </Group> 153 + </Group> 154 + ) : ( 155 + <Group gap={'xs'}> 112 156 <Button 113 157 variant="light" 114 158 color="gray" ··· 119 163 > 120 164 {note ? 'Edit note' : 'Add note'} 121 165 </Button> 166 + {props.noteId && ( 167 + <Button 168 + variant="light" 169 + color="red" 170 + onClick={(e) => { 171 + e.stopPropagation(); 172 + setShowDeleteWarning(true); 173 + }} 174 + > 175 + Delete note 176 + </Button> 177 + )} 122 178 </Group> 123 - </Stack> 124 - </Card> 179 + )} 180 + </Stack> 125 181 ); 126 182 }
+59 -6
src/webapp/features/notes/components/noteCardModal/NoteCardModalContent.tsx
··· 14 14 } from '@mantine/core'; 15 15 import { UrlCard, User } from '@semble/types'; 16 16 import Link from 'next/link'; 17 - import { useState } from 'react'; 17 + import { Fragment, useState } from 'react'; 18 18 import useUpdateNote from '../../lib/mutations/useUpdateNote'; 19 19 import { notifications } from '@mantine/notifications'; 20 + import useRemoveCardFromLibrary from '@/features/cards/lib/mutations/useRemoveCardFromLibrary'; 20 21 21 22 interface Props { 23 + onClose: () => void; 22 24 note: UrlCard['note']; 23 25 cardContent: UrlCard['cardContent']; 24 26 cardAuthor?: User; ··· 30 32 const isMyCard = props.cardAuthor?.id === cardStatus.data.card?.author.id; 31 33 const [note, setNote] = useState(isMyCard ? props.note?.text : ''); 32 34 const [editMode, setEditMode] = useState(false); 35 + const [showDeleteWarning, setShowDeleteWarning] = useState(false); 33 36 37 + const removeNote = useRemoveCardFromLibrary(); 34 38 const updateNote = useUpdateNote(); 39 + 40 + const handleDeleteNote = () => { 41 + if (!isMyCard || !props.note) return; 42 + 43 + removeNote.mutate(props.note.id, { 44 + onError: () => { 45 + notifications.show({ 46 + message: 'Could not delete note.', 47 + position: 'top-center', 48 + }); 49 + }, 50 + onSettled: () => { 51 + props.onClose(); 52 + }, 53 + }); 54 + }; 35 55 36 56 const handleUpdateNote = () => { 37 57 if (!props.note || !note) return; ··· 151 171 </Text> 152 172 )} 153 173 </Stack> 154 - {isMyCard && ( 174 + </Group> 175 + </Stack> 176 + </Card> 177 + {isMyCard && ( 178 + <Fragment> 179 + {showDeleteWarning ? ( 180 + <Group justify="space-between" gap={'xs'}> 181 + <Text>Delete note?</Text> 182 + <Group gap={'xs'}> 183 + <Button color="red" onClick={handleDeleteNote}> 184 + Delete 185 + </Button> 186 + <Button 187 + variant="light" 188 + color="gray" 189 + onClick={() => setShowDeleteWarning(false)} 190 + > 191 + Cancel 192 + </Button> 193 + </Group> 194 + </Group> 195 + ) : ( 196 + <Group gap={'xs'} grow> 155 197 <Button 156 198 variant="light" 157 199 color="gray" ··· 162 204 > 163 205 Edit note 164 206 </Button> 165 - )} 166 - </Group> 167 - </Stack> 168 - </Card> 207 + 208 + <Button 209 + variant="light" 210 + color="red" 211 + onClick={(e) => { 212 + e.stopPropagation(); 213 + setShowDeleteWarning(true); 214 + }} 215 + > 216 + Delete note 217 + </Button> 218 + </Group> 219 + )} 220 + </Fragment> 221 + )} 169 222 </Stack> 170 223 ); 171 224 }