File size: 5,079 Bytes
cd99321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import React from 'react'
import { Plus, Check, Route } from 'lucide-react'
import PlaceAvatar from '../shared/PlaceAvatar'
import { getCategoryIcon } from '../shared/categoryIcons'
import type { Place, Category } from '../../types'

interface MemoPlaceRowProps {
  place: Place
  category: Category | undefined
  isSelected: boolean
  isPlanned: boolean
  inDay: boolean
  isChecked: boolean
  selectMode: boolean
  selectedDayId: number | null
  canEditPlaces: boolean
  isMobile: boolean
  t: (key: string, params?: Record<string, any>) => string
  onPlaceClick: (id: number | null) => void
  onContextMenu: (e: React.MouseEvent, place: Place) => void
  onAssignToDay: (placeId: number, dayId?: number) => void
  toggleSelected: (id: number) => void
  setDayPickerPlace: (place: any) => void
}

export const MemoPlaceRow = React.memo(function MemoPlaceRow({
  place, category: cat, isSelected, isPlanned, inDay, isChecked,
  selectMode, selectedDayId, canEditPlaces, isMobile, t,
  onPlaceClick, onContextMenu, onAssignToDay, toggleSelected, setDayPickerPlace,
}: MemoPlaceRowProps) {
  const hasGeometry = Boolean(place.route_geometry)
  return (
    <div
      key={place.id}
      draggable={!selectMode}
      onDragStart={e => {
        e.dataTransfer.setData('placeId', String(place.id))
        e.dataTransfer.effectAllowed = 'copy'
        window.__dragData = { placeId: String(place.id) }
      }}
      onClick={() => {
        if (selectMode) {
          toggleSelected(place.id)
        } else if (isMobile) {
          setDayPickerPlace(place)
        } else {
          onPlaceClick(isSelected ? null : place.id)
        }
      }}
      onContextMenu={selectMode ? undefined : e => onContextMenu(e, place)}
      style={{
        display: 'flex', alignItems: 'center', gap: 10,
        padding: '9px 14px 9px 16px',
        cursor: selectMode ? 'pointer' : 'grab',
        background: isChecked ? 'color-mix(in srgb, var(--accent) 8%, transparent)' : isSelected ? 'var(--border-faint)' : 'transparent',
        borderBottom: '1px solid var(--border-faint)',
        transition: 'background 0.1s',
        contentVisibility: 'auto',
        containIntrinsicSize: '0 52px',
      }}
      onMouseEnter={e => { if (!isSelected && !isChecked) e.currentTarget.style.background = 'var(--bg-hover)' }}
      onMouseLeave={e => { if (!isSelected && !isChecked) e.currentTarget.style.background = 'transparent' }}
    >
      {selectMode && (
        <div className={isChecked ? 'bg-accent' : 'bg-transparent'} style={{
          width: 16, height: 16, borderRadius: 4, flexShrink: 0,
          border: isChecked ? 'none' : '1.5px solid var(--border-primary)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {isChecked && <Check size={10} strokeWidth={3} color="white" />}
        </div>
      )}
      <PlaceAvatar place={place} category={cat} size={34} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 5, overflow: 'hidden' }}>
          {hasGeometry && <span title="Track / Route" style={{ display: 'inline-flex', flexShrink: 0 }}><Route size={11} strokeWidth={2} color="var(--text-faint)" /></span>}
          {cat && (() => {
            const CatIcon = getCategoryIcon(cat.icon)
            return <span title={cat.name} style={{ display: 'inline-flex', flexShrink: 0 }}><CatIcon size={11} strokeWidth={2} color={cat.color || '#6366f1'} /></span>
          })()}
          <span className="text-content" style={{ fontSize: 13, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', lineHeight: 1.2 }}>
            {place.name}
          </span>
        </div>
        {(place.description || place.address || cat?.name) && (
          <div style={{ marginTop: 2 }}>
            <span className="text-content-faint" style={{ fontSize: 11, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block', lineHeight: 1.2 }}>
              {place.description || place.address || cat?.name}
            </span>
          </div>
        )}
      </div>
      <div style={{ flexShrink: 0, display: 'flex', alignItems: 'center' }}>
        {!selectMode && !inDay && selectedDayId && (
          <button
            onClick={e => { e.stopPropagation(); onAssignToDay(place.id) }}
            className="bg-surface-hover text-content-faint"
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 20, height: 20, borderRadius: 6,
              border: 'none', cursor: 'pointer',
              padding: 0, transition: 'background 0.15s, color 0.15s',
            }}
            onMouseEnter={e => { e.currentTarget.style.background = 'var(--accent)'; e.currentTarget.style.color = 'var(--accent-text)' }}
            onMouseLeave={e => { e.currentTarget.style.background = 'var(--bg-hover)'; e.currentTarget.style.color = 'var(--text-faint)' }}
          ><Plus size={12} strokeWidth={2.5} /></button>
        )}
      </div>
    </div>
  )
})