From 1aacac149d2b94aeb11827c911480504a5dcd7e9 Mon Sep 17 00:00:00 2001 From: Copus Team Date: Sat, 24 Jan 2026 16:24:07 +0800 Subject: [PATCH 01/16] feat(spaces): add cover image upload functionality for space creation and editing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add cover image upload option to space creation modal with ImageUploader component - Add cover image upload option to space editing modal with proper state management - Update AuthService.createSpace() to support coverUrl parameter - Update AuthService.updateSpace() to support coverUrl parameter - Add proper state initialization and cleanup for cover image URLs - Support optional cover images with fallback to default sharing images - Maintain consistent UI patterns with existing image upload functionality ๐Ÿค– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .screen-graph.json | 974 ++++++++++++++++++ src/components/ui/TreasuryCard.tsx | 39 +- .../screens/sections/MainContentSection.tsx | 213 +++- .../Space/sections/SpaceContentSection.tsx | 224 ++-- .../sections/UserProfileContent.tsx | 152 +++ src/services/authService.ts | 14 +- 6 files changed, 1537 insertions(+), 79 deletions(-) create mode 100644 .screen-graph.json diff --git a/.screen-graph.json b/.screen-graph.json new file mode 100644 index 00000000..67dc27de --- /dev/null +++ b/.screen-graph.json @@ -0,0 +1,974 @@ +{ + "nodes": [ + { + "id": "src/screens/Discovery/Discovery.tsx", + "label": "Discovery", + "routes": [ + "/", + "/home", + "/copus" + ], + "isRoot": true + }, + { + "id": "src/components/guards/AuthGuard.tsx", + "label": "AuthGuard", + "routes": [ + "/following", + "/treasury", + "/notification", + "/setting", + "/earning", + "/my-treasury", + "/space/:category", + "/curate", + "/account/delete", + "/seoSet" + ] + }, + { + "id": "src/routes/Login/screens/Login.tsx", + "label": "Login", + "routes": [ + "/login" + ] + }, + { + "id": "src/components/ShortLinkHandler.tsx", + "label": "ShortLinkHandler", + "routes": [ + "/u/:namespace" + ] + }, + { + "id": "src/screens/Content/Content.tsx", + "label": "Content", + "routes": [ + "/work/:id" + ], + "dataModelId": "9091:54529" + }, + { + "id": "src/routes/NewExplore/screens/NewExplore.tsx", + "label": "NewExplore", + "routes": [ + "/*" + ], + "isRoot": true + } + ], + "edges": [ + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:34:4-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": "navigate('/setting')", + "line": 34, + "endLine": 34, + "column": 4, + "endColumn": 24, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:67:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n \n ", + "line": 67, + "endLine": 73, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:75:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n Copus\n ", + "line": 75, + "endLine": 77, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:121:12-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/notification", + "trigger": { + "element": "\n \n {unreadCount > 0 && (\n
\n {unreadCount > 99 ? '99+' : unreadCount}\n
\n )}\n ", + "line": 121, + "endLine": 132, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:161:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n My Treasury\n ", + "line": 161, + "endLine": 167, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:168:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n Settings\n ", + "line": 168, + "endLine": 174, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:188:14-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n
\n Discover now\n
\n ", + "line": 188, + "endLine": 192, + "column": 14, + "endColumn": 21, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:200:16-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "Log in / Sign up", + "line": 200, + "endLine": 200, + "column": 16, + "endColumn": 57, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/MobileMenu/MobileMenu.tsx:80:6-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 80, + "endLine": 80, + "column": 6, + "endColumn": 24, + "sourceFile": "src/components/shared/MobileMenu/MobileMenu.tsx" + } + } + }, + { + "id": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx:139:33-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 139, + "endLine": 139, + "column": 33, + "endColumn": 51, + "sourceFile": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx" + } + } + }, + { + "id": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx:197:25-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 197, + "endLine": 197, + "column": 25, + "endColumn": 43, + "sourceFile": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx" + } + } + }, + { + "id": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx:212:6-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": "navigate('/my-treasury')", + "line": 212, + "endLine": 212, + "column": 6, + "endColumn": 30, + "sourceFile": "src/screens/Discovery/sections/DiscoveryContentSection/DiscoveryContentSection.tsx" + } + } + }, + { + "id": "src/components/guards/AuthGuard.tsx:43:11-to-src/screens/Discovery/Discovery.tsx", + "source": "src/components/guards/AuthGuard.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "", + "line": 43, + "endLine": 43, + "column": 11, + "endColumn": 43, + "sourceFile": "src/components/guards/AuthGuard.tsx" + } + } + }, + { + "id": "src/components/pages/UnauthorizedPage.tsx:45:29-to-src/routes/Login/screens/Login.tsx", + "source": "src/components/guards/AuthGuard.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 45, + "endLine": 45, + "column": 29, + "endColumn": 47, + "sourceFile": "src/components/pages/UnauthorizedPage.tsx" + } + } + }, + { + "id": "src/components/pages/UnauthorizedPage.tsx:59:12-to-src/screens/Discovery/Discovery.tsx", + "source": "src/components/guards/AuthGuard.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n Back to Home\n ", + "line": 59, + "endLine": 64, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/pages/UnauthorizedPage.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:34:4-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": "navigate('/setting')", + "line": 34, + "endLine": 34, + "column": 4, + "endColumn": 24, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:67:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n \n ", + "line": 67, + "endLine": 73, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:75:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n Copus\n ", + "line": 75, + "endLine": 77, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:121:12-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/notification", + "trigger": { + "element": "\n \n {unreadCount > 0 && (\n
\n {unreadCount > 99 ? '99+' : unreadCount}\n
\n )}\n ", + "line": 121, + "endLine": 132, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:161:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n My Treasury\n ", + "line": 161, + "endLine": 167, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:168:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n Settings\n ", + "line": 168, + "endLine": 174, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:188:14-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n
\n Discover now\n
\n ", + "line": 188, + "endLine": 192, + "column": 14, + "endColumn": 21, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:200:16-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "Log in / Sign up", + "line": 200, + "endLine": 200, + "column": 16, + "endColumn": 57, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/MobileMenu/MobileMenu.tsx:80:6-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 80, + "endLine": 80, + "column": 6, + "endColumn": 24, + "sourceFile": "src/components/shared/MobileMenu/MobileMenu.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:34:4-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": "navigate('/setting')", + "line": 34, + "endLine": 34, + "column": 4, + "endColumn": 24, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:67:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n \n ", + "line": 67, + "endLine": 73, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:75:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n Copus\n ", + "line": 75, + "endLine": 77, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:121:12-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/notification", + "trigger": { + "element": "\n \n {unreadCount > 0 && (\n
\n {unreadCount > 99 ? '99+' : unreadCount}\n
\n )}\n ", + "line": 121, + "endLine": 132, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:161:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n My Treasury\n ", + "line": 161, + "endLine": 167, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:168:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n Settings\n ", + "line": 168, + "endLine": 174, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:188:14-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n
\n Discover now\n
\n ", + "line": 188, + "endLine": 192, + "column": 14, + "endColumn": 21, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:200:16-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "Log in / Sign up", + "line": 200, + "endLine": 200, + "column": 16, + "endColumn": 57, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/MobileMenu/MobileMenu.tsx:80:6-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 80, + "endLine": 80, + "column": 6, + "endColumn": 24, + "sourceFile": "src/components/shared/MobileMenu/MobileMenu.tsx" + } + } + }, + { + "id": "src/routes/MyTreasury/screens/sections/MainContentSection.tsx:386:6-to-src/components/guards/AuthGuard.tsx", + "source": "src/routes/MyTreasury/screens/MyTreasury.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": "navigate('/my-treasury')", + "line": 386, + "endLine": 386, + "column": 6, + "endColumn": 30, + "sourceFile": "src/routes/MyTreasury/screens/sections/MainContentSection.tsx" + } + } + }, + { + "id": "src/screens/Content/Content.tsx:111:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Content/Content.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n Back to Discovery\n ", + "line": 111, + "endLine": 113, + "column": 10, + "endColumn": 17, + "sourceFile": "src/screens/Content/Content.tsx" + } + } + }, + { + "id": "src/screens/Content/Content.tsx:126:25-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Content/Content.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 126, + "endLine": 126, + "column": 25, + "endColumn": 43, + "sourceFile": "src/screens/Content/Content.tsx" + } + } + }, + { + "id": "src/screens/Content/Content.tsx:169:25-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Content/Content.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 169, + "endLine": 169, + "column": 25, + "endColumn": 43, + "sourceFile": "src/screens/Content/Content.tsx" + } + } + }, + { + "id": "src/screens/Content/Content.tsx:177:6-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Content/Content.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": "navigate('/my-treasury')", + "line": 177, + "endLine": 177, + "column": 6, + "endColumn": 30, + "sourceFile": "src/screens/Content/Content.tsx" + } + } + }, + { + "id": "src/screens/Content/Content.tsx:180:6-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Content/Content.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": "navigate('/my-treasury')", + "line": 180, + "endLine": 180, + "column": 6, + "endColumn": 30, + "sourceFile": "src/screens/Content/Content.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:34:4-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": "navigate('/setting')", + "line": 34, + "endLine": 34, + "column": 4, + "endColumn": 24, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:67:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n \n ", + "line": 67, + "endLine": 73, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:75:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n Copus\n ", + "line": 75, + "endLine": 77, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:121:12-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/notification", + "trigger": { + "element": "\n \n {unreadCount > 0 && (\n
\n {unreadCount > 99 ? '99+' : unreadCount}\n
\n )}\n ", + "line": 121, + "endLine": 132, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:161:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n My Treasury\n ", + "line": 161, + "endLine": 167, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:168:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n Settings\n ", + "line": 168, + "endLine": 174, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:188:14-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n
\n Discover now\n
\n ", + "line": 188, + "endLine": 192, + "column": 14, + "endColumn": 21, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:200:16-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "Log in / Sign up", + "line": 200, + "endLine": 200, + "column": 16, + "endColumn": 57, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/MobileMenu/MobileMenu.tsx:80:6-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 80, + "endLine": 80, + "column": 6, + "endColumn": 24, + "sourceFile": "src/components/shared/MobileMenu/MobileMenu.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:34:4-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": "navigate('/setting')", + "line": 34, + "endLine": 34, + "column": 4, + "endColumn": 24, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:67:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n \n ", + "line": 67, + "endLine": 73, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:75:10-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/", + "trigger": { + "element": "\n Copus\n ", + "line": 75, + "endLine": 77, + "column": 10, + "endColumn": 17, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:121:12-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/notification", + "trigger": { + "element": "\n \n {unreadCount > 0 && (\n
\n {unreadCount > 99 ? '99+' : unreadCount}\n
\n )}\n ", + "line": 121, + "endLine": 132, + "column": 12, + "endColumn": 19, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:161:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/my-treasury", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n My Treasury\n ", + "line": 161, + "endLine": 167, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:168:18-to-src/components/guards/AuthGuard.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/components/guards/AuthGuard.tsx", + "data": { + "viaRoute": "/setting", + "trigger": { + "element": " setShowUserMenu(false)}\n >\n Settings\n ", + "line": 168, + "endLine": 174, + "column": 18, + "endColumn": 25, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:188:14-to-src/screens/Discovery/Discovery.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/screens/Discovery/Discovery.tsx", + "data": { + "viaRoute": "/copus", + "trigger": { + "element": "\n
\n Discover now\n
\n ", + "line": 188, + "endLine": 192, + "column": 14, + "endColumn": 21, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/HeaderSection/HeaderSection.tsx:200:16-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "Log in / Sign up", + "line": 200, + "endLine": 200, + "column": 16, + "endColumn": 57, + "sourceFile": "src/components/shared/HeaderSection/HeaderSection.tsx" + } + } + }, + { + "id": "src/components/shared/MobileMenu/MobileMenu.tsx:80:6-to-src/routes/Login/screens/Login.tsx", + "source": "src/screens/Discovery/Discovery.tsx", + "target": "src/routes/Login/screens/Login.tsx", + "data": { + "viaRoute": "/login", + "trigger": { + "element": "navigate('/login')", + "line": 80, + "endLine": 80, + "column": 6, + "endColumn": 24, + "sourceFile": "src/components/shared/MobileMenu/MobileMenu.tsx" + } + } + } + ] +} \ No newline at end of file diff --git a/src/components/ui/TreasuryCard.tsx b/src/components/ui/TreasuryCard.tsx index faa8bcb4..2a8c597d 100644 --- a/src/components/ui/TreasuryCard.tsx +++ b/src/components/ui/TreasuryCard.tsx @@ -17,7 +17,8 @@ export interface SpaceData { namespace?: string; name?: string; title?: string; - spaceType?: number; // 1 = Collections, 2 = Curations + description?: string; + spaceType?: number; // 1 = Collections, 2 = Curations, 0 = Custom articleCount?: number; treasureCount?: number; ownerInfo?: { @@ -178,11 +179,19 @@ export const TreasuryCard = ({

No treasures yet

)} -
-

