diff --git a/src/Provider/MailContext.tsx b/src/Provider/MailContext.tsx index d1ec4ba..a8b0f1c 100644 --- a/src/Provider/MailContext.tsx +++ b/src/Provider/MailContext.tsx @@ -1,20 +1,37 @@ import React, { createContext, useContext, useState } from 'react'; import type { ReactNode } from 'react'; +import { MailInput } from '@/types'; -import { mailSend } from '@/types'; +export type mailSendUniv = { + sender: string; + content: string; + department: string; + studentId: string; + subject: string; + receiver: string; +}; + +export type mailSendBusiness = { + content: string; + sender: string; + company: string; + department: string; + additional: string; + name: string; +}; interface MailContextProps { - mailInput: mailSend; - handleMail: (mailBox: mailSend) => void; - isActive: string; - onIsActive: (state: string) => void; + mailInput: MailInput; + handleMail: (mailBox: MailInput) => void; + isActive: 'univ' | 'business'; + onIsActive: (state: 'univ' | 'business') => void; } export const MailContext = createContext(null); export const MailProvider = ({ children }: { children: ReactNode }) => { - const [isActive, setIsActive] = useState('univ'); - const [mailInput, setMailInput] = useState({ + const [isActive, setIsActive] = useState<'univ' | 'business'>('univ'); + const [mailInput, setMailInput] = useState({ sender: '', content: '', department: '', @@ -23,19 +40,31 @@ export const MailProvider = ({ children }: { children: ReactNode }) => { receiver: '', }); - const handleMail = (mailBox: mailSend) => { - setMailInput({ - sender: mailBox.sender, - content: mailBox.content, - department: mailBox.department, - studentId: mailBox.studentId, - subject: mailBox.subject, - receiver: mailBox.receiver, - }); + const handleMail = (mailBox: MailInput) => { + setMailInput(mailBox); }; - const onIsActive = (state: string) => { + const onIsActive = (state: 'univ' | 'business') => { setIsActive(state); + if (state === 'business') { + setMailInput({ + content: '', + sender: '', + company: '', + department: '', + additional: '', + receiver: '', + }); + } else { + setMailInput({ + sender: '', + content: '', + department: '', + studentId: '', + subject: '', + receiver: '', + }); + } }; return ( diff --git a/src/api/hooks/usePostBusiness.tsx b/src/api/hooks/usePostBusiness.tsx new file mode 100644 index 0000000..5524afa --- /dev/null +++ b/src/api/hooks/usePostBusiness.tsx @@ -0,0 +1,27 @@ +import { useMutation } from '@tanstack/react-query'; +import { mailSendBusiness, mailResponseData } from '@/types'; +import { BASE_URL } from '..'; +import axios from 'axios'; + +export const postBusinessPath = () => `${BASE_URL}/api/mails/business`; + +export const postBusiness = async (mailData: mailSendBusiness): Promise => { + const response = await axios.post(postBusinessPath(), mailData); + return response.data; +}; + +export const usePostBusiness = () => { + const { mutate: businessMutate, status: businessStatus } = useMutation< + mailResponseData, + Error, + mailSendBusiness + >({ + mutationFn: postBusiness, + retry: 3, + onError: (error) => { + console.error('API call failed:', error); + }, + }); + + return { businessMutate, businessStatus }; +}; diff --git a/src/api/hooks/usePostUniv.tsx b/src/api/hooks/usePostUniv.tsx index 81eab0c..e8e296b 100644 --- a/src/api/hooks/usePostUniv.tsx +++ b/src/api/hooks/usePostUniv.tsx @@ -1,17 +1,21 @@ import { useMutation } from '@tanstack/react-query'; -import { mailSend, mailResponseData } from '@/types'; +import { mailSendUniv, mailResponseData } from '@/types'; import { BASE_URL } from '..'; import axios from 'axios'; export const postUnivPath = () => `${BASE_URL}/api/mails/univ`; -export const postUniv = async (mailData: mailSend): Promise => { +export const postUniv = async (mailData: mailSendUniv): Promise => { const response = await axios.post(postUnivPath(), mailData); return response.data; }; export const usePostUniv = () => { - const mutation = useMutation({ + const { mutate: univMutate, status: univStatus } = useMutation< + mailResponseData, + Error, + mailSendUniv + >({ mutationFn: postUniv, retry: 3, onError: (error) => { @@ -19,5 +23,5 @@ export const usePostUniv = () => { }, }); - return mutation; + return { univMutate, univStatus }; }; diff --git a/src/components/HomePage/TestersBox/AskList.tsx b/src/components/HomePage/TestersBox/AskList.tsx index 3fa2fc2..afa01df 100644 --- a/src/components/HomePage/TestersBox/AskList.tsx +++ b/src/components/HomePage/TestersBox/AskList.tsx @@ -1,10 +1,8 @@ import React from 'react'; import styled from '@emotion/styled'; -import { mailSend } from '@/types'; - -interface AskListProps { - randomInput: mailSend; -} +import { AskListProps, Question } from '@/types'; +import { useMail } from '@/Provider/MailContext'; +import { useState, useEffect } from 'react'; const purposes = [ { id: '์งˆ๋ฌธ', label: '๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ์งˆ๋ฌธ' }, @@ -15,45 +13,56 @@ const purposes = [ ]; export const AskList = ({ randomInput }: AskListProps) => { + const { isActive } = useMail(); + const [questions, setQuestions] = useState([]); + + useEffect(() => { + if (isActive === 'business' && 'company' in randomInput) { + setQuestions([ + { ask: '๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.content }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.sender }, + { ask: '์†Œ์† ํšŒ์‚ฌ๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.company }, + { ask: '์†Œ์† ๋ถ€์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.department }, + { ask: '์ถ”๊ฐ€ ๊ธฐ์žฌ์‚ฌํ•ญ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.additional }, + { ask: '๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.receiver }, + ]); + } else if (isActive !== 'business' && 'studentId' in randomInput) { + setQuestions([ + { ask: '๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.content }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.sender }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๊ณผ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.department }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๋ฒˆ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.studentId }, + { ask: '๊ฐ•์˜๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.subject }, + { ask: '๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', input: randomInput.receiver }, + ]); + } + }, [isActive, randomInput]); + return ( - - ๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - - {purposes.map((purpose) => ( - - {purpose.label} - - ))} - - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.sender} - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๊ณผ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.department} - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๋ฒˆ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.studentId} - - - ๊ฐ•์˜๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.subject} - - - ๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” - {randomInput.receiver} - + {questions.map((question, index) => ( + + {question.ask} + {isActive === 'univ' && index === 0 ? ( + + {purposes.map((purpose) => ( + + {purpose.label} + + ))} + + ) : ( + {question.input} + )} + + ))} ); }; const AskListWrapper = styled.div` width: 768px; - height: auto; + height: 750px; flex-shrink: 0; border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.3); @@ -62,10 +71,9 @@ const AskListWrapper = styled.div` flex-direction: column; padding-left: 36px; padding-top: 46px; - padding-bottom: 46px; - gap: 40px; + padding-bottom: 86px; + gap: 10px; `; - const AskListItemWrapper = styled.div` display: flex; flex-direction: column; diff --git a/src/components/HomePage/TestersBox/Buttons.tsx b/src/components/HomePage/TestersBox/Buttons.tsx index 9f40a94..77331fe 100644 --- a/src/components/HomePage/TestersBox/Buttons.tsx +++ b/src/components/HomePage/TestersBox/Buttons.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { mailSend } from '@/types'; +import { MailInput, mailSendUniv, mailSendBusiness } from '@/types'; import { usePostUniv } from '@/api/hooks/usePostUniv'; import { useState } from 'react'; import { @@ -13,27 +13,52 @@ import { Button, Spinner, } from '@chakra-ui/react'; +import { useMail } from '@/Provider/MailContext'; +import { usePostBusiness } from '@/api/hooks/usePostBusiness'; interface ButtonsProps { - handleList: () => void; - randomInput: mailSend; + handleListUniv: () => void; + handleListBusiness: () => void; + randomInput: MailInput; } -export const Buttons = ({ handleList, randomInput }: ButtonsProps) => { - const { mutate, status } = usePostUniv(); +export const Buttons = ({ handleListUniv, handleListBusiness, randomInput }: ButtonsProps) => { + const { univMutate, univStatus } = usePostUniv(); + const { businessMutate, businessStatus } = usePostBusiness(); const [isOpen, setIsOpen] = useState(false); const [title, setTitle] = useState(''); const [content, setContent] = useState(''); + const { isActive } = useMail(); + const onClose = () => { setIsOpen(false); }; - const setMailInput = () => { + const setMailInputUniv = () => { + setIsOpen(true); + + univMutate( + { ...(randomInput as unknown as mailSendUniv) }, + { + onSuccess: (data) => { + console.log(data); + setTitle(data.title || '๋ฉ”์ผ ์ƒ์„ฑ ์„ฑ๊ณต'); + setContent(data.content || '๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); + }, + onError: (error) => { + setTitle('๋ฉ”์ผ ์ƒ์„ฑ ์‹คํŒจ'); + setContent('๋ฉ”์ผ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + }, + }, + ); + }; + + const setMailInputBusiness = () => { setIsOpen(true); - mutate( - { ...randomInput }, + businessMutate( + { ...(randomInput as unknown as mailSendBusiness) }, { onSuccess: (data) => { console.log(data); @@ -48,15 +73,21 @@ export const Buttons = ({ handleList, randomInput }: ButtonsProps) => { ); }; + const isLoading = univStatus === 'pending' || businessStatus === 'pending'; + return ( - + (isActive === 'univ' ? handleListUniv() : handleListBusiness())} + > ์˜ˆ์‹œ ๋ณ€๊ฒฝ - + (isActive === 'univ' ? setMailInputUniv() : setMailInputBusiness())} + > ๋ฉ”์ผ ์ƒ์„ฑํ•˜๊ธฐ @@ -64,14 +95,12 @@ export const Buttons = ({ handleList, randomInput }: ButtonsProps) => { - {status === 'pending' || status === 'error' ? ( + {isLoading ? ( - - {status === 'pending' ? '๋ฉ”์ผ ์ƒ์„ฑ ์ค‘...์กฐ๊ธˆ๋งŒ ๊ธฐ๋‹ค๋ ค ์ฃผ์„ธ์š”!' : title} - + ๋ฉ”์ผ ์ƒ์„ฑ ์ค‘...์กฐ๊ธˆ๋งŒ ๊ธฐ๋‹ค๋ ค ์ฃผ์„ธ์š”! - {status === 'pending' ? :

{content}

} +
) : ( @@ -105,6 +134,10 @@ const ButtonsWrapper = styled.div` align-items: center; justify-content: space-around; padding: 20px 0; + z-index: 2; + position: absolute; + top: 50%; + left: 20%; `; const ButtonContainer = styled.div` diff --git a/src/components/HomePage/TestersBox/Header.tsx b/src/components/HomePage/TestersBox/Header.tsx index 5e0dfff..25cf29e 100644 --- a/src/components/HomePage/TestersBox/Header.tsx +++ b/src/components/HomePage/TestersBox/Header.tsx @@ -1,90 +1,64 @@ import styled from '@emotion/styled'; -import { breakpoints } from '@/styles/variants'; // breakpoints๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. interface HeaderProps { isActive: string; - onIsActive: (isActive: string) => void; + onIsActive: (state: 'univ' | 'business') => void; } interface StudentProps { isActive: string; } +interface BusinessProps { + isActive: string; +} + export const Header = ({ isActive, onIsActive }: HeaderProps) => { return ( - - onIsActive('univ')}> - ๋Œ€ํ•™์ƒ - - - ์ง์žฅ์ธ - - + <> +
+ onIsActive('univ')}> + ๋Œ€ํ•™์ƒ + + onIsActive('business')}> + ์ง์žฅ์ธ + +
-
+ ); }; -const HeaderWrapper = styled.div` - display: flex; - flex-direction: row; - align-items: flex-start; - width: 100%; - padding-top: 33px; - position: relative; -`; - const Student = styled.div` margin-left: 167px; cursor: pointer; - box-shadow: ${(props) => (props.isActive ? '0 4px 0 0 #6AB9F2' : 'none')}; + box-shadow: ${(props) => (props.isActive === 'univ' ? '0 4px 0 0 #6AB9F2' : 'none')}; position: relative; z-index: 2; - bottom: -1px; - - @media (${breakpoints.md}) { - margin-left: 20px; - } + bottom: -13px; `; -const Office = styled.div` +const Business = styled.div` margin-left: 44px; + cursor: pointer; + box-shadow: ${(props) => (props.isActive === 'business' ? '0 4px 0 0 #6AB9F2' : 'none')}; position: relative; z-index: 2; - bottom: -1px; - - &:hover > img { - visibility: visible; - } - - @media (${breakpoints.md}) { - margin-left: 20px; - } -`; - -const HoverImage = styled.img` - visibility: hidden; - position: relative; - top: -70px; - left: 50%; - transform: translateX(-50%); - width: 174px; - height: 34px; - flex-shrink: 0; - z-index: 3; + bottom: -13px; `; const Bar = styled.div` background: white; - width: 1300px; + width: 1200px; height: 3px; position: absolute; - bottom: 45px; - z-index: 1; /* Ensure it is below Student and Office */ - - @media (${breakpoints.md}) { - position: relative; - bottom: -20px; - margin-top: 10px; - } + bottom: 8px; `; diff --git a/src/components/HomePage/TestersBox/index.tsx b/src/components/HomePage/TestersBox/index.tsx index 95e30ee..3a2beff 100644 --- a/src/components/HomePage/TestersBox/index.tsx +++ b/src/components/HomePage/TestersBox/index.tsx @@ -2,15 +2,19 @@ import { Img } from '@chakra-ui/react'; import styled from '@emotion/styled'; import { Grid, GridItem } from '@chakra-ui/react'; import { useState } from 'react'; -import { mockData } from '@/types/mock'; + import { AskList } from './AskList'; import { Header } from './Header'; import { Buttons } from './Buttons'; import { breakpoints } from '@/styles/variants'; import { useMail } from '@/Provider/MailContext'; +import { mockDataUniv } from '@/types/mock/mockUniv'; +import { mockDataBusiness } from '@/types/mock/mockBusiness'; +import { MailInput } from '@/types'; +import { useEffect } from 'react'; export const TestersBox = () => { - const [randomInput, setRandomInput] = useState({ + const [randomInput, setRandomInput] = useState({ sender: 'ํ™๊ธธ๋™', content: '์งˆ๋ฌธ', department: '์ปดํ“จํ„ฐ๊ณตํ•™๊ณผ', @@ -20,11 +24,24 @@ export const TestersBox = () => { }); const { isActive, onIsActive } = useMail(); - const handleList = () => { - const randomIndex = Math.floor(Math.random() * mockData.length); - setRandomInput(mockData[randomIndex]); + const handleListUniv = () => { + const randomIndex = Math.floor(Math.random() * mockDataUniv.length); + setRandomInput(mockDataUniv[randomIndex]); + }; + + const handleListBusiness = () => { + const randomIndex = Math.floor(Math.random() * mockDataBusiness.length); + setRandomInput(mockDataBusiness[randomIndex]); }; + useEffect(() => { + if (isActive === 'univ') { + handleListUniv(); + } else { + handleListBusiness(); + } + }, [isActive]); + return ( @@ -33,13 +50,20 @@ export const TestersBox = () => { - +
- + { templateColumns={{ base: 'repeat(1, 1fr)', md: 'repeat(3, 1fr)' }} gap={{ base: '20px', md: '0' }} > - + { justifyContent={{ base: 'center', md: 'space-between' }} alignItems={{ base: 'center', md: 'flex-end' }} flexDirection={{ base: 'column', md: 'column' }} - marginRight={{ base: '0', md: '56px' }} - marginBottom={{ base: '0', md: '25px' }} - backgroundImage={'/images/exampleImage2.svg'} - backgroundSize="cover" - backgroundPosition="center" - maxWidth={400} + position={'relative'} + width={'fit-content'} > - + + @@ -98,3 +123,5 @@ const MedeaItems = styled(Grid)` display: none; } `; + +const ImageWrapper = styled.img``; diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index e8d4aca..136fbf7 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -29,6 +29,7 @@ export const Header = () => { subject: '', receiver: '', }); + window.location.reload(); }; return ( diff --git a/src/components/Layout/MainHeader.tsx b/src/components/Layout/MainHeader.tsx new file mode 100644 index 0000000..fe0ec50 --- /dev/null +++ b/src/components/Layout/MainHeader.tsx @@ -0,0 +1,131 @@ +import styled from '@emotion/styled'; +import { Link } from 'react-router-dom'; +import { Button } from '@chakra-ui/react'; +import { breakpoints } from '@/styles/variants'; +import { useMail } from '@/Provider/MailContext'; + +const scrollToSection = (sectionId: string) => { + const element = document.getElementById(sectionId); + if (element) { + const elementPosition = element.getBoundingClientRect().top + window.scrollY - 80; + window.scrollTo({ top: elementPosition, behavior: 'smooth' }); + } +}; + +export const MainHeader = () => { + const mailContext = useMail(); + + if (!mailContext) { + throw new Error('MailContext not found'); + } + const { handleMail } = mailContext; + + const handleMailInput = () => { + handleMail({ + sender: '', + content: '', + department: '', + studentId: '', + subject: '', + receiver: '', + }); + }; + + return ( + + +
Login
+ + + +
+
+ scrollToSection('section2')}> ์„œ๋น„์Šค ์ฒดํ—˜ + scrollToSection('section3')}> ๊ธฐ๋Šฅ ์‚ดํŽด๋ณด๊ธฐ +
+ + AI ๋ฉ”์ผ ์ƒ์„ฑํ•˜๊ธฐ + +
+
+
+ ); +}; + +export const HEADER_HEIGHT = '80px'; + +const Wrapper = styled.header` + z-index: 100; + height: ${HEADER_HEIGHT}; + padding: 16px 40px; + background: linear-gradient(90deg, #e6e9ff 0%, #e5f3ff 100%); + box-shadow: 0px 2px 18px 2px rgba(0, 0, 0, 0.1); +`; + +const Logo = styled.img` + height: 48px; + cursor: pointer; +`; + +const Container = styled.div` + display: flex; + flex-direction: row; + font-size: 14px; + justify-content: space-between; +`; + +const AiButton = styled(Button)` + position: relative; + display: flex; + height: 40px; + width: 136px; + padding: 10px 20px; + border-radius: 20px; + align-items: center; + justify-content: center; + gap: 10px; + background-color: transparent; + color: #000000; + font-family: 'Inter', sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 19.6px; + letter-spacing: -2%; + background-clip: padding-box; + + &:hover { + background: linear-gradient(to right, #6ab9f2, #7a89f0); + color: white; + } + + &:before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 20px; + padding: 1px; + background: linear-gradient(to right, #6ab9f2, #7a89f0); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + } +`; + +const MidWrapper = styled.div` + cursor: pointer; + margin: 0px 20px; + @media (max-width: ${breakpoints.md}) { + display: none; + } +`; + +const LogoLink = styled(Link)` + margin-left: 250px; + + @media (max-width: ${breakpoints.md}) { + margin-left: 100px; + } +`; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 01f9e4e..528b2fd 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -1,14 +1,18 @@ import styled from '@emotion/styled'; import { Outlet } from 'react-router-dom'; -import { Header, HEADER_HEIGHT } from './Header'; - import { Footer } from './Footer'; - +import { HEADER_HEIGHT, MainHeader } from './MainHeader'; +import { UpperImage } from './UpperImage'; export const Layout = () => { return ( -
+ + + + + + @@ -22,9 +26,20 @@ const Wrapper = styled.div` position: relative; `; +const UpperImageWrapper = styled.div` + width: 100%; + height: calc(100vh - ${HEADER_HEIGHT}); +`; + +const HeaderWrapper = styled.div` + width: 100%; + position: sticky; + top: 0; + z-index: 100; +`; + const InnerWrapper = styled.div` width: 100%; - padding-top: ${HEADER_HEIGHT}; position: relative; background-color: transparent; `; diff --git a/src/components/Mail/AskList.tsx b/src/components/Mail/AskList.tsx index 78e3541..a4eefb6 100644 --- a/src/components/Mail/AskList.tsx +++ b/src/components/Mail/AskList.tsx @@ -1,39 +1,42 @@ import styled from '@emotion/styled'; -import { mailSend } from '@/types'; +import { AskListProps, Question } from '@/types'; +import { useMail } from '@/Provider/MailContext'; +import { useState, useEffect } from 'react'; + +export const AskList = ({ randomInput }: AskListProps) => { + const { isActive } = useMail(); + const [questions, setQuestions] = useState([]); + + useEffect(() => { + if (isActive === 'business' && 'company' in randomInput) { + setQuestions([ + { ask: '๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.content }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.sender }, + { ask: '์†Œ์† ํšŒ์‚ฌ๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.company }, + { ask: '์†Œ์† ๋ถ€์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.department }, + { ask: '์ถ”๊ฐ€ ๊ธฐ์žฌ์‚ฌํ•ญ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.additional }, + { ask: '๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.receiver }, + ]); + } else if (isActive !== 'business' && 'studentId' in randomInput) { + setQuestions([ + { ask: '๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.content }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.sender }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๊ณผ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.department }, + { ask: '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๋ฒˆ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.studentId }, + { ask: '๊ฐ•์˜๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', input: randomInput.subject }, + { ask: '๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', input: randomInput.receiver }, + ]); + } + }, [isActive, randomInput]); -export const AskList = ({ randomInput }: { randomInput: mailSend }) => { return ( - - ๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.content || ' '} - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.sender || ' '} - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๊ณผ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - - {randomInput.department || ' '} - - - - ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ํ•™๋ฒˆ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - - {randomInput.studentId || ' '} - - - - ๊ฐ•์˜๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š” - {randomInput.subject || ' '} - - - ๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” - - {randomInput.receiver || ' '} - - + {questions.map((question, index) => ( + + {question.ask} + {question.input || ' '} + + ))} ); }; diff --git a/src/components/Mail/Header.tsx b/src/components/Mail/Header.tsx index b89663b..bf6c62b 100644 --- a/src/components/Mail/Header.tsx +++ b/src/components/Mail/Header.tsx @@ -2,14 +2,26 @@ import styled from '@emotion/styled'; interface HeaderProps { isActive: string; - onIsActive: (isActive: string) => void; + onIsActive: (state: 'univ' | 'business') => void; + onOpen: () => void; + onClose: () => void; } -interface StudentProps { +interface ActiveProps { isActive: string; } -export const Header = ({ isActive, onIsActive }: HeaderProps) => { +export const Header = ({ isActive, onIsActive, onOpen, onClose }: HeaderProps) => { + const handleUniv = () => { + onIsActive('univ'); + onOpen(); + }; + + const handleBusiness = () => { + onIsActive('business'); + onOpen(); + }; + return ( <>
{ paddingTop: '33px', }} > - onIsActive('univ')}> + ๋Œ€ํ•™์ƒ - + ์ง์žฅ์ธ -
@@ -34,35 +45,22 @@ export const Header = ({ isActive, onIsActive }: HeaderProps) => { ); }; -const Student = styled.div` +const Student = styled.div` margin-left: 167px; cursor: pointer; - box-shadow: ${(props) => (props.isActive ? '0 4px 0 0 #6AB9F2' : 'none')}; + box-shadow: ${(props) => (props.isActive === 'univ' ? '0 4px 0 0 #6AB9F2' : 'none')}; position: relative; z-index: 2; bottom: -13px; `; -const Office = styled.div` +const Office = styled.div` margin-left: 44px; + cursor: pointer; + box-shadow: ${(props) => (props.isActive === 'business' ? '0 4px 0 0 #6AB9F2' : 'none')}; position: relative; z-index: 2; bottom: -13px; - &:hover > img { - visibility: visible; - } -`; - -const HoverImage = styled.img` - visibility: hidden; - position: relative; - top: -70px; - left: 50%; - transform: translateX(-50%); - width: 174px; - height: 34px; - flex-shrink: 0; - z-index: 3; `; const Bar = styled.div` @@ -70,5 +68,5 @@ const Bar = styled.div` width: 1200px; height: 3px; position: absolute; - bottom: 24px; + bottom: 8px; `; diff --git a/src/components/Mail/MailModal.tsx b/src/components/Mail/MailModal.tsx index a554876..4e08391 100644 --- a/src/components/Mail/MailModal.tsx +++ b/src/components/Mail/MailModal.tsx @@ -13,16 +13,54 @@ import { Spinner, } from '@chakra-ui/react'; import styled from '@emotion/styled'; -import { mailSend } from '@/types'; +import { mailSendUniv, mailSendBusiness } from '@/types'; import { usePostUniv } from '@/api/hooks/usePostUniv'; import { useForm, Controller } from 'react-hook-form'; +import { usePostBusiness } from '@/api/hooks/usePostBusiness'; interface MailModalProps { isOpen: boolean; onClose: () => void; } -const mailLetterInitialState: mailSend = { +const mailLetterInitialStateBusiness: mailSendBusiness = { + content: '', + sender: '', + company: '', + department: '', + additional: '', + receiver: '', +}; + +const currentInputNamesBusiness: (keyof mailSendBusiness)[] = [ + 'content', + 'sender', + 'company', + 'department', + 'additional', + 'receiver', +]; + +const placeholderTextsBusiness = [ + '๊ธ€์ž ์ˆ˜ ์ œํ•œ: 5์ž ์ด์ƒ~300์ž ์ดํ•˜', + 'ํ™๊ธธ๋™', + '์•ŒํŒŒ์ฝ”', + '์ธ์‚ฌํŒ€', + '์ถ”๊ฐ€ ๊ธฐ์žฌ์‚ฌํ•ญ', + '๊น€์•ŒํŒŒ', +]; + +const modalHeaderContentBusiness = [ + '๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์„ ํƒํ•ด ์ฃผ์„ธ์š”', + '๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', + '์†Œ์† ํšŒ์‚ฌ๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', + '์†Œ์† ๋ถ€์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', + '์ถ”๊ฐ€ ๊ธฐ์žฌ์‚ฌํ•ญ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', + '๋ฐ›๋Š” ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”', + '๋ฉ”์ผ์„ ์ƒ์„ฑ ์ค‘ ์ž…๋‹ˆ๋‹ค', +]; + +const mailLetterInitialState: mailSendUniv = { content: '', sender: '', department: '', @@ -41,7 +79,7 @@ const modalHeaderContent = [ '๋ฉ”์ผ์„ ์ƒ์„ฑ ์ค‘ ์ž…๋‹ˆ๋‹ค', ]; -const inputNames: (keyof mailSend)[] = [ +const currentInputNames: (keyof mailSendUniv)[] = [ 'content', 'sender', 'department', @@ -67,11 +105,15 @@ const options = [ { label: '๐Ÿ“ ์ƒ๋‹ด ์š”์ฒญ', value: '์ƒ๋‹ด ์š”์ฒญ' }, ]; -const warningTexts = { +const warningTextsUniv = { content: ['๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', '5์ž ์ด์ƒ~300์ž ์ดํ•˜๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'], studentId: '์ˆซ์ž๋งŒ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ด์š”', }; +const warningTextsBusiness = { + content: ['๋ฉ”์ผ ์ž‘์„ฑ ๋ชฉ์ ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', '5์ž ์ด์ƒ~300์ž ์ดํ•˜๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'], +}; + interface OptionButtonProps extends React.ButtonHTMLAttributes { selected?: boolean; // selected prop ์ถ”๊ฐ€ } @@ -86,43 +128,70 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { const [isFocused, setIsFocused] = useState(false); const [isHide, setIsHide] = useState(false); const [firstInput, setFirstInput] = useState(''); + const { isActive } = useMail(); + + const currentcurrentInputNames = + isActive === 'univ' ? currentInputNames : currentInputNamesBusiness; + const currentPlaceholderTexts = isActive === 'univ' ? placeholderTexts : placeholderTextsBusiness; + const currentModalHeaderContent = + isActive === 'univ' ? modalHeaderContent : modalHeaderContentBusiness; const handleOptionClick = (value: string) => { setFirstInput(value); }; - const { mutate } = usePostUniv(); + const { univMutate } = usePostUniv(); + const { businessMutate } = usePostBusiness(); + const { control, handleSubmit, setValue, trigger, - formState: { errors, isValid }, - } = useForm({ + formState: { isValid }, + } = useForm({ mode: 'onChange', - defaultValues: { - ...mailLetterInitialState, - }, + defaultValues: isActive === 'univ' ? mailLetterInitialState : mailLetterInitialStateBusiness, }); - const onSubmit = (data: mailSend) => { + const setMailInputUniv = (data: mailSendUniv) => { + setIsLoading(true); + handleMail(data); + setIsHide(true); + + univMutate( + { ...(data as unknown as mailSendUniv) }, + { + onSuccess: (data) => { + console.log(data); + setTitle(data.title || '๋ฉ”์ผ ์ƒ์„ฑ ์„ฑ๊ณต'); + setContent(data.content || '๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); + }, + onError: (error) => { + setTitle('๋ฉ”์ผ ์ƒ์„ฑ ์‹คํŒจ'); + setContent('๋ฉ”์ผ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + }, + }, + ); + setIsHide(!isHide); + }; + + const setMailInputBusiness = (data: mailSendBusiness) => { setIsLoading(true); handleMail(data); setIsHide(true); - mutate( - { ...data }, + + businessMutate( + { ...(data as unknown as mailSendBusiness) }, { - onSuccess: (response) => { - setTitle(response.title || '๋ฉ”์ผ ์ƒ์„ฑ ์„ฑ๊ณต'); - setContent(response.content || '๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); - setIsSubmitted(true); - setIsLoading(false); + onSuccess: (data) => { + console.log(data); + setTitle(data.title || '๋ฉ”์ผ ์ƒ์„ฑ ์„ฑ๊ณต'); + setContent(data.content || '๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'); }, onError: (error) => { setTitle('๋ฉ”์ผ ์ƒ์„ฑ ์‹คํŒจ'); setContent('๋ฉ”์ผ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); - setIsSubmitted(true); - setIsLoading(false); }, }, ); @@ -130,14 +199,14 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { }; const handleNextClick = async (inputValue: string) => { - const isValid = await trigger(inputNames[currentIndex]); + const isValid = await trigger(currentcurrentInputNames[currentIndex]); if (currentIndex === 0 && firstInput && !inputValue) { - setValue(inputNames[currentIndex], firstInput, { shouldValidate: true }); + setValue(currentcurrentInputNames[currentIndex], firstInput, { shouldValidate: true }); } if (isValid) { - if (currentIndex < inputNames.length - 1) { + if (currentIndex < currentInputNames.length - 1) { setCurrentIndex(currentIndex + 1); setIsFocused(false); } @@ -157,9 +226,9 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { if (currentIndex === 0 && firstInput) { event.preventDefault(); const combinedValue = `${firstInput} : ${inputValue}`.trim(); - await setValue(inputNames[currentIndex], combinedValue, { shouldValidate: true }); + await setValue(currentInputNames[currentIndex], combinedValue, { shouldValidate: true }); } else { - await setValue(inputNames[currentIndex], inputValue, { shouldValidate: true }); + await setValue(currentInputNames[currentIndex], inputValue, { shouldValidate: true }); } await handleNextClick(inputValue); return; @@ -168,9 +237,11 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { useEffect(() => { setIsFocused(false); - setValue(inputNames[currentIndex], '', { shouldValidate: true }); + setValue(currentInputNames[currentIndex], '', { shouldValidate: true }); }, [currentIndex, setValue]); + const currentWarningTexts = isActive === 'univ' ? warningTextsUniv : warningTextsBusiness; + return ( { ? title : isLoading ? '๋ฉ”์ผ ์ƒ์„ฑ ์ค‘ ์ž…๋‹ˆ๋‹ค...' - : modalHeaderContent[currentIndex]} + : currentModalHeaderContent[currentIndex]} {isSubmitted ? ( @@ -206,7 +277,7 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { ) : ( <> - {currentIndex === 0 && ( + {currentIndex === 0 && isActive === 'univ' && ( {options.map((option) => ( { )} { if (currentIndex === 0) { if (!value && !firstInput) { - return warningTexts.content[0]; + return currentWarningTexts.content[0]; } if (value.length < 5 || value.length > 300) { - return warningTexts.content[1]; + return currentWarningTexts.content[1]; } } - if (currentIndex === 3 && (!/^\d+$/.test(value) || '')) { - return warningTexts.studentId; + if (currentIndex === 3) { + if (isActive === 'univ' && (!/^\d+$/.test(value) || '')) { + return (currentWarningTexts as typeof warningTextsUniv).studentId; + } + if (isActive === 'business' && value.length < 5) { + return currentWarningTexts.content[1]; + } } + return true; }, }} @@ -244,20 +321,17 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { <> setIsFocused(true)} onBlur={() => setIsFocused(false)} onChange={(e) => { field.onChange(e); - setValue(inputNames[currentIndex], e.target.value, { + setValue(currentInputNames[currentIndex], e.target.value, { shouldValidate: true, }); }} onKeyDown={handleKeyDown} /> - {errors[inputNames[currentIndex]] && ( - {errors[inputNames[currentIndex]]?.message} - )} )} /> @@ -268,10 +342,15 @@ export const MailModal = ({ isOpen, onClose }: MailModalProps) => { {!isHide && ( - {currentIndex < inputNames.length - 1 ? ( + {currentIndex < currentInputNames.length - 1 ? ( handleNextClick('')} /> ) : ( - + + isActive === 'univ' ? setMailInputUniv : setMailInputBusiness, + )} + disabled={!isValid} + > ์ƒ์„ฑํ•˜๊ธฐ @@ -412,11 +491,11 @@ const StyledInput = styled(Input)` text-align: center; `; -const WarningText = styled(Text)` - color: red; - font-size: 15px; - margin-top: 10px; -`; +// const WarningText = styled(Text)` +// color: red; +// font-size: 15px; +// margin-top: 10px; +// `; const ArrowButton = styled(Button)` background: none; diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index b78621a..3844c8a 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,13 +1,13 @@ -import { Contents } from "@/components/HomePage/Contents" -import styled from "@emotion/styled" +import { Contents } from '@/components/HomePage/Contents'; +import styled from '@emotion/styled'; export const HomePage = () => { return ( - ) -} + ); +}; const Wrapper = styled.div` width: 100%; @@ -15,4 +15,5 @@ const Wrapper = styled.div` radial-gradient(50% 50% at 25% 25%, #dee2fd 0%, rgba(230, 233, 255, 0) 100%), linear-gradient(180deg, #e5efff 0%, #fff 100%); overflow-x: hidden; -` + height: 100%; +`; diff --git a/src/pages/Mail/index.tsx b/src/pages/Mail/index.tsx index c5823a4..490ef3b 100644 --- a/src/pages/Mail/index.tsx +++ b/src/pages/Mail/index.tsx @@ -16,6 +16,10 @@ export const MailPage = () => { } const { mailInput } = mailContext; + const openModal = () => { + setIsModalOpen(true); + }; + const closeModal = () => { setIsModalOpen(false); }; @@ -42,12 +46,17 @@ export const MailPage = () => { justifyContent="center" position="relative" > -
+
- +