feat: update components for multi-user support
- Add sharing indicator to ListCard showing collaborator count - Add permission badge and share button to ListDetailView - Disable editing in ItemForm for viewers with visual feedback - Add permission checks to item detail and edit pages - Hide edit/delete buttons for viewers on item detail page - Pass permission and collaborator data through component hierarchy - Update navigation to include profile and invitations links (already done in previous tasks) Implements task 15 from user-auth-and-sharing spec
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react'
|
||||
import { Share2 } from 'lucide-react'
|
||||
import ItemCard from './ItemCard'
|
||||
import SearchBar from './SearchBar'
|
||||
import FilterPanel from './FilterPanel'
|
||||
import SearchResults from './SearchResults'
|
||||
import EmptyState from './EmptyState'
|
||||
import ShareListModal from './ShareListModal'
|
||||
import PermissionBadge from './PermissionBadge'
|
||||
import { searchItems, getItemsByFilter } from '@/lib/actions'
|
||||
import { useSearch, useFilters, useScrollPosition } from '@/hooks'
|
||||
|
||||
@@ -34,12 +37,38 @@ interface ItemWithList extends Item {
|
||||
interface ListDetailViewProps {
|
||||
listId: string
|
||||
initialItems: Item[]
|
||||
permission?: 'owner' | 'editor' | 'viewer'
|
||||
canShare?: boolean
|
||||
listTitle?: string
|
||||
ownerId?: string
|
||||
ownerName?: string | null
|
||||
ownerEmail?: string
|
||||
collaborators?: Array<{
|
||||
id: string
|
||||
permission: 'editor' | 'viewer'
|
||||
user: {
|
||||
id: string
|
||||
name: string | null
|
||||
email: string
|
||||
}
|
||||
}>
|
||||
}
|
||||
|
||||
export default function ListDetailView({ listId, initialItems }: ListDetailViewProps) {
|
||||
export default function ListDetailView({
|
||||
listId,
|
||||
initialItems,
|
||||
permission,
|
||||
canShare = false,
|
||||
listTitle = '',
|
||||
ownerId = '',
|
||||
ownerName = null,
|
||||
ownerEmail = '',
|
||||
collaborators = []
|
||||
}: ListDetailViewProps) {
|
||||
const [searchResults, setSearchResults] = useState<ItemWithList[]>([])
|
||||
const [isSearching, setIsSearching] = useState(false)
|
||||
const [filteredItems, setFilteredItems] = useState<Item[]>(initialItems)
|
||||
const [isShareModalOpen, setIsShareModalOpen] = useState(false)
|
||||
|
||||
// Use scroll position preservation hook
|
||||
useScrollPosition({ key: `list-${listId}` })
|
||||
@@ -118,6 +147,26 @@ export default function ListDetailView({ listId, initialItems }: ListDetailViewP
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Permission Badge and Share Button */}
|
||||
{(permission || canShare) && (
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
{permission && (
|
||||
<div>
|
||||
<PermissionBadge permission={permission} />
|
||||
</div>
|
||||
)}
|
||||
{canShare && (
|
||||
<button
|
||||
onClick={() => setIsShareModalOpen(true)}
|
||||
className="ml-auto flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white rounded-lg transition-colors text-sm font-medium"
|
||||
>
|
||||
<Share2 size={16} />
|
||||
Share
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Search Bar */}
|
||||
<SearchBar
|
||||
onSearch={handleSearchCallback}
|
||||
@@ -181,6 +230,19 @@ export default function ListDetailView({ listId, initialItems }: ListDetailViewP
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Share Modal */}
|
||||
<ShareListModal
|
||||
isOpen={isShareModalOpen}
|
||||
onClose={() => setIsShareModalOpen(false)}
|
||||
listId={listId}
|
||||
listTitle={listTitle}
|
||||
isOwner={permission === 'owner'}
|
||||
ownerId={ownerId}
|
||||
ownerName={ownerName}
|
||||
ownerEmail={ownerEmail}
|
||||
initialCollaborators={collaborators}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user