'use client'; import { forwardRef, useState, useTransition, useRef, ReactNode } from 'react'; import type { WeeklyCheckInCategory } from '@prisma/client'; import { createWeeklyCheckInItem } from '@/actions/weekly-checkin'; import { WEEKLY_CHECK_IN_BY_CATEGORY, EMOTION_BY_TYPE } from '@/lib/types'; import { Select } from '@/components/ui/Select'; interface WeeklyCheckInSectionProps { category: WeeklyCheckInCategory; sessionId: string; isDraggingOver: boolean; children: ReactNode; } export const WeeklyCheckInSection = forwardRef( ({ category, sessionId, isDraggingOver, children, ...props }, ref) => { const [isAdding, setIsAdding] = useState(false); const [newContent, setNewContent] = useState(''); const [newEmotion, setNewEmotion] = useState<'NONE'>('NONE'); const [isPending, startTransition] = useTransition(); const isSubmittingRef = useRef(false); const config = WEEKLY_CHECK_IN_BY_CATEGORY[category]; async function handleAdd() { if (isSubmittingRef.current || !newContent.trim()) { setIsAdding(false); return; } isSubmittingRef.current = true; startTransition(async () => { await createWeeklyCheckInItem(sessionId, { content: newContent.trim(), category, emotion: newEmotion, }); setNewContent(''); setNewEmotion('NONE'); setIsAdding(false); isSubmittingRef.current = false; }); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleAdd(); } else if (e.key === 'Escape') { setIsAdding(false); setNewContent(''); setNewEmotion('NONE'); } } return (
{/* Header */}
{config.icon}

{config.title}

{config.description}

{/* Items */}
{children} {/* Add Form */} {isAdding && (
{ // Don't close if focus moves to another element in this container const currentTarget = e.currentTarget; const relatedTarget = e.relatedTarget as Node | null; if (relatedTarget && currentTarget.contains(relatedTarget)) { return; } // Only add on blur if content is not empty if (newContent.trim()) { handleAdd(); } else { setIsAdding(false); setNewContent(''); setNewEmotion('NONE'); } }} >