diff --git a/src/webapp/app/page.tsx b/src/webapp/app/page.tsx index 7d0316a7..c260cd5e 100644 --- a/src/webapp/app/page.tsx +++ b/src/webapp/app/page.tsx @@ -15,6 +15,7 @@ import { } from '@mantine/core'; import { FaBluesky, FaGithub, FaDiscord } from 'react-icons/fa6'; import { BiRightArrowAlt } from 'react-icons/bi'; +import { RiArrowRightUpLine } from 'react-icons/ri'; import BG from '@/assets/semble-bg.webp'; import CosmikLogo from '@/assets/cosmik-logo-full.svg'; import CurateIcon from '@/assets/icons/curate-icon.svg'; @@ -134,6 +135,53 @@ export default function Home() { pos={'relative'} > + + + + + + + + + + + + Made by   - - - - - - - - - - - -- 2.51.2 From 391359ac3cbbce4f7fed32fed8cbd980a644f2d0 Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Mon, 22 Sep 2025 14:28:19 -0700 Subject: [PATCH 2/7] fix: missing extension icon --- src/webapp/assets/icon.svg | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/webapp/assets/icon.svg diff --git a/src/webapp/assets/icon.svg b/src/webapp/assets/icon.svg new file mode 100644 index 00000000..1a77273c --- /dev/null +++ b/src/webapp/assets/icon.svg @@ -0,0 +1,6 @@ + + + + + + -- 2.51.2 From 4df8f2c74b86ff13ee513b6cd7c17562e53f4970 Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Tue, 23 Sep 2025 11:30:49 -0700 Subject: [PATCH 3/7] feat: rename library to home --- src/webapp/app/(authenticated)/cards/add/page.tsx | 2 +- .../app/(authenticated)/{library => home}/layout.tsx | 0 src/webapp/app/(authenticated)/home/loading.tsx | 5 +++++ src/webapp/app/(authenticated)/home/page.tsx | 5 +++++ src/webapp/app/(authenticated)/library/loading.tsx | 5 ----- src/webapp/app/(authenticated)/library/page.tsx | 5 ----- src/webapp/app/auth/complete/page.tsx | 4 ++-- src/webapp/app/login/page.tsx | 2 +- src/webapp/app/signup/page.tsx | 2 +- src/webapp/components/navigation/navbar/Navbar.tsx | 8 ++------ .../features/auth/components/loginForm/LoginForm.tsx | 4 ++-- .../components/addCardToModal/CardToBeAddedPreview.tsx | 2 +- src/webapp/features/cards/lib/mutations/useAddCard.tsx | 2 +- .../features/cards/lib/mutations/useAddCardToLibrary.tsx | 2 +- .../cards/lib/mutations/useRemoveCardFromCollections.tsx | 2 +- .../collections/lib/mutations/useAddCardToCollection.tsx | 2 +- .../containers/homeContainer/HomeContainer.tsx} | 4 ++-- .../containers/homeContainer/Skeleton.HomeContainer.tsx} | 4 ++-- 18 files changed, 28 insertions(+), 32 deletions(-) rename src/webapp/app/(authenticated)/{library => home}/layout.tsx (100%) create mode 100644 src/webapp/app/(authenticated)/home/loading.tsx create mode 100644 src/webapp/app/(authenticated)/home/page.tsx delete mode 100644 src/webapp/app/(authenticated)/library/loading.tsx delete mode 100644 src/webapp/app/(authenticated)/library/page.tsx rename src/webapp/features/{library/containers/libraryContainer/LibraryContainer.tsx => home/containers/homeContainer/HomeContainer.tsx} (98%) rename src/webapp/features/{library/containers/libraryContainer/Skeleton.LibraryContainer.tsx => home/containers/homeContainer/Skeleton.HomeContainer.tsx} (95%) diff --git a/src/webapp/app/(authenticated)/cards/add/page.tsx b/src/webapp/app/(authenticated)/cards/add/page.tsx index fb77ef41..dab55351 100644 --- a/src/webapp/app/(authenticated)/cards/add/page.tsx +++ b/src/webapp/app/(authenticated)/cards/add/page.tsx @@ -26,7 +26,7 @@ export default function AddCardPage() { ); const handleSuccess = () => { - router.push('/library'); + router.push('/home'); }; const handleCancel = () => { diff --git a/src/webapp/app/(authenticated)/library/layout.tsx b/src/webapp/app/(authenticated)/home/layout.tsx similarity index 100% rename from src/webapp/app/(authenticated)/library/layout.tsx rename to src/webapp/app/(authenticated)/home/layout.tsx diff --git a/src/webapp/app/(authenticated)/home/loading.tsx b/src/webapp/app/(authenticated)/home/loading.tsx new file mode 100644 index 00000000..4c69f4af --- /dev/null +++ b/src/webapp/app/(authenticated)/home/loading.tsx @@ -0,0 +1,5 @@ +import HomeContainerSkeleton from '@/features/home/containers/homeContainer/Skeleton.HomeContainer'; + +export default function Loading() { + return ; +} diff --git a/src/webapp/app/(authenticated)/home/page.tsx b/src/webapp/app/(authenticated)/home/page.tsx new file mode 100644 index 00000000..cbe599b9 --- /dev/null +++ b/src/webapp/app/(authenticated)/home/page.tsx @@ -0,0 +1,5 @@ +import HomeContainer from '@/features/home/containers/homeContainer/HomeContainer'; + +export default function Page() { + return ; +} diff --git a/src/webapp/app/(authenticated)/library/loading.tsx b/src/webapp/app/(authenticated)/library/loading.tsx deleted file mode 100644 index ce0c730d..00000000 --- a/src/webapp/app/(authenticated)/library/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import LibraryContainerSkeleton from '@/features/library/containers/libraryContainer/Skeleton.LibraryContainer'; - -export default function Loading() { - return ; -} diff --git a/src/webapp/app/(authenticated)/library/page.tsx b/src/webapp/app/(authenticated)/library/page.tsx deleted file mode 100644 index f68a1303..00000000 --- a/src/webapp/app/(authenticated)/library/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import LibraryContainer from '@/features/library/containers/libraryContainer/LibraryContainer'; - -export default function Page() { - return ; -} diff --git a/src/webapp/app/auth/complete/page.tsx b/src/webapp/app/auth/complete/page.tsx index 042c6e4e..47e7ab56 100644 --- a/src/webapp/app/auth/complete/page.tsx +++ b/src/webapp/app/auth/complete/page.tsx @@ -65,8 +65,8 @@ function AuthCompleteContent() { if (ExtensionService.isExtensionTokensRequested()) { handleExtensionTokenGeneration(); } else { - // Redirect to library - router.push('/library'); + // Redirect to home + router.push('/home'); } } else { router.push('/login?error=Authentication failed'); diff --git a/src/webapp/app/login/page.tsx b/src/webapp/app/login/page.tsx index e1963a95..ace0c06d 100644 --- a/src/webapp/app/login/page.tsx +++ b/src/webapp/app/login/page.tsx @@ -34,7 +34,7 @@ function InnerPage() { // redirect after 1 second timeoutId = setTimeout(() => { - router.push('/library'); + router.push('/home'); }, 1000); } diff --git a/src/webapp/app/signup/page.tsx b/src/webapp/app/signup/page.tsx index 969c5b46..4434667c 100644 --- a/src/webapp/app/signup/page.tsx +++ b/src/webapp/app/signup/page.tsx @@ -20,7 +20,7 @@ export default function Page() { // redirect after 1 second timeoutId = setTimeout(() => { - router.push('/library'); + router.push('/home'); }, 1000); } diff --git a/src/webapp/components/navigation/navbar/Navbar.tsx b/src/webapp/components/navigation/navbar/Navbar.tsx index 4162dad7..9cae1a56 100644 --- a/src/webapp/components/navigation/navbar/Navbar.tsx +++ b/src/webapp/components/navigation/navbar/Navbar.tsx @@ -30,7 +30,7 @@ export default function Navbar() { return ( - + Semble logo @@ -43,11 +43,7 @@ export default function Navbar() { - } - /> + } /> } > diff --git a/src/webapp/features/cards/lib/mutations/useAddCard.tsx b/src/webapp/features/cards/lib/mutations/useAddCard.tsx index 539a965a..96225e0e 100644 --- a/src/webapp/features/cards/lib/mutations/useAddCard.tsx +++ b/src/webapp/features/cards/lib/mutations/useAddCard.tsx @@ -28,7 +28,7 @@ export default function useAddCard() { // https://tkdodo.eu/blog/mastering-mutations-in-react-query#some-callbacks-might-not-fire onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['my cards'] }); - queryClient.invalidateQueries({ queryKey: ['library'] }); + queryClient.invalidateQueries({ queryKey: ['home'] }); queryClient.invalidateQueries({ queryKey: ['collections'] }); // invalidate each collection query individually diff --git a/src/webapp/features/cards/lib/mutations/useAddCardToLibrary.tsx b/src/webapp/features/cards/lib/mutations/useAddCardToLibrary.tsx index 0acaafc6..2b46f9a5 100644 --- a/src/webapp/features/cards/lib/mutations/useAddCardToLibrary.tsx +++ b/src/webapp/features/cards/lib/mutations/useAddCardToLibrary.tsx @@ -24,7 +24,7 @@ export default function useAddCardToLibrary() { onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['card', variables.cardId] }); queryClient.invalidateQueries({ queryKey: ['my cards'] }); - queryClient.invalidateQueries({ queryKey: ['library'] }); + queryClient.invalidateQueries({ queryKey: ['home'] }); queryClient.invalidateQueries({ queryKey: ['collections'] }); variables.collectionIds.forEach((id) => { diff --git a/src/webapp/features/cards/lib/mutations/useRemoveCardFromCollections.tsx b/src/webapp/features/cards/lib/mutations/useRemoveCardFromCollections.tsx index 5774c051..363c8b8c 100644 --- a/src/webapp/features/cards/lib/mutations/useRemoveCardFromCollections.tsx +++ b/src/webapp/features/cards/lib/mutations/useRemoveCardFromCollections.tsx @@ -24,7 +24,7 @@ export default function useRemoveCardFromCollections() { onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['card', variables.cardId] }); queryClient.invalidateQueries({ queryKey: ['my cards'] }); - queryClient.invalidateQueries({ queryKey: ['library'] }); + queryClient.invalidateQueries({ queryKey: ['home'] }); queryClient.invalidateQueries({ queryKey: ['collections'] }); variables.collectionIds.forEach((id) => { diff --git a/src/webapp/features/collections/lib/mutations/useAddCardToCollection.tsx b/src/webapp/features/collections/lib/mutations/useAddCardToCollection.tsx index e8e569de..0a464a1d 100644 --- a/src/webapp/features/collections/lib/mutations/useAddCardToCollection.tsx +++ b/src/webapp/features/collections/lib/mutations/useAddCardToCollection.tsx @@ -24,7 +24,7 @@ export default function useAddCardToCollection() { onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['card', variables.cardId] }); queryClient.invalidateQueries({ queryKey: ['my cards'] }); - queryClient.invalidateQueries({ queryKey: ['library'] }); + queryClient.invalidateQueries({ queryKey: ['home'] }); queryClient.invalidateQueries({ queryKey: ['collections'] }); variables.collectionIds.forEach((id) => { diff --git a/src/webapp/features/library/containers/libraryContainer/LibraryContainer.tsx b/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx similarity index 98% rename from src/webapp/features/library/containers/libraryContainer/LibraryContainer.tsx rename to src/webapp/features/home/containers/homeContainer/HomeContainer.tsx index 3711e008..c344800b 100644 --- a/src/webapp/features/library/containers/libraryContainer/LibraryContainer.tsx +++ b/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx @@ -22,7 +22,7 @@ import { BiCollection, BiPlus } from 'react-icons/bi'; import { FaRegNoteSticky } from 'react-icons/fa6'; import AddCardDrawer from '@/features/cards/components/addCardDrawer/AddCardDrawer'; -export default function LibraryContainer() { +export default function HomeContainer() { const { data: collectionsData } = useCollections({ limit: 4 }); const { data: myCardsData } = useMyCards({ limit: 4 }); @@ -36,7 +36,7 @@ export default function LibraryContainer() { return ( - Library + Home {/* Collections */} diff --git a/src/webapp/features/library/containers/libraryContainer/Skeleton.LibraryContainer.tsx b/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx similarity index 95% rename from src/webapp/features/library/containers/libraryContainer/Skeleton.LibraryContainer.tsx rename to src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx index 77dedc68..af488932 100644 --- a/src/webapp/features/library/containers/libraryContainer/Skeleton.LibraryContainer.tsx +++ b/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx @@ -14,11 +14,11 @@ import { FaRegNoteSticky } from 'react-icons/fa6'; import UrlCardSkeleton from '@/features/cards/components/urlCard/Skeleton.UrlCard'; import CollectionCardSkeleton from '@/features/collections/components/collectionCard/Skeleton.CollectionCard'; -export default function LibraryContainerSkeleton() { +export default function HomeContainerSkeleton() { return ( - Library + Home {/* Collections */} -- 2.51.2 From 3c9900fa9fe506aa2226752ea5cbb4d584ad4279 Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Tue, 23 Sep 2025 14:15:41 -0700 Subject: [PATCH 4/7] feat: move collections and my cards to profile --- .../[handle]/(withHeader)/cards}/error.tsx | 0 .../[handle]/(withHeader)/cards}/layout.tsx | 4 +- .../[handle]/(withHeader)/cards}/loading.tsx | 0 .../[handle]/(withHeader)/cards}/page.tsx | 0 .../(withHeader)}/collections/error.tsx | 0 .../(withHeader)}/collections/layout.tsx | 7 +-- .../(withHeader)}/collections/loading.tsx | 0 .../(withHeader)}/collections/page.tsx | 0 .../profile/[handle]/(withHeader)/layout.tsx | 58 +++++++++++++++++ .../[handle]/{ => (withHeader)}/loading.tsx | 0 .../profile/[handle]/(withHeader)/page.tsx | 3 + .../collections/[collectionId]/error.tsx | 0 .../collections/[collectionId]}/layout.tsx | 12 +--- .../collections/[collectionId]/loading.tsx | 0 .../collections/[collectionId]/page.tsx | 0 .../profile/[handle]/layout.tsx | 26 -------- .../(authenticated)/profile/[handle]/page.tsx | 24 ------- .../app/(authenticated)/profile/page.tsx | 14 +---- .../components/navigation/navbar/Navbar.tsx | 6 +- .../addCardToModal/CardToBeAddedPreview.tsx | 2 +- .../myCardsContainer/MyCardsContainer.tsx | 2 +- .../Skeleton.MyCardsContainer.tsx | 2 +- .../CardToBeAddedPreview.tsx | 2 +- .../collectionCard/CollectionCard.tsx | 6 +- .../collectionsNavList/CollectionsNavList.tsx | 6 +- .../DeleteCollectionModal.tsx | 4 +- .../feedActivityStatus/FeedActivityStatus.tsx | 4 +- .../homeContainer/HomeContainer.tsx | 18 +++++- .../homeContainer/Skeleton.HomeContainer.tsx | 13 ++-- .../profileHeader/ProfileHeader.tsx | 63 +++++++++++++++++++ .../components/profileMenu/ProfileMenu.tsx | 2 +- 31 files changed, 175 insertions(+), 103 deletions(-) rename src/webapp/app/(authenticated)/{my-cards => profile/[handle]/(withHeader)/cards}/error.tsx (100%) rename src/webapp/app/(authenticated)/{collections/[collectionId] => profile/[handle]/(withHeader)/cards}/layout.tsx (86%) rename src/webapp/app/(authenticated)/{my-cards => profile/[handle]/(withHeader)/cards}/loading.tsx (100%) rename src/webapp/app/(authenticated)/{my-cards => profile/[handle]/(withHeader)/cards}/page.tsx (100%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withHeader)}/collections/error.tsx (100%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withHeader)}/collections/layout.tsx (78%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withHeader)}/collections/loading.tsx (100%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withHeader)}/collections/page.tsx (100%) create mode 100644 src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/layout.tsx rename src/webapp/app/(authenticated)/profile/[handle]/{ => (withHeader)}/loading.tsx (100%) create mode 100644 src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/page.tsx rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withoutHeader)}/collections/[collectionId]/error.tsx (100%) rename src/webapp/app/(authenticated)/{my-cards => profile/[handle]/(withoutHeader)/collections/[collectionId]}/layout.tsx (51%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withoutHeader)}/collections/[collectionId]/loading.tsx (100%) rename src/webapp/app/(authenticated)/{ => profile/[handle]/(withoutHeader)}/collections/[collectionId]/page.tsx (100%) delete mode 100644 src/webapp/app/(authenticated)/profile/[handle]/layout.tsx delete mode 100644 src/webapp/app/(authenticated)/profile/[handle]/page.tsx create mode 100644 src/webapp/features/profile/components/profileHeader/ProfileHeader.tsx diff --git a/src/webapp/app/(authenticated)/my-cards/error.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/error.tsx similarity index 100% rename from src/webapp/app/(authenticated)/my-cards/error.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/error.tsx diff --git a/src/webapp/app/(authenticated)/collections/[collectionId]/layout.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/layout.tsx similarity index 86% rename from src/webapp/app/(authenticated)/collections/[collectionId]/layout.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/layout.tsx index bb204ea7..89af4c97 100644 --- a/src/webapp/app/(authenticated)/collections/[collectionId]/layout.tsx +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/layout.tsx @@ -3,8 +3,8 @@ import type { Metadata } from 'next'; import { Fragment } from 'react'; export const metadata: Metadata = { - title: 'Collection', - description: 'Collection', + title: 'My Cards', + description: 'All my cards', }; interface Props { diff --git a/src/webapp/app/(authenticated)/my-cards/loading.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/loading.tsx similarity index 100% rename from src/webapp/app/(authenticated)/my-cards/loading.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/loading.tsx diff --git a/src/webapp/app/(authenticated)/my-cards/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/page.tsx similarity index 100% rename from src/webapp/app/(authenticated)/my-cards/page.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/cards/page.tsx diff --git a/src/webapp/app/(authenticated)/collections/error.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/error.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/error.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/error.tsx diff --git a/src/webapp/app/(authenticated)/collections/layout.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/layout.tsx similarity index 78% rename from src/webapp/app/(authenticated)/collections/layout.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/layout.tsx index 98351f2e..467e7667 100644 --- a/src/webapp/app/(authenticated)/collections/layout.tsx +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/layout.tsx @@ -12,10 +12,5 @@ interface Props { } export default function Layout(props: Props) { - return ( - -
- {props.children} - - ); + return {props.children}; } diff --git a/src/webapp/app/(authenticated)/collections/loading.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/loading.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/loading.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/loading.tsx diff --git a/src/webapp/app/(authenticated)/collections/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/page.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/page.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/collections/page.tsx diff --git a/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/layout.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/layout.tsx new file mode 100644 index 00000000..d082cc04 --- /dev/null +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/layout.tsx @@ -0,0 +1,58 @@ +import { ApiClient } from '@/api-client/ApiClient'; +import Header from '@/components/navigation/header/Header'; +import ProfileHeader from '@/features/profile/components/profileHeader/ProfileHeader'; +import { getAccessTokenInServerComponent } from '@/services/auth'; +import { Button, Container, Stack, Text, Title } from '@mantine/core'; +import type { Metadata } from 'next'; +import Link from 'next/link'; +import { Fragment } from 'react'; + +interface Props { + params: Promise<{ handle: string }>; + children: React.ReactNode; +} + +export async function generateMetadata({ params }: Props): Promise { + const { handle } = await params; + + return { + title: handle, + description: 'Profile', + }; +} + +export default async function Layout(props: Props) { + const { handle } = await props.params; + const accessToken = await getAccessTokenInServerComponent(); + const apiClient = new ApiClient( + process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', + () => accessToken, + ); + const data = await apiClient.getMyProfile(); + + // TODO: use profile endpoints to fetch profile information + // for now we'll use getMyProfile + if (!accessToken || data.handle !== handle) { + return ( + +
+ + + Public profiles are coming soon! + + + + + ); + } + + return ( + +
+ + {props.children} + + ); +} diff --git a/src/webapp/app/(authenticated)/profile/[handle]/loading.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/loading.tsx similarity index 100% rename from src/webapp/app/(authenticated)/profile/[handle]/loading.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/loading.tsx diff --git a/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/page.tsx new file mode 100644 index 00000000..7d1e0b71 --- /dev/null +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withHeader)/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return <>; +} diff --git a/src/webapp/app/(authenticated)/collections/[collectionId]/error.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/error.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/[collectionId]/error.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/error.tsx diff --git a/src/webapp/app/(authenticated)/my-cards/layout.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/layout.tsx similarity index 51% rename from src/webapp/app/(authenticated)/my-cards/layout.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/layout.tsx index aea0cf5a..1e8e7579 100644 --- a/src/webapp/app/(authenticated)/my-cards/layout.tsx +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/layout.tsx @@ -1,10 +1,9 @@ -import Header from '@/components/navigation/header/Header'; import type { Metadata } from 'next'; import { Fragment } from 'react'; export const metadata: Metadata = { - title: 'My Cards', - description: 'All my cards', + title: 'Collection', + description: 'Collection', }; interface Props { @@ -12,10 +11,5 @@ interface Props { } export default function Layout(props: Props) { - return ( - -
- {props.children} - - ); + return {props.children}; } diff --git a/src/webapp/app/(authenticated)/collections/[collectionId]/loading.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/loading.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/[collectionId]/loading.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/loading.tsx diff --git a/src/webapp/app/(authenticated)/collections/[collectionId]/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/page.tsx similarity index 100% rename from src/webapp/app/(authenticated)/collections/[collectionId]/page.tsx rename to src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/collections/[collectionId]/page.tsx diff --git a/src/webapp/app/(authenticated)/profile/[handle]/layout.tsx b/src/webapp/app/(authenticated)/profile/[handle]/layout.tsx deleted file mode 100644 index baff099f..00000000 --- a/src/webapp/app/(authenticated)/profile/[handle]/layout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import Header from '@/components/navigation/header/Header'; -import type { Metadata } from 'next'; -import { Fragment } from 'react'; - -interface Props { - params: Promise<{ handle: string }>; - children: React.ReactNode; -} - -export async function generateMetadata({ params }: Props): Promise { - const { handle } = await params; - - return { - title: handle, - description: 'Profile', - }; -} - -export default async function Layout(props: Props) { - return ( - -
- {props.children} - - ); -} diff --git a/src/webapp/app/(authenticated)/profile/[handle]/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/page.tsx deleted file mode 100644 index 4ab89d1f..00000000 --- a/src/webapp/app/(authenticated)/profile/[handle]/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -'use client'; - -import { useParams } from 'next/navigation'; -import { Stack, Title, Text, Card, Center } from '@mantine/core'; - -export default function ProfilePage() { - const params = useParams(); - const handle = params.handle as string; - - return ( -
- - - Profile Page - Profile for @{handle} - Coming Soon! - - This page will show user profile information and their public - activity. - - - -
- ); -} diff --git a/src/webapp/app/(authenticated)/profile/page.tsx b/src/webapp/app/(authenticated)/profile/page.tsx index 19d39e56..fc84468e 100644 --- a/src/webapp/app/(authenticated)/profile/page.tsx +++ b/src/webapp/app/(authenticated)/profile/page.tsx @@ -1,14 +1,6 @@ -'use client'; - -import Header from '@/components/navigation/header/Header'; -import ProfileContainer from '@/features/profile/containers/profileContainer/ProfileContainer'; -import { Fragment } from 'react'; +import { redirect } from 'next/navigation'; export default function Page() { - return ( - -
- - - ); + // page is left empty, redirect to home if [handle] isn't provided + redirect('/home'); } diff --git a/src/webapp/components/navigation/navbar/Navbar.tsx b/src/webapp/components/navigation/navbar/Navbar.tsx index 9cae1a56..5856817d 100644 --- a/src/webapp/components/navigation/navbar/Navbar.tsx +++ b/src/webapp/components/navigation/navbar/Navbar.tsx @@ -23,9 +23,11 @@ import CollectionsNavListSkeleton from '@/features/collections/components/collec import NavbarToggle from '../NavbarToggle'; import { FiPlus } from 'react-icons/fi'; import AddCardDrawer from '@/features/cards/components/addCardDrawer/AddCardDrawer'; +import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; export default function Navbar() { const [openAddDrawer, setOpenAddDrawer] = useState(false); + const { data: profile } = useMyProfile(); return ( @@ -45,8 +47,8 @@ export default function Navbar() { } /> } /> - My Cards + Cards {allCards.length > 0 ? ( diff --git a/src/webapp/features/cards/containers/myCardsContainer/Skeleton.MyCardsContainer.tsx b/src/webapp/features/cards/containers/myCardsContainer/Skeleton.MyCardsContainer.tsx index fe3e114e..8833b93c 100644 --- a/src/webapp/features/cards/containers/myCardsContainer/Skeleton.MyCardsContainer.tsx +++ b/src/webapp/features/cards/containers/myCardsContainer/Skeleton.MyCardsContainer.tsx @@ -5,7 +5,7 @@ export default function MyCardsContainerSkeleton() { return ( - My Cards + Cards {Array.from({ length: 8 }).map((_, i) => ( diff --git a/src/webapp/features/collections/components/addToCollectionModal/CardToBeAddedPreview.tsx b/src/webapp/features/collections/components/addToCollectionModal/CardToBeAddedPreview.tsx index e6839159..e51c8566 100644 --- a/src/webapp/features/collections/components/addToCollectionModal/CardToBeAddedPreview.tsx +++ b/src/webapp/features/collections/components/addToCollectionModal/CardToBeAddedPreview.tsx @@ -74,7 +74,7 @@ export default function CardToBeAddedPreview(props: Props) { router.push(`/collections/${collection.id}`)} + onClick={() => + router.push( + `/profile/${collection.createdBy.handle}/collections/${collection.id}`, + ) + } radius={'lg'} p={'sm'} style={{ cursor: 'pointer' }} diff --git a/src/webapp/features/collections/components/collectionsNavList/CollectionsNavList.tsx b/src/webapp/features/collections/components/collectionsNavList/CollectionsNavList.tsx index f1271b70..4256adea 100644 --- a/src/webapp/features/collections/components/collectionsNavList/CollectionsNavList.tsx +++ b/src/webapp/features/collections/components/collectionsNavList/CollectionsNavList.tsx @@ -6,9 +6,11 @@ import useCollections from '../../lib/queries/useCollections'; import { useToggle } from '@mantine/hooks'; import CollectionsNavListError from './Error.CollectionsNavList'; import CreateCollectionShortcut from '../createCollectionShortcut/CreateCollectionShortcut'; +import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; export default function CollectionsNavList() { const { data, error } = useCollections({ limit: 30 }); + const { data: profile } = useMyProfile(); const [opened, toggleMenu] = useToggle([true, false]); if (error) { @@ -31,7 +33,7 @@ export default function CollectionsNavList() { ))} diff --git a/src/webapp/features/collections/components/deleteCollectionModal/DeleteCollectionModal.tsx b/src/webapp/features/collections/components/deleteCollectionModal/DeleteCollectionModal.tsx index fd64237e..f9f4f87b 100644 --- a/src/webapp/features/collections/components/deleteCollectionModal/DeleteCollectionModal.tsx +++ b/src/webapp/features/collections/components/deleteCollectionModal/DeleteCollectionModal.tsx @@ -16,9 +16,9 @@ export default function DeleteCollectionModal(props: Props) { const handleDeleteCollection = () => { deleteCollection.mutate(props.collectionId, { - onSuccess: () => { + onSuccess: (fes) => { props.onClose(); - router.push('/collections'); + router.push('./'); }, onError: () => { notifications.show({ diff --git a/src/webapp/features/feeds/components/feedActivityStatus/FeedActivityStatus.tsx b/src/webapp/features/feeds/components/feedActivityStatus/FeedActivityStatus.tsx index c87ad705..c0286af6 100644 --- a/src/webapp/features/feeds/components/feedActivityStatus/FeedActivityStatus.tsx +++ b/src/webapp/features/feeds/components/feedActivityStatus/FeedActivityStatus.tsx @@ -32,14 +32,16 @@ export default function FeedActivityStatus(props: Props) { added to{' '} {displayedCollections.map((collection, index) => ( + {/* TODO: use collection creator's handle to direct to profile/creatorHandle/collections/id */} {collection.name} + {index < displayedCollections.length - 1 ? ' and ' : ''} ))} diff --git a/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx b/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx index c344800b..dc1dd58a 100644 --- a/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx +++ b/src/webapp/features/home/containers/homeContainer/HomeContainer.tsx @@ -21,10 +21,12 @@ import { useState } from 'react'; import { BiCollection, BiPlus } from 'react-icons/bi'; import { FaRegNoteSticky } from 'react-icons/fa6'; import AddCardDrawer from '@/features/cards/components/addCardDrawer/AddCardDrawer'; +import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; export default function HomeContainer() { const { data: collectionsData } = useCollections({ limit: 4 }); const { data: myCardsData } = useMyCards({ limit: 4 }); + const { data: profile } = useMyProfile(); const [showCollectionDrawer, setShowCollectionDrawer] = useState(false); const [showAddDrawer, setShowAddDrawer] = useState(false); @@ -46,7 +48,12 @@ export default function HomeContainer() { Collections - + View all @@ -80,9 +87,14 @@ export default function HomeContainer() { - My Cards + Cards - + View all diff --git a/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx b/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx index af488932..cb7f82e4 100644 --- a/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx +++ b/src/webapp/features/home/containers/homeContainer/Skeleton.HomeContainer.tsx @@ -1,14 +1,13 @@ import { - Anchor, Container, Grid, GridCol, Group, SimpleGrid, + Skeleton, Stack, Title, } from '@mantine/core'; -import Link from 'next/link'; import { BiCollection } from 'react-icons/bi'; import { FaRegNoteSticky } from 'react-icons/fa6'; import UrlCardSkeleton from '@/features/cards/components/urlCard/Skeleton.UrlCard'; @@ -28,9 +27,7 @@ export default function HomeContainerSkeleton() { Collections - - View all - + @@ -45,11 +42,9 @@ export default function HomeContainerSkeleton() { - My Cards + Cards - - View all - + diff --git a/src/webapp/features/profile/components/profileHeader/ProfileHeader.tsx b/src/webapp/features/profile/components/profileHeader/ProfileHeader.tsx new file mode 100644 index 00000000..bacf3ae6 --- /dev/null +++ b/src/webapp/features/profile/components/profileHeader/ProfileHeader.tsx @@ -0,0 +1,63 @@ +import { ApiClient } from '@/api-client/ApiClient'; +import { getAccessTokenInServerComponent } from '@/services/auth'; +import { + Container, + Stack, + Group, + Avatar, + Text, + Title, + Button, +} from '@mantine/core'; +import { FaBluesky } from 'react-icons/fa6'; + +interface Props { + handle: string; +} + +export default async function ProfileHeader(props: Props) { + const accessToken = await getAccessTokenInServerComponent(); + + const apiClient = new ApiClient( + process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', + () => accessToken, + ); + const data = await apiClient.getMyProfile(); + + return ( + + + + + + + + + {data.name} + + + {data.handle} + + + {data.description && {data.description}} + + + + + + + ); +} diff --git a/src/webapp/features/profile/components/profileMenu/ProfileMenu.tsx b/src/webapp/features/profile/components/profileMenu/ProfileMenu.tsx index bb66fa26..467cbd1c 100644 --- a/src/webapp/features/profile/components/profileMenu/ProfileMenu.tsx +++ b/src/webapp/features/profile/components/profileMenu/ProfileMenu.tsx @@ -58,7 +58,7 @@ export default function ProfileMenu() { - + -- 2.51.2 From 5dddbb3f66b4896689661241991814ae620b14ff Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Tue, 23 Sep 2025 14:24:39 -0700 Subject: [PATCH 5/7] feat: card page route --- .../profile/[handle]/(withoutHeader)/cards/[cardId]/page.tsx | 3 +++ .../cards/components/addCardToModal/CardToBeAddedPreview.tsx | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/cards/[cardId]/page.tsx diff --git a/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/cards/[cardId]/page.tsx b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/cards/[cardId]/page.tsx new file mode 100644 index 00000000..2fbb10f1 --- /dev/null +++ b/src/webapp/app/(authenticated)/profile/[handle]/(withoutHeader)/cards/[cardId]/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return <>Card page — coming soon!; +} diff --git a/src/webapp/features/cards/components/addCardToModal/CardToBeAddedPreview.tsx b/src/webapp/features/cards/components/addCardToModal/CardToBeAddedPreview.tsx index 52385b56..ccab82dd 100644 --- a/src/webapp/features/cards/components/addCardToModal/CardToBeAddedPreview.tsx +++ b/src/webapp/features/cards/components/addCardToModal/CardToBeAddedPreview.tsx @@ -15,6 +15,7 @@ import { GetMyCollectionsResponse, UrlCardView } from '@/api-client/types'; import { BiCollection } from 'react-icons/bi'; import { LuLibrary } from 'react-icons/lu'; import { getDomain } from '@/lib/utils/link'; +import useMyProfile from '@/features/profile/lib/queries/useMyProfile'; interface Props { cardId: string; @@ -25,6 +26,7 @@ interface Props { export default function CardToBeAddedPreview(props: Props) { const domain = getDomain(props.cardContent.url); + const { data: profile } = useMyProfile(); return ( @@ -68,7 +70,7 @@ export default function CardToBeAddedPreview(props: Props) { variant="light" color="green" component={Link} - href={`/home/cards/${props.cardId}`} + href={`/profile/${profile.handle}/cards/${props.cardId}`} target="_blank" leftSection={} > -- 2.51.2 From 369f8d521c03d4ec27a75d1acfd2277b7caed700 Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Tue, 23 Sep 2025 14:32:18 -0700 Subject: [PATCH 6/7] chore: remove unused cards route --- .../(authenticated)/cards/[cardId]/page.tsx | 191 ------------------ .../app/(authenticated)/cards/add/page.tsx | 61 ------ 2 files changed, 252 deletions(-) delete mode 100644 src/webapp/app/(authenticated)/cards/[cardId]/page.tsx delete mode 100644 src/webapp/app/(authenticated)/cards/add/page.tsx diff --git a/src/webapp/app/(authenticated)/cards/[cardId]/page.tsx b/src/webapp/app/(authenticated)/cards/[cardId]/page.tsx deleted file mode 100644 index 2546e05c..00000000 --- a/src/webapp/app/(authenticated)/cards/[cardId]/page.tsx +++ /dev/null @@ -1,191 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import { useRouter, useParams } from 'next/navigation'; -import { getAccessToken } from '@/services/auth'; -import { ApiClient } from '@/api-client/ApiClient'; -import type { GetUrlCardViewResponse } from '@/api-client/types'; -import { - Button, - Loader, - Stack, - Text, - Card, - Title, - Anchor, - Blockquote, - Box, - Group, - Badge, - Image, - Divider, -} from '@mantine/core'; - -export default function CardPage() { - const [card, setCard] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); - const router = useRouter(); - const params = useParams(); - const cardId = params.cardId as string; - - useEffect(() => { - // Create API client instance - const apiClient = new ApiClient( - process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', - () => getAccessToken(), - ); - - const fetchCard = async () => { - try { - setLoading(true); - const response = await apiClient.getUrlCardView(cardId); - setCard(response); - } catch (error: any) { - console.error('Error fetching card:', error); - setError(error.message || 'Failed to load card'); - } finally { - setLoading(false); - } - }; - - if (cardId) { - fetchCard(); - } - }, [cardId]); - - if (loading) { - return ; - } - - if (error || !card) { - return ( - - {error || 'Card not found'} - - - ); - } - - return ( - - - - - - - - - - - - - {card.cardContent.title || 'Untitled'} - - - {card.type} - - Added {new Date(card.createdAt).toLocaleDateString()} - - - - {card.cardContent.thumbnailUrl && ( - {card.cardContent.title - )} - - - - {/* URL */} - - - URL - - - {card.url} - - - - {/* Description */} - {card.cardContent.description && ( - - - Description - - {card.cardContent.description} - - )} - - {/* Author */} - {card.cardContent.author && ( - - - Author - - {card.cardContent.author} - - )} - - {/* Note */} - {card.note && ( - - - Note - -
- {card.note.text} -
-
- )} - - {/* Collections */} - {card.collections && card.collections.length > 0 && ( - - - Collections - - - {card.collections.map((collection) => ( - - router.push(`/collections/${collection.id}`) - } - > - {collection.name} - - ))} - - - )} - - {/* Metadata */} - - - - - Created: {new Date(card.createdAt).toLocaleString()} - - - Updated: {new Date(card.updatedAt).toLocaleString()} - - -
-
-
-
-
- ); -} diff --git a/src/webapp/app/(authenticated)/cards/add/page.tsx b/src/webapp/app/(authenticated)/cards/add/page.tsx deleted file mode 100644 index dab55351..00000000 --- a/src/webapp/app/(authenticated)/cards/add/page.tsx +++ /dev/null @@ -1,61 +0,0 @@ -'use client'; - -import { useMemo } from 'react'; -import { useRouter, useSearchParams } from 'next/navigation'; -import { getAccessToken } from '@/services/auth'; -import { ApiClient } from '@/api-client/ApiClient'; -import { Box, Stack, Text, Title, Card } from '@mantine/core'; -import { UrlCardForm } from '@/components/UrlCardForm'; -import { useAuth } from '@/hooks/useAuth'; - -export default function AddCardPage() { - const router = useRouter(); - const searchParams = useSearchParams(); - const { user } = useAuth(); - - const preSelectedCollectionId = searchParams.get('collectionId'); - - // Create API client instance - memoized to avoid recreating on every render - const apiClient = useMemo( - () => - new ApiClient( - process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000', - () => getAccessToken(), - ), - [], - ); - - const handleSuccess = () => { - router.push('/home'); - }; - - const handleCancel = () => { - router.back(); - }; - - return ( - - - - Add Card - Add a URL to your library with an optional note. - - - - - Add URL to Library - - - - - - ); -} -- 2.51.2 From 2d0de6006a325f0ce726c60390a7af98cb30a7e0 Mon Sep 17 00:00:00 2001 From: Pouria Delfanazari Date: Tue, 23 Sep 2025 14:35:20 -0700 Subject: [PATCH 7/7] feat: move explore nav link above cards --- src/webapp/components/navigation/navbar/Navbar.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/webapp/components/navigation/navbar/Navbar.tsx b/src/webapp/components/navigation/navbar/Navbar.tsx index 5856817d..1535ebb7 100644 --- a/src/webapp/components/navigation/navbar/Navbar.tsx +++ b/src/webapp/components/navigation/navbar/Navbar.tsx @@ -46,16 +46,16 @@ export default function Navbar() { } /> - } - /> } /> + } + />