From 2fbff5129938ca827c4827f67f6e7266844df86b Mon Sep 17 00:00:00 2001 From: Maurice Date: Wed, 21 Oct 2026 22:39:43 +0200 Subject: [PATCH] feat(assistant): change cards in the style of the planner's day list A waiting change is one row as in the day list: a round choice in front, what it touches in bold, a faint line with what happens and when. No switch, nothing to fold open, no day band: the planner's day list already shows the suggestion among the day's stops. Whether the days still fit is one pill in the card's head, with what to look at on hover. Also mends the comment the rebase onto dev split in json-columns.ts. --- .../Assistant/AssistantChangeCard.test.tsx | 33 +-- .../Assistant/AssistantChangeCard.tsx | 82 ++++-- .../Assistant/AssistantChangeFields.tsx | 131 +++------- .../components/Assistant/AssistantDayBand.tsx | 235 ------------------ .../Assistant/AssistantFitCheck.tsx | 74 ++++++ .../Assistant/dayAfterModel.test.ts | 15 +- .../src/components/Assistant/dayAfterModel.ts | 24 -- server/src/db/json-columns.ts | 2 + shared/src/i18n/ar/assistant.ts | 24 -- shared/src/i18n/az/assistant.ts | 12 - shared/src/i18n/br/assistant.ts | 12 - shared/src/i18n/ca/assistant.ts | 12 - shared/src/i18n/cs/assistant.ts | 15 -- shared/src/i18n/de/assistant.ts | 12 - shared/src/i18n/en/assistant.ts | 12 - shared/src/i18n/es/assistant.ts | 12 - shared/src/i18n/et/assistant.ts | 12 - shared/src/i18n/fr/assistant.ts | 12 - shared/src/i18n/gr/assistant.ts | 12 - shared/src/i18n/hu/assistant.ts | 12 - shared/src/i18n/id/assistant.ts | 9 - shared/src/i18n/it/assistant.ts | 12 - shared/src/i18n/ja/assistant.ts | 9 - shared/src/i18n/ko/assistant.ts | 9 - shared/src/i18n/nl/assistant.ts | 12 - shared/src/i18n/pl/assistant.ts | 18 -- shared/src/i18n/ru/assistant.ts | 18 -- shared/src/i18n/sk/assistant.ts | 15 -- shared/src/i18n/sv/assistant.ts | 12 - shared/src/i18n/th/assistant.ts | 9 - shared/src/i18n/tr/assistant.ts | 12 - shared/src/i18n/uk/assistant.ts | 18 -- shared/src/i18n/vi/assistant.ts | 9 - shared/src/i18n/zh-TW/assistant.ts | 9 - shared/src/i18n/zh/assistant.ts | 9 - 35 files changed, 176 insertions(+), 759 deletions(-) delete mode 100644 client/src/components/Assistant/AssistantDayBand.tsx create mode 100644 client/src/components/Assistant/AssistantFitCheck.tsx diff --git a/client/src/components/Assistant/AssistantChangeCard.test.tsx b/client/src/components/Assistant/AssistantChangeCard.test.tsx index 52fa684c1..8c2a0c011 100644 --- a/client/src/components/Assistant/AssistantChangeCard.test.tsx +++ b/client/src/components/Assistant/AssistantChangeCard.test.tsx @@ -128,13 +128,10 @@ describe('AssistantChangeCard: deciding', () => { renderCard([pending('c1', 'Kinkaku-ji')]); expect(screen.getByText('Kinkaku-ji')).toBeInTheDocument(); expect(screen.getByText('Add place')).toBeInTheDocument(); - // The time is a chip of its own, old to new; the address waits behind "Details". + // The faint line says when, old to new; the address is for the planner, not the card. expect(screen.getByText('09:00')).toBeInTheDocument(); expect(screen.getByText('10:30')).toBeInTheDocument(); expect(screen.queryByText('Kyoto')).toBeNull(); - fireEvent.click(screen.getByRole('button', { name: 'Details' })); - expect(screen.getByText('Address')).toBeInTheDocument(); - expect(screen.getByText('Kyoto')).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Include this change' })).toBeNull(); expect(screen.getByRole('status')).toHaveTextContent('1 change is waiting for you'); }); @@ -239,36 +236,24 @@ describe('AssistantChangeCard: on the map', () => { expect(row).toHaveClass('bg-surface-hover'); }); - it('FE-AI-CARD-009: the days a waiting card touches read as named stops, with the schedule folded away', () => { + it('FE-AI-CARD-009: the head says whether the days still fit, without drawing the days again', () => { plannerHere(); renderCard([onTheMap('c1', 'Pantheon')]); - expect(screen.getByText('Rome')).toBeInTheDocument(); - // Folded, each stop is a chip with its name, not a blank block behind a tooltip. - expect(screen.getByText('Louvre')).toBeInTheDocument(); - expect(screen.getAllByText('Pantheon')).toHaveLength(2); - expect(screen.queryByText('New')).toBeNull(); - - fireEvent.click(screen.getByRole('button', { name: 'Show schedule' })); - expect(screen.getByRole('button', { name: 'Hide schedule' })).toHaveAttribute('aria-expanded', 'true'); - expect(screen.getByText('Louvre')).toBeInTheDocument(); - expect(screen.getAllByText('Pantheon')).toHaveLength(2); - expect(screen.getByText('New')).toBeInTheDocument(); - expect(screen.getByText(/min travel/)).toBeInTheDocument(); - - // Hovering the stop in the schedule lights the same pin as its row. - fireEvent.mouseEnter(screen.getByText('New')); - expect(useAssistantStore.getState().mapLink?.hoveredId).toBe('c1'); + expect(screen.getByText(/Fits the time|to check/)).toBeInTheDocument(); + // The day list of the planner shows the suggestion; the card keeps to one line per change. + expect(screen.getAllByText('Pantheon')).toHaveLength(1); + expect(screen.queryByRole('button', { name: 'Show schedule' })).toBeNull(); }); - it('FE-AI-CARD-010: no band while the planner holds another trip, or once nothing waits', () => { + it('FE-AI-CARD-010: no check while the planner holds another trip, or once nothing waits', () => { plannerHere(TRIP + 1); const first = renderCard([onTheMap('c1', 'Pantheon')]); - expect(screen.queryByRole('button', { name: 'Show schedule' })).toBeNull(); + expect(screen.queryByText(/Fits the time|to check/)).toBeNull(); first.unmount(); plannerHere(); renderCard([{ ...onTheMap('c1', 'Pantheon'), state: 'applied' }]); - expect(screen.queryByRole('button', { name: 'Show schedule' })).toBeNull(); + expect(screen.queryByText(/Fits the time|to check/)).toBeNull(); }); it('FE-AI-CARD-011: on the phone the card hops to the map and frames what it would change', () => { diff --git a/client/src/components/Assistant/AssistantChangeCard.tsx b/client/src/components/Assistant/AssistantChangeCard.tsx index e255d34e5..01d193301 100644 --- a/client/src/components/Assistant/AssistantChangeCard.tsx +++ b/client/src/components/Assistant/AssistantChangeCard.tsx @@ -26,12 +26,11 @@ import { useTranslation } from '../../i18n'; import { blockKeyOf } from '../../store/assistantMapModel'; import { chatOf, useAssistantStore } from '../../store/assistantStore'; import { useTripStore } from '../../store/tripStore'; -import ToggleSwitch from '../Settings/ToggleSwitch'; import { useToast } from '../shared/Toast'; import { Tooltip } from '../shared/Tooltip'; import AssistantChangeFields from './AssistantChangeFields'; import AssistantCompareSwitch from './AssistantCompareSwitch'; -import AssistantDayBand from './AssistantDayBand'; +import AssistantFitCheck from './AssistantFitCheck'; import AssistantWeekOverview from './AssistantWeekOverview'; import { type ChangeItem, type ChangeState, undoLeftMs } from './assistantParts'; import { useAssistantView } from './assistantViewContext'; @@ -137,18 +136,18 @@ function ChangeHead({ preview, struck = false }: { preview: AssistantChangePrevi if (!preview) return