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'}
>
+
+
+
+
+
+
+
+
+
+
+
+ }
+ >
+ Follow our blog for updates
+
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 (
-
+
@@ -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}}
+
+
+ }
+ >
+ @{data.handle}
+
+
+
+
+ );
+}
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 && (
-
- )}
-
-
-
- {/* 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() {
} />
- }
- />
}
/>
+ }
+ />