Skip to content

Commit

Permalink
feat: boards page and add cards (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
nunocaseiro authored May 11, 2022
1 parent 9696f59 commit 412ba13
Show file tree
Hide file tree
Showing 15 changed files with 733 additions and 361 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LeanDocument } from 'mongoose';
import { BoardDocument } from '../../schemas/board.schema';
import { GetBoardInterface } from '../getBoard.interface';
import { BoardsAndPage } from '../boards-page.interface';

export interface GetBoardApplicationInterface {
Expand All @@ -18,17 +17,6 @@ export interface GetBoardApplicationInterface {
page?: number,
size?: number,
): Promise<BoardsAndPage | null>;
getBoard(
boardId: string,
userId: string,
): Promise<
| { board: LeanDocument<BoardDocument> }
| null
| {
board: LeanDocument<BoardDocument>;
mainBoardData: LeanDocument<BoardDocument>;
}
| null
>;
getBoard(boardId: string, userId: string): Promise<GetBoardInterface>;
countBoards(userId: string): Promise<number>;
}
10 changes: 10 additions & 0 deletions backend/src/modules/boards/interfaces/getBoard.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LeanDocument } from 'mongoose';
import { BoardDocument } from '../schemas/board.schema';

export type GetBoardInterface =
| { board: LeanDocument<BoardDocument> }
| {
board: LeanDocument<BoardDocument>;
mainBoardData: LeanDocument<BoardDocument>;
}
| null;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LeanDocument } from 'mongoose';
import { GetBoardInterface } from '../getBoard.interface';
import { BoardDocument } from '../../schemas/board.schema';
import { BoardsAndPage } from '../boards-page.interface';

Expand All @@ -21,17 +22,6 @@ export interface GetBoardServiceInterface {
getBoardFromRepo(
boardId: string,
): Promise<LeanDocument<BoardDocument> | null>;
getBoard(
boardId: string,
userId: string,
): Promise<
| { board: LeanDocument<BoardDocument> }
| null
| {
board: LeanDocument<BoardDocument>;
mainBoardData: LeanDocument<BoardDocument>;
}
| null
>;
getBoard(boardId: string, userId: string): Promise<GetBoardInterface>;
countBoards(userId: string): Promise<number>;
}
17 changes: 8 additions & 9 deletions backend/src/modules/boards/services/create.board.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,14 @@ export default class CreateBoardServiceImpl implements CreateBoardService {
const teamUsers = await this.getTeamService.getUsersOfTeam(team);
teamUsers.forEach((teamUser) => {
const user = teamUser.user as UserDocument;
if (!usersIds.includes(user._id.toString())) {
newUsers.push({
user: user._id.toString(),
role: !stakeHolders.includes(user.email)
? BoardRoles.MEMBER
: BoardRoles.STAKEHOLDER,
votesCount: 0,
});
}
if (usersIds.includes(user._id.toString())) return;
newUsers.push({
user: user._id.toString(),
role: !stakeHolders.includes(user.email)
? BoardRoles.MEMBER
: BoardRoles.STAKEHOLDER,
votesCount: 0,
});
});
}

Expand Down
23 changes: 16 additions & 7 deletions frontend/api/boardService.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GetServerSidePropsContext } from "next";
import fetchData from "../utils/fetchData";
import BoardType, { CreateBoardDto } from "../types/board/board";
import BoardType, { CreateBoardDto, GetBoardResponse } from "../types/board/board";
import UpdateCardPositionDto from "../types/card/updateCardPosition.dto";
import UpdateBoardDto from "../types/board/updateBoard";
import AddCardDto from "../types/card/addCard.dto";
Expand All @@ -26,8 +26,8 @@ export const updateBoardRequest = ({ board }: UpdateBoardDto): Promise<BoardType
export const getBoardRequest = (
id: string,
context?: GetServerSidePropsContext
): Promise<BoardType> => {
return fetchData<BoardType>(`/boards/${id}`, { context, serverSide: !!context });
): Promise<GetBoardResponse> => {
return fetchData<GetBoardResponse>(`/boards/${id}`, { context, serverSide: !!context });
};

export const getStakeholders = (): Promise<string[]> => {
Expand Down Expand Up @@ -75,6 +75,10 @@ export const updateCardRequest = (updateCard: UpdateCardDto): Promise<BoardType>
);
};

export const mergeBoardRequest = (subBoardId: string): Promise<BoardType> => {
return fetchData<BoardType>(`/boards/${subBoardId}/merge`, { method: "PUT" });
};

