From 4b6f19ccefa6aa6edfb82a455bc0b577b325521d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Wed, 24 Jul 2024 23:04:21 +0200 Subject: [PATCH] climbing: Add My ticks page (#420) --- src/components/App/App.tsx | 4 +- .../Climbing/Editor/PathWithBorder.tsx | 4 +- .../FeaturePanel/Climbing/MyTicksPage.tsx | 117 +++++++++++++++++ .../Climbing/RouteDifficultyBadge.tsx | 19 +-- .../Climbing/RouteDistribution.tsx | 3 +- .../Climbing/RouteList/ExpandedRow.tsx | 4 +- .../Climbing/RouteList/MyRouteTicks.tsx | 23 ++++ .../Climbing/RouteList/MyTicks.tsx | 74 ----------- .../Climbing/RouteList/RouteListRow.tsx | 9 +- .../FeaturePanel/Climbing/TickRow.tsx | 112 ++++++++++++++++ .../Climbing/utils/grades/routeGrade.ts | 13 +- .../FeaturePanel/ImagePane/Path.tsx | 7 +- .../HomepagePanel/UserSettingsDialog.tsx | 39 ++++++ src/components/Map/TopMenu/LoginMenu.tsx | 120 +++++++++++++----- src/config.ts | 2 + src/locales/vocabulary.js | 8 ++ src/services/overpassSearch.ts | 2 +- src/services/ticks.ts | 10 +- 18 files changed, 424 insertions(+), 146 deletions(-) create mode 100644 src/components/FeaturePanel/Climbing/MyTicksPage.tsx create mode 100644 src/components/FeaturePanel/Climbing/RouteList/MyRouteTicks.tsx delete mode 100644 src/components/FeaturePanel/Climbing/RouteList/MyTicks.tsx create mode 100644 src/components/FeaturePanel/Climbing/TickRow.tsx create mode 100644 src/components/HomepagePanel/UserSettingsDialog.tsx diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 56c4320f..bc26193c 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -23,6 +23,7 @@ import { SnackbarProvider } from '../utils/SnackbarContext'; import { useMobileMode } from '../helpers'; import { FeaturePanelInDrawer } from '../FeaturePanel/FeaturePanelInDrawer'; import { UserSettingsProvider } from '../utils/UserSettingsContext'; +import { MyTicksPage } from '../FeaturePanel/Climbing/MyTicksPage'; const usePersistMapView = () => { const { view } = useMapStateContext(); @@ -79,6 +80,7 @@ const IndexWithProviders = () => { const isClimbingDialogShown = router.query.all?.[2] === 'climbing'; const photo = router.query.all?.[3]; + return ( <> @@ -90,8 +92,8 @@ const IndexWithProviders = () => { )} - + {router.query.all?.[0] === 'my-ticks' && } {router.pathname === '/install' && } diff --git a/src/components/FeaturePanel/Climbing/Editor/PathWithBorder.tsx b/src/components/FeaturePanel/Climbing/Editor/PathWithBorder.tsx index 938a3673..43c98a94 100644 --- a/src/components/FeaturePanel/Climbing/Editor/PathWithBorder.tsx +++ b/src/components/FeaturePanel/Climbing/Editor/PathWithBorder.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { useTheme } from '@mui/material'; import { useConfig } from '../config'; import { useClimbingContext } from '../contexts/ClimbingContext'; -import { getDifficultyColor } from '../utils/grades/routeGrade'; +import { getDifficulty, getDifficultyColor } from '../utils/grades/routeGrade'; const RouteLine = styled.path` pointer-events: all; @@ -26,7 +26,7 @@ export const PathWithBorder = ({ const theme = useTheme(); const strokeColor = isDifficultyHeatmapEnabled - ? getDifficultyColor(route.feature.tags, theme) + ? getDifficultyColor(getDifficulty(route.feature.tags), theme) : config.pathStrokeColor; const getPathColor = () => { diff --git a/src/components/FeaturePanel/Climbing/MyTicksPage.tsx b/src/components/FeaturePanel/Climbing/MyTicksPage.tsx new file mode 100644 index 00000000..f9c531a6 --- /dev/null +++ b/src/components/FeaturePanel/Climbing/MyTicksPage.tsx @@ -0,0 +1,117 @@ +import React, { useEffect, useState } from 'react'; +import Router from 'next/router'; +import { + TableHead, + TableRow, + Table, + TableBody, + TableCell, + TableContainer, + Paper, +} from '@mui/material'; +import { t } from '../../../services/intl'; +import { getAllTicks } from '../../../services/ticks'; +import { TickRow } from './TickRow'; +import { fetchJson } from '../../../services/fetch'; +import { + getOverpassUrl, + overpassGeomToGeojson, +} from '../../../services/overpassSearch'; +import { getApiId, getShortId } from '../../../services/helpers'; +import { getRouteGrade } from './utils/grades/routeGrade'; +import { ClosePanelButton } from '../../utils/ClosePanelButton'; +import { + PanelContent, + PanelScrollbars, + PanelSidePadding, + PanelWrapper, +} from '../../utils/PanelHelpers'; +import { ClientOnly } from '../../helpers'; +import { useUserSettingsContext } from '../../utils/UserSettingsContext'; + +export const MyTicksPage = () => { + const [myTicksData, setMyTicksData] = useState({}); + const allTicks = getAllTicks(); + const { userSettings } = useUserSettingsContext(); + + const getOverpassData = async () => { + const queryTicks = allTicks + .map(({ osmId }) => { + if (!osmId) return ''; + const { id } = getApiId(osmId); + return `node(${id});`; + }) + .join(''); + const query = `[out:json];(${queryTicks});out body qt;`; + const overpass = await fetchJson(getOverpassUrl(query)); + + const features = overpassGeomToGeojson(overpass); + + const data = Object.keys(features).reduce((acc, key) => { + const feature = features[key]; + return { + ...acc, + [getShortId(feature.osmMeta)]: feature.tags, + }; + }, {}); + setMyTicksData(data); + }; + + useEffect(() => { + getOverpassData(); + }, []); + + const handleClose = () => { + Router.push(`/`); + }; + + return ( + + + + + + +

{t('my_ticks.title')}

+
+ + + + + {t('my_ticks.route_name')} + {t('my_ticks.route_grade')} + {t('my_ticks.route_style')} + {t('my_ticks.route_date')} + + + + {allTicks.map((tick, index) => { + const tickData = myTicksData[tick.osmId]; + const name = tickData?.name; + const grade = getRouteGrade( + tickData, + userSettings['climbing.gradeSystem'], + ); + + return ( + + ); + })} + +
+
+
+
+
+
+ ); +}; diff --git a/src/components/FeaturePanel/Climbing/RouteDifficultyBadge.tsx b/src/components/FeaturePanel/Climbing/RouteDifficultyBadge.tsx index c8d631a3..8d2505c6 100644 --- a/src/components/FeaturePanel/Climbing/RouteDifficultyBadge.tsx +++ b/src/components/FeaturePanel/Climbing/RouteDifficultyBadge.tsx @@ -3,12 +3,11 @@ import styled from 'styled-components'; import { Tooltip, useTheme } from '@mui/material'; import { convertGrade, - getDifficulty, getDifficultyColor, getGradeSystemName, } from './utils/grades/routeGrade'; -import { GradeSystem } from './utils/grades/gradeData'; -import { Feature } from '../../../services/types'; +import { useUserSettingsContext } from '../../utils/UserSettingsContext'; +import { RouteDifficulty } from './types'; const Container = styled.div<{ $color: string }>` border-radius: 12px; @@ -22,17 +21,13 @@ const Container = styled.div<{ $color: string }>` `; type Props = { - routeFeature: Feature; - selectedRouteSystem?: GradeSystem; + routeDifficulty?: RouteDifficulty; }; -export const RouteDifficultyBadge = ({ - routeFeature, - selectedRouteSystem, -}: Props) => { +export const RouteDifficultyBadge = ({ routeDifficulty }: Props) => { const theme = useTheme(); - const routeDifficulty = getDifficulty(routeFeature?.tags); - + const { userSettings } = useUserSettingsContext(); + const selectedRouteSystem = userSettings['climbing.gradeSystem']; const convertedGrade = selectedRouteSystem ? convertGrade( routeDifficulty?.gradeSystem, @@ -47,7 +42,7 @@ export const RouteDifficultyBadge = ({ convertedGrade ? selectedRouteSystem : routeDifficulty?.gradeSystem, ); - const colorByDifficulty = getDifficultyColor(routeFeature?.tags, theme); + const colorByDifficulty = getDifficultyColor(routeDifficulty, theme); return ( { {heightsRatios.map((heightRatioItem) => { const color = getDifficultyColor( { - 'climbing:grade:uiaa': heightRatioItem.grade, + gradeSystem: 'uiaa', + grade: heightRatioItem.grade, }, theme, ); diff --git a/src/components/FeaturePanel/Climbing/RouteList/ExpandedRow.tsx b/src/components/FeaturePanel/Climbing/RouteList/ExpandedRow.tsx index 1a59bdcd..59fc22dc 100644 --- a/src/components/FeaturePanel/Climbing/RouteList/ExpandedRow.tsx +++ b/src/components/FeaturePanel/Climbing/RouteList/ExpandedRow.tsx @@ -21,7 +21,7 @@ import { RouteInDifferentPhotos } from './RouteInDifferentPhotos'; import { Label } from './Label'; import { getOsmappLink } from '../../../../services/helpers'; import { onTickAdd } from '../../../../services/ticks'; -import { MyTicks } from './MyTicks'; +import { MyRouteTicks } from './MyRouteTicks'; const Left = styled.div` flex: 1; @@ -203,7 +203,7 @@ export const ExpandedRow = ({ - + { + const ticks = findTicks(osmId); + if (ticks.length === 0) return null; + + return ( + + Ticks: + {ticks.map((tick, index) => ( + + ))} + + ); +}; diff --git a/src/components/FeaturePanel/Climbing/RouteList/MyTicks.tsx b/src/components/FeaturePanel/Climbing/RouteList/MyTicks.tsx deleted file mode 100644 index a9b91bf6..00000000 --- a/src/components/FeaturePanel/Climbing/RouteList/MyTicks.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import DeleteIcon from '@mui/icons-material/Delete'; -import { format } from 'date-fns'; -import { FormControl, Select, MenuItem, Button } from '@mui/material'; -import { - findTicks, - onTickDelete, - onTickUpdate, - tickStyles, -} from '../../../../services/ticks'; -import { PanelLabel } from '../PanelLabel'; - -const Container = styled.div` - margin-bottom: 20px; -`; -const Item = styled.div` - font-size: 12px; - display: flex; - gap: 8px; - align-items: center; -`; -const Date = styled.div``; - -export const MyTicks = ({ osmId }) => { - const ticks = findTicks(osmId); - if (ticks.length === 0) return null; - - const deleteTick = (index) => { - onTickDelete({ osmId, index }); - }; - - const onTickStyleChange = (event, index) => { - // @TODO tickId vs osmId - onTickUpdate({ - osmId, - index, - updatedObject: { style: event.target.value }, - }); - }; - - return ( - - Ticks: - {ticks.map((tick, index) => { - const date = format(tick.date, 'd.M.yy'); - return ( - - {date} - - - - - -