Files
eventify_command_center/src/features/users/components/shared/AdminNote.tsx

77 lines
2.8 KiB
TypeScript

'use client';
import { useState, useEffect, useRef } from 'react';
import { Textarea } from '@/components/ui/textarea';
import { Loader2, Check } from 'lucide-react';
import { saveUserNote } from '@/lib/actions/user-tabs';
import { toast } from 'sonner';
interface AdminNoteProps {
userId: string;
initialNote?: string;
}
export function AdminNote({ userId, initialNote = '' }: AdminNoteProps) {
const [content, setContent] = useState(initialNote);
const [status, setStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');
const timeoutRef = useRef<NodeJS.Timeout>(null);
// Sync remote changes if any (unlikely in single user flow but good practice)
useEffect(() => {
setContent(initialNote || '');
}, [initialNote]);
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newValue = e.target.value;
setContent(newValue);
setStatus('idle');
// Debounce save
if (timeoutRef.current) clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(async () => {
if (newValue.trim() === initialNote.trim()) return;
setStatus('saving');
const result = await saveUserNote(userId, newValue);
if (result.success) {
setStatus('saved');
// Reset saved status after 2 seconds
setTimeout(() => setStatus('idle'), 2000);
} else {
setStatus('error');
toast.error("Failed to save note");
}
}, 1000); // 1s delay
};
return (
<div className="relative">
<Textarea
value={content}
onChange={handleChange}
placeholder="Add private notes about this user..."
className="min-h-[120px] bg-amber-50/50 border-amber-200/50 resize-y text-sm focus-visible:ring-amber-500/20"
/>
<div className="absolute bottom-2 right-2 flex items-center gap-1.5 pointer-events-none">
{status === 'saving' && (
<span className="text-[10px] text-amber-600 flex items-center gap-1 bg-white/50 px-1.5 rounded-full">
<Loader2 className="h-3 w-3 animate-spin" /> Saving...
</span>
)}
{status === 'saved' && (
<span className="text-[10px] text-emerald-600 flex items-center gap-1 bg-white/50 px-1.5 rounded-full font-medium">
<Check className="h-3 w-3" /> Saved
</span>
)}
{status === 'error' && (
<span className="text-[10px] text-red-600 bg-white/50 px-1.5 rounded-full">
Not Saved
</span>
)}
</div>
</div>
);
}