"use client"; import { RiAddLine, RiCheckboxCircleFill } from "@remixicon/react"; import type { KeyboardEvent, MouseEvent } from "react"; import type { CalendarDay, CalendarEvent } from "@/shared/lib/types/calendar"; import { currencyFormatter } from "@/shared/utils/currency"; import { cn } from "@/shared/utils/ui"; type DayCellProps = { day: CalendarDay; onSelect: (day: CalendarDay) => void; onCreate: (day: CalendarDay) => void; }; export const EVENT_TYPE_STYLES: Record< CalendarEvent["type"], { wrapper: string; dot: string } > = { transaction: { wrapper: "bg-primary/10 text-primary dark:bg-primary/5 dark:text-primary", dot: "bg-primary", }, installment: { wrapper: "bg-amber-100 text-amber-600 dark:bg-amber-900/10 dark:text-amber-500", dot: "bg-amber-500", }, boleto: { wrapper: "bg-info/10 text-info dark:bg-info/5 dark:text-info", dot: "bg-info", }, card: { wrapper: "bg-violet-100 text-violet-600 dark:bg-violet-900/10 dark:text-violet-500", dot: "bg-violet-600 dark:bg-violet-500", }, }; const formatCurrencyValue = (value: number | null | undefined) => currencyFormatter.format(Math.abs(value ?? 0)); const buildEventLabel = (event: CalendarEvent) => { switch (event.type) { case "transaction": case "boleto": return event.transaction.name; case "installment": return event.transaction.name; case "card": return event.card.name; default: return ""; } }; const buildEventComplement = (event: CalendarEvent) => { switch (event.type) { case "transaction": case "boleto": return formatCurrencyValue(event.transaction.amount); case "installment": return `${event.installmentCount}x de ${formatCurrencyValue(event.installmentValue)}`; case "card": return event.card.totalDue !== null ? formatCurrencyValue(event.card.totalDue) : null; default: return null; } }; const isPaid = (event: CalendarEvent) => { if (event.type === "boleto") return Boolean(event.transaction.isSettled); if (event.type === "card") return event.card.isPaid; return false; }; const DayEventPreview = ({ event }: { event: CalendarEvent }) => { const complement = buildEventComplement(event); const label = buildEventLabel(event); const style = EVENT_TYPE_STYLES[event.type]; return (
{label} {isPaid(event) && ( )}
{complement ? ( {complement} ) : null}
); }; export function DayCell({ day, onSelect, onCreate }: DayCellProps) { const previewEvents = day.events.slice(0, 3); const hasOverflow = day.events.length > 3; const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Enter" || event.key === " " || event.key === "Space") { event.preventDefault(); onSelect(day); } }; const handleCreateClick = (event: MouseEvent) => { event.stopPropagation(); onCreate(day); }; const overflowCount = day.events.length - previewEvents.length; return (
onSelect(day)} onKeyDown={handleKeyDown} className={cn( "group flex h-full cursor-pointer flex-col gap-1.5 rounded-lg border bg-card/70 p-2 text-left transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 hover:border-primary/40 hover:bg-primary/5 dark:hover:bg-accent", !day.isCurrentMonth && "bg-muted/20 opacity-60", day.isToday && "border-primary/70 bg-primary/5 hover:border-primary", )} >
{day.label} {day.isCurrentMonth && ( )}
{day.isCurrentMonth && previewEvents.map((event) => ( ))} {day.isCurrentMonth && hasOverflow ? ( +{overflowCount} mais ) : null}
); }