Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipes - Kate Evans-Spitzer - BackTREK #40

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
537f604
initialize
Guribot Nov 28, 2017
ade1b58
basic html layout
Guribot Nov 29, 2017
3bca65b
add Trip and TripList model/collection
Guribot Nov 29, 2017
20cc153
add default values to trip model
Guribot Nov 29, 2017
11487c1
trip list populates
Guribot Nov 29, 2017
b31f49b
add initial show logic
Guribot Nov 29, 2017
d2d4fd2
implement trip#show logic, change trip#index to list i/o table
Guribot Nov 29, 2017
0161dac
fix trip#show to use id instead of faking cid
Guribot Nov 29, 2017
e99533d
clicking a selected trip will deselect/minimize
Guribot Nov 29, 2017
bfd2896
formatting for forms
Guribot Nov 29, 2017
32c1a74
colors??
Guribot Nov 29, 2017
0f04cd2
tone down colors
Guribot Nov 29, 2017
895b69f
add duration, cost to filter list
Guribot Nov 29, 2017
dac3cc7
add reservation form modal
Guribot Nov 30, 2017
1da09e4
add background image
Guribot Nov 30, 2017
e221abe
add background image
Guribot Nov 30, 2017
d5fbfb6
Merge branch 'master' of https://github.com/Guribot/BackTREK
Guribot Nov 30, 2017
456a1bf
can book reservation
Guribot Nov 30, 2017
d5cb2d8
styling for form success text
Guribot Nov 30, 2017
b2adb68
fix reservation button not minimizing properly
Guribot Nov 30, 2017
3479b08
remove header bgcolor
Guribot Nov 30, 2017
b206b8e
add clientside validation for reservations
Guribot Dec 1, 2017
da1837c
header formatting tweaks
Guribot Dec 1, 2017
e2f9a62
implement add trip modal (no logic)
Guribot Dec 1, 2017
db11e7f
implement trip post logic
Guribot Dec 1, 2017
5e4a433
organize functions
Guribot Dec 1, 2017
33322ce
validations for trip
Guribot Dec 1, 2017
b34b0d1
sort data by clicking headers
Guribot Dec 1, 2017
feb9f5a
visual feedback for sorting
Guribot Dec 1, 2017
bb6dec3
implement basic filtering
Guribot Dec 1, 2017
0590e8e
live filtering
Guribot Dec 1, 2017
5d08bfd
add message for search with zero results
Guribot Dec 1, 2017
6abc4da
formatting for search
Guribot Dec 1, 2017
d73d4e2
fontsgit st
Guribot Dec 1, 2017
137644c
fonts!!!
Guribot Dec 1, 2017
a6d39cb
clean up ID finders, event delegation
Guribot Dec 4, 2017
7142c94
Merge branch 'master' of https://github.com/Guribot/BackTREK
Guribot Dec 4, 2017
eb3b965
remove debugging output from TripList
Guribot Dec 4, 2017
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
156 changes: 149 additions & 7 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,161 @@
<html>
<head>
<meta charset="utf-8">
<title>My JavaScript App</title>
<title>backTREK</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Comfortaa" rel="stylesheet">
</head>
<body>
<header>
<div class="row">

</header>
<main>
<h1>backTREK</h1>
<a id="add-trip" class="button add-trip">+</a>
</div>
<form id="trip-search" class="small-12 medium-9 columns on-load">
<div class="form-holder search-type-holder small-12 medium-4 large-3 columns">
<select name="search-type">
<option value="name">Trip Name</option>
<option value="continent">Continent</option>
<option value="category">Category</option>
<option value="weeks">Duration</option>
<option value="cost">Cost</option>
</select>
</div>

</main>
<footer>
<div class="form-holder text-holder small-12 medium-8 large-9 columns">
<input type="text" name="query" />
</div>
</form>
</header>
<section id="intro-button">
<a class="button intro-button small-10 medium-5 columns" id="show-trips">See The World</a>
</section>
<main class="on-load">
<div id="loading">
<h3>Loading . . .</h2>
</div>
<section id="trip-list" class="trip-list" style="display: none;">
<ul>
<li class="headers">
<h4 id="name" class="sort name-col">Name</h4>
<h4 id="continent" class="sort cont-col">Continent</h4>
<h4 id="category" class="sort cat-col">Category</h4>
<h4 id="weeks" class="sort weeks-col">Duration</h4>
<h4 id="cost" class="sort cost-col">Cost</h4>
</li>
</ul>
</section>
</main>
<footer>

</footer>
<script src="app.bundle.js" type="text/javascript"></script>
</footer>

