({});
+
+ const handleClickCheckBox = (e: React.MouseEvent) => {
+ const target = e.target as HTMLInputElement;
+ const checkNumber = target.id;
+ if (checkNumber === '') return;
+
+ const toggleBoolean = isChecked[checkNumber] === true ? false : true;
+ if (toggleBoolean)
+ setQuery({
+ ...query,
+ closed: null,
+ milestone: Number(checkNumber),
+ });
+
+ setChecked({
+ ...isChecked,
+ [checkNumber]: toggleBoolean,
+ });
+ };
return (
마일스톤 필터
{data.map(({ id, title }) => {
return (
-
}>
+
+
diff --git a/FE/issue-tracker/src/components/issues/tableMain/Issue.tsx b/FE/issue-tracker/src/components/issues/tableMain/Issue.tsx
index 21e70a2b3..55b6247e6 100644
--- a/FE/issue-tracker/src/components/issues/tableMain/Issue.tsx
+++ b/FE/issue-tracker/src/components/issues/tableMain/Issue.tsx
@@ -1,3 +1,4 @@
+import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { Avatar } from '@chakra-ui/avatar';
@@ -44,13 +45,18 @@ function Issue({ info }: Props) {
getRenderingText
)(created_time);
+ const linkPath = {
+ pathname: `/issues/detail/${id}`,
+ };
return (
- {title}
+
+ {title}
+
{label_list.map(({ id, title, color_code }) => (
-
+
diff --git a/FE/issue-tracker/src/components/issues/tableMain/IssueList.tsx b/FE/issue-tracker/src/components/issues/tableMain/IssueList.tsx
index 7865c4c3d..550bb886a 100644
--- a/FE/issue-tracker/src/components/issues/tableMain/IssueList.tsx
+++ b/FE/issue-tracker/src/components/issues/tableMain/IssueList.tsx
@@ -1,12 +1,12 @@
import { useRecoilValue, useRecoilValueLoadable } from 'recoil';
import { queryString, wholeIssueLists } from '@store/atoms/issueList';
+import { pushState } from '@utils/query';
import { IssueSkeleton } from '@components/common/Skeleton';
import Issue from './Issue';
import ErrorIssueList from './ErrorIssueList';
import NoIssue from './NoIssue';
-import { pushState } from '@utils/query';
function IssueList() {
const query = useRecoilValue(queryString);
@@ -17,7 +17,6 @@ function IssueList() {
return ;
}
};
- console.log(contents);
pushState(query);
return (
<>
From 8da2ae5e74d923ed0beab97129876e6464fe86ee Mon Sep 17 00:00:00 2001
From: somedaycode
Date: Tue, 22 Jun 2021 18:47:55 +0900
Subject: [PATCH 088/157] =?UTF-8?q?Feat:=20=EC=9D=B4=EC=8A=88=20=EC=83=81?=
=?UTF-8?q?=EC=84=B8=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=8E=B8=EC=A7=91?=
=?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C?=
=?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 버튼 클릭시 patch 요청을 보낸다
---
.../src/components/issueDetail/TextArea.tsx | 128 ++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 FE/issue-tracker/src/components/issueDetail/TextArea.tsx
diff --git a/FE/issue-tracker/src/components/issueDetail/TextArea.tsx b/FE/issue-tracker/src/components/issueDetail/TextArea.tsx
new file mode 100644
index 000000000..dcf0d7ebc
--- /dev/null
+++ b/FE/issue-tracker/src/components/issueDetail/TextArea.tsx
@@ -0,0 +1,128 @@
+import { useParams } from 'react-router-dom';
+import { ChangeEvent, useState } from 'react';
+import styled from 'styled-components';
+
+import { Button, Textarea } from '@chakra-ui/react';
+import { ReactComponent as FileIcon } from '@assets/file.svg';
+
+import type { Param } from '@pages/IssueDetail';
+import { contentsInput } from '@components/newIssue/style';
+import { fetchWithAuth } from '@utils/fetchWithAuth';
+import { issueAPI } from '@const/var';
+
+type Prop = {
+ commentID: number;
+ value: string;
+};
+
+function TextArea({ value, commentID }: Prop) {
+ const { id }: Param = useParams();
+ const [commentValue, SetCommentValue] = useState(value);
+
+ const handleOnChangeText = (e: ChangeEvent) => {
+ const target = e.target as HTMLTextAreaElement;
+ SetCommentValue(target.value);
+ };
+
+ const handleClickEditComplete = () => {
+ const finishEdit = async () => {
+ const url = `${issueAPI}/${id}/comments/${commentID}`;
+ await fetchWithAuth(url, '이슈 내용 수정 오류', {
+ method: 'PATCH',
+ 'Content-Type': 'application/json',
+ body: { description: `${commentValue}` },
+ });
+ };
+ finishEdit();
+ };
+
+ return (
+ <>
+
+
+ 띄어쓰기 포함 {commentValue.length}자
+
+
+ 파일 첨부하기
+
+
+
+
+
+
+ >
+ );
+}
+
+export default TextArea;
+
+const Description = styled.div`
+ margin-bottom: 12px;
+ position: relative;
+ background: ${({ theme }) => theme.colors.gr_offWhite};
+ border-radius: 0 0 ${({ theme }) => theme.radii['2xl']}
+ ${({ theme }) => theme.radii['2xl']};
+ border: 1px solid ${({ theme }) => theme.colors.gr_line};
+ &:hover {
+ border: 1px solid ${({ theme }) => theme.colors.bl_initial};
+ }
+`;
+
+const Span = styled.div`
+ right: 30px;
+ bottom: 72px;
+ font-size: ${({ theme }) => theme.fontSizes.xs};
+ font-weight: ${({ theme }) => theme.fontWeights.medium};
+ color: ${({ theme }) => theme.colors.gr_label};
+ position: absolute;
+`;
+
+const ImageUploadWrap = styled.div`
+ display: flex;
+ align-items: center;
+ padding: 16px 24px;
+ height: 52px;
+ color: ${({ theme }) => theme.colors.gr_label};
+ font-weight: ${({ theme }) => theme.fontWeights.bold};
+ border-top: 1px dotted ${({ theme }) => theme.colors.gr_line};
+ cursor: pointer;
+
+ span {
+ padding-left: 10px;
+ }
+`;
+
+const btnStyle = {
+ width: '120px',
+ padding: '16px',
+ fontSize: 'xs',
+};
+
+const completeButton = {
+ ...btnStyle,
+ background: 'bl_initial',
+ colorScheme: 'blue',
+ color: 'white',
+};
+
+const deleteButton = {
+ ...btnStyle,
+ marginRight: '16px',
+ background: 'gr_offWhite',
+ colorScheme: 'whiteAlpha',
+ color: 'bl_initial',
+ border: '1px',
+ borderColor: 'bl_initial',
+};
+
+const ButtonBox = styled.div`
+ margin-bottom: 24px;
+ display: flex;
+ flex-direction: row-reverse;
+`;
From b44ddc66b8472a1944815a8c262dc379af13da2c Mon Sep 17 00:00:00 2001
From: somedaycode
Date: Tue, 22 Jun 2021 18:49:27 +0900
Subject: [PATCH 089/157] =?UTF-8?q?Feat:=20#72=20=EC=9D=B4=EC=8A=88=20?=
=?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20?=
=?UTF-8?q?=EB=B0=9B=EC=95=84=EC=84=9C=20=EC=B6=9C=EB=A0=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/issueDetail/IssueHeader.tsx | 64 +++++++++++++++----
1 file changed, 53 insertions(+), 11 deletions(-)
diff --git a/FE/issue-tracker/src/components/issueDetail/IssueHeader.tsx b/FE/issue-tracker/src/components/issueDetail/IssueHeader.tsx
index 468c09e2f..b69860a0f 100644
--- a/FE/issue-tracker/src/components/issueDetail/IssueHeader.tsx
+++ b/FE/issue-tracker/src/components/issueDetail/IssueHeader.tsx
@@ -1,28 +1,70 @@
+import { useRecoilValue } from 'recoil';
+import { useParams } from 'react-router-dom';
import styled from 'styled-components';
+
import { Button } from '@chakra-ui/react';
import { ReactComponent as EditIcon } from '@assets/edit.svg';
import { ReactComponent as CloseIcon } from '@assets/archive.svg';
import { ReactComponent as AlertIcon } from '@assets/alert.svg';
+import { issueDetailComment, issueDetailList } from '@store/atoms/issueDetail';
+import pipe from '@utils/pipe';
+import {
+ checkIfDayPassedFromCreation,
+ getCreatedTime,
+ getRenderingText,
+ getTime,
+ getTimeGapFromCreation,
+ getTotalMinutesBetweenGap,
+} from '@utils/renderTimeText';
+
+import type { Param } from '@pages/IssueDetail';
+
function IssueHeader() {
- const issueTitle = 'FE 이슈트래커 디자인 시스템 구현';
- const issueNumber = '#2';
- const issueInfo = '이 이슈가 20분 전에 Oni님에 의해 열렸습니다 • 코멘트 1개';
+ const { id }: Param = useParams();
+ const issueData = useRecoilValue(issueDetailList(id));
+
+ const {
+ assignee,
+ author_user_id,
+ closed,
+ created_time,
+ description,
+ issue_number,
+ label_list,
+ milestone,
+ title,
+ } = issueData;
+
+ const currentTime = new Date().getTime();
+ const timePassed = pipe(
+ getCreatedTime,
+ getTimeGapFromCreation(currentTime),
+ getTotalMinutesBetweenGap,
+ checkIfDayPassedFromCreation,
+ getTime,
+ getRenderingText
+ )(created_time);
+
+ const issueInfo = `이 이슈가 ${timePassed}에 ${''}님에 의해 열렸습니다 • 코멘트 1개`;
return (
- {issueTitle}
- {issueNumber}
+ {title}
+ #{issue_number}
-
- 열린 이슈
-
-
- 닫힌 이슈
-
+ {closed ? (
+
+ 닫힌 이슈
+
+ ) : (
+
+ 열린 이슈
+
+ )}
{issueInfo}
From 2b443bfe9d502c359b65b2ad7a4a8a0aa32bcaa2 Mon Sep 17 00:00:00 2001
From: somedaycode
Date: Tue, 22 Jun 2021 18:49:46 +0900
Subject: [PATCH 090/157] =?UTF-8?q?Chore:=20=EC=BD=94=EB=93=9C=20=EB=9D=BC?=
=?UTF-8?q?=EC=9D=B8=20=EA=B9=94=EB=81=94=ED=95=98=EA=B2=8C=20=EB=B3=80?=
=?UTF-8?q?=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/components/issueDetail/NewComment.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/FE/issue-tracker/src/components/issueDetail/NewComment.tsx b/FE/issue-tracker/src/components/issueDetail/NewComment.tsx
index 2b41ad8cc..a3910924c 100644
--- a/FE/issue-tracker/src/components/issueDetail/NewComment.tsx
+++ b/FE/issue-tracker/src/components/issueDetail/NewComment.tsx
@@ -1,4 +1,5 @@
import styled from 'styled-components';
+
import { Avatar } from '@chakra-ui/react';
import TextBox from '@components/newIssue/TextBox';
From e91d1ec7e956f74d158f3f886f7add09f8ea84fb Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 18:50:58 +0900
Subject: [PATCH 091/157] =?UTF-8?q?Fix:=20#38=20=EB=94=94=EC=BD=94?=
=?UTF-8?q?=EB=93=9C=EB=90=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95?=
=?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EB=A1=9C=EC=BB=AC=20=EC=8A=A4=ED=86=A0?=
=?UTF-8?q?=EB=A6=AC=EC=A7=80=20=EC=A0=80=EC=9E=A5=EB=B0=A9=EC=8B=9D?=
=?UTF-8?q?=EC=97=90=EC=84=9C=20atom=20=EC=A0=84=EC=97=AD=20=EC=83=81?=
=?UTF-8?q?=ED=83=9C=20=EC=A0=80=EC=9E=A5=EC=9C=BC=EB=A1=9C=20=EB=B3=80?=
=?UTF-8?q?=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 로컬스토리지가 아닌 전역 상태에 정보를 저장하기 위해 새로고침을 하지 않는 방식으로 변경
* window.location.href 방식에서 useHistory를 사용하는 history.push로 변경
---
.../login/{getAccessToken.ts => fetchToken.ts} | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
rename FE/issue-tracker/src/components/login/{getAccessToken.ts => fetchToken.ts} (73%)
diff --git a/FE/issue-tracker/src/components/login/getAccessToken.ts b/FE/issue-tracker/src/components/login/fetchToken.ts
similarity index 73%
rename from FE/issue-tracker/src/components/login/getAccessToken.ts
rename to FE/issue-tracker/src/components/login/fetchToken.ts
index 560b71f53..9644b7155 100644
--- a/FE/issue-tracker/src/components/login/getAccessToken.ts
+++ b/FE/issue-tracker/src/components/login/fetchToken.ts
@@ -1,5 +1,7 @@
+import React from 'react';
import jwt_decode from 'jwt-decode';
import { TOKEN_URL } from '@const/var';
+import { loginInfoType } from '@store/atoms/login';
type decodedType = {
avatar_url: string;
@@ -19,21 +21,21 @@ const getDecodedOauthToken = (jwt: string) => {
};
type Arg = {
- isLogin: boolean;
setIsLogin: (state: boolean) => void;
+ setLoginInfo: (state: loginInfoType) => void;
code: string;
+ history: any;
};
-const fetchToken = async ({ isLogin, setIsLogin, code }: Arg) => {
- if (isLogin) return;
+const fetchToken = async ({ setIsLogin, setLoginInfo, code, history }: Arg) => {
try {
const response = await fetch(TOKEN_URL + code);
const { jwt } = await response.json();
const decodedOauthToken = getDecodedOauthToken(jwt);
localStorage.setItem('oauth_login_token', jwt);
- localStorage.setItem('login_info', JSON.stringify(decodedOauthToken));
+ setLoginInfo(decodedOauthToken);
setIsLogin(true);
- window.location.href = '/issues';
+ history.push('/issues');
} catch (error) {
console.error('getAccessToken Error');
}
From d45e9ac4db74697e2acf14c0089d0b02e8dba339 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 18:51:34 +0900
Subject: [PATCH 092/157] =?UTF-8?q?Chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?=
=?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?=
=?UTF-8?q?=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/components/login/fetchToken.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/FE/issue-tracker/src/components/login/fetchToken.ts b/FE/issue-tracker/src/components/login/fetchToken.ts
index 9644b7155..a5923596e 100644
--- a/FE/issue-tracker/src/components/login/fetchToken.ts
+++ b/FE/issue-tracker/src/components/login/fetchToken.ts
@@ -1,4 +1,3 @@
-import React from 'react';
import jwt_decode from 'jwt-decode';
import { TOKEN_URL } from '@const/var';
import { loginInfoType } from '@store/atoms/login';
From c0b70b1c5132a2d5ba7a2a73f1e32593f7de122d Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 18:54:21 +0900
Subject: [PATCH 093/157] =?UTF-8?q?Feat:=20#38=20=EB=A1=9C=EA=B7=B8?=
=?UTF-8?q?=EC=9D=B8=20=EC=8B=9C=20url=20=EC=9D=B4=EB=8F=99=EC=9D=84=20?=
=?UTF-8?q?=EC=9C=84=ED=95=9C=20useHistory=20=EC=82=AC=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/login/LoginMain.tsx | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/FE/issue-tracker/src/components/login/LoginMain.tsx b/FE/issue-tracker/src/components/login/LoginMain.tsx
index 4cf34b93b..e20910e87 100644
--- a/FE/issue-tracker/src/components/login/LoginMain.tsx
+++ b/FE/issue-tracker/src/components/login/LoginMain.tsx
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from 'react';
-import { Link } from 'react-router-dom';
+import { Link, useHistory } from 'react-router-dom';
import styled from 'styled-components';
import queryString from 'query-string';
+import { useRecoilState, useSetRecoilState } from 'recoil';
import { Button } from '@chakra-ui/button';
import { Stack } from '@chakra-ui/layout';
@@ -10,7 +11,8 @@ import { LinkBox, LinkOverlay } from '@chakra-ui/react';
import { ReactComponent as LogoLarge } from '@assets/LogotypeLarge.svg';
import { LOGIN_URL } from '@const/var';
-import fetchToken from './getAccessToken';
+import fetchToken from './fetchToken';
+import { isLoginState, loginInfoState } from '@store/atoms/login';
import {
gitLoginStyle,
activeLoginStyle,
@@ -22,8 +24,10 @@ function LoginMain() {
const [isLoginActive, setIsActiveLogin] = useState(false);
const [isInputtedID, setIsInputtedID] = useState(false);
const [isInputtedPW, setIsInputtedPW] = useState(false);
- const [isLogin, setIsLogin] = useState(false);
+ const [isLogin, setIsLogin] = useRecoilState(isLoginState);
+ const setLoginInfo = useSetRecoilState(loginInfoState);
const [password, setPassword] = useState('');
+ const history = useHistory();
const handleChangeID = (e: React.ChangeEvent) => {
const target = e.target as HTMLInputElement;
@@ -46,8 +50,8 @@ function LoginMain() {
useEffect(() => {
const { code } = queryString.parse(window.location.search);
if (!code) return;
- else if (typeof code === 'string') {
- fetchToken({ isLogin, setIsLogin, code });
+ else if (typeof code === 'string' && !isLogin) {
+ fetchToken({ setIsLogin, setLoginInfo, code, history });
}
}, []);
From 5efc0aeb74e994e60c1047bb9aa621ab8df7949b Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 18:54:46 +0900
Subject: [PATCH 094/157] =?UTF-8?q?Feat:=20#38=20=EB=A1=9C=EA=B7=B8?=
=?UTF-8?q?=EC=9D=B8=20=EC=A0=84=EC=97=AD=EC=83=81=ED=83=9C=20=EC=83=9D?=
=?UTF-8?q?=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/store/atoms/login.ts | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 FE/issue-tracker/src/store/atoms/login.ts
diff --git a/FE/issue-tracker/src/store/atoms/login.ts b/FE/issue-tracker/src/store/atoms/login.ts
new file mode 100644
index 000000000..6ec2a1c7c
--- /dev/null
+++ b/FE/issue-tracker/src/store/atoms/login.ts
@@ -0,0 +1,17 @@
+import { atom } from 'recoil';
+
+export type loginInfoType = {
+ name: string;
+ avatar_url: string;
+ id: number | null;
+};
+
+export const isLoginState = atom({
+ key: 'isLoginState',
+ default: false,
+});
+
+export const loginInfoState = atom({
+ key: 'loginInfoState',
+ default: { name: '', avatar_url: '', id: null },
+});
From a084cf77b54241f53377b0d073686862822bc8ad Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:00:52 +0900
Subject: [PATCH 095/157] =?UTF-8?q?Feat:=20#39=20=EC=84=A0=ED=83=9D?=
=?UTF-8?q?=EB=90=9C=20label,=20milestone,=20assignee=EC=97=90=20=EB=8C=80?=
=?UTF-8?q?=ED=95=9C=20atom=20=EC=83=81=ED=83=9C=20=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/store/atoms/checkedThings.ts | 27 ++++++++++++-------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/FE/issue-tracker/src/store/atoms/checkedThings.ts b/FE/issue-tracker/src/store/atoms/checkedThings.ts
index 41ed48764..8bdf26210 100644
--- a/FE/issue-tracker/src/store/atoms/checkedThings.ts
+++ b/FE/issue-tracker/src/store/atoms/checkedThings.ts
@@ -1,24 +1,33 @@
import { atom } from 'recoil';
+export type labelType = {
+ id: number;
+ title: string;
+ description: string;
+ color_code: string;
+ font_light: boolean;
+};
+
+export type milestoneType = {
+ id: number;
+ title: string;
+ description: string;
+ due_date: string;
+ opened_issue_count: number;
+ closed_issue_count: number;
+};
+
export const checkedAssigneesState = atom({
key: 'checkedAssignees',
default: [],
});
-type labelType = {
- id: string;
- index: string;
- title: string;
- color_code: string;
- font_light: string;
-};
-
export const checkedLabelsState = atom({
key: 'checkedLabels',
default: [],
});
-export const checkedMilestoneState = atom({
+export const checkedMilestoneState = atom({
key: 'checkedMilestone',
default: null,
});
From c406ba44ba0bb9d0d4d325f736dd1bd37d3e6d0f Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:01:38 +0900
Subject: [PATCH 096/157] =?UTF-8?q?Fix:=20#39=20fetch=20=EC=9A=94=EC=B2=AD?=
=?UTF-8?q?=EC=9D=84=20=EB=B3=B4=EB=82=BC=20=EB=95=8C=20=ED=97=A4=EB=8D=94?=
=?UTF-8?q?=EC=97=90=20jwt=ED=86=A0=ED=81=B0=20=EB=8B=B4=EC=95=84=EC=84=9C?=
=?UTF-8?q?=20=EB=B3=B4=EB=82=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/utils/fetchModal.ts | 25 +++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/FE/issue-tracker/src/utils/fetchModal.ts b/FE/issue-tracker/src/utils/fetchModal.ts
index 3fadd3ddc..3f2541348 100644
--- a/FE/issue-tracker/src/utils/fetchModal.ts
+++ b/FE/issue-tracker/src/utils/fetchModal.ts
@@ -3,23 +3,38 @@ import { baseURL } from '@const/var';
type fetchModalType = {
path: string;
setState: (state: any) => void;
+ setErrorMsg: (state: any) => void;
};
const handleError = (status: number) => {
if (status >= 400 && status < 500) throw `💢 에러!!!(${status})`;
- else if (status >= 500) throw '🚨 서버 확인!!!';
+ else if (status >= 500) throw `🚨 서버 확인!!!(${status})`;
};
-export const fetchModal = async ({ path, setState }: fetchModalType) => {
+const getHeaders = (): any => {
+ const oauthToken = localStorage.getItem('oauth_login_token');
+ return {
+ headers: {
+ Authorization: `bearer ${oauthToken}`,
+ },
+ };
+};
+
+export const fetchModal = async ({
+ path,
+ setState,
+ setErrorMsg,
+}: fetchModalType) => {
try {
- const res = await fetch(`${baseURL}/${path}`);
+ const res = await fetch(`${baseURL}/${path}`, getHeaders());
handleError(res.status);
const json = await res.json();
setState(json);
+ setErrorMsg('No Error');
} catch (error) {
- if (typeof error === 'string') throw error;
+ if (typeof error === 'string') throw setErrorMsg(error);
else {
- throw '🔺 요청 주소 확인!!';
+ throw setErrorMsg('🔺 요청 주소 확인!!');
}
}
};
From 66f9f30386cdc7c2e9a5d3f7a7717fd7d1282d97 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:02:16 +0900
Subject: [PATCH 097/157] =?UTF-8?q?Feat:=20#39=20SelecBox=EC=9D=98=20?=
=?UTF-8?q?=EB=A9=94=EB=89=B4=20=EC=95=84=EC=9D=B4=ED=85=9C=20=ED=81=B4?=
=?UTF-8?q?=EB=A6=AD=ED=96=88=EC=9D=84=20=EB=95=8C=20=EC=83=81=ED=83=9C=20?=
=?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98?=
=?UTF-8?q?=EB=93=A4=20=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/utils/onClickMenuItem.ts | 95 +++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 FE/issue-tracker/src/utils/onClickMenuItem.ts
diff --git a/FE/issue-tracker/src/utils/onClickMenuItem.ts b/FE/issue-tracker/src/utils/onClickMenuItem.ts
new file mode 100644
index 000000000..9ab8c976f
--- /dev/null
+++ b/FE/issue-tracker/src/utils/onClickMenuItem.ts
@@ -0,0 +1,95 @@
+import { labelType, milestoneType } from '@store/atoms/checkedThings';
+import {
+ getClickedItemInfoType,
+ setCheckedBooleanType,
+ setCheckedMenusItemType,
+ getCheckedIdType,
+ handleClickMenuItemType,
+} from './onClickMenuItem_types';
+
+// 클릭된 메뉴 아이템의 정보 반환
+const getClickedItemInfo = (args: getClickedItemInfoType) => {
+ const { menu, menuData, checkedId } = args;
+ let info: any;
+ if (menu === 'label')
+ info = menuData.find((label) => label.id === +checkedId) as labelType;
+ if (menu === 'milestone')
+ info = menuData.find(
+ (milestone) => milestone.id === +checkedId
+ ) as milestoneType;
+ // if(menu === "assignee")
+ return info;
+};
+
+// '아이템 클릭 여부' 상태 저장, 상태 반환
+const getAndSetIsItemChecked = (args: setCheckedBooleanType) => {
+ const { menu, checkedId, isChecked, setIsChecked } = args;
+ const isItemChecked = isChecked[checkedId] ? false : true;
+ if (menu === 'label') {
+ setIsChecked({
+ ...isChecked,
+ [checkedId]: isItemChecked,
+ });
+ } else {
+ setIsChecked({
+ [checkedId]: isItemChecked,
+ });
+ }
+ return isItemChecked;
+};
+
+// 아이템 클릭 여부에 따라 '클릭된 아이템' 상태 저장
+const setCheckedMenusItem = (args: setCheckedMenusItemType) => {
+ const { menu, isItemChecked, checkedMenus, setCheckedMenus, menuInfo } = args;
+ if (
+ menu === 'label' &&
+ checkedMenus !== null &&
+ Array.isArray(checkedMenus)
+ ) {
+ if (isItemChecked) setCheckedMenus([...checkedMenus, menuInfo]);
+ else
+ setCheckedMenus(checkedMenus.filter((menu) => menu.id !== menuInfo.id));
+ } else if (menu === 'milestone') {
+ if (isItemChecked) setCheckedMenus(menuInfo);
+ else setCheckedMenus(null);
+ }
+};
+
+// 선택된 요소가 체크박스가 아니면 얼리 리턴, 맞으면 chekedId 반환
+const getCheckedId = ({ target, menuData }: getCheckedIdType) => {
+ const menuItemEl = target.closest('.checkbox') as HTMLInputElement;
+ const checkedId = menuItemEl.dataset.id;
+ if (target.tagName !== 'INPUT' || menuData == null || checkedId == null)
+ return;
+ else return checkedId;
+};
+
+// 클릭된 아이템의 클릭여부, 정보를 상태에 저장
+const setIsCheckedAndCheckedItem = (args: handleClickMenuItemType) => {
+ const {
+ menu,
+ menuData,
+ checkedId,
+ isChecked,
+ setIsChecked,
+ checkedMenus,
+ setCheckedMenus,
+ } = args;
+ if (menuData == null) return;
+ const isItemChecked = getAndSetIsItemChecked({
+ menu,
+ checkedId,
+ isChecked,
+ setIsChecked,
+ });
+ const menuInfo = getClickedItemInfo({ menu, menuData, checkedId });
+ setCheckedMenusItem({
+ menu,
+ isItemChecked,
+ checkedMenus,
+ setCheckedMenus,
+ menuInfo,
+ });
+};
+
+export { getCheckedId, setIsCheckedAndCheckedItem };
From ad8aa3f462d1a527b52614c74b2fc74788a604b7 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:03:03 +0900
Subject: [PATCH 098/157] =?UTF-8?q?Feat:=20#39=20=EC=B2=B4=ED=81=AC?=
=?UTF-8?q?=EB=B0=95=EC=8A=A4=20=EB=A9=94=EB=89=B4=20=EC=95=84=EC=9D=B4?=
=?UTF-8?q?=ED=85=9C=20=EA=B4=80=EB=A0=A8=20=ED=95=A8=EC=88=98=EB=93=A4=20?=
=?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/utils/onClickMenuItem_types.ts | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 FE/issue-tracker/src/utils/onClickMenuItem_types.ts
diff --git a/FE/issue-tracker/src/utils/onClickMenuItem_types.ts b/FE/issue-tracker/src/utils/onClickMenuItem_types.ts
new file mode 100644
index 000000000..03e2a7ce3
--- /dev/null
+++ b/FE/issue-tracker/src/utils/onClickMenuItem_types.ts
@@ -0,0 +1,41 @@
+import { labelType, milestoneType } from '@store/atoms/checkedThings';
+
+export type getClickedItemInfoType = {
+ menu: string;
+ menuData: any[];
+ checkedId: string;
+};
+
+export type setCheckedBooleanType = {
+ menu: string;
+ checkedId: string;
+ isChecked: {
+ [id: string]: boolean;
+ };
+ setIsChecked: (state: any) => void;
+};
+
+export type setCheckedMenusItemType = {
+ menu: string;
+ isItemChecked: boolean;
+ checkedMenus: labelType[] | milestoneType | null;
+ setCheckedMenus: (state: any) => void;
+ menuInfo: { id: number };
+};
+
+export type getCheckedIdType = {
+ target: HTMLInputElement;
+ menuData: any[] | null;
+};
+
+export type handleClickMenuItemType = {
+ menu: string;
+ menuData: any[] | null;
+ checkedId: string;
+ isChecked: {
+ [id: string]: boolean;
+ };
+ setIsChecked: (state: any) => void;
+ checkedMenus: labelType[] | milestoneType | null;
+ setCheckedMenus: (state: any) => void;
+};
From d626a2fe757df7fd76fff4da0caf29cfebe1c052 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:03:51 +0900
Subject: [PATCH 099/157] =?UTF-8?q?Add:=20#39=20SelectBox=EC=9D=98=20?=
=?UTF-8?q?=EB=AA=A8=EB=8B=AC=EC=97=90=EC=84=9C=20=ED=81=B4=EB=A6=AD?=
=?UTF-8?q?=EB=90=90=EB=8A=94=EC=A7=80=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?=
=?UTF-8?q?=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=83=81=ED=83=9C=20?=
=?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
FE/issue-tracker/src/utils/isChecked_type.ts | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 FE/issue-tracker/src/utils/isChecked_type.ts
diff --git a/FE/issue-tracker/src/utils/isChecked_type.ts b/FE/issue-tracker/src/utils/isChecked_type.ts
new file mode 100644
index 000000000..491a1064b
--- /dev/null
+++ b/FE/issue-tracker/src/utils/isChecked_type.ts
@@ -0,0 +1,3 @@
+export type isCheckedType = {
+ [id: string]: boolean;
+};
From 7c567d1e07c21773eeadf7eba0f7da193b8d7993 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:04:46 +0900
Subject: [PATCH 100/157] =?UTF-8?q?Feat:=20#39=20=EB=AA=A8=EB=8B=AC?=
=?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=95=84=EC=9D=B4=ED=85=9C=EC=9D=84=20?=
=?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=98=EB=A9=B4=20=EB=A0=8C=EB=8D=94?=
=?UTF-8?q?=EB=A7=81=20=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=BB=B4=ED=8F=AC?=
=?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95,=20fetchModal=20?=
=?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../newIssue/select/SelectLabel.tsx | 35 ++++++++-----
.../newIssue/select/SelectMilestone.tsx | 52 +++++++++++++------
2 files changed, 60 insertions(+), 27 deletions(-)
diff --git a/FE/issue-tracker/src/components/newIssue/select/SelectLabel.tsx b/FE/issue-tracker/src/components/newIssue/select/SelectLabel.tsx
index 7cd17e99c..21b0fc727 100644
--- a/FE/issue-tracker/src/components/newIssue/select/SelectLabel.tsx
+++ b/FE/issue-tracker/src/components/newIssue/select/SelectLabel.tsx
@@ -1,5 +1,6 @@
import { useState } from 'react';
import styled from 'styled-components';
+import { useRecoilValue } from 'recoil';
import { Menu, MenuButton, Button } from '@chakra-ui/react';
import { ReactComponent as PlusIcon } from '@assets/plus.svg';
@@ -7,20 +8,19 @@ import Label from '@components/common/Label';
import { menuBtnStyle } from '@styles/chakraStyle';
import LabelModal from './LabelModal';
import { fetchModal } from '@utils/fetchModal';
+import { checkedLabelsState } from '@store/atoms/checkedThings';
function SelectLabel() {
const [labels, setLabels] = useState(null);
- const [errorMsg, setErrorMsg] = useState(null);
+ const [errorMsg, setErrorMsg] = useState('No Error');
+ const checkedLabels = useRecoilValue(checkedLabelsState);
const handleClickLabels = () => {
- const fetchLabels = async () => {
- try {
- await fetchModal({ path: 'labels', setState: setLabels });
- } catch (errorTxt) {
- setErrorMsg(errorTxt);
- }
- };
- fetchLabels();
+ fetchModal({
+ path: 'labels',
+ setState: setLabels,
+ setErrorMsg: setErrorMsg,
+ });
};
return (
@@ -39,9 +39,17 @@ function SelectLabel() {
-
-
-
+ {checkedLabels.map(({ title, color_code, font_light }) => {
+ return (
+
+
+
+ );
+ })}
);
@@ -56,4 +64,7 @@ const Wrap = styled.div`
const AddList = styled.ul`
padding: 8px 0;
+ li {
+ padding: 0.3rem;
+ }
`;
diff --git a/FE/issue-tracker/src/components/newIssue/select/SelectMilestone.tsx b/FE/issue-tracker/src/components/newIssue/select/SelectMilestone.tsx
index b0ede2af4..7ae44a88e 100644
--- a/FE/issue-tracker/src/components/newIssue/select/SelectMilestone.tsx
+++ b/FE/issue-tracker/src/components/newIssue/select/SelectMilestone.tsx
@@ -1,5 +1,6 @@
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import styled from 'styled-components';
+import { useRecoilValue } from 'recoil';
import { Menu, MenuButton, Button, Progress } from '@chakra-ui/react';
import { ReactComponent as PlusIcon } from '@assets/plus.svg';
@@ -7,25 +8,44 @@ import { menuBtnStyle } from '@styles/chakraStyle';
import { progressBar } from '../style';
import MilestoneModal from './MilestoneModal';
import { fetchModal } from '@utils/fetchModal';
+import { checkedMilestoneState } from '@store/atoms/checkedThings';
+
+type progressValueType = {
+ progress: number;
+ title: string;
+};
function SelectMilestone() {
const [milestones, setMilestones] = useState(null);
- const [errorMsg, setErrorMsg] = useState(null);
+ const [errorMsg, setErrorMsg] = useState('No Error');
+ const checkedMilestones = useRecoilValue(checkedMilestoneState);
+ const [progressValue, setProgressValue] =
+ useState(null);
+
+ console.log(checkedMilestones);
+
+ useEffect(() => {
+ if (checkedMilestones == null) setProgressValue(null);
+ else {
+ const { opened_issue_count, closed_issue_count, title } =
+ checkedMilestones;
+ const total = opened_issue_count + closed_issue_count;
+ const progress = (closed_issue_count / total) * 100;
+ setProgressValue({ progress, title });
+ }
+ }, [checkedMilestones]);
const handleClickMilestone = () => {
- const fetchMilestones = async () => {
- try {
- await fetchModal({ path: 'milestones', setState: setMilestones });
- } catch (errorTxt) {
- setErrorMsg(errorTxt);
- }
- };
- fetchMilestones();
+ fetchModal({
+ path: 'milestones',
+ setState: setMilestones,
+ setErrorMsg: setErrorMsg,
+ });
};
return (
-
);
From 01f77d82229e502335469aade9dc89d6054ae3c8 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:05:18 +0900
Subject: [PATCH 101/157] =?UTF-8?q?Refactor:=20#39=20=EB=8B=B4=EB=8B=B9?=
=?UTF-8?q?=EC=9E=90=20=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=EC=9D=98=20fet?=
=?UTF-8?q?chModal=20=ED=95=A8=EC=88=98=20=EB=A6=AC=ED=8C=A9=ED=86=A0?=
=?UTF-8?q?=EB=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/newIssue/select/SelectAssignee.tsx | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/FE/issue-tracker/src/components/newIssue/select/SelectAssignee.tsx b/FE/issue-tracker/src/components/newIssue/select/SelectAssignee.tsx
index d1d97346c..4a47317b6 100644
--- a/FE/issue-tracker/src/components/newIssue/select/SelectAssignee.tsx
+++ b/FE/issue-tracker/src/components/newIssue/select/SelectAssignee.tsx
@@ -10,17 +10,14 @@ import { fetchModal } from '@utils/fetchModal';
function SelectAssignee() {
const [assignees, setAssignees] = useState(null);
- const [errorMsg, setErrorMsg] = useState(null);
+ const [errorMsg, setErrorMsg] = useState('No Error');
const handleClickAssignee = () => {
- const fetchAssignees = async () => {
- try {
- await fetchModal({ path: 'assignees', setState: setAssignees });
- } catch (errorTxt) {
- setErrorMsg(errorTxt);
- }
- };
- fetchAssignees();
+ fetchModal({
+ path: 'assignees',
+ setState: setAssignees,
+ setErrorMsg: setErrorMsg,
+ });
};
return (
From dbdab96b29251811ab8cdf0a0f52767192ad52a9 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:06:09 +0900
Subject: [PATCH 102/157] =?UTF-8?q?Refactor:=20#39=20ErrorMsg=20=EC=B4=88?=
=?UTF-8?q?=EA=B8=B0=EA=B0=92=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/components/newIssue/select/AssigneeModal.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/FE/issue-tracker/src/components/newIssue/select/AssigneeModal.tsx b/FE/issue-tracker/src/components/newIssue/select/AssigneeModal.tsx
index 189698822..13b34f121 100644
--- a/FE/issue-tracker/src/components/newIssue/select/AssigneeModal.tsx
+++ b/FE/issue-tracker/src/components/newIssue/select/AssigneeModal.tsx
@@ -5,11 +5,11 @@ import { modalStyle, modalTitleStyle, modalListStyle } from '../style';
type Props = {
assignees: { user_id: number; name: string; avatar_url: string }[] | null;
- errorMsg: string | null;
+ errorMsg: string;
};
function AssigneeModal({ assignees, errorMsg }: Props) {
- const modalTitle = errorMsg == null ? '담당자 추가' : errorMsg;
+ const modalTitle = errorMsg == 'No Error' ? '담당자 추가' : errorMsg;
return (
From 72528e9ca966937fdc8c43d74e8d5c0c0f688c53 Mon Sep 17 00:00:00 2001
From: eve712 <62237639+eve712@users.noreply.github.com>
Date: Tue, 22 Jun 2021 19:06:55 +0900
Subject: [PATCH 103/157] =?UTF-8?q?Feat:=20#39=20=EC=84=A0=ED=83=9D?=
=?UTF-8?q?=EB=90=9C=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EC=83=81=ED=83=9C?=
=?UTF-8?q?=EA=B4=80=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/newIssue/select/LabelModal.tsx | 95 +++++++++----------
.../newIssue/select/MilestoneModal.tsx | 78 ++++++++++-----
2 files changed, 97 insertions(+), 76 deletions(-)
diff --git a/FE/issue-tracker/src/components/newIssue/select/LabelModal.tsx b/FE/issue-tracker/src/components/newIssue/select/LabelModal.tsx
index 439d9f46a..9c09f13d1 100644
--- a/FE/issue-tracker/src/components/newIssue/select/LabelModal.tsx
+++ b/FE/issue-tracker/src/components/newIssue/select/LabelModal.tsx
@@ -1,65 +1,55 @@
-import React from 'react';
+import { useState } from 'react';
import styled from 'styled-components';
import { useRecoilState } from 'recoil';
-import { MenuList, MenuOptionGroup, MenuItemOption } from '@chakra-ui/react';
+import { MenuList, MenuItem, Checkbox } from '@chakra-ui/react';
import Label from '@components/common/Label';
-import { modalStyle, modalTitleStyle, modalListStyle } from '../style';
-import { checkedLabelsState } from '@store/atoms/checkedThings';
+import MenuTitle from '@components/common/MenuTitle';
+import { checkBoxStyle, menuItemStyle } from '@styles/chakraStyle';
+import { modalStyle } from '../style';
+import { labelType, checkedLabelsState } from '@store/atoms/checkedThings';
+import { isCheckedType } from '../../../utils/isChecked_type';
+import {
+ getCheckedId,
+ setIsCheckedAndCheckedItem,
+} from '@utils/onClickMenuItem';
type Props = {
- labels:
- | {
- id: number;
- title: string;
- description: string;
- color_code: string;
- font_light: boolean;
- }[]
- | null;
- errorMsg: string | null;
+ labels: labelType[] | null;
+ errorMsg: string;
};
function LabelModal({ labels, errorMsg }: Props) {
- console.log(errorMsg);
const [checkedLabels, setCheckedLabels] = useRecoilState(checkedLabelsState);
- const modalTitle = errorMsg == null ? '레이블 추가' : errorMsg;
+ const [isChecked, setIsChecked] = useState({});
+ const modalTitle = errorMsg == 'No Error' ? '레이블 추가' : errorMsg;
- const handleClickLabel = (e: React.MouseEvent) => {
- const target = e.target as HTMLButtonElement;
- const menuItem: HTMLButtonElement | null = target.closest('.label_item');
- if (menuItem == null) return;
-
- const isChecked = menuItem.getAttribute('aria-checked') === 'false';
- if (isChecked) {
- const labelData = JSON.parse(JSON.stringify(menuItem.dataset));
- setCheckedLabels([...checkedLabels, labelData]);
- } else {
- setCheckedLabels((prev) =>
- prev.filter((label) => label.id !== menuItem.dataset.id)
- );
- }
+ const handleClickMenuItem = (e: React.MouseEvent) => {
+ const target = e.target as HTMLInputElement;
+ const checkedId = getCheckedId({ target: target, menuData: labels });
+ if (checkedId == null) return;
+ setIsCheckedAndCheckedItem({
+ menu: 'label',
+ menuData: labels,
+ checkedId: checkedId,
+ isChecked: isChecked,
+ setIsChecked: setIsChecked,
+ checkedMenus: checkedLabels,
+ setCheckedMenus: setCheckedLabels,
+ });
};
return (
-
-
- {labels &&
- labels.map(({ id, title, color_code, font_light }) => {
- return (
-
+ {modalTitle}
+ {labels &&
+ labels.map(({ id, title, color_code, font_light }) => {
+ return (
+
+
-
- );
- })}
-
+
+