From a81a59939afcb608cbf85a1288cfcf431d2d86df Mon Sep 17 00:00:00 2001 From: parkyejin Date: Sat, 9 Mar 2024 04:37:41 +0900 Subject: [PATCH 1/4] =?UTF-8?q?docs(#28):=20adCopy=20createAdCopy=20?= =?UTF-8?q?=EA=B2=BD=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/app/adCopy/{ => createAdCopy}/page.tsx | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/app/adCopy/{ => createAdCopy}/page.tsx (100%) diff --git a/src/app/adCopy/page.tsx b/src/app/adCopy/createAdCopy/page.tsx similarity index 100% rename from src/app/adCopy/page.tsx rename to src/app/adCopy/createAdCopy/page.tsx From 5378af7418ae82e975575bc73eb4765b82cfaa63 Mon Sep 17 00:00:00 2001 From: parkyejin Date: Sat, 9 Mar 2024 05:31:08 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat(#28):=20Service=20Result=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/user/page.tsx | 14 + src/components/mypage/MyIndex.tsx | 38 ++ src/components/mypage/Mypage.tsx | 40 +++ src/components/mypage/Service.tsx | 17 + src/components/mypage/ServiceBox.tsx | 442 ++++++++++++++++++++++++ src/components/mypage/ServiceResult.tsx | 151 ++++++++ src/components/navbar/Navbar.tsx | 2 +- 7 files changed, 703 insertions(+), 1 deletion(-) create mode 100644 src/app/user/page.tsx create mode 100644 src/components/mypage/MyIndex.tsx create mode 100644 src/components/mypage/Mypage.tsx create mode 100644 src/components/mypage/Service.tsx create mode 100644 src/components/mypage/ServiceBox.tsx create mode 100644 src/components/mypage/ServiceResult.tsx diff --git a/src/app/user/page.tsx b/src/app/user/page.tsx new file mode 100644 index 0000000..864e611 --- /dev/null +++ b/src/app/user/page.tsx @@ -0,0 +1,14 @@ +"use client"; + +import NOSSR from "@/components/common/NOSSR"; +import Mypage from "@/components/mypage/Mypage"; + +const User = async () => { + return ( + + + + ); +}; + +export default User; diff --git a/src/components/mypage/MyIndex.tsx b/src/components/mypage/MyIndex.tsx new file mode 100644 index 0000000..8b27e77 --- /dev/null +++ b/src/components/mypage/MyIndex.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useState } from "react"; +import { styled } from "styled-components"; + +const MyIndex = () => { + const [selected, setSelected] = useState(1); + + return ( + + setSelected(1)}> + 마이 카피 + + setSelected(2)}> + 마이 스토리보드 + + + ); +}; + +export default MyIndex; + +const Layout = styled.div` + display: flex; + text-align: center; + cursor: pointer; +`; + +const Index = styled.div<{ selected: boolean }>` + width: 10rem; + padding: 0.7rem 0; + border-bottom: 2px solid + ${({ theme, selected }) => + selected ? theme.colors.main : theme.colors.grey1}; + color: ${({ theme, selected }) => + selected ? theme.colors.white : theme.colors.grey1}; + white-space: nowrap; +`; diff --git a/src/components/mypage/Mypage.tsx b/src/components/mypage/Mypage.tsx new file mode 100644 index 0000000..41d6392 --- /dev/null +++ b/src/components/mypage/Mypage.tsx @@ -0,0 +1,40 @@ +import { styled } from "styled-components"; +import MyIndex from "./MyIndex"; +import ServiceBox from "./ServiceBox"; +import ServiceResult from "./ServiceResult"; + +const Mypage = () => { + return ( + + 마이 페이지 + + + + + + + ); +}; + +export default Mypage; + +const Layout = styled.div` + display: flex; + height: 80%; + flex-direction: column; + justify-content: center; + padding: 5.5rem 6% 0 6%; + gap: 1.5rem; +`; + +const Title = styled.div` + color: ${({ theme }) => theme.colors.white}; + font-size: 1.6rem; + font-weight: 500; + margin-left: 1rem; +`; + +const ServiceContent = styled.div` + display: inline-flex; + width: 100%; +`; diff --git a/src/components/mypage/Service.tsx b/src/components/mypage/Service.tsx new file mode 100644 index 0000000..26ec7a6 --- /dev/null +++ b/src/components/mypage/Service.tsx @@ -0,0 +1,17 @@ +const Service = () => { + return ( + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + ); +}; + +export default Service; diff --git a/src/components/mypage/ServiceBox.tsx b/src/components/mypage/ServiceBox.tsx new file mode 100644 index 0000000..41519bd --- /dev/null +++ b/src/components/mypage/ServiceBox.tsx @@ -0,0 +1,442 @@ +"use client"; + +import { useWindowSize } from "@/hooks/useWindowSize"; +import { colors } from "@/styles/theme"; +import { useEffect, useState } from "react"; +import styled from "styled-components"; +import { Toggle } from "../common/Toggle"; +import Image from "next/image"; + +const genderOption = ["전체", "남성", "여성"]; +const ageOption = [ + "전체", + "0~9세", + "10~19세", + "20~29세", + "30~39세", + "40~49세", + "50~59세", + "60~69세", + "70세 이상", +]; + +const ServiceBox = () => { + const size = useWindowSize(); + + // 백엔드에 보낼 데이터 (Form submit 용) + const [values, setValues] = useState({ + category: "", // 서비스 선택: 헤드/바디 + projectName: "", // 프로젝트명 + serviceName: "", // 상품/서비스명 + targetGender: "", // 성별 + targetAge: "", // 연령대 + keyword: "", //키워드 + toneManner: "", // 톤앤매너 + }); + const handleChange = (e: any) => { + setValues({ + ...values, + [e.target.name]: e.target.value, + }); + }; + + // 생성 버튼 disabled 인지 아닌지 + const [canSubmit, setCanSubmit] = useState(false); + useEffect(() => { + const isFull = Object.values(values).every((value) => value.trim() !== ""); + setCanSubmit(isFull); + }, [values]); + + const [focused, setFocused] = useState(""); + // 포커스 상태 변경 함수 + const handleFocus = (name: string) => { + setFocused(name); + }; + // 포커스 해제 함수 + const handleBlur = () => { + setFocused(""); + }; + + // 헤드카피, 바디카피 + const [category, setCategory] = useState(""); + const categoryClick = (opt: string) => { + category === opt ? setCategory("") : setCategory(opt); + }; + + // 키워드 + const [keywords, setKeywords] = useState([]); + const [inputValue, setInputValue] = useState(""); + // 키워드 input이 변경될 때마다 업데이트 + const keywordChange = (e: any) => { + setInputValue(e.target.value); + }; + // 엔터를 누르면 키워드 배열에 값 추가 & input 초기화 + // e.nativeEvent.isComposing == false: onKeyDown 한글 오류 해결 + const keywordEnter = (e: any) => { + if (e.key === "Enter" && e.nativeEvent.isComposing === false) { + e.preventDefault(); + setKeywords((prevKeywords) => [...prevKeywords, inputValue]); + setInputValue(""); + } + }; + // 키워드 배열에서 삭제 + const removeKeyword = (indexToRemove: number) => { + setKeywords((prevKeywords) => + prevKeywords.filter((_, index) => index !== indexToRemove) + ); + }; + + // 톤앤매너 + const [toneManner, setToneManner] = useState(0); + + return ( + + + + + N카피 + + + K카피 + + + N카피는 네이버 HyperCLOVA를 연계해 구축한 AI 카피 생성 서비스예요 + + + + 서비스 선택 + + categoryClick("head")} + > + 헤드 카피 + + categoryClick("body")} + > + 바디 카피 + + + + + 프로젝트명 + handleFocus("projectName")} + onBlur={handleBlur} + autoComplete="off" + /> + + + 상품/서비스 명 + handleFocus("serviceName")} + onBlur={handleBlur} + autoComplete="off" + /> + + + 타겟 + + + + + + + 키워드 + handleFocus("keyword")} + onBlur={handleBlur} + onChange={keywordChange} + onKeyDown={keywordEnter} + value={inputValue} + autoComplete="off" + /> + + {keywords.map((keyword, index) => ( + + {keyword} + close removeKeyword(index)} + /> + + ))} + + + + 톤 앤 매너 + + + setToneManner(1)} + > + 기본형 + + setToneManner(2)} + > + 언어유희형 + + setToneManner(3)} + > + 행동촉구형 + + setToneManner(4)} + > + 리뷰형 + + + + setToneManner(5)} + > + 경고형 + + setToneManner(6)} + > + 감정호소형 + + setToneManner(7)} + > + 문제제기형 + + setToneManner(8)} + > + 질문형 + + + + + + + 광고카피생성 + + + ); +}; + +export default ServiceBox; + +const BoxWrapper = styled.div` + display: flex; + flex-direction: column; + width: 40%; + flex-shrink: 0; + border-radius: 0.875rem; + background: #212121; + padding: 1.88rem 2.5rem; + align-items: center; +`; +const BoxHead = styled.div` + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + color: ${colors.grey05}; + text-align: center; + font-size: 0.75rem; + font-style: normal; + font-weight: 400; + line-height: 1.875rem; + margin-bottom: 1rem; +`; +const InlineContent = styled.div<{ gap: string }>` + display: flex; + flex-grow: 1; + gap: ${(props) => props.gap}; +`; +const TitleBox = styled.div<{ color: string; border: string }>` + display: flex; + width: 9.625rem; + padding: 0.625rem; + justify-content: center; + align-items: center; + gap: 0.625rem; + border-bottom: 2px solid ${(props) => props.border}; + color: ${(props) => props.color}; + text-align: center; + font-size: 1rem; + font-style: normal; + font-weight: 500; + line-height: normal; +`; +const BoxContent = styled.div` + display: flex; + flex-direction: column; + width: 100%; + overflow-y: scroll; + gap: 1.5rem; + ::-webkit-scrollbar { + display: none; + } + -ms-overflow-style: none; /* 인터넷 익스플로러 */ + scrollbar-width: none; /* 파이어폭스 */ +`; +const Contents = styled.div<{ focus: string; opt: string }>` + display: flex; + flex-direction: column; + flex-wrap: nowrap; + width: 100%; + gap: 1rem; + color: ${(props) => (props.focus === props.opt ? colors.main : colors.white)}; + font-size: 1rem; + font-style: normal; + font-weight: 500; + line-height: normal; +`; +const SelectButton = styled.button<{ + active: boolean; + color: string; + background: string; +}>` + display: flex; + flex-grow: 1; + height: 3.125rem; + justify-content: center; + align-items: center; + flex-shrink: 0; + border-radius: 6.25rem; + border: 1px solid ${(props) => (props.active ? props.color : colors.grey0)}; + background: ${(props) => (props.active ? props.background : colors.grey0)}; + color: ${(props) => (props.active ? props.color : colors.grey1)}; + font-size: 0.875rem; + font-style: normal; + font-weight: 500; + line-height: normal; + cursor: pointer; +`; +const InputContent = styled.input` + display: flex; + width: 100%; + height: 3.125rem; + padding-left: 2rem; + align-items: center; + flex-shrink: 0; + border-radius: 6.25rem; + color: ${colors.white}; + font-size: 0.875rem; + font-style: normal; + font-weight: 500; + line-height: normal; + border: 1px solid ${colors.grey0}; + background: ${colors.grey0}; + &:focus { + outline: none; + border: 1px solid ${colors.main}; + } +`; +const SubmitButton = styled.button` + display: flex; + width: 100%; + padding: 0.75rem 2.5rem; + justify-content: center; + align-items: center; + border-radius: 2.1875rem; + border: none; + color: ${(props) => (props.disabled ? colors.grey05 : colors.white)}; + background: ${(props) => (props.disabled ? "#393939" : colors.main)}; + margin-top: 1.88rem; +`; +const KeywordRegion = styled.ul` + width: 100%; + color: ${colors.grey4}; + font-size: 0.875rem; + font-style: normal; + font-weight: 500; + line-height: normal; + padding-left: 0.94rem; +`; +const Keyword = styled.li` + display: inline-flex; + padding: 0.25rem 0.25rem 0.25rem 0.75rem; + justify-content: space-between; + align-items: center; + gap: 0.1875rem; + border-radius: 6.25rem; + background: ${colors.grey0}; + margin-right: 0.5rem; +`; +const ToneButton = styled.button<{ + active: boolean; + color: string; + background: string; +}>` + display: flex; + flex-grow: 1; + height: 2.5rem; + justify-content: center; + align-items: center; + border-radius: 1.825rem; + border: 1px solid ${(props) => (props.active ? props.color : colors.grey1)}; + background: ${(props) => (props.active ? props.background : "transparent")}; + color: ${(props) => (props.active ? props.color : colors.grey1)}; + font-size: 0.875rem; + font-style: normal; + font-weight: 500; + line-height: normal; + cursor: pointer; + &:focus { + outline-color: ${colors.main}; + outline-offset: 0; + outline-width: 1px; + outline-style: solid; + border-color: transparent; + } +`; +const ToneRegion = styled.div` + display: flex; + flex-direction: column; + padding: 0 0.125rem; + gap: 0.5rem; + margin-bottom: 1rem; +`; diff --git a/src/components/mypage/ServiceResult.tsx b/src/components/mypage/ServiceResult.tsx new file mode 100644 index 0000000..4806983 --- /dev/null +++ b/src/components/mypage/ServiceResult.tsx @@ -0,0 +1,151 @@ +"use client"; + +import styled from "styled-components"; +import { colors } from "@/styles/theme"; +import Image from "next/image"; +import { useState } from "react"; +import { useWindowSize } from "@/hooks/useWindowSize"; + +const ServiceResult = () => { + const size = useWindowSize(); + const [categoryIndex, setCategoryIndex] = useState(0); + + return ( + + {categoryIndex == 0 ? ( + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + + + 바디 카피 + + + 톤 앤 매너 + + + ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + + + ) : ( + <> + )} + + ); +}; + +export default ServiceResult; + +const BoxWrapper = styled.div` + width: 60%; + padding-left: 1.38rem; +`; +const BoxContents = styled.div` + width: 100%; + display: inline-flex; + flex-wrap: wrap; + overflow-y: auto; + justify-content: space-between; + padding-right: 0.875rem; + + &::-webkit-scrollbar-track { + margin: 1rem; + border-radius: 10px; + background-color: ${colors.grey0}; + } + &::-webkit-scrollbar { + width: 0.375rem; + } + &::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: ${colors.main}; + } +`; +const CopyWrapper = styled.div` + display: flex; + width: 49%; + flex-direction: column; + justify-content: space-between; + border-radius: 0.875rem; + background: ${colors.grey0}; + padding: 1rem 1rem 2rem 1rem; + color: var(--Basic-White, #fff); + text-align: center; + font-size: 0.9375rem; + font-style: normal; + font-weight: 500; + line-height: 1.375rem; + margin-bottom: 2%; +`; +const TagWrapper = styled.div` + display: inline-flex; + gap: 0.5rem; + margin-bottom: 2rem; +`; +const Tag = styled.div<{ color: string; background: string }>` + padding: 0.375rem 0.875rem; + justify-content: center; + align-items: center; + border-radius: 1.375rem; + border: 1px solid ${(props) => props.color}; + background: ${(props) => props.background}; + color: ${(props) => props.color}; + font-size: 0.75rem; + font-style: normal; + font-weight: 500; + line-height: normal; +`; diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx index fabe708..df6ce72 100644 --- a/src/components/navbar/Navbar.tsx +++ b/src/components/navbar/Navbar.tsx @@ -92,7 +92,7 @@ export default function Navbar() { -
로그인
+
router.push("/user")}>로그인
|
회원가입
From 3558879427e49fbb28998f33121b2b3f0829bf30 Mon Sep 17 00:00:00 2001 From: parkyejin Date: Sat, 9 Mar 2024 21:02:19 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor(#28):=20Service=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mypage/Service.tsx | 54 ++++++++++- src/components/mypage/ServiceResult.tsx | 115 +++--------------------- src/lib/user/userData.ts | 38 ++++++++ 3 files changed, 100 insertions(+), 107 deletions(-) create mode 100644 src/lib/user/userData.ts diff --git a/src/components/mypage/Service.tsx b/src/components/mypage/Service.tsx index 26ec7a6..e5f46d7 100644 --- a/src/components/mypage/Service.tsx +++ b/src/components/mypage/Service.tsx @@ -1,17 +1,63 @@ -const Service = () => { +import { colors } from "@/styles/theme"; +import { styled } from "styled-components"; + +interface ServiceProps { + button1: string; + button2: string; + content: string; +} + +const Service = (props: ServiceProps) => { + const { button1, button2, content } = props; + return ( - 바디 카피 + {button1} - 톤 앤 매너 + {button2} - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ + {content} ); }; export default Service; + +const CopyWrapper = styled.div` + display: flex; + width: 49%; + flex-direction: column; + justify-content: space-between; + border-radius: 0.875rem; + background: ${colors.grey0}; + padding: 1rem 1rem 3rem 1rem; + color: var(--Basic-White, #fff); + text-align: center; + font-size: 0.9rem; + font-style: normal; + font-weight: 500; + line-height: 1.375rem; + margin-bottom: 2%; +`; +const TagWrapper = styled.div` + display: inline-flex; + gap: 0.5rem; + margin-bottom: 3rem; +`; +const Tag = styled.div<{ color: string; background: string }>` + padding: 0.375rem 0.875rem; + justify-content: center; + align-items: center; + border-radius: 1.375rem; + border: 1px solid ${(props) => props.color}; + background: ${(props) => props.background}; + color: ${(props) => props.color}; + font-size: 0.75rem; + font-style: normal; + font-weight: 500; + line-height: normal; +`; diff --git a/src/components/mypage/ServiceResult.tsx b/src/components/mypage/ServiceResult.tsx index 4806983..fc41874 100644 --- a/src/components/mypage/ServiceResult.tsx +++ b/src/components/mypage/ServiceResult.tsx @@ -2,9 +2,10 @@ import styled from "styled-components"; import { colors } from "@/styles/theme"; -import Image from "next/image"; import { useState } from "react"; import { useWindowSize } from "@/hooks/useWindowSize"; +import { serviceData } from "@/lib/user/userData"; +import Service from "./Service"; const ServiceResult = () => { const size = useWindowSize(); @@ -14,72 +15,14 @@ const ServiceResult = () => { {categoryIndex == 0 ? ( - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - - - - - 바디 카피 - - - 톤 앤 매너 - - - ‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’ - + {serviceData.map((data) => ( + + ))} ) : ( <> @@ -105,47 +48,13 @@ const BoxContents = styled.div` &::-webkit-scrollbar-track { margin: 1rem; border-radius: 10px; - background-color: ${colors.grey0}; + background-color: ${colors.secondaryLight3}; } &::-webkit-scrollbar { width: 0.375rem; } &::-webkit-scrollbar-thumb { border-radius: 10px; - background-color: ${colors.main}; + background-color: ${colors.secondary}; } `; -const CopyWrapper = styled.div` - display: flex; - width: 49%; - flex-direction: column; - justify-content: space-between; - border-radius: 0.875rem; - background: ${colors.grey0}; - padding: 1rem 1rem 2rem 1rem; - color: var(--Basic-White, #fff); - text-align: center; - font-size: 0.9375rem; - font-style: normal; - font-weight: 500; - line-height: 1.375rem; - margin-bottom: 2%; -`; -const TagWrapper = styled.div` - display: inline-flex; - gap: 0.5rem; - margin-bottom: 2rem; -`; -const Tag = styled.div<{ color: string; background: string }>` - padding: 0.375rem 0.875rem; - justify-content: center; - align-items: center; - border-radius: 1.375rem; - border: 1px solid ${(props) => props.color}; - background: ${(props) => props.background}; - color: ${(props) => props.color}; - font-size: 0.75rem; - font-style: normal; - font-weight: 500; - line-height: normal; -`; diff --git a/src/lib/user/userData.ts b/src/lib/user/userData.ts new file mode 100644 index 0000000..4aded71 --- /dev/null +++ b/src/lib/user/userData.ts @@ -0,0 +1,38 @@ +export const serviceData = [ + { + id: 1, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, + { + id: 2, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, + { + id: 3, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, + { + id: 4, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, + { + id: 5, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, + { + id: 6, + button1: "바디 카피", + button2: "톤 앤 매너", + content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", + }, +]; From 7775f8799dea46f19c750ae8741a42574e8e484f Mon Sep 17 00:00:00 2001 From: parkyejin Date: Sat, 9 Mar 2024 22:20:17 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat(#28):=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/mypage/Mypage.tsx | 1 - src/components/mypage/ServiceBox.tsx | 404 +++++---------------------- src/lib/user/userData.ts | 46 +++ 3 files changed, 115 insertions(+), 336 deletions(-) diff --git a/src/components/mypage/Mypage.tsx b/src/components/mypage/Mypage.tsx index 41d6392..8a330c6 100644 --- a/src/components/mypage/Mypage.tsx +++ b/src/components/mypage/Mypage.tsx @@ -20,7 +20,6 @@ export default Mypage; const Layout = styled.div` display: flex; - height: 80%; flex-direction: column; justify-content: center; padding: 5.5rem 6% 0 6%; diff --git a/src/components/mypage/ServiceBox.tsx b/src/components/mypage/ServiceBox.tsx index 41519bd..20b2853 100644 --- a/src/components/mypage/ServiceBox.tsx +++ b/src/components/mypage/ServiceBox.tsx @@ -1,265 +1,86 @@ "use client"; -import { useWindowSize } from "@/hooks/useWindowSize"; +import { serviceOption, toneMannerOption } from "@/lib/user/userData"; import { colors } from "@/styles/theme"; import { useEffect, useState } from "react"; import styled from "styled-components"; -import { Toggle } from "../common/Toggle"; -import Image from "next/image"; - -const genderOption = ["전체", "남성", "여성"]; -const ageOption = [ - "전체", - "0~9세", - "10~19세", - "20~29세", - "30~39세", - "40~49세", - "50~59세", - "60~69세", - "70세 이상", -]; const ServiceBox = () => { - const size = useWindowSize(); - - // 백엔드에 보낼 데이터 (Form submit 용) const [values, setValues] = useState({ - category: "", // 서비스 선택: 헤드/바디 - projectName: "", // 프로젝트명 - serviceName: "", // 상품/서비스명 - targetGender: "", // 성별 - targetAge: "", // 연령대 - keyword: "", //키워드 - toneManner: "", // 톤앤매너 + service: "", + toneManner: "", }); - const handleChange = (e: any) => { - setValues({ - ...values, - [e.target.name]: e.target.value, - }); - }; - - // 생성 버튼 disabled 인지 아닌지 - const [canSubmit, setCanSubmit] = useState(false); - useEffect(() => { - const isFull = Object.values(values).every((value) => value.trim() !== ""); - setCanSubmit(isFull); - }, [values]); - - const [focused, setFocused] = useState(""); - // 포커스 상태 변경 함수 - const handleFocus = (name: string) => { - setFocused(name); - }; - // 포커스 해제 함수 - const handleBlur = () => { - setFocused(""); - }; - // 헤드카피, 바디카피 const [category, setCategory] = useState(""); + const [toneManner, setToneManner] = useState(""); const categoryClick = (opt: string) => { category === opt ? setCategory("") : setCategory(opt); }; - - // 키워드 - const [keywords, setKeywords] = useState([]); - const [inputValue, setInputValue] = useState(""); - // 키워드 input이 변경될 때마다 업데이트 - const keywordChange = (e: any) => { - setInputValue(e.target.value); + const toneMannerClick = (opt: string) => { + toneManner === opt ? setToneManner("") : setToneManner(opt); }; - // 엔터를 누르면 키워드 배열에 값 추가 & input 초기화 - // e.nativeEvent.isComposing == false: onKeyDown 한글 오류 해결 - const keywordEnter = (e: any) => { - if (e.key === "Enter" && e.nativeEvent.isComposing === false) { - e.preventDefault(); - setKeywords((prevKeywords) => [...prevKeywords, inputValue]); - setInputValue(""); + + const [canSubmit, setCanSubmit] = useState(false); + const [okSubmit, setOkSubmit] = useState(false); + const handleSubmit = () => { + setValues({ service: category, toneManner: toneManner }); + if (canSubmit) { + setOkSubmit(true); } }; - // 키워드 배열에서 삭제 - const removeKeyword = (indexToRemove: number) => { - setKeywords((prevKeywords) => - prevKeywords.filter((_, index) => index !== indexToRemove) - ); - }; - // 톤앤매너 - const [toneManner, setToneManner] = useState(0); + useEffect(() => { + if (category !== "" && toneManner !== "") { + setCanSubmit(true); + } else { + setCanSubmit(false); + } + }, [category, toneManner]); return ( - - - - - N카피 - - - K카피 - - - N카피는 네이버 HyperCLOVA를 연계해 구축한 AI 카피 생성 서비스예요 - + 서비스 선택 - - categoryClick("head")} - > - 헤드 카피 - - categoryClick("body")} - > - 바디 카피 - - - - - 프로젝트명 - handleFocus("projectName")} - onBlur={handleBlur} - autoComplete="off" - /> - - - 상품/서비스 명 - handleFocus("serviceName")} - onBlur={handleBlur} - autoComplete="off" - /> - - - 타겟 - - - - - - - 키워드 - handleFocus("keyword")} - onBlur={handleBlur} - onChange={keywordChange} - onKeyDown={keywordEnter} - value={inputValue} - autoComplete="off" - /> - - {keywords.map((keyword, index) => ( - - {keyword} - close removeKeyword(index)} - /> - - ))} - - - - 톤 앤 매너 - - - setToneManner(1)} - > - 기본형 - - setToneManner(2)} - > - 언어유희형 - - setToneManner(3)} - > - 행동촉구형 - - setToneManner(4)} - > - 리뷰형 - - - - setToneManner(5)} - > - 경고형 - - setToneManner(6)} - > - 감정호소형 - + + {serviceOption.map((item) => ( setToneManner(7)} + onClick={() => categoryClick(item.name)} > - 문제제기형 + {item.name} + ))} + + + + + 톤 앤 매너 + + {toneMannerOption.map((item) => ( setToneManner(8)} + onClick={() => toneMannerClick(item.name)} > - 질문형 + {item.name} - - + ))} + - - 광고카피생성 + + + 적용하기 ); @@ -271,44 +92,18 @@ const BoxWrapper = styled.div` display: flex; flex-direction: column; width: 40%; + justify-content: space-between; flex-shrink: 0; border-radius: 0.875rem; background: #212121; padding: 1.88rem 2.5rem; align-items: center; `; -const BoxHead = styled.div` - display: flex; - flex-direction: column; - align-items: center; - gap: 0.5rem; - color: ${colors.grey05}; - text-align: center; - font-size: 0.75rem; - font-style: normal; - font-weight: 400; - line-height: 1.875rem; - margin-bottom: 1rem; -`; const InlineContent = styled.div<{ gap: string }>` display: flex; - flex-grow: 1; + flex-wrap: wrap; gap: ${(props) => props.gap}; -`; -const TitleBox = styled.div<{ color: string; border: string }>` - display: flex; - width: 9.625rem; - padding: 0.625rem; - justify-content: center; - align-items: center; - gap: 0.625rem; - border-bottom: 2px solid ${(props) => props.border}; - color: ${(props) => props.color}; - text-align: center; - font-size: 1rem; - font-style: normal; - font-weight: 500; - line-height: normal; + margin-bottom: 1rem; `; const BoxContent = styled.div` display: flex; @@ -334,86 +129,12 @@ const Contents = styled.div<{ focus: string; opt: string }>` font-weight: 500; line-height: normal; `; -const SelectButton = styled.button<{ - active: boolean; - color: string; - background: string; -}>` - display: flex; - flex-grow: 1; - height: 3.125rem; - justify-content: center; - align-items: center; - flex-shrink: 0; - border-radius: 6.25rem; - border: 1px solid ${(props) => (props.active ? props.color : colors.grey0)}; - background: ${(props) => (props.active ? props.background : colors.grey0)}; - color: ${(props) => (props.active ? props.color : colors.grey1)}; - font-size: 0.875rem; - font-style: normal; - font-weight: 500; - line-height: normal; - cursor: pointer; -`; -const InputContent = styled.input` - display: flex; - width: 100%; - height: 3.125rem; - padding-left: 2rem; - align-items: center; - flex-shrink: 0; - border-radius: 6.25rem; - color: ${colors.white}; - font-size: 0.875rem; - font-style: normal; - font-weight: 500; - line-height: normal; - border: 1px solid ${colors.grey0}; - background: ${colors.grey0}; - &:focus { - outline: none; - border: 1px solid ${colors.main}; - } -`; -const SubmitButton = styled.button` - display: flex; - width: 100%; - padding: 0.75rem 2.5rem; - justify-content: center; - align-items: center; - border-radius: 2.1875rem; - border: none; - color: ${(props) => (props.disabled ? colors.grey05 : colors.white)}; - background: ${(props) => (props.disabled ? "#393939" : colors.main)}; - margin-top: 1.88rem; -`; -const KeywordRegion = styled.ul` - width: 100%; - color: ${colors.grey4}; - font-size: 0.875rem; - font-style: normal; - font-weight: 500; - line-height: normal; - padding-left: 0.94rem; -`; -const Keyword = styled.li` - display: inline-flex; - padding: 0.25rem 0.25rem 0.25rem 0.75rem; - justify-content: space-between; - align-items: center; - gap: 0.1875rem; - border-radius: 6.25rem; - background: ${colors.grey0}; - margin-right: 0.5rem; -`; const ToneButton = styled.button<{ active: boolean; color: string; background: string; }>` display: flex; - flex-grow: 1; - height: 2.5rem; justify-content: center; align-items: center; border-radius: 1.825rem; @@ -424,6 +145,7 @@ const ToneButton = styled.button<{ font-style: normal; font-weight: 500; line-height: normal; + padding: 0.5rem 1.3rem; cursor: pointer; &:focus { outline-color: ${colors.main}; @@ -433,10 +155,22 @@ const ToneButton = styled.button<{ border-color: transparent; } `; -const ToneRegion = styled.div` + +const SubmitButton = styled.button<{ okSubmit: boolean; disabled: boolean }>` display: flex; - flex-direction: column; - padding: 0 0.125rem; - gap: 0.5rem; - margin-bottom: 1rem; + width: 100%; + padding: 0.75rem 2.5rem; + justify-content: center; + align-items: center; + border-radius: 2.1875rem; + border: none; + margin-top: 1.88rem; + color: ${(props) => (props.okSubmit ? colors.white : "#5D5D5D")}; + background: ${(props) => (props.okSubmit ? colors.main : "#393939")}; + cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")}; + &:hover { + color: ${(props) => (props.disabled ? colors.grey05 : colors.white)}; + background: ${(props) => (props.disabled ? "#393939" : colors.main)}; + transition: 0.3s; + } `; diff --git a/src/lib/user/userData.ts b/src/lib/user/userData.ts index 4aded71..2e3f50a 100644 --- a/src/lib/user/userData.ts +++ b/src/lib/user/userData.ts @@ -36,3 +36,49 @@ export const serviceData = [ content: "‘내가 사는 지역을 더 살기 좋게, 더 매력 있게’", }, ]; + +export const serviceOption = [ + { + id: 1, + name: "하드 카피", + }, + { + id: 2, + name: "바디 카피", + }, +]; + +export const toneMannerOption = [ + { + id: 1, + name: "기본형", + }, + { + id: 2, + name: "언어유희형", + }, + { + id: 3, + name: "행동촉구형", + }, + { + id: 4, + name: "리뷰형", + }, + { + id: 5, + name: "경고형", + }, + { + id: 6, + name: "감정호소형", + }, + { + id: 7, + name: "문제제기형", + }, + { + id: 8, + name: "질문형", + }, +];