Files
TREK/client/src/components/Assistant/assistantViewContext.ts
T
Maurice 5d334d7ec8 feat(assistant): the assistant opens outside a trip, as a home chat about all trips
A third scope, home, next to trip and journey: threads that name neither a
trip nor a journey (the CHECK now only forbids both), reached under
/api/assistant by their owner only. A home turn reads the user's trips
through list_trips into a short card (under way, next, later, behind,
undated), offers every read (a trip's on the id the model names, checked by
the tool with the user's rights) and only the writes that take no trip or
journey (atlas, vacation planner, collections, tour library, settings), all
held as change cards. open_trip_chat answers with a card that goes on in
that trip's own chat with the question waiting in its composer.

On the desktop the window opens on the home chat outside a trip; its head
lists the trips to switch into and a switched trip chat has the way back.
On the phone the home chat opens full screen from the dashboard head and the
dock's More list, and the card opens the trip with its chat. Both run on
useAssistantHome.
2026-10-23 22:00:06 +02:00

62 lines
2.5 KiB
TypeScript

import type { AssistantScope } from '@trek/shared';
import { createContext, useContext } from 'react';
import { type AssistantChatKey, assistantScopeOf } from '../../store/assistantChatKey';
import type { EntityTarget } from './cards/cardTypes';
/** What the parts deep inside a chat need from whoever shows it. */
export interface AssistantView {
/**
* The chat's key, which every part hands to the assistant store: the trip's
* id in the planner, a journey's key in TREK Studio (`assistantChatKey`).
* No trip is held under a journey's key, so the parts that read the trip
* (its map, its days, found places) stay empty there.
*/
tripId: AssistantChatKey;
/** 'window' on the desktop, 'fullscreen' on the phone. */
variant: 'window' | 'fullscreen';
/** How much room the chat has: a narrow window and the phone are 'compact'. */
density?: 'compact' | 'roomy';
/**
* Opens what a card or an applied change points at: a spot on the plan's
* map, a tab of the trip, another page. The buttons are left out where
* nothing can open them.
*/
onOpen?: (target: EntityTarget) => void;
/** Selects a day in the planner, from its weather; left out where no planner can show it. */
onFocusDay?: (dayId: number) => void;
/** Brings the map into view where the chat covers it (the phone), before the map moves. */
onRevealMap?: () => void;
/**
* The stored book's version the book open in TREK Studio stands on, null
* before it has one; left out outside the Studio. A book card draws the page
* after as the server's trial made it only while the book is still at the
* version the trial ran on.
*/
bookVersion?: number | null;
/**
* Goes on in a trip's own chat with a question waiting there, from the home
* chat's card that offers it; left out where no chat can be switched to.
*/
onOpenTripChat?: (trip: AssistantChatTrip, question: string | null) => void;
}
/** A trip as the chat switches to it: its id, which is its chat's key, and its title for the head. */
export interface AssistantChatTrip {
id: number;
title: string;
}
export const AssistantViewContext = createContext<AssistantView | null>(null);
export function useAssistantView(): AssistantView {
const view = useContext(AssistantViewContext);
if (!view) throw new Error('useAssistantView outside AssistantSurface');
return view;
}
/** What the chat on screen is about, for the parts that only make sense on a trip. */
export function useAssistantScope(): AssistantScope {
return assistantScopeOf(useAssistantView().tripId);
}