diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 4307a43a..5d78d49a 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import { GlobalStyle, theme } from '../src/styles'; +import { GlobalStyle } from '../src/styles'; import type { Preview } from '@storybook/react'; -import { ThemeProvider } from '@emotion/react'; import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'; +import Providers from '../src/app/providers'; const customViewports = { width600: { @@ -52,10 +52,10 @@ const preview: Preview = { }, decorators: [ (Story) => ( - + - + ), ], }; diff --git a/src/app/register/mentee/page.tsx b/src/app/register/mentee/page.tsx new file mode 100644 index 00000000..945b456b --- /dev/null +++ b/src/app/register/mentee/page.tsx @@ -0,0 +1,5 @@ +import { MenteeRegister } from '@/pageContainer'; + +const Mentee = () => ; + +export default Mentee; diff --git a/src/assets/GoBackIcon.tsx b/src/assets/GoBackIcon.tsx new file mode 100644 index 00000000..4770e445 --- /dev/null +++ b/src/assets/GoBackIcon.tsx @@ -0,0 +1,30 @@ +const GoBackIcon = () => ( + + + + + + + + + + +); + +export default GoBackIcon; diff --git a/src/assets/SendIcon.tsx b/src/assets/SendIcon.tsx new file mode 100644 index 00000000..55c4e55b --- /dev/null +++ b/src/assets/SendIcon.tsx @@ -0,0 +1,17 @@ +const SendIcon = () => ( + + + + +); + +export default SendIcon; diff --git a/src/assets/index.ts b/src/assets/index.ts index d576115f..47c7576c 100644 --- a/src/assets/index.ts +++ b/src/assets/index.ts @@ -6,6 +6,7 @@ export { default as EmailIcon } from './EmailIcon'; export { default as ExitIcon } from './ExitIcon'; export { default as FilterIcon } from './FilterIcon'; export { default as FoldIcon } from './FoldIcon'; +export { default as GoBackIcon } from './GoBackIcon'; export { default as GoogleIcon } from './GoogleIcon'; export { default as GsmNetworkingIcon } from './GsmNetworkingIcon'; export { default as ImageRegisterIcon } from './ImageRegisterIcon'; @@ -28,5 +29,6 @@ export { default as RemovePositionIcon } from './RemovePositionIcon'; export { default as SNSIcon } from './SNSIcon'; export { default as SearchIcon } from './SearchIcon'; export { default as SearchNotFoundIcon } from './SearchNotFoundIcon'; +export { default as SendIcon } from './SendIcon'; export { default as TriangleIcon } from './TriangleIcon'; export { default as UploadIcon } from './UploadIcon'; diff --git a/src/components/Buttons/ProfileUpdate/index.tsx b/src/components/Buttons/ProfileUpdate/index.tsx index 42928c63..edef34e3 100644 --- a/src/components/Buttons/ProfileUpdate/index.tsx +++ b/src/components/Buttons/ProfileUpdate/index.tsx @@ -11,8 +11,7 @@ interface Props { const ProfileUpdateButton: React.FC = ({ onClick }) => ( - 이미지 등록 - {/* 프로필 수정 // 임시로 이미지 등록으로 내용 변경해두겠습니다. */} + 이미지 수정 ); diff --git a/src/components/CareerRegistrationBox/index.tsx b/src/components/CareerRegistrationBox/index.tsx index acefd042..be58471b 100644 --- a/src/components/CareerRegistrationBox/index.tsx +++ b/src/components/CareerRegistrationBox/index.tsx @@ -22,6 +22,7 @@ import { deepCopy } from '@/utils'; interface Props { career: CareerFormType; + index: number; setCareerArray: React.Dispatch>; } @@ -38,6 +39,7 @@ const CareerRegistrationBox: React.FC = ({ isWorking, }, setCareerArray, + index, }) => { const endYearRef = useRef(null); const endMonthRef = useRef(null); @@ -116,8 +118,6 @@ const CareerRegistrationBox: React.FC = ({ newCareer.isWorking.value = isChecked; if (isChecked) { - if (endYearRef.current) endYearRef.current.value = ''; - if (endMonthRef.current) endMonthRef.current.value = ''; newCareer.endYear.value = '년'; newCareer.endYear.errorMessage = null; newCareer.endMonth.value = '월'; @@ -136,7 +136,7 @@ const CareerRegistrationBox: React.FC = ({ 재직 회사 정보 - {id !== 0 && ( + {index !== 0 && ( @@ -163,11 +163,12 @@ const CareerRegistrationBox: React.FC = ({ errorMessage={companyUrl.errorMessage} /> @@ -183,31 +184,35 @@ const CareerRegistrationBox: React.FC = ({ > handlePeriodChange(e, 'startMonth')} errorMessage={startMonth.errorMessage} /> ~ handlePeriodChange(e, 'endMonth')} errorMessage={endMonth.errorMessage} /> @@ -217,6 +222,7 @@ const CareerRegistrationBox: React.FC = ({ type='checkbox' id={`checkbox-${id}`} onChange={handleTenureCheck} + checked={isWorking.value} /> diff --git a/src/components/ChattingHeader/index.stories.tsx b/src/components/ChattingHeader/index.stories.tsx new file mode 100644 index 00000000..9440da01 --- /dev/null +++ b/src/components/ChattingHeader/index.stories.tsx @@ -0,0 +1,21 @@ +import ChattingHeader from '.'; + +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + component: ChattingHeader, + parameters: { + layout: 'padded', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + name: '방가온', + generation: 7, + }, +}; diff --git a/src/components/ChattingHeader/index.tsx b/src/components/ChattingHeader/index.tsx new file mode 100644 index 00000000..482ae2ce --- /dev/null +++ b/src/components/ChattingHeader/index.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { useRouter } from 'next/navigation'; + +import * as S from './style'; + +import { GoBackIcon } from '@/assets'; + +interface Props { + name: string; + generation: number; +} + +const ChattingHeader: React.FC = ({ name, generation }) => { + const { push } = useRouter(); + + // 어디로 이동해야 할지 정해지지 않아 /로 이동하게 해두었습니다! + const handleGoBackClick = () => push('/'); + + return ( + + + + + + {generation}기 {name} + + + ); +}; + +export default ChattingHeader; diff --git a/src/components/ChattingHeader/style.ts b/src/components/ChattingHeader/style.ts new file mode 100644 index 00000000..c481c9d6 --- /dev/null +++ b/src/components/ChattingHeader/style.ts @@ -0,0 +1,24 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + position: relative; + width: 100%; + padding: 1rem 1.25rem; + display: flex; + align-items: center; + justify-content: center; +`; + +export const IconBox = styled.div` + margin: 0.25rem 0.4375rem; + display: flex; + align-items: center; + cursor: pointer; + position: absolute; + left: 1.69rem; +`; + +export const OpponentInfo = styled.div` + ${({ theme }) => theme.typo.subtitle}; + color: ${({ theme }) => theme.color.grey[500]}; +`; diff --git a/src/components/ChattingListCard/index.stories.tsx b/src/components/ChattingListCard/index.stories.tsx new file mode 100644 index 00000000..5b21786a --- /dev/null +++ b/src/components/ChattingListCard/index.stories.tsx @@ -0,0 +1,34 @@ +import type { OpponentInfo } from '@/types/opponentInfo'; + +import ChattingListCard from '.'; + +import type { Meta, StoryObj } from '@storybook/react'; + +const opponent: OpponentInfo = { + id: 1, + name: '방가온', + generation: 7, +}; + +const meta: Meta = { + component: ChattingListCard, + args: { + opponent, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + isNewMessage: false, + }, +}; + +export const isNewMessage: Story = { + args: { + isNewMessage: true, + }, +}; diff --git a/src/components/ChattingListCard/index.tsx b/src/components/ChattingListCard/index.tsx new file mode 100644 index 00000000..5146aff0 --- /dev/null +++ b/src/components/ChattingListCard/index.tsx @@ -0,0 +1,33 @@ +'use client'; + +import React from 'react'; + +import * as S from './style'; + +import { PersonImg4 } from '@/assets'; +import type { OpponentInfo } from '@/types'; + +interface Props { + opponent: OpponentInfo; + isNewMessage: boolean; +} + +const ChattingListCard: React.FC = ({ opponent, isNewMessage }) => ( + + + + + + + + + {opponent.generation}기 {opponent.name} + + 1시간 전 채팅 + + + {isNewMessage && } + +); + +export default ChattingListCard; diff --git a/src/components/ChattingListCard/style.ts b/src/components/ChattingListCard/style.ts new file mode 100644 index 00000000..0dc436bc --- /dev/null +++ b/src/components/ChattingListCard/style.ts @@ -0,0 +1,57 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + padding: 0.75rem 1rem; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; +`; + +export const OpponentProfile = styled.div` + display: flex; + column-gap: 1rem; +`; + +export const ProfileImg = styled.div` + background-color: ${({ theme }) => theme.color.grey[50]}; + border-radius: 3.125rem; + overflow: hidden; + width: 2.25rem; + height: 2.25rem; + + & > svg { + width: 2.1875rem; + height: 2rem; + position: relative; + top: 0.44rem; + left: 0.13rem; + } +`; + +export const ProfileBox = styled.div` + display: flex; + flex-direction: column; + row-gap: 0.25rem; +`; + +export const ProfileInfo = styled.p` + ${({ theme }) => theme.typo.body1}; + color: ${({ theme }) => theme.color.grey[900]}; +`; + +export const ChattingTime = styled.p` + ${({ theme }) => theme.typo.caption}; + color: ${({ theme }) => theme.color.grey[500]}; +`; + +export const SpaceBlock = styled.div` + width: 0.5rem; +`; + +export const BlueCircleIcon = styled.div` + width: 0.5rem; + height: 0.5rem; + border-radius: 50%; + background-color: ${({ theme }) => theme.color.skyBlue[400]}; +`; diff --git a/src/components/CommunityCard/style.ts b/src/components/CommunityCard/style.ts index 4de76447..e8b12398 100644 --- a/src/components/CommunityCard/style.ts +++ b/src/components/CommunityCard/style.ts @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; export const CardWrapper = styled.div` - padding: 0.75rem 1rem; + padding: 0 1rem; display: flex; flex-direction: column; gap: 0.37rem; diff --git a/src/components/FormItem/Select/index.tsx b/src/components/FormItem/Select/index.tsx index 2e511d03..52d91d19 100644 --- a/src/components/FormItem/Select/index.tsx +++ b/src/components/FormItem/Select/index.tsx @@ -3,7 +3,6 @@ import { forwardRef } from 'react'; import { FormItemWrapper, Select } from '@/components'; -import { useForwardRef } from '@/hooks'; interface Props extends React.SelectHTMLAttributes { selectTitle: string; @@ -14,24 +13,20 @@ interface Props extends React.SelectHTMLAttributes { } const SelectFormItem = forwardRef( - ({ selectTitle, errorMessage, options, required, ...attributes }, ref) => { - const selectRef = useForwardRef(ref); - - return ( - ( + + - - ); - } + ref={ref} + {...attributes} + /> + + ) ); SelectFormItem.displayName = 'Input'; diff --git a/src/components/InfoSearch/index.tsx b/src/components/InfoSearch/index.tsx index 781f8546..81660056 100644 --- a/src/components/InfoSearch/index.tsx +++ b/src/components/InfoSearch/index.tsx @@ -14,7 +14,7 @@ import * as S from './style'; import { TempMentorCard, SearchNotFound } from '@/components'; import { useGetSearchTempMentor } from '@/hooks'; import { tempMentorSearchFormSchema } from '@/schemas'; -import type { TempMentorSearchFormType } from '@/types/form/tempMentorSearchForm'; +import type { TempMentorSearchFormType } from '@/types'; const InfoSearch: React.FC = () => { const [inputValue, setInputValue] = useState(''); diff --git a/src/components/MessageCard/index.stories.tsx b/src/components/MessageCard/index.stories.tsx new file mode 100644 index 00000000..63d6e6b8 --- /dev/null +++ b/src/components/MessageCard/index.stories.tsx @@ -0,0 +1,32 @@ +import MessageCard from '.'; + +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + component: MessageCard, + parameters: { + layout: 'padded', + }, + args: { + children: '안녕하세요', + isMine: true, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: '안녕하세요', + isMine: true, + }, +}; + +export const isMine: Story = { + args: { + children: '안녕하세요', + isMine: false, + }, +}; diff --git a/src/components/MessageCard/index.tsx b/src/components/MessageCard/index.tsx new file mode 100644 index 00000000..baa1ce49 --- /dev/null +++ b/src/components/MessageCard/index.tsx @@ -0,0 +1,26 @@ +'use client'; + +import React from 'react'; + +import * as S from './style'; + +interface Props { + children: string; + isMine: boolean; +} + +const MessageCard: React.FC = ({ children, isMine }) => ( + <> + {isMine ? ( + + {children} + + ) : ( + + {children} + + )} + +); + +export default MessageCard; diff --git a/src/components/MessageCard/style.ts b/src/components/MessageCard/style.ts new file mode 100644 index 00000000..73c3cf70 --- /dev/null +++ b/src/components/MessageCard/style.ts @@ -0,0 +1,21 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + ${({ theme }) => theme.typo.body1}; + padding: 0.5rem 1.25rem; + display: inline-block; +`; + +export const MineContainer = styled(Container)` + border-radius: 1.25rem 1.25rem 0rem 1.25rem; + color: ${({ theme }) => theme.color.white}; + background-color: ${({ theme }) => theme.color.skyBlue[400]}; +`; + +export const OpponentContainer = styled(Container)` + border-radius: 0rem 1.25rem 1.25rem 1.25rem; + color: ${({ theme }) => theme.color.grey[800]}; + background-color: ${({ theme }) => theme.color.grey[100]}; +`; + +export const Content = styled.p``; diff --git a/src/components/PrivacyCard/index.stories.tsx b/src/components/PrivacyCard/index.stories.tsx new file mode 100644 index 00000000..d310bbd9 --- /dev/null +++ b/src/components/PrivacyCard/index.stories.tsx @@ -0,0 +1,32 @@ +import PrivacyCard from '.'; + +import type { Meta, StoryObj } from '@storybook/react'; + +const meta: Meta = { + component: PrivacyCard, + parameters: { + layout: 'padded', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const PhoneNumber: Story = { + args: { + privacy: { + privacyKey: '전화번호', + privacyValue: '010 9999 9999️', + }, + }, +}; + +export const SNS: Story = { + args: { + privacy: { + privacyKey: 'SNS', + privacyValue: 'https://www.instagram.com/', + }, + }, +}; diff --git a/src/components/PrivacyCard/index.tsx b/src/components/PrivacyCard/index.tsx new file mode 100644 index 00000000..0ea75053 --- /dev/null +++ b/src/components/PrivacyCard/index.tsx @@ -0,0 +1,25 @@ +'use client'; + +import React from 'react'; + +import * as S from './style'; + +interface PrivacyType { + privacyKey: string; + privacyValue: string; +} + +interface Props { + privacy: PrivacyType; +} + +const PrivacyCard: React.FC = ({ privacy }) => ( + + + {privacy.privacyKey} + {privacy.privacyValue} + + +); + +export default PrivacyCard; diff --git a/src/components/PrivacyCard/style.ts b/src/components/PrivacyCard/style.ts new file mode 100644 index 00000000..88248dfa --- /dev/null +++ b/src/components/PrivacyCard/style.ts @@ -0,0 +1,30 @@ +import styled from '@emotion/styled'; + +export const PrivacyCardContainer = styled.div` + max-width: 18.25rem; + padding: 1rem; + border: 0.0625rem solid ${({ theme }) => theme.color.grey[100]}; + border-radius: 0.625rem; +`; + +export const PrivacyInfoBox = styled.div` + display: flex; + flex-direction: column; + row-gap: 0.5rem; +`; + +export const PrivacyKey = styled.p` + ${({ theme }) => theme.typo.caption}; + color: ${({ theme }) => theme.color.grey[900]}; +`; + +export const PrivacyValue = styled.p` + ${({ theme }) => theme.typo.body1}; + color: ${({ theme }) => theme.color.black}; +`; + +export const PrivacyPeriod = styled.p<{ isWorking: boolean }>` + ${({ theme }) => theme.typo.body2}; + color: ${({ theme, isWorking }) => + isWorking ? theme.color.skyBlue[400] : theme.color.grey[500]}; +`; diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index ada2366b..8a9188f8 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -25,8 +25,6 @@ const Profile: React.FC = ({ // TODO : server side 와 마크업을 일치시키기 위한 로직 변경 필요. const randomValue = Math.floor(Math.random() * 5); //0부터 4까지 중의 랜덤값 생성 - // const handleClick = () => {}; - return ( diff --git a/src/components/Select/index.tsx b/src/components/Select/index.tsx index 9f2e4244..be237f9d 100644 --- a/src/components/Select/index.tsx +++ b/src/components/Select/index.tsx @@ -1,12 +1,9 @@ 'use client'; -import type { ChangeEvent } from 'react'; -import { forwardRef, useState } from 'react'; +import { forwardRef } from 'react'; import * as S from './style'; -import { useForwardRef } from '@/hooks'; - interface Props extends React.InputHTMLAttributes { errorMessage?: string | null; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -18,35 +15,24 @@ interface Props extends React.InputHTMLAttributes { * @param options - options 배열 */ const Select = forwardRef( - ({ errorMessage, options, defaultValue, onChange, ...attributes }, ref) => { - const [isDefault, setIsDefault] = useState(true); - const selectRef = useForwardRef(ref); - - const handleChange = (e: ChangeEvent) => { - setIsDefault(e.target.value === defaultValue); - onChange && onChange(e); - }; - - return ( - - + ) ); Select.displayName = 'Select'; diff --git a/src/components/Select/style.ts b/src/components/Select/style.ts index f682fb42..d64a5fc4 100644 --- a/src/components/Select/style.ts +++ b/src/components/Select/style.ts @@ -19,13 +19,10 @@ export const CustomSelect = styled.select<{ :disabled { background-color: ${({ theme }) => theme.color.grey[50]}; + color: ${({ theme }) => theme.color.grey[200]}; cursor: default; } - ::placeholder { - color: ${({ theme }) => theme.color.grey[400]}; - } - :focus { outline: none; border: 0.0625rem solid diff --git a/src/components/TextArea/index.stories.tsx b/src/components/TextArea/index.stories.tsx index 2e66146f..5333b890 100644 --- a/src/components/TextArea/index.stories.tsx +++ b/src/components/TextArea/index.stories.tsx @@ -10,4 +10,14 @@ export default meta; type Story = StoryObj; -export const Primary: Story = {}; +export const Gwangya: Story = { + args: { + textAreaType: 'gwangya', + }, +}; + +export const Chatting: Story = { + args: { + textAreaType: 'chatting', + }, +}; diff --git a/src/components/TextArea/index.tsx b/src/components/TextArea/index.tsx index a2c80be6..1a2b159f 100644 --- a/src/components/TextArea/index.tsx +++ b/src/components/TextArea/index.tsx @@ -3,33 +3,38 @@ import { useState, useRef, useEffect } from 'react'; import type { ChangeEvent } from 'react'; -import { toast } from 'react-toastify'; - import * as S from './style'; -import { UploadIcon } from '@/assets'; -import { useAutosizeTextArea, usePostGwangyaContent } from '@/hooks'; +import { SendIcon, UploadIcon } from '@/assets'; +import { useAutoResizeTextArea } from '@/hooks'; const MAX_LENGTH = 200; -const TextArea = () => { +interface Props { + textAreaType: 'gwangya' | 'chatting'; + onClick: (content: string) => void; + disabled: boolean; +} + +const TextArea: React.FC = ({ textAreaType, onClick, disabled }) => { + const textAreaElements = { + gwangya: { + placeholder: + '비방 및 성적 발언, 욕설 등이 포함된 글은 삭제 조치를 받을 수 있습니다.', + icon: , + }, + chatting: { + placeholder: '메시지 보내기', + icon: , + }, + } as const; + const [inputValue, setInputValue] = useState(''); const textAreaRef = useRef(null); const [isFocused, setIsFocused] = useState(false); const [isMultiLine, setIsMultiLine] = useState(false); - const { - mutate: mutateUploadContent, - isPending, - isSuccess, - } = usePostGwangyaContent({ - onSuccess: () => { - document.cookie = 'isSuccess=true; max-age=5'; - window.location.reload(); - }, - }); - - useAutosizeTextArea(textAreaRef.current, inputValue, setIsMultiLine); + useAutoResizeTextArea(textAreaRef.current, inputValue, setIsMultiLine); // textArea의 focus를 컨트롤합니다. -> focus 시 border 변경. useEffect(() => { @@ -51,12 +56,6 @@ const TextArea = () => { }; }, []); - const handleSubmit = () => { - if (inputValue.replaceAll('\n', '').replaceAll('\u0020', '').length !== 0) - mutateUploadContent(inputValue); - else toast.error('게시물 내용을 입력해주세요.'); - }; - const handleInputChange = (e: ChangeEvent) => { const inputValue = e.target.value.slice(0, MAX_LENGTH); @@ -66,7 +65,7 @@ const TextArea = () => { return ( { /> {inputValue.length > 0 && ( - {isMultiLine && ( + {isMultiLine && textAreaType === 'gwangya' && ( {MAX_LENGTH - inputValue.length} )} onClick(inputValue)} + disabled={disabled} > - + {textAreaElements[textAreaType].icon} )} diff --git a/src/components/index.ts b/src/components/index.ts index e09dc583..7af19964 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -3,6 +3,7 @@ export * from './FormItem'; export * from './Modal'; export { default as CareerCard } from './CareerCard'; export { default as CareerRegistrationBox } from './CareerRegistrationBox'; +export { default as ChattingListCard } from './ChattingListCard'; export { default as CommunityCard } from './CommunityCard'; export { default as DropDown } from './DropDown'; export { default as FilterButton } from './Buttons/Filter'; @@ -13,6 +14,7 @@ export { default as MainPage } from './MainPage'; export { default as MentorCard } from './MentorCard'; export { default as MentorList } from './MentorList'; export { default as NavigationEvents } from './NavigationEvents'; +export { default as PrivacyCard } from './PrivacyCard'; export { default as Profile } from './Profile'; export { default as RandomMentorImg } from './MentorCard/RandomMentorImg'; export { default as SearchBar } from './SearchBar'; diff --git a/src/constants/generation.ts b/src/constants/generation.ts deleted file mode 100644 index 0e47abca..00000000 --- a/src/constants/generation.ts +++ /dev/null @@ -1,3 +0,0 @@ -const GENERATION_ARRAY = [1, 2, 3, 4, 5] as const; - -export default GENERATION_ARRAY; diff --git a/src/constants/index.ts b/src/constants/index.ts index 67ad763d..eefcffe0 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,4 +1,5 @@ -export { default as GENERATION_ARRAY } from './generation'; +export { default as MENTEE_GENERATION_ARRAY } from './menteeGeneration'; +export { default as MENTOR_GENERATION_ARRAY } from './mentorGeneration'; export { default as MONTH_ARRAY } from './month'; export { default as POSITION_ARRAY } from './position'; export { default as PRIVACY_POLICY_URL } from './privacyPolicyURL'; diff --git a/src/constants/menteeGeneration.ts b/src/constants/menteeGeneration.ts new file mode 100644 index 00000000..1e864914 --- /dev/null +++ b/src/constants/menteeGeneration.ts @@ -0,0 +1,3 @@ +const MENTEE_GENERATION_ARRAY = [1, 2, 3, 4, 5, 6, 7] as const; + +export default MENTEE_GENERATION_ARRAY; diff --git a/src/constants/mentorGeneration.ts b/src/constants/mentorGeneration.ts new file mode 100644 index 00000000..d36bd196 --- /dev/null +++ b/src/constants/mentorGeneration.ts @@ -0,0 +1,3 @@ +const MENTOR_GENERATION_ARRAY = [1, 2, 3, 4, 5] as const; + +export default MENTOR_GENERATION_ARRAY; diff --git a/src/hooks/api/mentee/index.ts b/src/hooks/api/mentee/index.ts index 5998e2e2..a794e5ee 100644 --- a/src/hooks/api/mentee/index.ts +++ b/src/hooks/api/mentee/index.ts @@ -1 +1,2 @@ -export * from './usePostMenteeRole'; +export * from './usePatchMenteeAuthority'; +export * from './usePostMenteeRegister'; diff --git a/src/hooks/api/mentee/usePatchMenteeAuthority.ts b/src/hooks/api/mentee/usePatchMenteeAuthority.ts new file mode 100644 index 00000000..18b18734 --- /dev/null +++ b/src/hooks/api/mentee/usePatchMenteeAuthority.ts @@ -0,0 +1,12 @@ +import { useMutation } from '@tanstack/react-query'; + +import { menteeQueryKeys, menteeUrl, patch } from '@/libs'; + +import type { UseMutationOptions } from '@tanstack/react-query'; + +export const usePatchMenteeAuthority = (options?: UseMutationOptions) => + useMutation({ + mutationKey: menteeQueryKeys.patchMenteeAuthority(), + mutationFn: () => patch(menteeUrl.patchMenteeAuthority()), + ...options, + }); diff --git a/src/hooks/api/mentee/usePostMenteeRegister.ts b/src/hooks/api/mentee/usePostMenteeRegister.ts new file mode 100644 index 00000000..f2b0f3bf --- /dev/null +++ b/src/hooks/api/mentee/usePostMenteeRegister.ts @@ -0,0 +1,17 @@ +import { useMutation } from '@tanstack/react-query'; + +import { menteeQueryKeys, menteeUrl, post } from '@/libs'; +import type { MenteeType } from '@/types/mentee'; + +import type { UseMutationOptions } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +export const usePostMenteeRegister = ( + options?: UseMutationOptions +) => + useMutation({ + mutationKey: menteeQueryKeys.postMenteeRegister(), + mutationFn: (menteeInfo: MenteeType) => + post(menteeUrl.postMenteeRegister(), menteeInfo), + ...options, + }); diff --git a/src/hooks/api/mentee/usePostMenteeRole.ts b/src/hooks/api/mentee/usePostMenteeRole.ts deleted file mode 100644 index baf39ba4..00000000 --- a/src/hooks/api/mentee/usePostMenteeRole.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { useMutation } from '@tanstack/react-query'; - -import { menteeQueryKeys, menteeUrl, post } from '@/libs'; - -import type { UseMutationOptions } from '@tanstack/react-query'; - -export const usePostMenteeRole = (options?: UseMutationOptions) => - useMutation({ - mutationKey: menteeQueryKeys.postMenteeRole(), - mutationFn: () => post(menteeUrl.postMenteeRole()), - ...options, - }); diff --git a/src/hooks/api/mentor/index.ts b/src/hooks/api/mentor/index.ts index 129d69e8..9a089834 100644 --- a/src/hooks/api/mentor/index.ts +++ b/src/hooks/api/mentor/index.ts @@ -2,3 +2,4 @@ export * from './useDeleteMyMentorData'; export * from './useGetMentorList'; export * from './useGetMyInfo'; export * from './usePostMentorRegister'; +export * from './usePutMentorUpdate'; diff --git a/src/hooks/api/mentor/usePutMentorUpdate.ts b/src/hooks/api/mentor/usePutMentorUpdate.ts new file mode 100644 index 00000000..d3bbe953 --- /dev/null +++ b/src/hooks/api/mentor/usePutMentorUpdate.ts @@ -0,0 +1,17 @@ +import { useMutation } from '@tanstack/react-query'; + +import { mentorQueryKeys, mentorUrl, put } from '@/libs'; +import type { MentorType } from '@/types'; + +import type { UseMutationOptions } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +export const usePutMentorUpdate = ( + options?: UseMutationOptions +) => + useMutation({ + mutationKey: mentorQueryKeys.putMentorUpdate(), + mutationFn: (mentorInfo: MentorType) => + put(mentorUrl.putMentorUpdate(), mentorInfo), + ...options, + }); diff --git a/src/hooks/index.ts b/src/hooks/index.ts index bd952ed9..69dd66ca 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,4 +1,4 @@ export * from './api'; -export * from './useAutoSizeTextArea'; +export * from './useAutoResizeTextArea'; export * from './useForwardRef'; export * from './useGetRem'; diff --git a/src/hooks/useAutoSizeTextArea.ts b/src/hooks/useAutoResizeTextArea.ts similarity index 92% rename from src/hooks/useAutoSizeTextArea.ts rename to src/hooks/useAutoResizeTextArea.ts index dbfd6fb4..f31a9e18 100644 --- a/src/hooks/useAutoSizeTextArea.ts +++ b/src/hooks/useAutoResizeTextArea.ts @@ -1,7 +1,7 @@ import type { Dispatch, SetStateAction } from 'react'; import { useEffect } from 'react'; -export const useAutosizeTextArea = ( +export const useAutoResizeTextArea = ( textAreaRef: HTMLTextAreaElement | null, value: string, setIsMultiLine: Dispatch> diff --git a/src/libs/api/http.ts b/src/libs/api/http.ts index 64547ca3..1ce5ad79 100644 --- a/src/libs/api/http.ts +++ b/src/libs/api/http.ts @@ -13,3 +13,6 @@ export const patch = async ( export const post = async (...args: Parameters) => await axiosInstance.post(...args); + +export const put = async (...args: Parameters) => + await axiosInstance.put(...args); diff --git a/src/libs/api/queryKeys.ts b/src/libs/api/queryKeys.ts index d0e20312..1746ba1b 100644 --- a/src/libs/api/queryKeys.ts +++ b/src/libs/api/queryKeys.ts @@ -8,11 +8,13 @@ export const gwangyaQueryKeys = { }; export const menteeQueryKeys = { - postMenteeRole: () => ['mentee'], + postMenteeRegister: () => ['mentee', 'register'], + patchMenteeAuthority: () => ['mentee', 'authority'], } as const; export const mentorQueryKeys = { postMentorRegister: () => ['mentor'], + putMentorUpdate: () => ['mentor', 'update'], getMentorList: () => ['mentor', 'list'], deleteMyMentorData: () => ['mentor', 'my'], getMyInfo: () => ['mentor', 'my', 'info'], diff --git a/src/libs/api/requestUrlController.ts b/src/libs/api/requestUrlController.ts index a6e41e2c..286d3a4f 100644 --- a/src/libs/api/requestUrlController.ts +++ b/src/libs/api/requestUrlController.ts @@ -16,12 +16,14 @@ export const gwangyaUrl = { }; export const menteeUrl = { - postMenteeRole: () => '/mentee', + postMenteeRegister: () => '/mentee', + patchMenteeAuthority: () => '/mentee/update', }; export const mentorUrl = { postMentorRegister: () => '/mentor', getMentorList: () => '/mentor', + putMentorUpdate: () => '/mentor/my', deleteMyMentorData: () => '/mentor/my', getMyInfo: () => '/mentor/my', }; diff --git a/src/pageContainer/gwangya/index.tsx b/src/pageContainer/gwangya/index.tsx index ffa7c672..f6c5c93a 100644 --- a/src/pageContainer/gwangya/index.tsx +++ b/src/pageContainer/gwangya/index.tsx @@ -7,7 +7,7 @@ import { toast } from 'react-toastify'; import * as S from './style'; import { Header, CommunityCard, TextArea } from '@/components'; -import { useGetGwangyaPostList } from '@/hooks'; +import { useGetGwangyaPostList, usePostGwangyaContent } from '@/hooks'; import type { GwangyaPostType } from '@/types'; import { isExistCookie } from '@/utils'; @@ -71,6 +71,23 @@ const Gwangya: React.FC = ({ initialData }) => { return () => observer.disconnect(); }, [handleObserver]); + const { + mutate: mutateUploadContent, + isPending, + isSuccess, + } = usePostGwangyaContent({ + onSuccess: () => { + document.cookie = 'isSuccess=true; max-age=5'; + window.location.reload(); + }, + }); + + const uploadContent = (inputValue: string) => { + if (inputValue.replaceAll('\n', '').replaceAll('\u0020', '').length !== 0) + mutateUploadContent(inputValue); + else toast.error('게시물 내용을 입력해주세요.'); + }; + return ( <>
@@ -96,7 +113,11 @@ const Gwangya: React.FC = ({ initialData }) => { )) )} -