import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { useAppSelector } from '@/hooks/useAppSelector'; import { useSocket } from '@/socket/socketContext'; import { SocketEvents } from '@/shared/socket-events'; import { Task } from '@/types/task-management.types'; import { ClearOutlined } from '@ant-design/icons'; interface TaskPhaseDropdownProps { task: Task; projectId: string; isDarkMode?: boolean; } const TaskPhaseDropdown: React.FC = ({ task, projectId, isDarkMode = false }) => { const { socket, connected } = useSocket(); const [isOpen, setIsOpen] = useState(false); const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 }); const buttonRef = useRef(null); const dropdownRef = useRef(null); const { phaseList } = useAppSelector(state => state.phaseReducer); // Find current phase details const currentPhase = useMemo(() => { return phaseList.find(phase => phase.name === task.phase); }, [phaseList, task.phase]); // Handle phase change const handlePhaseChange = useCallback((phaseId: string, phaseName: string) => { if (!task.id || !phaseId || !connected) return; console.log('🎯 Phase change initiated:', { taskId: task.id, phaseId, phaseName }); socket?.emit( SocketEvents.TASK_PHASE_CHANGE.toString(), { task_id: task.id, phase_id: phaseId, parent_task: null, // Assuming top-level tasks for now } ); setIsOpen(false); }, [task.id, connected, socket]); // Handle phase clear const handlePhaseClear = useCallback(() => { if (!task.id || !connected) return; console.log('🎯 Phase clear initiated:', { taskId: task.id }); socket?.emit( SocketEvents.TASK_PHASE_CHANGE.toString(), { task_id: task.id, phase_id: null, parent_task: null, } ); setIsOpen(false); }, [task.id, connected, socket]); // Calculate dropdown position and handle outside clicks useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (buttonRef.current && buttonRef.current.contains(event.target as Node)) { return; // Don't close if clicking the button } if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } }; if (isOpen && buttonRef.current) { // Calculate position const rect = buttonRef.current.getBoundingClientRect(); setDropdownPosition({ top: rect.bottom + window.scrollY + 4, left: rect.left + window.scrollX, }); document.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [isOpen]); // Get phase color const getPhaseColor = useCallback((phase: any) => { return phase?.color_code || '#722ed1'; }, []); // Format phase name for display const formatPhaseName = useCallback((name: string) => { if (!name) return 'Select'; return name; }, []); // Determine if no phase is selected const hasPhase = task.phase && task.phase.trim() !== ''; return ( <> {/* Phase Button - Show "Select" when no phase */} {/* Dropdown Menu */} {isOpen && createPortal(
{/* Phase Options */}
{/* No Phase Option */} {/* Phase Options */} {phaseList.map((phase, index) => { const isSelected = phase.name === task.phase; return ( ); })}
, document.body )} {/* CSS Animations */} {isOpen && createPortal( , document.head )} ); }; export default TaskPhaseDropdown;