Move permission badge and share button above add task bar
This commit is contained in:
@@ -58,6 +58,25 @@ export default async function ListDetailPage({ params }: { params: { id: string
|
||||
</p>
|
||||
</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 */}
|
||||
{canEdit && (
|
||||
<div className="mb-6 sm:mb-8">
|
||||
@@ -65,7 +84,7 @@ export default async function ListDetailPage({ params }: { params: { id: string
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Search, Filter, and Items List */}
|
||||
{/* Items List */}
|
||||
<ListDetailView
|
||||
listId={list.id}
|
||||
initialItems={list.items}
|
||||
@@ -79,6 +98,7 @@ export default async function ListDetailPage({ params }: { params: { id: string
|
||||
...c,
|
||||
permission: c.permission as 'editor' | 'viewer'
|
||||
}))}
|
||||
showOnlyItems={true}
|
||||
/>
|
||||
</main>
|
||||
)
|
||||
|
||||
@@ -41,6 +41,8 @@ interface ListDetailViewProps {
|
||||
email: string
|
||||
}
|
||||
}>
|
||||
showOnlyHeader?: boolean
|
||||
showOnlyItems?: boolean
|
||||
}
|
||||
|
||||
export default function ListDetailView({
|
||||
@@ -52,17 +54,22 @@ export default function ListDetailView({
|
||||
ownerId = '',
|
||||
ownerName = null,
|
||||
ownerEmail = '',
|
||||
collaborators = []
|
||||
collaborators = [],
|
||||
showOnlyHeader = false,
|
||||
showOnlyItems = false
|
||||
}: ListDetailViewProps) {
|
||||
const [isShareModalOpen, setIsShareModalOpen] = useState(false)
|
||||
|
||||
// Use scroll position preservation hook
|
||||
useScrollPosition({ key: `list-${listId}` })
|
||||
// Conditionally use hooks based on view mode
|
||||
const shouldUseHooks = !showOnlyHeader
|
||||
|
||||
// Use scroll position preservation hook (only for items view)
|
||||
useScrollPosition({ key: shouldUseHooks ? `list-${listId}` : 'disabled' })
|
||||
|
||||
// Use real-time sync hook to poll for updates
|
||||
// Use real-time sync hook to poll for updates (only for items view)
|
||||
useRealtimeSync({
|
||||
listId,
|
||||
enabled: true,
|
||||
enabled: shouldUseHooks,
|
||||
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 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 (
|
||||
<div className="space-y-6">
|
||||
{/* Permission Badge and Share Button */}
|
||||
|
||||
Reference in New Issue
Block a user