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.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}
+ />
);
}