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
68 changes: 68 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
body {
font-family: 'Roboto', sans-serif;
font-weight: 100;
}

button, .button {
margin: 0.5em;
background: linear-gradient(#F0F0F0, #7C7B7B);
color: #FFFFFF;
border-radius: 5px;
font-size: 0.85em;
padding: 0.8em;
cursor: pointer;
}

.container {
display: grid;
grid-template-columns: 1fr 1fr;
}

.hidden {
display: none;
}

.trip-detail h3 {
text-align: center;
}

.trip-detail-section {
margin-bottom: 0.5em;
}

.trip-detail-section, .reserve-trip{
border: .5px solid black;
padding: 0 1em 1em 1em;
}

.trips, span {
cursor: pointer;
margin-bottom: 1em;
}

.trips li {
padding: 0.5em;
padding-left: 0;
list-style-type: none;
}

#trip-form > div {
margin-bottom: 0.5em;
}

#reserve-trip-button {
margin-top: 1em;
}

.more {
background-color: lightgrey;
}

@media screen and (max-width: 630px) {
.container {
display: flex;
flex-direction: column-reverse;
}

.trips, .trip-detail-section {
}
56 changes: 56 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Trek</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<section id="status-message"></section>
<h1>Trek</h1>
<div>
<h3>Welcome To Trek</h3>
<h4>Your destination for planning a fabulous trip to... another destination.</h4>
</div>
<main>
<section class="buttons">
<button id="load">See ALL Trips</button>
<button id="asia">Asia</button>
<button id="africa">Africa</button>
<button id="antartica">Antartica</button>
<button id="australasia">Australasia</button>
<button id="europe">Europe</button>
<button id="north-amer">North America</button>
<button id="south-amer">South America</button>
</section>
<div class="container">
<div>
<ul class="trips hidden" id="trip-list"></ul>
</div>
<section class="hidden trip-detail">
<h3>Trip Details</h3>
<div id="trip-detail-section" class="trip-detail-section">
</div>
<div class="reserve-trip">
<h3>Reserve Trip</h3>
<form id="trip-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 class="button" type="submit" name="add-trip" value="Reserve Trip" />
</form>
</div>
</section>
</div>
</main>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="index.js"></script>
</body>
</html>
219 changes: 219 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
const URL = 'https://ada-backtrek-api.herokuapp.com/trips/';

// Report helpers
const reportStatus = (message) => {
$('#status-message').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);
};

//LOAD all/specific trips based on url params
const getTrips = (url) => {
const tripList = $('#trip-list');
tripList.show();
Copy link

Choose a reason for hiding this comment

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

This is just a random jQuery thing that I'm not too concerned about but: Since you're calling .show() on this element, jQuery actually puts an inline style on this element for style={display: block;} ... which is fine, except that it's awkward since there's a class on this called hidden that never gets removed... so it ends up looking like this:

<ul class="trips hidden" id="trip-list" style="display: block;"> ... </ul>

It's a little awkward to read class="hidden" and at the same time see it on the page because of the inline style.

Like I said, I'm not too worried about this... unless it introduces bugs later (what if you try to select on $('.hidden')?) It might make sense to conform to one style or the other (either removing the class hidden instead of using .show(), or in $(document).ready calling $('#trip-list').hide() right at the beginning

tripList.empty();

reportStatus('Loading trips, please wait...');

axios.get(url)
.then((response) => {
let header = $(`<h4>All Trips</h4>`)
tripList.append(header);

response.data.forEach((trip) => {
let item = $(`<li>${trip.name}</li>`).attr('id', `${trip.id}`);
tripList.append(item);
});

reportStatus(`Successfully loaded ${response.data.length} trips`)
})
.catch((error) => {
console.log(error);
reportStatus(`Error: ${error.message}`);
});
};

// GET ALL TRIPS
const loadTrips = () => {
getTrips(URL)
}
// GET ASIA
const asiaTrips = () => {
let url = (URL + '/continent?query=Asia')
getTrips(url)
}
// GET AFRICA
const africaTrips = () => {
let url = (URL + '/continent?query=Africa')
getTrips(url)
}
// GET Antartica
const antarticaTrips = () => {
let url = (URL + '/continent?query=Antartica')
getTrips(url)
}
// GET Australasia
const australasiaTrips = () => {
let url = (URL + '/continent?query=Australasia')
getTrips(url)
}
// GET EUROPE
const europeTrips = () => {
let url = (URL + '/continent?query=Europe')
getTrips(url)
}
// GET North America
const nAmericaTrips = () => {
let url = (URL + '/continent?query=North%20America')
getTrips(url)
}
// GET South America
const sAmericaTrips = () => {
let url = (URL + '/continent?query=South%20America')
getTrips(url)
}
Copy link

@tildeee tildeee Jun 1, 2018

Choose a reason for hiding this comment

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

