ultisuite-client/components/gmail/sidebar/category-nav-row.tsx
2026-05-20 16:01:08 +02:00

298 lines
9.5 KiB
TypeScript

"use client"
import { useRef, useState } from "react"
import { Folder, MoreVertical } from "lucide-react"
import { Icon } from "@iconify/react"
import { cn, formatCount } from "@/lib/utils"
import { useEmailDropTarget } from "@/lib/drag-context"
import { isSystemNavLabelId } from "@/lib/sidebar-nav-data"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
SidebarNavOptionsSheet,
SidebarNavSheetAction,
} from "@/components/gmail/sidebar-nav-options-sheet"
import { useSidebarTouchOptionsMenu } from "@/components/gmail/use-sidebar-touch-options"
import type { CategoryNavSourceItem } from "@/components/gmail/sidebar/sidebar-nav-constants"
import {
navRowRoundedWhenActive,
SidebarNavIconSlot,
SidebarOverflowColumn,
sidebarOverflowMenuButtonClass,
} from "@/components/gmail/sidebar/sidebar-nav-primitives"
export function CategoryNavRow({
item,
isSelected,
isExpanded,
unreadCount,
onSelectFolder,
onDisableNavLabel,
onEnableNavLabel,
touchNav,
variant = "listed",
}: {
item: CategoryNavSourceItem
isSelected: boolean
isExpanded: boolean
unreadCount: number
onSelectFolder: (id: string) => void
onDisableNavLabel: (id: string) => void
onEnableNavLabel: (id: string) => void
touchNav: boolean
variant?: "listed" | "hidden"
}) {
const { isOver, dropHandlers } = useEmailDropTarget(item.id, item.label)
const [menuOpen, setMenuOpen] = useState(false)
const menuTriggerRef = useRef<HTMLButtonElement>(null)
const isHiddenRow = variant === "hidden"
const showCategoryMenu = isSystemNavLabelId(item.id) && isExpanded
const hasUnread = unreadCount > 0
const touchMenuEnabled = touchNav && (isHiddenRow || showCategoryMenu)
const { sheetOpen, setSheetOpen, touchRowProps, touchRowClassName, closeSheet } =
useSidebarTouchOptionsMenu(touchMenuEnabled)
const handleMenuOpenChange = (open: boolean) => {
setMenuOpen(open)
if (!open) {
queueMicrotask(() => menuTriggerRef.current?.blur())
}
}
const rowHoverHeld =
!isHiddenRow && !isSelected && !isOver && (menuOpen || sheetOpen)
const rowIcon = item.icon ? (
<Icon
icon={item.icon}
className={cn(
"h-5 w-5 shrink-0",
isHiddenRow && "opacity-70",
hasUnread && !isSelected && !isHiddenRow && "text-gray-900"
)}
aria-hidden
/>
) : (
<Folder
className={cn(
"h-5 w-5 shrink-0",
isHiddenRow && "opacity-70",
hasUnread && !isSelected && !isHiddenRow && "text-gray-900"
)}
aria-hidden
/>
)
if (isHiddenRow) {
return (
<>
<div
{...dropHandlers}
{...touchRowProps}
className={cn(
"flex h-8 w-full min-w-0 shrink-0 items-center pl-6 pr-2 text-gray-500 transition-colors",
isOver ? "rounded-r-full" : "rounded-r-none",
isOver && "bg-mail-nav-drop text-foreground",
touchRowClassName
)}
>
<button
type="button"
onClick={() => onSelectFolder(item.id)}
className="flex h-8 min-w-0 flex-1 items-center gap-4 rounded-r-none py-0 pr-1 text-left outline-none hover:rounded-r-full hover:bg-gray-50"
>
{rowIcon}
<div className="flex min-w-0 flex-1 items-baseline gap-4">
<span
className={cn(
"min-w-0 flex-1 truncate text-sm leading-5",
hasUnread && "font-semibold text-gray-900"
)}
>
{item.label}
</span>
{unreadCount > 0 && (
<span
className={cn(
"shrink-0 text-xs tabular-nums leading-none text-gray-700",
hasUnread && "font-semibold"
)}
>
{formatCount(unreadCount)}
</span>
)}
</div>
</button>
{!touchNav && (
<DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
<DropdownMenuTrigger asChild>
<button
ref={menuTriggerRef}
type="button"
className={sidebarOverflowMenuButtonClass}
aria-label={`Options pour ${item.label}`}
onClick={(e) => e.stopPropagation()}
>
<MoreVertical className="h-4 w-4" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="min-w-40">
<DropdownMenuItem
onClick={() => {
onEnableNavLabel(item.id)
setMenuOpen(false)
}}
>
Réactiver le libellé
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
{touchNav && (
<SidebarNavOptionsSheet
open={sheetOpen}
onOpenChange={setSheetOpen}
title={item.label}
>
<SidebarNavSheetAction
onClick={() => {
onEnableNavLabel(item.id)
closeSheet()
}}
>
Réactiver le libellé
</SidebarNavSheetAction>
</SidebarNavOptionsSheet>
)}
</>
)
}
return (
<>
<div
{...dropHandlers}
{...touchRowProps}
className={cn(
"group/catnav flex h-8 w-full min-w-0 shrink-0 cursor-pointer items-center pl-6 pr-2 transition-colors",
navRowRoundedWhenActive(isSelected || isOver || rowHoverHeld),
isSelected
? "bg-mail-nav-selected text-mail-nav-selected font-medium"
: isOver
? "bg-mail-nav-drop text-foreground"
: rowHoverHeld
? "bg-mail-nav-hover text-foreground"
: hasUnread
? "text-gray-900 hover:bg-mail-nav-hover"
: "text-gray-700 hover:bg-mail-nav-hover",
touchRowClassName
)}
>
<button
type="button"
onClick={() => onSelectFolder(item.id)}
title={!isExpanded ? item.label : undefined}
className={cn(
"flex h-8 min-w-0 flex-1 cursor-pointer items-center gap-4 py-0 text-left outline-none",
showCategoryMenu ? "pr-1" : "pr-3"
)}
>
<SidebarNavIconSlot showUnreadDot={hasUnread}>
{rowIcon}
</SidebarNavIconSlot>
{isExpanded && (
<div className="flex min-w-0 flex-1 items-baseline gap-4">
<span
className={cn(
"min-w-0 flex-1 truncate text-sm leading-5",
hasUnread && !isSelected && "font-semibold text-gray-900"
)}
>
{item.label}
</span>
{!showCategoryMenu && unreadCount > 0 && (
<span
className={cn(
"shrink-0 text-xs tabular-nums leading-none",
isSelected && "font-medium",
hasUnread && !isSelected && "font-semibold"
)}
>
{formatCount(unreadCount)}
</span>
)}
</div>
)}
</button>
{showCategoryMenu && (
<SidebarOverflowColumn
unread={unreadCount}
menuOpen={menuOpen || sheetOpen}
hoverGroup="catnav"
isSelected={isSelected}
hasUnread={hasUnread}
className="mr-[-7px]"
showMenuButton={!touchNav}
>
{!touchNav && (
<DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
<DropdownMenuTrigger asChild>
<button
ref={menuTriggerRef}
type="button"
className={cn(
sidebarOverflowMenuButtonClass,
isSelected && "text-gray-900"
)}
aria-label={`Options pour ${item.label}`}
onClick={(e) => {
e.stopPropagation()
}}
>
<MoreVertical className="h-4 w-4" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="min-w-40">
<DropdownMenuItem disabled className="text-gray-400">
Afficher
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
onDisableNavLabel(item.id)
setMenuOpen(false)
}}
>
Désactiver le libellé
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</SidebarOverflowColumn>
)}
</div>
{touchNav && showCategoryMenu && (
<SidebarNavOptionsSheet
open={sheetOpen}
onOpenChange={setSheetOpen}
title={item.label}
>
<div className="px-4 py-3 text-sm text-muted-foreground">Afficher</div>
<SidebarNavSheetAction
onClick={() => {
onDisableNavLabel(item.id)
closeSheet()
}}
>
Désactiver le libellé
</SidebarNavSheetAction>
</SidebarNavOptionsSheet>
)}
</>
)
}