From 855ff938928580560593cdc2f5b4a64d8b1224d6 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Tue, 23 Jan 2024 16:52:41 +0900 Subject: [PATCH 01/38] =?UTF-8?q?fix:=20lineheight=201.4=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=EA=B0=92=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/commons/Text/Text.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/commons/Text/Text.tsx b/src/components/commons/Text/Text.tsx index 4c38139..ce909a3 100644 --- a/src/components/commons/Text/Text.tsx +++ b/src/components/commons/Text/Text.tsx @@ -25,17 +25,13 @@ const Text = React.memo((props: TextProps) => { }); const StyledText = styled('div')` - ${({ lineHeight }) => - lineHeight && - css` - line-height: ${lineHeight}; - `} + line-height: ${({ lineHeight }) => lineHeight || '1.4'}; ${({ align }) => align && css` text-align: ${align}; `} - ${({ color }) => + ${({ color }) => color && css` color: ${color}; From c73a3fcf32ff842539d3a2a211bd5856c81e336e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:38:11 +0900 Subject: [PATCH 02/38] =?UTF-8?q?feat:=20text,=20image=20icon=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/image-icon-selected.svg | 5 +++++ src/assets/icons/image-icon.svg | 5 +++++ src/assets/icons/index.ts | 8 ++++++++ src/assets/icons/text-icon-selected.svg | 7 +++++++ src/assets/icons/text-icon.svg | 5 +++++ 5 files changed, 30 insertions(+) create mode 100644 src/assets/icons/image-icon-selected.svg create mode 100644 src/assets/icons/image-icon.svg create mode 100644 src/assets/icons/text-icon-selected.svg create mode 100644 src/assets/icons/text-icon.svg diff --git a/src/assets/icons/image-icon-selected.svg b/src/assets/icons/image-icon-selected.svg new file mode 100644 index 0000000..723511a --- /dev/null +++ b/src/assets/icons/image-icon-selected.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/image-icon.svg b/src/assets/icons/image-icon.svg new file mode 100644 index 0000000..001ea74 --- /dev/null +++ b/src/assets/icons/image-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 0206198..dabd740 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -15,6 +15,8 @@ import GoogleIcon from './google.svg?react'; import HideIcon from './hide.svg?react'; import HitIcon from './hit.svg?react'; import SelectedHomeIcon from './home-selected.svg?react'; +import SelectedImageIcon from './image-icon-selected.svg?react'; +import ImageIcon from './image-icon.svg?react'; import KakaoIcon from './kakao.svg?react'; import LeftDoubleArrowIcon from './left-double-arrow.svg?react'; import MeatballIcon from './meatball.svg?react'; @@ -26,6 +28,8 @@ import RightChevronIcon from './right-chevron.svg?react'; import RightDoubleArrowIcon from './right-double-arrow.svg?react'; import RotateIcon from './rotate.svg?react'; import SizeUpIcon from './size-up.svg?react'; +import SelectedTextIcon from './text-icon-selected.svg?react'; +import TextIcon from './text-icon.svg?react'; import ThumbsIcon from './thumbs.svg?react'; import TopicCreatBackgrounIcon from './topic-create-background.svg?react'; import WriteBoxIcon from './write-box.svg?react'; @@ -62,4 +66,8 @@ export { ThumbsIcon, TopicCreatBackgrounIcon, WriteBoxIcon, + TextIcon, + SelectedTextIcon, + ImageIcon, + SelectedImageIcon, }; diff --git a/src/assets/icons/text-icon-selected.svg b/src/assets/icons/text-icon-selected.svg new file mode 100644 index 0000000..3eb7bee --- /dev/null +++ b/src/assets/icons/text-icon-selected.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/icons/text-icon.svg b/src/assets/icons/text-icon.svg new file mode 100644 index 0000000..f3ac061 --- /dev/null +++ b/src/assets/icons/text-icon.svg @@ -0,0 +1,5 @@ + + + + + From 434339320d0cc82d873533b1838bfd48fe31aa64 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:38:36 +0900 Subject: [PATCH 03/38] =?UTF-8?q?fix:=20padding=20=EA=B0=92=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/{ => Create/ASide}/ATopicCreate.styles.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/routes/Topic/{ => Create/ASide}/ATopicCreate.styles.tsx (98%) diff --git a/src/routes/Topic/ATopicCreate.styles.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.styles.tsx similarity index 98% rename from src/routes/Topic/ATopicCreate.styles.tsx rename to src/routes/Topic/Create/ASide/ATopicCreate.styles.tsx index 12b3e8d..8b7f88e 100644 --- a/src/routes/Topic/ATopicCreate.styles.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.styles.tsx @@ -10,7 +10,7 @@ export const Container = styled.div` justify-content: flex-start; width: 100%; height: 100%; - padding: 51px 20px 0; + padding: 54px 20px 0; background-color: ${colors.navy}; `; From 994921a52e13ae3cb2aa406c99d9756199192fd9 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:38:58 +0900 Subject: [PATCH 04/38] =?UTF-8?q?fix:=20=EC=88=98=EC=A0=95=EB=90=9C=20inpu?= =?UTF-8?q?t=20theme=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/{ => Create/ASide}/ATopicCreate.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/routes/Topic/{ => Create/ASide}/ATopicCreate.tsx (92%) diff --git a/src/routes/Topic/ATopicCreate.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.tsx similarity index 92% rename from src/routes/Topic/ATopicCreate.tsx rename to src/routes/Topic/Create/ASide/ATopicCreate.tsx index a90c460..31ce51d 100644 --- a/src/routes/Topic/ATopicCreate.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.tsx @@ -6,7 +6,7 @@ import DefaultButton from '@components/commons/Button/DefaultButton'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; import TextInput from '@components/commons/TextInput/TextInput'; -import { theme2 } from '@components/commons/TextInput/theme'; +import { theme3 } from '@components/commons/TextInput/theme'; import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; import { colors } from '@styles/theme'; @@ -42,7 +42,7 @@ const ATopicCreate = () => { id={INPUT_TYPE.TOPICTITLE} options={CONFIG.TOPICTITLE.options} placeholder={'제목을 입력해주세요.'} - theme={theme2} + theme={theme3} right={() => ( {titleProgress} @@ -50,7 +50,7 @@ const ATopicCreate = () => { )} /> - + Date: Fri, 26 Jan 2024 15:39:41 +0900 Subject: [PATCH 05/38] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20input=20form=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/form.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/constants/form.ts b/src/constants/form.ts index c0e0a05..c366fc4 100644 --- a/src/constants/form.ts +++ b/src/constants/form.ts @@ -12,6 +12,7 @@ export const INPUT_TYPE = { TOPICTITLE: 'topicTitle', ATOPIC: 'aTopic', BTOPIC: 'bTopic', + TOPICCATEGORY: 'topicCategory', } as const; export type ConfigKeys = keyof typeof INPUT_TYPE; @@ -88,4 +89,20 @@ export const CONFIG: Record = { required: true, }, }, + TOPICCATEGORY: { + options: { + required: { + value: true, + message: '카테고리를 입력해주세요.', + }, + pattern: { + value: /^[가-힣a-zA-Z0-9]+$/, + message: '한글, 영문, 숫자만 가능해요.', + }, + maxLength: { + value: 20, + message: '카테고리는 6자리 이내로 입력해주세요.', + }, + }, + }, } as const; From b113a7a1d4435899b3fbc3139414f3a9b7d6e28b Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:39:56 +0900 Subject: [PATCH 06/38] =?UTF-8?q?fix:=20=ED=8C=8C=EC=9D=BC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/index.tsx b/src/routes/index.tsx index d36c288..62df555 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -8,7 +8,7 @@ import Login from './Auth/login/Login'; import Signup from './Auth/signup/Signup'; import Home from './Home/Home'; import Notification from './Notification/Notification'; -import TopicCreate from './Topic/TopicCreate'; +import TopicCreate from './Topic/Create/TopicCreate'; import TopicSideSelection from './Topic/TopicSideSelection'; const Router = () => { From 05fd4a6d47a1c4a9b09777ed5db8594043162d64 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:40:27 +0900 Subject: [PATCH 07/38] =?UTF-8?q?feat:=20=ED=86=A0=ED=94=BD=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20image=20input=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 --- .../TopicCreateImageInput.styles.tsx | 75 ++++++++++ .../TopicCreate/TopicCreateImageInput.tsx | 138 ++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 src/components/TopicCreate/TopicCreateImageInput.styles.tsx create mode 100644 src/components/TopicCreate/TopicCreateImageInput.tsx diff --git a/src/components/TopicCreate/TopicCreateImageInput.styles.tsx b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx new file mode 100644 index 0000000..bf64b8b --- /dev/null +++ b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx @@ -0,0 +1,75 @@ +import { styled } from 'styled-components'; + +import { colors } from '@styles/theme'; + +export const ReplaceButton = styled.div` + display: flex; + flex-direction: row; + gap: 6px; + align-items: center; + justify-content: space-between; + width: 111px; + height: 18px; +`; + +export const ReplaceIcon = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 14px; + height: 14px; +`; + +export const ImageInputContainer = styled.div` + position: relative; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 122px; + height: 124px; + overflow: hidden; + background-color: ${colors.navy2_80}; + border-radius: 10px; +`; + +export const Image = styled.img` + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + overflow: hidden; +`; + +export const ImageInput = styled.input` + display: none; +`; + +export const ImageInputTextContainer = styled.div` + position: absolute; + top: 32px; + left: 50%; + display: flex; + align-items: center; + justify-content: center; + transform: translateX(-50%); +`; + +export const ImageInputDescriptionContainer = styled.div` + position: absolute; + top: 50%; + left: 50%; + display: flex; + align-items: center; + justify-content: center; + transform: translate(-50%, -50%); +`; + +export const InputSuffix = styled.div` + position: absolute; + top: 50%; + right: 16px; + transform: translateY(-50%); +`; diff --git a/src/components/TopicCreate/TopicCreateImageInput.tsx b/src/components/TopicCreate/TopicCreateImageInput.tsx new file mode 100644 index 0000000..a1348ef --- /dev/null +++ b/src/components/TopicCreate/TopicCreateImageInput.tsx @@ -0,0 +1,138 @@ +import { Register } from '@tanstack/react-query'; +import React, { useRef, useState } from 'react'; +import { RegisterOptions, useFormContext } from 'react-hook-form'; +import { CONFIG, INPUT_TYPE, InputType } from 'src/constants/form'; + +import { Col, Row } from '@components/commons/Flex/Flex'; +import Text from '@components/commons/Text/Text'; + +import { colors } from '@styles/theme'; + +import { RotateIcon } from '@icons/index'; + +import { + ReplaceButton, + ReplaceIcon, + ImageInput, + ImageInputContainer, + ImageInputTextContainer, + ImageInputDescriptionContainer, + Image, +} from './TopicCreateImageInput.styles'; + +interface TopicCreareProps { + topic: 'A' | 'B'; + topicContent: string; + onKeyDown?: (e: React.KeyboardEvent) => void; +} + +const TopicCreateImageInput = () => { + const { register, watch } = useFormContext(); + const imageInputRef_A = useRef(null); + const imageInputRef_B = useRef(null); + const [imageAUrl, setImageAUrl] = useState(null); + const [imageBUrl, setImageBUrl] = useState(null); + + const handleImageInputAClick = () => { + if (imageInputRef_A.current) { + imageInputRef_A.current.click(); + } + }; + + const handleImageInputBClick = () => { + if (imageInputRef_B.current) { + imageInputRef_B.current.click(); + } + }; + + const handleFileChangeA = (event: React.ChangeEvent) => { + handleFileChange(event, setImageAUrl); + }; + + const handleFileChangeB = (event: React.ChangeEvent) => { + handleFileChange(event, setImageBUrl); + }; + + const handleFileChange = ( + event: React.ChangeEvent, + setImageUrl: React.Dispatch> + ) => { + const fileObj = event.target.files && event.target.files[0]; + if (!fileObj) { + return; + } + + const reader = new FileReader(); + reader.onloadend = () => { + setImageUrl(reader.result as string); + }; + reader.readAsDataURL(fileObj); + }; + return ( + + + + 어떤 선택지가 있나요? + + + + + + + AB 선택지 바꾸기 + + + + + + {imageAUrl && Image A} + + + A + + + {!imageAUrl && ( + + + 이미지 +
+ 가져오기 +
+
+ )} + +
+ + {imageBUrl && Image B} + + + B + + + {!imageBUrl && ( + + + 이미지 +
+ 가져오기 +
+
+ )} + +
+
+ + ); +}; + +export default TopicCreateImageInput; From f54f375ae224e9e3c98170b4c94e90e4793adb6a Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:40:57 +0900 Subject: [PATCH 08/38] =?UTF-8?q?fix:=20textinput=20props=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 --- src/components/TopicCreate/TopicCreateTextInput.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/TopicCreate/TopicCreateTextInput.tsx b/src/components/TopicCreate/TopicCreateTextInput.tsx index 8a72f07..2baeb25 100644 --- a/src/components/TopicCreate/TopicCreateTextInput.tsx +++ b/src/components/TopicCreate/TopicCreateTextInput.tsx @@ -20,12 +20,10 @@ import { } from './TopicCreateTextInput.styles'; interface TopicCreareProps { - topic: 'A' | 'B'; - topicContent: string; onKeyDown?: (e: React.KeyboardEvent) => void; } -const TopicCreateTextInput = ({ topic, topicContent }: TopicCreareProps) => { +const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { const { register, watch } = useFormContext(); const ATopicProgress = watch(INPUT_TYPE.ATOPIC) ? `${watch(INPUT_TYPE.ATOPIC)?.length}/25` From d44f5c849f9ac7280693832d42ca5dd2da335b06 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:41:39 +0900 Subject: [PATCH 09/38] =?UTF-8?q?feat:=20=EB=92=A4=EB=A1=9C=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/{ => Create}/TopicCreate.sytles.tsx | 0 src/routes/Topic/{ => Create}/TopicCreate.tsx | 6 +++--- src/routes/Topic/TopicSideSelection.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/routes/Topic/{ => Create}/TopicCreate.sytles.tsx (100%) rename src/routes/Topic/{ => Create}/TopicCreate.tsx (93%) diff --git a/src/routes/Topic/TopicCreate.sytles.tsx b/src/routes/Topic/Create/TopicCreate.sytles.tsx similarity index 100% rename from src/routes/Topic/TopicCreate.sytles.tsx rename to src/routes/Topic/Create/TopicCreate.sytles.tsx diff --git a/src/routes/Topic/TopicCreate.tsx b/src/routes/Topic/Create/TopicCreate.tsx similarity index 93% rename from src/routes/Topic/TopicCreate.tsx rename to src/routes/Topic/Create/TopicCreate.tsx index 3ef4c90..51d171e 100644 --- a/src/routes/Topic/TopicCreate.tsx +++ b/src/routes/Topic/Create/TopicCreate.tsx @@ -8,8 +8,8 @@ import { colors } from '@styles/theme'; import { DownChevronIcon, RightChevronIcon } from '@icons/index'; -import ATopicCreate from './ATopicCreate'; -import BTopicCreate from './BTopicCreate'; +import ATopicCreate from './ASide/ATopicCreate'; +import BTopicCreate from './BSide/BTopicCreate'; import { BackButton, DownShevron, @@ -33,7 +33,7 @@ const TopicCreate = () => { }; const handleSideChangeButtonClick = (newtopicSideValue: string) => { - navigate(`/topics/create/${newtopicSideValue}`, { replace: true }); + navigate(`/topics/create/${newtopicSideValue}?step=1`, { replace: true }); }; const Container = topicSide === 'A' ? : ; diff --git a/src/routes/Topic/TopicSideSelection.tsx b/src/routes/Topic/TopicSideSelection.tsx index bd60bae..23510b9 100644 --- a/src/routes/Topic/TopicSideSelection.tsx +++ b/src/routes/Topic/TopicSideSelection.tsx @@ -48,7 +48,7 @@ const TopicSideSelection = () => { const handleTopicCreateButtonClick = () => { if (selected !== null) { - navigate(`/topics/create/${selected}`); + navigate(`/topics/create/${selected}?step=1`); } }; From cf420e0f8c9305a0a0a4f6ee445933f1fb19ea40 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:42:13 +0900 Subject: [PATCH 10/38] =?UTF-8?q?feat:=20B=20topic=20step2=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/BTopicCreate.styles.tsx | 15 ----- .../Create/BSide/BTopicCreateStep2.styles.tsx | 33 ++++++++++ .../Topic/Create/BSide/BTopicCreateStep2.tsx | 66 +++++++++++++++++++ 3 files changed, 99 insertions(+), 15 deletions(-) delete mode 100644 src/routes/Topic/BTopicCreate.styles.tsx create mode 100644 src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx create mode 100644 src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx diff --git a/src/routes/Topic/BTopicCreate.styles.tsx b/src/routes/Topic/BTopicCreate.styles.tsx deleted file mode 100644 index 031f83d..0000000 --- a/src/routes/Topic/BTopicCreate.styles.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { styled } from 'styled-components'; - -import { colors } from '@styles/theme'; - -export const Container = styled.div` - position: relative; - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - width: 100%; - height: 100%; - padding: 51px 20px 0; - background-color: ${colors.navy}; -`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx new file mode 100644 index 0000000..2dfe8a3 --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx @@ -0,0 +1,33 @@ +import { styled } from 'styled-components'; + +import { colors } from '@styles/theme'; + +export const Container = styled.div` + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + width: 100%; + height: 100%; + padding: 30px 0 0; + background-color: ${colors.navy}; +`; + +export const UnderLine = styled.div` + width: 100%; + height: 1px; + background-color: ${colors.white_20}; +`; + +export const SelectIconContainer = styled.button<{ selected: boolean }>` + display: flex; + align-items: center; + justify-content: center; + width: 42px; + height: 42px; + background-color: ${(props) => (!props.selected ? colors.navy : colors.black)}; + border: ${(props) => (!props.selected ? `1px solid ${colors.white_20}` : 'none')}; + border-radius: 50%; + transition: all 0.2s ease-in-out; +`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx new file mode 100644 index 0000000..ae48ada --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -0,0 +1,66 @@ +import React, { useState } from 'react'; +import { useFormContext } from 'react-hook-form'; + +import { Col, Row } from '@components/commons/Flex/Flex'; +import Text from '@components/commons/Text/Text'; +import TopicCreateImageInput from '@components/TopicCreate/TopicCreateImageInput'; +import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; + +import { colors } from '@styles/theme'; + +import { ImageIcon, SelectedImageIcon, SelectedTextIcon, TextIcon } from '@icons/index'; + +import { Container, SelectIconContainer, UnderLine } from './BTopicCreateStep2.styles'; + +interface BTopicCreateStep2Props { + topicTitle: string; + topicCategory: string; + onKeyDown?: (e: React.KeyboardEvent) => void; +} + +const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props) => { + const methods = useFormContext(); + + const [selected, setSelected] = useState('text'); + + const Selection = selected === 'text' ? : ; + + const handleTextSelect = () => { + setSelected('text'); + }; + + const handleImageSelect = () => { + setSelected('image'); + }; + + return ( + + + + + + {topicTitle} + + + {topicCategory} + + + + + + + + {selected === 'text' ? : } + + + {selected === 'image' ? : } + + + {Selection} + + + + ); +}; + +export default BTopicCreateStep2; From 566a0d380da8d8caf89e51d8f49365d4842e714d Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:42:32 +0900 Subject: [PATCH 11/38] =?UTF-8?q?feat:=20B=20topic=20step1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/BTopicCreate.tsx | 58 ----------- .../Create/BSide/BTopicCreateStep1.styles.tsx | 45 +++++++++ .../Topic/Create/BSide/BTopicCreateStep1.tsx | 98 +++++++++++++++++++ 3 files changed, 143 insertions(+), 58 deletions(-) delete mode 100644 src/routes/Topic/BTopicCreate.tsx create mode 100644 src/routes/Topic/Create/BSide/BTopicCreateStep1.styles.tsx create mode 100644 src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx diff --git a/src/routes/Topic/BTopicCreate.tsx b/src/routes/Topic/BTopicCreate.tsx deleted file mode 100644 index d52fda9..0000000 --- a/src/routes/Topic/BTopicCreate.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React, { useState } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { CONFIG, INPUT_TYPE } from 'src/constants/form'; - -import { Col } from '@components/commons/Flex/Flex'; -import Text from '@components/commons/Text/Text'; -import TextInput from '@components/commons/TextInput/TextInput'; -import { theme2 } from '@components/commons/TextInput/theme'; - -import { colors } from '@styles/theme'; - -import { Container } from './ATopicCreate.styles'; - -interface TopicCreateDTO { - topicTitle: string; - ATopic: string; - BTopic: string; -} - -const BTopicCreate = () => { - const methods = useForm({ mode: 'onChange' }); - - const titleProgress = methods.watch(INPUT_TYPE.TOPICTITLE) - ? `${methods.watch(INPUT_TYPE.TOPICTITLE)?.length}/20` - : '0/20'; - - return ( - - - - - - 어떤 주제로 물어볼까요? - - ( - - {titleProgress} - - )} - /> - - - - 토픽의 카테고리를 알려주세요 - - - - - - ); -}; - -export default BTopicCreate; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep1.styles.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep1.styles.tsx new file mode 100644 index 0000000..0543aba --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep1.styles.tsx @@ -0,0 +1,45 @@ +import { styled } from 'styled-components'; + +import { colors } from '@styles/theme'; + +export const Container = styled.div` + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + width: 100%; + height: 100%; + padding: 54px 0 0; + background-color: ${colors.navy}; +`; + +export const CategoryChipContainer = styled.div` + display: flex; + flex-direction: row; + gap: 5px; + align-items: center; + justify-content: flex-start; + padding-right: 20px; + overflow-x: scroll; + background-color: ${colors.navy}; + + &::-webkit-scrollbar { + display: none; + } +`; + +export const CategoryChip = styled.button` + display: flex; + align-items: center; + justify-content: center; + padding: 5px 16px; + font-size: 14px; + font-weight: 600; + color: ${colors.purple}; + text-align: center; + white-space: nowrap; + background-color: ${colors.navy}; + border: 1px solid ${colors.navy2}; + border-radius: 23px; +`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx new file mode 100644 index 0000000..6d3b93a --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { useFormContext } from 'react-hook-form'; +import { CONFIG, INPUT_TYPE } from 'src/constants/form'; + +import { Col } from '@components/commons/Flex/Flex'; +import Text from '@components/commons/Text/Text'; +import TextInput from '@components/commons/TextInput/TextInput'; +import { theme2, theme3 } from '@components/commons/TextInput/theme'; + +import { colors } from '@styles/theme'; + +import { CategoryChip, CategoryChipContainer, Container } from './BTopicCreateStep1.styles'; + +interface BTopicCreareProps { + onKeyDown?: (e: React.KeyboardEvent) => void; +} + +const BTopicCreateStep1 = () => { + const methods = useFormContext(); + const titleProgress = methods.watch(INPUT_TYPE.TOPICTITLE) + ? `${methods.watch(INPUT_TYPE.TOPICTITLE)?.length}/20` + : '0/20'; + + const categoryProgress = methods.watch(INPUT_TYPE.TOPICCATEGORY) + ? `${methods.watch(INPUT_TYPE.TOPICCATEGORY)?.length}/6` + : '0/6'; + + const categoryChipList = ['스포츠', '연예방송', '일상다반사', '게임', '일상']; + + const handleCategoryChipClick = (categoryChip: string) => { + methods.setValue(INPUT_TYPE.TOPICCATEGORY, categoryChip); + methods.clearErrors(INPUT_TYPE.TOPICCATEGORY); + }; + + return ( + + + + + 어떤 주제로 물어볼까요? + + ( + + {titleProgress} + + )} + /> + + + + + 토픽의 카테고리를 알려주세요 + + ( + + {categoryProgress} + + )} + /> + + + + 추천 키워드 + + + {categoryChipList.map((categoryChip, index) => ( + { + handleCategoryChipClick(categoryChip); + }} + key={index} + > + {categoryChip} + + ))} + + + 비속어를 포함한 부적절한 단어의 태그를 입력할 경우
+ 게시물 삭제 및 이용 제재를 받을 수 있어요. +
+ + + +
+ ); +}; + +export default BTopicCreateStep1; From c2194aeb4db4bf77322687ffceac824c6dbdb34e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 26 Jan 2024 15:42:56 +0900 Subject: [PATCH 12/38] =?UTF-8?q?feat:=20B=20topic=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Create/BSide/BTopicCreate.styles.tsx | 48 +++++++++++++++ .../Topic/Create/BSide/BTopicCreate.tsx | 59 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx create mode 100644 src/routes/Topic/Create/BSide/BTopicCreate.tsx diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx new file mode 100644 index 0000000..12f759a --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx @@ -0,0 +1,48 @@ +import { styled } from 'styled-components'; + +import { colors } from '@styles/theme'; + +export const Container = styled.div` + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + width: 100%; + height: 100%; + background-color: ${colors.navy}; +`; + +export const PageControllerContainer = styled.div` + position: absolute; + bottom: 66px; + left: 50%; + display: flex; + align-items: center; + justify-content: center; + transform: translateX(-50%); +`; + +export const PageController = styled.div<{ currentStage: boolean }>` + display: flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + color: ${(props) => (props.currentStage ? colors.purple : colors.navy2)}; + text-align: center; + background-color: ${colors.navy}; + border: 2px solid ${(props) => (props.currentStage ? colors.purple : colors.navy2)}; + border-radius: 50%; +`; + +export const PageControllerLine = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 13px; + height: 0; + text-align: center; + background-color: ${colors.navy}; + border: 1px solid ${colors.navy2}; +`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx new file mode 100644 index 0000000..3cb8311 --- /dev/null +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -0,0 +1,59 @@ +import React, { useState } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { CONFIG, INPUT_TYPE } from 'src/constants/form'; + +import { + Container, + PageController, + PageControllerContainer, + PageControllerLine, +} from './BTopicCreate.styles'; +import BTopicCreateStep1 from './BTopicCreateStep1'; +import BTopicCreateStep2 from './BTopicCreateStep2'; + +interface TopicCreateDTO { + topicTitle: string; + ATopic: string; + BTopic: string; + topicCategory: string; +} + +const BTopicCreate = () => { + const navigate = useNavigate(); + const methods = useForm({ mode: 'onChange' }); + const [searchParams] = useSearchParams(); + const step = searchParams.get('step'); + + const navigateToNextStep = () => { + navigate('/topics/create/B?step=2'); + }; + + if (step === null) { + return; + } + + const Step = + step === '1' ? ( + + ) : ( + + ); + + return ( + + + {Step} + + 1 + + + 2 + + + + + ); +}; + +export default BTopicCreate; From 9635ad1f000f8ab1e64785f9509a64eab0507e8a Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:02:08 +0900 Subject: [PATCH 13/38] feat: add delete icon --- src/assets/icons/delete.svg | 4 ++++ src/assets/icons/index.ts | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 src/assets/icons/delete.svg diff --git a/src/assets/icons/delete.svg b/src/assets/icons/delete.svg new file mode 100644 index 0000000..16ddc30 --- /dev/null +++ b/src/assets/icons/delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index dabd740..0e21d24 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -10,6 +10,7 @@ import CheckIcon from './check.svg?react'; import ClockIcon from './clock.svg?react'; import CloseIcon from './close.svg?react'; import CommentIcon from './comment.svg?react'; +import DeleteIcon from './delete.svg?react'; import DownChevronIcon from './down-chevron.svg?react'; import GoogleIcon from './google.svg?react'; import HideIcon from './hide.svg?react'; @@ -70,4 +71,5 @@ export { SelectedTextIcon, ImageIcon, SelectedImageIcon, + DeleteIcon, }; From a6f51202b76ce53fb5b8cb9c4a212a3613035d4e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:05:51 +0900 Subject: [PATCH 14/38] feat: add maxlength --- src/components/commons/TextInput/TextInput.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/commons/TextInput/TextInput.tsx b/src/components/commons/TextInput/TextInput.tsx index 56d3201..1484bf5 100644 --- a/src/components/commons/TextInput/TextInput.tsx +++ b/src/components/commons/TextInput/TextInput.tsx @@ -26,7 +26,17 @@ interface TextInputProps extends React.InputHTMLAttributes { } const TextInput = (props: TextInputProps) => { - const { id, type = 'text', options, placeholder, left, right, onKeyDown, theme = theme1 } = props; + const { + id, + type = 'text', + options, + placeholder, + maxLength, + left, + right, + onKeyDown, + theme = theme1, + } = props; const { register, formState: { errors }, @@ -40,6 +50,7 @@ const TextInput = (props: TextInputProps) => { inputTheme={theme} type={type} placeholder={placeholder} + maxLength={maxLength} {...register(id, options)} onKeyDown={onKeyDown} /> From e553957a994f93da9d25ab0456055ab4493a3b2e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:06:13 +0900 Subject: [PATCH 15/38] fix: constant fix --- src/routes/Topic/Create/ASide/ATopicCreate.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/routes/Topic/Create/ASide/ATopicCreate.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.tsx index 31ce51d..2c4002b 100644 --- a/src/routes/Topic/Create/ASide/ATopicCreate.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.tsx @@ -22,8 +22,8 @@ interface TopicCreateDTO { const ATopicCreate = () => { const methods = useForm({ mode: 'onChange' }); - const titleProgress = methods.watch(INPUT_TYPE.TOPICTITLE) - ? `${methods.watch(INPUT_TYPE.TOPICTITLE)?.length}/20` + const titleProgress = methods.watch(INPUT_TYPE.TOPIC_TITLE) + ? `${methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length}/20` : '0/20'; const handleSummitButtonClick = () => { @@ -39,12 +39,13 @@ const ATopicCreate = () => { 어떤 주제로 물어볼까요?
( - + {titleProgress} )} From 0172e74565c33550cfcda01f969ae62fcc2a1e3e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:07:32 +0900 Subject: [PATCH 16/38] fix: constant fix --- .../Topic/Create/BSide/BTopicCreateStep1.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx index 6d3b93a..440151b 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx @@ -17,19 +17,19 @@ interface BTopicCreareProps { const BTopicCreateStep1 = () => { const methods = useFormContext(); - const titleProgress = methods.watch(INPUT_TYPE.TOPICTITLE) - ? `${methods.watch(INPUT_TYPE.TOPICTITLE)?.length}/20` + const titleProgress = methods.watch(INPUT_TYPE.TOPIC_TITLE) + ? `${methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length}/20` : '0/20'; - const categoryProgress = methods.watch(INPUT_TYPE.TOPICCATEGORY) - ? `${methods.watch(INPUT_TYPE.TOPICCATEGORY)?.length}/6` + const categoryProgress = methods.watch(INPUT_TYPE.TOPIC_CATEGORY) + ? `${methods.watch(INPUT_TYPE.TOPIC_CATEGORY)?.length}/6` : '0/6'; const categoryChipList = ['스포츠', '연예방송', '일상다반사', '게임', '일상']; const handleCategoryChipClick = (categoryChip: string) => { - methods.setValue(INPUT_TYPE.TOPICCATEGORY, categoryChip); - methods.clearErrors(INPUT_TYPE.TOPICCATEGORY); + methods.setValue(INPUT_TYPE.TOPIC_CATEGORY, categoryChip); + methods.clearErrors(INPUT_TYPE.TOPIC_CATEGORY); }; return ( @@ -40,12 +40,13 @@ const BTopicCreateStep1 = () => { 어떤 주제로 물어볼까요? ( - + {titleProgress} )} @@ -57,9 +58,10 @@ const BTopicCreateStep1 = () => { 토픽의 카테고리를 알려주세요 ( From ed145fc3186d0745a66ac13692178eca105bd226 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:08:25 +0900 Subject: [PATCH 17/38] fix: form fix --- src/constants/form.ts | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/constants/form.ts b/src/constants/form.ts index c366fc4..d11eaf6 100644 --- a/src/constants/form.ts +++ b/src/constants/form.ts @@ -9,10 +9,13 @@ export const INPUT_TYPE = { BIRTHDAY: 'birth', GENDER: 'gender', JOB: 'job', - TOPICTITLE: 'topicTitle', - ATOPIC: 'aTopic', - BTOPIC: 'bTopic', - TOPICCATEGORY: 'topicCategory', + TOPIC_TITLE: 'topicTitle', + A_TOPIC: 'aTopic', + B_TOPIC: 'bTopic', + A_TOPIC_IMAGEURL: 'aTopicImageURL', + B_TOPIC_IMAGEURL: 'bTopicImageURL', + TOPIC_CATEGORY: 'topicCategory', + TOPIC_DEADLINE: 'topicDeadline', } as const; export type ConfigKeys = keyof typeof INPUT_TYPE; @@ -63,7 +66,7 @@ export const CONFIG: Record = { }, }, }, - TOPICTITLE: { + TOPIC_TITLE: { options: { required: { value: true, @@ -79,17 +82,31 @@ export const CONFIG: Record = { }, }, }, - ATOPIC: { + A_TOPIC: { + options: { + required: true, + maxLength: { + value: 25, + message: '', + }, + }, + }, + B_TOPIC: { + options: { + required: true, + }, + }, + A_TOPIC_IMAGEURL: { options: { required: true, }, }, - BTOPIC: { + B_TOPIC_IMAGEURL: { options: { required: true, }, }, - TOPICCATEGORY: { + TOPIC_CATEGORY: { options: { required: { value: true, @@ -105,4 +122,9 @@ export const CONFIG: Record = { }, }, }, + TOPIC_DEADLINE: { + options: { + required: true, + }, + }, } as const; From 2e67b540676c1c41bf318208f924b10355a05705 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:10:02 +0900 Subject: [PATCH 18/38] feat: add BTopicCreate Step2 page --- .../TopicCreateImageInput.styles.tsx | 60 ++------ .../TopicCreate/TopicCreateImageInput.tsx | 135 ++++-------------- .../TopicCreate/TopicCreateTextInput.tsx | 27 ++-- .../Create/BSide/BTopicCreateStep2.styles.tsx | 29 ++++ .../Topic/Create/BSide/BTopicCreateStep2.tsx | 71 ++++++++- 5 files changed, 153 insertions(+), 169 deletions(-) diff --git a/src/components/TopicCreate/TopicCreateImageInput.styles.tsx b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx index bf64b8b..92e48ec 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.styles.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx @@ -8,8 +8,6 @@ export const ReplaceButton = styled.div` gap: 6px; align-items: center; justify-content: space-between; - width: 111px; - height: 18px; `; export const ReplaceIcon = styled.div` @@ -20,56 +18,20 @@ export const ReplaceIcon = styled.div` height: 14px; `; -export const ImageInputContainer = styled.div` - position: relative; - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: center; - width: 122px; - height: 124px; - overflow: hidden; - background-color: ${colors.navy2_80}; - border-radius: 10px; -`; - -export const Image = styled.img` - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 100%; - overflow: hidden; -`; - -export const ImageInput = styled.input` - display: none; -`; - -export const ImageInputTextContainer = styled.div` - position: absolute; - top: 32px; - left: 50%; - display: flex; - align-items: center; - justify-content: center; - transform: translateX(-50%); -`; - -export const ImageInputDescriptionContainer = styled.div` - position: absolute; - top: 50%; - left: 50%; - display: flex; - align-items: center; - justify-content: center; - transform: translate(-50%, -50%); -`; - export const InputSuffix = styled.div` position: absolute; top: 50%; right: 16px; transform: translateY(-50%); `; + +export const ImageInputDescription = styled.div` + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: flex-start; + width: 100%; + padding: 16px; + background-color: rgb(255 255 255 / 4%); + border-radius: 10px; +`; diff --git a/src/components/TopicCreate/TopicCreateImageInput.tsx b/src/components/TopicCreate/TopicCreateImageInput.tsx index a1348ef..c369c94 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.tsx @@ -1,7 +1,4 @@ -import { Register } from '@tanstack/react-query'; -import React, { useRef, useState } from 'react'; -import { RegisterOptions, useFormContext } from 'react-hook-form'; -import { CONFIG, INPUT_TYPE, InputType } from 'src/constants/form'; +import React from 'react'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; @@ -10,15 +7,9 @@ import { colors } from '@styles/theme'; import { RotateIcon } from '@icons/index'; -import { - ReplaceButton, - ReplaceIcon, - ImageInput, - ImageInputContainer, - ImageInputTextContainer, - ImageInputDescriptionContainer, - Image, -} from './TopicCreateImageInput.styles'; +import ImageInputComponent from './ImageInputComponent'; +import { ImageInputChip } from './ImageInputComponent.styles'; +import { ImageInputDescription, ReplaceButton, ReplaceIcon } from './TopicCreateImageInput.styles'; interface TopicCreareProps { topic: 'A' | 'B'; @@ -27,50 +18,9 @@ interface TopicCreareProps { } const TopicCreateImageInput = () => { - const { register, watch } = useFormContext(); - const imageInputRef_A = useRef(null); - const imageInputRef_B = useRef(null); - const [imageAUrl, setImageAUrl] = useState(null); - const [imageBUrl, setImageBUrl] = useState(null); - - const handleImageInputAClick = () => { - if (imageInputRef_A.current) { - imageInputRef_A.current.click(); - } - }; - - const handleImageInputBClick = () => { - if (imageInputRef_B.current) { - imageInputRef_B.current.click(); - } - }; - - const handleFileChangeA = (event: React.ChangeEvent) => { - handleFileChange(event, setImageAUrl); - }; - - const handleFileChangeB = (event: React.ChangeEvent) => { - handleFileChange(event, setImageBUrl); - }; - - const handleFileChange = ( - event: React.ChangeEvent, - setImageUrl: React.Dispatch> - ) => { - const fileObj = event.target.files && event.target.files[0]; - if (!fileObj) { - return; - } - - const reader = new FileReader(); - reader.onloadend = () => { - setImageUrl(reader.result as string); - }; - reader.readAsDataURL(fileObj); - }; return ( - - + + 어떤 선택지가 있나요? @@ -83,54 +33,31 @@ const TopicCreateImageInput = () => { - - - {imageAUrl && Image A} - - - A - - - {!imageAUrl && ( - - - 이미지 -
- 가져오기 -
-
- )} - -
- - {imageBUrl && Image B} - - - B - - - {!imageBUrl && ( - - - 이미지 -
- 가져오기 -
-
- )} - -
-
+ + + + {['A', 'B'].map((label) => ( + + ))} + + + {['A', 'B'].map((label) => ( + + + {label} 선택지 + + + ))} + + + + + 가로 세로 길이가 같은 사진을 올리는 것이 좋아요. +
+ 너무 큰 용량의 사진은 화질이 조정될 수 있어요. +
+
+ ); }; diff --git a/src/components/TopicCreate/TopicCreateTextInput.tsx b/src/components/TopicCreate/TopicCreateTextInput.tsx index 2baeb25..fe3806c 100644 --- a/src/components/TopicCreate/TopicCreateTextInput.tsx +++ b/src/components/TopicCreate/TopicCreateTextInput.tsx @@ -1,7 +1,6 @@ -import { Register } from '@tanstack/react-query'; import React from 'react'; -import { RegisterOptions, useFormContext } from 'react-hook-form'; -import { CONFIG, INPUT_TYPE, InputType } from 'src/constants/form'; +import { useFormContext } from 'react-hook-form'; +import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; @@ -25,15 +24,15 @@ interface TopicCreareProps { const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { const { register, watch } = useFormContext(); - const ATopicProgress = watch(INPUT_TYPE.ATOPIC) - ? `${watch(INPUT_TYPE.ATOPIC)?.length}/25` + const ATopicProgress = watch(INPUT_TYPE.A_TOPIC) + ? `${watch(INPUT_TYPE.A_TOPIC)?.length}/25` : '0/25'; - const BTopicProgress = watch(INPUT_TYPE.BTOPIC) - ? `${watch(INPUT_TYPE.BTOPIC)?.length}/25` + const BTopicProgress = watch(INPUT_TYPE.B_TOPIC) + ? `${watch(INPUT_TYPE.B_TOPIC)?.length}/25` : '0/25'; return ( - + 어떤 선택지가 있나요? @@ -41,7 +40,7 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { - + AB 선택지 바꾸기 @@ -49,13 +48,14 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { - + A @@ -66,13 +66,14 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { - + B diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx index 2dfe8a3..d6df3b3 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.styles.tsx @@ -31,3 +31,32 @@ export const SelectIconContainer = styled.button<{ selected: boolean }>` border-radius: 50%; transition: all 0.2s ease-in-out; `; + +export const DeadlineInputContainer = styled.div` + position: relative; + display: flex; + gap: 6px; + align-items: center; + justify-content: space-between; +`; + +export const DeadlineInputButton = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 14px; + height: 14px; +`; + +export const DeadlineInput = styled.select` + position: absolute; + top: 50%; + left: 50%; + display: flex; + align-items: center; + justify-content: center; + width: 80px; + height: 24px; + opacity: 0; + transform: translate(-50%, -50%); +`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx index ae48ada..671c871 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -1,5 +1,7 @@ import React, { useState } from 'react'; import { useFormContext } from 'react-hook-form'; +import { CONFIG, INPUT_TYPE } from 'src/constants/form'; +import { TOPIC_DEADLINES } from 'src/constants/topic'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; @@ -8,9 +10,22 @@ import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; import { colors } from '@styles/theme'; -import { ImageIcon, SelectedImageIcon, SelectedTextIcon, TextIcon } from '@icons/index'; +import { + BigDownChevronIcon, + ImageIcon, + SelectedImageIcon, + SelectedTextIcon, + TextIcon, +} from '@icons/index'; -import { Container, SelectIconContainer, UnderLine } from './BTopicCreateStep2.styles'; +import { + Container, + DeadlineInput, + DeadlineInputButton, + DeadlineInputContainer, + SelectIconContainer, + UnderLine, +} from './BTopicCreateStep2.styles'; interface BTopicCreateStep2Props { topicTitle: string; @@ -19,12 +34,20 @@ interface BTopicCreateStep2Props { } const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props) => { - const methods = useFormContext(); + const { register, setValue } = useFormContext(); const [selected, setSelected] = useState('text'); + const [selectedDeadline, setSelectedDeadline] = useState('1시간 뒤'); + const Selection = selected === 'text' ? : ; + const { + ref: deadlineInputRef, + onChange: deadlinInputOnChange, + ...rest + } = register(INPUT_TYPE.TOPIC_DEADLINE, CONFIG.TOPIC_DEADLINE.options); + const handleTextSelect = () => { setSelected('text'); }; @@ -33,6 +56,23 @@ const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props setSelected('image'); }; + const handleDeadlineInputClick = () => { + const inputElement = document.getElementById(INPUT_TYPE.TOPIC_DEADLINE); + if (inputElement) { + inputElement.click(); + console.log('click'); + } + }; + + const handleDeadlineChange = (e: React.ChangeEvent) => { + deadlinInputOnChange(e); + setValue(INPUT_TYPE.TOPIC_DEADLINE, e.target.value); + setSelectedDeadline( + `${TOPIC_DEADLINES.find((option) => option.value.toString() === e.target.value)?.label} 뒤` + ); + console.log(selectedDeadline); + }; + return ( @@ -58,6 +98,31 @@ const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props {Selection} + + + + + + + {selectedDeadline} + + handleDeadlineChange(e)} + {...rest} + > + {TOPIC_DEADLINES.map((option, index) => ( + + ))} + + + + 에 토픽을 마감해요 + + ); From 9bf16118d7f7f5c6d8081e3b4530b9b5bf21ee8e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:11:07 +0900 Subject: [PATCH 19/38] feat: separate imageinput component --- .../ImageInputComponent.styles.tsx | 146 ++++++++++++++++++ .../TopicCreate/ImageInputComponent.tsx | 126 +++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 src/components/TopicCreate/ImageInputComponent.styles.tsx create mode 100644 src/components/TopicCreate/ImageInputComponent.tsx diff --git a/src/components/TopicCreate/ImageInputComponent.styles.tsx b/src/components/TopicCreate/ImageInputComponent.styles.tsx new file mode 100644 index 0000000..2bf4e2a --- /dev/null +++ b/src/components/TopicCreate/ImageInputComponent.styles.tsx @@ -0,0 +1,146 @@ +import { color } from 'framer-motion'; +import { styled } from 'styled-components'; + +import { colors } from '@styles/theme'; + +export const ImageInputContainer = styled.div` + position: relative; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 122px; + height: 124px; + overflow: hidden; + background-color: ${colors.navy2_80}; + border-radius: 10px; +`; + +export const Image = styled.img` + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + overflow: hidden; +`; + +export const ImageInput = styled.input` + display: none; +`; + +export const ImageCover = styled.div` + position: absolute; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background-color: ${colors.navy2_40}; +`; + +export const ImageInputTextContainer = styled.div` + position: absolute; + top: 32px; + left: 50%; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + transform: translateX(-50%); +`; + +export const ImageInputChip = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 65px; + height: 22px; + background-color: ${colors.navy2_40}; + border-radius: 20px; +`; + +export const ImageInputDescriptionContainer = styled.div` + position: absolute; + top: 50%; + left: 50%; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + transform: translate(-50%, -50%); +`; + +export const DeleteButton = styled.button` + position: absolute; + top: 8px; + left: 50%; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + padding: 7px; + background: ${colors.navy_40}; + border: 1px solid ${colors.white_40}; + border-radius: 50%; + transform: translate(-50%, 0); +`; + +export const ModalContainer = styled.div<{ side: string }>` + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + width: 100%; + height: 488px; + overflow: hidden; + background-color: ${(props) => (props.side === 'A' ? colors.A : colors.B)}; +`; + +export const ModalImage = styled.img` + width: 100%; + height: 340px; + background-color: ${colors.white}; +`; + +export const ModalContent = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + overflow: hidden; +`; + +export const ModalContentText = styled.div` + position: absolute; + display: flex; + font-size: 24px; + font-weight: 600; + color: ${colors.white}; +`; + +export const CloseButton = styled.button` + position: absolute; + top: 10px; + left: 10px; + width: 24px; + height: 24px; + padding: 5px; + background: rgb(0 0 0 / 60%); + border-radius: 50%; +`; + +export const DescriptionContainer = styled.div` + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + transform: translate(-50%, -50%); +`; diff --git a/src/components/TopicCreate/ImageInputComponent.tsx b/src/components/TopicCreate/ImageInputComponent.tsx new file mode 100644 index 0000000..5b47d1f --- /dev/null +++ b/src/components/TopicCreate/ImageInputComponent.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { set, useFormContext } from 'react-hook-form'; +import { INPUT_TYPE } from 'src/constants/form'; + +import Text from '@components/commons/Text/Text'; +import useModal from '@hooks/useModal/useModal'; + +import { colors } from '@styles/theme'; + +import { CloseIcon, DeleteIcon } from '@icons/index'; + +import { + ImageInputContainer, + Image, + ImageInput, + ImageInputDescriptionContainer, + ImageInputTextContainer, + ImageCover, + ModalContainer, + ModalImage, + ModalContent, + ModalContentText, + CloseButton, + DeleteButton, +} from './ImageInputComponent.styles'; + +interface ImageInputComponetProps { + label: string; +} + +const ImageInputComponent = ({ label }: ImageInputComponetProps) => { + const { Modal, toggleModal } = useModal('default'); + const { register, setValue } = useFormContext(); + const id = label === 'A' ? INPUT_TYPE.A_TOPIC_IMAGEURL : INPUT_TYPE.B_TOPIC_IMAGEURL; + const [imageUrl, setImageUrl] = useState(null); + + const handleFileChange = ( + event: React.ChangeEvent, + registerOnChange: React.ChangeEventHandler + ) => { + registerOnChange(event); + + console.log(event.target); + const fileObj = event.target.files && event.target.files[0]; + console.log(fileObj); + if (!fileObj) { + return; + } + + const reader = new FileReader(); + reader.onloadend = () => { + setImageUrl(reader.result as string); + }; + reader.readAsDataURL(fileObj); + }; + + const handleDeleteButtonClick = (e: React.MouseEvent) => { + e.stopPropagation(); + setImageUrl(null); + setValue(id, null); + }; + + return ( + { + if (imageUrl) { + toggleModal(); + } else { + document.getElementById(id)?.click(); + } + }} + > + {imageUrl && ( + <> + {`image${label}`} + handleDeleteButtonClick(e)}> + + + + + )} + + + {label} + + + {!imageUrl && ( + + + 이미지 +
+ 가져오기 +
+
+ )} + handleFileChange(event, register(id).onChange)} + /> + + + + + + {label} + + {label} + + toggleModal}> + + + + +
+ ); +}; + +export default ImageInputComponent; From 38d716554b7915b327cfe03f96416381ed583ed7 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:11:32 +0900 Subject: [PATCH 20/38] feat: add imgurl dto --- src/routes/Topic/Create/BSide/BTopicCreate.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index 3cb8311..98f860d 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -1,7 +1,6 @@ import React, { useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate, useSearchParams } from 'react-router-dom'; -import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Container, @@ -17,6 +16,8 @@ interface TopicCreateDTO { ATopic: string; BTopic: string; topicCategory: string; + aTopicImageURL: string; + bTopicImageURL: string; } const BTopicCreate = () => { From 1885fe4f1d032220b802a9687ce46726712d1e74 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:11:52 +0900 Subject: [PATCH 21/38] feat: add topic deadline constant --- src/constants/topic.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/constants/topic.ts diff --git a/src/constants/topic.ts b/src/constants/topic.ts new file mode 100644 index 0000000..1c1b8c0 --- /dev/null +++ b/src/constants/topic.ts @@ -0,0 +1,15 @@ +interface TopicDeadline { + label: string; + value: number; +} + +export const TOPIC_DEADLINES: TopicDeadline[] = Array.from({ length: 24 }, (_, i) => { + const hoursToAdd = i + 1; + const date = new Date(); + date.setHours(date.getHours() + hoursToAdd); + + return { + label: `${hoursToAdd}시간`, + value: Math.floor(date.getTime() / 1000), + }; +}); From 1841bcce4dea9524f4f78e2b473ef3ade5b113b0 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Fri, 2 Feb 2024 16:12:11 +0900 Subject: [PATCH 22/38] fix: modal close button width, height fix --- src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx | 5 +++-- src/components/Home/ChoiceSlide/ChoiceSlide.tsx | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx b/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx index 5515ecd..3b6bddf 100644 --- a/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx +++ b/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx @@ -102,8 +102,9 @@ export const CloseButton = styled.button` position: absolute; top: 10px; left: 10px; - width: 34px; - height: 34px; + width: 24px; + height: 24px; + padding: 5px; background: rgb(0 0 0 / 60%); border-radius: 50%; `; diff --git a/src/components/Home/ChoiceSlide/ChoiceSlide.tsx b/src/components/Home/ChoiceSlide/ChoiceSlide.tsx index ce85ba5..9a761d3 100644 --- a/src/components/Home/ChoiceSlide/ChoiceSlide.tsx +++ b/src/components/Home/ChoiceSlide/ChoiceSlide.tsx @@ -84,7 +84,7 @@ const ChoiceSlide = ({ side, topicContent }: ChoiceSlideProps) => { {topicContent.text} - + toggleModal}> From 9252b80ed5eb4e0272556f722cc919c7062058bd Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Wed, 7 Feb 2024 15:44:12 +0900 Subject: [PATCH 23/38] =?UTF-8?q?feat:=20=ED=86=A0=ED=94=BD=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20api=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/topic/useTopics.ts | 31 +++++++++++++++++++++++++++++-- src/constants/topic.ts | 15 ++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/apis/topic/useTopics.ts b/src/apis/topic/useTopics.ts index 486514a..bf4ca64 100644 --- a/src/apis/topic/useTopics.ts +++ b/src/apis/topic/useTopics.ts @@ -1,6 +1,6 @@ -import { useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; -import { TopicResponse } from '@interfaces/api/topic'; +import { CHOICE_OPTIONS, ChoiceContent, TopicResponse } from '@interfaces/api/topic'; import { PagingDataResponse } from '@interfaces/api'; @@ -8,6 +8,20 @@ import client from '@apis/fetch'; export const TOPIC_KEY = 'topics'; +interface Choice { + choiceId: number; + choiceContentRequest: ChoiceContent; + choiceOption: typeof CHOICE_OPTIONS.CHOICE_A | typeof CHOICE_OPTIONS.CHOICE_B; +} + +interface TopicCreateRequestDTO { + side: string; + keywordName: string; + title: string; + choices: Choice[]; + deadline: number; +} + const getTopics = () => { return client.get>('/topics/info/voting'); }; @@ -16,4 +30,17 @@ const useTopics = () => { return useQuery({ queryKey: [TOPIC_KEY], queryFn: getTopics }); }; +const createTopics = (req: TopicCreateRequestDTO) => { + return client.post({ + path: `/topics`, + body: req, + }); +}; + +const useCreateTopics = () => { + return useMutation({ mutationFn: createTopics }); +}; + export default useTopics; + +export { useCreateTopics }; diff --git a/src/constants/topic.ts b/src/constants/topic.ts index 1c1b8c0..85b1581 100644 --- a/src/constants/topic.ts +++ b/src/constants/topic.ts @@ -5,11 +5,20 @@ interface TopicDeadline { export const TOPIC_DEADLINES: TopicDeadline[] = Array.from({ length: 24 }, (_, i) => { const hoursToAdd = i + 1; - const date = new Date(); - date.setHours(date.getHours() + hoursToAdd); return { label: `${hoursToAdd}시간`, - value: Math.floor(date.getTime() / 1000), + value: i + 1, }; }); + +// export const TOPIC_DEADLINES: TopicDeadline[] = Array.from({ length: 24 }, (_, i) => { +// const hoursToAdd = i + 1; +// const date = new Date(); +// date.setHours(date.getHours() + hoursToAdd); + +// return { +// label: `${hoursToAdd}시간`, +// value: Math.floor(date.getTime() / 1000), +// }; +// }); From ce8ed019194cdbd3aeb0bab8128684563062b58b Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Wed, 7 Feb 2024 15:44:57 +0900 Subject: [PATCH 24/38] =?UTF-8?q?feat:=20=ED=86=A0=ED=94=BD=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20form=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TopicCreate/ImageInputComponent.tsx | 3 +- .../TopicCreateImageInput.styles.tsx | 2 +- .../TopicCreate/TopicCreateImageInput.tsx | 29 +++++- .../TopicCreateTextInput.styles.tsx | 3 +- .../TopicCreate/TopicCreateTextInput.tsx | 30 ++++-- .../commons/TextInput/TextInput.tsx | 12 ++- src/constants/form.ts | 30 +++--- .../Topic/Create/ASide/ATopicCreate.tsx | 24 +++-- .../Create/BSide/BTopicCreate.styles.tsx | 10 ++ .../Topic/Create/BSide/BTopicCreate.tsx | 92 ++++++++++++++----- .../Topic/Create/BSide/BTopicCreateStep1.tsx | 31 +++++-- .../Topic/Create/BSide/BTopicCreateStep2.tsx | 54 +++++------ .../Topic/Create/TopicCreate.sytles.tsx | 6 +- src/routes/Topic/Create/TopicCreate.tsx | 21 ++++- 14 files changed, 249 insertions(+), 98 deletions(-) diff --git a/src/components/TopicCreate/ImageInputComponent.tsx b/src/components/TopicCreate/ImageInputComponent.tsx index 5b47d1f..adf2cc1 100644 --- a/src/components/TopicCreate/ImageInputComponent.tsx +++ b/src/components/TopicCreate/ImageInputComponent.tsx @@ -40,9 +40,7 @@ const ImageInputComponent = ({ label }: ImageInputComponetProps) => { ) => { registerOnChange(event); - console.log(event.target); const fileObj = event.target.files && event.target.files[0]; - console.log(fileObj); if (!fileObj) { return; } @@ -50,6 +48,7 @@ const ImageInputComponent = ({ label }: ImageInputComponetProps) => { const reader = new FileReader(); reader.onloadend = () => { setImageUrl(reader.result as string); + setValue(id, reader.result as string); }; reader.readAsDataURL(fileObj); }; diff --git a/src/components/TopicCreate/TopicCreateImageInput.styles.tsx b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx index 92e48ec..730ea55 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.styles.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.styles.tsx @@ -2,7 +2,7 @@ import { styled } from 'styled-components'; import { colors } from '@styles/theme'; -export const ReplaceButton = styled.div` +export const ReplaceButton = styled.button` display: flex; flex-direction: row; gap: 6px; diff --git a/src/components/TopicCreate/TopicCreateImageInput.tsx b/src/components/TopicCreate/TopicCreateImageInput.tsx index c369c94..6ca8b4d 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; @@ -18,17 +20,36 @@ interface TopicCreareProps { } const TopicCreateImageInput = () => { + const { getValues, getFieldState } = useFormContext(); + + const [isImageFilled, setIsImageFilled] = useState(false); + + useEffect(() => { + if ( + !getFieldState(INPUT_TYPE.A_TOPIC_IMAGEURL).invalid && + !getFieldState(INPUT_TYPE.B_TOPIC_IMAGEURL).invalid + ) { + setIsImageFilled(true); + } else { + setIsImageFilled(false); + } + }, [getValues([INPUT_TYPE.A_TOPIC_IMAGEURL, INPUT_TYPE.B_TOPIC_IMAGEURL])]); return ( 어떤 선택지가 있나요? - + - + - + AB 선택지 바꾸기 diff --git a/src/components/TopicCreate/TopicCreateTextInput.styles.tsx b/src/components/TopicCreate/TopicCreateTextInput.styles.tsx index fbef74a..51fcb17 100644 --- a/src/components/TopicCreate/TopicCreateTextInput.styles.tsx +++ b/src/components/TopicCreate/TopicCreateTextInput.styles.tsx @@ -2,7 +2,7 @@ import { styled } from 'styled-components'; import { colors } from '@styles/theme'; -export const ReplaceButton = styled.div` +export const ReplaceButton = styled.button` display: flex; flex-direction: row; gap: 6px; @@ -44,6 +44,7 @@ export const TextInputTextContainer = styled.div` `; export const Input = styled.input` + z-index: 1; width: 100%; height: 100%; padding: 16px; diff --git a/src/components/TopicCreate/TopicCreateTextInput.tsx b/src/components/TopicCreate/TopicCreateTextInput.tsx index fe3806c..d48cfea 100644 --- a/src/components/TopicCreate/TopicCreateTextInput.tsx +++ b/src/components/TopicCreate/TopicCreateTextInput.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; import { CONFIG, INPUT_TYPE } from 'src/constants/form'; @@ -18,29 +18,45 @@ import { InputSuffix, } from './TopicCreateTextInput.styles'; -interface TopicCreareProps { +interface TopicCreateProps { onKeyDown?: (e: React.KeyboardEvent) => void; } -const TopicCreateTextInput = ({ onKeyDown }: TopicCreareProps) => { - const { register, watch } = useFormContext(); +const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { + const { register, watch, getValues } = useFormContext(); const ATopicProgress = watch(INPUT_TYPE.A_TOPIC) ? `${watch(INPUT_TYPE.A_TOPIC)?.length}/25` : '0/25'; const BTopicProgress = watch(INPUT_TYPE.B_TOPIC) ? `${watch(INPUT_TYPE.B_TOPIC)?.length}/25` : '0/25'; + + const [isTopicFilled, setIsTopicFilled] = useState(false); + + useEffect(() => { + if (getValues(INPUT_TYPE.A_TOPIC) && getValues(INPUT_TYPE.B_TOPIC)) { + setIsTopicFilled(true); + } else { + setIsTopicFilled(false); + } + }, [getValues([INPUT_TYPE.A_TOPIC, INPUT_TYPE.B_TOPIC])]); + return ( 어떤 선택지가 있나요? - + - + - + AB 선택지 바꾸기 diff --git a/src/components/commons/TextInput/TextInput.tsx b/src/components/commons/TextInput/TextInput.tsx index 1484bf5..c46f69a 100644 --- a/src/components/commons/TextInput/TextInput.tsx +++ b/src/components/commons/TextInput/TextInput.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { RegisterOptions, useFormContext } from 'react-hook-form'; import { InputType } from 'src/constants/form'; @@ -40,7 +40,16 @@ const TextInput = (props: TextInputProps) => { const { register, formState: { errors }, + watch, + setValue, } = useFormContext(); + const value = watch(id); + + useEffect(() => { + if (maxLength && value?.length > maxLength) { + setValue(id, value.slice(0, maxLength)); + } + }, [value]); return (
@@ -51,6 +60,7 @@ const TextInput = (props: TextInputProps) => { type={type} placeholder={placeholder} maxLength={maxLength} + autoComplete="off" {...register(id, options)} onKeyDown={onKeyDown} /> diff --git a/src/constants/form.ts b/src/constants/form.ts index d11eaf6..cf80ba4 100644 --- a/src/constants/form.ts +++ b/src/constants/form.ts @@ -10,10 +10,11 @@ export const INPUT_TYPE = { GENDER: 'gender', JOB: 'job', TOPIC_TITLE: 'topicTitle', - A_TOPIC: 'aTopic', - B_TOPIC: 'bTopic', - A_TOPIC_IMAGEURL: 'aTopicImageURL', - B_TOPIC_IMAGEURL: 'bTopicImageURL', + A_TOPIC: 'ATopic', + B_TOPIC: 'BTopic', + A_TOPIC_IMAGEURL: 'ATopicImageURL', + B_TOPIC_IMAGEURL: 'BTopicImageURL', + TOPIC_CONTENT_TYPE: 'topicType', TOPIC_CATEGORY: 'topicCategory', TOPIC_DEADLINE: 'topicDeadline', } as const; @@ -72,10 +73,6 @@ export const CONFIG: Record = { value: true, message: '제목을 입력해주세요.', }, - pattern: { - value: /^[가-힣a-zA-Z0-9!@#$%^()]+$/, - message: '특수문자는 !@#$%^()만 사용하실 수 있습니다.', - }, maxLength: { value: 20, message: '제목은 20자리 이내로 입력해주세요.', @@ -84,16 +81,18 @@ export const CONFIG: Record = { }, A_TOPIC: { options: { - required: true, - maxLength: { - value: 25, + required: { + value: true, message: '', }, }, }, B_TOPIC: { options: { - required: true, + required: { + value: true, + message: '', + }, }, }, A_TOPIC_IMAGEURL: { @@ -117,11 +116,16 @@ export const CONFIG: Record = { message: '한글, 영문, 숫자만 가능해요.', }, maxLength: { - value: 20, + value: 6, message: '카테고리는 6자리 이내로 입력해주세요.', }, }, }, + TOPIC_CONTENT_TYPE: { + options: { + required: true, + }, + }, TOPIC_DEADLINE: { options: { required: true, diff --git a/src/routes/Topic/Create/ASide/ATopicCreate.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.tsx index 2c4002b..4f827ff 100644 --- a/src/routes/Topic/Create/ASide/ATopicCreate.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { CONFIG, INPUT_TYPE } from 'src/constants/form'; @@ -25,11 +25,23 @@ const ATopicCreate = () => { const titleProgress = methods.watch(INPUT_TYPE.TOPIC_TITLE) ? `${methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length}/20` : '0/20'; - - const handleSummitButtonClick = () => { - console.log('summit'); + const [isFormFilled, setIsFormFilled] = useState(false); + const handleSubmitButtonClick = () => { + console.log('submit'); }; + useEffect(() => { + if ( + methods.getValues(INPUT_TYPE.TOPIC_TITLE) && + methods.getValues(INPUT_TYPE.A_TOPIC) && + methods.getValues(INPUT_TYPE.B_TOPIC) + ) { + setIsFormFilled(true); + } else { + setIsFormFilled(false); + } + }, [methods.getValues([INPUT_TYPE.TOPIC_TITLE, INPUT_TYPE.A_TOPIC, INPUT_TYPE.B_TOPIC])]); + return ( @@ -56,8 +68,8 @@ const ATopicCreate = () => { diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx index 12f759a..ecd63a5 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.styles.tsx @@ -46,3 +46,13 @@ export const PageControllerLine = styled.div` background-color: ${colors.navy}; border: 1px solid ${colors.navy2}; `; + +export const SubmitButton = styled.div` + position: absolute; + bottom: 48px; + left: 50%; + justify-content: center; + width: 100%; + padding: 0 20px; + transform: translateX(-50%); +`; diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index 98f860d..6ba03bc 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -1,12 +1,16 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; +import { INPUT_TYPE } from 'src/constants/form'; + +import DefaultButton from '@components/commons/Button/DefaultButton'; import { Container, PageController, PageControllerContainer, PageControllerLine, + SubmitButton, } from './BTopicCreate.styles'; import BTopicCreateStep1 from './BTopicCreateStep1'; import BTopicCreateStep2 from './BTopicCreateStep2'; @@ -16,42 +20,88 @@ interface TopicCreateDTO { ATopic: string; BTopic: string; topicCategory: string; - aTopicImageURL: string; - bTopicImageURL: string; + ATopicImageURL: string; + BTopicImageURL: string; + topicDeadline: string; + topicType: string; } const BTopicCreate = () => { - const navigate = useNavigate(); const methods = useForm({ mode: 'onChange' }); const [searchParams] = useSearchParams(); const step = searchParams.get('step'); - const navigateToNextStep = () => { - navigate('/topics/create/B?step=2'); + const [isFormFilled, setIsFormFilled] = useState(false); + + const Step = step === '1' ? : ; + + const handleSubmitButtonClick = () => { + console.log('submit'); }; + useEffect(() => { + const contentType = methods.getValues(INPUT_TYPE.TOPIC_CONTENT_TYPE); + console.log('ㅋ', contentType); + const ATopicCondition = methods.getFieldState(INPUT_TYPE.A_TOPIC, methods.formState); + const BTopicCondition = methods.getFieldState(INPUT_TYPE.B_TOPIC, methods.formState); + const ATopiImageURLCondition = methods.getFieldState( + INPUT_TYPE.A_TOPIC_IMAGEURL, + methods.formState + ); + const BTopicImageURLCondition = methods.getFieldState( + INPUT_TYPE.B_TOPIC_IMAGEURL, + methods.formState + ); + if (step === '2') { + if (contentType === 'text') { + if ( + !ATopicCondition.invalid && + ATopicCondition.isDirty && + !BTopicCondition.invalid && + BTopicCondition.isDirty + ) { + setIsFormFilled(true); + } else { + setIsFormFilled(false); + } + } else if (contentType === 'image') { + if ( + !ATopiImageURLCondition.invalid && + ATopiImageURLCondition.isDirty && + !BTopicImageURLCondition.invalid && + BTopicImageURLCondition.isDirty + ) { + setIsFormFilled(true); + } else { + setIsFormFilled(false); + } + } + } + }, [methods.formState, step, methods.getValues([INPUT_TYPE.TOPIC_CONTENT_TYPE])]); + if (step === null) { return; } - const Step = - step === '1' ? ( - - ) : ( - - ); - return ( {Step} - - 1 - - - 2 - - + {isFormFilled ? ( + + + + ) : ( + + 1 + + 2 + + )} ); diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx index 440151b..83fb814 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useNavigate } from 'react-router-dom'; import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Col } from '@components/commons/Flex/Flex'; @@ -11,27 +12,43 @@ import { colors } from '@styles/theme'; import { CategoryChip, CategoryChipContainer, Container } from './BTopicCreateStep1.styles'; -interface BTopicCreareProps { - onKeyDown?: (e: React.KeyboardEvent) => void; -} - const BTopicCreateStep1 = () => { + const navigate = useNavigate(); const methods = useFormContext(); const titleProgress = methods.watch(INPUT_TYPE.TOPIC_TITLE) - ? `${methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length}/20` + ? `${Math.min(methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length, 20)}/20` : '0/20'; const categoryProgress = methods.watch(INPUT_TYPE.TOPIC_CATEGORY) - ? `${methods.watch(INPUT_TYPE.TOPIC_CATEGORY)?.length}/6` + ? `${Math.min(methods.watch(INPUT_TYPE.TOPIC_CATEGORY)?.length, 20)}/6` : '0/6'; const categoryChipList = ['스포츠', '연예방송', '일상다반사', '게임', '일상']; + const navigateToNextStep = () => { + navigate('/topics/create/B?step=2'); + }; + const handleCategoryChipClick = (categoryChip: string) => { methods.setValue(INPUT_TYPE.TOPIC_CATEGORY, categoryChip); methods.clearErrors(INPUT_TYPE.TOPIC_CATEGORY); }; + const handleEnterkey = async (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + e.preventDefault(); + + // Trigger validation for the fields + const result = await methods.trigger([INPUT_TYPE.TOPIC_TITLE, INPUT_TYPE.TOPIC_CATEGORY]); + + if (result) { + setTimeout(() => navigateToNextStep(), 1000); + } else { + console.log('invalid'); + } + } + }; + return ( @@ -45,6 +62,7 @@ const BTopicCreateStep1 = () => { options={CONFIG.TOPIC_TITLE.options} placeholder={'제목을 입력해주세요.'} theme={theme3} + onKeyDown={handleEnterkey} right={() => ( {titleProgress} @@ -63,6 +81,7 @@ const BTopicCreateStep1 = () => { placeholder={'한글, 영문, 숫자만 가능.'} maxLength={6} theme={theme2} + onKeyDown={handleEnterkey} right={() => ( {categoryProgress} diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx index 671c871..886dff7 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -1,5 +1,6 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; +import { useNavigate } from 'react-router-dom'; import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { TOPIC_DEADLINES } from 'src/constants/topic'; @@ -27,14 +28,12 @@ import { UnderLine, } from './BTopicCreateStep2.styles'; -interface BTopicCreateStep2Props { - topicTitle: string; - topicCategory: string; - onKeyDown?: (e: React.KeyboardEvent) => void; -} +const BTopicCreateStep2 = () => { + const navigate = useNavigate(); + const { register, setValue, getValues } = useFormContext(); -const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props) => { - const { register, setValue } = useFormContext(); + const topicTitle = getValues(INPUT_TYPE.TOPIC_TITLE); + const topicCategory = getValues(INPUT_TYPE.TOPIC_CATEGORY); const [selected, setSelected] = useState('text'); @@ -42,37 +41,39 @@ const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props const Selection = selected === 'text' ? : ; - const { - ref: deadlineInputRef, - onChange: deadlinInputOnChange, - ...rest - } = register(INPUT_TYPE.TOPIC_DEADLINE, CONFIG.TOPIC_DEADLINE.options); + const { onChange: deadlinInputOnChange, ...rest } = register( + INPUT_TYPE.TOPIC_DEADLINE, + CONFIG.TOPIC_DEADLINE.options + ); + + setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'text'); const handleTextSelect = () => { + setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'text'); setSelected('text'); }; const handleImageSelect = () => { + setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'image'); setSelected('image'); }; - const handleDeadlineInputClick = () => { - const inputElement = document.getElementById(INPUT_TYPE.TOPIC_DEADLINE); - if (inputElement) { - inputElement.click(); - console.log('click'); - } - }; - const handleDeadlineChange = (e: React.ChangeEvent) => { deadlinInputOnChange(e); setValue(INPUT_TYPE.TOPIC_DEADLINE, e.target.value); - setSelectedDeadline( - `${TOPIC_DEADLINES.find((option) => option.value.toString() === e.target.value)?.label} 뒤` - ); - console.log(selectedDeadline); + setSelectedDeadline(`${e.target.value}시간 뒤`); }; + useEffect(() => { + if (!topicTitle || !topicCategory) { + navigate(-1); + } + }, [topicTitle, topicCategory]); + + useEffect(() => { + register(INPUT_TYPE.TOPIC_CONTENT_TYPE, CONFIG.TOPIC_CONTENT_TYPE.options); + }, [register]); + return ( @@ -99,7 +100,7 @@ const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props {Selection} - + @@ -108,7 +109,6 @@ const BTopicCreateStep2 = ({ topicTitle, topicCategory }: BTopicCreateStep2Props handleDeadlineChange(e)} {...rest} > diff --git a/src/routes/Topic/Create/TopicCreate.sytles.tsx b/src/routes/Topic/Create/TopicCreate.sytles.tsx index 77b1025..9efb9c9 100644 --- a/src/routes/Topic/Create/TopicCreate.sytles.tsx +++ b/src/routes/Topic/Create/TopicCreate.sytles.tsx @@ -45,8 +45,6 @@ export const SideButton = styled.button<{ side: string | undefined }>` gap: 3px; align-items: center; justify-content: center; - width: 90px; - height: 25px; padding: 2px 10px; background-color: ${(props) => props.side === 'A' ? 'rgb(208 67 118 / 20%)' : 'rgb(20 152 170 / 20%)'}; @@ -71,8 +69,8 @@ export const SideChangeButton = styled.button<{ side: string | undefined; isHidd border-radius: 50px; `; -export const DownShevron = styled.div` - display: flex; +export const DownShevron = styled.div<{ isStep2: boolean }>` + display: ${(props) => (props.isStep2 ? 'none' : 'flex')}; align-items: center; justify-content: flex-start; width: 14px; diff --git a/src/routes/Topic/Create/TopicCreate.tsx b/src/routes/Topic/Create/TopicCreate.tsx index 51d171e..ab0415c 100644 --- a/src/routes/Topic/Create/TopicCreate.tsx +++ b/src/routes/Topic/Create/TopicCreate.tsx @@ -1,5 +1,5 @@ -import React, { useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; +import React, { useEffect, useState } from 'react'; +import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import Layout from '@components/commons/Layout/Layout'; import Text from '@components/commons/Text/Text'; @@ -21,8 +21,13 @@ import { const TopicCreate = () => { const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const step = searchParams.get('step'); const { topicSide } = useParams(); const [isHidden, setIsHidden] = useState(true); + const [isStep2, setIsStep2] = useState(step === '2' && topicSide === 'B'); + + const Container = topicSide === 'A' ? : ; const handleSideButtonClick = () => { if (isHidden) { @@ -36,7 +41,13 @@ const TopicCreate = () => { navigate(`/topics/create/${newtopicSideValue}?step=1`, { replace: true }); }; - const Container = topicSide === 'A' ? : ; + useEffect(() => { + if (step === '2' && topicSide === 'B') { + setIsStep2(true); + } else { + setIsStep2(false); + } + }, [step, topicSide]); return ( { 토픽 만들기 - + {topicSide} 사이드 - + Date: Wed, 7 Feb 2024 15:59:37 +0900 Subject: [PATCH 25/38] chore: update gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b8ffae3..9a0eacc 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ dist-ssr *.sw? # env -.env +.env.* \ No newline at end of file From 2b430745896c3caae2a117a1f052b927bb30a25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=A7=84=ED=98=B8?= Date: Wed, 7 Feb 2024 15:59:48 +0900 Subject: [PATCH 26/38] fix: update value by useWatch --- src/routes/Topic/Create/BSide/BTopicCreate.tsx | 9 ++++++--- src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx | 8 ++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index 6ba03bc..2e342e8 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; +import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { useSearchParams } from 'react-router-dom'; import { INPUT_TYPE } from 'src/constants/form'; @@ -28,6 +28,10 @@ interface TopicCreateDTO { const BTopicCreate = () => { const methods = useForm({ mode: 'onChange' }); + const contentType = useWatch({ + control: methods.control, + name: INPUT_TYPE.TOPIC_CONTENT_TYPE, + }); const [searchParams] = useSearchParams(); const step = searchParams.get('step'); @@ -40,7 +44,6 @@ const BTopicCreate = () => { }; useEffect(() => { - const contentType = methods.getValues(INPUT_TYPE.TOPIC_CONTENT_TYPE); console.log('ㅋ', contentType); const ATopicCondition = methods.getFieldState(INPUT_TYPE.A_TOPIC, methods.formState); const BTopicCondition = methods.getFieldState(INPUT_TYPE.B_TOPIC, methods.formState); @@ -77,7 +80,7 @@ const BTopicCreate = () => { } } } - }, [methods.formState, step, methods.getValues([INPUT_TYPE.TOPIC_CONTENT_TYPE])]); + }, [contentType, methods, methods.formState, step]); if (step === null) { return; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx index 886dff7..1c4067c 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -32,6 +32,8 @@ const BTopicCreateStep2 = () => { const navigate = useNavigate(); const { register, setValue, getValues } = useFormContext(); + register(INPUT_TYPE.TOPIC_CONTENT_TYPE, CONFIG.TOPIC_CONTENT_TYPE.options); + const topicTitle = getValues(INPUT_TYPE.TOPIC_TITLE); const topicCategory = getValues(INPUT_TYPE.TOPIC_CATEGORY); @@ -46,8 +48,6 @@ const BTopicCreateStep2 = () => { CONFIG.TOPIC_DEADLINE.options ); - setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'text'); - const handleTextSelect = () => { setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'text'); setSelected('text'); @@ -70,10 +70,6 @@ const BTopicCreateStep2 = () => { } }, [topicTitle, topicCategory]); - useEffect(() => { - register(INPUT_TYPE.TOPIC_CONTENT_TYPE, CONFIG.TOPIC_CONTENT_TYPE.options); - }, [register]); - return ( From e7aaad0750219b68a32804dedddaf6f583307056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=EC=A7=84=ED=98=B8?= Date: Wed, 7 Feb 2024 16:26:40 +0900 Subject: [PATCH 27/38] fix: lint error --- src/components/TopicCreate/ImageInputComponent.tsx | 5 +++-- src/components/TopicCreate/TopicCreateImageInput.tsx | 3 ++- src/routes/Topic/Create/BSide/BTopicCreate.tsx | 3 ++- src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx | 3 ++- src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx | 5 +++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/TopicCreate/ImageInputComponent.tsx b/src/components/TopicCreate/ImageInputComponent.tsx index adf2cc1..e5394a3 100644 --- a/src/components/TopicCreate/ImageInputComponent.tsx +++ b/src/components/TopicCreate/ImageInputComponent.tsx @@ -1,10 +1,11 @@ import React, { useState } from 'react'; -import { set, useFormContext } from 'react-hook-form'; -import { INPUT_TYPE } from 'src/constants/form'; +import { useFormContext } from 'react-hook-form'; import Text from '@components/commons/Text/Text'; import useModal from '@hooks/useModal/useModal'; +import { INPUT_TYPE } from '@constants/form'; + import { colors } from '@styles/theme'; import { CloseIcon, DeleteIcon } from '@icons/index'; diff --git a/src/components/TopicCreate/TopicCreateImageInput.tsx b/src/components/TopicCreate/TopicCreateImageInput.tsx index 6ca8b4d..2c4c9ae 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.tsx @@ -1,10 +1,11 @@ import React, { useState, useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; -import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; +import { INPUT_TYPE } from '@constants/form'; + import { colors } from '@styles/theme'; import { RotateIcon } from '@icons/index'; diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index 2e342e8..bf9c825 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -1,10 +1,11 @@ import React, { useEffect, useState } from 'react'; import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { useSearchParams } from 'react-router-dom'; -import { INPUT_TYPE } from 'src/constants/form'; import DefaultButton from '@components/commons/Button/DefaultButton'; +import { INPUT_TYPE } from '@constants/form'; + import { Container, PageController, diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx index 83fb814..be0c5c8 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep1.tsx @@ -1,13 +1,14 @@ import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { CONFIG, INPUT_TYPE } from 'src/constants/form'; import { Col } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; import TextInput from '@components/commons/TextInput/TextInput'; import { theme2, theme3 } from '@components/commons/TextInput/theme'; +import { INPUT_TYPE, CONFIG } from '@constants/form'; + import { colors } from '@styles/theme'; import { CategoryChip, CategoryChipContainer, Container } from './BTopicCreateStep1.styles'; diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx index 1c4067c..d8b7bbf 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -1,14 +1,15 @@ import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { CONFIG, INPUT_TYPE } from 'src/constants/form'; -import { TOPIC_DEADLINES } from 'src/constants/topic'; import { Col, Row } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; import TopicCreateImageInput from '@components/TopicCreate/TopicCreateImageInput'; import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; +import { INPUT_TYPE, CONFIG } from '@constants/form'; +import { TOPIC_DEADLINES } from '@constants/topic'; + import { colors } from '@styles/theme'; import { From f89216433fad9f86566cdfbca4bbdd9d4f9f43d1 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:14:38 +0900 Subject: [PATCH 28/38] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B3=A0=EC=83=89?= =?UTF-8?q?=EC=83=81=20=EB=B3=80=EA=B2=BD=20#169?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/a-logo.svg | 3 --- src/assets/icons/b-logo.svg | 3 +-- src/routes/Topic/TopicSideSelection.tsx | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/assets/icons/a-logo.svg b/src/assets/icons/a-logo.svg index 208c0c8..cc6de48 100644 --- a/src/assets/icons/a-logo.svg +++ b/src/assets/icons/a-logo.svg @@ -2,7 +2,4 @@ - \ No newline at end of file diff --git a/src/assets/icons/b-logo.svg b/src/assets/icons/b-logo.svg index 17cfd45..9740c67 100644 --- a/src/assets/icons/b-logo.svg +++ b/src/assets/icons/b-logo.svg @@ -1,5 +1,4 @@ - + - diff --git a/src/routes/Topic/TopicSideSelection.tsx b/src/routes/Topic/TopicSideSelection.tsx index cacb76e..9e6bd08 100644 --- a/src/routes/Topic/TopicSideSelection.tsx +++ b/src/routes/Topic/TopicSideSelection.tsx @@ -74,7 +74,7 @@ const TopicSideSelection = () => { - + Business
Side From 5ed4022228fe0d832b016b040189e2fdeea05539 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:15:54 +0900 Subject: [PATCH 29/38] =?UTF-8?q?feat:=20=ED=86=A0=ED=94=BD=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=EB=B0=8F=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TopicCreate/ImageInputComponent.tsx | 14 +++--- .../TopicCreate/TopicCreateImageInput.tsx | 31 +++++++----- .../TopicCreate/TopicCreateTextInput.tsx | 31 ++++++++---- src/interfaces/api/topic.ts | 15 +++++- .../Topic/Create/BSide/BTopicCreate.tsx | 50 ++++++++++++++++--- .../Topic/Create/BSide/BTopicCreateStep2.tsx | 2 + 6 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/components/TopicCreate/ImageInputComponent.tsx b/src/components/TopicCreate/ImageInputComponent.tsx index e5394a3..68efd5a 100644 --- a/src/components/TopicCreate/ImageInputComponent.tsx +++ b/src/components/TopicCreate/ImageInputComponent.tsx @@ -4,7 +4,7 @@ import { useFormContext } from 'react-hook-form'; import Text from '@components/commons/Text/Text'; import useModal from '@hooks/useModal/useModal'; -import { INPUT_TYPE } from '@constants/form'; +import { CONFIG, INPUT_TYPE } from '@constants/form'; import { colors } from '@styles/theme'; @@ -31,9 +31,10 @@ interface ImageInputComponetProps { const ImageInputComponent = ({ label }: ImageInputComponetProps) => { const { Modal, toggleModal } = useModal('default'); - const { register, setValue } = useFormContext(); + const { register, setValue, watch } = useFormContext(); const id = label === 'A' ? INPUT_TYPE.A_TOPIC_IMAGEURL : INPUT_TYPE.B_TOPIC_IMAGEURL; - const [imageUrl, setImageUrl] = useState(null); + const config = label === 'A' ? CONFIG.A_TOPIC_IMAGEURL : CONFIG.B_TOPIC_IMAGEURL; + const imageUrl = watch(id); const handleFileChange = ( event: React.ChangeEvent, @@ -48,7 +49,6 @@ const ImageInputComponent = ({ label }: ImageInputComponetProps) => { const reader = new FileReader(); reader.onloadend = () => { - setImageUrl(reader.result as string); setValue(id, reader.result as string); }; reader.readAsDataURL(fileObj); @@ -56,8 +56,8 @@ const ImageInputComponent = ({ label }: ImageInputComponetProps) => { const handleDeleteButtonClick = (e: React.MouseEvent) => { e.stopPropagation(); - setImageUrl(null); - setValue(id, null); + + setValue(id, null, { shouldValidate: true, shouldDirty: true }); }; return ( @@ -101,7 +101,7 @@ const ImageInputComponent = ({ label }: ImageInputComponetProps) => { handleFileChange(event, register(id).onChange)} /> diff --git a/src/components/TopicCreate/TopicCreateImageInput.tsx b/src/components/TopicCreate/TopicCreateImageInput.tsx index 2c4c9ae..e4bf706 100644 --- a/src/components/TopicCreate/TopicCreateImageInput.tsx +++ b/src/components/TopicCreate/TopicCreateImageInput.tsx @@ -14,34 +14,39 @@ import ImageInputComponent from './ImageInputComponent'; import { ImageInputChip } from './ImageInputComponent.styles'; import { ImageInputDescription, ReplaceButton, ReplaceIcon } from './TopicCreateImageInput.styles'; -interface TopicCreareProps { - topic: 'A' | 'B'; - topicContent: string; - onKeyDown?: (e: React.KeyboardEvent) => void; -} - const TopicCreateImageInput = () => { - const { getValues, getFieldState } = useFormContext(); + const { getValues, getFieldState, formState, setValue } = useFormContext(); const [isImageFilled, setIsImageFilled] = useState(false); + const handleReplaceButtonClick = () => { + const aImage = getValues(INPUT_TYPE.A_TOPIC_IMAGEURL); + const bImage = getValues(INPUT_TYPE.B_TOPIC_IMAGEURL); + + setValue(INPUT_TYPE.A_TOPIC_IMAGEURL, bImage); + setValue(INPUT_TYPE.B_TOPIC_IMAGEURL, aImage); + }; + useEffect(() => { if ( - !getFieldState(INPUT_TYPE.A_TOPIC_IMAGEURL).invalid && - !getFieldState(INPUT_TYPE.B_TOPIC_IMAGEURL).invalid + getFieldState(INPUT_TYPE.A_TOPIC_IMAGEURL, formState).isDirty && + !getFieldState(INPUT_TYPE.A_TOPIC_IMAGEURL, formState).invalid && + getFieldState(INPUT_TYPE.B_TOPIC_IMAGEURL, formState).isDirty && + !getFieldState(INPUT_TYPE.B_TOPIC_IMAGEURL, formState).invalid ) { setIsImageFilled(true); } else { setIsImageFilled(false); } - }, [getValues([INPUT_TYPE.A_TOPIC_IMAGEURL, INPUT_TYPE.B_TOPIC_IMAGEURL])]); + }, [formState]); + return ( 어떤 선택지가 있나요? - + @@ -72,13 +77,13 @@ const TopicCreateImageInput = () => { ))} - + {/* 가로 세로 길이가 같은 사진을 올리는 것이 좋아요.
너무 큰 용량의 사진은 화질이 조정될 수 있어요.
-
+
*/} ); diff --git a/src/components/TopicCreate/TopicCreateTextInput.tsx b/src/components/TopicCreate/TopicCreateTextInput.tsx index 20da097..0570e93 100644 --- a/src/components/TopicCreate/TopicCreateTextInput.tsx +++ b/src/components/TopicCreate/TopicCreateTextInput.tsx @@ -19,12 +19,8 @@ import { InputSuffix, } from './TopicCreateTextInput.styles'; -interface TopicCreateProps { - onKeyDown?: (e: React.KeyboardEvent) => void; -} - -const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { - const { register, watch, getValues } = useFormContext(); +const TopicCreateTextInput = () => { + const { register, watch, getFieldState, formState, setValue } = useFormContext(); const ATopicProgress = watch(INPUT_TYPE.A_TOPIC) ? `${watch(INPUT_TYPE.A_TOPIC)?.length}/25` : '0/25'; @@ -34,13 +30,28 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { const [isTopicFilled, setIsTopicFilled] = useState(false); + const handleReplaceButtonClick = () => { + const aTopic = watch(INPUT_TYPE.A_TOPIC); + const bTopic = watch(INPUT_TYPE.B_TOPIC); + + setValue(INPUT_TYPE.A_TOPIC, bTopic); + setValue(INPUT_TYPE.B_TOPIC, aTopic); + }; + useEffect(() => { - if (getValues(INPUT_TYPE.A_TOPIC) && getValues(INPUT_TYPE.B_TOPIC)) { + const ATopicCondition = getFieldState(INPUT_TYPE.A_TOPIC, formState); + const BTopicCondition = getFieldState(INPUT_TYPE.B_TOPIC, formState); + if ( + !ATopicCondition.invalid && + ATopicCondition.isDirty && + !BTopicCondition.invalid && + BTopicCondition.isDirty + ) { setIsTopicFilled(true); } else { setIsTopicFilled(false); } - }, [getValues([INPUT_TYPE.A_TOPIC, INPUT_TYPE.B_TOPIC])]); + }, [formState, getFieldState]); return ( @@ -48,7 +59,7 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { 어떤 선택지가 있나요? - + @@ -72,6 +83,7 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { @@ -90,6 +102,7 @@ const TopicCreateTextInput = ({ onKeyDown }: TopicCreateProps) => { diff --git a/src/interfaces/api/topic.ts b/src/interfaces/api/topic.ts index 47702b4..78e517d 100644 --- a/src/interfaces/api/topic.ts +++ b/src/interfaces/api/topic.ts @@ -16,6 +16,19 @@ interface TopicResponse { selectedOption: typeof CHOICE_OPTIONS.CHOICE_A | typeof CHOICE_OPTIONS.CHOICE_B | null; } +export interface TopicCreateRequestDTO { + side: string; + keywordName: string; + title: string; + choices: ChoiceRequest[]; + deadline: number; +} + +interface ChoiceRequest { + choiceContentRequest: ChoiceContent; + choiceOption: typeof CHOICE_OPTIONS.CHOICE_A | typeof CHOICE_OPTIONS.CHOICE_B; +} + interface Choice { choiceId: number; content: ChoiceContent; @@ -23,7 +36,7 @@ interface Choice { } interface ChoiceContent { - text: string; + text: null | string; imageUrl: null | string; type: string; } diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index bf9c825..e528713 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -1,8 +1,10 @@ import React, { useEffect, useState } from 'react'; -import { FormProvider, useForm, useWatch } from 'react-hook-form'; +import { FormProvider, SubmitHandler, useForm, useWatch } from 'react-hook-form'; import { useSearchParams } from 'react-router-dom'; +import { useCreateTopics } from '@apis/topic/useTopics'; import DefaultButton from '@components/commons/Button/DefaultButton'; +import { CHOICE_OPTIONS, TopicCreateRequestDTO } from '@interfaces/api/topic'; import { INPUT_TYPE } from '@constants/form'; @@ -23,7 +25,7 @@ interface TopicCreateDTO { topicCategory: string; ATopicImageURL: string; BTopicImageURL: string; - topicDeadline: string; + topicDeadline: number; topicType: string; } @@ -38,14 +40,50 @@ const BTopicCreate = () => { const [isFormFilled, setIsFormFilled] = useState(false); + const createTopicMutation = useCreateTopics(); + const Step = step === '1' ? : ; - const handleSubmitButtonClick = () => { - console.log('submit'); + const handleDeadline = (deadline: number) => { + const date = new Date(); + date.setHours(date.getHours() + deadline); + return Math.floor(date.getTime() / 1000); + }; + + const handleSubmitForm = async () => { + const data = methods.getValues(); + try { + const res = await createTopicMutation.mutateAsync({ + side: 'TOPIC_B', + title: data.topicTitle, + keywordName: data.topicCategory, + deadline: handleDeadline(data.topicDeadline), + choices: [ + { + choiceContentRequest: { + text: contentType === 'text' ? data.ATopic : '', + type: 'IMAGE_TEXT', + imageUrl: contentType === 'image' ? data.ATopicImageURL : null, + }, + choiceOption: CHOICE_OPTIONS.CHOICE_A, + }, + { + choiceContentRequest: { + text: contentType === 'text' ? data.BTopic : null, + type: 'IMAGE_TEXT', + imageUrl: contentType === 'image' ? data.BTopicImageURL : null, + }, + choiceOption: CHOICE_OPTIONS.CHOICE_B, + }, + ], + }); + console.log('success :', res); + } catch (error) { + console.error(error); + } }; useEffect(() => { - console.log('ㅋ', contentType); const ATopicCondition = methods.getFieldState(INPUT_TYPE.A_TOPIC, methods.formState); const BTopicCondition = methods.getFieldState(INPUT_TYPE.B_TOPIC, methods.formState); const ATopiImageURLCondition = methods.getFieldState( @@ -95,7 +133,7 @@ const BTopicCreate = () => { diff --git a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx index d8b7bbf..b2c9af0 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreateStep2.tsx @@ -49,6 +49,8 @@ const BTopicCreateStep2 = () => { CONFIG.TOPIC_DEADLINE.options ); + setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, selected); + const handleTextSelect = () => { setValue(INPUT_TYPE.TOPIC_CONTENT_TYPE, 'text'); setSelected('text'); From ebb1e215da3fd121435f949562e52e3593697405 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:16:26 +0900 Subject: [PATCH 30/38] =?UTF-8?q?feat:=20=ED=86=A0=ED=94=BD=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20api=20dto=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/topic/useTopics.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/apis/topic/useTopics.ts b/src/apis/topic/useTopics.ts index bf4ca64..6de0df0 100644 --- a/src/apis/topic/useTopics.ts +++ b/src/apis/topic/useTopics.ts @@ -1,6 +1,11 @@ import { useMutation, useQuery } from '@tanstack/react-query'; -import { CHOICE_OPTIONS, ChoiceContent, TopicResponse } from '@interfaces/api/topic'; +import { + CHOICE_OPTIONS, + ChoiceContent, + TopicCreateRequestDTO, + TopicResponse, +} from '@interfaces/api/topic'; import { PagingDataResponse } from '@interfaces/api'; @@ -8,22 +13,8 @@ import client from '@apis/fetch'; export const TOPIC_KEY = 'topics'; -interface Choice { - choiceId: number; - choiceContentRequest: ChoiceContent; - choiceOption: typeof CHOICE_OPTIONS.CHOICE_A | typeof CHOICE_OPTIONS.CHOICE_B; -} - -interface TopicCreateRequestDTO { - side: string; - keywordName: string; - title: string; - choices: Choice[]; - deadline: number; -} - const getTopics = () => { - return client.get>('/topics/info/voting'); + return client.get>('/topics/info/voting?size=100'); }; const useTopics = () => { From 2268ba5c04abf963e3a564e40ca3608ef81ff565 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:18:10 +0900 Subject: [PATCH 31/38] =?UTF-8?q?fix:=20=EC=8A=AC=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=8D=94=20,=20=ED=88=AC=ED=91=9C=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=82=B4=20=EB=A1=9C?= =?UTF-8?q?=EA=B3=A0=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/ChoiceSlide/ChoiceSlide.tsx | 4 ++-- src/components/Home/VoteCompletion/VoteCompletion.styles.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Home/ChoiceSlide/ChoiceSlide.tsx b/src/components/Home/ChoiceSlide/ChoiceSlide.tsx index 9a761d3..1d32196 100644 --- a/src/components/Home/ChoiceSlide/ChoiceSlide.tsx +++ b/src/components/Home/ChoiceSlide/ChoiceSlide.tsx @@ -44,12 +44,12 @@ const ChoiceSlide = ({ side, topicContent }: ChoiceSlideProps) => {
- + {side}
diff --git a/src/components/Home/VoteCompletion/VoteCompletion.styles.tsx b/src/components/Home/VoteCompletion/VoteCompletion.styles.tsx index 1e21790..380d29e 100644 --- a/src/components/Home/VoteCompletion/VoteCompletion.styles.tsx +++ b/src/components/Home/VoteCompletion/VoteCompletion.styles.tsx @@ -47,5 +47,5 @@ export const VoteCompletionBackground = styled.div<{ side: 'A' | 'B' }>` export const VoteCompletionTextContainer = styled.div` position: absolute; - top: -20px; + top: -45px; `; From b058bfac5164cdfc374f98fc0269619ae20cca2e Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:18:46 +0900 Subject: [PATCH 32/38] =?UTF-8?q?fix:=20topic=20content=20=EA=B8=80?= =?UTF-8?q?=EC=9E=90=EC=88=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20size=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/VoteCompletion/VoteCompletion.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/Home/VoteCompletion/VoteCompletion.tsx b/src/components/Home/VoteCompletion/VoteCompletion.tsx index 699baa3..42bfc30 100644 --- a/src/components/Home/VoteCompletion/VoteCompletion.tsx +++ b/src/components/Home/VoteCompletion/VoteCompletion.tsx @@ -26,8 +26,13 @@ const VoteCompletion = ({ side, topicContent }: VoteCompletionProps) => { return ( -
- +
+ = 21 ? 16 : 20} + weight={600} + align="center" + > {topicContent}
From 5a9a7f56c6fae3233fb4ef54f50bbe9e9148fa76 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:19:09 +0900 Subject: [PATCH 33/38] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EB=A1=9C=EA=B3=A0=20B=20=EC=83=89?= =?UTF-8?q?=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Auth/kakao/KakaoLogin.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Auth/kakao/KakaoLogin.tsx b/src/routes/Auth/kakao/KakaoLogin.tsx index 240e09a..2124702 100644 --- a/src/routes/Auth/kakao/KakaoLogin.tsx +++ b/src/routes/Auth/kakao/KakaoLogin.tsx @@ -74,7 +74,7 @@ const KakaoLogin = () => { style={{ width: '100%', height: '100%' }} > - +
From 5b73c90c0290034d51f8eade7917b39fed57509c Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:19:31 +0900 Subject: [PATCH 34/38] =?UTF-8?q?fix:=20=EC=8A=AC=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=8D=94=20topic=20content=20text=20z=20index=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx b/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx index 3b6bddf..64794b3 100644 --- a/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx +++ b/src/components/Home/ChoiceSlide/ChoiceSlide.styles.tsx @@ -30,8 +30,11 @@ export const BetaSideContainer = styled(SlideContainer)` `; export const TextContainer = styled.div` + z-index: 1; justify-content: flex-start; + width: 87px; padding: 0 44px; + word-break: break-all; `; export const SideImage = styled.img` From 5f43c70a7c45c3de0daef647d53498736d4d46aa Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 15:20:31 +0900 Subject: [PATCH 35/38] =?UTF-8?q?fix:=20api=20=EB=B3=80=EA=B2=BD=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20topic=20content=20=EB=B0=9B=EC=95=84?= =?UTF-8?q?=EC=98=A4=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 --- src/components/Home/TopicCard/TopicCard.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Home/TopicCard/TopicCard.tsx b/src/components/Home/TopicCard/TopicCard.tsx index 65e3238..d77f2c8 100644 --- a/src/components/Home/TopicCard/TopicCard.tsx +++ b/src/components/Home/TopicCard/TopicCard.tsx @@ -120,9 +120,12 @@ const TopicCard = ({ topic }: TopicCardProps) => { ? topic.choices[0]?.content?.text || 'A' : topic.choices[1]?.content?.text || 'B' } - /> // TODO: 선택 완료 컴포넌트 + /> ) : ( - + 0 ? topic.choices : choices} + /> )} From c0db0a58df80b616d42b3f60fb846864282f9c3f Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 20:19:31 +0900 Subject: [PATCH 36/38] =?UTF-8?q?fix:=20topiccreate=20dto=20interface=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/Create/TopicCreate.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/routes/Topic/Create/TopicCreate.tsx b/src/routes/Topic/Create/TopicCreate.tsx index 2fcb355..994ada8 100644 --- a/src/routes/Topic/Create/TopicCreate.tsx +++ b/src/routes/Topic/Create/TopicCreate.tsx @@ -18,6 +18,17 @@ import { SideChangeButton, } from './TopicCreate.sytles'; +export interface TopicCreateDTO { + topicTitle: string; + ATopic: string; + BTopic: string; + topicCategory: string; + ATopicImageURL: string; + BTopicImageURL: string; + topicDeadline: number; + topicType: string; +} + const TopicCreate = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); From fc8d96fbb5c3b85ce0ab1cf4907dde21fdd52b17 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 20:20:18 +0900 Subject: [PATCH 37/38] =?UTF-8?q?feat:=20Aside=20topiccreate=20api=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/topic/useTopics.ts | 7 +-- src/interfaces/api/topic.ts | 4 +- .../Topic/Create/ASide/ATopicCreate.tsx | 59 +++++++++++++++---- .../Topic/Create/BSide/BTopicCreate.tsx | 13 +--- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/apis/topic/useTopics.ts b/src/apis/topic/useTopics.ts index 6de0df0..8596351 100644 --- a/src/apis/topic/useTopics.ts +++ b/src/apis/topic/useTopics.ts @@ -1,11 +1,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'; -import { - CHOICE_OPTIONS, - ChoiceContent, - TopicCreateRequestDTO, - TopicResponse, -} from '@interfaces/api/topic'; +import { TopicCreateRequestDTO, TopicResponse } from '@interfaces/api/topic'; import { PagingDataResponse } from '@interfaces/api'; diff --git a/src/interfaces/api/topic.ts b/src/interfaces/api/topic.ts index 78e517d..15fcd7b 100644 --- a/src/interfaces/api/topic.ts +++ b/src/interfaces/api/topic.ts @@ -18,10 +18,10 @@ interface TopicResponse { export interface TopicCreateRequestDTO { side: string; - keywordName: string; + keywordName: string | null; title: string; choices: ChoiceRequest[]; - deadline: number; + deadline: number | null; } interface ChoiceRequest { diff --git a/src/routes/Topic/Create/ASide/ATopicCreate.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.tsx index 4ac5011..f203605 100644 --- a/src/routes/Topic/Create/ASide/ATopicCreate.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.tsx @@ -1,24 +1,22 @@ import React, { useState, useEffect } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; +import { useCreateTopics } from '@apis/topic/useTopics'; import DefaultButton from '@components/commons/Button/DefaultButton'; import { Col } from '@components/commons/Flex/Flex'; import Text from '@components/commons/Text/Text'; import TextInput from '@components/commons/TextInput/TextInput'; import { theme3 } from '@components/commons/TextInput/theme'; import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; +import { CHOICE_OPTIONS } from '@interfaces/api/topic'; import { INPUT_TYPE, CONFIG } from '@constants/form'; import { colors } from '@styles/theme'; -import { Container, SubmitButton } from './ATopicCreate.styles'; +import { TopicCreateDTO } from '../TopicCreate'; -interface TopicCreateDTO { - topicTitle: string; - ATopic: string; - BTopic: string; -} +import { Container, SubmitButton } from './ATopicCreate.styles'; const ATopicCreate = () => { const methods = useForm({ mode: 'onChange' }); @@ -27,21 +25,56 @@ const ATopicCreate = () => { ? `${methods.watch(INPUT_TYPE.TOPIC_TITLE)?.length}/20` : '0/20'; const [isFormFilled, setIsFormFilled] = useState(false); - const handleSubmitButtonClick = () => { - console.log('submit'); + + const createTopicMutation = useCreateTopics(); + + const handleSubmitForm = async () => { + const data = methods.getValues(); + try { + const res = await createTopicMutation.mutateAsync({ + side: 'TOPIC_A', + title: data.topicTitle, + keywordName: null, + deadline: null, + choices: [ + { + choiceContentRequest: { + text: data.ATopic, + type: 'IMAGE_TEXT', + imageUrl: null, + }, + choiceOption: CHOICE_OPTIONS.CHOICE_A, + }, + { + choiceContentRequest: { + text: data.BTopic, + type: 'IMAGE_TEXT', + imageUrl: null, + }, + choiceOption: CHOICE_OPTIONS.CHOICE_B, + }, + ], + }); + console.log('success :', res); + } catch (error) { + console.error(error); + } }; useEffect(() => { + const ATopicCondition = methods.getFieldState(INPUT_TYPE.A_TOPIC, methods.formState); + const BTopicCondition = methods.getFieldState(INPUT_TYPE.B_TOPIC, methods.formState); if ( - methods.getValues(INPUT_TYPE.TOPIC_TITLE) && - methods.getValues(INPUT_TYPE.A_TOPIC) && - methods.getValues(INPUT_TYPE.B_TOPIC) + !ATopicCondition.invalid && + !BTopicCondition.invalid && + ATopicCondition.isDirty && + BTopicCondition.isDirty ) { setIsFormFilled(true); } else { setIsFormFilled(false); } - }, [methods]); + }, [methods.formState, methods]); return ( @@ -69,7 +102,7 @@ const ATopicCreate = () => { diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index e528713..d40f1eb 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -8,6 +8,8 @@ import { CHOICE_OPTIONS, TopicCreateRequestDTO } from '@interfaces/api/topic'; import { INPUT_TYPE } from '@constants/form'; +import { TopicCreateDTO } from '../TopicCreate'; + import { Container, PageController, @@ -18,17 +20,6 @@ import { import BTopicCreateStep1 from './BTopicCreateStep1'; import BTopicCreateStep2 from './BTopicCreateStep2'; -interface TopicCreateDTO { - topicTitle: string; - ATopic: string; - BTopic: string; - topicCategory: string; - ATopicImageURL: string; - BTopicImageURL: string; - topicDeadline: number; - topicType: string; -} - const BTopicCreate = () => { const methods = useForm({ mode: 'onChange' }); const contentType = useWatch({ From d6f57b1f6e047227e7f1eb3313a9325a42f14615 Mon Sep 17 00:00:00 2001 From: chaeyoung103 Date: Thu, 8 Feb 2024 20:27:20 +0900 Subject: [PATCH 38/38] =?UTF-8?q?fix:=20=EC=A0=88=EB=8C=80=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/Topic/Create/ASide/ATopicCreate.tsx | 3 +-- src/routes/Topic/Create/BSide/BTopicCreate.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/Topic/Create/ASide/ATopicCreate.tsx b/src/routes/Topic/Create/ASide/ATopicCreate.tsx index f203605..7424745 100644 --- a/src/routes/Topic/Create/ASide/ATopicCreate.tsx +++ b/src/routes/Topic/Create/ASide/ATopicCreate.tsx @@ -9,13 +9,12 @@ import TextInput from '@components/commons/TextInput/TextInput'; import { theme3 } from '@components/commons/TextInput/theme'; import TopicCreateTextInput from '@components/TopicCreate/TopicCreateTextInput'; import { CHOICE_OPTIONS } from '@interfaces/api/topic'; +import { TopicCreateDTO } from '@routes/Topic/Create/TopicCreate'; import { INPUT_TYPE, CONFIG } from '@constants/form'; import { colors } from '@styles/theme'; -import { TopicCreateDTO } from '../TopicCreate'; - import { Container, SubmitButton } from './ATopicCreate.styles'; const ATopicCreate = () => { diff --git a/src/routes/Topic/Create/BSide/BTopicCreate.tsx b/src/routes/Topic/Create/BSide/BTopicCreate.tsx index d40f1eb..f26018a 100644 --- a/src/routes/Topic/Create/BSide/BTopicCreate.tsx +++ b/src/routes/Topic/Create/BSide/BTopicCreate.tsx @@ -5,11 +5,10 @@ import { useSearchParams } from 'react-router-dom'; import { useCreateTopics } from '@apis/topic/useTopics'; import DefaultButton from '@components/commons/Button/DefaultButton'; import { CHOICE_OPTIONS, TopicCreateRequestDTO } from '@interfaces/api/topic'; +import { TopicCreateDTO } from '@routes/Topic/Create/TopicCreate'; import { INPUT_TYPE } from '@constants/form'; -import { TopicCreateDTO } from '../TopicCreate'; - import { Container, PageController,