import { Component } from '@angular/core'; import { CdkDragDrop, moveItemInArray, transferArrayItem, } from '@angular/cdk/drag-drop'; import { Spell } from 'src/interfaces/spell'; import { DataService } from 'src/services/data/data.service'; import { ModalService } from 'src/services/modal/modal.service'; import { SpellsService } from 'src/services/spells/spells.service'; import { SpellModalComponent } from 'src/app/journal/spell-modal/spell-modal.component'; import { FullSpellcardComponent } from 'src/app/shared-components/full-spellcard/full-spellcard.component'; import { CustomSpellsModalComponent } from './custom-spells-modal/custom-spells-modal.component'; @Component({ selector: 'app-journal-spellcards', templateUrl: './journal-spellcards.component.html', styleUrls: ['./journal-spellcards.component.scss'], }) export class JournalSpellcardsComponent { public level0: Spell[] = []; public level1: Spell[] = []; public level2: Spell[] = []; public level3: Spell[] = []; public level4: Spell[] = []; public level5: Spell[] = []; public level6: Spell[] = []; public level7: Spell[] = []; public level8: Spell[] = []; public level9: Spell[] = []; public showSpellList: boolean[] = [ true, true, true, true, true, true, true, true, true, true, ]; public draggingIndex: number | undefined; public constructor( private dataAccessor: DataService, private modalAccessor: ModalService, public spellsService: SpellsService ) { this.loadSpells(); this.hideEmptySpelllists(); } ///////// FUNCTIONS ////////// public getUsedIDs(level: number): number[] { const usedIDs: number[] = []; this.getSpellList(level).forEach((spell) => { usedIDs.push(spell.id); }); return usedIDs; } public showFullSpellcard( spell: Spell, level: number, spellIndex: number ): void { const favorites = this.dataAccessor.favoriteSpells; const alreadyInFavorites = favorites.some( (currentSpell) => currentSpell.id === spell.id ); this.modalAccessor.openModal(FullSpellcardComponent, { spell: spell, isFromDashboard: false, alreadyInFavorites: alreadyInFavorites, }); const resultSubscription = this.modalAccessor.result$.subscribe( (result) => { resultSubscription.unsubscribe(); if (result.state === 'delete') { this.spellsService.deleteCustomSpell(spell); this.dataAccessor.deleteCustomSpell(spell); this.dataAccessor.removeFavoriteSpell(spell); this.getSpellList(level).splice(spellIndex, 1); this.updateSpellsInDatabase(level); } else if (result.state === 'remove') { this.dataAccessor.removeFavoriteSpell(spell); this.getSpellList(level).splice(spellIndex, 1); this.updateSpellsInDatabase(level); } else if (result.state === 'update') { setTimeout(() => { this.openSpellModificationModal(level, spellIndex); }, 100); } else if (result.state === 'add') { this.dataAccessor.addFavoriteSpell(spell); } } ); } // TODO: Update favorites, when modifying a spell public openSpellModificationModal(level: number, index: number): void { this.modalAccessor.openModal(SpellModalComponent, { spell: index !== undefined ? JSON.parse(JSON.stringify(this.getSpellList(level)![index])) : undefined, isModification: true, }); const resultSubscription = this.modalAccessor.result$.subscribe( (result) => { if (result.state === 'update') { // level was not modified if (level === result.data.level) { this.updateSpell(result.data, level, index); this.dataAccessor.updateFavoriteSpell(result.data); this.dataAccessor.updateCustomSpell(result.data); } else { // level was modified this.getSpellList(level).splice(index, 1); this.addSpell(result.data, result.data.level); } } resultSubscription.unsubscribe(); } ); } /** * In this modal new spells can be created. This can be completely new spells or * modified official spells. If successful, the spell is added to the spell list, * sent to the daService and sent to the spellsService which in return sends it to the dataBase * @param level * @param isBasedOnOfficialSpell * @param spell */ public openSpellCreationModal( level: number, isBasedOnOfficialSpell: boolean, spell?: Spell ): void { this.modalAccessor.openModal(SpellModalComponent, { spell: isBasedOnOfficialSpell ? spell : undefined, level: level, id: this.dataAccessor.customSpellId, isBasedOnOfficialSpell: isBasedOnOfficialSpell, classes: [this.dataAccessor.characterData.class], }); const resultSubscription = this.modalAccessor.result$.subscribe( (result) => { if (result.state === 'add') { this.addSpell(result.data, level); // this.spellsService.addCustomSpell(result.data); this.dataAccessor.addCustomSpell(result.data); } else { } resultSubscription.unsubscribe(); } ); } /** * Opens the modal to manage custom spells. Here, custom spells can be deleted. */ public openManageCustomSpellsModal(): void { this.modalAccessor.openModal(CustomSpellsModalComponent, { spells: this.dataAccessor.customSpells, }); const resultSubscription = this.modalAccessor.result$.subscribe( (result) => { console.warn('CustomSpellsModalComponent: result', result); if (result.state === 'delete') { result.data.forEach((spell: Spell) => { this.deleteCustomSpell(spell); }); } resultSubscription.unsubscribe(); } ); } /** * Deletes a custom spell from the custom spells list. * It is deleted in the spells and data service. * It is also removed from the prepared and favorite spells list if present. * @param spell */ public deleteCustomSpell(spell: Spell): void { this.dataAccessor.deleteCustomSpell(spell); this.spellsService.deleteCustomSpell(spell); let list = this.getSpellList(spell.level); const index = list.findIndex((spellList) => spellList.id === spell.id); if (index > -1) { list.splice(index, 1); this.dataAccessor.removeFavoriteSpell(spell); this.updateSpellsInDatabase(spell.level); } } /** * Adds a given spell to the spelllist of a specific level. * @param spell The spell to add. * @param level The level the spell needs to be added to. */ public addSpellToSpelllist(spell: Spell, level: number): void { this.addSpell(spell, level); } /** * Adds a given spell to the spell list specified by level. * Also updates the spell list in the database. * @param spell The spell to add. * @param level The level to add the spell to. */ public addSpell(spell: Spell, level: number) { this.getSpellList(level).push(spell); this.updateSpellsInDatabase(level); } /** * Overrides a spell in a given spell list, specified by the index. * @param spell The new spell. * @param level The level to add the spell to. * @param index The index at which the spell should be overridden. */ public updateSpell(spell: Spell, level: number, index: number): void { this.getSpellList(level)![index] = spell; this.updateSpellsInDatabase(level); } /** * Returns the reference to the spell list specified by the level. * @param level Specifies the level of the spell list. * @returns Returns the spell list specified by the level. */ public getSpellList(level: number): Spell[] { switch (level) { case 0: return this.level0; case 1: return this.level1; case 2: return this.level2; case 3: return this.level3; case 4: return this.level4; case 5: return this.level5; case 6: return this.level6; case 7: return this.level7; case 8: return this.level8; case 9: return this.level9; default: console.warn('Invalid spell level'); return []; } } /** * A lookup function to match spell levels from 0-9 to strings eg: 2 => "Level 2". * @param level The level that is looked up. * @returns Returns a string with the name to display in the view. */ public getSpellLevel(level: number): string { switch (level) { case 0: return 'Zaubertricks'; case 1: return 'Level 1'; case 2: return 'Level 2'; case 3: return 'Level 3'; case 4: return 'Level 4'; case 5: return 'Level 5'; case 6: return 'Level 6'; case 7: return 'Level 7'; case 8: return 'Level 8'; case 9: return 'Level 9'; default: return ''; } } public toggleSpellList(index: number) { this.showSpellList[index] = !this.showSpellList[index]; } public drop(event: CdkDragDrop) { if (event.previousContainer === event.container) { moveItemInArray( event.container.data, event.previousIndex, event.currentIndex ); this.updateSpellsInDatabase(this.getIndex(event.previousContainer.id)); // update database with one level } else { transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex ); this.updateSpellsInDatabase(this.getIndex(event.previousContainer.id)); // Update level of moved spell const movedSpell = event.container.data[event.currentIndex]; const newContainer = event.container.id; switch (newContainer) { case 'cdk-drop-list-0': movedSpell.level = 0; this.updateSpellsInDatabase(0); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-1': movedSpell.level = 1; this.updateSpellsInDatabase(1); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-2': movedSpell.level = 2; this.updateSpellsInDatabase(2); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-3': movedSpell.level = 3; this.updateSpellsInDatabase(3); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-4': movedSpell.level = 4; this.updateSpellsInDatabase(4); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-5': movedSpell.level = 5; this.updateSpellsInDatabase(5); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-6': movedSpell.level = 6; this.updateSpellsInDatabase(6); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-7': movedSpell.level = 7; this.updateSpellsInDatabase(7); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-8': movedSpell.level = 8; this.updateSpellsInDatabase(8); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; case 'cdk-drop-list-9': movedSpell.level = 9; this.updateSpellsInDatabase(9); if (movedSpell.isCustom) { this.dataAccessor.updateCustomSpell(movedSpell); } break; } } } private getIndex(id: string): number { switch (id) { case 'cdk-drop-list-0': return 0; case 'cdk-drop-list-1': return 1; case 'cdk-drop-list-2': return 2; case 'cdk-drop-list-3': return 3; case 'cdk-drop-list-4': return 4; case 'cdk-drop-list-5': return 5; case 'cdk-drop-list-6': return 6; case 'cdk-drop-list-7': return 7; case 'cdk-drop-list-8': return 8; case 'cdk-drop-list-9': return 9; default: console.warn('DND-ERROR: Invalid spell level'); return -1; } } public dragStart(index: number) { this.draggingIndex = index; } public dragEnd(event: any) { if (event.event.target.classList.contains('removal-card')) { this.getSpellList(this.draggingIndex!).splice( event.source.element.nativeElement.id, 1 ); this.updateSpellsInDatabase(this.draggingIndex!); } this.draggingIndex = undefined; } private loadSpells(): void { this.level0 = this.dataAccessor.spellLevel0; this.level1 = this.dataAccessor.spellLevel1; this.level2 = this.dataAccessor.spellLevel2; this.level3 = this.dataAccessor.spellLevel3; this.level4 = this.dataAccessor.spellLevel4; this.level5 = this.dataAccessor.spellLevel5; this.level6 = this.dataAccessor.spellLevel6; this.level7 = this.dataAccessor.spellLevel7; this.level8 = this.dataAccessor.spellLevel8; this.level9 = this.dataAccessor.spellLevel9; } private hideEmptySpelllists(): void { this.showSpellList = [ this.level0.length > 0, this.level1.length > 0, this.level2.length > 0, this.level3.length > 0, this.level4.length > 0, this.level5.length > 0, this.level6.length > 0, this.level7.length > 0, this.level8.length > 0, this.level9.length > 0, ]; } private updateSpellsInDatabase(level: number): void { switch (level) { case 0: this.dataAccessor.spellLevel0 = this.level0; break; case 1: this.dataAccessor.spellLevel1 = this.level1; break; case 2: this.dataAccessor.spellLevel2 = this.level2; break; case 3: this.dataAccessor.spellLevel3 = this.level3; break; case 4: this.dataAccessor.spellLevel4 = this.level4; break; case 5: this.dataAccessor.spellLevel5 = this.level5; break; case 6: this.dataAccessor.spellLevel6 = this.level6; break; case 7: this.dataAccessor.spellLevel7 = this.level7; break; case 8: this.dataAccessor.spellLevel8 = this.level8; break; case 9: this.dataAccessor.spellLevel9 = this.level9; break; } } }