diff --git a/src/webapp/features/cards/components/addCardToModal/AddCardToModal.tsx b/src/webapp/features/cards/components/addCardToModal/AddCardToModal.tsx index b732dcd5..36ecc7b0 100644 --- a/src/webapp/features/cards/components/addCardToModal/AddCardToModal.tsx +++ b/src/webapp/features/cards/components/addCardToModal/AddCardToModal.tsx @@ -1,36 +1,53 @@ -import type { UrlCard } from '@/api-client'; import { DEFAULT_OVERLAY_PROPS } from '@/styles/overlays'; import { Modal, Stack, Text } from '@mantine/core'; import { Suspense } from 'react'; import CollectionSelectorSkeleton from '@/features/collections/components/collectionSelector/Skeleton.CollectionSelector'; -import AddCardToModalContent from './AddCardToModalContent'; // new file or inline +import AddCardToModalContent from './AddCardToModalContent'; interface Props { isOpen: boolean; onClose: () => void; - cardContent: UrlCard['cardContent']; - urlLibraryCount: number; - cardId: string; + url: string; + cardId?: string; note?: string; - isInYourLibrary: boolean; + urlLibraryCount?: number; + isInYourLibrary?: boolean; } export default function AddCardToModal(props: Props) { + const { + isOpen, + onClose, + url, + cardId, + note, + urlLibraryCount, + isInYourLibrary, + } = props; + + const count = urlLibraryCount ?? 0; + + const subtitle = (() => { + if (count === 0) return 'Not saved by anyone yet'; + + if (isInYourLibrary) { + if (count === 1) return 'Saved by you'; + return `Saved by you and ${count - 1} other${count - 1 > 1 ? 's' : ''}`; + } else { + if (count === 1) return 'Saved by 1 person'; + return `Saved by ${count} people`; + } + })(); + return ( Add or update card - {props.isInYourLibrary - ? props.urlLibraryCount === 1 - ? 'Saved by you' - : `Saved by you and ${props.urlLibraryCount - 1} other${props.urlLibraryCount - 1 > 1 ? 's' : ''}` - : props.urlLibraryCount === 1 - ? 'Saved by 1 person' - : `Saved by ${props.urlLibraryCount} people`} + {subtitle} } @@ -40,10 +57,10 @@ export default function AddCardToModal(props: Props) { > }> diff --git a/src/webapp/features/cards/components/addCardToModal/AddCardToModalContent.tsx b/src/webapp/features/cards/components/addCardToModal/AddCardToModalContent.tsx index d06d10af..d2af4226 100644 --- a/src/webapp/features/cards/components/addCardToModal/AddCardToModalContent.tsx +++ b/src/webapp/features/cards/components/addCardToModal/AddCardToModalContent.tsx @@ -11,6 +11,7 @@ import useGetCardFromMyLibrary from '@/features/cards/lib/queries/useGetCardFrom import useMyCollections from '@/features/collections/lib/queries/useMyCollections'; import useUpdateCardAssociations from '@/features/cards/lib/mutations/useUpdateCardAssociations'; import useAddCard from '@/features/cards/lib/mutations/useAddCard'; +import useUrlMetadata from '../../lib/queries/useUrlMetadata'; interface SelectableCollectionItem { id: string; @@ -20,14 +21,17 @@ interface SelectableCollectionItem { interface Props { onClose: () => void; - cardContent: UrlCard['cardContent']; - cardId: string; + url: string; + cardId?: string; note?: string; } export default function AddCardToModalContent(props: Props) { - const cardStatus = useGetCardFromMyLibrary({ url: props.cardContent.url }); - const isMyCard = props.cardId === cardStatus.data.card?.id; + const { + data: { metadata }, + } = useUrlMetadata({ url: props.url }); + const cardStatus = useGetCardFromMyLibrary({ url: props.url }); + const isMyCard = props?.cardId === cardStatus.data.card?.id; const [note, setNote] = useState(isMyCard ? props.note : ''); const { data, error } = useMyCollections(); @@ -77,7 +81,7 @@ export default function AddCardToModalContent(props: Props) { if (!cardStatus.data.card) { addCard.mutate( { - url: props.cardContent.url, + url: props.url, note: trimmedNote, collectionIds: selectedCollections.map((c) => c.id), }, @@ -122,7 +126,9 @@ export default function AddCardToModalContent(props: Props) { return ( diff --git a/src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx b/src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx index 2a8ba54c..ca2a763d 100644 --- a/src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx +++ b/src/webapp/features/cards/components/cardToBeAddedPreview/CardToBeAddedPreview.tsx @@ -16,7 +16,9 @@ import { UrlCard } from '@/api-client'; import { getDomain } from '@/lib/utils/link'; interface Props { - cardContent: UrlCard['cardContent']; + url: string; + thumbnailUrl?: string; + title?: string; note?: string; onUpdateNote: Dispatch>; } @@ -24,7 +26,7 @@ interface Props { export default function CardToBeAddedPreview(props: Props) { const [noteMode, setNoteMode] = useState(false); const [note, setNote] = useState(props.note); - const domain = getDomain(props.cardContent.url); + const domain = getDomain(props.url); if (noteMode) { return ( @@ -77,11 +79,11 @@ export default function CardToBeAddedPreview(props: Props) { - {props.cardContent.thumbnailUrl && ( + {props.thumbnailUrl && ( {`${props.cardContent.url} )} - + - {props.cardContent.title && ( + {props.title && ( - {props.cardContent.title} + {props.title} )} diff --git a/src/webapp/features/cards/components/urlCardActions/UrlCardActions.tsx b/src/webapp/features/cards/components/urlCardActions/UrlCardActions.tsx index cdf64c0e..00789d4e 100644 --- a/src/webapp/features/cards/components/urlCardActions/UrlCardActions.tsx +++ b/src/webapp/features/cards/components/urlCardActions/UrlCardActions.tsx @@ -118,7 +118,7 @@ export default function UrlCardActions(props: Props) { setShowAddToModal(false)} - cardContent={props.cardContent} + url={props.cardContent.url} cardId={props.id} note={props.note?.text} urlLibraryCount={props.urlLibraryCount} diff --git a/src/webapp/features/cards/lib/queries/useUrlMetadata.tsx b/src/webapp/features/cards/lib/queries/useUrlMetadata.tsx new file mode 100644 index 00000000..f78b176a --- /dev/null +++ b/src/webapp/features/cards/lib/queries/useUrlMetadata.tsx @@ -0,0 +1,14 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; +import { getUrlMetadata } from '../dal'; + +interface Props { + url: string; +} + +export default function useUrlMetadata(props: Props) { + const metadata = useSuspenseQuery({ + queryKey: [props.url], + queryFn: () => getUrlMetadata(props.url), + }); + return metadata; +} diff --git a/src/webapp/features/semble/components/SembleHeader/SembleHeader.tsx b/src/webapp/features/semble/components/SembleHeader/SembleHeader.tsx index 538d41b3..11df60f9 100644 --- a/src/webapp/features/semble/components/SembleHeader/SembleHeader.tsx +++ b/src/webapp/features/semble/components/SembleHeader/SembleHeader.tsx @@ -15,6 +15,7 @@ import { getUrlMetadata } from '@/features/cards/lib/dal'; import { getDomain } from '@/lib/utils/link'; import UrlAddedBySummary from '../urlAddedBySummary/UrlAddedBySummary'; import SembleActions from '../sembleActions/SembleActions'; +import { verifySessionOnServer } from '@/lib/auth/dal.server'; interface Props { url: string; @@ -22,6 +23,7 @@ interface Props { export default async function SembleHeader(props: Props) { const { metadata } = await getUrlMetadata(props.url); + const session = await verifySessionOnServer(); return ( @@ -74,7 +76,7 @@ export default async function SembleHeader(props: Props) { /> )} - + {session && } diff --git a/src/webapp/features/semble/components/sembleActions/SembleActions.tsx b/src/webapp/features/semble/components/sembleActions/SembleActions.tsx index 6cd52144..e4c6ce1a 100644 --- a/src/webapp/features/semble/components/sembleActions/SembleActions.tsx +++ b/src/webapp/features/semble/components/sembleActions/SembleActions.tsx @@ -1,8 +1,9 @@ 'use client'; +import AddCardToModal from '@/features/cards/components/addCardToModal/AddCardToModal'; import useGetCardFromMyLibrary from '@/features/cards/lib/queries/useGetCardFromMyLibrary'; import { Button, Group } from '@mantine/core'; -import { Fragment } from 'react'; +import { Fragment, useState } from 'react'; import { FiPlus } from 'react-icons/fi'; import { IoMdCheckmark } from 'react-icons/io'; @@ -13,6 +14,7 @@ interface Props { export default function SembleActions(props: Props) { const cardStatus = useGetCardFromMyLibrary({ url: props.url }); const isInYourLibrary = cardStatus.data.card?.urlInLibrary; + const [showAddToModal, setShowAddToModal] = useState(false); if (cardStatus.error) { return null; @@ -27,10 +29,21 @@ export default function SembleActions(props: Props) { leftSection={ isInYourLibrary ? : } + onClick={() => setShowAddToModal(true)} > {isInYourLibrary ? 'In library' : 'Add to library'} + + setShowAddToModal(false)} + url={props.url} + cardId={cardStatus.data.card?.id} + note={cardStatus.data.card?.note?.text} + urlLibraryCount={cardStatus.data.card?.urlLibraryCount} + isInYourLibrary={cardStatus.data.card?.urlInLibrary} + /> ); }