These functions all end up feeling very similar! It might make sense to refactor them such that...

const getTripsByContinent = (continentName) => {
  getTrips( encodeURI( URL + '/continent?query=' + continentName ) );
}

Then lines 167-173 could look maybe more like

$('#asia').click( (event) => getTripsByContinent('Asia') );


// GET details for single trip
const getTripDetails = function getTripDetails(id) {

let tripDetail = $('#trip-detail-section');
tripDetail.empty();

axios.get(URL + id)
.then((response) => {
let data = response.data;
let name = $(`<h4><strong>Name:</strong> ${data.name}</h4>`).addClass(`${id}`);
Copy link

Choose a reason for hiding this comment

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

It might make more sense to set the id attr on this element instead of adding a class, because this value represents a unique identifier rather than a styling class?

let about = $(`<span><strong>Description:</strong> ${data.about.slice(0, 150)}</span>`).addClass("teaser");
let aboutFullText = $(`<span>${data.about.slice(150)}</span>`).addClass("moreinfo hidden").attr('id', 'info1');
Copy link

Choose a reason for hiding this comment

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

super neat solution, nice!

let more = $(`<span>...Read more</span>`).addClass("more").attr('target', 1);
let continent = $(`<p><strong>Continent:</strong> ${data.continent}</p>`);
let category = $(`<p><strong>Category:</strong> ${data.category}</p>`);
let weeks = $(`<p><strong>Weeks:</strong> ${data.weeks}</p>`);
let cost = $(`<p><strong>Cost:</strong> $${data.cost}</p>`);

tripDetail.append(name, about, aboutFullText, more, continent, category, weeks, cost);

reportStatus(`Successfully loaded details for ${response.data.name} trip`)
})
.catch((error) => {
console.log(error);
reportStatus(`Error: ${error.message}`);
});
}

// Form helpers
const FORM_FIELDS = ['name', 'email'];
const inputField = name => $(`#trip-form input[name="${name}"]`);

const readFormData = () => {
const getInput = name => {
const input = inputField(name).val();
return input ? input : undefined;
};

const formData = {};
FORM_FIELDS.forEach((field) => {
formData[field] = getInput(field);
});

return formData;
};

const clearForm = () => {
FORM_FIELDS.forEach((field) => {
inputField(field).val('');
});
}

// Reserve spot on trip
const reserveTrip = (event) => {
event.preventDefault();
// let id = Number($('#trip-detail-section h4')[0].classList[0]);
let id = $('.trip-detail-section h4').attr("class");

const tripData = readFormData();

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

axios.post((`${URL}${id}/reservations`), tripData)
.then((response) => {
clearForm();
reportStatus(`Successfully created trip reservation with ID ${response.data.trip_id}!`);
Copy link

Choose a reason for hiding this comment

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

response.data.trip_id refer to the ID of the trip, not the reservation itself. Funnily enough, the API doesn't give back a response with the reservation ID!

})
.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: ${error.message}`);
}
});
}

$(document).ready(() => {
$('#load').click(loadTrips);
$('#asia').click(asiaTrips);
$('#africa').click(africaTrips);
$('#antartica').click(antarticaTrips);
$('#australasia').click(australasiaTrips);
$('#europe').click(europeTrips);
$('#north-amer').click(nAmericaTrips);
$('#south-amer').click(sAmericaTrips);

$('#trip-list').on('click', 'li', function(event) {
let id = Number(event.target.id);
$("section").removeClass("hidden");
Copy link

Choose a reason for hiding this comment

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

this ends up working, but it might be more specific to use a more specific selector than 'section' since you have more than one section in your HTML

getTripDetails(id);
});

$('#trip-form').submit(reserveTrip);

$(".trip-detail-section").on('click', '.more', function(event) {
$(".moreinfo").removeClass("hidden");
$(".more").addClass("hidden");
});

//Failed attempts at reading input from a drop-down form to select specific continent...
// $('load-by-continent-form').submit(function() {
// console.log($("#load-by-continent-form").val());
// });

// $('#submit').on('click', function() {
// let continent = $( "#load-by-continent" ).val();
// loadTripsByContinent(continent);
// });

// $('#load-by-continent').submit(function() {
// let continent = $( "#load-by-continent" ).val();
// loadTripsByContinent(continent);
// });

//More failed attempts at making a toggle read more/less function
// $('.moreinfo').hide();
// $('.more').click(function (ev) {
// $(".more-info").removeClass("hidden");
// console.log(ev);
// let t = ev.target
// $('#info' + $(this).attr('target')).toggle(500, function(){
// $(t).html($(this).is(':visible')? 'I\'m done reading more' : 'Read more')
// });
// return false;
// });
// $(".more").toggle(function(){
// $(this).text("less..").siblings(".complete").show();
// }, function(){
// $(this).text("more..").siblings(".complete").hide();
// });
});