This repository has no description
0

Configure Feed

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

semble / src / webapp / features / notes / components / noteCardModal / NoteCardModalContent.tsx
6.7 kB 247 lines
1import useGetCardFromMyLibrary from '@/features/cards/lib/queries/useGetCardFromMyLibrary'; 2import { 3 Anchor, 4 AspectRatio, 5 Avatar, 6 Card, 7 Group, 8 Stack, 9 Tooltip, 10 Text, 11 Image, 12 Textarea, 13 Button, 14} from '@mantine/core'; 15import { UrlCard, User } from '@semble/types'; 16import Link from 'next/link'; 17import { Fragment, useState } from 'react'; 18import useUpdateNote from '../../lib/mutations/useUpdateNote'; 19import { notifications } from '@mantine/notifications'; 20import useRemoveCardFromLibrary from '@/features/cards/lib/mutations/useRemoveCardFromLibrary'; 21 22interface Props { 23 onClose: () => void; 24 note: UrlCard['note']; 25 cardContent: UrlCard['cardContent']; 26 cardAuthor?: User; 27 domain: string; 28} 29 30export default function NoteCardModalContent(props: Props) { 31 const cardStatus = useGetCardFromMyLibrary({ url: props.cardContent.url }); 32 const isMyCard = props.cardAuthor?.id === cardStatus.data.card?.author.id; 33 const [note, setNote] = useState(isMyCard ? props.note?.text : ''); 34 const [editMode, setEditMode] = useState(false); 35 const [showDeleteWarning, setShowDeleteWarning] = useState(false); 36 37 const removeNote = useRemoveCardFromLibrary(); 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 }; 55 56 const handleUpdateNote = () => { 57 if (!props.note || !note) { 58 props.onClose(); 59 return; 60 } 61 62 if (props.note.text === note) { 63 props.onClose(); 64 return; 65 } 66 67 updateNote.mutate( 68 { 69 cardId: props.note?.id, 70 note: note, 71 }, 72 { 73 onError: () => { 74 notifications.show({ 75 message: 'Could not update note.', 76 position: 'top-center', 77 }); 78 }, 79 onSettled: () => { 80 setEditMode(false); 81 }, 82 }, 83 ); 84 }; 85 86 if (editMode) { 87 return ( 88 <Stack gap={'xs'}> 89 <Textarea 90 id="note" 91 label="Your note" 92 placeholder="Add a note about this card" 93 variant="filled" 94 size="md" 95 autosize 96 minRows={3} 97 maxRows={8} 98 maxLength={500} 99 value={note} 100 onChange={(e) => setNote(e.currentTarget.value)} 101 /> 102 <Group gap={'xs'} grow> 103 <Button 104 variant="light" 105 color="gray" 106 onClick={() => { 107 setEditMode(false); 108 setNote(props.note?.text); 109 }} 110 > 111 Cancel 112 </Button> 113 <Button 114 onClick={handleUpdateNote} 115 loading={updateNote.isPending} 116 disabled={note?.trimEnd() === ''} 117 > 118 Save 119 </Button> 120 </Group> 121 </Stack> 122 ); 123 } 124 return ( 125 <Stack gap={'xs'}> 126 {props.cardAuthor && ( 127 <Group gap={5}> 128 <Avatar 129 size={'sm'} 130 component={Link} 131 href={`/profile/${props.cardAuthor.handle}`} 132 target="_blank" 133 src={props.cardAuthor.avatarUrl?.replace( 134 'avatar', 135 'avatar_thumbnail', 136 )} 137 alt={`${props.cardAuthor.name}'s' avatar`} 138 /> 139 <Anchor 140 component={Link} 141 href={`/profile/${props.cardAuthor.handle}`} 142 target="_blank" 143 fw={700} 144 c="bright" 145 lineClamp={1} 146 > 147 {props.cardAuthor.name} 148 </Anchor> 149 </Group> 150 )} 151 {props.note && <Text fs={'italic'}>{props.note.text}</Text>} 152 <Card withBorder component="article" p={'xs'} radius={'lg'}> 153 <Stack> 154 <Group gap={'sm'} justify="space-between"> 155 {props.cardContent.imageUrl && ( 156 <AspectRatio ratio={1 / 1} flex={0.1}> 157 <Image 158 src={props.cardContent.imageUrl} 159 alt={`${props.cardContent.url} social preview image`} 160 radius={'md'} 161 w={45} 162 h={45} 163 /> 164 </AspectRatio> 165 )} 166 <Stack gap={0} flex={0.9}> 167 <Tooltip label={props.cardContent.url}> 168 <Anchor 169 component={Link} 170 href={props.cardContent.url} 171 target="_blank" 172 c={'gray'} 173 lineClamp={1} 174 onClick={(e) => e.stopPropagation()} 175 > 176 {props.domain} 177 </Anchor> 178 </Tooltip> 179 {props.cardContent.title && ( 180 <Anchor 181 component={Link} 182 href={props.cardContent.url} 183 target="_blank" 184 fw={500} 185 lineClamp={1} 186 c={'bright'} 187 w={'fit-content'} 188 > 189 {props.cardContent.title} 190 </Anchor> 191 )} 192 </Stack> 193 </Group> 194 </Stack> 195 </Card> 196 {isMyCard && ( 197 <Fragment> 198 {showDeleteWarning ? ( 199 <Group justify="space-between" gap={'xs'}> 200 <Text>Delete note?</Text> 201 <Group gap={'xs'}> 202 <Button 203 color="red" 204 onClick={handleDeleteNote} 205 loading={removeNote.isPending} 206 > 207 Delete 208 </Button> 209 <Button 210 variant="light" 211 color="gray" 212 onClick={() => setShowDeleteWarning(false)} 213 > 214 Cancel 215 </Button> 216 </Group> 217 </Group> 218 ) : ( 219 <Group gap={'xs'} grow> 220 <Button 221 variant="light" 222 color="gray" 223 onClick={(e) => { 224 e.stopPropagation(); 225 setEditMode(true); 226 }} 227 > 228 Edit note 229 </Button> 230 231 <Button 232 variant="light" 233 color="red" 234 onClick={(e) => { 235 e.stopPropagation(); 236 setShowDeleteWarning(true); 237 }} 238 > 239 Delete note 240 </Button> 241 </Group> 242 )} 243 </Fragment> 244 )} 245 </Stack> 246 ); 247}