// Draggable node for the tour/transit tool.
// Three rendering modes:
// - image : node.image is set (uploaded photo)
// - icon : node.icon is one of the Lucide icon names from icons.js
// - emoji/init : fallback (kept for compatibility / freeform notes)
function Node({
node, selected, onSelect, onDrag, onDragEnd, onDelete,
dragging, worldZoom,
}){
const ref = React.useRef(null);
const moveState = React.useRef(null);
const onPointerDown = (e) => {
if (e.target.closest('.delete-btn')) return;
e.stopPropagation();
// shiftKey is forwarded so Canvas can dispatch "copy times from this
// node into the currently-selected one" without selecting this node.
onSelect(node.id, { shiftKey: !!e.shiftKey });
const startX = e.clientX, startY = e.clientY;
const ox = node.x, oy = node.y;
moveState.current = { startX, startY, ox, oy, moved:false };
e.currentTarget.setPointerCapture(e.pointerId);
};
const onPointerMove = (e) => {
if (!moveState.current) return;
const { startX, startY, ox, oy } = moveState.current;
const dx = (e.clientX - startX) / worldZoom;
const dy = (e.clientY - startY) / worldZoom;
if (Math.abs(dx)+Math.abs(dy) > 2) moveState.current.moved = true;
onDrag(node.id, ox+dx, oy+dy);
};
const onPointerUp = (e) => {
if (!moveState.current) return;
const moved = moveState.current.moved;
moveState.current = null;
onDragEnd(node.id, moved);
try { e.currentTarget.releasePointerCapture(e.pointerId); } catch(_){}
};
// (Manual edge-drawing is gone: edges are auto-derived from each node's
// arrival/departure times. The connect-handle on the node has been
// removed accordingly.)
const shape = node.shape || 'square';
// node.highlight is a hex color used for an extra accent ring around the
// avatar. Independent of node.color (background). Used to mark "外せない
// 商談相手" / "今回の目玉スポット" — visual is also reflected in Schedule.
const hi = node.highlight || null;
const avatarStyle = {
background: node.color || '#FFFFFF',
...(hi ? {
borderColor: hi,
borderWidth: 3,
boxShadow: `0 0 0 3px ${hexAlpha(hi, 0.25)}, 0 2px 4px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.08)`,
} : {}),
};
let inner;
if (node.image){
inner = ;
} else if (node.icon && window.TourIcon){
inner =