Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(retro): adds the possibility to add coments #122

Closed
wants to merge 8 commits into from
1 change: 1 addition & 0 deletions backend/src/events/card-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export function createCard(io: Server, client: Socket, roomId: string): void {
card.isBlurred = board.isBlurred;
card.author = author.trim();
card.content = content.trim();
card.commentIds = [];
board.items[card.id] = card;
board.columns[columnId].itemIds.push(card.id);

Expand Down
90 changes: 90 additions & 0 deletions backend/src/events/comment-events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import fs from "fs";
import { forIn, pull, unset } from "lodash";
import { Server, Socket } from "socket.io";
import { RetroComment } from "src/models/RetroComment";
import { getPath, getRetroBoard, logError, stringify } from "../utils";
import {
BOARD_ERROR,
COMMENT_CARD,
DELETE_COMMENT,
EDIT_COMMENT,
UPDATE_BOARD,
} from "./event-names";

const UTF8 = "utf8";

export function commentCard(io: Server, client: Socket, roomId: string): void {
client.on(
COMMENT_CARD,
(boardId: string, cardId: string, comment: RetroComment) => {
const path = getPath(boardId);
fs.readFile(path, UTF8, (error, file: string) => {
if (error) logError(COMMENT_CARD, error);
const board = getRetroBoard(file);

if (board === null) {
client.emit(BOARD_ERROR);
} else {
const { id, author, content } = comment;

comment.author = author.trim();
comment.content = content.trim();
board.items[cardId].commentIds.push(id);
board.comments[id] = comment;

fs.writeFile(path, stringify(board), UTF8, error => {
if (error) logError(COMMENT_CARD, error);
io.to(roomId).emit(UPDATE_BOARD, board);
});
}
});
}
);
}

export function deleteComment(io: Server, client: Socket, roomId: string): void {
client.on(DELETE_COMMENT, (boardId: string, commentId: string) => {
const path = getPath(boardId);
fs.readFile(path, UTF8, (error, file: string) => {
if (error) logError(DELETE_COMMENT, error);
const board = getRetroBoard(file);

if (board === null) {
client.emit(BOARD_ERROR);
} else {
unset(board.comments, commentId);
forIn(board.items, item => pull(item.commentIds, commentId));

fs.writeFile(path, stringify(board), UTF8, error => {
if (error) logError(DELETE_COMMENT, error);
io.to(roomId).emit(UPDATE_BOARD, board);
});
}
});
});
}

export function editComment(io: Server, client: Socket, roomId: string): void {
client.on(EDIT_COMMENT, (boardId: string, comment: RetroComment) => {
const path = getPath(boardId);
fs.readFile(path, UTF8, (error, file: string) => {
if (error) logError(EDIT_COMMENT, error);
const board = getRetroBoard(file);

if (board === null) {
client.emit(BOARD_ERROR);
} else {
const { id, author, content } = comment;

comment.author = author.trim();
comment.content = content.trim();
board.comments[id] = comment;

fs.writeFile(path, stringify(board), UTF8, error => {
if (error) logError(EDIT_COMMENT, error);
io.to(roomId).emit(UPDATE_BOARD, board);
});
}
});
});
}
3 changes: 3 additions & 0 deletions backend/src/events/event-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export const VOTE_CARD = "vote card";
export const EDIT_CARD = "edit card";
export const SORT_COLUMN = "sort column";
export const DELETE_CARD = "delete card";
export const COMMENT_CARD = "comment card";
export const EDIT_COMMENT = "edit comment";
export const DELETE_COMMENT = "delete comment";
export const JOIN_BOARD = "join board";
export const UNBLUR_CARDS = "unblur cards";
export const EDIT_COLUMN = "edit column";
Expand Down
7 changes: 7 additions & 0 deletions backend/src/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
setPokerUnit,
removePokerUser,
} from "./poker-events";
import { commentCard, deleteComment, editComment } from "./comment-events";

