From 72e8b1f8d9a74abf571db27cb8dfc9a97298e47a Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 13 Nov 2026 09:28:17 +0100 Subject: [PATCH] feat(collections): "want to revisit" status for saved places (#2567) A fourth status after visited, for a place already seen that the user wants to go back to. It joins the one-tap cycle, the filters, the pickers, the assistant cards and the MCP status tool, and counts as visited wherever visits are counted (isVisitedCollectionStatus), so "visited everywhere" keeps it. The status pickers go two by two where four would not fit. --- .../collection/CollectionCardBlocks.test.tsx | 10 +++++++++- .../cards/collection/CollectionChangeSlots.tsx | 17 +++++++++-------- .../cards/collection/collectionCardParts.tsx | 14 ++++++++++---- .../Collections/StatusBadge.test.tsx | 14 +++++++++++--- .../src/components/Collections/StatusBadge.tsx | 4 ++-- .../components/Collections/collectionStatus.ts | 5 +++-- .../Collections/useSaveToCollection.test.ts | 6 ++++-- .../Collections/useSaveToCollection.ts | 11 ++++++++--- .../screens/collections/MCollAddSheet.tsx | 3 ++- .../screens/collections/MCollPlaceSheet.tsx | 4 ++-- .../collections/collectionsMobileModel.ts | 5 +++-- .../pages/collections/collectionsModel.test.ts | 18 ++++++++++++------ .../src/pages/collections/collectionsModel.ts | 2 +- client/src/styles/collections.css | 4 +++- client/tests/helpers/collectionCards.ts | 2 +- .../collections/MCollPlaceSheet.test.tsx | 3 +++ .../collections/collectionsMobileModel.test.ts | 4 +++- .../cards/collection/collection-values.ts | 2 +- server/src/nest/collections/collections.mcp.ts | 3 ++- .../tests/unit/mcp/tools-collections.test.ts | 9 +++++++++ .../collection/collection-answers.test.ts | 11 +++++++++-- .../collection/collection-changes.test.ts | 2 +- .../assistant/cards/collection-places.card.ts | 11 +++++++++-- .../src/collection/collection.schema.spec.ts | 18 ++++++++++++++++++ shared/src/collection/collection.schema.ts | 12 +++++++++++- shared/src/i18n/ar/collection.ts | 1 + shared/src/i18n/az/collection.ts | 1 + shared/src/i18n/br/collection.ts | 1 + shared/src/i18n/ca/collection.ts | 1 + shared/src/i18n/cs/collection.ts | 1 + shared/src/i18n/de/collection.ts | 1 + shared/src/i18n/en/collection.ts | 1 + shared/src/i18n/es/collection.ts | 1 + shared/src/i18n/et/collection.ts | 1 + shared/src/i18n/fr/collection.ts | 1 + shared/src/i18n/gr/collection.ts | 1 + shared/src/i18n/he/collection.ts | 1 + shared/src/i18n/hu/collection.ts | 1 + shared/src/i18n/id/collection.ts | 1 + shared/src/i18n/it/collection.ts | 1 + shared/src/i18n/ja/collection.ts | 1 + shared/src/i18n/ko/collection.ts | 1 + shared/src/i18n/nl/collection.ts | 1 + shared/src/i18n/pl/collection.ts | 1 + shared/src/i18n/ru/collection.ts | 1 + shared/src/i18n/sk/collection.ts | 1 + shared/src/i18n/sv/collection.ts | 1 + shared/src/i18n/th/collection.ts | 1 + shared/src/i18n/tr/collection.ts | 1 + shared/src/i18n/uk/collection.ts | 1 + shared/src/i18n/vi/collection.ts | 1 + shared/src/i18n/zh-TW/collection.ts | 1 + shared/src/i18n/zh/collection.ts | 1 + wiki/Addons-Overview.md | 2 +- wiki/Collections.md | 3 ++- wiki/MCP-Addon-Tools.md | 2 +- 56 files changed, 178 insertions(+), 51 deletions(-) diff --git a/client/src/components/Assistant/cards/collection/CollectionCardBlocks.test.tsx b/client/src/components/Assistant/cards/collection/CollectionCardBlocks.test.tsx index ca0e3fb5c..d965bd944 100644 --- a/client/src/components/Assistant/cards/collection/CollectionCardBlocks.test.tsx +++ b/client/src/components/Assistant/cards/collection/CollectionCardBlocks.test.tsx @@ -1,5 +1,5 @@ /** - * FE-AI-COLL-010 to FE-AI-COLL-017 + * FE-AI-COLL-010 to FE-AI-COLL-017, FE-AI-COLL-040 * * The answer cards of the collections as the chat draws them: a list's head * with its size, people and places per status, its saved places as rows @@ -57,6 +57,14 @@ describe('collection answer cards', () => { expect(view.onOpen).toHaveBeenCalledWith({ kind: 'page', path: '/collections/12' }); }); + it('FE-AI-COLL-040: the places to revisit have a pill of their own in the head, in the visited tone (#2567)', () => { + draw([placesCard({ list: { ...placesCard().list, counts: { idea: 3, want: 5, visited: 4, revisit: 7 } } })]); + const card = screen.getByRole('region', { name: 'Saved places in Paris food' }); + const pill = within(card).getByText('Want to revisit').parentElement as HTMLElement; + expect(within(pill).getByText('7')).toBeInTheDocument(); + expect(within(card).getByText('Visited').parentElement?.className).toBe(pill.className); + }); + it('FE-AI-COLL-011: a saved place shows its status, two labels and the rest counted, its rating and the trip having it', () => { draw([placesCard({ places: [savedPlace({ inTripPlaceId: 6 })] })]); expect(screen.getByText('Septime')).toBeInTheDocument(); diff --git a/client/src/components/Assistant/cards/collection/CollectionChangeSlots.tsx b/client/src/components/Assistant/cards/collection/CollectionChangeSlots.tsx index df309dab7..877a46e7a 100644 --- a/client/src/components/Assistant/cards/collection/CollectionChangeSlots.tsx +++ b/client/src/components/Assistant/cards/collection/CollectionChangeSlots.tsx @@ -1,10 +1,11 @@ -import type { - CollectionCardDelta, - CollectionCardLabel, - CollectionCardList, - CollectionCardPlace, - CollectionListsCard, - CollectionPlacesCard, +import { + type CollectionCardDelta, + type CollectionCardLabel, + type CollectionCardList, + type CollectionCardPlace, + type CollectionListsCard, + type CollectionPlacesCard, + isVisitedCollectionStatus, } from '@trek/shared'; import { Bookmark, Info, Tag } from 'lucide-react'; import type { ReactNode } from 'react'; @@ -110,7 +111,7 @@ function ListChip({ list }: { list: CollectionCardList }) { function statusChange(status: NonNullable, t: T): ReactNode { const to = STATUS_META[status.to]; const before = status.from ? t(STATUS_META[status.from].labelKey) : null; - const tone = status.to === 'visited' ? 'success' : 'neutral'; + const tone = isVisitedCollectionStatus(status.to) ? 'success' : 'neutral'; return ; } diff --git a/client/src/components/Assistant/cards/collection/collectionCardParts.tsx b/client/src/components/Assistant/cards/collection/collectionCardParts.tsx index 98c424fd3..1187599fe 100644 --- a/client/src/components/Assistant/cards/collection/collectionCardParts.tsx +++ b/client/src/components/Assistant/cards/collection/collectionCardParts.tsx @@ -1,10 +1,16 @@ -import type { CollectionCardLabel, CollectionCardList, CollectionCardPlace, CollectionStatus } from '@trek/shared'; +import { + type CollectionCardLabel, + type CollectionCardList, + type CollectionCardPlace, + type CollectionStatus, + isVisitedCollectionStatus, +} from '@trek/shared'; import { Star } from 'lucide-react'; import type { CSSProperties } from 'react'; import { useTranslation } from '../../../../i18n'; import { safeHexColor } from '../../../../utils/safeColor'; -import { STATUS_META } from '../../../Collections/collectionStatus'; +import { STATUS_META, STATUS_ORDER } from '../../../Collections/collectionStatus'; import { SoftPill, tintOf, WhiteBadge } from '../../../Planner/planParts'; import PlaceAvatar from '../../../shared/PlaceAvatar'; import { Tooltip } from '../../../shared/Tooltip'; @@ -93,7 +99,7 @@ export function StatusPill({ status, count }: { status: CollectionStatus; count?