This repository has no description
9.6 kB
301 lines
1'use client';
2
3import {
4 type UrlCard,
5 type Collection,
6 type User,
7 CollectionAccessType,
8} from '@/api-client';
9import {
10 ActionIcon,
11 Button,
12 Collapse,
13 CopyButton,
14 Group,
15 Menu,
16 Tooltip,
17} from '@mantine/core';
18import { Fragment, useState } from 'react';
19import { FiPlus } from 'react-icons/fi';
20import { BsThreeDots, BsTrash2Fill } from 'react-icons/bs';
21import RemoveCardFromCollectionModal from '../removeCardFromCollectionModal/RemoveCardFromCollectionModal';
22import RemoveCardFromLibraryModal from '../removeCardFromLibraryModal/RemoveCardFromLibraryModal';
23import AddCardToModal from '@/features/cards/components/addCardToModal/AddCardToModal';
24import { MdIosShare, MdOutlineStickyNote2 } from 'react-icons/md';
25import NoteCardInline from '@/features/notes/components/noteCardInline/NoteCardInline';
26import { useAuth } from '@/hooks/useAuth';
27import { useRouter } from 'next/navigation';
28import { IoMdCheckmark } from 'react-icons/io';
29import { notifications } from '@mantine/notifications';
30import { BiCopy } from 'react-icons/bi';
31import { CardSaveAnalyticsContext } from '@/features/analytics/types';
32import { TbPlugConnected } from 'react-icons/tb';
33import AddConnectionModal from '@/features/connections/components/addConnectionModal/AddConnectionModal';
34import { AiOutlineDisconnect } from 'react-icons/ai';
35import { useWebHaptics } from 'web-haptics/react';
36
37interface Props {
38 id: string;
39 cardContent: UrlCard['cardContent'];
40 cardCount: number;
41 cardAuthor?: User;
42 authorHandle?: string;
43 note?: UrlCard['note'];
44 currentCollection?: Collection;
45 urlLibraryCount: number;
46 urlIsInLibrary: boolean;
47 urlIsConnected?: boolean;
48 urlConnectionCount: number;
49 viaCardId?: string;
50 semblePageUrl?: string;
51 analyticsContext?: CardSaveAnalyticsContext;
52}
53
54export default function UrlCardActions(props: Props) {
55 const { isAuthenticated, user } = useAuth();
56
57 const userId = user?.id;
58 const userHandle = user?.handle;
59
60 const isAuthor =
61 !!user &&
62 (props.authorHandle
63 ? userHandle === props.authorHandle
64 : userId === props.cardAuthor?.id);
65
66 const isOpenCollection =
67 props.currentCollection?.accessType === CollectionAccessType.OPEN;
68
69 const isCardAdder = userId === props.cardAuthor?.id;
70 const isCollectionOwner = userId === props.currentCollection?.author.id;
71
72 const canRemoveFromOpenCollection =
73 !!user && isOpenCollection && (isCardAdder || isCollectionOwner);
74
75 const canRemoveFromLibrary = isAuthor && props.urlIsInLibrary;
76
77 const [showNote, setShowNote] = useState(false);
78 const [showRemoveFromCollectionModal, setShowRemoveFromCollectionModal] =
79 useState(false);
80 const [showRemoveFromLibaryModal, setShowRemoveFromLibraryModal] =
81 useState(false);
82 const [showAddToModal, setShowAddToModal] = useState(false);
83 const [showAddConnectionModal, setShowAddConnectionModal] = useState(false);
84
85 const { trigger } = useWebHaptics();
86 const router = useRouter();
87
88 return (
89 <Fragment>
90 {props.note && (
91 <Collapse expanded={showNote}>
92 <NoteCardInline
93 note={props.note}
94 cardContent={props.cardContent}
95 cardAuthor={props.cardAuthor}
96 isOwner={isAuthenticated && isAuthor}
97 onClose={() => setShowNote(false)}
98 />
99 </Collapse>
100 )}
101 <Group justify="space-between">
102 <Group gap={'xs'}>
103 <Tooltip label="Save or update" withArrow>
104 <Button
105 variant="light"
106 color={'gray'}
107 size="xs"
108 radius={'xl'}
109 leftSection={
110 props.urlLibraryCount > 0 ? (
111 props.urlIsInLibrary ? (
112 <IoMdCheckmark size={18} />
113 ) : (
114 <FiPlus size={18} />
115 )
116 ) : undefined
117 }
118 onClick={(e) => {
119 e.stopPropagation();
120 if (!isAuthenticated) {
121 router.push('/login');
122 return;
123 }
124 trigger();
125 setShowAddToModal(true);
126 }}
127 >
128 {props.urlLibraryCount ? (
129 props.urlLibraryCount
130 ) : props.urlIsInLibrary ? (
131 <IoMdCheckmark size={18} />
132 ) : (
133 <FiPlus size={18} />
134 )}
135 </Button>
136 </Tooltip>
137 <Tooltip label="Connect to another card" withArrow>
138 <Button
139 variant="light"
140 color="gray"
141 c={props.urlIsConnected ? 'green' : 'gray'}
142 size="xs"
143 radius={'xl'}
144 leftSection={
145 props.urlConnectionCount > 0 ? (
146 <TbPlugConnected size={15} />
147 ) : undefined
148 }
149 onClick={(e) => {
150 e.stopPropagation();
151 if (!isAuthenticated) {
152 router.push('/login');
153 return;
154 }
155 trigger();
156 setShowAddConnectionModal(true);
157 }}
158 >
159 {props.urlConnectionCount ? (
160 props.urlConnectionCount
161 ) : (
162 <TbPlugConnected size={15} />
163 )}
164 </Button>
165 </Tooltip>
166
167 {props.note && (
168 <Tooltip label="View note" withArrow>
169 <ActionIcon
170 variant="light"
171 color="gray"
172 radius={'xl'}
173 onClick={(e) => {
174 e.stopPropagation();
175 setShowNote((prev) => !prev);
176 }}
177 >
178 <MdOutlineStickyNote2 />
179 </ActionIcon>
180 </Tooltip>
181 )}
182 </Group>
183
184 <Menu shadow="sm">
185 <Menu.Target>
186 <ActionIcon
187 variant="light"
188 color={'gray'}
189 radius={'xl'}
190 onClick={(e) => e.stopPropagation()}
191 >
192 <BsThreeDots size={18} />
193 </ActionIcon>
194 </Menu.Target>
195 <Menu.Dropdown>
196 <CopyButton value={props.cardContent.url}>
197 {({ copy }) => (
198 <Menu.Item
199 leftSection={<BiCopy />}
200 onClick={(e) => {
201 e.stopPropagation();
202 copy();
203 notifications.show({
204 message: 'Link copied!',
205 position: 'top-center',
206 });
207 }}
208 >
209 Copy link
210 </Menu.Item>
211 )}
212 </CopyButton>
213
214 <CopyButton
215 value={`${process.env.NEXT_PUBLIC_APP_URL}/url?id=${props.cardContent.url}`}
216 >
217 {({ copy }) => (
218 <Menu.Item
219 leftSection={<MdIosShare />}
220 onClick={(e) => {
221 e.stopPropagation();
222 copy();
223 notifications.show({
224 message: 'Semble link copied!',
225 position: 'top-center',
226 });
227 }}
228 >
229 Share Semble page
230 </Menu.Item>
231 )}
232 </CopyButton>
233
234 {props.currentCollection &&
235 (isAuthor || canRemoveFromOpenCollection) && (
236 <Menu.Item
237 leftSection={<AiOutlineDisconnect />}
238 onClick={(e) => {
239 e.stopPropagation();
240 setShowRemoveFromCollectionModal(true);
241 }}
242 >
243 Remove from this collection
244 </Menu.Item>
245 )}
246 {canRemoveFromLibrary && (
247 <Menu.Item
248 color="red"
249 leftSection={<BsTrash2Fill />}
250 onClick={(e) => {
251 e.stopPropagation();
252 setShowRemoveFromLibraryModal(true);
253 }}
254 >
255 Remove from library
256 </Menu.Item>
257 )}
258 </Menu.Dropdown>
259 </Menu>
260 </Group>
261
262 {isAuthenticated && (
263 <>
264 <AddCardToModal
265 isOpen={showAddToModal}
266 onClose={() => setShowAddToModal(false)}
267 url={props.cardContent.url}
268 cardContent={props.cardContent}
269 cardId={props.id}
270 note={props.note?.text}
271 isInYourLibrary={props.urlIsInLibrary}
272 urlLibraryCount={props.urlLibraryCount}
273 viaCardId={props.viaCardId}
274 analyticsContext={props.analyticsContext}
275 />
276
277 <AddConnectionModal
278 isOpen={showAddConnectionModal}
279 onClose={() => setShowAddConnectionModal(false)}
280 sourceUrl={props.cardContent.url}
281 targetUrl={props.semblePageUrl}
282 />
283
284 {props.currentCollection && (
285 <RemoveCardFromCollectionModal
286 isOpen={showRemoveFromCollectionModal}
287 onClose={() => setShowRemoveFromCollectionModal(false)}
288 cardId={props.id}
289 collectionId={props.currentCollection.id}
290 />
291 )}
292 <RemoveCardFromLibraryModal
293 isOpen={showRemoveFromLibaryModal}
294 onClose={() => setShowRemoveFromLibraryModal(false)}
295 cardId={props.id}
296 />
297 </>
298 )}
299 </Fragment>
300 );
301}