diff --git a/resources/views/finance/journal-entries.blade.php b/resources/views/finance/journal-entries.blade.php index 4e81b90d..0b7ea3a7 100644 --- a/resources/views/finance/journal-entries.blade.php +++ b/resources/views/finance/journal-entries.blade.php @@ -103,7 +103,10 @@ const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(''); const [highlightIndex, setHighlightIndex] = useState(-1); + const [dropdownStyle, setDropdownStyle] = useState({}); const containerRef = useRef(null); + const triggerRef = useRef(null); + const dropdownRef = useRef(null); const listRef = useRef(null); const selectedItem = accountCodes.find(c => c.code === value); @@ -119,7 +122,8 @@ useEffect(() => { const handleClickOutside = (e) => { - if (containerRef.current && !containerRef.current.contains(e.target)) { + if (containerRef.current && !containerRef.current.contains(e.target) && + (!dropdownRef.current || !dropdownRef.current.contains(e.target))) { setIsOpen(false); setSearch(''); setHighlightIndex(-1); } }; @@ -127,6 +131,20 @@ return () => document.removeEventListener('mousedown', handleClickOutside); }, []); + const calcDropdownPos = () => { + if (!triggerRef.current) return; + const rect = triggerRef.current.getBoundingClientRect(); + const spaceBelow = window.innerHeight - rect.bottom; + const openUp = spaceBelow < 260; + setDropdownStyle({ + position: 'fixed', + left: rect.left, + width: Math.max(rect.width, 224), + zIndex: 9999, + ...(openUp ? { bottom: window.innerHeight - rect.top + 4 } : { top: rect.bottom + 4 }), + }); + }; + const handleSelect = (code) => { onChange(code.code, code.name); setIsOpen(false); setSearch(''); setHighlightIndex(-1); @@ -155,7 +173,7 @@ return (
-
setIsOpen(!isOpen)} +
{ if (!isOpen) calcDropdownPos(); setIsOpen(!isOpen); }} className={`w-full px-2 py-1.5 text-xs border rounded cursor-pointer flex items-center justify-between gap-1 ${isOpen ? 'border-emerald-500 ring-2 ring-emerald-500' : 'border-stone-200'} bg-white`}> {displayText || '계정과목 선택'}
@@ -165,8 +183,8 @@ className={`w-full px-2 py-1.5 text-xs border rounded cursor-pointer flex items-
- {isOpen && ( -
+ {isOpen && ReactDOM.createPortal( +
setSearch(e.target.value)} onKeyDown={handleKeyDown} placeholder="코드 또는 이름 검색..." className="w-full px-2 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-emerald-500 outline-none" autoFocus /> @@ -183,7 +201,8 @@ className={`px-3 py-1.5 text-xs cursor-pointer ${index === highlightIndex ? 'bg- ))} {filteredCodes.length > 50 &&
+{filteredCodes.length - 50}개 더 있음
}
-
+
, + document.body )}
); @@ -456,7 +475,10 @@ className="px-4 py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg ho const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(''); const [highlightIndex, setHighlightIndex] = useState(-1); + const [dropdownStyle, setDropdownStyle] = useState({}); const containerRef = useRef(null); + const triggerRef = useRef(null); + const dropdownRef = useRef(null); const listRef = useRef(null); const displayText = valueName || ''; @@ -470,7 +492,8 @@ className="px-4 py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg ho useEffect(() => { setHighlightIndex(-1); }, [search]); useEffect(() => { const handleClickOutside = (e) => { - if (containerRef.current && !containerRef.current.contains(e.target)) { + if (containerRef.current && !containerRef.current.contains(e.target) && + (!dropdownRef.current || !dropdownRef.current.contains(e.target))) { setIsOpen(false); setSearch(''); setHighlightIndex(-1); } }; @@ -478,6 +501,20 @@ className="px-4 py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg ho return () => document.removeEventListener('mousedown', handleClickOutside); }, []); + const calcDropdownPos = () => { + if (!triggerRef.current) return; + const rect = triggerRef.current.getBoundingClientRect(); + const spaceBelow = window.innerHeight - rect.bottom; + const openUp = spaceBelow < 280; + setDropdownStyle({ + position: 'fixed', + left: rect.left, + width: Math.max(rect.width, 224), + zIndex: 9999, + ...(openUp ? { bottom: window.innerHeight - rect.top + 4 } : { top: rect.bottom + 4 }), + }); + }; + const handleSelect = (partner) => { onChange(partner.id, partner.name); setIsOpen(false); setSearch(''); setHighlightIndex(-1); @@ -506,7 +543,7 @@ className="px-4 py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg ho return (
-
setIsOpen(!isOpen)} +
{ if (!isOpen) calcDropdownPos(); setIsOpen(!isOpen); }} className={`w-full px-2 py-1.5 text-xs border rounded cursor-pointer flex items-center justify-between gap-1 ${isOpen ? 'border-emerald-500 ring-2 ring-emerald-500' : 'border-stone-200'} bg-white`}> {displayText || '거래처 선택'}
@@ -516,8 +553,8 @@ className={`w-full px-2 py-1.5 text-xs border rounded cursor-pointer flex items-
- {isOpen && ( -
+ {isOpen && ReactDOM.createPortal( +
setSearch(e.target.value)} onKeyDown={handleKeyDown} placeholder="거래처명 또는 사업자번호 검색..." className="w-full px-2 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-emerald-500 outline-none" autoFocus /> @@ -539,7 +576,8 @@ className={`px-3 py-1.5 text-xs cursor-pointer ${index === highlightIndex ? 'bg-
))}
-
+
, + document.body )}
); @@ -962,9 +1000,9 @@ className="px-2.5 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-f return (
-
+
{/* 헤더 */} -
+

{isEditMode ? `전표 수정 (${existingEntryNo})` : '수동 전표 생성'}

@@ -973,7 +1011,7 @@ className="px-2.5 py-1 text-xs font-medium bg-amber-100 text-amber-700 rounded-f
-
+
{loadingEntry ? (
@@ -1116,7 +1154,7 @@ className={`p-1 rounded ${lines.length <= 2 ? 'text-stone-200 cursor-not-allowed
{/* 하단 버튼 */} -
+
{isEditMode && (
-
+
{/* 거래 정보 카드 */}

거래 정보

@@ -1515,7 +1553,7 @@ className={`p-1 rounded ${lines.length <= 2 ? 'text-stone-200 cursor-not-allowed
{/* 하단 버튼 */} -
+
{isEditMode && (