Skip to content

Commit

Permalink
Merge pull request #822 from HSLdevcom/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
ahjyrkia authored Dec 2, 2024
2 parents 6a7b49a + 845dc8d commit c7939e6
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 17 deletions.
144 changes: 136 additions & 8 deletions src/components/sidepanel/SpeedAreaJourneyList.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React, {useCallback, useMemo} from "react";
import React, {useState, useCallback} from "react";
import {observer} from "mobx-react-lite";
import SidepanelList from "./SidepanelList";
import getJourneyId from "../../helpers/getJourneyId";
import styled from "styled-components";
import flow from "lodash/flow";
import get from "lodash/get";
import {inject} from "../../helpers/inject";
import EmptyView from "../EmptyView";
import {text} from "../../helpers/text";
import Tooltip from "../Tooltip";
import ClipBoard from "../../icons/ClipBoard";

const ListHeader = styled.div`
display: flex;
Expand All @@ -18,12 +21,29 @@ const ListHeader = styled.div`

const ListWrapper = styled.div``;

const TableRowsHeader = styled.div`
display: flex;
align-items: stretch;
border-bottom: 1px solid var(--lightest-grey);
background-color: #ececf3;
flex-wrap: nowrap;
cursor: pointer;
`;

const TableRow = styled.div`
display: flex;
align-items: stretch;
border-bottom: 1px solid var(--lightest-grey);
flex-wrap: nowrap;
background-color: #f6fcff;
cursor: pointer;
:hover {
background-color: var(--lightest-blue);
}
${({selected}) =>
selected &&
`
background-color: var(--lightest-blue);
`}
`;

const TableBody = styled.div`
Expand All @@ -45,20 +65,48 @@ const TableCell = styled.div`
}
`;

const TableHeader = styled(TableRow)`
const TableHeader = styled(TableRowsHeader)`
font-weight: bold;
border-bottom-width: 1px;
border-color: var(--alt-grey);
background-color: #fdfdff;
${TableCell} {
border-color: var(--alt-grey);
}
`;

const CopyButton = styled.div`
width: fit-content;
height: 22px;
border-radius: 3px;
background-color: #007ac9;
cursor: pointer;
margin: 0.2rem;
:hover {
transform: scale(1.025);
background-color: var(--dark-blue);
}
`;

const HeaderContainer = styled.div`
display: flex;
`;

const HeaderText = styled.div`
margin: 0.2rem;
`;

const decorate = flow(observer, inject("Journey", "Time", "UI"));

