diff --git a/dist/index.html b/dist/index.html index b873b1e..d47c7d6 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,20 +1,111 @@ - - - My JavaScript App - - - -
- -
-
- -
- - - + + + + Trekkin' + + + + + +
+

Trekkin' - Go Global!

+ +
+ +
+
+ + + +
+
+ + + + + + + + + + +
NameTrip IDCategoryContinentWeeksCost
+
+ +
+ + + + + + + + + + + diff --git a/src/app.js b/src/app.js index e7af594..a6d0edf 100644 --- a/src/app.js +++ b/src/app.js @@ -1,13 +1,204 @@ -// Vendor Modules +// Vendor Modules. import $ from 'jquery'; import _ from 'underscore'; -// CSS +// CSS. import './css/foundation.css'; import './css/style.css'; -console.log('it loaded!'); +// Models and collections. +import Trip from './app/models/trip'; +import TripList from './app/collections/trip_list'; +import Reservation from './app/models/reservation'; + +// DOM Selectors. +const $tripsList = $('#trips-list') +const $tripDescription = $('#trip-description') +const $reservationTripForm = $('#reservation-trip-form') + +// Templates for trip list and details. +let tripTemplate; +let tripDetailsTemplate; + +// Start of trip list. +const tripList = new TripList(); + +const render = function render(tripList) { + console.log(tripList); + const $trips = $('#trips-list') + + // Remember to empty, so things don't repeat. + $trips.empty(); + tripList.forEach((trip) => { + $trips.append(tripTemplate(trip.attributes)); + console.log(trip.attributes); + console.log('It loaded!'); + }); +}; + +const fields = ['name', 'id', 'category', 'continent', 'weeks', 'cost', 'about']; + +const reservationFields = ['name', 'email', 'age']; + +// const updateStatusMessageFrom = (messageHash) => { +// $('#status-messages ul').empty(); +// for(let messageType in messageHash) { +// messageHash[messageType].forEach((message) => { +// $('#status-messages ul').append($(`
  • ${messageType}: ${message}
  • `)); +// console.log(`
  • ${messageType}: ${message}
  • `); +// }) +// } +// $('#status-messages').show(); +// } +// +// const updateStatusMessageWith = (message) => { +// $('#status-messages ul').empty(); +// $('#status-messages ul').append(`
  • ${message}
  • `); +// $('#status-messages').show(); +// } + +const events = { + // Add a bloody trip + addTrip(event) { + event.preventDefault(); + const tripData = {}; + fields.forEach( (field) => { + const val = $(`input[name=${field}]`).val(); + if (val != '') { + tripData[field] = val; + } + }); + + const trip = new Trip(tripData); + + if (trip.isValid()) { + // tripList.add(trip); + trip.save({}, { + success: events.successfullSave, + error: events.failedSave, + }); + } else { + console.log('Trip is invalid, sad trombone.'); + console.log(trip.validationError); + + // updateStatusMessageFrom(trip.validationError); + } + }, + + successfullSave(trip, response) { + console.log('Success!'); + console.log(trip); + console.log(response); + $('#status-messages ul').empty(); + $('#status-messages ul').append(`
  • ${trip.get('title')} added to ze listy list list!
  • `); + $('#status-messages').show(); + tripList.fetch(); + }, + + failedSave(trip, response) { + console.log('ERROR!'); + console.log(trip); + console.log(response); + $('#status-messages ul').empty(); + console.log(response.responseJSON.errors); + + for(let key in response.responseJSON.errors) { + response.responseJSON.errors[key].forEach((error) => { + $('#status-messages ul').append(`
  • ${key}: ${error}
  • `); + }) + } + $('#status-messages').show(); + trip.destroy(); + }, + + // Make a reservation + + + + addReservation(event){ + event.preventDefault(); + let reserveData = {}; + + reservationFields.forEach((field) => { + console.log(`assigning ${field}`); + const value = $(`#reservation-trip-form input[name=${field}]`).val(); + console.log(value); + reserveData[field] = value; + }); + + console.log('Your reservation has been added!'); + console.log(reserveData); + + const reservation = new Reservation(reserveData); + reservation.urlRoot = `https://ada-backtrek-api.herokuapp.com/trips/1/reservations`; + + reservation.save(); + + }, + + // Sort Trips + sortTrips(event) { + console.log(event); + console.log(this); + // Get the class list of the selected element + const classes = $(this).attr('class').split(/\s+/); + + classes.forEach((className) => { + if (fields.includes(className)) { + if (className === tripList.comparator) { + tripList.models.reverse(); + tripList.trigger('sort', tripList); + } + else { + tripList.comparator = className; + tripList.sort(); + } + } + }); + + $('.sort-field').removeClass('sort-field'); + $(this).addClass('sort-field'); + }, +}; $(document).ready( () => { - $('main').html('

    Hello World!

    '); + + // $('#reservation-trip-form').submit((event) => { + // event.preventDefault(); + // + // const url = $('form').attr('action'); + // console.log(url); + // const id = ($('form').attr('tripid')); + // const reservationUrl = `${url}${id}/reservations`; + // const formData = $('form').serialize(); + // + // $.post(reservationUrl, formData, (response) => { + // $('#message').html('

    Trip Reserved!

    '); + // console.log(response); + // }); + // }); + + // Get those trip deets. + $tripsList.on('click', 'tr', function getTrip() { + const trip = new Trip({ id: $(this).attr('data-id') }) + $tripDescription.empty(); + + trip.fetch().done(() => { + $tripDescription.append(tripDetailsTemplate(trip.attributes)); + }); + }); + + + tripTemplate = _.template($('#trip-template').html()); + tripList.on('update', render, tripList); + tripList.fetch(); + + tripDetailsTemplate = _.template($('#trip-details-template').html()); + + $('#add-trip-form').submit(events.addTrip); + + $('#reservation-trip-form').submit(events.addReservation); + + $('.sort').click(events.sortTrips); + tripList.on('sort', render, tripList); }); diff --git a/src/app/collections/trip_list.js b/src/app/collections/trip_list.js new file mode 100644 index 0000000..80ecfdb --- /dev/null +++ b/src/app/collections/trip_list.js @@ -0,0 +1,15 @@ +import Backbone from 'backbone'; +import Trip from '../models/trip'; + +const TripList = Backbone.Collection.extend({ + + model: Trip, + + url: 'https://ada-backtrek-api.herokuapp.com/trips', + + parse: function(response) { + return response; + } +}); + +export default TripList; diff --git a/src/app/models/reservation.js b/src/app/models/reservation.js new file mode 100644 index 0000000..00917c9 --- /dev/null +++ b/src/app/models/reservation.js @@ -0,0 +1,32 @@ +import Backbone from 'backbone'; + +const Reservation = Backbone.Model.extend({ + + validate: function(attributes) { + const error = {}; + + if (!attributes.name) { + error['name'] = 'Full Name cannot be blank!'; + } + + if (!attributes.email) { + error['email'] = 'E-Mail cannot be blank!'; + } + + if (!attributes.age) { + error['age'] = 'Age cannot be blank!'; + } else if (isNaN(attributes.age)) { + error['age'] = 'Age must be a number!'; + } + + console.log('Error!'); + console.log(error); + if (Object.keys(error).length > 0) { + return error; + } else { + return false; + } + } +}); + +export default Reservation; diff --git a/src/app/models/trip.js b/src/app/models/trip.js new file mode 100644 index 0000000..8592825 --- /dev/null +++ b/src/app/models/trip.js @@ -0,0 +1,49 @@ +import Backbone from 'backbone'; + +const Trip = Backbone.Model.extend ({ + + urlRoot: 'https://ada-backtrek-api.herokuapp.com/trips', + + parse(response) { + return response + }, + + validate: function(attributes) { + const error = {}; + const continents = ['Africa', 'Antartica', 'Asia', 'Australasia', 'Europe', 'North America', 'South America'] + + if (!attributes.name) { + error['name'] = 'Name cannot be blank!'; + } + + if (!attributes.continent) { + error['continent'] = 'Continent cannot be blank!'; + } else if (!continents.includes(attributes.continent)) { + error['continent'] = 'Please only use actual continents!'; + } + + if (!attributes.category) { + error['category'] = 'The category cannot be blank!'; + } + + if (!attributes.weeks) { + error['weeks'] = 'Weeks cannot be blank!'; + } else if (isNaN(attributes.weeks)){ + error['weeks'] = 'Numbers only please!'; + } + + if (!attributes.cost) { + error['cost'] = 'The cost cannot be blank!'; + } else if (isNaN(attributes.cost)) { + error['cost'] = 'Numbers only please!' + } + + if (Object.keys(error).length > 0) { + return error; + } else { + return false; + } + }, +}); + +export default Trip; diff --git a/src/css/models/.keep b/src/css/models/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/css/models/book.js b/src/css/models/book.js new file mode 100644 index 0000000..beb48a1 --- /dev/null +++ b/src/css/models/book.js @@ -0,0 +1,7 @@ +import Backbone from 'backbone'; + +const Book = Backbone.Model.extend ({ +// Custom code +}); + +export default Book; diff --git a/src/css/models/cat.js b/src/css/models/cat.js new file mode 100644 index 0000000..b31d419 --- /dev/null +++ b/src/css/models/cat.js @@ -0,0 +1,7 @@ +import Backbone from 'backbone'; + +const Cat = Backbone.Model.extend ({ +// Custom code +}); + +export default Cat; diff --git a/src/css/style.css b/src/css/style.css index b7b2d44..8bc7ef4 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1,2 +1,60 @@ +h1 { + text-align: center; +} -/* Your styles go here! */ +#trip-list { + list-style: none; + margin-left: 0; +} + +th.sort { + cursor: pointer; +} + +.sort-field { + background-color: green; + color: white; +} + +footer { + text-align: center; +} + +#trip-details-template { + +} + +/* Styles for error section at the top */ +#status-messages { + background-color: #dfdfdf; + + /* Hide by default */ + display: none; + + border-radius: 1rem; + margin: 1rem; + height: 100%; + padding: .8rem; +} + +#status-messages ul { + list-style: none; + margin-left: 0; +} + +#status-messages button.clear { + margin-top: .2rem; + height: 100%; +} + +#status-messages button.clear img { + width: 2rem; +} + +#status-messages .error { + color: red; +} + +#status-messages .success { + color: green; +}