diff --git a/fe/client/src/Pages/CreateIssuePage.tsx b/fe/client/src/Pages/CreateIssuePage.tsx index 66dee12a0..fb59d9817 100644 --- a/fe/client/src/Pages/CreateIssuePage.tsx +++ b/fe/client/src/Pages/CreateIssuePage.tsx @@ -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 ( <> @@ -26,9 +23,7 @@ const CreateIssuePage = () => { 작성취소 - + ) diff --git a/fe/client/src/components/common/FilterTab.tsx b/fe/client/src/components/common/FilterTab.tsx index 863a42984..7be6b616a 100644 --- a/fe/client/src/components/common/FilterTab.tsx +++ b/fe/client/src/components/common/FilterTab.tsx @@ -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]] } }); } diff --git a/fe/client/src/components/common/InputField.tsx b/fe/client/src/components/common/InputField.tsx index e95961915..43e269dc9 100644 --- a/fe/client/src/components/common/InputField.tsx +++ b/fe/client/src/components/common/InputField.tsx @@ -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 ( className={classes.title} style={{ marginBottom: '16px', width }} defaultValue={defaultValue} - + {...props} InputProps={{ disableUnderline: true, - ...props + endAdornment: endAdornment }} /> ) diff --git a/fe/client/src/components/common/atoms/issueInputAtom.ts b/fe/client/src/components/common/atoms/issueInputAtom.ts new file mode 100644 index 000000000..60ab451f2 --- /dev/null +++ b/fe/client/src/components/common/atoms/issueInputAtom.ts @@ -0,0 +1,11 @@ +import atom from '@/utils/myRecoil/atom'; + +export const issueTitleInputAtom = atom({ + key: 'issueTitleInputAtom', + default: '' +}); + +export const issueCommentInputAtom = atom({ + key: 'issueCommentInputAtom', + default: '' +}); \ No newline at end of file diff --git a/fe/client/src/components/common/types/APIType.ts b/fe/client/src/components/common/types/APIType.ts index 24c2b7138..bc05b73ac 100644 --- a/fe/client/src/components/common/types/APIType.ts +++ b/fe/client/src/components/common/types/APIType.ts @@ -35,4 +35,14 @@ export type IssueListItemType = { closed: boolean }, closed: boolean -} \ No newline at end of file +}; + + +export type IssueCreateType = { + title: string; + mainCommentContents: string; + authorId: number; + assigneeIds: Array; + labelIds: Array; + milestoneId: number; +} diff --git a/fe/client/src/components/createIssue/FilterItem.tsx b/fe/client/src/components/createIssue/FilterItem.tsx index aa51b0b7f..56450f52a 100644 --- a/fe/client/src/components/createIssue/FilterItem.tsx +++ b/fe/client/src/components/createIssue/FilterItem.tsx @@ -22,19 +22,36 @@ const FilterItem = ({ header }: { header: string }) => { return ( <> - - - Oni - + {header === 'manager' && checkedItems[header].length + ? checkedItems[header].map(({ name, info }: { name: string, info: any }) => { + return + + {name} + + }) + : null + } - - + {header === 'label' && checkedItems[header].length + ? checkedItems[header].map(({ name, info: { color } }: { name: string, info: any }) => { + return + + }) + : null + } - - - 마스터즈 코스 - + {header === 'milestone' && checkedItems[header].length + ? checkedItems[header].map(({ name, info }: { name: string, info: any }) => { + const { openedIssueCount, closedIssueCount } = info; + const allIssueCount = openedIssueCount + closedIssueCount; + return + + {name} + + }) + : null + } {data && { + 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 ( + + ) +} + +function getCheckedItemId({ info: { id } }: FilteredIdType) { + return id; +} + +export default SendButton; diff --git a/fe/client/src/components/createIssue/TitleInput.tsx b/fe/client/src/components/createIssue/TitleInput.tsx index 2e40a870a..9caeb7cf7 100644 --- a/fe/client/src/components/createIssue/TitleInput.tsx +++ b/fe/client/src/components/createIssue/TitleInput.tsx @@ -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(0, { start: 500, end: 2000 }); + const titleInputState = useRecoilInput(issueTitleInputAtom); + const { value: commentInputValue, onChange: commentOnChange } = useRecoilInput(issueCommentInputAtom); + const handleChangeTyping = useCallback((event: React.ChangeEvent) => { setDebounceCount(event.target.value.length); + commentOnChange(event) }, []); const handleChangeFile = async (event: React.ChangeEvent) => { @@ -21,7 +27,8 @@ 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); } @@ -29,7 +36,7 @@ const TitleInput = () => { return ( - + { className={classes.desc} variant="filled" onChange={handleChangeTyping} + value={commentInputValue} InputProps={{ disableUnderline: true }} diff --git a/fe/client/src/utils/API.ts b/fe/client/src/utils/API.ts index 6bda7020a..e62056b0d 100644 --- a/fe/client/src/utils/API.ts +++ b/fe/client/src/utils/API.ts @@ -1,3 +1,5 @@ +import { IssueCreateType } from "@/components/common/types/APIType"; + const API_END_POINT = 'https://issue-tracker-swagger.herokuapp.com'; const API: any = { @@ -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(); } } }; diff --git a/fe/client/src/utils/hook/useRecoilInput.ts b/fe/client/src/utils/hook/useRecoilInput.ts new file mode 100644 index 000000000..7293fec92 --- /dev/null +++ b/fe/client/src/utils/hook/useRecoilInput.ts @@ -0,0 +1,15 @@ +import { useRecoilState } from '@/utils/myRecoil/useRecoilState'; +import { AtomType } from '@/utils/myRecoil/atom'; + +const useRecoilInput = (atom: AtomType) => { + 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; \ No newline at end of file diff --git a/fe/client/src/utils/myRecoil/atom.ts b/fe/client/src/utils/myRecoil/atom.ts index b20c77dfb..f1cf264b6 100644 --- a/fe/client/src/utils/myRecoil/atom.ts +++ b/fe/client/src/utils/myRecoil/atom.ts @@ -1,4 +1,4 @@ -type AtomType = { +export type AtomType = { key: string; default: T; }