import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, map, Observable, of, switchMap, take, tap, throwError } from 'rxjs'; import { Board, Card, Label, List } from 'app/modules/admin/apps/scrumboard/scrumboard.models'; @Injectable({ providedIn: 'root' }) export class ScrumboardService { // Private private _board: BehaviorSubject; private _boards: BehaviorSubject; private _card: BehaviorSubject; /** * Constructor */ constructor( private _httpClient: HttpClient ) { // Set the private defaults this._board = new BehaviorSubject(null); this._boards = new BehaviorSubject(null); this._card = new BehaviorSubject(null); } // ----------------------------------------------------------------------------------------------------- // @ Accessors // ----------------------------------------------------------------------------------------------------- /** * Getter for board */ get board$(): Observable { return this._board.asObservable(); } /** * Getter for boards */ get boards$(): Observable { return this._boards.asObservable(); } /** * Getter for card */ get card$(): Observable { return this._card.asObservable(); } // ----------------------------------------------------------------------------------------------------- // @ Public methods // ----------------------------------------------------------------------------------------------------- /** * Get boards */ getBoards(): Observable { return this._httpClient.get('api/apps/scrumboard/boards').pipe( map(response => response.map(item => new Board(item))), tap(boards => this._boards.next(boards)) ); } /** * Get board * * @param id */ getBoard(id: string): Observable { return this._httpClient.get('api/apps/scrumboard/board', {params: {id}}).pipe( map(response => new Board(response)), tap(board => this._board.next(board)) ); } /** * Create board * * @param board */ createBoard(board: Board): Observable { return this.boards$.pipe( take(1), switchMap(boards => this._httpClient.put('api/apps/scrumboard/board', {board}).pipe( map((newBoard) => { // Update the boards with the new board this._boards.next([...boards, newBoard]); // Return new board from observable return newBoard; }) )) ); } /** * Update the board * * @param id * @param board */ updateBoard(id: string, board: Board): Observable { return this.boards$.pipe( take(1), switchMap(boards => this._httpClient.patch('api/apps/scrumboard/board', { id, board }).pipe( map((updatedBoard) => { // Find the index of the updated board const index = boards.findIndex(item => item.id === id); // Update the board boards[index] = updatedBoard; // Update the boards this._boards.next(boards); // Return the updated board return updatedBoard; }) )) ); } /** * Delete the board * * @param id */ deleteBoard(id: string): Observable { return this.boards$.pipe( take(1), switchMap(boards => this._httpClient.delete('api/apps/scrumboard/board', {params: {id}}).pipe( map((isDeleted: boolean) => { // Find the index of the deleted board const index = boards.findIndex(item => item.id === id); // Delete the board boards.splice(index, 1); // Update the boards this._boards.next(boards); // Update the board this._board.next(null); // Update the card this._card.next(null); // Return the deleted status return isDeleted; }) )) ); } /** * Create list * * @param list */ createList(list: List): Observable { return this._httpClient.post('api/apps/scrumboard/board/list', {list}).pipe( map(response => new List(response)), tap((newList) => { // Get the board value const board = this._board.value; // Update the board lists with the new list board.lists = [...board.lists, newList]; // Sort the board lists board.lists.sort((a, b) => a.position - b.position); // Update the board this._board.next(board); }) ); } /** * Update the list * * @param list */ updateList(list: List): Observable { return this._httpClient.patch('api/apps/scrumboard/board/list', {list}).pipe( map(response => new List(response)), tap((updatedList) => { // Get the board value const board = this._board.value; // Find the index of the updated list const index = board.lists.findIndex(item => item.id === list.id); // Update the list board.lists[index] = updatedList; // Sort the board lists board.lists.sort((a, b) => a.position - b.position); // Update the board this._board.next(board); }) ); } /** * Update the lists * * @param lists */ updateLists(lists: List[]): Observable { return this._httpClient.patch('api/apps/scrumboard/board/lists', {lists}).pipe( map(response => response.map(item => new List(item))), tap((updatedLists) => { // Get the board value const board = this._board.value; // Go through the updated lists updatedLists.forEach((updatedList) => { // Find the index of the updated list const index = board.lists.findIndex(item => item.id === updatedList.id); // Update the list board.lists[index] = updatedList; }); // Sort the board lists board.lists.sort((a, b) => a.position - b.position); // Update the board this._board.next(board); }) ); } /** * Delete the list * * @param id */ deleteList(id: string): Observable { return this._httpClient.delete('api/apps/scrumboard/board/list', {params: {id}}).pipe( tap((isDeleted) => { // Get the board value const board = this._board.value; // Find the index of the deleted list const index = board.lists.findIndex(item => item.id === id); // Delete the list board.lists.splice(index, 1); // Sort the board lists board.lists.sort((a, b) => a.position - b.position); // Update the board this._board.next(board); }) ); } /** * Get card */ getCard(id: string): Observable { return this._board.pipe( take(1), map((board) => { // Find the card const card = board.lists.find(list => list.cards.some(item => item.id === id)) .cards.find(item => item.id === id); // Update the card this._card.next(card); // Return the card return card; }), switchMap((card) => { if ( !card ) { return throwError('Could not found the card with id of ' + id + '!'); } return of(card); }) ); } /** * Create card * * @param card */ createCard(card: Card): Observable { return this._httpClient.put('api/apps/scrumboard/board/card', {card}).pipe( map(response => new Card(response)), tap((newCard) => { // Get the board value const board = this._board.value; // Find the list and push the new card in it board.lists.forEach((listItem, index, list) => { if ( listItem.id === newCard.listId ) { list[index].cards.push(newCard); } }); // Update the board this._board.next(board); // Return the new card return newCard; }) ); } /** * Update the card * * @param id * @param card */ updateCard(id: string, card: Card): Observable { return this.board$.pipe( take(1), switchMap(board => this._httpClient.patch('api/apps/scrumboard/board/card', { id, card }).pipe( map((updatedCard) => { // Find the card and update it board.lists.forEach((listItem) => { listItem.cards.forEach((cardItem, index, array) => { if ( cardItem.id === id ) { array[index] = updatedCard; } }); }); // Update the board this._board.next(board); // Update the card this._card.next(updatedCard); // Return the updated card return updatedCard; }) )) ); } /** * Update the cards * * @param cards */ updateCards(cards: Card[]): Observable { return this._httpClient.patch('api/apps/scrumboard/board/cards', {cards}).pipe( map(response => response.map(item => new Card(item))), tap((updatedCards) => { // Get the board value const board = this._board.value; // Go through the updated cards updatedCards.forEach((updatedCard) => { // Find the index of the updated card's list const listIndex = board.lists.findIndex(list => list.id === updatedCard.listId); // Find the index of the updated card const cardIndex = board.lists[listIndex].cards.findIndex(item => item.id === updatedCard.id); // Update the card board.lists[listIndex].cards[cardIndex] = updatedCard; // Sort the cards board.lists[listIndex].cards.sort((a, b) => a.position - b.position); }); // Update the board this._board.next(board); }) ); } /** * Delete the card * * @param id */ deleteCard(id: string): Observable { return this.board$.pipe( take(1), switchMap(board => this._httpClient.delete('api/apps/scrumboard/board/card', {params: {id}}).pipe( map((isDeleted: boolean) => { // Find the card and delete it board.lists.forEach((listItem) => { listItem.cards.forEach((cardItem, index, array) => { if ( cardItem.id === id ) { array.splice(index, 1); } }); }); // Update the board this._board.next(board); // Update the card this._card.next(null); // Return the deleted status return isDeleted; }) )) ); } /** * Update card positions * * @param cards */ updateCardPositions(cards: Card[]): void // Observable { /*return this._httpClient.patch('api/apps/scrumboard/board/card/positions', {cards}).pipe( map((response) => response.map((item) => new Card(item))), tap((updatedCards) => { // Get the board value const board = this._board.value; // Find the card and update it board.lists.forEach((listItem) => { listItem.cards.forEach((cardItem, index, array) => { if ( cardItem.id === id ) { array[index] = updatedCard; } }); }); // Update the lists board.lists = updatedLists; // Sort the board lists board.lists.sort((a, b) => a.position - b.position); // Update the board this._board.next(board); }) );*/ } /** * Create label * * @param label */ createLabel(label: Label): Observable