export const updateCardPositionRequest = (
updateCardPosition: UpdateCardPositionDto
): Promise<BoardType> => {
Expand All @@ -85,10 +89,15 @@ export const updateCardPositionRequest = (
};

export const deleteCardRequest = (deleteCardDto: DeleteCardDto): Promise<BoardType> => {
return fetchData<BoardType>(`/boards/${deleteCardDto.boardId}/card/${deleteCardDto.cardId}`, {
method: "DELETE",
data: deleteCardDto,
});
return fetchData<BoardType>(
deleteCardDto.isCardGroup
? `/boards/${deleteCardDto.boardId}/card/${deleteCardDto.cardId}`
: `/boards/${deleteCardDto.boardId}/card/${deleteCardDto.cardId}/items/${deleteCardDto.cardItemId}`,
{
method: "DELETE",
data: deleteCardDto,
}
);
};

// #endregion
Expand Down
199 changes: 199 additions & 0 deletions frontend/components/Board/AddCardOrComments.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import * as z from "zod";
import React, { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { styled } from "../../stitches.config";
import { CardToAdd } from "../../types/card/card";
import AddCardDto from "../../types/card/addCard.dto";
import Button from "../Primitives/Button";
import Flex from "../Primitives/Flex";
import useCards from "../../hooks/useCards";
import TextArea from "../Primitives/TextArea";
import CrossIcon from "../icons/CrossIcon";
import CheckIcon from "../icons/Check";
import PlusIcon from "../icons/PlusIcon";
import UpdateCardDto from "../../types/card/updateCard.dto";
import useComments from "../../hooks/useComments";
import AddCommentDto from "../../types/comment/addComment.dto";
import UpdateCommentDto from "../../types/comment/updateComment.dto";

const ActionButton = styled(Button, { width: "$48", height: "$36" });

const StyledForm = styled("form", Flex, { width: "100%" });

interface AddCardProps {
isUpdate: boolean;
isCard: boolean;
colId: string;
boardId: string;
socketId: string;
cardId?: string;
cardItemId?: string;
cardText?: string;
commentId?: string;
cancelUpdate?: () => void;
defaultOpen?: boolean;
}

const AddCardOrComments = React.memo<AddCardProps>(
({
isUpdate,
colId,
boardId,
socketId,
cardId,
cardItemId,
cardText,
cancelUpdate,
isCard,
commentId,
defaultOpen,
}) => {
const { addCardInColumn, updateCard } = useCards();
const { addCommentInCard, updateComment } = useComments();
const [isOpen, setIsOpen] = useState(!!isUpdate || !!cancelUpdate || defaultOpen);

const methods = useForm<{ text: string }>({
mode: "onSubmit",
reValidateMode: "onChange",
defaultValues: {
text: cardText || "",
},
resolver: zodResolver(z.object({ text: z.string().min(1) })),
});

const handleAddCard = (text: string) => {
const newCard: CardToAdd = {
items: [
{
text: text.trim(),
votes: [],
comments: [],
},
],
text: text.trim(),
votes: [],
comments: [],
};
const changes: AddCardDto = {
colIdToAdd: colId,
boardId,
card: newCard,
socketId,
};

addCardInColumn.mutate(changes);
};

const handleUpdateCard = (text: string) => {
if (!cardId || !cancelUpdate) return;
const cardUpdated: UpdateCardDto = {
cardId,
cardItemId: cardItemId ?? "",
text,
boardId,
socketId,
isCardGroup: !cardItemId,
};

updateCard.mutate(cardUpdated);
cancelUpdate();
};

const handleAddComment = (text: string) => {
if (!cardId || !cancelUpdate) return;
const commentDto: AddCommentDto = {
cardId,
cardItemId,
text,
boardId,
socketId,
isCardGroup: !cardItemId,
};

addCommentInCard.mutate(commentDto);
cancelUpdate();
};

const handleUpdateComment = (text: string) => {
if (!cardId || !cancelUpdate || !commentId) return;
const updateCommentDto: UpdateCommentDto = {
cardId,
cardItemId,
text,
boardId,
socketId,
isCardGroup: !cardItemId,
commentId,
};

updateComment.mutate(updateCommentDto);
cancelUpdate();
};

const handleClear = () => {
if ((isUpdate || !isCard) && cancelUpdate) {
cancelUpdate();
return;
}

methods.reset({ text: "" });
setIsOpen(false);
};

const handleSubmit = (text: string) => {
if (isCard) {
if (!isUpdate) {
handleAddCard(text);
return;
}
handleUpdateCard(text);
}
if (!isCard) {
if (!isUpdate) {
handleAddComment(text);
return;
}
handleUpdateComment(text);
}
};

if (!isOpen)
return (
<ActionButton css={{ display: "flex" }} onClick={() => setIsOpen(true)}>
<PlusIcon size="16" css={{ size: "$12", color: "white" }} />
Add new card
</ActionButton>
);

return (
<StyledForm
direction="column"
align="center"
justify="center"
gap="8"
tabIndex={0}
onSubmit={methods.handleSubmit(({ text }) => {
handleSubmit(text);
})}
>
<FormProvider {...methods}>
<TextArea id="text" floatPlaceholder={false} placeholder="Write your comment here..." />
<Flex justify="end" gap="4" css={{ width: "100%" }}>
<ActionButton
size="sm"
variant={!isUpdate && isCard ? "lightOutline" : "primaryOutline"}
onClick={handleClear}
>
<CrossIcon size="16" />
</ActionButton>
<ActionButton size="sm" type="submit" variant="primary">
<CheckIcon />
</ActionButton>
</Flex>
</FormProvider>
</StyledForm>
);
}
);
export default AddCardOrComments;
Loading

0 comments on commit 412ba13

Please sign in to comment.