diff --git a/src/app/modules/shows/services/show-song-data.service.ts b/src/app/modules/shows/services/show-song-data.service.ts index cd6c500..f262227 100644 --- a/src/app/modules/shows/services/show-song-data.service.ts +++ b/src/app/modules/shows/services/show-song-data.service.ts @@ -13,8 +13,9 @@ export class ShowSongDataService { constructor(private dbService: DbService) { } - public list$ = (showId: string): Observable => this.dbService.col$(`${this.collection}/${showId}/${this.subCollection}`); + public list$ = (showId: string, queryFn?): Observable => this.dbService.col$(`${this.collection}/${showId}/${this.subCollection}`, queryFn); public read$ = (showId: string, songId: string): Observable => this.dbService.doc$(`${this.collection}/${showId}/${this.subCollection}/${songId}`); - public update = async (showId: string, songId: string, data: Partial): Promise => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).update(data); + public update$ = async (showId: string, songId: string, data: Partial): Promise => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).update(data); + public delete = async (showId: string, songId: string): Promise => await this.dbService.doc(`${this.collection}/${showId}/${this.subCollection}/${songId}`).delete(); public add = async (showId: string, data: Partial): Promise => (await this.dbService.col(`${this.collection}/${showId}/${this.subCollection}`).add(data)).id } diff --git a/src/app/modules/shows/services/show-song.service.ts b/src/app/modules/shows/services/show-song.service.ts index 2f50a5c..ed3091d 100644 --- a/src/app/modules/shows/services/show-song.service.ts +++ b/src/app/modules/shows/services/show-song.service.ts @@ -1,5 +1,7 @@ import {Injectable} from '@angular/core'; import {ShowSongDataService} from './show-song-data.service'; +import {Observable} from 'rxjs'; +import {ShowSong} from './showSong'; @Injectable({ providedIn: 'root' @@ -9,8 +11,12 @@ export class ShowSongService { constructor(private showSongDataService: ShowSongDataService) { } - public async new$(showId: string, songId: string): Promise { - const data = {songId}; + public async new$(showId: string, songId: string, order: number): Promise { + const data = {songId, order}; return await this.showSongDataService.add(showId, data); } + + public list$ = (showId: string): Observable => this.showSongDataService.list$(showId, _ => _.orderBy('order')); + public delete$ = (showId: string, songId: string): Promise => this.showSongDataService.delete(showId, songId); + public update$ = async (showId: string, songId: string, data: Partial): Promise => await this.showSongDataService.update$(showId, songId, data); } diff --git a/src/app/modules/shows/services/showSong.ts b/src/app/modules/shows/services/showSong.ts index 5706238..a75dd3c 100644 --- a/src/app/modules/shows/services/showSong.ts +++ b/src/app/modules/shows/services/showSong.ts @@ -1,4 +1,5 @@ export interface ShowSong { id: string; songId: string; + order: number; } diff --git a/src/app/modules/shows/show/show.component.html b/src/app/modules/shows/show/show.component.html index 7c67808..6a6943c 100644 --- a/src/app/modules/shows/show/show.component.html +++ b/src/app/modules/shows/show/show.component.html @@ -2,8 +2,17 @@ -
- +
+ +
+ +
+ Lied hinzufügen... {{song.title}} diff --git a/src/app/modules/shows/show/show.component.ts b/src/app/modules/shows/show/show.component.ts index e4dad23..436c247 100644 --- a/src/app/modules/shows/show/show.component.ts +++ b/src/app/modules/shows/show/show.component.ts @@ -1,5 +1,5 @@ import {Component, OnInit} from '@angular/core'; -import {map, switchMap, tap} from 'rxjs/operators'; +import {filter, map, switchMap, tap} from 'rxjs/operators'; import {ActivatedRoute} from '@angular/router'; import {ShowService} from '../services/show.service'; import {Observable} from 'rxjs'; @@ -8,6 +8,7 @@ import {SongService} from '../../songs/services/song.service'; import {Song} from '../../songs/services/song'; import {MatSelectChange} from '@angular/material/select'; import {ShowSongService} from '../services/show-song.service'; +import {ShowSong} from '../services/showSong'; @Component({ selector: 'app-show', @@ -16,8 +17,9 @@ import {ShowSongService} from '../services/show-song.service'; }) export class ShowComponent implements OnInit { public show$: Observable; - public songs$: Observable; - private showId: string; + public songs: Song[]; + public showSongs: ShowSong[]; + public showId: string; constructor( private activatedRoute: ActivatedRoute, @@ -33,23 +35,38 @@ export class ShowComponent implements OnInit { tap(_ => this.showId = _), switchMap(showId => this.showService.read$(showId)) ); - this.songs$ = this.songService.list$().pipe(map(_ => _ - .filter(_ => !!_.title) - .filter(_ => _.title !== 'nicht gefunden') - .filter(_ => _.title !== 'nicht vorhanden') - .sort((a, b) => { - if (a.title < b.title) { - return -1; - } - if (a.title > b.title) { - return 1; - } - return 0; - }))); + this.activatedRoute.params.pipe( + map(param => param.showId), + switchMap(showId => this.showSongService.list$(showId)), + filter(_ => !!_) + ).subscribe(_ => this.showSongs = _); + this.songService.list$().pipe( + map(_ => _ + .filter(_ => !!_) + .filter(_ => !!_.title) + .filter(_ => _.title !== 'nicht gefunden') + .filter(_ => _.title !== 'nicht vorhanden') + .sort((a, b) => { + if (a.title < b.title) { + return -1; + } + if (a.title > b.title) { + return 1; + } + return 0; + })), + filter(_ => !!_) + ).subscribe(_ => this.songs = _); } public async onAddSongSelectionChanged(event: MatSelectChange) { - await this.showSongService.new$(this.showId, event.value); + await this.showSongService.new$(this.showId, event.value, this.showSongs.reduce((oa, u) => Math.max(oa, u.order), 0) + 1); event.source.value = null; } + + public getSong(songs: Song[], songId: string): Song { + if (!songs) return null; + const filtered = songs.filter(_ => _.id === songId); + return filtered.length > 0 ? filtered[0] : null; + } } diff --git a/src/app/modules/shows/show/song/song.component.html b/src/app/modules/shows/show/song/song.component.html new file mode 100644 index 0000000..30e06d3 --- /dev/null +++ b/src/app/modules/shows/show/song/song.component.html @@ -0,0 +1,10 @@ +
+

+ + + {{song.title}}

+ +
diff --git a/src/app/modules/shows/show/song/song.component.less b/src/app/modules/shows/show/song/song.component.less new file mode 100644 index 0000000..a5149d7 --- /dev/null +++ b/src/app/modules/shows/show/song/song.component.less @@ -0,0 +1,15 @@ +.song { + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + justify-content: space-between; +} + +.menu { + display: flex; + +} + +button { + +} diff --git a/src/app/modules/shows/show/song/song.component.spec.ts b/src/app/modules/shows/show/song/song.component.spec.ts new file mode 100644 index 0000000..94c21a8 --- /dev/null +++ b/src/app/modules/shows/show/song/song.component.spec.ts @@ -0,0 +1,25 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {SongComponent} from './song.component'; + +describe('SongComponent', () => { + let component: SongComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [SongComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SongComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/shows/show/song/song.component.ts b/src/app/modules/shows/show/song/song.component.ts new file mode 100644 index 0000000..5e7c79a --- /dev/null +++ b/src/app/modules/shows/show/song/song.component.ts @@ -0,0 +1,60 @@ +import {Component, Input} from '@angular/core'; +import {Song} from '../../../songs/services/song'; +import {faTrash} from '@fortawesome/free-solid-svg-icons/faTrash'; +import {faCaretUp} from '@fortawesome/free-solid-svg-icons/faCaretUp'; +import {faCaretDown} from '@fortawesome/free-solid-svg-icons/faCaretDown'; +import {ShowSongService} from '../../services/show-song.service'; +import {ShowSong} from '../../services/showSong'; + +@Component({ + selector: 'app-song', + templateUrl: './song.component.html', + styleUrls: ['./song.component.less'] +}) +export class SongComponent { + @Input() public song: Song; + @Input() public showId: string; + @Input() public showSongId: string; + @Input() public showSongs: ShowSong[]; + public faDelete = faTrash; + public faUp = faCaretUp; + public faDown = faCaretDown; + + constructor( + private showSongService: ShowSongService, + ) { + } + + public async onDelete(): Promise { + await this.showSongService.delete$(this.showId, this.showSongId); + } + + + public async reorder(up: boolean): Promise { + if (up) await this.reorderUp(); else await this.reorderDown(); + } + + public async reorderUp(): Promise { + const index = this.showSongs.findIndex(_ => _.songId === this.song.id); + if (index === 0) return; + + const song = this.showSongs[index]; + const toggleSong = this.showSongs[index - 1]; + + await this.showSongService.update$(this.showId, song.id, {order: toggleSong.order}); + await this.showSongService.update$(this.showId, toggleSong.id, {order: song.order}); + } + + public async reorderDown(): Promise { + const index = this.showSongs.findIndex(_ => _.songId === this.song.id); + if (index === this.showSongs.length - 1) return; + + const song = this.showSongs[index]; + const toggleSong = this.showSongs[index + 1]; + + await this.showSongService.update$(this.showId, song.id, {order: toggleSong.order}); + await this.showSongService.update$(this.showId, toggleSong.id, {order: song.order}); + } + + +} diff --git a/src/app/modules/shows/shows.module.ts b/src/app/modules/shows/shows.module.ts index e852c28..2e3f990 100644 --- a/src/app/modules/shows/shows.module.ts +++ b/src/app/modules/shows/shows.module.ts @@ -18,10 +18,13 @@ import {MatSelectModule} from '@angular/material/select'; import {ShowTypeTranslaterModule} from '../../widget-modules/pipes/show-type-translater/show-type-translater.module'; import {MatNativeDateModule} from '@angular/material/core'; import {ShowComponent} from './show/show.component'; +import {SongComponent} from './show/song/song.component'; +import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; +import {MenuButtonModule} from '../../widget-modules/components/menu-button/menu-button.module'; @NgModule({ - declarations: [NewComponent, ListComponent, ListItemComponent, ShowComponent], + declarations: [NewComponent, ListComponent, ListItemComponent, ShowComponent, SongComponent], imports: [ CommonModule, ShowsRoutingModule, @@ -36,7 +39,9 @@ import {ShowComponent} from './show/show.component'; MatDatepickerModule, MatNativeDateModule, MatSelectModule, - ShowTypeTranslaterModule + ShowTypeTranslaterModule, + FontAwesomeModule, + MenuButtonModule ] }) export class ShowsModule { diff --git a/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.less b/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.less index 61f57fd..b62c2f0 100644 --- a/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.less +++ b/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.less @@ -6,11 +6,14 @@ input { border: none; border-bottom: 1px solid #ccc; color: #888; - margin-right: 20px; &:focus { outline: none; border-bottom: 2px solid @primary-color; margin-bottom: -1px; } + + @media screen and (max-width: 500px) { + width: 100px; + } } diff --git a/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.ts b/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.ts index 5b1c61c..5adae26 100644 --- a/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.ts +++ b/src/app/widget-modules/components/application-frame/navigation/filter/filter.component.ts @@ -11,11 +11,11 @@ export class FilterComponent { constructor(private router: Router) { } - public onInputChange(text: string): void { + public async onInputChange(text: string): Promise { const route = text ? this.router.createUrlTree(['songs'], {queryParams: {q: text}}) : this.router.createUrlTree(['songs']); - this.router.navigateByUrl(route); + await this.router.navigateByUrl(route); } } diff --git a/src/app/widget-modules/components/application-frame/navigation/navigation.component.less b/src/app/widget-modules/components/application-frame/navigation/navigation.component.less index 6bbba0b..e8e0fae 100644 --- a/src/app/widget-modules/components/application-frame/navigation/navigation.component.less +++ b/src/app/widget-modules/components/application-frame/navigation/navigation.component.less @@ -24,6 +24,7 @@ nav { display: flex; height: 100%; align-items: center; + padding-right: 20px; } diff --git a/src/app/widget-modules/components/card/card.component.less b/src/app/widget-modules/components/card/card.component.less index 4a6c462..9da63c9 100644 --- a/src/app/widget-modules/components/card/card.component.less +++ b/src/app/widget-modules/components/card/card.component.less @@ -11,6 +11,7 @@ width: 100vw; border-radius: 0px; background: #fffa; + margin: 0; } &.padding { diff --git a/src/app/widget-modules/components/list-header/list-header.component.less b/src/app/widget-modules/components/list-header/list-header.component.less index 326d349..1cfcd70 100644 --- a/src/app/widget-modules/components/list-header/list-header.component.less +++ b/src/app/widget-modules/components/list-header/list-header.component.less @@ -2,7 +2,11 @@ .header { position: relative; height: 34px; + margin: 20px 20px -20px 20px; + @media screen and (max-width: 860px) { + margin: 0; + } display: flex; align-items: center; justify-content: flex-end; diff --git a/src/app/widget-modules/components/menu-button/menu-button.component.html b/src/app/widget-modules/components/menu-button/menu-button.component.html new file mode 100644 index 0000000..f3034f2 --- /dev/null +++ b/src/app/widget-modules/components/menu-button/menu-button.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/widget-modules/components/menu-button/menu-button.component.less b/src/app/widget-modules/components/menu-button/menu-button.component.less new file mode 100644 index 0000000..9473595 --- /dev/null +++ b/src/app/widget-modules/components/menu-button/menu-button.component.less @@ -0,0 +1,7 @@ +button { + min-width: 0; + padding: 0 5px; + @media screen and (max-width: 860px) { + padding: 0 15px; + } +} diff --git a/src/app/widget-modules/components/menu-button/menu-button.component.spec.ts b/src/app/widget-modules/components/menu-button/menu-button.component.spec.ts new file mode 100644 index 0000000..02edd5e --- /dev/null +++ b/src/app/widget-modules/components/menu-button/menu-button.component.spec.ts @@ -0,0 +1,25 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {MenuButtonComponent} from './menu-button.component'; + +describe('MenuButtonComponent', () => { + let component: MenuButtonComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [MenuButtonComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MenuButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/widget-modules/components/menu-button/menu-button.component.ts b/src/app/widget-modules/components/menu-button/menu-button.component.ts new file mode 100644 index 0000000..8e46495 --- /dev/null +++ b/src/app/widget-modules/components/menu-button/menu-button.component.ts @@ -0,0 +1,11 @@ +import {Component, Input} from '@angular/core'; +import {IconProp} from '@fortawesome/fontawesome-svg-core'; + +@Component({ + selector: 'app-menu-button', + templateUrl: './menu-button.component.html', + styleUrls: ['./menu-button.component.less'] +}) +export class MenuButtonComponent { + @Input() public icon: IconProp; +} diff --git a/src/app/widget-modules/components/menu-button/menu-button.module.ts b/src/app/widget-modules/components/menu-button/menu-button.module.ts new file mode 100644 index 0000000..f69e3e3 --- /dev/null +++ b/src/app/widget-modules/components/menu-button/menu-button.module.ts @@ -0,0 +1,20 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {MenuButtonComponent} from './menu-button.component'; +import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; +import {MatButtonModule} from '@angular/material/button'; + + +@NgModule({ + declarations: [MenuButtonComponent], + exports: [ + MenuButtonComponent + ], + imports: [ + CommonModule, + FontAwesomeModule, + MatButtonModule + ] +}) +export class MenuButtonModule { +} diff --git a/src/styles/styles.less b/src/styles/styles.less index fb6a0f9..d2471f0 100644 --- a/src/styles/styles.less +++ b/src/styles/styles.less @@ -37,9 +37,6 @@ h1, h2, h3, h4 { .content > *:not(router-outlet) { margin-top: 60px; - @media screen and (max-width: 860px) { - margin-top: 40px; - } display: flex; justify-content: center; }