/** * 시간대 선택 — 하단 바 클릭·설정 화면 공용 */ import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { TIMEZONE_OPTIONS, formatUnixClock, getTimezoneAbbr, normalizeTimezone } from '../utils/timezone'; interface Props { value: string; onChange: (tz: string) => void; /** compact: 하단 바용 버튼 스타일 */ variant?: 'bar' | 'select'; /** 하단 바: 마지막 봉 시각 표시 (unix 초) */ displayUnix?: number; className?: string; } const TimezonePicker: React.FC = ({ value, onChange, variant = 'bar', displayUnix, className = '' }) => { const [open, setOpen] = useState(false); const [menuPos, setMenuPos] = useState<{ bottom: number; right: number } | null>(null); const rootRef = useRef(null); const triggerRef = useRef(null); const menuRef = useRef(null); const tz = normalizeTimezone(value); const updateMenuPos = useCallback(() => { const btn = triggerRef.current; if (!btn) return; const r = btn.getBoundingClientRect(); setMenuPos({ bottom: window.innerHeight - r.top + 4, right: Math.max(8, window.innerWidth - r.right), }); }, []); useLayoutEffect(() => { if (!open || variant !== 'bar') return; updateMenuPos(); const onResize = () => updateMenuPos(); window.addEventListener('resize', onResize); window.addEventListener('scroll', onResize, true); return () => { window.removeEventListener('resize', onResize); window.removeEventListener('scroll', onResize, true); }; }, [open, variant, updateMenuPos]); useEffect(() => { if (!open) return; const onDoc = (e: MouseEvent) => { const t = e.target as Node; if (rootRef.current?.contains(t) || menuRef.current?.contains(t)) return; setOpen(false); }; const id = window.setTimeout(() => { document.addEventListener('mousedown', onDoc); }, 0); return () => { window.clearTimeout(id); document.removeEventListener('mousedown', onDoc); }; }, [open]); if (variant === 'select') { return ( ); } const menu = open && variant === 'bar' && menuPos && (
    {TIMEZONE_OPTIONS.map(o => (
  • ))}
); return (
{menu && createPortal(menu, document.body)}
); }; export default TimezonePicker;