const SpeedAreaJourneyList = decorate(
({areaSpeeds, loading, state: {language, speedFilter}}) => {
({
Journey,
areaSpeeds,
loading,
Time,
state: {language, speedFilter, date, selectedJourney},
}) => {
const vehiclepositions = areaSpeeds.flatMap((journey) => {
return journey.vehiclePositions.map((vehiclePosition) => {
const speed = Math.round(vehiclePosition.velocity * 3.6 * 100) / 100;
Expand All @@ -69,10 +117,33 @@ const SpeedAreaJourneyList = decorate(
operatorId: journey.operatorId,
vehicleId: journey.vehicleId,
direction: journey.direction,
journeyType: journey.journeyType,
uniqueVehicleId: journey.uniqueVehicleId,
speed: speed,
};
});
});
const selectedJourneyId = getJourneyId(selectedJourney);
const selectJourney = useCallback(
(journey) => {
if (journey && journey.journeyType === "journey") {
const journeyId = `${date}_${journey.departureTime}_${journey.routeId}_${journey.direction}_${journey.uniqueVehicleId}`;
if (journeyId && selectedJourneyId !== journeyId) {
journey.departureDate = date;
Journey.setSelectedJourney(journey);
} else {
Journey.setSelectedJourney(null);
}
} else if (journey.journeyType !== "journey") {
const time = get(journey, "vehiclePositions[0].recordedTime");
console.log(time);
if (time) {
Time.setTime(time);
}
}
},
[selectedJourneyId]
);
const headerText = {
fi: `${text("filterpanel.speed_search_text_1")} ${speedFilter} Km/h ${text(
"filterpanel.speed_search_text_2"
Expand All @@ -81,14 +152,67 @@ const SpeedAreaJourneyList = decorate(
en: `${text("filterpanel.speed_search_text_1")} ${speedFilter} Km/h`,
};
vehiclepositions.sort((a, b) => b.speed - a.speed);
const copyToClipboard = () => {
const headers = [
"pvm",
"Km/h",
text("map.stops.depart"),
`${text("domain.route")}`,
text("vehicle.identifier_short"),
text("sidepanel.tabs.timestamp"),
];

const dataRows = vehiclepositions.map((vehicleposition) => {
const {
departureTime,
routeId,
speed,
recordedTime,
direction,
vehicleId,
} = vehicleposition;
const formattedSpeed = `${speed}`.replace(".", ",");
const routeDirection = `${routeId}/${direction}`;
return [
`${date}`,
formattedSpeed,
departureTime,
routeDirection,
vehicleId,
recordedTime,
];
});

const clipboardContent = [headers, ...dataRows]
.map((row) => row.join("\t"))
.join("\n");

navigator.clipboard
.writeText(clipboardContent)
.then(() => {
console.log("Data copied to clipboard!");
})
.catch((err) => {
console.error("Failed to copy data to clipboard:", err);
});
};
return (
<SidepanelList
testIdPrefix="journeys-by-week"
loading={loading}
disableScrollOffset={true}
header={
<ListHeader>
{headerText[language] ? `${headerText[language]}` : `${headerText["en"]}`}
<HeaderContainer>
<HeaderText>
{headerText[language] ? `${headerText[language]}` : `${headerText["en"]}`}
</HeaderText>
<Tooltip helpText={text("sidepanel.tabs.copy_to_clipboard")}>
<CopyButton onClick={copyToClipboard}>
<ClipBoard width="1.5rem" height="1.5rem" fill="white" />
</CopyButton>
</Tooltip>
</HeaderContainer>
</ListHeader>
}
floatingListHeader={
Expand Down Expand Up @@ -124,16 +248,20 @@ const SpeedAreaJourneyList = decorate(
recordedTime,
direction,
vehicleId,
uniqueVehicleId,
} = vehicleposition;

const journeyId = `${date}_${departureTime}_${routeId}_${direction}_${uniqueVehicleId}`;
const isSelected = journeyId === selectedJourneyId;
const formattedSpeed = `${speed}`.replace(".", ",");
return (
<TableRow
data-testid={``}
ref={scrollRef}
key={`area_event_row_${departureTime}_${routeId}_${speed}_${recordedTime}_${index}`}
selected={false}>
selected={isSelected}
onClick={() => selectJourney(vehicleposition)}>
<Tooltip helpText={text("sidepanel.tabs.speed")}>
<TableCell>{speed}</TableCell>
<TableCell>{formattedSpeed}</TableCell>
</Tooltip>
<Tooltip helpText={text("sidepanel.tabs.departure")}>
<TableCell>{departureTime}</TableCell>
Expand Down
9 changes: 5 additions & 4 deletions src/components/sidepanel/UsageInstructions.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ export function UsageInstructions({language}) {
</ColoredBackgroundSlot>
<PlainSlotMono>17:59:30</PlainSlotMono>
</TagButton>
The vehicle departured more than 10 seconds before the scheduled departure
so it is early.
The vehicle departured more than 15 seconds before the scheduled departure
so it is early. For origin stops the threshold for early departure is 20
seconds.
</li>
</ExampleSlotWrapper>
<li>
Expand Down Expand Up @@ -283,8 +284,8 @@ export function UsageInstructions({language}) {
</ColoredBackgroundSlot>
<PlainSlotMono>17:59:30</PlainSlotMono>
</TagButton>
Lähtö on tapahtunut 10 sekuntia ennen suunniteltua lähtöä eli lähtö on
etuajassa.
Lähtö on tapahtunut 15 sekuntia ennen suunniteltua lähtöä eli lähtö on
etuajassa. Reitin aloituspysäkille tämä raja on 20 sekuntia.
</li>
</ExampleSlotWrapper>

Expand Down
6 changes: 3 additions & 3 deletions src/helpers/getDelayType.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ function getDelayType(delay, stopType = delayStopType.NORMAL) {

switch (stopType) {
case "timing":
earlyThreshold = -5;
earlyThreshold = -15;
break;
case "origin":
earlyThreshold = -20;
break;
case "destination":
earlyThreshold = -10;
earlyThreshold = -15;
break;
default:
case "normal":
earlyThreshold = -10;
earlyThreshold = -15;
}

let earlyType = [delayStopType.NORMAL, delayStopType.DESTINATION].includes(stopType)
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/getDelayType.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import getDelayType from "./getDelayType";

describe("getDelayType", () => {
test("delayType is 'early' if the value is -10 or under (seconds)", () => {
const delayValue = -10;
test("delayType is 'early' if the value is -15 or under (seconds)", () => {
const delayValue = -15;
const delayType = getDelayType(delayValue);

expect(delayType).toBe("normal-early");
Expand Down
53 changes: 53 additions & 0 deletions src/icons/ClipBoard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import {Svg, Circle, G, Path} from "react-primitives-svg";
import PropTypes from "prop-types";
import {Colors} from "./HSL_COLORS";
import {svgTranslate, svgSize} from "../helpers/svg";

export default function Icon({fill, height, width, ...rest}) {
return (
<Svg
{...svgSize(height, width)}
viewBox="0 0 24 24"
fill={"#007ac9"}
xmlns="http://www.w3.org/2000/svg">
<Path
d="M15.5 4H18C19.1046 4 20 4.89543 20 6V19C20 20.1046 19.1046 21 18 21H6C4.89543 21 4 20.1046 4 19V6C4 4.89543 4.89543 4 6 4H8.5"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<Path
d="M8.62127 3.51493C8.84385 2.62459 9.64382 2 10.5616 2H13.4384C14.3562 2 15.1561 2.62459 15.3787 3.51493L16 6H8L8.62127 3.51493Z"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<Path d="M9 12L15 12" stroke="white" strokeWidth="2" strokeLinecap="round" />
<Path d="M9 16H15" stroke="white" strokeWidth="2" strokeLinecap="round" />
</Svg>
);
}

Icon.propTypes = {
fill: PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
inner: PropTypes.string,
outer: PropTypes.string,
}),
]),
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

Icon.defaultProps = {
fill: {
inner: Colors.primary.hslGrey,
outer: Colors.primary.hslBlue,
},
};

Icon.displayName = "Icons.ClipBoard";
2 changes: 2 additions & 0 deletions src/icons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ import Timetable from "./Timetable";
import TrashCan from "./TrashCan";
import UserNearestStop from "./UserNearestStop";
import TravelZones from "./TravelZones";
import ClipBoard from "./ClipBoard";

export default {
AddCard,
Expand Down Expand Up @@ -184,6 +185,7 @@ export default {
CheckmarkAnimated,
CircleCheckmark,
City,
ClipBoard,
Cog,
CreditCard,
Cross,
Expand Down
1 change: 1 addition & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
--teal: #00b2a9;
--light-blue: #00b9e4;
--lighter-blue: #bee4f8;
--lightest-blue: #e5f4fc;
--pink: #f092cd;
--light-pink: #f4deea;
--light-green: #64be1e;
Expand Down
1 change: 1 addition & 0 deletions src/languages/ui/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"sidepanel.tabs.vehicle_number": "Vehicle number",
"sidepanel.tabs.timestamp_description": "HFP VP-event timestamp",
"sidepanel.tabs.selected_route_dir": "Selected route and direction",
"sidepanel.tabs.copy_to_clipboard": "Copy to clipboard",

"map.stops.arrive": "Arrival",
"map.stops.depart": "Departure",
Expand Down
1 change: 1 addition & 0 deletions src/languages/ui/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"sidepanel.tabs.vehicle_number": "Ajoneuvon kylkinumero",
"sidepanel.tabs.timestamp_description": "HFP VP-eventin aikaleima",
"sidepanel.tabs.selected_route_dir": "Valittu reitti ja suunta",
"sidepanel.tabs.copy_to_clipboard": "Kopioi leikepöydälle",

"map.stops.arrive": "Saapumisaika",
"map.stops.depart": "Lähtöaika",
Expand Down
1 change: 1 addition & 0 deletions src/languages/ui/se.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"sidepanel.tabs.vehicle_number": "Fordonsnummer",
"sidepanel.tabs.timestamp_description": "HFP VP-event tidsstämpel för HFP VP-händelse",
"sidepanel.tabs.selected_route_dir": "Vald rutt och riktning",
"sidepanel.tabs.copy_to_clipboard": "Kopiera till urklipp",

"map.stops.arrive": "Ankomst",
"map.stops.depart": "Avgång",
Expand Down

0 comments on commit c7939e6

Please sign in to comment.