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