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: create board and configurations #142

Merged
merged 1 commit into from
May 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 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, { BoardToAdd } from "../types/board/board";
import BoardType, { CreateBoardDto } 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 @@ -15,7 +15,7 @@ import RemoveFromCardGroupDto from "../types/card/removeFromCardGroup.dto";

// #region BOARD

export const createBoardRequest = (newBoard: BoardToAdd): Promise<BoardType> => {
export const createBoardRequest = (newBoard: CreateBoardDto): Promise<BoardType> => {
return fetchData(`/boards`, { method: "POST", data: newBoard });
};

Expand Down
150 changes: 150 additions & 0 deletions frontend/components/CreateBoard/Configurations/BoardConfigurations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { useFormContext } from "react-hook-form";
import { useRecoilState } from "recoil";
import { createBoardDataState } from "../../../store/createBoard/atoms/create-board.atom";
import CheckIcon from "../../icons/Check";
import Flex from "../../Primitives/Flex";
import Input from "../../Primitives/Input";
import { Switch, SwitchThumb } from "../../Primitives/Switch";
import Text from "../../Primitives/Text";

const BoardConfigurations = () => {
const [createBoardData, setCreateBoardData] = useRecoilState(createBoardDataState);

const { board } = createBoardData;

const { register, unregister, clearErrors, setValue } = useFormContext();

const handleHideCardsChange = (checked: boolean) => {
setCreateBoardData((prev) => ({
...prev,
board: {
...prev.board,
hideCards: checked,
},
}));
};

const handleHideVotesChange = (checked: boolean) => {
setCreateBoardData((prev) => ({
...prev,
board: {
...prev.board,
hideVotes: checked,
},
}));
};

const handlePostAnonymouslyChange = (checked: boolean) => {
setCreateBoardData((prev) => ({
...prev,
board: {
...prev.board,
postAnonymously: checked,
},
}));
};

const handleLimitVotesChange = (checked: boolean) => {
setCreateBoardData((prev) => ({
...prev,
board: {
...prev.board,
maxVotes: checked ? "6" : undefined,
},
}));
setValue("maxVotes", checked ? "6" : "");
if (checked) register("maxVotes");
if (!checked) {
unregister("maxVotes");
clearErrors("maxVotes");
}
};

return (
<Flex direction="column">
<Text color="primary500" css={{ py: "$32" }}>
You can change the board configurations still later inside your retro board.
</Text>
<Flex direction="column" gap="24">
<Flex gap="16">
<Switch checked={board.hideCards} onCheckedChange={handleHideCardsChange}>
<SwitchThumb>
{board.hideCards && (
<CheckIcon css={{ size: "$10", color: "$successBase !important" }} />
)}
</SwitchThumb>
</Switch>
<Flex direction="column">
<Text size="md" weight="medium">
Hide cards from others
</Text>
<Text size="sm" color="primary500">
Participants can not see the cards from other participants of this retrospective.
</Text>
</Flex>
</Flex>
<Flex gap="16">
<Switch checked={board.hideVotes} onCheckedChange={handleHideVotesChange}>
<SwitchThumb>
{board.hideVotes && (
<CheckIcon css={{ size: "$10", color: "$successBase !important" }} />
)}
</SwitchThumb>
</Switch>
<Flex direction="column">
<Text size="md" weight="medium">
Hide votes from others
</Text>
<Text size="sm" color="primary500">
Participants can not see the votes from other participants of this retrospective.
</Text>
</Flex>
</Flex>
<Flex gap="16">
<Switch checked={board.postAnonymously} onCheckedChange={handlePostAnonymouslyChange}>
<SwitchThumb>
{board.postAnonymously && (
<CheckIcon css={{ size: "$10", color: "$successBase !important" }} />
)}
</SwitchThumb>
</Switch>
<Flex direction="column">
<Text size="md" weight="medium">
Option to post cards anonymously
</Text>
<Text size="sm" color="primary500">
Participants can decide to post cards anonymously or publicly (Name on card is
disabled/enabled.)
</Text>
</Flex>
</Flex>
<Flex gap="16">
<Switch checked={!!board.maxVotes} onCheckedChange={handleLimitVotesChange}>
<SwitchThumb>
{!!board.maxVotes && (
<CheckIcon css={{ size: "$10", color: "$successBase !important" }} />
)}
</SwitchThumb>
</Switch>
<Flex direction="column">
<Text size="md" weight="medium">
Limit votes
</Text>
<Text size="sm" color="primary500">
Make votes more significant by limiting them.
</Text>
<Input
css={{ mt: "$8" }}
id="maxVotes"
disabled={!board.maxVotes}
type="number"
placeholder="Max votes"
/>
</Flex>
</Flex>
</Flex>
</Flex>
);
};

export default BoardConfigurations;
49 changes: 44 additions & 5 deletions frontend/components/CreateBoard/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm, FormProvider, useWatch } from "react-hook-form";
import { SetterOrUpdater, useRecoilValue } from "recoil";
import { SetterOrUpdater, useRecoilValue, useResetRecoilState } from "recoil";
import ClickEvent from "../../types/events/clickEvent";
import Flex from "../Primitives/Flex";
import { styled } from "../../stitches.config";
Expand All @@ -9,20 +10,24 @@ import Button from "../Primitives/Button";
import BoardName from "./BoardName";
import { createBoardDataState } from "../../store/createBoard/atoms/create-board.atom";
import SettingsTabs from "./SettingsTabs";
import useBoard from "../../hooks/useBoard";
import { CreateBoardDto } from "../../types/board/board";

