journal-spellcards.component.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. import { Component } from '@angular/core';
  2. import {
  3. CdkDragDrop,
  4. CdkDrag,
  5. CdkDropList,
  6. CdkDropListGroup,
  7. moveItemInArray,
  8. transferArrayItem,
  9. } from '@angular/cdk/drag-drop';
  10. import { Spell } from 'src/interfaces/spell';
  11. import { DataService } from 'src/services/data/data.service';
  12. import { ModalService } from 'src/services/modal/modal.service';
  13. import { SpellsService } from 'src/services/spells/spells.service';
  14. import { SpellModalComponent } from 'src/app/journal/spell-modal/spell-modal.component';
  15. import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
  16. import { Observable, OperatorFunction } from 'rxjs';
  17. import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
  18. import { FormsModule } from '@angular/forms';
  19. import { JsonPipe } from '@angular/common';
  20. import { FormControl } from '@angular/forms';
  21. import { FullSpellcardComponent } from 'src/app/shared-components/full-spellcard/full-spellcard.component';
  22. @Component({
  23. selector: 'app-journal-spellcards',
  24. templateUrl: './journal-spellcards.component.html',
  25. styleUrls: ['./journal-spellcards.component.scss'],
  26. })
  27. export class JournalSpellcardsComponent {
  28. public level0: Spell[] = [];
  29. public level1: Spell[] = [];
  30. public level2: Spell[] = [];
  31. public level3: Spell[] = [];
  32. public level4: Spell[] = [];
  33. public level5: Spell[] = [];
  34. public level6: Spell[] = [];
  35. public level7: Spell[] = [];
  36. public level8: Spell[] = [];
  37. public level9: Spell[] = [];
  38. public showSpellList: boolean[] = [
  39. true,
  40. true,
  41. true,
  42. true,
  43. true,
  44. true,
  45. true,
  46. true,
  47. true,
  48. true,
  49. ];
  50. public draggingIndex: number | undefined;
  51. public constructor(
  52. public dataAccessor: DataService,
  53. private modalAccessor: ModalService,
  54. private spellsService: SpellsService
  55. ) {
  56. this.loadSpells();
  57. this.hideEmptySpelllists();
  58. }
  59. ///////// FUNCTIONS //////////
  60. public getUsedIDs(level: number): number[] {
  61. const usedIDs: number[] = [];
  62. this.getSpellList(level).forEach((spell) => {
  63. usedIDs.push(spell.id);
  64. });
  65. return usedIDs;
  66. }
  67. public showFullSpellcard(
  68. spell: Spell,
  69. level: number,
  70. spellIndex: number
  71. ): void {
  72. const favorites = this.dataAccessor.favoriteSpells;
  73. const alreadyInFavorites = favorites.some(
  74. (currentSpell) => currentSpell.id === spell.id
  75. );
  76. this.modalAccessor.openModal(FullSpellcardComponent, {
  77. spell: spell,
  78. isFromDashboard: false,
  79. alreadyInFavorites: alreadyInFavorites,
  80. });
  81. const resultSubscription = this.modalAccessor.result$.subscribe(
  82. (result) => {
  83. resultSubscription.unsubscribe();
  84. if (result.state === 'delete') {
  85. this.spellsService.deleteCustomSpell(spell);
  86. this.dataAccessor.deleteCustomSpell(spell);
  87. this.dataAccessor.removeFavoriteSpell(spell);
  88. this.getSpellList(level).splice(spellIndex, 1);
  89. this.updateSpellsInDatabase(level);
  90. } else if (result.state === 'remove') {
  91. this.dataAccessor.removeFavoriteSpell(spell);
  92. this.getSpellList(level).splice(spellIndex, 1);
  93. this.updateSpellsInDatabase(level);
  94. } else if (result.state === 'update') {
  95. setTimeout(() => {
  96. this.openSpellModificationModal(level, spellIndex);
  97. }, 100);
  98. } else if (result.state === 'add') {
  99. this.dataAccessor.addFavoriteSpell(spell);
  100. }
  101. }
  102. );
  103. }
  104. // TODO: Update favorites, when modifying a spell
  105. public openSpellModificationModal(level: number, index: number): void {
  106. this.modalAccessor.openModal(SpellModalComponent, {
  107. spell:
  108. index !== undefined
  109. ? JSON.parse(JSON.stringify(this.getSpellList(level)![index]))
  110. : undefined,
  111. isModification: true,
  112. });
  113. const resultSubscription = this.modalAccessor.result$.subscribe(
  114. (result) => {
  115. if (result.state === 'update') {
  116. // level was not modified
  117. if (level === result.data.level) {
  118. this.updateSpell(result.data, level, index);
  119. this.dataAccessor.updateFavoriteSpell(result.data);
  120. this.dataAccessor.updateCustomSpell(result.data);
  121. } else {
  122. // level was modified
  123. this.getSpellList(level).splice(index, 1);
  124. this.addSpell(result.data, result.data.level);
  125. }
  126. } else {
  127. throw new Error('REsult state from modal: ' + result.state);
  128. }
  129. resultSubscription.unsubscribe();
  130. }
  131. );
  132. }
  133. /**
  134. * In this modal new spells can be created. This can be completely new spells or
  135. * modified official spells. If successful, the spell is added to the spell list,
  136. * sent to the daService and sent to the spellsService which in return sends it to the dataBase
  137. * @param level
  138. * @param isBasedOnOfficialSpell
  139. * @param spell
  140. */
  141. public openSpellCreationModal(
  142. level: number,
  143. isBasedOnOfficialSpell: boolean,
  144. spell?: Spell
  145. ): void {
  146. this.modalAccessor.openModal(SpellModalComponent, {
  147. spell: isBasedOnOfficialSpell ? spell : undefined,
  148. level: level,
  149. id: this.dataAccessor.customSpellId,
  150. isBasedOnOfficialSpell: isBasedOnOfficialSpell,
  151. classes: [this.dataAccessor.characterData.class],
  152. });
  153. const resultSubscription = this.modalAccessor.result$.subscribe(
  154. (result) => {
  155. if (result.state === 'add') {
  156. console.warn('Add spell: ', result.data);
  157. this.addSpell(result.data, level);
  158. // this.spellsService.addCustomSpell(result.data);
  159. this.dataAccessor.addCustomSpell(result.data);
  160. } else {
  161. console.warn('Result state from modal: ' + result.state);
  162. }
  163. resultSubscription.unsubscribe();
  164. }
  165. );
  166. }
  167. public handleSpellSelection(spell: Spell, level: number): void {
  168. this.addSpell(spell, level);
  169. }
  170. public addSpell(spell: Spell, level: number) {
  171. this.getSpellList(level).push(spell);
  172. this.updateSpellsInDatabase(level);
  173. }
  174. public updateSpell(spell: Spell, level: number, index: number): void {
  175. this.getSpellList(level)![index] = spell;
  176. this.updateSpellsInDatabase(level);
  177. }
  178. public getSpellList(level: number): Spell[] {
  179. switch (level) {
  180. case 0:
  181. return this.level0;
  182. case 1:
  183. return this.level1;
  184. case 2:
  185. return this.level2;
  186. case 3:
  187. return this.level3;
  188. case 4:
  189. return this.level4;
  190. case 5:
  191. return this.level5;
  192. case 6:
  193. return this.level6;
  194. case 7:
  195. return this.level7;
  196. case 8:
  197. return this.level8;
  198. case 9:
  199. return this.level9;
  200. default:
  201. throw new Error('Invalid spell level');
  202. }
  203. }
  204. public getSpellLevel(level: number): string {
  205. switch (level) {
  206. case 0:
  207. return 'Zaubertricks';
  208. case 1:
  209. return 'Level 1';
  210. case 2:
  211. return 'Level 2';
  212. case 3:
  213. return 'Level 3';
  214. case 4:
  215. return 'Level 4';
  216. case 5:
  217. return 'Level 5';
  218. case 6:
  219. return 'Level 6';
  220. case 7:
  221. return 'Level 7';
  222. case 8:
  223. return 'Level 8';
  224. case 9:
  225. return 'Level 9';
  226. default:
  227. return '';
  228. }
  229. }
  230. public toggleSpellList(index: number) {
  231. this.showSpellList[index] = !this.showSpellList[index];
  232. }
  233. public drop(event: CdkDragDrop<any[]>) {
  234. if (event.previousContainer === event.container) {
  235. moveItemInArray(
  236. event.container.data,
  237. event.previousIndex,
  238. event.currentIndex
  239. );
  240. this.updateSpellsInDatabase(this.getIndex(event.previousContainer.id));
  241. // update database with one level
  242. } else {
  243. transferArrayItem(
  244. event.previousContainer.data,
  245. event.container.data,
  246. event.previousIndex,
  247. event.currentIndex
  248. );
  249. this.updateSpellsInDatabase(this.getIndex(event.previousContainer.id));
  250. // Update level of moved spell
  251. const movedSpell = event.container.data[event.currentIndex];
  252. const newContainer = event.container.id;
  253. switch (newContainer) {
  254. case 'cdk-drop-list-0':
  255. movedSpell.level = 0;
  256. this.updateSpellsInDatabase(0);
  257. if (movedSpell.isCustom) {
  258. this.dataAccessor.updateCustomSpell(movedSpell);
  259. }
  260. break;
  261. case 'cdk-drop-list-1':
  262. movedSpell.level = 1;
  263. this.updateSpellsInDatabase(1);
  264. if (movedSpell.isCustom) {
  265. this.dataAccessor.updateCustomSpell(movedSpell);
  266. }
  267. break;
  268. case 'cdk-drop-list-2':
  269. movedSpell.level = 2;
  270. this.updateSpellsInDatabase(2);
  271. if (movedSpell.isCustom) {
  272. this.dataAccessor.updateCustomSpell(movedSpell);
  273. }
  274. break;
  275. case 'cdk-drop-list-3':
  276. movedSpell.level = 3;
  277. this.updateSpellsInDatabase(3);
  278. if (movedSpell.isCustom) {
  279. this.dataAccessor.updateCustomSpell(movedSpell);
  280. }
  281. break;
  282. case 'cdk-drop-list-4':
  283. movedSpell.level = 4;
  284. this.updateSpellsInDatabase(4);
  285. if (movedSpell.isCustom) {
  286. this.dataAccessor.updateCustomSpell(movedSpell);
  287. }
  288. break;
  289. case 'cdk-drop-list-5':
  290. movedSpell.level = 5;
  291. this.updateSpellsInDatabase(5);
  292. if (movedSpell.isCustom) {
  293. this.dataAccessor.updateCustomSpell(movedSpell);
  294. }
  295. break;
  296. case 'cdk-drop-list-6':
  297. movedSpell.level = 6;
  298. this.updateSpellsInDatabase(6);
  299. if (movedSpell.isCustom) {
  300. this.dataAccessor.updateCustomSpell(movedSpell);
  301. }
  302. break;
  303. case 'cdk-drop-list-7':
  304. movedSpell.level = 7;
  305. this.updateSpellsInDatabase(7);
  306. if (movedSpell.isCustom) {
  307. this.dataAccessor.updateCustomSpell(movedSpell);
  308. }
  309. break;
  310. case 'cdk-drop-list-8':
  311. movedSpell.level = 8;
  312. this.updateSpellsInDatabase(8);
  313. if (movedSpell.isCustom) {
  314. this.dataAccessor.updateCustomSpell(movedSpell);
  315. }
  316. break;
  317. case 'cdk-drop-list-9':
  318. movedSpell.level = 9;
  319. this.updateSpellsInDatabase(9);
  320. if (movedSpell.isCustom) {
  321. this.dataAccessor.updateCustomSpell(movedSpell);
  322. }
  323. break;
  324. }
  325. }
  326. }
  327. private getIndex(id: string): number {
  328. switch (id) {
  329. case 'cdk-drop-list-0':
  330. return 0;
  331. case 'cdk-drop-list-1':
  332. return 1;
  333. case 'cdk-drop-list-2':
  334. return 2;
  335. case 'cdk-drop-list-3':
  336. return 3;
  337. case 'cdk-drop-list-4':
  338. return 4;
  339. case 'cdk-drop-list-5':
  340. return 5;
  341. case 'cdk-drop-list-6':
  342. return 6;
  343. case 'cdk-drop-list-7':
  344. return 7;
  345. case 'cdk-drop-list-8':
  346. return 8;
  347. case 'cdk-drop-list-9':
  348. return 9;
  349. default:
  350. throw new Error('DND-ERROR: Invalid spell level');
  351. }
  352. }
  353. public dragStart(index: number) {
  354. this.draggingIndex = index;
  355. }
  356. public dragEnd(event: any) {
  357. if (event.event.target.classList.contains('removal-card')) {
  358. this.getSpellList(this.draggingIndex!).splice(
  359. event.source.element.nativeElement.id,
  360. 1
  361. );
  362. this.updateSpellsInDatabase(this.draggingIndex!);
  363. }
  364. this.draggingIndex = undefined;
  365. }
  366. private loadSpells(): void {
  367. this.level0 = this.dataAccessor.spellLevel0;
  368. this.level1 = this.dataAccessor.spellLevel1;
  369. this.level2 = this.dataAccessor.spellLevel2;
  370. this.level3 = this.dataAccessor.spellLevel3;
  371. this.level4 = this.dataAccessor.spellLevel4;
  372. this.level5 = this.dataAccessor.spellLevel5;
  373. this.level6 = this.dataAccessor.spellLevel6;
  374. this.level7 = this.dataAccessor.spellLevel7;
  375. this.level8 = this.dataAccessor.spellLevel8;
  376. this.level9 = this.dataAccessor.spellLevel9;
  377. }
  378. private hideEmptySpelllists(): void {
  379. this.showSpellList = [
  380. this.level0.length > 0,
  381. this.level1.length > 0,
  382. this.level2.length > 0,
  383. this.level3.length > 0,
  384. this.level4.length > 0,
  385. this.level5.length > 0,
  386. this.level6.length > 0,
  387. this.level7.length > 0,
  388. this.level8.length > 0,
  389. this.level9.length > 0,
  390. ];
  391. }
  392. private updateSpellsInDatabase(level: number): void {
  393. switch (level) {
  394. case 0:
  395. this.dataAccessor.spellLevel0 = this.level0;
  396. break;
  397. case 1:
  398. this.dataAccessor.spellLevel1 = this.level1;
  399. break;
  400. case 2:
  401. this.dataAccessor.spellLevel2 = this.level2;
  402. break;
  403. case 3:
  404. this.dataAccessor.spellLevel3 = this.level3;
  405. break;
  406. case 4:
  407. this.dataAccessor.spellLevel4 = this.level4;
  408. break;
  409. case 5:
  410. this.dataAccessor.spellLevel5 = this.level5;
  411. break;
  412. case 6:
  413. this.dataAccessor.spellLevel6 = this.level6;
  414. break;
  415. case 7:
  416. this.dataAccessor.spellLevel7 = this.level7;
  417. break;
  418. case 8:
  419. this.dataAccessor.spellLevel8 = this.level8;
  420. break;
  421. case 9:
  422. this.dataAccessor.spellLevel9 = this.level9;
  423. break;
  424. }
  425. }
  426. }