Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added septa-fare-calculator/favicon.ico
Binary file not shown.
115 changes: 107 additions & 8 deletions septa-fare-calculator/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SEPTA Regional Rail Fare Calculator</title>
</head>
<body>

</body>
</html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SEPTA Regional Rail Fare Calculator</title>
<link rel="stylesheet" href="./src/css/index.css" />
<link rel="icon" href="./favicon.ico" />
</head>
<body onload="onLoad()">
<!-- Tried to keep things super semantic, but called in aria-labels when necessary -->
<main name="main content" class="widget-body">
<header name="header" class="widget-header">
<img
src="favicon.ico"
alt="The logo of SEPTA Regional Rail, two opposite arrows dividing a red and blue background"
/>Regional Rail Fares
</header>
<section id="where-going" class="widget-section">
<label for="where-going-select">Where are you going?</label>
<select id="where-going-select" autocomplete="off">
<option tabindex="" value="Zone 1">Zone 1</option>
<option tabindex="" value="Zone 2">Zone 2</option>
<option tabindex="" value="Zone 3">Zone 3</option>
<option tabindex="" value="Zone 4" selected>Zone 4</option>
<option tabindex="" value="Zone 5">Zone 5</option>
</select>
</section>
<section id="when-riding" class="widget-section">
<label for="when-riding-select">When are you riding?</label>
<select id="when-riding-select" name="select menu" autocomplete="off">
<option tabindex="" value="weekday" selected>Weekday</option>
<option tabindex="" value="weekday_evening">
Weekday (After 7pm)
</option>
<option tabindex="" value="weekend">Weekend</option>
<option tabindex="" value="holiday">Federal Holiday</option>
<option tabindex="" value="anytime">Anytime</option>
</select>
<span
class="when-riding-helper"
name="extra info about when you are riding"
aria-labelled="extra fare info"
id="when-riding-helper-text"
>Valid Monday through Friday, 4:00 a.m. - 7:00 p.m. On trains arriving
or departing 30th Street Station, Suburban and Jefferson Station</span
>
</section>
<section id="where-fare" class="widget-section">
<span>Where will you purchase the fare?</span>
<div role="radiogroup" class="kioskOrOnboardContainer">
<label for="kiosk" class="kioskOrOnboardContainer-label"
>Station Kiosk</label
>
<input
name="kioskOrOnboardBtn"
role="radio"
class="kioskOrOnboardRadio"
type="radio"
id="kiosk"
value="kiosk"
/>
<label
for="onboard"
class="kioskOrOnboardContainer-label checked-label"
>Onboard</label
>
<input
name="kioskOrOnboardBtn"
role="radio"
type="radio"
class="kioskOrOnboardRadio"
id="onboard"
value="onboard"
checked="checked"
/>
</div>
</section>
<section id="num-rides" class="widget-section">
<label for="num-rides-input">How many rides will you need?</label>
<input
id="num-rides-input"
name="number of rides"
type="number"
value="4"
min="1"
max="10"
autocomplete="off"
/>
</section>
<section id="price-calc" class="widget-section">
<div class="price-calc-output">
<span class="price-calc-output-text" id="fare-cost"
>Your fare will cost</span
>
<span
class="price-calc-output-number"
name="price of fare"
aria-labelledby="fare-cost"
>$28.00</span
>
</div>
</section>
<script type="text/javascript" src="./src/js/FareCalculator.js"></script>
<script type="text/javascript" src="./src/js/index.js"></script>
</main>
</body>
</html>
125 changes: 125 additions & 0 deletions septa-fare-calculator/src/css/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
body {
height: 100vh;
display: flex;
}

.widget-body {
border: 2px solid lightgrey;
width: 100%;
margin: auto;
}

.widget-body,
.widget-section,
.widget-section div {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}

.widget-section {
border-bottom: 1px solid lightgrey;
width: 100%;
height: 20vh;
}

.widget-section input[type="number"],
.widget-section select {
font-size: 1.25em;
}

.kioskOrOnboardContainer-label {
font-size: 1.5em;
margin: 5px;
color: grey;
}

.widget-section select,
.widget-section input[type="number"] {
background: none;
text-align: left;
border: 1px solid lightgrey;
border-radius: 10px;
width: 75%;
padding: 0.5em;
color: grey;
}

.widget-section input[type="number"] {
text-align: center;
color: black;
}

.widget-section > label,
.widget-section > span:first-child {
margin: 0.5rem;
font-size: 1.25em;
font-family: Verdana, Geneva, Tahoma, sans-serif;
color: grey;
}

.widget-header {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
font-size: 1.5em;
background-color: grey;
color: white;
height: 2em;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-weight: bold;
}

.widget-header img {
margin-right: 20px;
}

.when-riding-helper {
color: grey;
font-size: 0.8rem;
width: 80%;
text-align: center;
}

.kioskOrOnboardContainer input {
display: none;
}

.kioskOrOnboardContainer-label {
padding: 5px;
border: 1px solid lightgrey;
border-radius: 10px;
width: 100%;
text-align: center;
}

.checked-label {
background: grey;
color: white;
border: 2px solid grey;
}

input:hover,
label:hover {
cursor: pointer;
}

#price-calc {
font-size: 1.25em;
background: gray;
color: white;
}

.price-calc-output-number {
font-size: 3em;
}

@media screen and (min-width: 600px) {
body {
width: 30%;
margin: auto;
}
}
Empty file.
67 changes: 67 additions & 0 deletions septa-fare-calculator/src/js/FareCalculator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
class FareCalculator {
constructor(
whereGoing,
whenRiding,
purchasedAtOnboard,
numberOfRides,
fareZoneInfo
) {
this.whereGoing = parseInt(whereGoing.split(" ")[1]) || 4;
this.whenRiding =
!whenRiding === "anytime" || !whenRiding === "weekday"
? "evening_weekend"
: whenRiding;
this.purchasedAtOnboard = purchasedAtOnboard
? "onboard_purchase"
: "advance_purchase";
this.numberOfRides = numberOfRides || 4;
this.fareZoneInfo = fareZoneInfo || [];
}

setWhereGoing(str) {
this.whereGoing = parseInt(str.split(" ")[1]);
}

setWhenRiding(str) {
const whenRiding =
str === "anytime" || str === "weekday" ? str : "evening_weekend";
this.whenRiding = whenRiding;
}

setPurchasedAtOnboard(boolean) {
const purchasedAtOnboard = boolean
? "onboard_purchase"
: "advance_purchase";
this.purchasedAtOnboard = purchasedAtOnboard;
}

setNumberOfRides(num) {
this.numberOfRides = num;
}

calculateFare() {
let price;
const fareZone = this.fareZoneInfo.find((z) => z.zone === this.whereGoing);

//because everything except anytime and weekday share same pricing, this parses the user's preference to coincide with the json.
//however, we kept the values as user-friendly labels in the html for screen readers
const fareType = fareZone.fares.filter((fare) => {
return fare.type === this.whenRiding;
});

//we can end the function early if "anytime" is selected, because that's all the info we need to get the user's price - only one anytime price exists per zone
if (this.whenRiding === "anytime") {
price = fareType[0].price;

return price;
}

const farePurchase = fareType.find(
(fare) => fare.purchase === this.purchasedAtOnboard
);

price = farePurchase.price;
if (this.numberOfRides > 9) return price;
return price * this.numberOfRides;
}
}
Loading