Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Elevator Closures list #2288

Merged
merged 42 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e7c4f25
API additions needed for Elevators.
cmaddox5 Oct 29, 2024
d68b8ab
Added new CG.
cmaddox5 Oct 29, 2024
07dd02d
Return maps with all info client will need.
cmaddox5 Oct 29, 2024
af81a49
Added mock support for tests.
cmaddox5 Oct 29, 2024
1a52746
Added CG tests.
cmaddox5 Oct 29, 2024
4f371bc
Fixed reference to key.
cmaddox5 Oct 29, 2024
b3af727
Improved test.
cmaddox5 Oct 29, 2024
c600627
Credo.
cmaddox5 Oct 29, 2024
299bb21
Logger error if one is returned.
cmaddox5 Oct 29, 2024
ba76705
Address PR feedback.
cmaddox5 Nov 4, 2024
b439295
Simplify business logic so it all lives in CG.
cmaddox5 Nov 4, 2024
7b039c1
Credo.
cmaddox5 Nov 4, 2024
9e85783
Fix serialization.
cmaddox5 Nov 4, 2024
4136085
Implement list without paging.
cmaddox5 Nov 5, 2024
dc299b8
Add paging.
cmaddox5 Nov 5, 2024
00fd9c6
Added route pills.
cmaddox5 Nov 5, 2024
6890428
Fix horizontal rules.
cmaddox5 Nov 5, 2024
d439a01
Generate pages before rendering any alerts.
cmaddox5 Nov 5, 2024
58e98f3
Added paging indicators.
cmaddox5 Nov 5, 2024
cce1aa1
Fix tests.
cmaddox5 Nov 5, 2024
090cea0
CSS styles.
cmaddox5 Nov 5, 2024
e8afdd1
Drop refresh rate to 7 seconds.
cmaddox5 Nov 5, 2024
89c6f8f
Simplify paging.
cmaddox5 Nov 6, 2024
4d27c3a
Fix horizontal rules.
cmaddox5 Nov 6, 2024
51d6ef5
Fixed paging logic.
cmaddox5 Nov 6, 2024
e7fc3ce
Group alerts by station.
cmaddox5 Nov 6, 2024
84cb3eb
Renamed variable.
cmaddox5 Nov 6, 2024
aa1dcd0
Added a test.
cmaddox5 Nov 6, 2024
414b4f0
Update refresh interval.
cmaddox5 Nov 6, 2024
cd49f08
Various spacing/sizing fixes.
cmaddox5 Nov 6, 2024
5fd3007
Address PR feedback.
cmaddox5 Nov 7, 2024
decbb24
Refactored out common hooks for client paging.
cmaddox5 Nov 8, 2024
8b4c7d5
Fix issue with data not updating if there is only one page.
cmaddox5 Nov 8, 2024
a3f8d53
Fixed styles on rows with short descriptions.
cmaddox5 Nov 8, 2024
7954abf
Simplify page index array generation.
cmaddox5 Nov 12, 2024
594bf8c
Import LCD screen container styles.
cmaddox5 Nov 12, 2024
15da030
Fix variable names.
cmaddox5 Nov 12, 2024
63a946c
Revert changes to LocationContext.
cmaddox5 Nov 12, 2024
218ca12
Merge branch 'main' into cm/list-elevator-closures
cmaddox5 Nov 12, 2024
4528250
Tweak CSS to use compatible features.
cmaddox5 Nov 15, 2024
d75ce56
Use structs instead of plain maps.
cmaddox5 Nov 15, 2024
767559e
Couple more style tweaks.
cmaddox5 Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/css/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ $line-color-ferry: #008eaa;

$alert-yellow: #fd0;

$true-grey-45: #737373;
$true-grey-70: #b2b1af;

$warm-neutral-80: #cccbc8;
Expand Down
3 changes: 3 additions & 0 deletions assets/css/elevator_v2.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
@import "https://rsms.me/inter/inter.css";
@import "colors";
@import "v2/lcd_common/screen_container";
@import "v2/elevator/elevator_closures";
@import "v2/elevator/normal";
@import "v2/simulation_common";
@import "v2/lcd_common/simulation";
@import "v2/elevator/header";
@import "v2/elevator/footer";
@import "v2/lcd_common/route_pill";

body {
margin: 0;
font-family: Inter;
}

