mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 07:26:30 +00:00
fix(reservations): honour the 24h time setting (#1725)
The 12h/24h rules lived in three copies and two of them ignored the setting. They are one function now. splitReservationDateTime also truncated the meridiem instead of converting it, so 3:00 PM became 3:00 — three in the morning. Values already stored that way normalise when a form renders the field, without changing the payload or the stored format.
This commit is contained in:
@@ -1830,3 +1830,43 @@ describe('DayDetailPanel remaining branches, part two', () => {
|
||||
expect(await screen.findByText(/Add accommodation/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
// FE-DDP1725-001 to -003 — the day panel reads times through the shared formatter, so a
|
||||
// value that was stored with a meridiem still follows the configured format (#1725).
|
||||
describe('DayDetailPanel time format', () => {
|
||||
const meridiemRes = (overrides: Record<string, unknown> = {}) =>
|
||||
buildReservation({
|
||||
id: 9, type: 'event', title: 'Matinee', day_id: 1,
|
||||
reservation_time: '3:00 PM', reservation_end_time: '11:00 PM', status: 'confirmed',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
it('FE-DDP1725-001: a reservation stored with a meridiem shows in 24h', async () => {
|
||||
render(<DayDetailPanel {...defaultProps} reservations={[meridiemRes()]} />);
|
||||
expect(await screen.findByText('15:00 – 23:00')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-DDP1725-002: the same reservation keeps its afternoon in 12h', async () => {
|
||||
seedStore(useSettingsStore, { settings: { time_format: '12h', temperature_unit: 'celsius', blur_booking_codes: false } });
|
||||
render(<DayDetailPanel {...defaultProps} reservations={[meridiemRes()]} />);
|
||||
expect(await screen.findByText('3:00 PM – 11:00 PM')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-DDP1725-003: an accommodation check-in stored with a meridiem shows in 24h', async () => {
|
||||
server.use(
|
||||
http.get('/api/trips/1/accommodations', () =>
|
||||
HttpResponse.json({
|
||||
accommodations: [{
|
||||
id: 1, place_id: 5, place_name: 'Grand Hotel', place_address: 'Paris',
|
||||
start_day_id: 1, end_day_id: 3, check_in: '3:00 PM', check_in_end: null,
|
||||
check_out: '11:00 AM', confirmation: null,
|
||||
}],
|
||||
}),
|
||||
),
|
||||
);
|
||||
render(<DayDetailPanel {...defaultProps} />);
|
||||
|
||||
expect(await screen.findByText('15:00')).toBeInTheDocument();
|
||||
expect(screen.getByText('11:00')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { getLocaleForLanguage, useTranslation } from '../../i18n'
|
||||
import type { Day, Place, Category, Reservation, AssignmentsMap } from '../../types'
|
||||
import { isDayInAccommodationRange } from '../../utils/dayOrder'
|
||||
import { splitReservationDateTime } from '../../utils/formatters'
|
||||
import { formatClockTime, splitReservationDateTime } from '../../utils/formatters'
|
||||
import { useDayDetail } from './useDayDetail'
|
||||
|
||||
const WEATHER_ICON_MAP = {
|
||||
@@ -36,16 +36,6 @@ function WIcon({ main, size = 14 }: WIconProps) {
|
||||
|
||||
function cTemp(c, f) { return Math.round(f ? c * 9 / 5 + 32 : c) }
|
||||
|
||||
function formatTime12(val, is12h) {
|
||||
if (!val) return val
|
||||
const [h, m] = val.split(':').map(Number)
|
||||
if (isNaN(h) || isNaN(m)) return val
|
||||
if (!is12h) return val
|
||||
const period = h >= 12 ? 'PM' : 'AM'
|
||||
const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h
|
||||
return `${h12}:${String(m).padStart(2, '0')} ${period}`
|
||||
}
|
||||
|
||||
interface DayDetailPanelProps {
|
||||
day: Day
|
||||
days: Day[]
|
||||
@@ -78,7 +68,7 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
const fmtTime = (v) => {
|
||||
if (!v) return v
|
||||
if (v.includes('T')) return new Date(v).toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', hour12: is12h })
|
||||
return formatTime12(v, is12h)
|
||||
return formatClockTime(v, is12h)
|
||||
}
|
||||
const unit = isFahrenheit ? '°F' : '°C'
|
||||
const collapsed = collapsedProp
|
||||
@@ -313,8 +303,8 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
if (!startTime && !endTime) return null
|
||||
return (
|
||||
<span style={{ fontSize: 'calc(10px * var(--fs-scale-caption, 1))', color: 'var(--text-muted)', whiteSpace: 'nowrap', flexShrink: 0 }}>
|
||||
{startTime ? formatTime12(startTime, is12h) : ''}
|
||||
{endTime ? ` – ${formatTime12(endTime, is12h)}` : ''}
|
||||
{startTime ? formatClockTime(startTime, is12h) : ''}
|
||||
{endTime ? ` – ${formatClockTime(endTime, is12h)}` : ''}
|
||||
</span>
|
||||
)
|
||||
})()}
|
||||
|
||||
Reference in New Issue
Block a user