const StyledForm = styled("form", Flex, {});

const CreateBoardContent: React.FC<{ setOpened: SetterOrUpdater<boolean> }> = ({ setOpened }) => {
const boardState = useRecoilValue(createBoardDataState);
const resetBoardState = useResetRecoilState(createBoardDataState);
const {
board: { maxVotes },
} = useRecoilValue(createBoardDataState);
createBoard: { status, mutate },
} = useBoard({ autoFetchBoard: false });

const methods = useForm<{ text: string; maxVotes: string }>({
mode: "onBlur",
reValidateMode: "onBlur",
defaultValues: {
text: "Main board -",
maxVotes: maxVotes ?? "",
maxVotes: String(boardState.board.maxVotes) ?? "",
},
resolver: zodResolver(SchemaCreateBoard),
});
Expand All @@ -37,11 +42,45 @@ const CreateBoardContent: React.FC<{ setOpened: SetterOrUpdater<boolean> }> = ({
setOpened(false);
};

const saveBoard = (title: string, maxVotes: string) => {
const newDividedBoards: CreateBoardDto[] = boardState.board.dividedBoards.map((subBoard) => {
const newSubBoard: CreateBoardDto = { ...subBoard, users: [], dividedBoards: [] };
newSubBoard.hideCards = boardState.board.hideCards;
newSubBoard.hideVotes = boardState.board.hideVotes;
newSubBoard.postAnonymously = boardState.board.postAnonymously;
newSubBoard.maxVotes = maxVotes;
const users = subBoard.users.map((boardUser) => ({
user: boardUser.user._id,
role: boardUser.role,
}));
newSubBoard.users = users;
return newSubBoard;
});

mutate({
...boardState.board,
users: boardState.users,
title,
dividedBoards: newDividedBoards,
maxVotes,
maxUsers: boardState.count.maxUsersCount.toString(),
});
};

useEffect(() => {
if (status === "success") {
setOpened(false);
resetBoardState();
}
}, [status, setOpened, resetBoardState]);

return (
<StyledForm
direction="column"
css={{ width: "100%", height: "100%", backgroundColor: "$background" }}
onSubmit={methods.handleSubmit(() => {})}
onSubmit={methods.handleSubmit(({ text, maxVotes }) => {
saveBoard(text, maxVotes);
})}
>
<Flex
direction="column"
Expand Down
8 changes: 8 additions & 0 deletions frontend/components/CreateBoard/SettingsTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import QueryError from "../Errors/QueryError";
import Flex from "../Primitives/Flex";
import Separator from "../Primitives/Separator";
import Text from "../Primitives/Text";
import BoardConfigurations from "./Configurations/BoardConfigurations";
import TeamSubTeamsConfigurations from "./SubTeamsTab/TeamSubTeamsConfigurations";

const StyledTextTab = styled(Text, {
Expand Down Expand Up @@ -68,6 +69,13 @@ const SettingsTabs = () => {
</QueryError>
</Suspense>
)}
{currentTab === 2 && (
<Suspense fallback={<TailSpin height={80} width={80} color="#060D16" />}>
<QueryError>
<BoardConfigurations />
</QueryError>
</Suspense>
)}
</Flex>
);
};
Expand Down
22 changes: 11 additions & 11 deletions frontend/components/CreateBoard/SubTeamsTab/SubCardBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ const SubCardBoard: React.FC<SubCardBoardProps> = ({ board, index, setBoard }) =
orientation="vertical"
css={{ "&[data-orientation=vertical]": { height: "$12", width: 1 } }}
/>
<Flex
css={{
borderRadius: "$round",
p: "4px",
border: "1px solid $colors$primary400",
ml: "$12",
}}
onClick={handleLottery}
>
<WandIcon />
</Flex>
<Text size="sm" color="primary300" css={{ mx: "$8" }}>
{responsible?.firstName} {responsible?.lastName}
</Text>
Expand All @@ -94,17 +105,6 @@ const SubCardBoard: React.FC<SubCardBoardProps> = ({ board, index, setBoard }) =
}}
fallbackText={`${responsible?.firstName[0]}${responsible?.lastName[0]}`}
/>
<Flex
css={{
borderRadius: "$round",
p: "4px",
border: "1px solid $colors$primary400",
ml: "$8",
}}
onClick={handleLottery}
>
<WandIcon />
</Flex>
</Flex>
</Flex>
<Flex align="center" gap="8">
Expand Down
32 changes: 32 additions & 0 deletions frontend/components/Primitives/Switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as SwitchPrimitive from "@radix-ui/react-switch";
import { styled } from "../../stitches.config";
import Flex from "./Flex";

