diff --git a/dist/index.html b/dist/index.html index 559b18ecd..7d40f8fda 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1,15 +1,135 @@ -
- -Hello World!
'); + let bus = {}; + bus = _.extend(bus, Backbone.Events); + + movieTemplate = _.template($('#movie-template').html()); + searchTemplate = _.template($('#search-template').html()); + + // orderTemplate = _.template($('#order-template').html()); + + + const movies = new MovieList(); + const searches = new SearchList({ + // query: "", + }); + + + const movieListView = new MovieListView({ + el: '#movie-list', + model: movies, + template: movieTemplate, + bus: bus, + }); + + const searchListView = new SearchListView({ + el: '#movie-search', + model: searches, + template: searchTemplate, + bus: bus, + }); + + + const modalOpener= function modalOpener() { + // console.log(event) + console.log('opening modal') + $('.modal').removeClass('hide'); + $('#close').on('click', modalCloser) + } + + const modalCloser= function modalCloser() { + // console.log(event) + console.log('closing modal') + $('.modal').addClass('hide'); + $('.modal').addClass('hide'); + } + + $('#modalBtn').on('click', modalOpener); + + // const movieList = new MovieList() + // + // TABLE_HEADERS.forEach((field) => { + // const headerElement = $(`th.sort.${ field }`); + // headerElement.on('click', (event) => { + // console.log(`Sorting table by ${ field }`); + // movieList.comparator = field; + // movieList.sort(); + // }); + // }); + + // TODO: check fetch and rerendering + movies.fetch(); + // movieListView.render(); + + // $('#main-content').append('Hello World!
'); }); diff --git a/src/collections/movie_list.js b/src/collections/movie_list.js new file mode 100644 index 000000000..951446602 --- /dev/null +++ b/src/collections/movie_list.js @@ -0,0 +1,21 @@ +import Backbone from 'backbone'; + +import Movie from '../models/movie'; + +const MovieList = Backbone.Collection.extend({ + model: Movie, + url: 'http://localhost:3000/movies', + comparator: 'title', + + validate(attributes) { + }, + + myWhere : function( key, val ){ + return this.filter( function( item ){ + return item.get( key ).toLowerCase() === val.toLowerCase(); + }); + }, +}); + + +export default MovieList; diff --git a/src/collections/search_list.js b/src/collections/search_list.js new file mode 100644 index 000000000..3d814f86a --- /dev/null +++ b/src/collections/search_list.js @@ -0,0 +1,34 @@ +import Backbone from 'backbone'; + +import Search from '../models/search'; + +const SearchList = Backbone.Collection.extend({ + model: Search, + url: 'http://localhost:3000/movies?query=', + comparator: 'title', + addTitle(title) { + return this.url += title + }, + resetUrl() { + this.url = 'http://localhost:3000/movies?query='; + }, + // if (this.get('query')) { + // `http://localhost:3000/movies?query=${this.get('query')}` + // else { + // 'http://localhost:3000/movies?query=' + // } + // }, + + // }') `http://localhost:3000/movies?query=${this.get('query')}`, + // // url: 'http://localhost:3000/movies', + // // urlR: function() { + // // return `http://localhost:3000/movies?query=${this.get('query')}` + // // }, + + validate(attributes) { + }, + +}); + + +export default SearchList; diff --git a/src/css/styles.css b/src/css/styles.css index 68a79a569..c588248dc 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -22,6 +22,33 @@ button.success { display: inline; } +button.black{ + background-color: black; +} + +label{ + font-size: 1.5em; +} + +.small{ + font-size: .75em; +} +img { + align-items: center; +} + +h4, p { + text-align: center; +} +td { + max-width: 200px; + +} + +button.black:hover { + background-color: grey; +} + aside.create-tasklist { background-color: navy; color: #FFFFFF; @@ -37,6 +64,51 @@ aside label { div { display: inline; } + +.red{ + color: red; +} +.white { + background-color: white +} +.green{ + color: green; +} + +#close { +margin-top: 10px; +background-color: black; +font-size: 2em +} + +#close.black:hover { + background-color: grey; +} + + +.modal { + position: fixed; + z-index: 100; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.4); + } + +.modal-content { + background-color: white; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +}; + +/*button { + background-color: black; + font-size: 2em; +}*/ /* * { border-style: solid; diff --git a/src/models/movie.js b/src/models/movie.js new file mode 100644 index 000000000..9d26ee6da --- /dev/null +++ b/src/models/movie.js @@ -0,0 +1,30 @@ +import Backbone from 'backbone'; + +const Movie = Backbone.Model.extend({ + // urlRoot: function() { + // return `http://localhost:3000/movies?query=${this.get('query')}` + // }, + + validate(attributes) { + const errors = {}; + + if (!attributes.title) { + errors['title'] = ["Movie Title is required"]; + console.log(errors) + } + if (!attributes.release_date) { + errors['release date'] = ["Movie release date is required"]; + console.log(errors) + } + if ( Object.keys(errors).length > 0 ) { + return errors; + } else { + return false; + } + }, + + +}); + + +export default Movie; diff --git a/src/models/search.js b/src/models/search.js new file mode 100644 index 000000000..83c530545 --- /dev/null +++ b/src/models/search.js @@ -0,0 +1,30 @@ +import Backbone from 'backbone'; + +const Search = Backbone.Model.extend({ + // urlRoot: function() { + // return `http://localhost:3000/movies?query=${this.get('query')}` + // }, + + validate(attributes) { + const errors = {}; + + if (!attributes.title) { + errors['title'] = ["Movie Title is required"]; + console.log(errors) + } + if (!attributes.release_date) { + errors['release date'] = ["Movie release date is required"]; + console.log(errors) + } + + if ( Object.keys(errors).length > 0 ) { + return errors; + } else { + return false; + } + }, + +}); + + +export default Search; diff --git a/src/views/movie_list_view.js b/src/views/movie_list_view.js new file mode 100644 index 000000000..d6121f599 --- /dev/null +++ b/src/views/movie_list_view.js @@ -0,0 +1,111 @@ +import Backbone from 'backbone'; +import MovieView from '../views/movie_view' + +import Movie from '../models/movie'; + +const MovieListView = Backbone.View.extend({ + initialize(params) { + this.template = params.template; + this.bus = params.bus; + this.listenTo(this.model, 'update', this.render); + this.listenTo(this.bus, 'addMovieDB', this.addMovieDB) + }, + render(searchResults) { + this.$('#movie-list').empty(); + if (searchResults) { + searchResults.forEach((movie) => { + console.log('in Movie List View render'); + const movieView = new MovieView({ + model: movie, + template: this.template, + tagName: 'tr', + className: 'movie', + bus: this.bus, + }); + this.$('#movie-list').append(movieView.render().$el); + }); + } else { + this.model.sort(); + this.model.each((movie) => { + console.log('in Movie List View render'); + const movieView = new MovieView({ + model: movie, + template: this.template, + tagName: 'tr', + className: 'movie', + bus: this.bus, + }); + this.$('#movie-list').append(movieView.render().$el); + }); + // } + return this; + } + }, + + events: { + 'click button.btn-search': 'searchMovies', + 'click button.btn-showAll': 'render', + }, + + addMovieDB(movie_hash){ + const newMovie = new Movie(movie_hash) + this.model.add(newMovie); + + if (!newMovie.isValid()) { + // handleValidationFailuresTrip(trip.validationError); + return; + } + this.clearMessages('#movie-success-messages'); + this.clearMessages('#movie-fail-messages'); + + newMovie.save({}, { + success: (model, response) => { + console.log(this.model.attributes) + console.log(`Successfully added new movie: ${newMovie.get('title')}`); + let successMessage = `Successfully added new movie: ${newMovie.get('title')}`; + this.$('#movie-success-messages').append(successMessage); + this.$('#movie-success-messages').show(); + }, + error: (model, response) => { + console.log('Failed to save movie! Server response:'); + console.log(response); + this.model.remove(model); + }, + }); + }, + + clearMessages(tag){ + this.$(tag).html(''); + }, + + getFormData() { + console.log("I am reading the movie rental form") + const title = this.$('.movie-search-form input[name=title]').val(); + this.$('.movie-search-form input[name=title]').val('') + return title; + }, + + searchMovies() { + event.preventDefault(); + const query = this.getFormData() + const searchResults = this.model.myWhere('title', query); + console.log(searchResults.length == 0); + this.clearMessages('#movie-fail-messages') + this.clearMessages('#movie-success-messages'); + if (searchResults.length == 0){ + this.render() + // this.$('#movie-fail-messages').html(''); + if (query == ""){ + let failMessage = 'Search requires an inputed title' + this.$('#movie-fail-messages').append(failMessage); + }else { + let failMessage = `No movies found for title "${query}"`; + this.$('#movie-fail-messages').append(failMessage); + } + } else { + this.render(searchResults); + } + }, +}); + +export default MovieListView; diff --git a/src/views/movie_view.js b/src/views/movie_view.js new file mode 100644 index 000000000..d6a0ce92f --- /dev/null +++ b/src/views/movie_view.js @@ -0,0 +1,33 @@ +import Backbone from 'backbone'; +import Movie from '../models/movie'; + +const MovieView = Backbone.View.extend({ + + initialize(params) { + this.template = params.template; + // this.bus = params.bus; + this.listenTo(this.model, 'change', this.render); + }, + events: { + }, + + render() { + const compiledTemplate = this.template(this.model.toJSON()); + this.$el.html(compiledTemplate); + return this; + }, + + // events: { + // 'click td': 'showModal', + // }, + // + // showModal() { + // console.log(this.model) + // this.$('.modal').removeClass('hide') + // } + + + +}); + +export default MovieView; diff --git a/src/views/search_list_view.js b/src/views/search_list_view.js new file mode 100644 index 000000000..01787ccff --- /dev/null +++ b/src/views/search_list_view.js @@ -0,0 +1,87 @@ +import Backbone from 'backbone'; +import SearchView from '../views/search_view' +import SearchList from '../collections/search_list' + + +import Search from '../models/search'; + +const SearchListView = Backbone.View.extend({ + initialize(params) { + this.template = params.template; + this.listenTo(this.model, 'update', this.render); + this.bus = params.bus + }, + render() { + this.$('#search-list').empty(); + this.model.sort(); + this.model.each((search) => { + console.log('in Search List View render'); + const searchView = new SearchView({ + model: search, + template: this.template, + tagName: 'tr', + className: 'search', + bus: this.bus, + }); + this.$('#search-list').append(searchView.render().$el); + }); + return this; + }, + + events: { + 'click button.btn-search-api': 'searchApi', + }, + + getFormData() { + console.log("I am reading the form") + const formData = {}; + const title = this.$('.movie-entry-form input[name=title]').val(); + this.$('.movie-entry-form input[name=title]').val('') + // formData['title'] = title; + return title; + }, + + + searchApi() { + //this is an ugly way to reset the URL. See if we can fix it + this.clearMessages('#search-error-message'); + event.preventDefault(); + const title = this.getFormData() + if (title === ""){ + console.log('Error: No title') + this.$('#search-error-message').append('Error: No search terms') + return + } else { + // this.model.url += title; + this.model.addTitle(title); + // console.log(this.model.url); + let that = this + this.model.fetch().done(function () { + that.reportNoResults(title); + }); + + + //reset URL + this.model.resetUrl(); + // this.model.url = 'http://localhost:3000/movies?query='; + // console.log(this.model.length) + + //what if no models are returned? report error here? + } + }, + + reportNoResults(title){ + if(this.model.length == 0) { + // this.$('#search-error-message').empty() + this.clearMessages('#search-error-message'); + console.log(`No movies match search term: ${title}`) + this.$('#search-error-message').append(`No movies match search term: ${title}`) + } + }, + clearMessages(tag){ + this.$(tag).empty(); + }, + +}); + +export default SearchListView; diff --git a/src/views/search_view.js b/src/views/search_view.js new file mode 100644 index 000000000..54a785603 --- /dev/null +++ b/src/views/search_view.js @@ -0,0 +1,42 @@ +import Backbone from 'backbone'; +import Search from '../models/search'; + +const SearchView = Backbone.View.extend({ + + initialize(params) { + this.template = params.template; + this.listenTo(this.model, 'change', this.render); + this.bus = params.bus + }, + events: { + }, + + render() { + let search = this.model; + const compiledTemplate = this.template(this.model.toJSON()); + this.$el.html(compiledTemplate); + console.log(this.model.attributes) + + return this; + }, + + events: { + 'click .add': 'addMovie', + }, + + addMovie(){ + console.log('I am in add movie') + console.log(this.model) + let movie_hash = this.model.attributes + console.log(movie_hash) + this.bus.trigger('addMovieDB', movie_hash) + this.$('.add').addClass('hide'); + this.$('.nothing').removeClass('hide'); + } + + + + +}); + +export default SearchView;