mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
4b3340546f
On /journey/:id the assistant window and the phone's assistant screen now open the journey's conversation, the one TREK Studio holds too, instead of the home chat; the Studio route keeps its own column. A turn sent from a chat the Studio does not host names the journal page, a hosted one the Studio, so the server offers the right tools. A journal card from the home chat opens that conversation in place on the desktop and the journal page on the phone, and the empty chat asks about the journal rather than the book.
71 lines
3.1 KiB
TypeScript
71 lines
3.1 KiB
TypeScript
import { useCallback, useMemo } from 'react';
|
|
import { useMatch } from 'react-router';
|
|
|
|
import { useTranslation } from '../../i18n';
|
|
import { assistantChatKey, assistantScopeOf, HOME_CHAT_KEY } from '../../store/assistantChatKey';
|
|
import { useAssistantStore } from '../../store/assistantStore';
|
|
import { useJourneyStore } from '../../store/journeyStore';
|
|
import type { AssistantChatTrip } from './assistantViewContext';
|
|
|
|
/**
|
|
* The home chat, the assistant outside any one trip, as the desktop window
|
|
* and the phone screen both show it: the key its conversations are kept
|
|
* under, the name its head carries, and the way into one trip's own chat.
|
|
* That way leaves the question the home chat handed over waiting in the
|
|
* trip's composer, ready to send, and then lets the view switch (the window
|
|
* shows that trip's chat in place, the phone opens the trip with its chat).
|
|
*/
|
|
export function useAssistantHome(switchTo: (trip: AssistantChatTrip) => void) {
|
|
const { t } = useTranslation();
|
|
const setDraft = useAssistantStore((s) => s.setDraft);
|
|
|
|
const openTripChat = useCallback(
|
|
(trip: AssistantChatTrip, question: string | null) => {
|
|
// A question typed there already stays; the handed-over one only fills an empty composer.
|
|
const typed = useAssistantStore.getState().byTrip[trip.id]?.draft ?? '';
|
|
if (question && !typed.trim()) setDraft(trip.id, question);
|
|
switchTo(trip);
|
|
},
|
|
[setDraft, switchTo]
|
|
);
|
|
|
|
const title = t('assistant.home.title');
|
|
const chat = useMemo((): AssistantChatTrip => ({ id: HOME_CHAT_KEY, title }), [title]);
|
|
return { chat, openTripChat };
|
|
}
|
|
|
|
/**
|
|
* The way into the home chat on the pages outside a trip (the phone's
|
|
* dashboard head and the dock's More list): offered only while the assistant
|
|
* can run for this user, like every other way in.
|
|
*/
|
|
export function useAssistantHomeLauncher() {
|
|
const available = useAssistantStore((s) => s.status?.available === true);
|
|
const open = useAssistantStore((s) => s.open);
|
|
return { available, open };
|
|
}
|
|
|
|
/**
|
|
* The journal on screen as a chat: on a journey's own page the journey's
|
|
* conversation (the one TREK Studio holds too), under its key and with the
|
|
* journey's title once the page has loaded it; null elsewhere and in the
|
|
* Studio, whose column holds that chat itself.
|
|
*/
|
|
export function useRouteJournalChat(): AssistantChatTrip | null {
|
|
const match = useMatch('/journey/:id/*');
|
|
const inStudio = useMatch('/journey/:id/studio/*') !== null;
|
|
const id = Number(match?.params.id);
|
|
const journeyId = !inStudio && Number.isInteger(id) && id > 0 ? id : null;
|
|
const title = useJourneyStore((s) => (s.current && s.current.id === journeyId ? s.current.title : ''));
|
|
return useMemo(
|
|
() => (journeyId === null ? null : { id: assistantChatKey({ kind: 'journey', journeyId }), title }),
|
|
[journeyId, title]
|
|
);
|
|
}
|
|
|
|
/** The page a chat switched to from the home chat lives on: a journey's for its key, a trip's otherwise. */
|
|
export function chatPagePath(chat: AssistantChatTrip): string {
|
|
const scope = assistantScopeOf(chat.id);
|
|
return scope.kind === 'journey' ? `/journey/${scope.journeyId}` : `/trips/${chat.id}`;
|
|
}
|