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
52 changes: 52 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Trekking</title>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript" src="index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css?family=Nunito&display=swap" rel="stylesheet">
</head>

<body>
<section id="status-message"></section>

<main>
<section id="list-trips" class="current-trips">
<h1>Trek</h1>
<button id="load" type="button" class="btn btn-primary">See all Trips</button>
<ul id="trip-list"></ul>
</section>

<section class="trip">
<section class="selected-trip">
<h1 id="trip-section" class="hide-reservation">Trip Details</h1>
<ul id="trip-details"></ul>
</section>

<section id="new-reservation" class="hide-reservation">
<h1>Add reservation to this trip</h1>
<form id="reservation-form">
<div>
<label for="name">Name</label>
<input type="text" name="name" />
</div>

<div>
<label for="email">Email</label>
<input type="text" name="email" />
</div>

<input type="submit" name="add-reservation" value="Reserve" class="btn btn-primary"/>
</form>
</section>
</section>
</main>
</body>
</html>



117 changes: 117 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const URL = 'https://trektravel.herokuapp.com/trips';

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

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

const showTripDetails = (event, tripId) => {
const tripDetails = $('#trip-details');
tripDetails.empty();

event.preventDefault();

$('#trip-section').removeClass().addClass('show-reservation');

// trip details
axios.get(`${URL}/${tripId}`)
.then((response) => {
reportStatus(`Successfully loaded details for ${response.data.name} trip`);
tripDetails.append(`<li>Trip ID: ${response.data.id}</li>`);
tripDetails.append(`<li>Name: ${response.data.name}</li>`);
tripDetails.append(`<li>Continent: ${response.data.continent}</li>`);
tripDetails.append(`<li>About: ${response.data.about}</li>`);
tripDetails.append(`<li>Category: ${response.data.category}</li>`);
tripDetails.append(`<li>Duration: ${response.data.weeks} weeks</li>`);
tripDetails.append(`<li>Cost: ${response.data.cost}</li>`);

$('#new-reservation').removeClass().addClass('show-reservation');
})
.catch((error) => {
reportStatus(`Encountered an error while loading trip: ${error.message}`);
console.log(error);
});

// reservation form
const readFormData = () => {
const parsedFormData = {};

const nameFromForm = $(`#reservation-form input[name="name"]`).val();
parsedFormData.name = nameFromForm ? nameFromForm : undefined;

const emailFromForm = $(`#reservation-form input[name="email"]`).val();
parsedFormData.email = emailFromForm ? emailFromForm : undefined;

return parsedFormData;
};

const clearForm = () => {
$(`#reservation-form input[name="name"]`).val('');
$(`#reservation-form input[name="email"]`).val('');
}

// create new reservation
const createReservation = (event) => {
event.preventDefault();

const reservationData = readFormData();
console.log(reservationData);

reportStatus('Sending reservation data...');

axios.post(`${URL}/${tripId}/reservations`, reservationData)
.then((response) => {
reportStatus(`Successfully added a reservation for ${response.data.name}!`);
clearForm();
})
.catch((error) => {
console.log(error.response);
if (error.response.data && error.response.data.errors) {

Choose a reason for hiding this comment

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

Nicely done

reportError(
`Encountered an error: ${error.message}`,
error.response.data.errors
);
} else {
reportStatus(`Encountered an error: ${error.message}`);
}
});
};
$('#reservation-form').submit(createReservation);

Choose a reason for hiding this comment

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

Every time you click on trips, this attaches a new event handler to the form. This means if I click on a few trips a few times and then fill out and submit the form, several submit event handlers will fire and I'll get added to the trip multiple times.

Take a look at it in dev tools with the network tab open. You'll see the problem.

Instead you should clear all the event handlers from the form before attaching a new one.

};

const listTrips = () => {
reportStatus('Loading trips...');

const tripList = $('#trip-list');
tripList.empty();

$('#load').removeClass().addClass('hide-reservation');

// list all trips
axios.get(URL)
.then((response) => {
reportStatus(`Successfully loaded ${response.data.length} trips`);
response.data.forEach((trip) => {
tripList.append(`<li><a href="#" onclick="return showTripDetails(event, ${trip.id});">${trip.name}</a></li>`);
});
})
.catch((error) => {
reportStatus(`Encountered an error while loading trips: ${error.message}`);
console.log(error);
});
};

$(document).ready(() => {
$('#load').click(listTrips);
});
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.hide-reservation {
display: none;
}

.show-reservation {
display: block;
}

body {
font-family: 'Nunito', sans-serif;
margin: 2em;
}

main {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 10px;
grid-auto-rows: minmax(100px, auto);
}

.list-trips {
grid-column: 1;
}

.trip {
grid-column: 2;
}

#trip-details {
list-style-type: none;
}

ul {
font-size: 1.25em;
}