const StyledSwitch = styled(SwitchPrimitive.Root, {
all: "unset",
width: 42,
height: 24,
display: "flex",
backgroundColor: "$primary200",
borderRadius: "9999px",
position: "relative",
WebkitTapHighlightColor: "rgba(0, 0, 0, 0)",
'&[data-state="checked"]': { backgroundColor: "$successBase" },
boxSizing: "border-box",
});

const StyledThumb = styled(SwitchPrimitive.Thumb, Flex, {
justifyContent: "center",
alignItems: "center",
width: 21,
height: 21,
backgroundColor: "white",
borderRadius: "9999px",
transition: "transform 100ms",
transform: "translate(1.5px, 1.5px)",
willChange: "transform",
'&[data-state="checked"]': { transform: "translate(19px, 1.5px)" },
});

export const Switch = StyledSwitch;
export const SwitchThumb = StyledThumb;
23 changes: 14 additions & 9 deletions frontend/components/icons/Check.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import React from "react";
import { CSSProps } from "../../stitches.config";
import Svg from "../Primitives/Svg";

const CheckIcon = () => {
const CheckIcon = ({ css }: CSSProps) => {
return (
<svg
preserveAspectRatio="xMidYMin meet"
width="6px"
height="6px"
viewBox="0 0 6px 6px"
fill="none"
<Svg
width="24"
css={css}
height="24"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="3" cy="3" r="3" fill="#A235FF" />
</svg>
<path
d="M20.7364 5.65424C20.385 5.30275 19.8151 5.30275 19.4636 5.65424L8.68106 16.4369L4.53642 12.2923C4.18496 11.9408 3.61515 11.9408 3.26362 12.2923C2.91213 12.6437 2.91213 13.2135 3.26362 13.565L8.04466 18.346C8.39601 18.6975 8.96624 18.6972 9.31746 18.346L20.7364 6.92704C21.0879 6.57558 21.0879 6.00574 20.7364 5.65424Z"
fill="currentColor"
/>
</Svg>
);
};

Expand Down
4 changes: 2 additions & 2 deletions frontend/types/board/useBoard.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { UseMutationResult, UseQueryResult } from "react-query";
import BoardType, { BoardToAdd } from "./board";
import BoardType, { CreateBoardDto } from "./board";
import UpdateBoardDto from "./updateBoard";

export default interface UseBoardType {
createBoard: UseMutationResult<BoardType, unknown, BoardToAdd, unknown>;
createBoard: UseMutationResult<BoardType, unknown, CreateBoardDto, unknown>;
updateBoard: UseMutationResult<BoardType, unknown, UpdateBoardDto, unknown>;
deleteBoard: UseMutationResult<BoardType, unknown, string, unknown>;
fetchBoard: UseQueryResult<BoardType | null, unknown>;
Expand Down