mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-20 22:16:26 +00:00
fix(tours): give an actual track its own mark and a winter tile its label's icon
Footprints stood for a snowshoe hike, an actual track and a walk's moving time at once, with the snowshoe pill and the track pill side by side in a tour's head. An actual track now goes by the done mark on the list row, in the head and on a recording's tile, and a winter tile's corner takes the icon its head pill shows.
This commit is contained in:
@@ -321,6 +321,7 @@ describe('TourDetailDialog', () => {
|
||||
render(<TourDetailDialog {...defaultProps} tour={{ ...tour, has_waypoints: false, origin: 'gpx', activity_of: 7 }} />)
|
||||
|
||||
expect(screen.getByTestId('tour-detail-track-of')).toHaveTextContent('Actual track of Lake loop')
|
||||
expect(screen.getByTestId('tour-detail-track-of').querySelector('svg.lucide-check-check')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('ACT-02: an actual track stands beside the plan the head shows, and only the map detail offers to compare it there', async () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ArrowDown,
|
||||
ArrowUp,
|
||||
Check,
|
||||
CheckCheck,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
Clock,
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
FileDown,
|
||||
FileImage,
|
||||
FileText,
|
||||
Footprints,
|
||||
Loader2,
|
||||
Minus,
|
||||
Navigation,
|
||||
@@ -301,7 +301,7 @@ function TourHeadPills({
|
||||
{documentsName && (
|
||||
<Tooltip label={t('tours.activity.isTrackHint')}>
|
||||
<span data-testid="tour-detail-track-of" className={`${HEAD_PILL} max-w-[220px]`} style={fs(10.5)}>
|
||||
<Footprints size={11} strokeWidth={2} className="flex-none text-success" />
|
||||
<CheckCheck size={11} strokeWidth={2} className="flex-none text-success" />
|
||||
<span className="min-w-0 truncate">{t('tours.activity.ofTour', { name: documentsName })}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
|
||||
@@ -11,6 +11,9 @@ describe('TourActivityBadge (ACT-01)', () => {
|
||||
<TourActivityBadge tour={{ activity_tracks: [{ id: 1, track_place_id: 9, assignment_id: null }] }} />
|
||||
);
|
||||
expect(screen.getByTestId('tour-activity-badge')).toHaveAttribute('aria-label', 'tours.activity.badgeHint');
|
||||
// The done mark, never footprints, which name a snowshoe hike and a walk's moving time.
|
||||
expect(screen.getByTestId('tour-activity-badge').querySelector('svg.lucide-check-check')).not.toBeNull();
|
||||
expect(screen.getByTestId('tour-activity-badge').querySelector('svg.lucide-footprints')).toBeNull();
|
||||
|
||||
rerender(<TourActivityBadge tour={{ activity_tracks: [], activity_of: 4 }} />);
|
||||
expect(screen.getByTestId('tour-activity-badge')).toHaveAttribute('aria-label', 'tours.activity.isTrackHint');
|
||||
|
||||
@@ -102,6 +102,10 @@ describe('TourActivitySection (ACT-01)', () => {
|
||||
expect(screen.getByTestId('tour-activity-compare-time')).toHaveTextContent('tours.activity.noTime');
|
||||
expect(screen.getByTestId('tour-activity-day')).toHaveTextContent('tours.activity.noDay');
|
||||
expect(screen.queryByText('tours.activity.recordedOn')).toBeNull();
|
||||
// The recording's tile goes by the done mark every actual track has, never footprints.
|
||||
const head = screen.getByTestId('tour-activity').querySelector('header') as HTMLElement;
|
||||
expect(head.querySelector('svg.lucide-check-check')).not.toBeNull();
|
||||
expect(head.querySelector('svg.lucide-footprints')).toBeNull();
|
||||
});
|
||||
|
||||
it('FE-ACT-SECTION-003: someone who may change the tour links, changes and unlinks; the dialog opens when asked', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { TourActivity, TourListItem } from '@trek/shared';
|
||||
import { CalendarDays, Clock, CloudOff, FileDown, Footprints, Plus, RefreshCw, Unlink } from 'lucide-react';
|
||||
import { CalendarDays, CheckCheck, Clock, CloudOff, FileDown, Plus, RefreshCw, Unlink } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from '../../../i18n';
|
||||
import { useSettingsStore } from '../../../store/settingsStore';
|
||||
@@ -29,11 +29,16 @@ interface PlanSide {
|
||||
comparison: ActivityComparisonState | null;
|
||||
}
|
||||
|
||||
/** The tile of a recording: footprints, with a small dot at its foot that says it was recorded. */
|
||||
/**
|
||||
* The tile of a recording: the done mark every actual track goes by (on the
|
||||
* list row, in the tour's head and here), with a small dot at its foot that
|
||||
* says it was recorded. Never footprints, which name a snowshoe hike and a
|
||||
* walk's moving time.
|
||||
*/
|
||||
function RecordedTile() {
|
||||
return (
|
||||
<span className="relative grid h-9 w-9 flex-none place-items-center rounded-full bg-surface-secondary text-content-secondary">
|
||||
<Footprints size={15} strokeWidth={2} aria-hidden="true" />
|
||||
<CheckCheck size={15} strokeWidth={2} aria-hidden="true" />
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="absolute -bottom-0.5 -end-0.5 h-3 w-3 rounded-full bg-success ring-2 ring-surface-card"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useId, useLayoutEffect, useRef, useState, type ReactNode } from 'react'
|
||||
import type { TourListItem } from '@trek/shared'
|
||||
import { AlertTriangle, CalendarDays, ChevronDown, Footprints, Info, Plus } from 'lucide-react'
|
||||
import { AlertTriangle, CalendarDays, CheckCheck, ChevronDown, Info, Plus } from 'lucide-react'
|
||||
import { createElement } from 'react'
|
||||
import type { Day, DistanceUnit } from '../../types'
|
||||
import type { RouteGeometryAnalysis } from '../../utils/routeGeometry'
|
||||
@@ -134,7 +134,7 @@ export function TourActivityBadge({ tour }: { tour: Pick<TourListItem, 'activity
|
||||
return (
|
||||
<Tooltip label={label}>
|
||||
<span data-testid="tour-activity-badge" aria-label={label} className="inline-flex flex-none">
|
||||
<WhiteBadge className="text-success" icon={<Footprints size={10} strokeWidth={2.2} className="flex-none" />}>
|
||||
<WhiteBadge className="text-success" icon={<CheckCheck size={10} strokeWidth={2.2} className="flex-none" />}>
|
||||
{null}
|
||||
</WhiteBadge>
|
||||
</span>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { TourDayRowAvatar } from '../TourDayRowFacts';
|
||||
import { TourGradeTile } from '../tourParts';
|
||||
import { WinterActivityPill, WinterCornerMark } from './winterMarks';
|
||||
|
||||
// FE-TOUR-WINTER-MARK-001 to FE-TOUR-WINTER-MARK-004
|
||||
// FE-TOUR-WINTER-MARK-001 to FE-TOUR-WINTER-MARK-005
|
||||
|
||||
const hike = { tour_type: 'hike' as const, max_hiking_difficulty: 2, wanderer_ref: null, has_waypoints: true };
|
||||
|
||||
@@ -40,4 +40,16 @@ describe('winter marks (HIK-01)', () => {
|
||||
expect(screen.getByTestId('plan-tour-icon')).toHaveTextContent('T2');
|
||||
expect(screen.getByTestId('tour-winter-mark')).toHaveStyle({ width: '22px' });
|
||||
});
|
||||
|
||||
it('FE-TOUR-WINTER-MARK-005: the corner mark goes by the same icon as the head pill of its label', () => {
|
||||
for (const activity of ['winter_hike', 'snowshoe'] as const) {
|
||||
const icon = activity === 'snowshoe' ? 'lucide-footprints' : 'lucide-snowflake';
|
||||
const mark = render(<WinterCornerMark activity={activity} />);
|
||||
expect(mark.container.querySelector(`svg.${icon}`)).not.toBeNull();
|
||||
mark.unmount();
|
||||
const pill = render(<WinterActivityPill activity={activity} className="head-pill" />);
|
||||
expect(pill.container.querySelector(`svg.${icon}`)).not.toBeNull();
|
||||
pill.unmount();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,9 +12,10 @@ export const WINTER_ACTIVITY_ICON: Record<WinterActivity, LucideIcon> = {
|
||||
};
|
||||
|
||||
/**
|
||||
* HIK-01: a hike's winter label on its round tile, a frosted snowflake badge
|
||||
* at the tile's top corner, the way the tile carries where a tour came from at
|
||||
* its foot. Its tooltip names the label; nothing is drawn for a hike without one.
|
||||
* HIK-01: a hike's winter label on its round tile, a frosted badge at the
|
||||
* tile's top corner with the label's own icon, the one its head pill shows,
|
||||
* the way the tile carries where a tour came from at its foot. Its tooltip
|
||||
* names the label; nothing is drawn for a hike without one.
|
||||
*/
|
||||
export function WinterCornerMark({
|
||||
activity,
|
||||
@@ -28,7 +29,7 @@ export function WinterCornerMark({
|
||||
if (!activity) return null;
|
||||
return (
|
||||
<TourCornerMark
|
||||
icon={Snowflake}
|
||||
icon={WINTER_ACTIVITY_ICON[activity]}
|
||||
label={t(`tours.winter.activity.${activity}`)}
|
||||
size={size}
|
||||
testId="tour-winter-mark"
|
||||
|
||||
Reference in New Issue
Block a user