mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 23:16:46 +00:00
188953158a
A stay, a name, an importance or a protection set in a stop's dialog no longer plans a city walk's route again: the walk stays ready to save, its time overview follows at once, and one undo takes the change back without routing either. A stop moved or added plans the route again as before. A walk saves no breaks, so a cafe never counts as a stay and as a break at once, and a break left from another type neither counts nor holds its save up. The planner and the tour detail show a walk's walking time, its stays and their total apart and in the same words: 45 minutes of walking, a museum of 90 minutes and a cafe of 30 minutes make 2 h 45 min. A stay not entered yet makes the stays and the total at least what is known, stays nobody entered read not known yet, and stays entered as 0 read 0 min. A total entered by hand keeps its own label, and the computed total shows beside it. The head of the tour detail, the day row on the desktop and the phone, the tour summary and the library of other trips show that same total, with a ≥ where a stay is missing. Their time on the move is called walking, and the summary says a walk is planned with its stays rather than breaks. The tour list and the library carry the minutes a walk's stops are entered with and how many have no stay yet, counted from the walk's points, so the way back of a loop is no stop and its start's stay counts once. A loop run the other way keeps its start as the stop there, with its key, name and stay. The planner's waypoint list keeps the rows of a leg in a file of their own, and the tour detail its name heading in a part of its own, so both stay within their size limits.
71 lines
3.2 KiB
TypeScript
71 lines
3.2 KiB
TypeScript
import { walkStationsOf } from '@trek/shared';
|
|
import type { TourPlannerWaypoint } from './tourPlannerWaypoints';
|
|
|
|
/**
|
|
* CW-02: a city walk's time, walking and staying kept apart. A stay nobody
|
|
* entered is unknown, never nothing: the total then counts only what is
|
|
* known and says it is at least that much. A point passed through is a stay
|
|
* of 0, entered on purpose.
|
|
*/
|
|
export interface WalkTimes {
|
|
walkingMinutes: number | null;
|
|
/** The stays entered, summed. */
|
|
stayMinutes: number;
|
|
/** Stations whose stay nobody entered. */
|
|
unknownStays: number;
|
|
/** The walk's stations, so that some stays unknown and all of them unknown read apart. */
|
|
stations: number;
|
|
/** Walking and the known stays; the known stays alone while the walking time is not known, null while nothing is. */
|
|
totalMinutes: number | null;
|
|
/** The total leaves out a stay or the walking time that is not known. */
|
|
partial: boolean;
|
|
}
|
|
|
|
/** The times of a walk from its parts: the walking time, the stays entered, how many are unknown and of how many. */
|
|
export function walkTimesOf(parts: Omit<WalkTimes, 'totalMinutes' | 'partial'>): WalkTimes {
|
|
const { walkingMinutes, stayMinutes, unknownStays } = parts;
|
|
// Without a walking time the stays entered are still part of the whole: at least that much, never nothing.
|
|
const totalMinutes = walkingMinutes !== null ? walkingMinutes + stayMinutes : stayMinutes > 0 ? stayMinutes : null;
|
|
return {
|
|
...parts,
|
|
totalMinutes,
|
|
partial: totalMinutes !== null && (unknownStays > 0 || walkingMinutes === null),
|
|
};
|
|
}
|
|
|
|
export function walkTimes(points: readonly TourPlannerWaypoint[], walkingMinutes: number | null): WalkTimes {
|
|
// A shaping point is no station, and the way back of a loop is its start again: its stay counts once.
|
|
const stations = walkStationsOf(points);
|
|
return walkTimesOf({
|
|
walkingMinutes,
|
|
stayMinutes: stations.reduce((sum, station) => sum + (station.stayMinutes ?? 0), 0),
|
|
unknownStays: stations.filter((station) => station.stayMinutes == null).length,
|
|
stations: stations.length,
|
|
});
|
|
}
|
|
|
|
/** What the station dialog edits; the rest of the point stays as it is. */
|
|
export type StationFields = Pick<TourPlannerWaypoint, 'name' | 'stayMinutes' | 'importance' | 'protected'>;
|
|
|
|
/** The point with the fields as edited, each one left out where it is empty. */
|
|
export function withStationFields(point: TourPlannerWaypoint, fields: StationFields): TourPlannerWaypoint {
|
|
const { name: _name, stayMinutes: _stay, importance: _importance, protected: _protected, ...rest } = point;
|
|
const name = fields.name?.trim();
|
|
return {
|
|
...rest,
|
|
...(name ? { name } : {}),
|
|
...(fields.stayMinutes != null ? { stayMinutes: fields.stayMinutes } : {}),
|
|
...(fields.importance ? { importance: fields.importance } : {}),
|
|
...(fields.protected ? { protected: true } : {}),
|
|
};
|
|
}
|
|
|
|
/** A stay as typed: empty is unknown, a whole number from 0 to a day is minutes, anything else is not taken. */
|
|
export function parseStay(text: string): number | null | undefined {
|
|
const trimmed = text.trim();
|
|
if (trimmed === '') return null;
|
|
if (!/^\d{1,4}$/.test(trimmed)) return undefined;
|
|
const minutes = Number(trimmed);
|
|
return minutes <= 24 * 60 ? minutes : undefined;
|
|
}
|