diff --git a/src/common/asset/font/Pretendard-Medium.woff2 b/src/common/asset/font/Pretendard-Medium.woff2 new file mode 100644 index 0000000..f8c743d Binary files /dev/null and b/src/common/asset/font/Pretendard-Medium.woff2 differ diff --git a/src/common/asset/image/home/check_icon.svg b/src/common/asset/image/home/check_icon.svg new file mode 100644 index 0000000..da2d8ae --- /dev/null +++ b/src/common/asset/image/home/check_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/common/asset/image/home/user_default_img.svg b/src/common/asset/image/home/user_default_img.svg new file mode 100644 index 0000000..eef8f07 --- /dev/null +++ b/src/common/asset/image/home/user_default_img.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/common/style/style.d.ts b/src/common/style/style.d.ts index ac3c624..e15bb36 100644 --- a/src/common/style/style.d.ts +++ b/src/common/style/style.d.ts @@ -37,7 +37,7 @@ declare module 'styled-components' { gradients: { pinktoyellow: string; yellowtopink: string; - } + }; fonts: { display_large: SerializedStyles; @@ -49,7 +49,10 @@ declare module 'styled-components' { body_large: SerializedStyles; body_medium: SerializedStyles; body_small: SerializedStyles; - chatting_medium: SerializedStyles; + chat_medium: SerializedStyles; + label_small: SerializedStyles; + title_extrasmall: SerializedStyles; + caption: SerializedStyles; }; } } diff --git a/src/common/style/theme.ts b/src/common/style/theme.ts index f96ac7c..e9bc486 100644 --- a/src/common/style/theme.ts +++ b/src/common/style/theme.ts @@ -34,7 +34,7 @@ const colors = { const gradients = { pinktoyellow: 'linear-gradient(to right, #FDD5F2, #FBE7CE 70%)', yellowtopink: 'linear-gradient(to right, #FBE7CE 50%, #FDD5F2)', -} +}; const fonts = { display_large: css` @@ -91,12 +91,30 @@ const fonts = { font-weight: 400; line-height: 16px; `, - chatting_medium: css` + chat_medium: css` font-family: 'Pretendard'; font-size: 1.4rem; font-weight: 500; line-height: 16px; `, + label_small: css` + font-family: 'Pretendard'; + font-size: 1rem; + font-weight: 500; + line-height: 12px; + `, + title_extrasmall: css` + font-family: 'Pretendard'; + font-size: 1.2rem; + font-weight: 700; + line-height: 14px; + `, + caption: css` + font-family: 'Pretendard'; + font-size: 1.1rem; + font-weight: 400; + line-height: 20px; + `, }; const theme: DefaultTheme = { colors, gradients, fonts }; diff --git a/src/page/main/chat/chatting/ChattingPage.tsx b/src/page/main/chat/chatting/ChattingPage.tsx index 03bbddd..acbd2c7 100644 --- a/src/page/main/chat/chatting/ChattingPage.tsx +++ b/src/page/main/chat/chatting/ChattingPage.tsx @@ -8,7 +8,6 @@ import Chatting from './component/Chatting'; import ChattingMessageInput from './component/ChattingMessageInput'; import CallDescription from '@image/chatting/CallDescription.svg?react'; import CallButton from '@image/chatting/call-button.svg?react'; -import { getChattingMessage } from '@/shared/api/chatting'; import { getUserInfo } from '@/shared/api/user'; interface MessageData { @@ -30,18 +29,17 @@ const ChattingPage = () => { try { const response = await getUserInfo(); userId = response.data.id; - console.log('userId', response); - console.log('제발', userId); } catch (error) { console.log(error); } }; - handleUserInfo(); - const socketRef = useRef(null); + const iRunOnlyOnce = () => { + handleUserInfo(); + }; + useEffect(iRunOnlyOnce, []); - // const previousMessages = getChattingMessage({ id: '2' }); - // console.log(previousMessages); + const socketRef = useRef(null); // Socket 연결 useEffect(() => { @@ -53,14 +51,12 @@ const ChattingPage = () => { // 메시지 수신 처리 socket.on('message', (data) => { - console.log('daaaa', data); const isUserMessage = data.senderId === userId; - console.log('asdfadfadfadsfadsf', data.senderId, isUserMessage); - console.log(data); + const nowTime = new Date(); const formattedMessage: MessageData = { text: data.content, sender: isUserMessage ? 'user' : 'other', - time: new Date().toLocaleTimeString(), + time: formatTime(nowTime), date: new Date().toLocaleDateString(), }; @@ -88,8 +84,6 @@ const ChattingPage = () => { date: new Date().toLocaleDateString(), }; - // setMessages((prevMessages) => [...prevMessages, newMessage]); - // 서버로 메시지 전송 socketRef.current?.emit('message', { senderId: userId, @@ -124,6 +118,21 @@ const ChattingPage = () => { return () => clearInterval(intervalId); }, [mentoringStartTime]); + function formatTime(date: Date): string { + const options: Intl.DateTimeFormatOptions = { + hour: 'numeric', + minute: 'numeric', + hour12: true, // 12시간 형식 (오전/오후) + }; + + const timeString = date.toLocaleTimeString('ko-KR', options); + + // '오전 10:00' 형식으로 반환 + return timeString.replace(/AM|PM/, (match) => + match === 'AM' ? '오전' : '오후' + ); + } + return ( theme.colors.gray200}; padding: 4px 8px; - ${({ theme }) => theme.fonts.body_small}; + ${({ theme }) => theme.fonts.title_extrasmall}; max-width: fit-content; `; @@ -111,7 +111,7 @@ const MessageWrapper = styled.div<{ $isUser: boolean }>` $isUser ? theme.colors.orange40 : theme.colors.white}; color: ${({ theme, $isUser }) => $isUser ? theme.colors.white : theme.colors.gray700}; - ${({ theme }) => theme.fonts.chatting_medium}; + ${({ theme }) => theme.fonts.chat_medium}; padding: 8px 12px; max-width: 70%; word-break: break-word; @@ -122,7 +122,7 @@ const MessageWrapper = styled.div<{ $isUser: boolean }>` `; const TimeLabel = styled.div<{ $isUser: boolean }>` - ${({ theme }) => theme.fonts.body_small}; + ${({ theme }) => theme.fonts.label_small}; color: ${({ theme }) => theme.colors.gray400}; margin: ${({ $isUser }) => ($isUser ? '0 8px 0 0' : '0 0 0 8px')}; align-self: flex-end; diff --git a/src/page/main/chat/chatting/component/MentoringStart.tsx b/src/page/main/chat/chatting/component/MentoringStart.tsx index 16db8dd..1911cb7 100644 --- a/src/page/main/chat/chatting/component/MentoringStart.tsx +++ b/src/page/main/chat/chatting/component/MentoringStart.tsx @@ -23,7 +23,7 @@ const St = { border-radius: 16px; border: none; padding: 18px 16px; - margin: 128px 20px 20px 20px; + margin: 128px 20px 0px 20px; display: flex; align-items: center; height: 66px; diff --git a/src/page/main/component/TabBar.tsx b/src/page/main/component/TabBar.tsx index d3ab310..e5649fc 100644 --- a/src/page/main/component/TabBar.tsx +++ b/src/page/main/component/TabBar.tsx @@ -38,7 +38,7 @@ const Tab = ({ const TabBar = () => { const navigate = useNavigate(); - const [selectedTab, setSelectedTab] = useState(0); + const [selectedTab, setSelectedTab] = useState(1); const tabs = [ { diff --git a/src/page/main/home/Home.tsx b/src/page/main/home/Home.tsx index bf2c3be..8ac25f0 100644 --- a/src/page/main/home/Home.tsx +++ b/src/page/main/home/Home.tsx @@ -1,21 +1,78 @@ +import { useState, useEffect } from 'react'; import styled from 'styled-components'; import Navigation from '@/page/component/navi/Navigation'; -import bannerImg from '@image/home/banner_mentor.png'; +import bannerMentorImg from '@image/home/banner_mentor.png'; +import bannerMenteeImg from '@image/home/banner_mentee.png'; import mentoringProcessImg from '@image/home/mentoring-explain.png'; +import UserProfile from '@/page/main/home/component/UserProfile'; +import { getMentors } from '@/shared/api/home'; +import { getUserInfo } from '@/shared/api/user'; + +interface UserList { + name: string; + keyword: string; +} const Home = () => { + const [userList, setUserList] = useState([]); + const [isMentor, setIsMentor] = useState(true); + const [profileText, setProfileText] = useState( + '멘토링 신청을 할 수 있는 멘토들이에요' + ); + + const handleHome = async () => { + try { + const response = await getMentors(); + const user = response.data.map((mentor) => ({ + name: mentor.name, + keyword: (mentor.keyword || []).join(', '), + })); + setUserList(user); + } catch (error) { + console.log(error); + } + }; + + const handleUserInfo = async () => { + try { + const response = await getUserInfo(); + setIsMentor(response.data.role === 'MENTOR'); + if (isMentor == true) { + setProfileText('멘토링 신청을 할 수 있는 멘토들이에요'); + } else { + setProfileText('멘토링은 어떻게 진행되나요?'); + } + console.log(isMentor); + } catch (error) { + console.log(error); + } + }; + + const iRunOnlyOnce = () => { + handleHome(); + handleUserInfo(); + }; + useEffect(iRunOnlyOnce, []); + return ( <> - profile + {isMentor ? ( + profile + ) : ( + profile + )} - - {'멘토링 신청을 할 수 있는 멘토들이에요'} - - + + {profileText} + + {userList.map((data) => ( + + ))} + {'멘토링은 어떻게 진행되나요?'} @@ -23,7 +80,11 @@ const Home = () => { mentoringProcess - {'안녕하세요 안녕 안녕...'} + {`ㆍ멘토 심사가 승인된 멘토만 멘토링을 진행할 수 있어요. +ㆍ멘티는 배우고 싶은 소프트 스킬을 가진 멘토에게 멘토링을 요청할 수 있어요. +ㆍ멘토는 멘티의 프로필을 보고 멘티의 멘토링을 수락하거나 거절할 수 있어요. +ㆍ멘토링 후 요약본이 도착하는 시간은 멘토링 진행 시간에 따라 달라지며, + 일반적으로는 약 4시간 정도 걸려요.`} @@ -40,12 +101,13 @@ const St = { `, BannerWrapper: styled.div` - width: 100%; - max-width: 393px; display: flex; - // width: 393px; + width: 393px; height: 128px; margin-top: 108px; + img { + width: 100%; + } `, ProfileText: styled.div` @@ -57,13 +119,17 @@ const St = { ProfileListWrapper: styled.div` display: flex; + margin: 0px 12px; + overflow-x: auto; /* 가로 스크롤 활성화 */ + overflow-y: hidden; /* 세로 스크롤 제거 */ + white-space: nowrap; /* 줄바꿈 방지 */ `, MentoringProcessText: styled.div` display: flex; ${({ theme }) => theme.fonts.title_medium}; color: ${({ theme }) => theme.colors.gray700}; - margin: 32px 20px; + margin: 32px 20px 0px 20px; `, MentoringProcessWrapper: styled.div` @@ -72,13 +138,17 @@ const St = { height: 88; margin: 16px 20px 0px 20px; justify-content: center; + img { + width: 100%; + } `, MentoringProcessDescription: styled.div` display: flex; - ${({ theme }) => theme.fonts.title_medium}; + ${({ theme }) => theme.fonts.caption}; color: ${({ theme }) => theme.colors.gray500}; margin: 16px 20px; + white-space: break-spaces; `, }; diff --git a/src/page/main/home/component/UserProfile.tsx b/src/page/main/home/component/UserProfile.tsx new file mode 100644 index 0000000..8f361ab --- /dev/null +++ b/src/page/main/home/component/UserProfile.tsx @@ -0,0 +1,63 @@ +import styled from 'styled-components'; + +import CheckIcon from '@image/home/check_icon.svg?react'; +import UserImg from '@image/home/user_default_img.svg?react'; + +interface UserListProps { + name: string; + keyword: string; +} + +const UserProfile = ({ name, keyword }: UserListProps) => { + console.log(name, keyword); + return ( + <> + + + + + + + + {name} + {keyword} + + + ); +}; + +const St = { + UserProfileWrapper: styled.div` + background-color: ${({ theme }) => theme.colors.white}; + border-radius: 16px; + border: 1px solid ${({ theme }) => theme.colors.gray200}; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + min-width: 128px; + height: 160px; + margin: 0px 4px; + `, + + CheckIcon: styled.div` + margin-top: 15px; + `, + + UserIcon: styled.div` + margin-top: 4px; + `, + + UserNameText: styled.div` + ${({ theme }) => theme.fonts.title_medium}; + color: ${({ theme }) => theme.colors.gray700}; + margin-top: 4px; + `, + + UserKeywordText: styled.div` + ${({ theme }) => theme.fonts.body_medium}; + color: ${({ theme }) => theme.colors.gray700}; + `, +}; + +export default UserProfile; diff --git a/src/shared/api/home/index.ts b/src/shared/api/home/index.ts new file mode 100644 index 0000000..a72b4a9 --- /dev/null +++ b/src/shared/api/home/index.ts @@ -0,0 +1,8 @@ +import { GetMentorsResponse } from '@shared/api/home/type'; + +import { axiosInstance } from '@shared/api/instance'; + +export const getMentors = async () => { + const response = await axiosInstance.get(`/mentors`); + return response.data; +}; diff --git a/src/shared/api/home/type.ts b/src/shared/api/home/type.ts new file mode 100644 index 0000000..877ed89 --- /dev/null +++ b/src/shared/api/home/type.ts @@ -0,0 +1,11 @@ +export interface GetMentorsResponse { + data: Mentor[]; +} + +export interface Mentor { + mentorId: number; + auditStatus: string; + profileImgUrl: string; + name: string; + keyword: string[]; +}