import { useState, useEffect, useRef } from 'react' import type { ContextMenuState, DayInfo } from './types' import type { SelectedCell } from './ScheduleTable' import { COLOR_PALETTE } from './cellColors' interface ContextMenuProps { state: ContextMenuState dayInfo: DayInfo personName: string | null cellValue: string | undefined cellColor: string | undefined existingDayComment: string | undefined existingCellComment: string | undefined existingTunnelClosure: string | undefined existingTunnelColor: string | undefined existingInfoRowClosure: string | undefined existingInfoRowColor: string | undefined selectedDays: number[] selectedCells: SelectedCell[] onSetCell: (personId: string, dayIdx: number, value: string | null) => void onAddDayComment: (dayIdx: number, text: string) => void onRemoveDayComment: (dayIdx: number) => void onAddCellComment: (personId: string, dayIdx: number, text: string) => void onRemoveCellComment: (personId: string, dayIdx: number) => void onSetTunnelClosure: (dayIdx: number, text: string | null) => void onSetCellColor: (personId: string, dayIdx: number, color: string | null) => void onSetTunnelClosureColor: (dayIdx: number, color: string | null) => void onSetInfoRowColor: (dayIdx: number, color: string | null) => void onClose: () => void } export function ContextMenu({ state, dayInfo, personName, cellValue, cellColor, existingDayComment, existingCellComment, existingTunnelClosure, existingTunnelColor, existingInfoRowClosure, existingInfoRowColor, selectedDays, selectedCells, onSetCell, onAddDayComment, onRemoveDayComment, onAddCellComment, onRemoveCellComment, onSetTunnelClosure, onSetCellColor, onSetTunnelClosureColor, onSetInfoRowColor, onClose, }: ContextMenuProps) { const isMultiSelect = selectedCells.length > 1 const [showCommentInput, setShowCommentInput] = useState(false) const [commentText, setCommentText] = useState('') const [showCellCommentInput, setShowCellCommentInput] = useState(false) const [cellCommentText, setCellCommentText] = useState('') const [cellValueInput, setCellValueInput] = useState(cellValue ?? '') const cellCommentInputRef = useRef(null) const commentInputRef = useRef(null) const cellValueInputRef = useRef(null) const menuRef = useRef(null) useEffect(() => { if (showCommentInput) commentInputRef.current?.focus() }, [showCommentInput]) useEffect(() => { if (showCellCommentInput) cellCommentInputRef.current?.focus() }, [showCellCommentInput]) useEffect(() => { const handleClick = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose() } } const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('mousedown', handleClick) document.addEventListener('keydown', handleKey) return () => { document.removeEventListener('mousedown', handleClick) document.removeEventListener('keydown', handleKey) } }, [onClose]) const handleAddComment = () => { if (commentText.trim()) { const days = selectedDays.length > 0 ? selectedDays : [state.dayIdx] for (const dayIdx of days) { onAddDayComment(dayIdx, commentText.trim()) } onClose() } } const handleRemoveComments = () => { const days = selectedDays.length > 0 ? selectedDays : [state.dayIdx] for (const dayIdx of days) { onRemoveDayComment(dayIdx) } onClose() } const handleSetCellValue = () => { const val = cellValueInput.trim() if (isMultiSelect) { for (const cell of selectedCells) { onSetCell(cell.personId, cell.dayIdx, val || null) } } else if (state.personId) { onSetCell(state.personId, state.dayIdx, val || null) } onClose() } const handleClearCell = () => { if (isMultiSelect) { for (const cell of selectedCells) { onSetCell(cell.personId, cell.dayIdx, null) } } else if (state.personId) { onSetCell(state.personId, state.dayIdx, null) } onClose() } const dateStr = `${dayInfo.day}.${dayInfo.month}.${dayInfo.year}` const isTunnelRow = !!state.isTunnelRow const isInfoRow = !!state.infoRowId const infoRowId = state.infoRowId const infoRowLabel = infoRowId === 'metro' ? 'METRO' : infoRowId === 'd8' ? 'D8' : '' const isDenRow = !state.personId && !isTunnelRow && !isInfoRow const multiDayLabel = selectedDays.length > 1 ? ` (${selectedDays.length} dnu)` : '' const renderColorPalette = () => { const activeColor = isTunnelRow ? existingTunnelColor : isInfoRow ? existingInfoRowColor : cellColor return (
Barva pozadi
{COLOR_PALETTE.map(({ color, label }) => { const isActive = activeColor === color return ( ) })}
) } return (
{isTunnelRow ? ( UZAVERY ) : isInfoRow ? ( {infoRowLabel} ) : isDenRow ? ( DEN{multiDayLabel} ) : isMultiSelect ? ( Vybrano {selectedCells.length} bunek ) : ( {personName || state.personId} )} -- {dateStr} (T{dayInfo.week})
{isInfoRow ? ( <> {existingInfoRowClosure && (
{existingInfoRowClosure}
)} {renderColorPalette()} ) : isTunnelRow ? ( <> {existingTunnelClosure && (
{existingTunnelClosure}
)} {renderColorPalette()} ) : isDenRow ? ( <> {existingDayComment && !showCommentInput ? ( <>
{existingDayComment}
) : ( <> {!showCommentInput ? ( ) : (
setCommentText(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleAddComment() }} placeholder="Komentar ke dni..." className="w-full bg-slate-900 border border-slate-600 rounded px-2 py-1.5 text-xs text-slate-200 placeholder-slate-500 outline-none focus:border-blue-500 transition-colors" />
)} )} ) : ( <> {/* Cell value editing */}
setCellValueInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleSetCellValue() }} placeholder="8, 12, D, N, U, O, D/2, x" className="flex-1 bg-slate-900 border border-slate-600 rounded px-2 py-1.5 text-xs text-slate-200 placeholder-slate-500 outline-none focus:border-blue-500 transition-colors" />
{/* Clear cell */} {(cellValue || isMultiSelect) && ( )} {/* Cell comment section - hidden for multi-select */} {!isMultiSelect &&
{existingCellComment ? ( <>
{existingCellComment}
) : ( <> {!showCellCommentInput ? ( ) : (
setCellCommentText(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && cellCommentText.trim() && state.personId) { onAddCellComment(state.personId, state.dayIdx, cellCommentText.trim()) onClose() } }} placeholder="Komentar k bunce..." className="w-full bg-slate-900 border border-slate-600 rounded px-2 py-1.5 text-xs text-slate-200 placeholder-slate-500 outline-none focus:border-blue-500 transition-colors" />
)} )}
} {renderColorPalette()} )}
) }