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>
|
</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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user