diff --git a/music-app/app/adapters/album.js b/music-app/app/adapters/album.js new file mode 100644 index 0000000..a68370b --- /dev/null +++ b/music-app/app/adapters/album.js @@ -0,0 +1,5 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + +}); \ No newline at end of file diff --git a/music-app/app/adapters/application.js b/music-app/app/adapters/application.js new file mode 100644 index 0000000..3128ba5 --- /dev/null +++ b/music-app/app/adapters/application.js @@ -0,0 +1,5 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + +}); \ No newline at end of file diff --git a/music-app/app/components/album-detail/component.js b/music-app/app/components/album-detail/component.js new file mode 100644 index 0000000..8475a5b --- /dev/null +++ b/music-app/app/components/album-detail/component.js @@ -0,0 +1,47 @@ +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; + +export default Component.extend({ + + album: null, + + showForm: false, + + newSong: null, + + genres: null, + + artists: null, + + store: service(), + + init() { + this._super(...arguments); + + this.set('genres', this.store.findAll('genre')); + this.set('artists', this.store.findAll('artist')); + this.set('newSong', { + title: undefined + }); + }, + + actions: { + toggleForm() { + this.toggleProperty('showForm'); + }, + + addSong() { + const selectGenreId = document.getElementById('selectGenre'); + const selectGenre = this.get('genres').findBy('id', selectGenreId.options[selectGenreId.selectedIndex].value); + let song = this.store.createRecord('song', { + title: this.get('newSong.title'), + album: this.get('album'), + genre: selectGenre + }); + + song.save(); + this.set(this.get('newSong.title', undefined)); + this.toggleProperty('showForm'); + } + } +}); diff --git a/music-app/app/components/album-detail/template.hbs b/music-app/app/components/album-detail/template.hbs new file mode 100644 index 0000000..c8a2d53 --- /dev/null +++ b/music-app/app/components/album-detail/template.hbs @@ -0,0 +1,40 @@ +{{#link-to "application"}}Back{{/link-to}} +Songs for {{album.name}} album: +
+ + + + + + + + + + {{#each album.songs as |song|}} + {{song-detail song=song genres=genres}} + {{/each}} + +
TitleGenreArtists
+ +
+ + {{#if showForm}} +
+ Name: {{input value=newSong.title}} +
+ Genre: + +
+ Artists: +
+ {{#each artists as |artist|}} + {{input type="checkbox" checked=foo}} + + {{/each}} +
+ + {{/if}} \ No newline at end of file diff --git a/music-app/app/components/music-list.js b/music-app/app/components/music-list.js deleted file mode 100644 index bb93d73..0000000 --- a/music-app/app/components/music-list.js +++ /dev/null @@ -1,4 +0,0 @@ -import Component from '@ember/component'; - -export default Component.extend({ -}); diff --git a/music-app/app/components/music-list/component.js b/music-app/app/components/music-list/component.js new file mode 100644 index 0000000..d34f9cd --- /dev/null +++ b/music-app/app/components/music-list/component.js @@ -0,0 +1,21 @@ +import Component from '@ember/component'; + +export default Component.extend({ + + albums: null, + + albumsToShow: null, + + textToSearch: '', + + init() { + this._super(...arguments); + this.set('albumsToShow', this.get('albums')); + }, + + actions: { + searchByText(textToSearch) { + this.set('albumsToShow', this.get('albums').filter((album) => album.name.toLowerCase().includes(textToSearch.toLowerCase()))); + } + } +}); diff --git a/music-app/app/components/music-list/template.hbs b/music-app/app/components/music-list/template.hbs new file mode 100644 index 0000000..6739545 --- /dev/null +++ b/music-app/app/components/music-list/template.hbs @@ -0,0 +1,23 @@ +
+
+ + {{input value=textToSearch}} + +
+ +
\ No newline at end of file diff --git a/music-app/app/components/song-detail/component.js b/music-app/app/components/song-detail/component.js new file mode 100644 index 0000000..5b4caa3 --- /dev/null +++ b/music-app/app/components/song-detail/component.js @@ -0,0 +1,59 @@ +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; + +export default Component.extend({ + + tagName: 'tr', + + song: null, + + songToEdit: null, + + showForm: false, + + store: service(), + + artistNames: undefined, + + init() { + this._super(...arguments); + this.set('artistNames', this.getArtistsNames(this.get('song.artists'))); + this.set('songToEdit', { + title: undefined + }); + }, + + getArtistsNames(artists) { + let names = ''; + + if (artists && artists.length) { + artists.forEach((artist) => { + names = `${names}, ${artist.name}`; + }); + names = names.slice(0, -2); + } + + return names; + }, + + actions: { + toggleForm() { + this.toggleProperty('showForm'); + }, + + updateSong() { + const titleToUpdate = this.get('songToEdit.title'); + const selectGenreId = document.getElementById('selectGenre'); + const selectGenre = this.get('genres').findBy('id', selectGenreId.options[selectGenreId.selectedIndex].value); + + this.store.findRecord('song', this.get('song.id')).then(function(songToUpdate) { + songToUpdate.title = titleToUpdate; + songToUpdate.genre = selectGenre; + + songToUpdate.save(); + }); + this.set('songToEdit.title', null); + this.toggleProperty('showForm'); + } + } +}); diff --git a/music-app/app/components/song-detail/template.hbs b/music-app/app/components/song-detail/template.hbs new file mode 100644 index 0000000..19913ef --- /dev/null +++ b/music-app/app/components/song-detail/template.hbs @@ -0,0 +1,20 @@ +{{#if showForm}} + {{input value=songToEdit.title placeholder=song.title}} + + + + //TODO + + + + +{{else}} + {{song.title}} + {{song.genre.name}} + {{artistNames}} + +{{/if}} \ No newline at end of file diff --git a/music-app/app/models/album.js b/music-app/app/models/album.js index 1f71205..6f1526b 100644 --- a/music-app/app/models/album.js +++ b/music-app/app/models/album.js @@ -1,5 +1,10 @@ -import Model from '@ember-data/model'; +import Model, { attr, hasMany } from '@ember-data/model'; export default Model.extend({ + name: attr('string'), + + cover: attr('string'), + + songs: hasMany('song') }); diff --git a/music-app/app/models/artist.js b/music-app/app/models/artist.js index 1f71205..139205b 100644 --- a/music-app/app/models/artist.js +++ b/music-app/app/models/artist.js @@ -1,5 +1,7 @@ -import Model from '@ember-data/model'; +import Model, { attr } from '@ember-data/model'; export default Model.extend({ + name: attr() + }); diff --git a/music-app/app/models/genre.js b/music-app/app/models/genre.js index 1f71205..139205b 100644 --- a/music-app/app/models/genre.js +++ b/music-app/app/models/genre.js @@ -1,5 +1,7 @@ -import Model from '@ember-data/model'; +import Model, { attr } from '@ember-data/model'; export default Model.extend({ + name: attr() + }); diff --git a/music-app/app/models/song.js b/music-app/app/models/song.js index 1f71205..bc59513 100644 --- a/music-app/app/models/song.js +++ b/music-app/app/models/song.js @@ -1,5 +1,12 @@ -import Model from '@ember-data/model'; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; export default Model.extend({ + title: attr(), + + album: belongsTo('album'), + + genre: belongsTo('genre', { inverse: null }), + + artists: hasMany('artist', { inverse: null }) }); diff --git a/music-app/app/router.js b/music-app/app/router.js index 224ca42..0d4ad59 100644 --- a/music-app/app/router.js +++ b/music-app/app/router.js @@ -7,4 +7,5 @@ export default class Router extends EmberRouter { } Router.map(function() { + this.route('albums', { path: '/albums/:id' }); }); diff --git a/music-app/app/routes/albums.js b/music-app/app/routes/albums.js new file mode 100644 index 0000000..e6c52b0 --- /dev/null +++ b/music-app/app/routes/albums.js @@ -0,0 +1,7 @@ +import Route from '@ember/routing/route'; + +export default Route.extend({ + model(transition) { + return this.store.findRecord('album', transition.id); + } +}) \ No newline at end of file diff --git a/music-app/app/routes/application.js b/music-app/app/routes/application.js new file mode 100644 index 0000000..88ffc5b --- /dev/null +++ b/music-app/app/routes/application.js @@ -0,0 +1,7 @@ +import Route from '@ember/routing/route'; + +export default Route.extend({ + model() { + return this.store.findAll('album'); + } +}) \ No newline at end of file diff --git a/music-app/app/serializers/application.js b/music-app/app/serializers/application.js new file mode 100644 index 0000000..5fc2c6c --- /dev/null +++ b/music-app/app/serializers/application.js @@ -0,0 +1,4 @@ +import JSONAPISerializer from '@ember-data/serializer/json-api'; + +export default class ApplicationSerializer extends JSONAPISerializer { +} \ No newline at end of file diff --git a/music-app/app/styles/app.scss b/music-app/app/styles/app.scss index e69de29..e80f7ca 100644 --- a/music-app/app/styles/app.scss +++ b/music-app/app/styles/app.scss @@ -0,0 +1,26 @@ +.music-list-filter { + text-align: center; +} + +.album-list { + display: grid; + margin: auto; + width: 400px; + grid-template-columns: 150px 150px; +} + +.album { + margin: 10px; + background-color: #fff; + box-shadow: 1px 0.5px 5px 1px hsla(0,0%,39.2%,.5); + border: 1px solid #bfc0bf; + list-style-type: none; +} + +.show { + display: block; +} + +.hide { + display: none; +} \ No newline at end of file diff --git a/music-app/app/templates/albums.hbs b/music-app/app/templates/albums.hbs new file mode 100644 index 0000000..87cbbdc --- /dev/null +++ b/music-app/app/templates/albums.hbs @@ -0,0 +1 @@ +{{album-detail album=model}} \ No newline at end of file diff --git a/music-app/app/templates/application.hbs b/music-app/app/templates/application.hbs index 30941c3..b53239e 100644 --- a/music-app/app/templates/application.hbs +++ b/music-app/app/templates/application.hbs @@ -1,3 +1,3 @@ - - +{{music-list albums=model}} +
{{outlet}} \ No newline at end of file diff --git a/music-app/app/templates/components/.gitkeep b/music-app/app/templates/components/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/music-app/app/templates/components/music-list.hbs b/music-app/app/templates/components/music-list.hbs deleted file mode 100644 index 889d9ee..0000000 --- a/music-app/app/templates/components/music-list.hbs +++ /dev/null @@ -1 +0,0 @@ -{{yield}} diff --git a/music-app/mirage/config.js b/music-app/mirage/config.js new file mode 100644 index 0000000..08982c0 --- /dev/null +++ b/music-app/mirage/config.js @@ -0,0 +1,39 @@ +export default function() { + + this.namespace = ''; + + this.get('/albums'); + this.get('/albums/:id'); + this.get('/songs'); + this.get('/songs/:id'); + this.post('/songs'); + this.patch('/songs/:id'); + this.get('/genres'); + this.get('/genres/:id'); + this.get('/artists'); + this.get('/artists/:id'); + + // These comments are here to help you get started. Feel free to delete them. + + /* + Config (with defaults). + + Note: these only affect routes defined *after* them! + */ + + // this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server + // this.namespace = ''; // make this `/api`, for example, if your API is namespaced + // this.timing = 400; // delay for each request, automatically set to 0 during testing + + /* + Shorthand cheatsheet: + + this.get('/posts'); + this.post('/posts'); + this.get('/posts/:id'); + this.put('/posts/:id'); // or this.patch + this.del('/posts/:id'); + + https://www.ember-cli-mirage.com/docs/route-handlers/shorthands + */ +} diff --git a/music-app/mirage/factories/album.js b/music-app/mirage/factories/album.js new file mode 100644 index 0000000..1402ce0 --- /dev/null +++ b/music-app/mirage/factories/album.js @@ -0,0 +1,12 @@ +import { Factory } from 'ember-cli-mirage'; + +export default Factory.extend({ + + name(i) { + return `Album title ${i+1}`; + }, + + afterCreate(album, server) { + album.update({ songs: server.createList('song', Math.floor(Math.random() * 10) + 3) }); + } +}); diff --git a/music-app/mirage/factories/artist.js b/music-app/mirage/factories/artist.js new file mode 100644 index 0000000..2b21be6 --- /dev/null +++ b/music-app/mirage/factories/artist.js @@ -0,0 +1,8 @@ +import { Factory } from 'ember-cli-mirage'; + +export default Factory.extend({ + + name(i) { + return `Artist name ${i+1}`; + } +}); diff --git a/music-app/mirage/factories/genre.js b/music-app/mirage/factories/genre.js new file mode 100644 index 0000000..3c8ece9 --- /dev/null +++ b/music-app/mirage/factories/genre.js @@ -0,0 +1,8 @@ +import { Factory } from 'ember-cli-mirage'; + +export default Factory.extend({ + + name(i) { + return `Genre name ${i+1}`; + } +}); diff --git a/music-app/mirage/factories/song.js b/music-app/mirage/factories/song.js new file mode 100644 index 0000000..b125fc2 --- /dev/null +++ b/music-app/mirage/factories/song.js @@ -0,0 +1,19 @@ +import { Factory } from 'ember-cli-mirage'; + +export default Factory.extend({ + + title(i) { + return `Song title ${i+1}`; + }, + + afterCreate(song, server) { + const genres = server.schema.genres.all(); + const randomGenre = genres.models[Math.floor(Math.random() * genres.length)]; + const artists = server.schema.artists.all(); + const selectedArtists = artists.filter(() => + Math.floor(Math.random() * 2) % 2 === 0 + ); + + song.update({ genre: randomGenre, artists: selectedArtists }); + } +}); diff --git a/music-app/mirage/models/album.js b/music-app/mirage/models/album.js new file mode 100644 index 0000000..54058e9 --- /dev/null +++ b/music-app/mirage/models/album.js @@ -0,0 +1,5 @@ +import { Model, hasMany } from 'ember-cli-mirage'; + +export default Model.extend({ + songs: hasMany('song') +}); diff --git a/music-app/mirage/models/artist.js b/music-app/mirage/models/artist.js new file mode 100644 index 0000000..1486a72 --- /dev/null +++ b/music-app/mirage/models/artist.js @@ -0,0 +1,4 @@ +import { Model } from 'ember-cli-mirage'; + +export default Model.extend({ +}); diff --git a/music-app/mirage/models/genre.js b/music-app/mirage/models/genre.js new file mode 100644 index 0000000..1486a72 --- /dev/null +++ b/music-app/mirage/models/genre.js @@ -0,0 +1,4 @@ +import { Model } from 'ember-cli-mirage'; + +export default Model.extend({ +}); diff --git a/music-app/mirage/models/song.js b/music-app/mirage/models/song.js new file mode 100644 index 0000000..3fa0358 --- /dev/null +++ b/music-app/mirage/models/song.js @@ -0,0 +1,7 @@ +import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; + +export default Model.extend({ + genre: belongsTo(), + + artists: hasMany() +}); diff --git a/music-app/mirage/scenarios/default.js b/music-app/mirage/scenarios/default.js new file mode 100644 index 0000000..7eb0d27 --- /dev/null +++ b/music-app/mirage/scenarios/default.js @@ -0,0 +1,5 @@ +export default function(server) { + server.createList('genre', 7); + server.createList('artist', 15); + server.createList('album', 10); +} diff --git a/music-app/mirage/serializers/application.js b/music-app/mirage/serializers/application.js new file mode 100644 index 0000000..619bf2e --- /dev/null +++ b/music-app/mirage/serializers/application.js @@ -0,0 +1,5 @@ +import { JSONAPISerializer } from 'ember-cli-mirage'; + +export default JSONAPISerializer.extend({ + alwaysIncludeLinkageData: true +}); diff --git a/music-app/package.json b/music-app/package.json index 2491ca3..1eb0113 100644 --- a/music-app/package.json +++ b/music-app/package.json @@ -29,6 +29,7 @@ "ember-cli-eslint": "^5.1.0", "ember-cli-htmlbars": "^4.0.5", "ember-cli-inject-live-reload": "^2.0.1", + "ember-cli-mirage": "^1.1.6", "ember-cli-sass": "^10.0.1", "ember-cli-sri": "^2.1.1", "ember-cli-template-lint": "^1.0.0-beta.3",