From 7f5783bf820ae448cf1dfca97bae6c8b3ec6879b Mon Sep 17 00:00:00 2001 From: Jason Wall Date: Sun, 2 Aug 2020 19:14:59 -0400 Subject: [PATCH] fix loading saved pages and normal pages, add settings to savePage, createNote fixed the router, cleaned up the note dialog so it can handle new/existing, added page edit modal --- app/db/src/app/app-routing.module.ts | 9 +- app/db/src/app/app.component.html | 20 +++- app/db/src/app/app.component.ts | 21 ++++- app/db/src/app/app.module.ts | 3 + app/db/src/app/models/app-state.ts | 2 + .../note-edit-modal.component.html | 9 -- .../note-edit-modal.component.ts | 42 +++++++-- .../page-edit-modal.component.html | 18 ++++ .../page-edit-modal.component.scss | 20 ++++ .../page-edit-modal.component.ts | 38 ++++++++ .../components/search-page/search.page.ts | 59 +++++++++--- app/db/src/app/services/app.service.ts | 94 +++++++++++++++---- app/db/src/app/services/nav.service.ts | 5 +- 13 files changed, 283 insertions(+), 57 deletions(-) create mode 100644 app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.html create mode 100644 app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.scss create mode 100644 app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.ts diff --git a/app/db/src/app/app-routing.module.ts b/app/db/src/app/app-routing.module.ts index 5f65fede..37c91dfb 100644 --- a/app/db/src/app/app-routing.module.ts +++ b/app/db/src/app/app-routing.module.ts @@ -5,25 +5,28 @@ import { SearchPage } from './search/components/search-page/search.page'; const routes: Routes = [ { path: '', - redirectTo: 'search/', pathMatch: 'full', + redirectTo: 'search', }, { - path: 'search/', + path: 'search', + pathMatch: 'prefix', component: SearchPage, }, { path: 'search/:term', + pathMatch: 'prefix', component: SearchPage, }, { path: 'saved/:id', + pathMatch: 'prefix', component: SearchPage, }, ]; @NgModule({ - imports: [RouterModule.forRoot(routes)], + imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })], exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/app/db/src/app/app.component.html b/app/db/src/app/app.component.html index 5d4e1b44..76e54330 100644 --- a/app/db/src/app/app.component.html +++ b/app/db/src/app/app.component.html @@ -13,7 +13,7 @@ {{ p.icon }} {{ p.title }} @@ -23,7 +23,7 @@ playlist_play {{ p.title }} @@ -38,6 +38,22 @@ position="end" [opened]="false" > + Search Settings + + + save Save Results as New + Page + + + + create Create a New Note + + + diff --git a/app/db/src/app/app.component.ts b/app/db/src/app/app.component.ts index b4149675..8de66df7 100644 --- a/app/db/src/app/app.component.ts +++ b/app/db/src/app/app.component.ts @@ -5,13 +5,19 @@ import { Observable } from 'rxjs'; import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout'; import { map, shareReplay } from 'rxjs/operators'; import { MatSidenav } from '@angular/material/sidenav'; +import { MatDialog } from '@angular/material/dialog'; +import { PageEditModalComponent } from './search/components/page-edit-modal/page-edit-modal.component'; +import { NoteEditModalComponent } from './search/components/note-edit-modal/note-edit-modal.component'; +import { SavedPage, Page } from './models/app-state'; +import { Router } from '@angular/router'; +import { SubscriberComponent } from './common/components/subscriber.component'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) -export class AppComponent implements AfterViewInit { +export class AppComponent extends SubscriberComponent implements AfterViewInit { savedPages$ = this.appService.select((state) => state.savedPages); mainPages$ = this.appService.select((state) => state.mainPages); fontSize$ = this.appService.select( @@ -34,8 +40,11 @@ export class AppComponent implements AfterViewInit { constructor( private appService: AppService, private navService: NavService, - private breakpointObserver: BreakpointObserver + private breakpointObserver: BreakpointObserver, + private dialog: MatDialog ) { + super(); + this.appService.initSavedPages(); this.appService.initDisplaySettings(); @@ -50,4 +59,12 @@ export class AppComponent implements AfterViewInit { ngAfterViewInit(): void { this.navService.setSidenav(this.sidenav, this.settings); } + + savePage() { + this.dialog.open(PageEditModalComponent); + } + + createNote() { + this.dialog.open(NoteEditModalComponent); + } } diff --git a/app/db/src/app/app.module.ts b/app/db/src/app/app.module.ts index 0f62bfa3..5aa575e4 100644 --- a/app/db/src/app/app.module.ts +++ b/app/db/src/app/app.module.ts @@ -16,6 +16,7 @@ import { WordsComponent } from './search/components/words/words.component'; import { NoteComponent } from './search/components/note/note.component'; import { SettingsComponent } from './common/components/settings/settings.component'; +import { PageEditModalComponent } from './search/components/page-edit-modal/page-edit-modal.component'; import { NoteEditModalComponent } from './search/components/note-edit-modal/note-edit-modal.component'; import { VersePickerModalComponent } from './search/components/verse-picker/verse-picker-modal.component'; @@ -64,6 +65,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard'; StrongsComponent, WordsComponent, NoteComponent, + PageEditModalComponent, NoteEditModalComponent, VersePickerModalComponent, SettingsComponent, @@ -78,6 +80,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard'; BrowserAnimationsModule, NgxMdModule.forRoot(), + MatSidenavModule, MatToolbarModule, MatIconModule, diff --git a/app/db/src/app/models/app-state.ts b/app/db/src/app/models/app-state.ts index 6f891697..edaafb0e 100644 --- a/app/db/src/app/models/app-state.ts +++ b/app/db/src/app/models/app-state.ts @@ -1,5 +1,7 @@ export interface AppState { + readonly currentPage: SavedPage; readonly savedPages: readonly SavedPage[]; + readonly savedPagesLoaded: boolean; readonly mainPages: readonly Page[]; readonly cards: readonly CardItem[]; readonly autocomplete: readonly string[]; diff --git a/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.html b/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.html index dd9c512c..5c93ea76 100644 --- a/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.html +++ b/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.html @@ -2,15 +2,6 @@ edit
Edit: {{ data.title }}
- - -
diff --git a/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.ts b/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.ts index 50a0844f..c8caeb35 100644 --- a/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.ts +++ b/app/db/src/app/search/components/note-edit-modal/note-edit-modal.component.ts @@ -3,6 +3,7 @@ import { FormGroup, FormBuilder } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { CardItem, NoteItem } from '../../../models/app-state'; import { AppService } from '../../../services/app.service'; +import { UUID } from 'angular2-uuid'; @Component({ selector: 'app-note-edit-modal', @@ -12,6 +13,7 @@ import { AppService } from '../../../services/app.service'; export class NoteEditModalComponent { noteForm: FormGroup; data: NoteItem; + isNew = false; constructor( @Inject(MAT_DIALOG_DATA) public cardItem: CardItem, @@ -19,7 +21,17 @@ export class NoteEditModalComponent { private appService: AppService, private fb: FormBuilder ) { - this.data = cardItem.data as NoteItem; + if (cardItem) { + this.data = cardItem.data as NoteItem; + } else { + this.isNew = true; + this.data = { + id: UUID.UUID(), + title: 'Title Here', + content: '# Content Here\nIn Markdown format.', + xref: '', + }; + } this.noteForm = this.fb.group(this.data); } @@ -28,17 +40,31 @@ export class NoteEditModalComponent { } save() { - this.appService.editNote( - { - ...this.cardItem, + if (this.isNew) { + this.appService.createNote({ + qry: '', + dict: 'n/a', + type: 'Note', data: { - ...this.cardItem.data, + ...this.data, title: this.noteForm.get('title').value, content: this.noteForm.get('content').value, }, - }, - this.cardItem - ); + }); + } else { + this.appService.editNote( + { + ...this.cardItem, + data: { + ...this.cardItem.data, + title: this.noteForm.get('title').value, + content: this.noteForm.get('content').value, + }, + }, + this.cardItem + ); + } + this.dialogRef.close(); } } diff --git a/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.html b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.html new file mode 100644 index 00000000..2b374b7b --- /dev/null +++ b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.html @@ -0,0 +1,18 @@ +
+ + save +
{{ dialogTitle }}
+
+
+ +
+ + Title + + +
+
+
+ + +
diff --git a/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.scss b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.scss new file mode 100644 index 00000000..4250d2f2 --- /dev/null +++ b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.scss @@ -0,0 +1,20 @@ +.close-button { + float: right; + mat-icon { + font-size: 2rem; + } +} + +.title { + width: 100%; + padding-left: 1rem; + font-size: 1.5rem; +} + +.mat-form-field { + display: block; +} + +.page-title { + min-width: 50vw; +} diff --git a/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.ts b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.ts new file mode 100644 index 00000000..bd035761 --- /dev/null +++ b/app/db/src/app/search/components/page-edit-modal/page-edit-modal.component.ts @@ -0,0 +1,38 @@ +import { Component, Inject } from '@angular/core'; +import { FormGroup, FormBuilder } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { AppService } from '../../../services/app.service'; + +@Component({ + selector: 'app-page-edit-modal', + templateUrl: 'page-edit-modal.component.html', + styleUrls: ['./page-edit-modal.component.scss'], +}) +export class PageEditModalComponent { + form: FormGroup; + dialogTitle = 'Save Page using Current Cards'; + + constructor( + @Inject(MAT_DIALOG_DATA) public title: string, + public dialogRef: MatDialogRef, + private appService: AppService, + private fb: FormBuilder + ) { + if (title) { + this.dialogTitle = 'Edit Page Name'; + } + + this.form = this.fb.group({ + title, + }); + } + + cancel() { + this.dialogRef.close(); + } + + save() { + this.appService.savePage(this.form.get('title').value); + this.dialogRef.close(); + } +} diff --git a/app/db/src/app/search/components/search-page/search.page.ts b/app/db/src/app/search/components/search-page/search.page.ts index 8944759c..0806789c 100644 --- a/app/db/src/app/search/components/search-page/search.page.ts +++ b/app/db/src/app/search/components/search-page/search.page.ts @@ -1,5 +1,5 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; import { FormControl } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { AppService } from '../../../services/app.service'; @@ -22,6 +22,9 @@ import { export class SearchPage extends SubscriberComponent implements OnInit { cards$ = this.appService.select((state) => state.cards); suggestions$ = this.appService.select((state) => state.autocomplete); + + savedPagedLoaded = false; + searchControl = new FormControl(); @ViewChild(MatAutocomplete) @@ -32,25 +35,31 @@ export class SearchPage extends SubscriberComponent implements OnInit { constructor( private activatedRoute: ActivatedRoute, private appService: AppService, + private router: Router, public navService: NavService, public dialog: MatDialog ) { super(); + // you need to know when certain things are loaded, so you can then do stuff. + // this will watch the state and store those items in your class so you can monitor them. + this.addSubscription( + this.appService.state$.subscribe((state) => { + this.savedPagedLoaded = state.savedPagesLoaded; + }) + ); } ngOnInit() { - // if a route was passed in, perform a search. - if (this.activatedRoute.snapshot.paramMap.has('term')) { - const term = this.activatedRoute.snapshot.paramMap.get('term'); - this.search(term); - } - - // if a route was passed in, perform a search. - if (this.activatedRoute.snapshot.paramMap.has('id')) { - const id = this.activatedRoute.snapshot.paramMap.get('id'); - this.appService.getSavedPage(id); - } + this.addSubscription( + this.router.events.subscribe((evt) => { + if (evt instanceof NavigationEnd) { + this.init(); + } + console.log(evt); + }) + ); + this.init(); // subscribe to autocomplete input control's changes this.addSubscription( this.searchControl.valueChanges.subscribe((value: string) => @@ -59,6 +68,32 @@ export class SearchPage extends SubscriberComponent implements OnInit { ); } + init() { + if (this.activatedRoute.snapshot.paramMap.has('term')) { + // if a route was passed in, perform a search. + const term = this.activatedRoute.snapshot.paramMap.get('term'); + this.search(term); + } else if (this.activatedRoute.snapshot.paramMap.has('id')) { + // if this is a saved page + const id = this.activatedRoute.snapshot.paramMap.get('id'); + this.onSavedPagedLoaded(id); + this.navService.close(); // close the nav immediately. + } else { + // its a blank search. load nothing. + } + } + + // monitor the saved paged loaded property, and fire the action once it turns true, then stop. + onSavedPagedLoaded(id: string) { + if (this.savedPagedLoaded) { + this.appService.getSavedPage(id); + return; + } + setTimeout(() => { + this.onSavedPagedLoaded(id); + }, 100); + } + launchPicker() { this.dialog.open(VersePickerModalComponent); } diff --git a/app/db/src/app/services/app.service.ts b/app/db/src/app/services/app.service.ts index e92beadb..e11f15ad 100644 --- a/app/db/src/app/services/app.service.ts +++ b/app/db/src/app/services/app.service.ts @@ -44,7 +44,9 @@ const initialState: AppState = { }, ], autocomplete: [], + currentPage: null, savedPages: [], + savedPagesLoaded: false, mainPages: [ { title: PageTitles.Search, icon: PageIcons.Search, route: 'search' }, { title: PageTitles.Settings, icon: PageIcons.Settings, route: 'settings' }, @@ -71,14 +73,14 @@ const initialState: AppState = { }; type AppAction = - | { - type: 'GET_SAVED_PAGES'; - pages: SavedPage[]; - } | { type: 'GET_SAVED_PAGE'; pageid: string; } + | { + type: 'UPDATE_SAVED_PAGES'; + savedPages: SavedPage[]; + } | { type: 'ADD_CARD'; card: CardItem; @@ -133,6 +135,13 @@ function reducer(state: AppState, action: AppAction): AppState { autocomplete: [...action.words], }; } + case 'UPDATE_SAVED_PAGES': { + return { + ...state, + savedPagesLoaded: true, + savedPages: action.savedPages, + }; + } case 'GET_SAVED_PAGE': { const page = state.savedPages.find( (o) => o.id.toString() === action.pageid @@ -144,15 +153,10 @@ function reducer(state: AppState, action: AppAction): AppState { return { ...state, + currentPage: page, cards: [...page.queries], }; } - case 'GET_SAVED_PAGES': { - return { - ...state, - savedPages: [...action.pages], - }; - } case 'ADD_CARD': { let cards = []; @@ -261,21 +265,17 @@ export class AppService extends createStateService(reducer, initialState) { const exists = await this.localStorageService.has('savedPages').toPromise(); if (exists) { - const pages = await this.getSavedPagesApi(); + const savedPages = (await this.localStorageService + .get('savedPages') + .toPromise()) as SavedPage[]; this.dispatch({ - type: 'GET_SAVED_PAGES', - pages, + type: 'UPDATE_SAVED_PAGES', + savedPages, }); } } - private async getSavedPagesApi() { - return (await this.localStorageService - .get('savedPages') - .toPromise()) as SavedPage[]; - } - getSavedPage(pageid: string) { this.dispatch({ type: 'GET_SAVED_PAGE', @@ -283,6 +283,40 @@ export class AppService extends createStateService(reducer, initialState) { }); } + savePage(title: string) { + const state = this.getState(); + + const savedPages = [ + ...state.savedPages, + { + // create a new saved page object + title, + id: UUID.UUID().toString(), + queries: [...state.cards], + }, + ]; + + this.localStorageService.set('savedPages', savedPages).subscribe( + // success + () => { + this.dispatch({ + type: 'UPDATE_SAVED_PAGES', + savedPages, + }); + }, + // error + () => { + this.dispatch({ + type: 'UPDATE_ERROR', + error: { + // tslint:disable-next-line: quotemark + msg: "Something went wrong and the page wasn't saved. :(", + }, + }); + } + ); + } + //#endregion //#region Display Settings @@ -357,6 +391,28 @@ export class AppService extends createStateService(reducer, initialState) { }); } + async createNote(card: CardItem, nextToItem: CardItem = null) { + this.saveNoteApi(card.data as NoteItem).subscribe( + // success + () => { + this.dispatch({ + type: 'ADD_CARD', + card, + nextToItem, + }); + }, + // error + () => { + this.dispatch({ + type: 'UPDATE_ERROR', + error: { + // tslint:disable-next-line: quotemark + msg: "Something went wrong and the note wasn't saved. :(", + }, + }); + } + ); + } async editNote(newCard: CardItem, oldCard: CardItem) { this.saveNoteApi(newCard.data as NoteItem).subscribe( // success diff --git a/app/db/src/app/services/nav.service.ts b/app/db/src/app/services/nav.service.ts index a4d5e1c2..668b4872 100644 --- a/app/db/src/app/services/nav.service.ts +++ b/app/db/src/app/services/nav.service.ts @@ -17,8 +17,9 @@ export class NavService { return this.sidenav.open(); } - public close() { - return this.sidenav.close(); + public async close() { + const r = await this.sidenav.close(); + return r; } public toggle(): void {