This repository has no description
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}