- {title} -

-

+

+
+

+ {title} +

+ {/* Space description */} + {space.description && ( +

+ {space.description} +

+ )} +
+

{treasureCount} {treasureCount === 1 ? 'treasure' : 'treasures'}

@@ -258,11 +267,19 @@ export const TreasuryCard = ({ )} -
-

- {title} -

-

+

+
+

+ {title} +

+ {/* Space description */} + {space.description && ( +

+ {space.description} +

+ )} +
+

{treasureCount} {treasureCount === 1 ? 'treasure' : 'treasures'}

diff --git a/src/routes/MyTreasury/screens/sections/MainContentSection.tsx b/src/routes/MyTreasury/screens/sections/MainContentSection.tsx index f4e21599..eedb3b90 100644 --- a/src/routes/MyTreasury/screens/sections/MainContentSection.tsx +++ b/src/routes/MyTreasury/screens/sections/MainContentSection.tsx @@ -6,6 +6,7 @@ import { Button } from "../../../../components/ui/button"; import { TreasuryCard } from "../../../../components/ui/TreasuryCard"; import profileDefaultAvatar from "../../../../assets/images/profile-default.svg"; import { useToast } from "../../../../components/ui/toast"; +import { ImageUploader } from "../../../../components/ImageUploader/ImageUploader"; // Module-level cache to prevent duplicate fetches across StrictMode remounts // Key: fetchKey (e.g., "user:123") @@ -37,6 +38,8 @@ const TreasuryHeaderSection = ({ avatarUrl, socialLinks, onShare, + onCreateSpace, + showCreateButton = false, }: { username: string; namespace: string; @@ -44,6 +47,8 @@ const TreasuryHeaderSection = ({ avatarUrl?: string; socialLinks: SocialLink[]; onShare?: () => void; + onCreateSpace?: () => void; + showCreateButton?: boolean; }): JSX.Element => { return (
@@ -120,6 +125,22 @@ const TreasuryHeaderSection = ({ ))} )} + + {/* Create Space button - only shown on own treasury */} + {showCreateButton && onCreateSpace && ( +
+ +
+ )} @@ -166,6 +187,14 @@ export const MainContentSection = (): JSX.Element => { const [error, setError] = useState(null); const [treasuryUserInfo, setTreasuryUserInfo] = useState(null); + // Create Space Modal state + const [showCreateSpaceModal, setShowCreateSpaceModal] = useState(false); + const [newSpaceName, setNewSpaceName] = useState(""); + const [newSpaceDescription, setNewSpaceDescription] = useState(""); + const [newSpaceCoverUrl, setNewSpaceCoverUrl] = useState(""); + const [isCreatingSpace, setIsCreatingSpace] = useState(false); + + // Determine if viewing other user const isViewingOtherUser = !!namespace && namespace !== user?.namespace; const targetNamespace = namespace || user?.namespace; @@ -324,9 +353,8 @@ export const MainContentSection = (): JSX.Element => { console.log('Spaces array length:', spacesArray.length); - // Use spaces directly from pageMySpaces API - // The API may include article previews in the response (check for data/articles fields) - // If not, TreasuryCard will display based on articleCount + + // Use spaces from API setSpaces(spacesArray); // Store in cache for reuse during redirects @@ -382,6 +410,53 @@ export const MainContentSection = (): JSX.Element => { } }; + // Handle creating a new space + const handleCreateNewSpace = async () => { + if (!newSpaceName.trim()) { + showToast('Please enter a space name', 'error'); + return; + } + + + setIsCreatingSpace(true); + + try { + // Prepare space data + const spaceData = { + name: newSpaceName.trim(), + description: newSpaceDescription.trim() || undefined, + coverUrl: newSpaceCoverUrl || undefined + }; + + console.log('Creating space with data:', spaceData); + + // Call the createSpace API to create a new space + const createResponse = await AuthService.createSpace(spaceData); + console.log('Create space response:', createResponse); + + showToast(`Space "${newSpaceName.trim()}" created successfully`, 'success'); + + // Reset and close modal + resetCreateSpaceModal(); + + // Refresh the page to show the new space + window.location.reload(); + } catch (err) { + console.error('Failed to create space:', err); + showToast('Failed to create space', 'error'); + } finally { + setIsCreatingSpace(false); + } + }; + + // Reset create space modal + const resetCreateSpaceModal = () => { + setNewSpaceName(""); + setNewSpaceDescription(""); + setNewSpaceCoverUrl(""); + setShowCreateSpaceModal(false); + }; + if (loading) { return (
@@ -421,6 +496,8 @@ export const MainContentSection = (): JSX.Element => { avatarUrl={displayUser?.faceUrl || profileDefaultAvatar} socialLinks={displaySocialLinks} onShare={handleShare} + onCreateSpace={() => setShowCreateSpaceModal(true)} + showCreateButton={!isViewingOtherUser} /> {/* Spaces Grid - auto-fill columns with min 360px, flexible max */} @@ -459,6 +536,136 @@ export const MainContentSection = (): JSX.Element => { )) )} + + {/* Create Space Modal */} + {showCreateSpaceModal && ( +
+ {/* Backdrop */} +
+ + {/* Modal */} +
+ {/* Close button */} + + +
+
+

+ Create New Space +

+ +
+ + +
+ setNewSpaceName(e.target.value)} + placeholder="Enter space name..." + className="flex-1 border-none bg-transparent [font-family:'Lato',Helvetica] font-normal text-gray-700 text-base tracking-[0] leading-[23px] outline-none placeholder:text-gray-400" + aria-required="true" + autoFocus + /> +
+
+ + {/* Space Description */} +
+ + +
+