"use client"; import * as React from "react"; import moment from "moment"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "../../../lib/utils"; const relativeTimeCardVariants = cva( "inline-flex items-center gap-2 rounded-md px-2.5 py-1 text-sm font-medium", { variants: { variant: { default: "bg-muted text-muted-foreground", subtle: "bg-transparent text-muted-foreground", outline: "border border-border text-foreground", accent: "bg-accent text-accent-foreground", }, size: { default: "text-sm px-2.5 py-1", sm: "text-xs px-2 py-0.5", lg: "text-base px-3 py-1.5", }, }, defaultVariants: { variant: "default", size: "default", }, } ); interface RelativeTimeCardProps extends React.HTMLAttributes, VariantProps { /** Date value — accepts Date, string in any format, number (timestamp), or Moment */ date: Date | string | number | moment.Moment; /** Input format hint if date is a string (e.g. "DD.MM.YYYY HH:mm"). Auto-detected if omitted. */ inputFormat?: string; /** Display format: relative | auto | datetime | custom */ format?: "relative" | "auto" | "datetime" | "custom"; /** Custom output format string (moment format). Used when format="custom" */ outputFormat?: string; /** Update interval in ms for relative format. @default 60000 */ updateInterval?: number; /** Text before the time */ prefix?: string; /** Text after the time */ suffix?: string; /** Locale for display. @default "en" */ locale?: string; /** Use UTC for all calculations. @default true */ utc?: boolean; } function parseDate( value: Date | string | number | moment.Moment, inputFormat?: string, useUtc: boolean = true ): moment.Moment { if (moment.isMoment(value)) { return useUtc ? value.utc() : value.local(); } const m = useUtc ? moment.utc : moment; if (value instanceof Date) { return m(value); } if (typeof value === "number") { return m(value); } if (typeof value === "string") { if (inputFormat) { return m(value, inputFormat, true); } return m(value); } return m(); } function getRelativeTime(date: moment.Moment, locale: string = "en"): string { moment.locale(locale); return date.fromNow(); } function getAutoFormat(date: moment.Moment, locale: string = "en"): string { moment.locale(locale); const now = moment(); const diffHours = now.diff(date, "hours"); const diffDays = now.diff(date, "days"); if (diffHours < 24) { return date.format("HH:mm"); } if (diffDays < 7) { return date.format("ddd"); } if (diffDays < 365) { return date.format("MMM D"); } return date.format("MMM D, YYYY"); } function getDateTimeFormat(date: moment.Moment, locale: string = "en"): string { moment.locale(locale); return date.format("MMM D, YYYY HH:mm"); } function formatDate( date: moment.Moment, format: "relative" | "auto" | "datetime" | "custom", locale: string, outputFormat?: string ): string { switch (format) { case "relative": return getRelativeTime(date, locale); case "auto": return getAutoFormat(date, locale); case "datetime": return getDateTimeFormat(date, locale); case "custom": moment.locale(locale); return date.format(outputFormat || "YYYY-MM-DD HH:mm"); } } const RelativeTimeCard = React.forwardRef< HTMLTimeElement, RelativeTimeCardProps >( ( { date, inputFormat, format = "relative", outputFormat, updateInterval = 60000, prefix, suffix, locale = "en", utc = true, className, variant, size, ...props }, ref ) => { const dateObj = React.useMemo( () => parseDate(date, inputFormat, utc), [date, inputFormat, utc] ); const [display, setDisplay] = React.useState(() => formatDate(dateObj, format, locale, outputFormat) ); React.useEffect(() => { setDisplay(formatDate(dateObj, format, locale, outputFormat)); if (format !== "relative") return; const id = setInterval(() => { setDisplay(formatDate(dateObj, format, locale, outputFormat)); }, updateInterval); return () => clearInterval(id); }, [dateObj, format, locale, outputFormat, updateInterval]); const isoString = dateObj.toISOString(); const title = dateObj.format("LLLL"); return ( ); } ); RelativeTimeCard.displayName = "RelativeTimeCard"; export { RelativeTimeCard, relativeTimeCardVariants }; export type { RelativeTimeCardProps };