This repository has no description
4.3 kB
141 lines
1'use client';
2
3import type { Collection, UrlCard } from '@semble/types';
4import { Stack } from '@mantine/core';
5import { useState, useEffect } from 'react';
6import CollectionSelector from '@/features/collections/components/collectionSelector/CollectionSelector';
7import useGetCardFromMyLibrary from '@/features/cards/lib/queries/useGetCardFromMyLibrary';
8import AddCardActions from '../addCardActions/AddCardActions';
9
10interface Props {
11 onClose: () => void;
12 onSubmit: (data: {
13 isAddingNewCard: boolean;
14 cardData?: {
15 url: string;
16 note?: string;
17 collectionIds: string[];
18 viaCardId?: string;
19 };
20 updateData?: {
21 cardId: string;
22 note?: string;
23 addToCollectionIds?: string[];
24 removeFromCollectionIds?: string[];
25 addToLibrary?: boolean;
26 viaCardId?: string;
27 };
28 }) => void;
29 url: string;
30 cardId?: string;
31 note?: string;
32 cardContent?: UrlCard['cardContent'];
33 viaCardId?: string;
34 isSaving: boolean;
35}
36
37export default function AddCardToModalContent(props: Props) {
38 const cardStatus = useGetCardFromMyLibrary({ url: props.url });
39 const isMyCard = props?.cardId === cardStatus.data.card?.id;
40 const [note, setNote] = useState(isMyCard ? props.note : '');
41
42 const collectionsWithCard = cardStatus.data.collections ?? [];
43
44 const [selectedCollections, setSelectedCollections] =
45 useState<Collection[]>(collectionsWithCard);
46
47 // Sync state with query data when it changes
48 useEffect(() => {
49 setSelectedCollections(cardStatus.data.collections ?? []);
50 }, [cardStatus.data.collections]);
51
52 const handleUpdateCard = (e: React.FormEvent) => {
53 e.preventDefault();
54
55 const trimmedNote = note?.trimEnd() === '' ? undefined : note;
56
57 const addedCollections = selectedCollections.filter(
58 (c) => !collectionsWithCard.some((original) => original.id === c.id),
59 );
60
61 const removedCollections = collectionsWithCard.filter(
62 (c) => !selectedCollections.some((selected) => selected.id === c.id),
63 );
64
65 const hasNoteChanged = trimmedNote !== props.note;
66 const hasAdded = addedCollections.length > 0;
67 const hasRemoved = removedCollections.length > 0;
68
69 // no change, close modal
70 if (cardStatus.data.card && !hasNoteChanged && !hasAdded && !hasRemoved) {
71 props.onClose();
72 return;
73 }
74
75 // card not yet in library, add it
76 if (!cardStatus.data.card) {
77 props.onSubmit({
78 isAddingNewCard: true,
79 cardData: {
80 url: props.url,
81 note: trimmedNote,
82 collectionIds: selectedCollections.map((c) => c.id),
83 viaCardId: props.viaCardId,
84 },
85 });
86 return;
87 }
88
89 // card already in library, update associations instead
90 const updatedCardPayload: {
91 cardId: string;
92 note?: string;
93 addToCollectionIds?: string[];
94 removeFromCollectionIds?: string[];
95 addToLibrary?: boolean;
96 viaCardId?: string;
97 } = { cardId: cardStatus.data.card.id };
98
99 if (hasNoteChanged) updatedCardPayload.note = trimmedNote;
100 if (hasAdded)
101 updatedCardPayload.addToCollectionIds = addedCollections.map((c) => c.id);
102 if (hasRemoved)
103 updatedCardPayload.removeFromCollectionIds = removedCollections.map(
104 (c) => c.id,
105 );
106
107 // Track as a card save if we're adding collections or a note (indicates user is saving/organizing the card)
108 updatedCardPayload.addToLibrary = hasAdded || hasNoteChanged;
109 updatedCardPayload.viaCardId = props.viaCardId;
110
111 props.onSubmit({
112 isAddingNewCard: false,
113 updateData: updatedCardPayload,
114 });
115 };
116
117 return (
118 <Stack>
119 <AddCardActions
120 cardId={cardStatus.data.card?.id}
121 note={isMyCard ? note : cardStatus.data.card?.note?.text}
122 noteId={cardStatus.data.card?.note?.id}
123 onUpdateNote={setNote}
124 onClose={props.onClose}
125 />
126
127 <CollectionSelector
128 isOpen={true}
129 onClose={props.onClose}
130 onCancel={() => {
131 props.onClose();
132 setSelectedCollections(cardStatus.data.collections ?? []);
133 }}
134 onSave={handleUpdateCard}
135 isSaving={props.isSaving}
136 selectedCollections={selectedCollections}
137 onSelectedCollectionsChange={setSelectedCollections}
138 />
139 </Stack>
140 );
141}