ultisuite-client/components/gmail/mobile-xs-bulk-sheets.tsx
2026-05-16 20:30:50 +02:00

208 lines
7.1 KiB
TypeScript

"use client"
import type { ComponentType, CSSProperties, ReactNode } from "react"
import { Clock, FolderInput, Tag } from "lucide-react"
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet"
import { cn } from "@/lib/utils"
import { EmailLabelPickerBlock } from "@/components/gmail/email-label-picker-block"
import type { MoveTarget } from "@/components/gmail/move-to-menu-items"
import type { LabelPickerVisual } from "@/lib/label-picker-visual"
function SheetActionRow({
children,
onClick,
className,
style,
}: {
children: ReactNode
onClick: () => void
className?: string
style?: CSSProperties
}) {
return (
<button
type="button"
className={cn(
"flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-[#3c4043] transition-colors hover:bg-[#f1f3f4] active:bg-[#e8eaed]",
className
)}
style={style}
onClick={onClick}
>
{children}
</button>
)
}
const SheetLabelItem: ComponentType<{
children: ReactNode
onSelect?: (event: Event) => void
className?: string
}> = ({ children, onSelect, className }) => (
<div
role="button"
tabIndex={0}
className={cn(
"flex w-full cursor-pointer items-center gap-3 px-4 py-2.5 text-left text-sm text-[#3c4043] transition-colors hover:bg-[#f1f3f4] active:bg-[#e8eaed] outline-none focus-visible:bg-[#f1f3f4] focus-visible:ring-2 focus-visible:ring-[#1a73e8]/30",
className
)}
onClick={(e) => onSelect?.(e as unknown as Event)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
onSelect?.(e as unknown as Event)
}
}}
>
{children}
</div>
)
type CatalogLabelPresence = "none" | "some" | "all"
export type MobileXsBulkSheetsProps = {
moveSheetOpen: boolean
onMoveSheetOpenChange: (open: boolean) => void
labelSheetOpen: boolean
onLabelSheetOpenChange: (open: boolean) => void
labelPickerQuery: string
onLabelPickerQueryChange: (query: string) => void
catalogLabels: string[]
resolveLabelVisual: (label: string) => LabelPickerVisual
moveTargets: { recents: MoveTarget[]; system: MoveTarget[]; folders: MoveTarget[] }
onMoveTo: (targetId: string) => void
getLabelPresence: (label: string) => CatalogLabelPresence
onToggleCatalogLabel: (label: string) => void
onCreateLabel: (label: string) => void
}
export function MobileXsBulkSheets({
moveSheetOpen,
onMoveSheetOpenChange,
labelSheetOpen,
onLabelSheetOpenChange,
labelPickerQuery,
onLabelPickerQueryChange,
catalogLabels,
resolveLabelVisual,
moveTargets,
onMoveTo,
getLabelPresence,
onToggleCatalogLabel,
onCreateLabel,
}: MobileXsBulkSheetsProps) {
return (
<>
<Sheet open={moveSheetOpen} onOpenChange={onMoveSheetOpenChange}>
<SheetContent
side="bottom"
className="max-h-[min(85vh,520px)] gap-0 overflow-hidden rounded-t-2xl border-[#dadce0] px-0 pb-[max(1rem,env(safe-area-inset-bottom))] pt-2 [&>button]:top-3.5 [&>button]:right-3.5"
>
<SheetHeader className="border-b border-[#eceff1] px-4 pb-3 text-left">
<SheetTitle className="text-base font-medium text-[#3c4043]">
Déplacer vers
</SheetTitle>
</SheetHeader>
<div className="flex flex-col overflow-y-auto py-1">
{moveTargets.recents.length > 0 && (
<>
<div className="px-4 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
Récents
</div>
{moveTargets.recents.map((t) => (
<SheetActionRow
key={`recent-${t.id}`}
onClick={() => {
onMoveTo(t.id)
onMoveSheetOpenChange(false)
}}
>
<span className="flex items-center gap-2">
{t.icon ?? <FolderInput className="size-[18px] shrink-0 text-[#5f6368]" strokeWidth={1.5} />}
<Clock className="size-3 shrink-0 text-[#9aa0a6]" strokeWidth={1.5} />
</span>
{t.label}
</SheetActionRow>
))}
<div className="mx-4 border-b border-[#eceff1]" />
</>
)}
{moveTargets.system.map((t) => (
<SheetActionRow
key={t.id}
onClick={() => {
onMoveTo(t.id)
onMoveSheetOpenChange(false)
}}
>
{t.icon ?? <FolderInput className="size-[18px] shrink-0 text-[#5f6368]" strokeWidth={1.5} />}
{t.label}
</SheetActionRow>
))}
{moveTargets.folders.length > 0 && (
<>
<div className="mx-4 border-b border-[#eceff1]" />
<div className="px-4 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
Dossiers
</div>
{moveTargets.folders.map((t) => (
<SheetActionRow
key={t.id}
onClick={() => {
onMoveTo(t.id)
onMoveSheetOpenChange(false)
}}
style={t.depth > 0 ? { paddingLeft: `${16 + t.depth * 16}px` } : undefined}
>
{t.icon ?? <FolderInput className="size-[18px] shrink-0 text-[#5f6368]" strokeWidth={1.5} />}
{t.label}
</SheetActionRow>
))}
</>
)}
</div>
</SheetContent>
</Sheet>
<Sheet
open={labelSheetOpen}
onOpenChange={(open) => {
onLabelSheetOpenChange(open)
if (!open) onLabelPickerQueryChange("")
}}
>
<SheetContent
side="bottom"
className="max-h-[min(85vh,520px)] gap-0 overflow-hidden rounded-t-2xl border-[#dadce0] px-0 pb-[max(1rem,env(safe-area-inset-bottom))] pt-2 [&>button]:top-3.5 [&>button]:right-3.5"
onOpenAutoFocus={(e) => e.preventDefault()}
>
<SheetHeader className="shrink-0 border-b border-[#eceff1] px-4 pb-3 text-left">
<SheetTitle className="flex items-center gap-2 text-base font-medium text-[#3c4043]">
<Tag className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
Ajouter le libellé
</SheetTitle>
</SheetHeader>
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
<EmailLabelPickerBlock
query={labelPickerQuery}
onQueryChange={onLabelPickerQueryChange}
catalogLabels={catalogLabels}
resolveLabelVisual={resolveLabelVisual}
Item={SheetLabelItem}
getLabelPresence={getLabelPresence}
onToggleCatalogLabel={onToggleCatalogLabel}
onCreateLabel={onCreateLabel}
listClassName="max-h-[min(50vh,280px)] flex-1"
/>
</div>
</SheetContent>
</Sheet>
</>
)
}