.multi-screen-page {
Expand Down
120 changes: 107 additions & 13 deletions assets/css/v2/elevator/elevator_closures.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,131 @@
display: flex;
flex-direction: column;
height: 100%;
font-family: Inter, sans-serif;
background-color: $warm-neutral-90;

.in-station-summary {
display: flex;
gap: 82px;
justify-content: space-between;
padding: 24px 58px;
padding: 24px 48px;
font-size: 48px;
font-weight: 400;
line-height: 64px;
color: $cool-black-30;
}

hr {
width: 100%;
height: 24px;
margin-top: 0;
margin-bottom: 0;
hr.thick {
min-height: 24px;
margin: 0;
background-color: $cool-black-15;
border: none;
}

.outside-alert-list {
hr.thin {
min-height: 2px;
margin: 24px 0 0;
background-color: $true-grey-45;
border: none;
opacity: 0.5;
}

.outside-closure-list {
position: relative;
height: 100%;
background-color: $warm-neutral-90;

.header {
.header-container {
margin: 48px;
margin-bottom: 0;

.header {
display: flex;
max-height: 432px;
font-size: 112px;
font-weight: 700;
line-height: 112px;

&__title {
word-spacing: 9999px;
}
}
}

.closure-list-container {
overflow: hidden;

.closure-list {
display: flex;
flex-flow: column wrap;
column-gap: 96px;
height: 904px;
padding: 0 48px;
transform: translateX(calc(-100% * var(--closure-list-offset)));

.closure-row {
margin-top: 24px;

&__station-name {
font-size: 62px;
font-weight: 600;
line-height: 80px;
color: $cool-black-15;
}

&__name-and-pills {
display: flex;
gap: 24px;
align-items: center;
margin-bottom: 14px;

.route-pill {
width: 132px;
height: 68.13px;

& > * {
height: 100%;
}
}
}

&__elevator-name {
line-height: 64px;
}

&__elevator-name.list-item {
display: list-item;
margin-bottom: 8px;
margin-left: 48px;
}
}
}
}

.paging-info-container {
position: absolute;
bottom: 0;
display: flex;
padding: 48px;
font-size: 150px;
font-weight: 700;
line-height: 150px;
justify-content: space-between;
width: 100%;
height: 72px;

& > * {
margin: 0 48px 12px;
}

.paging-indicators {
display: flex;
gap: 27px;
align-items: center;
margin-right: 66px;
}
}

.paging-info-container,
.closure-row__elevator-name {
font-size: 48px;
font-weight: 400;
color: $cool-black-30;
}
}
}
185 changes: 163 additions & 22 deletions assets/src/components/v2/elevator/elevator_closures.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,65 @@
import React from "react";
import React, { ComponentType, useLayoutEffect, useRef, useState } from "react";
import cx from "classnames";
import NormalService from "Images/svgr_bundled/normal-service.svg";
import AccessibilityAlert from "Images/svgr_bundled/accessibility-alert.svg";
import PagingDotUnselected from "Images/svgr_bundled/paging_dot_unselected.svg";
import PagingDotSelected from "Images/svgr_bundled/paging_dot_selected.svg";
import makePersistent, { WrappedComponentProps } from "../persistent_wrapper";
import RoutePill, { routePillKey, type Pill } from "../departures/route_pill";
digitalcora marked this conversation as resolved.
Show resolved Hide resolved
import _ from "lodash";
import useClientPaging from "Hooks/v2/use_client_paging";

type StationWithClosures = {
id: string;
name: string;
route_icons: Pill[];
closures: ElevatorClosure[];
};

type ElevatorClosure = {
id: string;
elevator_name: string;
elevator_id: string;
description: string;
header_text: string;
};

interface ClosureRowProps {
station: StationWithClosures;
}

const ClosureRow = ({ station }: ClosureRowProps) => {
const { name, closures, route_icons, id } = station;

return (
<div className="closure-row">
<div className="closure-row__name-and-pills">
{route_icons.map((route) => (
<RoutePill pill={route} key={`${routePillKey(route)}-${id}`} />
))}
<div className="closure-row__station-name">{name}</div>
</div>
{closures.map((closure) => (
<div
key={closure.id}
className={cx("closure-row__elevator-name", {
"list-item": closures.length > 1,
})}
>
{closure.elevator_name} ({closure.elevator_id})
</div>
))}
<hr className="thin" />
</div>
);
};

interface InStationSummaryProps {
alerts: string[];
closures: ElevatorClosure[];
}

const InStationSummary = ({ alerts }: InStationSummaryProps) => {
const summaryText = alerts.length
const InStationSummary = ({ closures }: InStationSummaryProps) => {
const summaryText = closures.length
? ""
: "All elevators at this station are currently working";

Expand All @@ -19,44 +71,133 @@ const InStationSummary = ({ alerts }: InStationSummaryProps) => {
<NormalService height={72} width={72} fill="#145A06" />
</span>
</div>
<hr />
<hr className="thick" />
</>
);
};

interface OutsideAlertListProps {
alerts: string[];
interface OutsideClosureListProps extends WrappedComponentProps {
stations: StationWithClosures[];
lastUpdate: number | null;
}

const OutsideAlertList = (_props: OutsideAlertListProps) => {
const OutsideClosureList = ({
stations,
lastUpdate,
onFinish,
}: OutsideClosureListProps) => {
const ref = useRef<HTMLDivElement>(null);

// Each index represents a page number and each value represents the number of rows
// on the corresponding page index.
const [rowCounts, setRowCounts] = useState<number[]>([]);

const numPages = Object.keys(rowCounts).length;
const pageIndex = useClientPaging({ numPages, onFinish, lastUpdate });

const numOffsetRows = Object.keys(rowCounts).reduce((acc, key) => {
if (parseInt(key) === pageIndex) {
return acc;
} else {
return acc + rowCounts[key];
}
}, 0);

useLayoutEffect(() => {
if (!ref.current) return;

const offsets = Array.from(ref.current.children).map((closure) => {
return (closure as HTMLDivElement).offsetLeft;
});

const rowCounts: number[] = [];

_.uniq(offsets).forEach((uo) => {
rowCounts.push(offsets.filter((o) => o === uo).length);
});

setRowCounts(rowCounts);
}, [stations]);

const getPagingIndicators = (num: number) => {
const indicators: JSX.Element[] = [];
for (let i = 0; i < num; i++) {
const indicator =
pageIndex === i ? (
<PagingDotSelected height={40} width={40} key={i} />
) : (
<PagingDotUnselected height={28} width={28} key={i} />
);
indicators.push(indicator);
}

return indicators;
};

return (
<div className="outside-alert-list">
<div className="header">
<span>MBTA Elevator Closures</span>
<span>
<AccessibilityAlert height={128} width={128} />
</span>
<div className="outside-closure-list">
<div className="header-container">
<div className="header">
<div className="header__title">MBTA Elevator Closures</div>
<div>
<AccessibilityAlert height={128} width={155} />
</div>
</div>
<hr className="thin" />
</div>
<div className="closure-list-container">
{
<div
className="closure-list"
style={
{
"--closure-list-offset": pageIndex,
} as React.CSSProperties
}
ref={ref}
>
{stations.map((station) => (
<ClosureRow station={station} key={station.id} />
))}
</div>
}
</div>
{numPages > 1 && (
<div className="paging-info-container">
<div>+{numOffsetRows} more elevators</div>
<div className="paging-indicators">
{getPagingIndicators(numPages)}
</div>
</div>
)}
</div>
);
};

interface Props {
interface Props extends WrappedComponentProps {
id: string;
in_station_alerts: string[];
outside_alerts: string[];
in_station_closures: ElevatorClosure[];
other_stations_with_closures: StationWithClosures[];
}

const ElevatorClosures: React.ComponentType<Props> = ({
in_station_alerts: inStationAlerts,
outside_alerts: outsideAlerts,
other_stations_with_closures: otherStationsWithClosures,
in_station_closures: inStationClosures,
lastUpdate,
onFinish,
}: Props) => {
return (
<div className="elevator-closures">
<InStationSummary alerts={inStationAlerts} />
<OutsideAlertList alerts={outsideAlerts} />
<InStationSummary closures={inStationClosures} />
<OutsideClosureList
stations={otherStationsWithClosures}
lastUpdate={lastUpdate}
onFinish={onFinish}
/>
</div>
);
};

export default ElevatorClosures;
export default makePersistent(
ElevatorClosures as ComponentType<WrappedComponentProps>,
);
Loading
Loading