Files
TREK/client/src/components/Assistant/cards/tour/TourRouteInRow.tsx
T
Maurice 6e43490ba0 feat(assistant): plan and save every tour type, bike tours, runs, paddle and ski tours included
The assistant can now plan and save every type the Tours tab plans. A bike
tour or a run is proposed and created through the hike's own plan and save
(propose_tour, create_tour), routed on the server with the costing of its
profile, now kept once in shared and read by the planner as well. A paddle
or ski tour planned with plan_paddle_route or plan_ski_route is saved with
create_paddle_tour or create_ski_tour, and "Plan this" takes those plans,
bike tours and runs too. Every create has its card and its way back.
2026-10-23 21:01:13 +02:00

82 lines
3.7 KiB
TypeScript

import type { TourRouteCard } from '@trek/shared';
import { useMemo } from 'react';
import { useTranslation } from '../../../../i18n';
import { useSettingsStore } from '../../../../store/settingsStore';
import ElevationProfile from '../../../shared/ElevationProfile';
import { variantPaintCss } from '../../../Tours/planner/legVariantPaint';
import { VariantDelta } from '../../../Tours/planner/LegVariantsCard';
import { tourDayRowIcon } from '../../../Tours/tourDayRowIcon';
import type { ChangeItem } from '../../assistantParts';
import { verbLookOf } from '../cardLooks';
import KindTile from '../parts/KindTile';
import WayFigures from './TourFigureLine';
import { TourGrade, TourRouteSketch } from './TourRouteHead';
import { legVariantOf, previousVariantOf, profileBands, profileSamples } from './tourRouteModel';
import { useTourRouteCard } from './useTourRouteCard';
/**
* A held tour change in its row, and the receipt it turns into: the route
* drawn small with its figures and grade, a small profile under it, and for a
* changed route how the new way differs from the one it replaces (the old
* line faint in the sketch). A tour whose way is planned only once it is
* added is drawn straight and says so. The receipt keeps all of it; "On map"
* and "Open in Tours" sit at the receipt's end.
*/
/** The tile in front of the row: what kind of tour, in the tone of what happens to it. */
export function TourRouteLead({ card, item }: { card: TourRouteCard; item: ChangeItem }) {
const tone = verbLookOf(item.preview?.verbKey ?? 'addTour').tone;
const settled = item.state === 'discarded' || item.state === 'expired';
return <KindTile icon={tourDayRowIcon(card.activity)} tone={tone} size="sm" dimmed={settled} />;
}
export default function TourRouteInRow({ card, item }: { card: TourRouteCard; item: ChangeItem }) {
const { t } = useTranslation();
const unit = useSettingsStore((s) => s.settings.distance_unit ?? 'metric');
const { showOnMap } = useTourRouteCard(item.toolCallId, card);
const samples = useMemo(() => profileSamples(card), [card]);
const previous = previousVariantOf(card);
const notPlanned = card.problem?.why === 'not_planned';
const grades = card.activity === 'hike' ? card.grades : null;
return (
<div
className="flex flex-col gap-2 rounded-[12px] border border-edge-faint bg-surface-secondary p-2.5"
data-testid="tour-route-row"
>
<div className="flex items-center gap-2.5">
<span className="w-14 flex-none overflow-hidden rounded-[10px] bg-surface-card p-1 shadow-sm">
<TourRouteSketch card={card} height={36} onShow={showOnMap} />
</span>
<div className="flex min-w-0 flex-1 flex-col gap-1">
<span className="flex min-w-0 items-center gap-2">
<span className="min-w-0 flex-1">
<WayFigures way={legVariantOf(card, 'current')} unit={unit} />
</span>
{((grades && grades.highest !== null) || card.routingProfile) && <TourGrade card={card} />}
</span>
{previous && (
<VariantDelta
variant={legVariantOf(card, 'current')}
current={previous}
unit={unit}
t={t}
hint={t('assistant.card.tour.deltaBefore')}
/>
)}
{notPlanned && <p className="m-0 text-caption text-content-faint">{t('assistant.card.tour.notPlanned')}</p>}
</div>
</div>
{!notPlanned && samples.length >= 2 && (
<ElevationProfile
samples={samples}
color={variantPaintCss('current')}
height={36}
gradientId={`assistant-tour-row-${item.toolCallId.replace(/[^\w-]/g, '-')}`}
bands={profileBands(card, samples)}
/>
)}
</div>
);
}