Skip to content

Commit 0a2f9ec

Browse files
authored
Merge pull request #319 from boostcampwm2023/feature/backlog-finished-page
feat: 완료된 스토리 페이지 구현
2 parents d9d44e9 + 5105635 commit 0a2f9ec

File tree

4 files changed

+72
-11
lines changed

4 files changed

+72
-11
lines changed

frontend/src/AppRouter.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import LandingPage from "./pages/landing/LandingPage";
2121
import InvitePage from "./pages/invite/InvitePage";
2222
import UnfinishedStoryPage from "./pages/backlog/UnfinishedStoryPage";
2323
import BacklogPage from "./pages/backlog/BacklogPage";
24+
import FinishedStoryPage from "./pages/backlog/FinishedStoryPage";
2425

2526
type RouteType = "PRIVATE" | "PUBLIC";
2627

@@ -89,7 +90,7 @@ const router = createBrowserRouter([
8990
},
9091
{
9192
path: ROUTER_URL.BACKLOG.COMPLETED,
92-
element: <div>backlog completed story Page</div>,
93+
element: <FinishedStoryPage />,
9394
},
9495
],
9596
element: <BacklogPage />,

frontend/src/components/backlog/StoryBlock.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ interface StoryBlockProps {
3030
children: React.ReactNode;
3131
taskExist: boolean;
3232
epicList: EpicCategoryDTO[];
33+
finished?: boolean;
3334
}
3435

3536
const StoryBlock = ({
@@ -41,6 +42,7 @@ const StoryBlock = ({
4142
status,
4243
taskExist,
4344
epicList,
45+
finished = false,
4446
children,
4547
}: StoryBlockProps) => {
4648
const { socket }: { socket: Socket } = useOutletContext();
@@ -277,7 +279,7 @@ const StoryBlock = ({
277279
<TaskContainer>
278280
<TaskHeader />
279281
{children}
280-
<TaskCreateBlock storyId={id} />
282+
{!finished && <TaskCreateBlock storyId={id} />}
281283
</TaskContainer>
282284
)}
283285
</>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useOutletContext } from "react-router-dom";
2+
import { BacklogDTO } from "../../types/DTO/backlogDTO";
3+
import { useMemo } from "react";
4+
import StoryBlock from "../../components/backlog/StoryBlock";
5+
import changeEpicListToStoryList from "../../utils/changeEpicListToStoryList";
6+
import TaskBlock from "../../components/backlog/TaskBlock";
7+
8+
const FinishedStoryPage = () => {
9+
const { backlog }: { backlog: BacklogDTO } = useOutletContext();
10+
const storyList = useMemo(
11+
() =>
12+
changeEpicListToStoryList(backlog.epicList).filter(
13+
({ status }) => status === "완료"
14+
),
15+
[backlog.epicList]
16+
);
17+
const epicCategoryList = useMemo(
18+
() => backlog.epicList.map(({ id, name, color }) => ({ id, name, color })),
19+
[backlog.epicList]
20+
);
21+
22+
return (
23+
<div className="flex flex-col items-center gap-4">
24+
<div className="w-full border-b">
25+
{...storyList.map(({ id, epic, title, point, status, taskList }) => {
26+
const progress = taskList.length
27+
? Math.round(
28+
(taskList.filter(({ status }) => status === "완료").length /
29+
taskList.length) *
30+
100
31+
)
32+
: 0;
33+
34+
return (
35+
<StoryBlock
36+
{...{ id, title, point, status }}
37+
epic={epic}
38+
progress={progress}
39+
taskExist={taskList.length > 0}
40+
epicList={epicCategoryList}
41+
finished={true}
42+
>
43+
{...taskList.map((task) => <TaskBlock {...task} />)}
44+
</StoryBlock>
45+
);
46+
})}
47+
</div>
48+
</div>
49+
);
50+
};
51+
52+
export default FinishedStoryPage;

frontend/src/stores/useMemberStore.ts

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { create } from "zustand";
22
import { LandingMemberDTO, MemberStatus } from "../types/DTO/landingDTO";
3+
import { createJSONStorage, persist } from "zustand/middleware";
34

45
interface InitialMemberState {
56
myInfo: LandingMemberDTO;
@@ -18,14 +19,19 @@ const initialState: InitialMemberState = {
1819
memberList: [],
1920
};
2021

21-
const useMemberStore = create<MemberState>((set) => ({
22-
...initialState,
23-
updateMyInfo: (newMyInfo) => set(() => ({ myInfo: newMyInfo })),
24-
updateMyStatus: (status) =>
25-
set((state) => ({ myInfo: { ...state.myInfo, status } })),
26-
updateMemberList: (newMember) => set({ memberList: newMember }),
27-
addMember: (member) =>
28-
set((state) => ({ memberList: [...state.memberList, member] })),
29-
}));
22+
const useMemberStore = create<MemberState>()(
23+
persist(
24+
(set) => ({
25+
...initialState,
26+
updateMyInfo: (newMyInfo) => set(() => ({ myInfo: newMyInfo })),
27+
updateMyStatus: (status) =>
28+
set((state) => ({ myInfo: { ...state.myInfo, status } })),
29+
updateMemberList: (newMember) => set({ memberList: newMember }),
30+
addMember: (member) =>
31+
set((state) => ({ memberList: [...state.memberList, member] })),
32+
}),
33+
{ name: "member-storage", storage: createJSONStorage(() => sessionStorage) }
34+
)
35+
);
3036

3137
export default useMemberStore;

0 commit comments

Comments
 (0)