Skip to content

Commit

Permalink
Feat: 이슈만들기 API 사용하기 #115
Browse files Browse the repository at this point in the history
  • Loading branch information
jeonyeonkyu committed Jun 17, 2021
1 parent 05e94fd commit 64ff358
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 25 deletions.
9 changes: 2 additions & 7 deletions fe/client/src/Pages/CreateIssuePage.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import HeadContent from '@components/createIssue/HeadContent';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import Button from '@material-ui/core/Button';
import Tabs from '@components/createIssue/Tabs';
import TitleInput from '@components/createIssue/TitleInput';
import SendButton from '@components/createIssue/SendButton';
import IconButton from '@components/common/IconButton';
import { inputStyles } from '@components/common/baseStyle/baseStyle';

const CreateIssuePage = () => {
const classes = inputStyles();

return (
<>
<HeadContent />
Expand All @@ -26,9 +23,7 @@ const CreateIssuePage = () => {
<FontBold>작성취소</FontBold>
</IconButton>
</Link>
<Button color="primary"
variant="contained"
className={classes.button}>완료</Button>
<SendButton />
</BottomContents>
</>
)
Expand Down
1 change: 1 addition & 0 deletions fe/client/src/components/common/FilterTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const FilterTab = ({ header, filterList, inputType }: FilterTabType) => {
[header]: [...state[header].slice(0, presentIndex), ...state[header].slice(presentIndex + 1)]
}
}
if (header === 'milestone') return { ...state, [header]: [{ name, info }] };
return { ...state, [header]: [{ name, info }, ...state[header]] }
});
}
Expand Down
6 changes: 3 additions & 3 deletions fe/client/src/components/common/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type InputFieldType = {
[x: string]: any;
}

const InputField = ({ defaultValue, label, width, ...props }: InputFieldType) => {
const InputField = ({ defaultValue, label, width, endAdornment, ...props }: InputFieldType) => {
const classes = inputStyles();
return (
<TextField
Expand All @@ -18,10 +18,10 @@ const InputField = ({ defaultValue, label, width, ...props }: InputFieldType) =>
className={classes.title}
style={{ marginBottom: '16px', width }}
defaultValue={defaultValue}

{...props}
InputProps={{
disableUnderline: true,
...props
endAdornment: endAdornment
}}
/>
)
Expand Down
11 changes: 11 additions & 0 deletions fe/client/src/components/common/atoms/issueInputAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import atom from '@/utils/myRecoil/atom';

export const issueTitleInputAtom = atom({
key: 'issueTitleInputAtom',
default: ''
});

export const issueCommentInputAtom = atom({
key: 'issueCommentInputAtom',
default: ''
});
12 changes: 11 additions & 1 deletion fe/client/src/components/common/types/APIType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,14 @@ export type IssueListItemType = {
closed: boolean
},
closed: boolean
}
};


