journal-spellcards.component.ts 15 KB

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