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 / addCardActions / AddCardActions.tsx
4.0 kB 160 lines
1'use client'; 2 3import { Dispatch, SetStateAction, useState } from 'react'; 4import useRemoveCardFromLibrary from '../../lib/mutations/useRemoveCardFromLibrary'; 5import { notifications } from '@mantine/notifications'; 6import { 7 Button, 8 Card, 9 Flex, 10 Group, 11 Input, 12 Stack, 13 Text, 14 Textarea, 15 VisuallyHidden, 16} from '@mantine/core'; 17 18interface Props { 19 note?: string; 20 noteId?: string; 21 onUpdateNote: Dispatch<SetStateAction<string | undefined>>; 22 onClose: () => void; 23} 24 25export default function AddCardActions(props: Props) { 26 const [showDeleteWarning, setShowDeleteWarning] = useState(false); 27 const [noteMode, setNoteMode] = useState(false); 28 const [note, setNote] = useState(props.note); 29 const MAX_NOTE_LENGTH = 500; 30 31 const removeNote = useRemoveCardFromLibrary(); 32 33 const handleDeleteNote = () => { 34 if (!props.noteId) return; 35 36 removeNote.mutate(props.noteId, { 37 onError: () => { 38 notifications.show({ 39 message: 'Could not delete note.', 40 position: 'top-center', 41 }); 42 }, 43 onSettled: () => { 44 props.onClose(); 45 }, 46 }); 47 }; 48 49 if (noteMode) { 50 return ( 51 <Card 52 withBorder 53 component="article" 54 p={'xs'} 55 radius={'lg'} 56 style={{ cursor: 'pointer' }} 57 > 58 <Stack gap={'xs'}> 59 <Stack gap={0}> 60 <Flex justify="space-between"> 61 <Input.Label size="md" htmlFor="note"> 62 Your note 63 </Input.Label> 64 <Text c={'gray'} aria-hidden> 65 {note?.length ?? 0} / {MAX_NOTE_LENGTH} 66 </Text> 67 </Flex> 68 69 <Textarea 70 id="note" 71 placeholder="Add a note about this card" 72 variant="filled" 73 size="md" 74 rows={3} 75 maxLength={500} 76 value={note} 77 onChange={(e) => setNote(e.currentTarget.value)} 78 /> 79 <VisuallyHidden id="note-char-remaining" aria-live="polite"> 80 {`${MAX_NOTE_LENGTH - (note?.length ?? 0)} characters remaining`} 81 </VisuallyHidden> 82 </Stack> 83 <Group gap={'xs'} grow> 84 <Button 85 variant="light" 86 color="gray" 87 onClick={() => { 88 setNoteMode(false); 89 setNote(props.note); 90 }} 91 > 92 Cancel 93 </Button> 94 <Button 95 onClick={() => { 96 props.onUpdateNote(note); 97 setNoteMode(false); 98 }} 99 disabled={note?.trimEnd() === ''} 100 > 101 Ok 102 </Button> 103 </Group> 104 </Stack> 105 </Card> 106 ); 107 } 108 109 return ( 110 <Stack gap={'xs'}> 111 {showDeleteWarning ? ( 112 <Group justify="space-between" gap={'xs'}> 113 <Text>Delete note?</Text> 114 <Group gap={'xs'}> 115 <Button 116 color="red" 117 onClick={handleDeleteNote} 118 loading={removeNote.isPending} 119 > 120 Delete 121 </Button> 122 <Button 123 variant="light" 124 color="gray" 125 onClick={() => setShowDeleteWarning(false)} 126 > 127 Cancel 128 </Button> 129 </Group> 130 </Group> 131 ) : ( 132 <Group gap={'xs'}> 133 <Button 134 variant="light" 135 size="xs" 136 color="gray" 137 onClick={(e) => { 138 e.stopPropagation(); 139 setNoteMode(true); 140 }} 141 > 142 {note ? 'Edit note' : 'Add note'} 143 </Button> 144 {props.noteId && ( 145 <Button 146 variant="light" 147 color="red" 148 onClick={(e) => { 149 e.stopPropagation(); 150 setShowDeleteWarning(true); 151 }} 152 > 153 Delete note 154 </Button> 155 )} 156 </Group> 157 )} 158 </Stack> 159 ); 160}