<script id="trip-template" type="text/template">
<li id="<%- id %>" class="trip-row" data-foo="bar">
<h6 class="name-col">
<%- name %>
</h6>
<h6 class="cont-col">
<%- continent %>
</h6>
<h6 class="cat-col">
<%- category %>
</h6>
<h6 class="weeks-col">
<%- weeks %> weeks
</h6>
<h6 class="cost-col">
$<%- cost.toFixed(2) %>
</h6>
</li>
</script>

<script id="empty-trip-template" type="text/template">
<li class="trip-row">
<h6 class="empty-col">
No trips match that criteria.
</h6>
</li>
</script>

<script id="trip-detail-template" type="text/template">
<div class="trip-detail-holder">
<p class="trip-details">
<%- about %>
</p>
<div class="reserve-holder">
<a id="reserve-btn" class="button reserve-btn">Reserve Your Spot!</a>
</div>
</div>
</script>

<script id="reserve-modal-template" type="text/template">
<section id="reserve-modal" class="reserve modal">
<div class="modal-shadow modal-close" id="modal-shadow">
<div class="modal-body small-11 medium-7 large-4 columns">
<a class="modal-close close-btn">X</a>
<h2>Make a Reservation</h2>
<form id="reservation-form" data-id="<%- id %>">
<span id="form-messages"></span>
<div id="reservation-name" class="reservation-form-holder small-12 columns">
<label for="name">Name:</label>
<input type="text" name="name" />
</div>
<div id="reservation-email" class="reservation-form-holder small-12 columns">
<label for="name">Email:</label>
<input type="text" name="email" />
</div>
<div class="reservation-form-holder small-12 columns">
<input type="submit" class="button" />
</div>
</form>
</div>
</div>
</section>
</script>

<script id="add-trip-modal-template" type="text/template">
<section id="add-trip-modal" class="add-trip-modal modal">
<div class="modal-shadow modal-close" id="modal-shadow">
<div class="modal-body small-11 medium-7 large-4 columns">
<a class="modal-close close-btn">X</a>
<h2>Create A Trip</h2>
<form id="add-trip-form">
<span id="form-messages"></span>
<div id="trip-name" class="add-trip-form-holder small-12 columns">
<label for="name">Name:</label>
<input type="text" name="name" />
</div>
<div id="trip-continent" class="add-trip-form-holder small-12 columns">
<label for="continent">Continent:</label>
<input type="text" name="continent" />
</div>
<div id="trip-category" class="add-trip-form-holder small-12 columns">
<label for="category">Category:</label>
<input type="text" name="category" />
</div>
<div id="trip-weeks" class="add-trip-form-holder small-12 columns">
<label for="weeks">Duration (week):</label>
<input type="text" name="weeks" />
</div>
<div id="trip-cost" class="add-trip-form-holder small-12 columns">
<label for="cost">Cost:</label>
<input type="text" name="cost" />
</div>
<div id="trip-about" class="add-trip-form-holder small-12 columns">
<label for="about">Description:</label>
<textarea name="about" />
</div>
<div class="add-trip-form-holder small-12 columns">
<input type="submit" class="button" />
</div>
</form>
</div>
</div>
</section>
</script>

<script src="app.bundle.js" type="text/javascript"></script>
</body>
</html>
204 changes: 202 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,208 @@ import _ from 'underscore';
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';

let tripTemplate;
let emptyTripTemplate;
let tripDetailTemplate;
let reserveModalTemplate;
let addTripModalTemplate;

// Trip List

const tripList = new TripList();

const render = function render(tripList) {
$('.trip-row').remove();
const tripListElement = $('#trip-list ul');
if (tripList.length > 0) {
tripList.forEach((trip) => {
const generatedHTML = $(tripTemplate(trip.attributes));
tripListElement.append(generatedHTML);
});
} else {
const generatedHTML = $(emptyTripTemplate());
tripListElement.append(generatedHTML);
}
};

const show = function show(e) {
// don't minimize trip details when the reserve button is clicked
if ($(e.target).is('#reserve-btn')) return;
const id = parseInt(findElementTripID(e));
const tripElement = $(`#${id}`);
if (tripElement.hasClass('show')) {
clearShow();
} else {
const trip = tripList.findWhere({id: id});
trip.fetch({
success: () => {
clearShow();
$('.trip-row').removeClass('show');
$('.trip-details').remove();
const generatedHTML = $(tripDetailTemplate(trip.attributes));
const reserveBtn = ('#reserve-btn');
tripElement.append(generatedHTML).addClass('show');
}
});
}
};

const clearShow = function clearShow() {
$('.trip-row').removeClass('show');
$('.trip-detail-holder').remove();
};

