feat: Enhance FieldWithHistory component with improved tooltip display and time formatting

This commit is contained in:
2025-10-02 10:01:54 +02:00
parent 50760ab099
commit 31736ccc78

View File

@@ -4,6 +4,8 @@ import { useState, useEffect } from "react";
import Tooltip from "@/components/ui/Tooltip"; import Tooltip from "@/components/ui/Tooltip";
import { formatDate } from "@/lib/utils"; import { formatDate } from "@/lib/utils";
import { useTranslation } from "@/lib/i18n"; import { useTranslation } from "@/lib/i18n";
import { formatDistanceToNow } from "date-fns";
import { pl, enUS } from "date-fns/locale";
export default function FieldWithHistory({ export default function FieldWithHistory({
tableName, tableName,
@@ -14,11 +16,14 @@ export default function FieldWithHistory({
label = null, label = null,
className = "", className = "",
}) { }) {
const { t } = useTranslation(); const { t, language } = useTranslation();
const [hasHistory, setHasHistory] = useState(false); const [hasHistory, setHasHistory] = useState(false);
const [history, setHistory] = useState([]); const [history, setHistory] = useState([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
// Get locale for date-fns
const locale = language === 'pl' ? pl : enUS;
useEffect(() => { useEffect(() => {
const fetchHistory = async () => { const fetchHistory = async () => {
try { try {
@@ -59,33 +64,95 @@ export default function FieldWithHistory({
// Create tooltip content // Create tooltip content
const tooltipContent = history.length > 0 && ( const tooltipContent = history.length > 0 && (
<div className="space-y-2"> <div className="space-y-2 max-w-sm">
<div className="font-medium text-white mb-2">{t("common.changeHistory")}:</div> <div className="flex items-center gap-2 font-semibold text-white mb-3 pb-2 border-b border-gray-600">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{t("common.changeHistory")} ({history.length})
</div>
{history.map((change, index) => ( {history.map((change, index) => (
<div key={change.id} className="text-xs border-b border-gray-600 pb-1 last:border-b-0"> <div
<div className="flex justify-between items-start gap-2"> key={change.id}
className="text-xs border-b border-gray-700 pb-2 last:border-b-0 hover:bg-gray-800/30 p-2 rounded transition-colors"
>
<div className="flex justify-between items-start gap-3 mb-2">
<div className="flex-1"> <div className="flex-1">
<div className="text-white font-medium"> {/* New Value */}
{t("common.changedTo")}: {getDisplayValue(change.new_value)} <div className="flex items-start gap-2 mb-1">
<svg className="w-3.5 h-3.5 text-green-400 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<div>
<span className="text-green-400 font-medium text-[10px] uppercase tracking-wide block mb-0.5">
{t("common.changedTo")}
</span>
<span className="text-white font-semibold">
{getDisplayValue(change.new_value)}
</span>
</div>
</div> </div>
{/* Old Value */}
{change.old_value && ( {change.old_value && (
<div className="text-gray-400 text-xs"> <div className="flex items-start gap-2 mb-1">
{t("common.from")}: {getDisplayValue(change.old_value)} <svg className="w-3.5 h-3.5 text-red-400 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
<div>
<span className="text-red-400 font-medium text-[10px] uppercase tracking-wide block mb-0.5">
{t("common.from")}
</span>
<span className="text-gray-300 line-through">
{getDisplayValue(change.old_value)}
</span>
</div>
</div> </div>
)} )}
{/* Changed By */}
{change.changed_by_name && ( {change.changed_by_name && (
<div className="text-gray-300"> <div className="flex items-center gap-1.5 mt-2 text-gray-400">
{t("common.by")} {change.changed_by_name} <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<span className="text-xs">
{t("common.by")} <span className="text-gray-200 font-medium">{change.changed_by_name}</span>
</span>
</div> </div>
)} )}
</div> </div>
<div className="text-gray-400 text-right text-xs">
{formatDate(change.changed_at)} {/* Timestamp */}
<div className="text-right flex-shrink-0">
<div className="text-gray-400 text-[10px] whitespace-nowrap">
{formatDistanceToNow(new Date(change.changed_at), {
addSuffix: true,
locale: locale
})}
</div>
<div className="text-gray-500 text-[9px] mt-0.5">
{formatDate(change.changed_at)}
</div>
</div> </div>
</div> </div>
{/* Change Reason */}
{change.change_reason && ( {change.change_reason && (
<div className="text-gray-400 text-xs mt-1"> <div className="mt-2 pt-2 border-t border-gray-700">
{t("common.reason")}: {change.change_reason} <div className="flex items-start gap-1.5">
<svg className="w-3 h-3 text-amber-400 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div>
<span className="text-amber-400 font-medium text-[10px] uppercase tracking-wide block mb-0.5">
{t("common.reason")}
</span>
<span className="text-gray-300 text-xs italic">
{change.change_reason}
</span>
</div>
</div>
</div> </div>
)} )}
</div> </div>
@@ -109,17 +176,27 @@ export default function FieldWithHistory({
<p className="text-gray-900 font-medium">{getDisplayValue(currentValue)}</p> <p className="text-gray-900 font-medium">{getDisplayValue(currentValue)}</p>
{hasHistory && ( {hasHistory && (
<Tooltip content={tooltipContent}> <Tooltip content={tooltipContent}>
<svg <div className="relative group cursor-help">
className="w-4 h-4 text-blue-500 hover:text-blue-700 cursor-help" {/* History Icon with Badge */}
fill="currentColor" <div className="flex items-center gap-1 px-2 py-1 rounded-full bg-blue-50 hover:bg-blue-100 transition-colors border border-blue-200">
viewBox="0 0 20 20" <svg
> className="w-3.5 h-3.5 text-blue-600 group-hover:text-blue-700 transition-colors"
<path fill="none"
fillRule="evenodd" stroke="currentColor"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" viewBox="0 0 24 24"
clipRule="evenodd" >
/> <path
</svg> strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span className="text-[10px] font-semibold text-blue-600 group-hover:text-blue-700 transition-colors">
{history.length}
</span>
</div>
</div>
</Tooltip> </Tooltip>
)} )}
</div> </div>