129 lines
4.3 KiB
TypeScript
129 lines
4.3 KiB
TypeScript
import { useState, useCallback, useRef, useEffect } from 'react'
|
|
import { createPortal } from 'react-dom'
|
|
import { cn } from '@/lib'
|
|
import { ItemImage } from '@/features/chat/components/ItemImage'
|
|
import { useChatInitStore } from '@/features/chat/stores/useChatInitStore'
|
|
|
|
export function ItemSection() {
|
|
return (
|
|
<div className="flex flex-col w-full flex-1 overflow-hidden min-h-0">
|
|
<ItemImage />
|
|
<ItemInfo />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface TooltipState {
|
|
text: string
|
|
x: number
|
|
y: number
|
|
above?: boolean
|
|
}
|
|
|
|
function Tooltip({ text, x, y, above }: TooltipState) {
|
|
return createPortal(
|
|
<div
|
|
className="fixed z-[9999] pointer-events-none"
|
|
style={{ left: x, top: y, transform: above ? 'translateY(-100%)' : undefined }}
|
|
>
|
|
<div className="px-3 py-2 mb-1 rounded-lg bg-neutral-20 text-neutral-90 text-[11px] leading-[16px] whitespace-pre-wrap break-keep max-w-[240px] shadow-md border border-neutral-30">
|
|
{text}
|
|
</div>
|
|
</div>,
|
|
document.body,
|
|
)
|
|
}
|
|
|
|
function ItemInfo() {
|
|
const {
|
|
item_code,
|
|
item_price,
|
|
item_vat_yn,
|
|
item_model_name,
|
|
item_maker_name,
|
|
item_min_order_quantity,
|
|
item_lead_time,
|
|
item_spec,
|
|
item_name,
|
|
} = useChatInitStore()
|
|
|
|
const [tooltip, setTooltip] = useState<TooltipState | null>(null)
|
|
const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
|
|
const showTooltip = useCallback((e: React.MouseEvent, text: string, above = false) => {
|
|
if (hideTimer.current) clearTimeout(hideTimer.current)
|
|
if (above) {
|
|
const rect = e.currentTarget.getBoundingClientRect()
|
|
setTooltip({ text, x: rect.left, y: rect.top - 8, above })
|
|
} else {
|
|
setTooltip({ text, x: e.clientX, y: e.clientY + 16, above })
|
|
}
|
|
}, [])
|
|
|
|
const hideTooltip = useCallback(() => {
|
|
hideTimer.current = setTimeout(() => setTooltip(null), 100)
|
|
}, [])
|
|
|
|
useEffect(() => () => {
|
|
if (hideTimer.current) clearTimeout(hideTimer.current)
|
|
}, [])
|
|
|
|
const formatPrice = (price: number) => price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
const isNewItem = !item_code && !item_price
|
|
const priceText = isNewItem ? '신규' : `${formatPrice(item_price)}원`
|
|
const formattedPrice = `${priceText}(${item_vat_yn || 'VAT별도'})`
|
|
|
|
const renderRow = (title: string, data: string, important = false) => {
|
|
const textClass = important ? 'title-3 text-neutral-90' : 'body-3 text-neutral-70'
|
|
const displayData = data || '-'
|
|
return (
|
|
<div className="flex items-start self-stretch gap-1 min-w-0">
|
|
<div className={cn(textClass, 'w-[100px]')}>{title}</div>
|
|
<div
|
|
className={cn(textClass, 'w-[150px] break-keep cursor-default')}
|
|
onMouseEnter={(e) => displayData !== '-' && showTooltip(e, displayData)}
|
|
onMouseLeave={hideTooltip}
|
|
>
|
|
{displayData}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col w-full flex-1 overflow-hidden min-h-0">
|
|
<div
|
|
className="text-center headline-3 text-neutral-90 mb-4 truncate px-8 flex-shrink-0 cursor-default"
|
|
onMouseEnter={(e) => item_name && showTooltip(e, item_name)}
|
|
onMouseLeave={hideTooltip}
|
|
>
|
|
{item_name}
|
|
</div>
|
|
|
|
<div className="flex flex-1 items-start self-stretch mr-2 overflow-y-auto pr-6 pl-8 min-h-0">
|
|
<div className="flex flex-col items-start self-stretch flex-[1_0_auto] gap-2 min-w-0">
|
|
{renderRow('상품코드', item_code, true)}
|
|
{renderRow('단가', formattedPrice, true)}
|
|
{renderRow('모델명', item_model_name, true)}
|
|
{renderRow('제조사', item_maker_name)}
|
|
{renderRow('최소주문수량', item_min_order_quantity)}
|
|
{renderRow('리드타임', item_lead_time)}
|
|
|
|
<div className="flex items-start self-stretch gap-1 flex-[1_0]">
|
|
<div className="body-3 text-neutral-70 w-[100px]">규격</div>
|
|
<div
|
|
className="body-3 text-neutral-70 self-stretch w-0 flex-[1_0] overflow-hidden whitespace-normal break-words break-keep cursor-default"
|
|
onMouseEnter={(e) => item_spec && showTooltip(e, item_spec, true)}
|
|
onMouseLeave={hideTooltip}
|
|
>
|
|
{item_spec || '-'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{tooltip && <Tooltip {...tooltip} />}
|
|
</div>
|
|
)
|
|
}
|