From 88c73e212c4510ce41ad8c6557fa7d5c8f72d199 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Mon, 17 Nov 2025 01:12:41 +0000
Subject: feat: Add collaborative lists (#2146)

* feat: Add collaborative lists backend implementation

This commit implements the core backend functionality for collaborative
lists, allowing multiple users to share and interact with bookmark lists.

Database changes:
- Add listCollaborators table to track users with access to lists and
  their roles (viewer/editor)
- Add addedBy field to bookmarksInLists to track who added bookmarks
- Add relations for collaborative list functionality

Access control updates:
- Update List model to support role-based access (owner/editor/viewer)
- Add methods to check and enforce permissions for list operations
- Update Bookmark model to allow access through collaborative lists
- Modify bookmark queries to include bookmarks from collaborative lists

List collaboration features:
- Add/remove/update collaborators
- Get list of collaborators
- Get lists shared with current user
- Only manual lists can have collaborators

tRPC procedures:
- addCollaborator: Add a user as a collaborator to a list
- removeCollaborator: Remove a collaborator from a list
- updateCollaboratorRole: Change a collaborator's role
- getCollaborators: Get all collaborators for a list
- getSharedWithMe: Get all lists shared with the current user
- cloneBookmark: Clone a bookmark to the current user's collection

Implementation notes:
- Editors can add/remove bookmarks from the list (must own the bookmark)
- Viewers can only view bookmarks in the list
- Only the list owner can manage collaborators and list metadata
- Smart lists cannot have collaborators (only manual lists)
- Users cannot edit bookmarks they don't own, even in shared lists

* feat: Add collaborative lists frontend UI

This commit implements the frontend user interface for collaborative lists,
allowing users to view shared bookmarks and manage list collaborators.

New pages:
- /dashboard/shared: Shows bookmarks from lists shared with the user
  - Displays bookmarks from all collaborative lists
  - Uses SharedBookmarks component
  - Shows empty state when no lists are shared

Navigation:
- Added "Shared with you" link to sidebar with Users icon
- Positioned after "Home" in main navigation
- Available in both desktop and mobile sidebar

Collaborator management:
- ManageCollaboratorsModal component for managing list collaborators
  - Add collaborators by user ID with viewer/editor role
  - View current collaborators with their roles
  - Update collaborator roles inline
  - Remove collaborators
  - Shows empty state when no collaborators
- Integrated into ListOptions dropdown menu
- Accessible via "Manage Collaborators" menu item

Components created:
- SharedBookmarks.tsx: Server component fetching shared lists/bookmarks
- ManageCollaboratorsModal.tsx: Client component with tRPC mutations
- /dashboard/shared/page.tsx: Route for shared bookmarks page

UI features:
- Role selector for viewer/editor permissions
- Real-time collaborator list updates
- Toast notifications for success/error states
- Loading states for async operations
- Responsive design matching existing UI patterns

Implementation notes:
- Uses existing tRPC endpoints (getSharedWithMe, getCollaborators, etc.)
- Follows established modal patterns from ShareListModal
- Integrates seamlessly with existing list UI
- Currently uses user ID for adding collaborators (email lookup TBD)

* fix typecheck

* add collaborator by email

* add shared list in the sidebar

* fix perm issue

* hide UI components from non list owners

* list leaving

* fix shared bookmarks showing up in homepage

* fix getBookmark access check

* e2e tests

* hide user specific fields from shared lists

* simplify bookmark perm checks

* disable editable fields in bookmark preview

* hide lists if they don't have options

* fix list ownership

* fix highlights

* move tests to trpc

* fix alignment of leave list

* make tag lists unclickable

* allow editors to remove from list

* add a badge for shared lists

* remove bookmarks of user when they're removed from a list

* fix tests

* show owner in the manage collab modal

* fix hasCollab

* drop shared with you

* i18n

* beta badge

* correctly invalidate caches on collab change

* reduce unnecessary changes

* Add ratelimits

* stop manually removing bookmarks on remove

* some fixes

* fixes

* remove unused function

* improve tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
---
 apps/web/components/dashboard/preview/ReaderView.tsx | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'apps/web/components/dashboard/preview/ReaderView.tsx')

diff --git a/apps/web/components/dashboard/preview/ReaderView.tsx b/apps/web/components/dashboard/preview/ReaderView.tsx
index bf4c27a5..1974626a 100644
--- a/apps/web/components/dashboard/preview/ReaderView.tsx
+++ b/apps/web/components/dashboard/preview/ReaderView.tsx
@@ -15,10 +15,12 @@ export default function ReaderView({
   bookmarkId,
   className,
   style,
+  readOnly,
 }: {
   bookmarkId: string;
   className?: string;
   style?: React.CSSProperties;
+  readOnly: boolean;
 }) {
   const { data: highlights } = api.highlights.getForBookmark.useQuery({
     bookmarkId,
@@ -93,6 +95,7 @@ export default function ReaderView({
         style={style}
         htmlContent={cachedContent || ""}
         highlights={highlights?.highlights ?? []}
+        readOnly={readOnly}
         onDeleteHighlight={(h) =>
           deleteHighlight({
             highlightId: h.id,
-- 
cgit v1.2.3-70-g09d2

