From 89d5df20b8ad9f04cf88e231d54ed18f13932244 Mon Sep 17 00:00:00 2001 From: Nuno Caseiro Date: Fri, 16 Dec 2022 18:41:06 +0000 Subject: [PATCH 1/3] fix: votes in card group --- backend/src/modules/votes/services/create.vote.service.ts | 5 +++++ backend/src/modules/votes/services/delete.vote.service.ts | 5 +++++ frontend/src/hooks/useBoard.tsx | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/src/modules/votes/services/create.vote.service.ts b/backend/src/modules/votes/services/create.vote.service.ts index 1cd6fd633..701ba2229 100644 --- a/backend/src/modules/votes/services/create.vote.service.ts +++ b/backend/src/modules/votes/services/create.vote.service.ts @@ -124,6 +124,11 @@ export default class CreateVoteServiceImpl implements CreateVoteService { new: true } ) + .populate({ + path: 'users', + select: 'user role votesCount -board', + populate: { path: 'user', select: 'firstName lastName _id' } + }) .lean() .exec(); diff --git a/backend/src/modules/votes/services/delete.vote.service.ts b/backend/src/modules/votes/services/delete.vote.service.ts index 6c8baa3ee..613b7768a 100644 --- a/backend/src/modules/votes/services/delete.vote.service.ts +++ b/backend/src/modules/votes/services/delete.vote.service.ts @@ -163,6 +163,11 @@ export default class DeleteVoteServiceImpl implements DeleteVoteService { new: true } ) + .populate({ + path: 'users', + select: 'user role votesCount -board', + populate: { path: 'user', select: 'firstName lastName _id' } + }) .lean() .exec(); diff --git a/frontend/src/hooks/useBoard.tsx b/frontend/src/hooks/useBoard.tsx index 8a4d8de34..22496b8a8 100644 --- a/frontend/src/hooks/useBoard.tsx +++ b/frontend/src/hooks/useBoard.tsx @@ -66,7 +66,7 @@ const useBoard = ({ autoFetchBoard = false }: AutoFetchProps): UseBoardType => { const updateBoard = useMutation(updateBoardRequest, { onSuccess: () => { - queryClient.invalidateQueries('board'); + queryClient.invalidateQueries(['board', { id: boardId }]); setToastState({ open: true, @@ -75,6 +75,7 @@ const useBoard = ({ autoFetchBoard = false }: AutoFetchProps): UseBoardType => { }); }, onError: (error: AxiosError) => { + queryClient.invalidateQueries(['board', { id: boardId }]); const errorMessage = error.response?.data.message.includes('max votes') ? error.response?.data.message : 'Error updating the board'; From 5f7aaa588fa75648483e422ef264646324705c14 Mon Sep 17 00:00:00 2001 From: Nuno Caseiro Date: Mon, 19 Dec 2022 11:33:56 +0000 Subject: [PATCH 2/3] fix: vote error --- frontend/src/api/boardService.tsx | 14 +-- .../src/components/Board/Column/Column.tsx | 36 ++++---- frontend/src/hooks/useVotes.tsx | 85 +++++++++++-------- frontend/src/types/vote/vote.dto.ts | 2 + 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/frontend/src/api/boardService.tsx b/frontend/src/api/boardService.tsx index ac2e0c7d6..241839b26 100644 --- a/frontend/src/api/boardService.tsx +++ b/frontend/src/api/boardService.tsx @@ -166,19 +166,7 @@ export const deleteVoteRequest = (voteDto: VoteDto): Promise => { method: 'DELETE', data: voteDto }, ); -export const handleVotes = (voteDto: { - cardId: string; - - cardItemId?: string; - - boardId: string; - - socketId?: string; - - isCardGroup: boolean; - - count: number; -}) => +export const handleVotes = (voteDto: VoteDto) => fetchData( voteDto.isCardGroup ? `/boards/${voteDto.boardId}/card/${voteDto.cardId}/vote` diff --git a/frontend/src/components/Board/Column/Column.tsx b/frontend/src/components/Board/Column/Column.tsx index 26d57f6de..9563ef426 100644 --- a/frontend/src/components/Board/Column/Column.tsx +++ b/frontend/src/components/Board/Column/Column.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { Droppable } from '@hello-pangea/dnd'; import Flex from '@/components/Primitives/Flex'; @@ -33,12 +33,6 @@ const Column = React.memo( const setFilteredColumns = useSetRecoilState(filteredColumnsState); const filteredCards = useCallback(() => { - if (filter) { - setFilteredColumns((prev) => { - if (prev.includes(columnId)) return prev; - return [...prev, columnId]; - }); - } switch (filter) { case 'asc': return [...cards].sort((a, b) => { @@ -53,17 +47,27 @@ const Column = React.memo( return votesB - votesA; }); default: - setFilteredColumns((prev) => { - const newValues = [...prev]; - const index = newValues.indexOf(columnId); - if (index > -1) { - newValues.splice(index, 1); - } - return newValues; - }); return cards; } - }, [cards, columnId, filter, setFilteredColumns]); + }, [cards, filter]); + + useEffect(() => { + if (filter) { + setFilteredColumns((prev) => { + if (prev.includes(columnId)) return prev; + return [...prev, columnId]; + }); + } else { + setFilteredColumns((prev) => { + const newValues = [...prev]; + const index = newValues.indexOf(columnId); + if (index > -1) { + newValues.splice(index, 1); + } + return newValues; + }); + } + }, [columnId, filter, setFilteredColumns]); return ( diff --git a/frontend/src/hooks/useVotes.tsx b/frontend/src/hooks/useVotes.tsx index a6dd29712..b23287dd8 100644 --- a/frontend/src/hooks/useVotes.tsx +++ b/frontend/src/hooks/useVotes.tsx @@ -34,6 +34,13 @@ const useVotes = () => { const getBoardQueryKey = (boardId = ''): QueryKeyType => ['board', { id: boardId }]; + const setPreviousBoardQuery = (id: string, context: any) => { + queryClient.setQueryData( + getBoardQueryKey(id), + (context as { previousBoard: BoardType }).previousBoard, + ); + }; + const getFirstCardItemIndexWithVotes = (cardItems: CardItemType[]) => cardItems.findIndex((cardItem) => cardItem.votes.length > 0); @@ -65,6 +72,19 @@ const useVotes = () => { return newBoardData; }; + const updateBoardUser = (boardData: BoardType, action: Action) => { + boardData.users = boardData.users.map((boardUser) => { + if (boardUser.user._id === userId) { + return { + ...boardUser, + votesCount: action === Action.Add ? boardUser.votesCount + 1 : boardUser.votesCount - 1, + }; + } + + return boardUser; + }); + }; + const updateCardItemVoteOptimistic = ( prevBoardData: BoardType, indexes: number[], @@ -145,7 +165,7 @@ const useVotes = () => { voteData: voteDto, action: Action, ) => { - const { cardId, cardItemId, isCardGroup } = voteData; + const { cardId, cardItemId, isCardGroup, count } = voteData; const [colIndex, cardIndex, cardItemIndex] = [-1, -1, -1]; let indexes = [colIndex, cardIndex, cardItemIndex]; @@ -165,7 +185,15 @@ const useVotes = () => { ); if (foundCardItem) { - return updateCardOrCardIndexVotesOptimistic(prevBoardData, indexes, isCardGroup, action); + const newBoard = updateCardOrCardIndexVotesOptimistic( + prevBoardData, + indexes, + isCardGroup, + action, + ); + updateBoardUser(newBoard, count > 0 ? Action.Add : Action.Remove); + + return newBoard; } return prevBoardData; @@ -185,11 +213,6 @@ const useVotes = () => { return { newBoardData, prevBoardData }; }; - const addVoteOptimistic = async (voteData: voteDto) => updateVoteOptimistic(Action.Add, voteData); - - const removeVoteOptimistic = async (voteData: voteDto) => - updateVoteOptimistic(Action.Remove, voteData); - const buildToastMessage = ( toastMessage: string, toastStateType: ToastStateEnum, @@ -209,39 +232,27 @@ const useVotes = () => { } }; - const restoreBoardDataAndToastError = ( - prevBoardData: BoardType | undefined, - { boardId }: voteDto, - errorMessage: string, - ) => { - queryClient.setQueryData(getBoardQueryKey(boardId), prevBoardData); - - toastErrorMessage(errorMessage); - }; - - const invalidateQueriesAndToastMessage = ( - boardDataFromApi: BoardType | undefined, - message: string, - ) => { - queryClient.invalidateQueries(getBoardQueryKey(boardDataFromApi?._id)); - - toastRemainingVotesMessage(message, boardDataFromApi); - }; - const handleVote = useMutation(handleVotes, { - onSuccess: (voteData, variables) => { - if (voteData.maxVotes) { - toastRemainingVotesMessage('', voteData); + onMutate: async (variables) => { + const { newBoardData, prevBoardData } = await updateVoteOptimistic( + variables.count > 0 ? Action.Add : Action.Remove, + variables, + ); + + if (newBoardData?.maxVotes && newBoardData) { + toastRemainingVotesMessage('', newBoardData); + } + + return { previousBoard: prevBoardData, variables }; + }, + onSettled: (data, error, variables, context) => { + if (error) { + queryClient.invalidateQueries(['board', { id: data?._id }]); } - queryClient.invalidateQueries(['board', { id: voteData?._id }]); }, - onError: (error, variables) => { - queryClient.invalidateQueries(['board', { id: variables.boardId }]); - setToastState({ - open: true, - content: 'Error adding the vote', - type: ToastStateEnum.ERROR, - }); + onError: (error, variables, context) => { + setPreviousBoardQuery(variables.boardId, context); + toastErrorMessage(`Error ${variables.count > 0 ? 'adding' : 'removing'} the vote`); }, }); diff --git a/frontend/src/types/vote/vote.dto.ts b/frontend/src/types/vote/vote.dto.ts index ca2133a9e..ba7ba53c3 100644 --- a/frontend/src/types/vote/vote.dto.ts +++ b/frontend/src/types/vote/vote.dto.ts @@ -8,4 +8,6 @@ export default interface VoteDto { socketId?: string; isCardGroup: boolean; + + count: number; } From 0abc8998530c8e31c5385907726065eabe84e58b Mon Sep 17 00:00:00 2001 From: Nuno Caseiro Date: Mon, 19 Dec 2022 11:57:15 +0000 Subject: [PATCH 3/3] refactor: add pr suggestion --- frontend/src/hooks/useVotes.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/frontend/src/hooks/useVotes.tsx b/frontend/src/hooks/useVotes.tsx index b23287dd8..5e6d1e7f6 100644 --- a/frontend/src/hooks/useVotes.tsx +++ b/frontend/src/hooks/useVotes.tsx @@ -74,14 +74,12 @@ const useVotes = () => { const updateBoardUser = (boardData: BoardType, action: Action) => { boardData.users = boardData.users.map((boardUser) => { - if (boardUser.user._id === userId) { - return { - ...boardUser, - votesCount: action === Action.Add ? boardUser.votesCount + 1 : boardUser.votesCount - 1, - }; - } + if (boardUser.user._id !== userId) return boardUser; - return boardUser; + return { + ...boardUser, + votesCount: action === Action.Add ? boardUser.votesCount + 1 : boardUser.votesCount - 1, + }; }); };