mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
feat: show date badge on day selectors + i18n transport modal titles
Day selectors in the Transport, Reservation and Hotel-Day-Range modals only showed the renamed day title once a day had a custom name — hiding the actual date. Added an optional badge prop to CustomSelect, rendered as a pill next to the label, and wired the date badge onto all affected dropdowns. FileManager day section headers got the same pill for consistency. Also translated transport.addTransport and transport.modalTitle.* in all 13 non-English language files; the keys existed but still carried the English source string.
This commit is contained in:
@@ -649,8 +649,14 @@ export default function FileManager({ files = [], onUpload, onDelete, onUpdate,
|
||||
</div>
|
||||
{dayGroups.map(({ day, dayPlaces }) => (
|
||||
<div key={day.id}>
|
||||
<div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', padding: '8px 10px 2px' }}>
|
||||
{day.title || `${t('dayplan.dayN', { n: day.day_number })}${day.date ? ` · ${day.date}` : ''}`}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, fontWeight: 600, color: 'var(--text-muted)', padding: '8px 10px 2px' }}>
|
||||
<span>{day.title || t('dayplan.dayN', { n: day.day_number })}</span>
|
||||
{day.date && (
|
||||
<span style={{
|
||||
fontSize: 10, fontWeight: 600, color: 'var(--text-faint)',
|
||||
background: 'var(--bg-tertiary)', padding: '1px 6px', borderRadius: 999,
|
||||
}}>{day.date}</span>
|
||||
)}
|
||||
</div>
|
||||
{dayPlaces.map(placeBtn)}
|
||||
</div>
|
||||
|
||||
@@ -462,7 +462,8 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
onChange={v => setHotelDayRange(prev => ({ start: v, end: Math.max(v, prev.end) }))}
|
||||
options={days.map((d, i) => ({
|
||||
value: d.id,
|
||||
label: `${d.title || t('planner.dayN', { n: i + 1 })}${d.date ? ` — ${new Date(d.date + 'T00:00:00Z').toLocaleDateString(locale, { day: 'numeric', month: 'short', timeZone: 'UTC' })}` : ''}`,
|
||||
label: d.title || t('planner.dayN', { n: i + 1 }),
|
||||
badge: d.date ? new Date(d.date + 'T00:00:00Z').toLocaleDateString(locale, { day: 'numeric', month: 'short', timeZone: 'UTC' }) : undefined,
|
||||
}))}
|
||||
size="sm"
|
||||
/>
|
||||
@@ -474,7 +475,8 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
onChange={v => setHotelDayRange(prev => ({ start: Math.min(prev.start, v), end: v }))}
|
||||
options={days.map((d, i) => ({
|
||||
value: d.id,
|
||||
label: `${d.title || t('planner.dayN', { n: i + 1 })}${d.date ? ` — ${new Date(d.date + 'T00:00:00Z').toLocaleDateString(locale, { day: 'numeric', month: 'short', timeZone: 'UTC' })}` : ''}`,
|
||||
label: d.title || t('planner.dayN', { n: i + 1 }),
|
||||
badge: d.date ? new Date(d.date + 'T00:00:00Z').toLocaleDateString(locale, { day: 'numeric', month: 'short', timeZone: 'UTC' }) : undefined,
|
||||
}))}
|
||||
size="sm"
|
||||
/>
|
||||
|
||||
@@ -439,7 +439,11 @@ export function ReservationModal({ isOpen, onClose, onSave, reservation, days, p
|
||||
value={form.hotel_start_day}
|
||||
onChange={value => set('hotel_start_day', value)}
|
||||
placeholder={t('reservations.meta.selectDay')}
|
||||
options={days.map(d => ({ value: d.id, label: d.title || `${t('dayplan.dayN', { n: d.day_number })}${d.date ? ` · ${formatDate(d.date, locale)}` : ''}` }))}
|
||||
options={days.map(d => ({
|
||||
value: d.id,
|
||||
label: d.title || t('dayplan.dayN', { n: d.day_number }),
|
||||
badge: d.date ? (formatDate(d.date, locale) ?? undefined) : undefined,
|
||||
}))}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
@@ -449,7 +453,11 @@ export function ReservationModal({ isOpen, onClose, onSave, reservation, days, p
|
||||
value={form.hotel_end_day}
|
||||
onChange={value => set('hotel_end_day', value)}
|
||||
placeholder={t('reservations.meta.selectDay')}
|
||||
options={days.map(d => ({ value: d.id, label: d.title || `${t('dayplan.dayN', { n: d.day_number })}${d.date ? ` · ${formatDate(d.date, locale)}` : ''}` }))}
|
||||
options={days.map(d => ({
|
||||
value: d.id,
|
||||
label: d.title || t('dayplan.dayN', { n: d.day_number }),
|
||||
badge: d.date ? (formatDate(d.date, locale) ?? undefined) : undefined,
|
||||
}))}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -222,7 +222,8 @@ export function TransportModal({ isOpen, onClose, onSave, reservation, days, sel
|
||||
{ value: '', label: '—' },
|
||||
...days.map(d => ({
|
||||
value: d.id,
|
||||
label: d.title || `${t('dayplan.dayN', { n: d.day_number })}${d.date ? ` · ${formatDate(d.date, locale) ?? ''}` : ''}`,
|
||||
label: d.title || t('dayplan.dayN', { n: d.day_number }),
|
||||
badge: d.date ? (formatDate(d.date, locale) ?? undefined) : undefined,
|
||||
})),
|
||||
]
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ interface SelectOption {
|
||||
isHeader?: boolean
|
||||
searchLabel?: string
|
||||
groupLabel?: string
|
||||
badge?: string
|
||||
}
|
||||
|
||||
interface CustomSelectProps {
|
||||
@@ -104,6 +105,13 @@ export default function CustomSelect({
|
||||
<span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: selected ? 'var(--text-primary)' : 'var(--text-faint)' }}>
|
||||
{selected ? selected.label : placeholder}
|
||||
</span>
|
||||
{selected?.badge && (
|
||||
<span style={{
|
||||
flexShrink: 0, fontSize: 10, fontWeight: 600, color: 'var(--text-muted)',
|
||||
background: 'var(--bg-tertiary)', padding: '2px 7px', borderRadius: 999,
|
||||
letterSpacing: '0.01em',
|
||||
}}>{selected.badge}</span>
|
||||
)}
|
||||
<ChevronDown size={sm ? 12 : 14} style={{ flexShrink: 0, color: 'var(--text-faint)', transition: 'transform 200ms cubic-bezier(0.23,1,0.32,1)', transform: open ? 'rotate(180deg)' : 'none' }} />
|
||||
</button>
|
||||
|
||||
@@ -186,6 +194,13 @@ export default function CustomSelect({
|
||||
>
|
||||
{option.icon && <span style={{ display: 'flex', flexShrink: 0 }}>{option.icon}</span>}
|
||||
<span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{option.label}</span>
|
||||
{option.badge && (
|
||||
<span style={{
|
||||
flexShrink: 0, fontSize: 10, fontWeight: 600, color: 'var(--text-muted)',
|
||||
background: 'var(--bg-tertiary)', padding: '2px 7px', borderRadius: 999,
|
||||
letterSpacing: '0.01em',
|
||||
}}>{option.badge}</span>
|
||||
)}
|
||||
{isSelected && <Check size={13} style={{ flexShrink: 0, color: 'var(--text-muted)' }} />}
|
||||
</button>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user