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
102 changes: 102 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
body {
font-family: 'Roboto', sans-serif;
color: rgba(18, 31, 39, 1);
}

main {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-template-rows: auto;
grid-gap: 20px;
}

h2 {
background-color: rgba(65,98,117, 1);
color: rgba(255, 255, 255, 1);
text-align: center;
padding: 10px 0 10px 0;
margin: 20px 0 0 0;
}

ul {
padding: 0;
height: 120vh;
overflow-x: scroll;
}

li {
padding: 10px 0;
text-align: center;
}

li:nth-child(even) {
background-color: rgba(228, 238, 240, 0.5);
}

li:nth-child(odd) {
background-color: rgba(187, 207, 218, 0.5);
}

li:hover {
background-color: rgba(187, 207, 218, 1);
}

section > div {
background-color: rgba(228, 238, 240, 0.5);
}

button, input[type="submit"] {
background-color: rgba(18, 31, 39, 1);
color: #FFFFFF;
font-size: 0.8rem;
padding: 10px 20px;
border-radius: 10px;
}

button:hover, input[type="submit"]:hover {
background-color: rgba(97, 145, 168, 1);
}

button:focus, input[type="submit"]:focus {
outline: none;
}

form, #trip-details > div {
padding: 20px;
}

#trip-details h4:last-of-type {
margin-bottom: 0;
}

#trip-details p {
margin-top: 5px;
line-height: 1.3;
}

form > div {
padding-bottom: 20px;
}

input[type="text"] {
width: 80%;
margin: 5px 10px;
padding: 5px 0;
}

#reserve-trip h3 {
text-align: center;
}

#status {
padding-top: 20px;
}

#status ul {
height: auto;
}

#status li {
text-align: left;
background-color: rgba(255, 255, 255, 1);
}
35 changes: 35 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Trek</title>
<script
src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link rel="stylesheet" href="index.css">
</head>
<body>
<header>
<h1>Trek</h1>

<button id="load-trips">See All Trips</button>

<section id="status"></section>
</header>

<main>
<section>
<ul id="trip-list"></ul>
</section>

<section>
<div id="trip-details"></div>
<div id="reserve-trip"></div>
</section>
</main>

<script type="text/javascript" src="index.js"></script>
</body>
</html>
145 changes: 145 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
const URL = "https://ada-backtrek-api.herokuapp.com/trips";

const reportStatus = function reportStatus(message) {
$('#status').html(message);
};

const reportError = (message, errors) => {
let content = `<p>${message}</p><ul>`;
for (const field in errors) {
for (const problem of errors[field]) {
content += `<li>${field}: ${problem}</li>`;
}
}
content += "</ul>";
reportStatus(content);
};

const loadTrips = function loadTrips() {
reportStatus("Loading trips... be patient");

const allTrips = $("#all-trips");
const tripList = $("#trip-list");

allTrips.remove();
tripList.empty();

axios.get(URL)
.then((response) => {
tripList.before("<h2 id='all-trips'>All Trips</h2>");
response.data.forEach((trip) => {
tripList.append(`<li id=${trip.id}>${trip.name}</li>`);
});
reportStatus(`Successfully loaded ${response.data.length} trips`);
})
.catch((error) => {
console.log(error.response);
if (error.response.data && error.response.data.errors) {
reportError(
`Encountered an error: ${error.message}`,
error.response.data.errors
);
} else {
reportStatus(`Encountered an error while loading trips: ${error.message}`);
}
});
};

const loadTripDetails = function loadTripDetails() {

const tripDetails = $("#trip-details");
tripDetails.empty();

axios.get(URL + `/${this.id}`)
.then((response) => {
const trip = response.data;
let html = "";

html += `<h2>Trip Details</h2>
<div>
<h3>Name: ${this.innerHTML}<h3>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to break the code to render trip details out into a separate function - as is, this function is doing two things (making the request, and rendering data). See also http://callbackhell.com/

<h4>Continent: ${trip.continent}</h4>
<h4>Category: ${trip.category}</h4>
<h4>Weeks: ${trip.weeks}</h4>
<h4>Cost: $${trip.cost}</h4>
<h4>About:</h4>
<p>${trip.about}</p>
</div>`;

tripDetails.append(html);
reportStatus(`Successfully loaded trip data for ${trip.name}`);
})
.catch((error) => {
console.log(error.response);
if (error.response.data && error.response.data.errors) {
reportError(
`Encountered an error: ${error.message}`,
error.response.data.errors
);
} else {
reportStatus(`Encountered an error while loading trip: ${error.message}`);
}
});
};

const loadReserveTrip = function loadReserveTrip() {

const reserveTrip = $("#reserve-trip");
reserveTrip.empty();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of breaking this code out into a separate function. Good organization!


let html = "";
html += `<h2>Reserve Trip</h2>
<h3>${this.innerHTML}</h3>
<form id=${this.id}>
<div>
<label for='name'>Name:</label>
<input type='text' id='name' />
</div>
<div>
<label for='email'>Email:</label>
<input type='text' id='email' />
</div>
<input type='submit' value='Reserve' />
</form>`;

reserveTrip.append(html);
};

const makeReservation = function makeReservation(event) {
event.preventDefault();

const entryData = {
name: $("#name").val(),
email: $("#email").val()
};

const tripID = event.target.id;

axios.post(URL + `/${tripID}/reservations`, entryData)
.then((response) => {
console.log(response);

reportStatus(`Successfully reserved trip ${tripID} for ${$("#name").val()}`);

$("#name").val(''),
$("#email").val('')
})
.catch((error) => {
console.log(error.response);
if (error.response.data && error.response.data.errors) {
reportError(
`Encountered an error: ${error.message}`,
error.response.data.errors
);
} else {
reportStatus(`Encountered an error reserving trip: ${error.message}`);
}
});
};

$(document).ready(() => {
$("#load-trips").click(loadTrips);
$("#trip-list").on("click", "li", loadTripDetails);
$("#trip-list").on("click", "li", loadReserveTrip);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than running loadReserveTrip immediately when a trip is clicked, it might work better to only load it when the GET request for the individual trip comes back. That is, call that function from within the then callback of loadTripDetails.

$("#reserve-trip").submit(makeReservation);
});