export type IssueCreateType = {
title: string;
mainCommentContents: string;
authorId: number;
assigneeIds: Array<string>;
labelIds: Array<string>;
milestoneId: number;
}
39 changes: 28 additions & 11 deletions fe/client/src/components/createIssue/FilterItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,36 @@ const FilterItem = ({ header }: { header: string }) => {

return (
<>
<CheckedItemWrapper>
<ImageTag src="https://user-images.githubusercontent.com/61257242/121417591-0d02b480-c9a5-11eb-9c7e-d926e8731bfb.png" alt="" />
<span>Oni</span>
</CheckedItemWrapper>
{header === 'manager' && checkedItems[header].length
? checkedItems[header].map(({ name, info }: { name: string, info: any }) => {
return <CheckedItemWrapper key={name}>
<ImageTag src="https://user-images.githubusercontent.com/61257242/121417591-0d02b480-c9a5-11eb-9c7e-d926e8731bfb.png" alt="" />
<span>{name}</span>
</CheckedItemWrapper>
})
: null
}

<CheckedItemWrapper>
<Label name='라벨네임' color='#0049' />
</CheckedItemWrapper>
{header === 'label' && checkedItems[header].length
? checkedItems[header].map(({ name, info: { color } }: { name: string, info: any }) => {
return <CheckedItemWrapper key={name}>
<Label name={name} color={color} />
</CheckedItemWrapper>
})
: null
}

<ProgressBarWrapper>
<ProgressBar variant="determinate" value={50} />
<span>마스터즈 코스</span>
</ProgressBarWrapper>
{header === 'milestone' && checkedItems[header].length
? checkedItems[header].map(({ name, info }: { name: string, info: any }) => {
const { openedIssueCount, closedIssueCount } = info;
const allIssueCount = openedIssueCount + closedIssueCount;
return <ProgressBarWrapper key={name}>
<ProgressBar variant="determinate" value={openedIssueCount / allIssueCount * 100} />
<span>{name}</span>
</ProgressBarWrapper>
})
: null
}

{data && <FilterTab
{...{ header }}
Expand Down
50 changes: 50 additions & 0 deletions fe/client/src/components/createIssue/SendButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import Button from '@material-ui/core/Button';
import { filterCheckboxListAtom } from '@components/common/atoms/filterAtom';
import { issueTitleInputAtom, issueCommentInputAtom } from '@components/common/atoms/issueInputAtom';
import { inputStyles } from '@components/common/baseStyle/baseStyle';
import { useRecoilState } from '@/utils/myRecoil/useRecoilState';
import API from '@/utils/API';

type FilteredIdType = {
info: {
id: number;
}
}

const SendButton = () => {
const classes = inputStyles();
const [checkedItems] = useRecoilState(filterCheckboxListAtom);
const [titleInputValue] = useRecoilState(issueTitleInputAtom);
const [commentInputValue] = useRecoilState(issueCommentInputAtom);

const handleClickSendData = async () => {

const data = {
title: titleInputValue,
mainCommentContents: commentInputValue,
authorId: 3, //수정필요
assigneeIds: checkedItems.manager.map(getCheckedItemId),
labelIds: checkedItems.label.map(getCheckedItemId),
milestoneId: checkedItems.milestone.map(getCheckedItemId)[0]
};

const a = await API.post.issues(data);
console.log(a);
}

return (
<Button color="primary"
variant="contained"
className={classes.button}
onClick={handleClickSendData}>
완료
</Button>
)
}

function getCheckedItemId({ info: { id } }: FilteredIdType) {
return id;
}

export default SendButton;
12 changes: 10 additions & 2 deletions fe/client/src/components/createIssue/TitleInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import styled from 'styled-components';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import InputField from '@/components/common/InputField';
import { issueCommentInputAtom, issueTitleInputAtom } from '@components/common/atoms/issueInputAtom';
import { inputStyles } from '@components/common/baseStyle/baseStyle';
import API from '@/utils/API';
import useDebounceTyping from '@/utils/hook/useDebounce';
import ClipIcon from '@/Icons/Clip.svg';
import useRecoilInput from '@/utils/hook/useRecoilInput';

const TitleInput = () => {
const classes = inputStyles();
const [debouncedCount, setDebounceCount] = useDebounceTyping<number>(0, { start: 500, end: 2000 });
const titleInputState = useRecoilInput(issueTitleInputAtom);
const { value: commentInputValue, onChange: commentOnChange } = useRecoilInput(issueCommentInputAtom);

const handleChangeTyping = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
setDebounceCount(event.target.value.length);
commentOnChange(event)
}, []);

const handleChangeFile = async (event: React.ChangeEvent<any>) => {
Expand All @@ -21,15 +27,16 @@ const TitleInput = () => {
formData.append("fileName", event.target.files[0].name);
try {
const data = await API.post.files(formData);
console.log(data)
const fileAddData = `\n[${data.name}](${data.path})`;
commentOnChange(event, fileAddData);
} catch (e) {
console.log(e);
}
}

return (
<InputWrapper>
<InputField />
<InputField {...titleInputState} />
<TextAreaWrapper>
<TextField
label="코멘트를 입력하세요"
Expand All @@ -38,6 +45,7 @@ const TitleInput = () => {
className={classes.desc}
variant="filled"
onChange={handleChangeTyping}
value={commentInputValue}
InputProps={{
disableUnderline: true
}}
Expand Down
12 changes: 12 additions & 0 deletions fe/client/src/utils/API.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IssueCreateType } from "@/components/common/types/APIType";

const API_END_POINT = 'https://issue-tracker-swagger.herokuapp.com';

const API: any = {
Expand Down Expand Up @@ -31,6 +33,16 @@ const API: any = {
files: async (formData: FormData) => {
const response = await fetch(`/files`, { method: 'POST', body: formData });
return response.json();
},
issues: async (data: IssueCreateType) => {
const response = await fetch(`/issues`, {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(data)
});
return response.json();
}
}
};
Expand Down
15 changes: 15 additions & 0 deletions fe/client/src/utils/hook/useRecoilInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useRecoilState } from '@/utils/myRecoil/useRecoilState';
import { AtomType } from '@/utils/myRecoil/atom';

const useRecoilInput = <T>(atom: AtomType<T>) => {
const [value, setValue] = useRecoilState(atom);

const onChange = ({ target }: { target: HTMLInputElement }, fileData?: string) => {
if (fileData) return setValue(value + fileData);
setValue(target.value)
}

return { value, onChange };
}

export default useRecoilInput;
2 changes: 1 addition & 1 deletion fe/client/src/utils/myRecoil/atom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type AtomType<T> = {
export type AtomType<T> = {
key: string;
default: T;
}
Expand Down

0 comments on commit 64ff358

Please sign in to comment.