Move permission badge and share button above add task bar

This commit is contained in:
2025-12-03 20:35:16 +00:00
parent 376b8cead9
commit 4422498bc9
2 changed files with 117 additions and 6 deletions

View File

@@ -58,6 +58,25 @@ export default async function ListDetailPage({ params }: { params: { id: string
</p> </p>
</div> </div>
{/* Permission Badge and Share Button */}
<div className="mb-6 sm:mb-8">
<ListDetailView
listId={list.id}
initialItems={list.items}
permission={permission}
canShare={canShare}
listTitle={list.title}
ownerId={list.ownerId}
ownerName={list.owner?.name}
ownerEmail={list.owner?.email || ''}
collaborators={list.collaborators.map(c => ({
...c,
permission: c.permission as 'editor' | 'viewer'
}))}
showOnlyHeader={true}
/>
</div>
{/* Inline Item Creation - only show if user can edit */} {/* Inline Item Creation - only show if user can edit */}
{canEdit && ( {canEdit && (
<div className="mb-6 sm:mb-8"> <div className="mb-6 sm:mb-8">
@@ -65,7 +84,7 @@ export default async function ListDetailPage({ params }: { params: { id: string
</div> </div>
)} )}
{/* Search, Filter, and Items List */} {/* Items List */}
<ListDetailView <ListDetailView
listId={list.id} listId={list.id}
initialItems={list.items} initialItems={list.items}
@@ -79,6 +98,7 @@ export default async function ListDetailPage({ params }: { params: { id: string
...c, ...c,
permission: c.permission as 'editor' | 'viewer' permission: c.permission as 'editor' | 'viewer'
}))} }))}
showOnlyItems={true}
/> />
</main> </main>
) )

View File

@@ -41,6 +41,8 @@ interface ListDetailViewProps {
email: string email: string
} }
}> }>
showOnlyHeader?: boolean
showOnlyItems?: boolean
} }
export default function ListDetailView({ export default function ListDetailView({
@@ -52,17 +54,22 @@ export default function ListDetailView({
ownerId = '', ownerId = '',
ownerName = null, ownerName = null,
ownerEmail = '', ownerEmail = '',
collaborators = [] collaborators = [],
showOnlyHeader = false,
showOnlyItems = false
}: ListDetailViewProps) { }: ListDetailViewProps) {
const [isShareModalOpen, setIsShareModalOpen] = useState(false) const [isShareModalOpen, setIsShareModalOpen] = useState(false)
// Use scroll position preservation hook // Conditionally use hooks based on view mode
useScrollPosition({ key: `list-${listId}` }) const shouldUseHooks = !showOnlyHeader
// Use real-time sync hook to poll for updates // Use scroll position preservation hook (only for items view)
useScrollPosition({ key: shouldUseHooks ? `list-${listId}` : 'disabled' })
// Use real-time sync hook to poll for updates (only for items view)
useRealtimeSync({ useRealtimeSync({
listId, listId,
enabled: true, enabled: shouldUseHooks,
pollInterval: 1000, // Poll every 1 second for faster updates pollInterval: 1000, // Poll every 1 second for faster updates
}) })
@@ -70,6 +77,90 @@ export default function ListDetailView({
const completedItems = useMemo(() => initialItems.filter(item => item.completed), [initialItems]) const completedItems = useMemo(() => initialItems.filter(item => item.completed), [initialItems])
const incompleteItems = useMemo(() => initialItems.filter(item => !item.completed), [initialItems]) const incompleteItems = useMemo(() => initialItems.filter(item => !item.completed), [initialItems])
// If showing only header, return just the permission badge and share button
if (showOnlyHeader) {
return (
<>
{(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>
)}
{/* Share Modal */}
<ShareListModal
isOpen={isShareModalOpen}
onClose={() => setIsShareModalOpen(false)}
listId={listId}
listTitle={listTitle}
isOwner={permission === 'owner'}
ownerId={ownerId}
ownerName={ownerName}
ownerEmail={ownerEmail}
initialCollaborators={collaborators}
/>
</>
)
}
// If showing only items, return just the items list
if (showOnlyItems) {
return (
<div className="space-y-6">
{/* Incomplete Items */}
{incompleteItems.length > 0 && (
<div className="animate-fade-in">
<h2 className="text-lg font-semibold text-gray-900 mb-3">
To Do ({incompleteItems.length})
</h2>
<div className="space-y-2">
{incompleteItems.map((item) => (
<ItemCard key={item.id} item={item} listId={listId} />
))}
</div>
</div>
)}
{/* Completed Items */}
{completedItems.length > 0 && (
<div className="animate-fade-in">
<h2 className="text-lg font-semibold text-gray-500 mb-3">
Completed ({completedItems.length})
</h2>
<div className="space-y-2">
{completedItems.map((item) => (
<ItemCard key={item.id} item={item} listId={listId} />
))}
</div>
</div>
)}
{/* Empty State */}
{initialItems.length === 0 && (
<EmptyState
icon="inbox"
title="No tasks found"
description="Add your first task using the button above"
/>
)}
</div>
)
}
// Default: show everything (for backward compatibility)
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* Permission Badge and Share Button */} {/* Permission Badge and Share Button */}