export function boardEvents(io: Server, client: Socket, roomId: string): void {
joinBoard(io, client);
Expand Down Expand Up @@ -71,6 +72,12 @@ export function cardEvents(io: Server, client: Socket, roomId: string): void {
removeFocusCard(io, client, roomId);
}

export function commentEvents(io: Server, client: Socket, roomId: string): void {
commentCard(io, client, roomId);
deleteComment(io, client, roomId);
editComment(io, client, roomId);
}

export function pokerEvents(io: Server, client: Socket, roomId: string): void {
joinPoker(io, client);
joinPokerSession(io, client, roomId);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/models/RetroBoard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RetroItem } from "./RetroItem";
import { RetroColumn } from "./RetroColumn";
import { RetroComment } from "./RetroComment";

export type RetroBoard = {
boardId: string;
Expand All @@ -8,6 +9,7 @@ export type RetroBoard = {
items: { [name: string]: RetroItem };
columns: { [name: string]: RetroColumn };
columnOrder: string[];
comments: { [name: string]: RetroComment};
error: boolean;
isBlurred: boolean;
isReactionOn: boolean;
Expand Down
5 changes: 5 additions & 0 deletions backend/src/models/RetroComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type RetroComment = {
id: string;
author: string;
content: string;
}
3 changes: 2 additions & 1 deletion backend/src/models/RetroItem.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export type RetroItem = {
id: string;
author: string;
commentIds: string[];
content: string;
points: number;
isBlurred: boolean;
isDiscussed: boolean;
};
};
3 changes: 2 additions & 1 deletion backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import apiRouter from "./routes/api-router";
import pokerRouter from "./routes/poker-router";
import { cleanStorage } from "./utils/storage-clean-up";
import { CONNECT, DISCONNECT } from "./events/event-names";
import { boardEvents, columnEvents, cardEvents, pokerEvents } from "./events";
import { boardEvents, columnEvents, cardEvents, pokerEvents, commentEvents } from "./events";

const origin = [
"http://localhost:3001",
Expand Down Expand Up @@ -72,6 +72,7 @@ io.on(CONNECT, (socket: Socket) => {
boardEvents(io, socket, retroRoomId);
columnEvents(io, socket, retroRoomId);
cardEvents(io, socket, retroRoomId);
commentEvents(io, socket, retroRoomId);
} else if (pokerRoomId) {
socket.join(pokerRoomId);
pokerEvents(io, socket, pokerRoomId);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/actions/board.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export const CONTINUE_DISCUSSION_VOTE_NO = "CONTINUE DISCUSSION VOTE NO";
export const CONTINUE_DISCUSSION_VOTE_ABSTAIN =
"CONTINUE DISCUSSION VOTE ABSTAIN";
export const SHOW_REACTION = "SHOW REACTION";
export const UPDATE_COMMENTS = "UPDATE COMMENTS";
3 changes: 3 additions & 0 deletions frontend/src/actions/dialog.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ export const CLOSE_EDIT_COLUMN_DIALOG = "CLOSE_EDIT_COLUMN_DIALOG";

export const OPEN_CREATE_ITEM_DIALOG = "OPEN_CREATE_ITEM_DIALOG";
export const CLOSE_CREATE_ITEM_DIALOG = "CLOSE_CREATE_ITEM_DIALOG";

export const OPEN_RETRO_ITEM_DETAIL_DIALOG = "OPEN_RETRO_ITEM_DETAIL_DIALOG";
export const CLOSE_RETRO_ITEM_DETAIL_DIALOG = "CLOSE_RETRO_ITEM_DETAIL_DIALOG";
1 change: 1 addition & 0 deletions frontend/src/actions/user.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export const RESET = "RESET";
export const SET_NAME = "SET_NAME";
export const CREATE_MODERATOR = "CREATE_MODERATOR";
export const CREATE_PARTICIPANT = "CREATE_PARTICIPANT";
export const WROTE_COMMENT = "WROTE_COMMENT";
121 changes: 75 additions & 46 deletions frontend/src/components/board/BoardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,57 @@
import React, { useState, useEffect, useContext } from "react";
import isEqual from "lodash/isEqual";
import { Grid, makeStyles } from "@material-ui/core";
import isEqual from "lodash/isEqual";
import React, { useContext, useEffect, useState } from "react";
import { DragDropContext, Droppable, DropResult } from "react-beautiful-dnd";
import { Redirect, useLocation, useRouteMatch } from "react-router-dom";

import AppHeader from "./header/AppHeader";
import BoardHeader from "./BoardHeader";
import Columns from "./columns/Columns";
import Dialogs from "./dialogs/Dialogs";
import CreateItemDialog from "./dialogs/CreateItemDialog";
import DeleteItemDialog from "./dialogs/DeleteItemDialog";
import DeleteColumnDialog from "./dialogs/DeleteColumnDialog";
import EditItemDialog from "./dialogs/EditItemDialog";
import EditColumnDialog from "./dialogs/EditColumnDialog";
import MergeCardsDialog from "./dialogs/MergeCardsDialog";

import { FlexContainer } from "../styled-components";
import {
BOARD_ERROR,
CONNECT,
CONTINUE_DISCUSSION_ABSTAIN,
CONTINUE_DISCUSSION_NO,
CONTINUE_DISCUSSION_YES,
FOCUS_CARD,
JOIN_BOARD,
JOIN_ERROR,
REMOVE_FOCUS_CARD,
RESET_VOTES,
SEND_REACTION,
SET_MAX_VOTES,
SHOW_CONTINUE_DISCUSSION,
UPDATE_BOARD,
} from "../../constants/event.constants";
import { BoardContext } from "../../context/BoardContext";
import { UserContext } from "../../context/UserContext";
import { RetroBoard } from "../../types/common.types";
import { defaultBoard, isSameColumn, isSamePosition } from "../../utils";
import {
ROLE_MODERATOR,
ROLE_PARTICIPANT,
getUser,
} from "../../utils/user.utils";
RetroBoard,
RetroCard,
RetroCommentMap,
} from "../../types/common.types";
import { defaultBoard, isSameColumn, isSamePosition } from "../../utils";
import {
handleCombine,
handleColumnDrag,
handleCombine,
handleInsideColumnDrag,
handleNormalDrag,
} from "../../utils/dnd-handler.utils";
import {
CONNECT,
UPDATE_BOARD,
JOIN_BOARD,
JOIN_ERROR,
SET_MAX_VOTES,
RESET_VOTES,
FOCUS_CARD,
REMOVE_FOCUS_CARD,
SHOW_CONTINUE_DISCUSSION,
CONTINUE_DISCUSSION_YES,
CONTINUE_DISCUSSION_ABSTAIN,
CONTINUE_DISCUSSION_NO,
BOARD_ERROR,
SEND_REACTION,
} from "../../constants/event.constants";
import VoteProgress from "./VoteProgress";
getUser,
ROLE_MODERATOR,
ROLE_PARTICIPANT,
} from "../../utils/user.utils";
import { FlexContainer } from "../styled-components";
import BoardHeader from "./BoardHeader";
import Columns from "./columns/Columns";
import CreateItemDialog from "./dialogs/CreateItemDialog";
import DeleteColumnDialog from "./dialogs/DeleteColumnDialog";
import DeleteItemDialog from "./dialogs/DeleteItemDialog";
import Dialogs from "./dialogs/Dialogs";
import EditColumnDialog from "./dialogs/EditColumnDialog";
import EditItemDialog from "./dialogs/EditItemDialog";
import MergeCardsDialog from "./dialogs/MergeCardsDialog";
import RetroItemDetailDialog from "./dialogs/RetroItemDetailDialog";
import ReactionBar from "./footer/ReactionBar";
import AppHeader from "./header/AppHeader";
import VoteProgress from "./VoteProgress";

const useStyles = makeStyles(() => ({
root: {
Expand All @@ -70,16 +73,13 @@ export default function BoardPage() {
showReaction,
removeFocusedCard,
toggleContinueDiscussion,
updateComments,
voteYes,
voteNo,
voteAbstain,
} = useContext(BoardContext);
const {
createModerator,
createParticipant,
setMaxVote,
resetVotes,
} = useContext(UserContext);
const { createModerator, createParticipant, setMaxVote, resetVotes } =
useContext(UserContext);
const classes = useStyles();
const location = useLocation();
const match = useRouteMatch();
Expand Down Expand Up @@ -116,6 +116,7 @@ export default function BoardPage() {
}

setBoard(boardData);
updateComments(getCommentMap(boardData));
});

socket.on(JOIN_ERROR, () => {
Expand All @@ -124,6 +125,7 @@ export default function BoardPage() {

socket.on(UPDATE_BOARD, (newBoard: RetroBoard) => {
setBoard(newBoard);
updateComments(getCommentMap(newBoard));
});

socket.on(SET_MAX_VOTES, (newBoard: RetroBoard) => {
Expand Down Expand Up @@ -162,7 +164,7 @@ export default function BoardPage() {

socket.on(SEND_REACTION, (reactionId: string) => {
showReaction(reactionId);
})
});

return () => {
// Pass nothing to remove all listeners on all events.
Expand All @@ -172,6 +174,32 @@ export default function BoardPage() {
// eslint-disable-next-line
}, []);

function getCommentMap(board: RetroBoard) {
const comments: RetroCommentMap = Object.keys(board.items)
// Get all Items
.map((columnId: string) => board.items[columnId])
//Bring all CommentIds in context to its cardId
.map((card: RetroCard) => ({ [card.id]: card.commentIds }))
//Get all RetroComments that match the cardId
.map((cardCommentsIds: { [x: string]: string[] }) => {
const cardId = Object.keys(cardCommentsIds)[0];
return {
[cardId]: cardCommentsIds[cardId].map(
(commentId: string) => board.comments[commentId]
),
};
})
//Remove unnecessary Array Layer
.reduce(
(obj, item) => (
(obj[Object.keys(item)[0]] = item[Object.keys(item)[0]]), obj
),
{}
);

return comments;
}

function openMergeDialog() {
setMergeDialog(true);
}
Expand Down Expand Up @@ -262,7 +290,7 @@ export default function BoardPage() {
</Droppable>
</DragDropContext>
</Grid>
{board.isReactionOn && <ReactionBar/>}
{board.isReactionOn && <ReactionBar />}
<MergeCardsDialog
open={isMergeDialogOpen}
closeDialog={closeMergeDialog}
Expand All @@ -275,6 +303,7 @@ export default function BoardPage() {
<EditItemDialog />
<EditColumnDialog />
<CreateItemDialog />
<RetroItemDetailDialog />
</Dialogs>
</Grid>
</>
Expand Down
Loading