fix(mobile): a transport card shows the notes of its booking

On the phone the Transports tab never rendered a booking's notes, so what
someone typed into a flight was only to be found by opening its sheet,
while the booking cards next to it showed theirs. Both cards now take the
notes from one part, sized on the caption tier so the text size setting
reaches them.
This commit is contained in:
Maurice
2026-10-18 12:47:43 +02:00
parent a74a2cf9b5
commit 097c1da0af
5 changed files with 42 additions and 10 deletions
+1 -1
View File
@@ -269,7 +269,7 @@
"mobile/screens/trip/sheets/PlSheetChrome.tsx": 7,
"mobile/screens/trip/sheets/PlTimeFields.tsx": 3,
"mobile/screens/trip/tabs/MBagsSheet.tsx": 13,
"mobile/screens/trip/tabs/MBookingsTab.tsx": 3,
"mobile/screens/trip/tabs/MBookingsTab.tsx": 2,
"mobile/screens/trip/tabs/MCollabChat.tsx": 22,
"mobile/screens/trip/tabs/MCollabNotes.tsx": 19,
"mobile/screens/trip/tabs/MCollabPolls.tsx": 18,
@@ -4,7 +4,7 @@ import { RES_ICONS } from '../../../../components/Planner/DayPlanSidebar.constan
import { formatTime, formatPriceText } from '../../../../utils/formatters'
import { useTranslation } from '../../../../i18n'
import type { Reservation } from '../../../../types'
import { CardActions, CardDeleteSheet, CardFiles, CardTitleButton, CardWhenAndCode } from './MReservationCardParts'
import { CardActions, CardDeleteSheet, CardFiles, CardNotes, CardTitleButton, CardWhenAndCode } from './MReservationCardParts'
import { Field, ReservationPluginSlots, SectionHeader, StatusDot, TabScroller, TravelerAvatars, TravelerFilterRow } from './tabChrome'
import { STATUS_COLOR, type MTabScreenProps } from './tabModel'
import { cardWhen, parseTransportMeta } from './transportsModel'
@@ -173,11 +173,7 @@ function BookingCard({ res, planner, canEdit, compact }: {
</div>
)}
{res.notes && (
<div className="mt-2 rounded-[10px] border border-[color:var(--m-rowbr)] bg-m-card px-[10px] py-2">
<p className="whitespace-pre-wrap font-geist text-[0.6875rem] leading-[1.5] text-m-muted">{res.notes}</p>
</div>
)}
<CardNotes notes={res.notes} />
<CardFiles files={files} card={card} t={t} />
</button>
@@ -1,11 +1,18 @@
// FE-COMP-MRESCARD-001 to FE-COMP-MRESCARD-009
// FE-COMP-MRESCARD-001 to FE-COMP-MRESCARD-010
import { fireEvent, render, screen } from '@testing-library/react';
import { Hotel, Plane } from 'lucide-react';
import { describe, expect, it, vi } from 'vitest';
import type { useReservationCard } from '../../../../components/Planner/bookings/useReservationCard';
import type { Reservation } from '../../../../types';
import { CardActions, CardDeleteSheet, CardFiles, CardTitleButton, CardWhenAndCode } from './MReservationCardParts';
import {
CardActions,
CardDeleteSheet,
CardFiles,
CardNotes,
CardTitleButton,
CardWhenAndCode,
} from './MReservationCardParts';
const t = (key: string, params?: Record<string, string | number>) =>
params ? `${key}:${Object.values(params).join(',')}` : key;
@@ -149,4 +156,15 @@ describe('MReservationCardParts', () => {
expect(title.contains(date)).toBe(false);
expect(container.querySelector('button > div')).toHaveClass('flex-col');
});
it('FE-COMP-MRESCARD-010: shows the notes of a booking, and nothing for empty ones (Discord, 15.10.2026)', () => {
const notes = 'Gate closes 40 min early\nBag drop at counter C';
const { container, rerender } = render(<CardNotes notes={notes} />);
expect(container.querySelector('p')?.textContent).toBe(notes);
rerender(<CardNotes notes=" " />);
expect(container).toBeEmptyDOMElement();
rerender(<CardNotes notes={null} />);
expect(container).toBeEmptyDOMElement();
});
});
@@ -128,6 +128,22 @@ export function CardWhenAndCode({
);
}
/**
* The booking's notes, inside the card body button. A transport card on the phone
* never showed them, so notes typed into a flight were nowhere to be read
* (reported on Discord, 15.10.2026); both cards now take them from here.
*/
export function CardNotes({ notes }: { notes: string | null | undefined }) {
if (!notes?.trim()) return null;
return (
<div className="mt-2 rounded-[10px] border border-[color:var(--m-rowbr)] bg-m-card px-[10px] py-2">
<p className="whitespace-pre-wrap font-geist text-caption leading-[1.5] text-m-muted [overflow-wrap:anywhere]">
{notes}
</p>
</div>
);
}
/** Attached files, listed inside the card body button. */
export function CardFiles({ files, card, t }: { files: ReturnType<typeof filesFor>; card: CardState; t: T }) {
if (files.length === 0) return null;
@@ -3,7 +3,7 @@ import { RES_ICONS } from '../../../../components/Planner/DayPlanSidebar.constan
import { formatPriceText } from '../../../../utils/formatters'
import { useTranslation } from '../../../../i18n'
import type { Reservation } from '../../../../types'
import { CardActions, CardDeleteSheet, CardFiles, CardTitleButton, CardWhenAndCode } from './MReservationCardParts'
import { CardActions, CardDeleteSheet, CardFiles, CardNotes, CardTitleButton, CardWhenAndCode } from './MReservationCardParts'
import { Field, ReservationPluginSlots, SectionHeader, StatusDot, TabScroller, TravelerAvatars, TravelerFilterRow } from './tabChrome'
import { STATUS_COLOR, type MTabScreenProps } from './tabModel'
import { cardWhen, parseTransportMeta } from './transportsModel'
@@ -189,6 +189,8 @@ function TransportCard({ res, planner, shell, canEdit, compact }: {
<TravelerAvatars travelers={res.travelers || []} label={t('reservations.travelers.label')} />
<CardNotes notes={res.notes} />
<CardFiles files={files} card={card} t={t} />
</button>
</div>