const sort = function sort(e) {
$('.current-sort').removeClass('current-sort');
let targetElement = $(e.target);
let field = targetElement[0].id;
tripList.comparator = field;
targetElement.addClass('current-sort');
tripList.sort();

Choose a reason for hiding this comment

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

It's better stylistically to have render listening for a sort event.

So adding tripList.on('sort', render);

render(tripList);
};

// Filtering

const filter = function filter(e) {
e.preventDefault();
const form = $('#trip-search');
const searchData = getFormData(form, ['search-type', 'query']);
const newList = tripList.filterBy(searchData['search-type'], searchData['query']);
render(newList);
};

// Modals

const addTripModal = function addTripModal() {
$('body').append(addTripModalTemplate());
};

const reserveModal = function reserveModal(e) {
const id = findElementTripID(e);
const generatedHTML = $(reserveModalTemplate({'id': id}));
const form = $('#reservation-form');
// form.on('submit', submitReservation);
$('body').append(generatedHTML);
};

const clearModal = function clearModal(e) {
if ($(e.target).hasClass('modal-close')) {
$('.modal').remove();
}
};

// Forms

const submitTrip = function submitTrip(e) {
e.preventDefault();
clearErrors();
const form = $(e.target);
const formData = getFormData(form, ['name', 'continent', 'category', 'weeks', 'cost', 'about']);
const newTrip = new Trip(formData);
saveIfValid(newTrip, form, 'trip');
};

const submitReservation = function submitReservation(e) {
e.preventDefault();
clearErrors();
$('.form-messages').html('');
const form = $('#reservation-form');
const id = form.data('id');
const formData = getFormData(form, ['name', 'email']);
formData['tripID'] = id;
const newReservation = new Reservation(formData);
saveIfValid(newReservation, form, 'reservation');
};

const getFormData = function getFormData(target, values) {
const formData = {};
values.forEach((value) => {
let targetElement = target.find(`[name="${ value }"]`);
formData[value] = targetElement.val();
});
return formData;
};

const saveIfValid = function saveIfValid(object, form, type) {
if (object.isValid()) {
object.save({}, {
success: (response) => {
formSuccess(type, form)

Choose a reason for hiding this comment

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

Note, for trips, this won't allow a newly created trip to show up in a displayed list. The user would have to refresh the browser to see it.

On a successful trip save, you should execute a tripList.fetch();. That would trigger render because it's listening for an update event.

I do however really like how you abstracted out the saveIfValid function so it works for all your models. Nice!

},
error: (status, response) => {
const errors = ($.parseJSON(response.responseText))['errors'];
printErrors(errors, type);
},
});
} else {
printErrors(object.validationError, type);
}
};

const formSuccess = function formSuccess(item, form) {
const messageBox = $('#form-messages');
messageBox.html(`<p class="success">Successfully created ${item}!</p>`);
form[0].reset();
}

const printErrors = function printErrors(errors, type) {
for(let field in errors) {
let errorElementID = `#${type}-${field} label`
let errorElement = $(errorElementID);
errorElement.addClass('has-errors');
errorElement.append(`<p class="error">${errors[field]}</p>`);
}
};

const clearErrors = function clearErrors() {
$('.has-errors').removeClass('has-errors');
$('.error').remove();
};

const findElementTripID = function findElementTripID(e) {
return $(e.target).closest('li.trip-row').attr('id');
};

$(document).ready( () => {
$('main').html('<h1>Hello World!</h1>');
$('.on-load').hide();
tripTemplate = _.template($('#trip-template').html());
emptyTripTemplate = _.template($('#empty-trip-template').html());
tripDetailTemplate = _.template($('#trip-detail-template').html());
reserveModalTemplate = _.template($('#reserve-modal-template').html());
addTripModalTemplate = _.template($('#add-trip-modal-template').html());

tripList.on('update', render);

$('#intro-button').on('click', (e) => {
$('#intro-button').hide(200);
$('#loading').show(500);
tripList.fetch({

Choose a reason for hiding this comment

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

You should also have an error callback, just in case the API is down to alert the user.

success: () => {
$('#loading').hide(200);
$('#trip-list').show(500);
},
});
$('.on-load').show(500);
});

$('#trip-list').on('click', 'li', show);

$('.sort').on('click', sort);

$('#add-trip').on('click', addTripModal);
$('body').on('click', '.modal-close', clearModal);

$('body').on('keyup', '#trip-search', filter);
$('#trip-search').on('submit', e => e.preventDefault());

$('#trip-list').on('click', '#reserve-btn', reserveModal);
$(document).on('submit', '#reservation-form', submitReservation);
$(document).on('submit', '#add-trip-form', submitTrip);

});
Loading