'use client'
import { cn } from '@/lib/utils'
import { addDays, differenceInCalendarDays } from 'date-fns'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import React from 'react'
import { motion as m, AnimatePresence } from 'motion/react'
interface PickCloseDayProps extends React.HTMLAttributes<HTMLDivElement> {
/** Initial or controlled date (defaults to today) */
date?: Date
/** Fires whenever the date changes */
onDateChange?: (date: Date) => void
}
export function PickCloseDay({
date: controlledDate,
onDateChange,
className,
...rest
}: PickCloseDayProps) {
// Uncontrolled fallback
const [internalDate, setInternalDate] = React.useState(new Date())
const date = controlledDate ?? internalDate
// Compute slide direction based on previous date
const prevDateRef = React.useRef(date)
const direction =
date.getTime() - prevDateRef.current.getTime() > 0 ? 1 : -1
React.useEffect(() => {
prevDateRef.current = date
}, [date])
// Variants for sliding transition
const variants = {
enter: (direction: number) => ({
x: direction > 0 ? 20 : -20,
opacity: 0,
}),
center: { x: 0, opacity: 1 },
exit: (direction: number) => ({
x: direction > 0 ? -20 : 20,
opacity: 0,
}),
}
const label = React.useMemo(() => {
const delta = differenceInCalendarDays(date, new Date())
if (delta === 0) return 'Today'
if (delta === -1) return 'Yesterday'
if (delta === 1) return 'Tomorrow'
if (delta < 0) return `${Math.abs(delta)} days ago`
return `In ${delta} days`
}, [date])
const shift = (by: number) => {
const next = addDays(date, by)
if (!controlledDate) setInternalDate(next)
onDateChange?.(next)
}
return (
<div
{...rest}
className={cn(
'inline-flex items-center gap-2 select-none',
'bg-accent text-accent-foreground rounded-md px-3 py-1.5',
className
)}
>
<button
type="button"
aria-label="Previous day"
onClick={() => shift(-1)}
>
<ChevronLeft className="h-4 w-4" />
</button>
<AnimatePresence mode="wait">
<m.span
key={date.toISOString()}
custom={direction}
variants={variants}
initial="enter"
animate="center"
exit="exit"
transition={{ duration: 0.3 }}
style={{ display: 'inline-block' }}
>
{label}
</m.span>
</AnimatePresence>
<button
type="button"
aria-label="Next day"
onClick={() => shift(1)}
>
<ChevronRight className="h-4 w-4" />
</button>
</div>
)
}