mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
5d334d7ec8
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.
64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
import { useMemo } from 'react';
|
|
|
|
import { useTranslation } from '../../i18n';
|
|
import { assistantScopeOf } from '../../store/assistantChatKey';
|
|
import { useJourneyStore } from '../../store/journeyStore';
|
|
import { useCanDo } from '../../store/permissionsStore';
|
|
import { useTripStore } from '../../store/tripStore';
|
|
import { localIsoDate } from '../../utils/localDate';
|
|
import { HOME_SUGGESTIONS, suggestionsFor, tripPhase } from './assistantModel';
|
|
import { useAssistantFocus } from './useAssistantFocus';
|
|
|
|
export interface ReadySuggestion {
|
|
id: string;
|
|
/** What the button says, and the question it sends. */
|
|
prompt: string;
|
|
}
|
|
|
|
/**
|
|
* The questions the empty chat offers, worded and ready to send, and whether
|
|
* the user may change this trip at all. For a trip the planner is not showing
|
|
* (one picked from the dashboard) neither its dates nor its rights are at
|
|
* hand, so it gets the general questions and none that would change it. A
|
|
* journey's chat in TREK Studio gets none, since they all ask about a trip,
|
|
* and its rights are the journey's role, as the Studio itself reads it. The
|
|
* home chat outside any one trip gets its own questions across the user's
|
|
* trips; what it may change the server decides, so nothing is held back here.
|
|
*/
|
|
export function useAssistantSuggestions(tripId: number): { suggestions: ReadySuggestion[]; canEdit: boolean } {
|
|
const { t } = useTranslation();
|
|
const can = useCanDo();
|
|
const trip = useTripStore((s) => (s.trip?.id === tripId ? s.trip : null));
|
|
const hasPlaces = useTripStore((s) => s.places.length > 0);
|
|
const { label, kind } = useAssistantFocus(tripId);
|
|
const scope = assistantScopeOf(tripId);
|
|
const tripChat = scope.kind === 'trip';
|
|
// The Studio's own reading: an owner until the journey says otherwise, and only a viewer changes nothing.
|
|
const journeyRole = useJourneyStore((s) =>
|
|
scope.kind === 'journey' && s.current?.id === scope.journeyId ? s.current.my_role : undefined
|
|
);
|
|
const home = scope.kind === 'home';
|
|
const canEdit = tripChat ? !!trip && can('place_edit', trip) : home || (journeyRole ?? 'owner') !== 'viewer';
|
|
|
|
const suggestions = useMemo((): ReadySuggestion[] => {
|
|
if (home) return HOME_SUGGESTIONS.map((s) => ({ id: s.id, prompt: t(s.labelKey) }));
|
|
if (!tripChat) return [];
|
|
const phase = trip
|
|
? tripPhase({
|
|
startDate: trip.start_date ?? null,
|
|
endDate: trip.end_date ?? null,
|
|
hasPlaces,
|
|
today: localIsoDate(),
|
|
})
|
|
: 'upcoming';
|
|
return suggestionsFor({
|
|
phase,
|
|
canEdit,
|
|
place: kind === 'place' ? label : null,
|
|
day: kind === 'day' ? label : null,
|
|
}).map((s) => ({ id: s.id, prompt: t(s.labelKey, s.params) }));
|
|
}, [home, tripChat, trip, hasPlaces, canEdit, kind, label, t]);
|
|
|
|
return { suggestions, canEdit };
|
|
}
|