Skip to content

Commit

Permalink
climbing: Tick updates (#310)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvaclavik authored Apr 16, 2024
1 parent 2cbc222 commit 589fb65
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 41 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@sentry/node": "^6.5.1",
"accept-language-parser": "^1.5.0",
"autosuggest-highlight": "^3.1.1",
"date-fns": "^3.6.0",
"isomorphic-unfetch": "^3.1.0",
"isomorphic-xml2js": "^0.1.3",
"jest": "^27.0.4",
Expand Down
62 changes: 49 additions & 13 deletions src/components/FeaturePanel/Climbing/RouteList/MyTicks.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,74 @@
import React from 'react';
import styled from 'styled-components';
import DeleteIcon from '@material-ui/icons/Delete';
import { Button } from '@material-ui/core';
import { findTicks, onTickDelete } from '../../../../services/ticks';
import { Button, FormControl, MenuItem, Select } from '@material-ui/core';
import { format } from 'date-fns';
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 deleteAscent = (index) => {
const deleteTick = (index) => {
onTickDelete({ osmId, index });
};

const onTickStyleChange = (event, index) => {
// @TODO tickId vs osmId
onTickUpdate({
osmId,
index,
updatedObject: { style: event.target.value },
});
};

return (
<Container>
<PanelLabel>Ticks:</PanelLabel>
{ticks.map((ascent, index) => (
<Item>
{ascent.date}
<Button
size="small"
onClick={() => deleteAscent(index)}
startIcon={<DeleteIcon />}
/>
</Item>
))}
{ticks.map((tick, index) => {
const date = format(tick.date, 'd.M.yy');
return (
<Item>
<Date>{date}</Date>

<FormControl size="small">
<Select
labelId="demo-simple-select-label"
value={tick.style}
label="Type"
onChange={(e) => onTickStyleChange(e, index)}
>
{tickStyles.map((tickStyle) => (
<MenuItem value={tickStyle.key}>{tickStyle.name}</MenuItem>
))}
</Select>
</FormControl>

<Button
size="small"
onClick={() => deleteTick(index)}
startIcon={<DeleteIcon />}
/>
</Item>
);
})}
</Container>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React, { useEffect, useState } from 'react';
import DragIndicatorIcon from '@material-ui/icons/DragIndicator';
import { useClimbingContext } from '../contexts/ClimbingContext';
import { RenderListRow } from './RouteListRow';
import { isTicked } from '../../../../services/ticks';

type Item = {
id: number;
Expand All @@ -26,20 +25,16 @@ const MaxWidthContainer = styled.div`

const RowWithDragHandler = styled.div<{
isDraggedOver: boolean;
isTicked: boolean;
isSelected: boolean;
}>`
cursor: pointer;
display: flex;
justify-content: center;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0.1);
/* background-color: ${({ isSelected }) =>
isSelected ? '#ccc' : 'transparent'}; */
background: ${({ isSelected, theme, isTickeded }) =>
isSelected
? theme.palette.action.selected
: isTickeded
? theme.palette.climbing.tick
: 'transparent'};
background: ${({ isSelected, theme }) =>
isSelected ? theme.palette.action.selected : 'transparent'};
position: relative;
font-size: 16px;
border-top: dotted 1px ${({ theme }) => theme.palette.divider};
Expand Down Expand Up @@ -215,9 +210,7 @@ export const RouteListDndContent = ({ isEditable }) => {
</MaxWidthContainer>
</TableHeader>
{items.map((item, index) => {
const osmId = item.route.feature?.osmMeta.id ?? null;
const isSelected = isRouteSelected(index);

return (
<React.Fragment key={item.id}>
{draggedItem?.id > index && (
Expand All @@ -230,7 +223,6 @@ export const RouteListDndContent = ({ isEditable }) => {
onDragOver={(e) => handleDragOver(e, index)}
onDragEnd={handleDragEnd}
isSelected={isSelected}
isTickeded={isTicked(osmId)}
onClick={() => {
onRowClick(index);
}}
Expand Down
15 changes: 12 additions & 3 deletions src/components/FeaturePanel/Climbing/RouteList/RouteListRow.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { IconButton, TextField } from '@material-ui/core';
import { IconButton, TextField, Tooltip } from '@material-ui/core';
import { debounce } from 'lodash';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import CheckIcon from '@material-ui/icons/Check';
import { ClimbingRoute } from '../types';
import { useClimbingContext } from '../contexts/ClimbingContext';
import { emptyRoute } from '../utils/emptyRoute';
import { RouteNumber } from '../RouteNumber';

import { toggleElementInArray } from '../utils/array';
import { ExpandedRow } from './ExpandedRow';
import { RouteDifficultyBadge } from '../RouteDifficultyBadge';
import { getShortId } from '../../../../services/helpers';
import { isTicked } from '../../../../services/ticks';

const DEBOUNCE_TIME = 1000;
const Container = styled.div`
Expand All @@ -27,6 +28,9 @@ const Cell = styled.div<{ width: number; align: 'center' | 'left' | 'right' }>`
`;
const NameCell = styled(Cell)`
flex: 1;
display: flex;
gap: 8px;
justify-content: space-between;
`;
const DifficultyCell = styled(Cell)`
margin-right: 8px;
Expand Down Expand Up @@ -104,7 +108,7 @@ export const RenderListRow = ({
setTempRoute({ ...tempRoute, [propName]: e.target.value });
debouncedValueChange(e, propName);
};

const ticked = isTicked(osmId);
const isExpanded = routesExpanded.indexOf(index) > -1;

const isReadOnly =
Expand Down Expand Up @@ -149,6 +153,11 @@ export const RenderListRow = ({
fullWidth
/>
)}
{ticked && (
<Tooltip title="You ticked this route">
<CheckIcon color="primary" style={{ marginRight: 20 }} />
</Tooltip>
)}
</NameCell>
<DifficultyCell width={50}>
<RouteDifficultyBadge
Expand Down
16 changes: 16 additions & 0 deletions src/components/FeaturePanel/Climbing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,19 @@ export type ZoomState = {

export type GradeSystem = typeof gradeSystem[number]['key'];
export type GradeTable = Record<GradeSystem, Array<string>>;

export type TickStyle =
| 'OS'
| 'FL'
| 'RP'
| 'PP'
| 'RK'
| 'AF'
| 'TR'
| 'FS'
| null;
export type Tick = {
osmId: string;
style: TickStyle;
date: string;
};
77 changes: 70 additions & 7 deletions src/services/ticks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
import { JSONValue } from './types';
import { Tick, TickStyle } from '../components/FeaturePanel/Climbing/types';
import { updateElementOnIndex } from '../components/FeaturePanel/Climbing/utils/array';

const KEY = 'ticks';

export const getLocalStorageItem = (key: string) => {
export const tickStyles: Array<{
key: TickStyle;
name: string;
description?: string;
}> = [
{
key: null,
name: 'Not selected',
},
{
key: 'OS',
name: 'On sight',
},
{
key: 'FL',
name: 'Flash',
},
{
key: 'RP',
name: 'Red point',
},
{
key: 'PP',
name: 'Pink point',
},
{
key: 'RK',
name: 'Red cross',
},
{
key: 'AF',
name: 'All free',
},
{
key: 'TR',
name: 'Top rope',
},
{
key: 'FS',
name: 'Free solo',
},
];

export const getLocalStorageItem = (key: string): Array<Tick> => {
if (typeof window === 'undefined') return [];
const raw = window?.localStorage.getItem(key);
if (raw) {
Expand All @@ -17,7 +61,7 @@ export const getLocalStorageItem = (key: string) => {
return [];
};

export const setLocalStorageItem = (key: string, value: JSONValue) => {
export const setLocalStorageItem = (key: string, value: Array<Tick>) => {
if (typeof window === 'undefined') return;
window?.localStorage.setItem(key, JSON.stringify(value));
};
Expand All @@ -27,13 +71,32 @@ export const onTickAdd = ({ osmId }) => {
const ticks = getLocalStorageItem(KEY);
setLocalStorageItem(KEY, [
...ticks,
{ id: osmId, date: new Date().toISOString() },
{ osmId, date: new Date().toISOString(), style: null },
]);
};

export const findTicks = (osmId: string) => {
export const findTicks = (osmId: string): Array<Tick> => {
const ticks = getLocalStorageItem(KEY);
return ticks?.filter((tick) => osmId === tick.id) ?? null;

return ticks?.filter((tick) => osmId === tick.osmId) ?? null;
};

export const onTickUpdate = ({
osmId,
index,
updatedObject,
}: {
osmId: string;
index: number;
updatedObject: Partial<Tick>;
}) => {
const routeTicks = findTicks(osmId);
const updatedArray = updateElementOnIndex<Tick>(
routeTicks,
index,
(item) => ({ ...item, ...updatedObject }),
);
setLocalStorageItem(KEY, updatedArray);
};

export const onTickDelete = ({
Expand All @@ -47,7 +110,7 @@ export const onTickDelete = ({

const newArray = ticks.reduce(
(acc, tick) => {
if (osmId === tick.id) {
if (osmId === tick.osmId) {
const newIndex = acc.index + 1;
if (acc.index === index) {
return {
Expand Down
7 changes: 0 additions & 7 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,3 @@ export interface Feature {

export type MessagesType = typeof Vocabulary;
export type TranslationId = keyof MessagesType;

export type JSONValue =
| string
| number
| boolean
| { [x: string]: JSONValue }
| Array<JSONValue>;
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3128,6 +3128,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"

date-fns@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf"
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==

debug@4, debug@^4.0.1, debug@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
Expand Down

0 comments on commit 589fb65

Please sign in to comment.