Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 64 additions & 39 deletions src/APP/components/Header/Header.header.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from "react";
import * as itemS from "./Styled/Header.header.styles";
import request from '../../Api/request';
import ProfileModal from './Header.profile.modal';
import request from "../../Api/request";
import ProfileModal from "./Header.profile.modal";

export default function Header({ dark }) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [userName, setUserName] = useState('');
const [profileUrl, setProfileUrl] = useState('');
const [userName, setUserName] = useState("");
const [profileUrl, setProfileUrl] = useState("");
const [showProfileModal, setShowProfileModal] = useState(false);
const [activeMenu, setActiveMenu] = useState('');
const [activeMenu, setActiveMenu] = useState("");

// Refs for detecting clicks outside
const modalRef = useRef(null);
const modalRef = useRef(null);
const studyMenuRef = useRef(null);
const codingMenuRef = useRef(null);

// Fetch login status on component mount
const checkLoginStatus = async () => {
try {
const response = await request.get('/member/info');
console.log("로그인 멤버 정보 조회", response);
const response = await request.get("/member/info");
// console.log("로그인 멤버 정보 조회", response);
if (response["isSuccess"]) {
setUserName(response.result.name);
setProfileUrl(response.result.profileUrl);
Expand All @@ -30,56 +30,58 @@ export default function Header({ dark }) {
}
};
useEffect(() => {

const accessToken = localStorage.getItem('accessToken');
const accessToken = localStorage.getItem("accessToken");
if (accessToken) {
checkLoginStatus();
}
}, []);

// Toggle Profile Modal
const toggleProfileModal = () => {
setShowProfileModal(prev => !prev);
setActiveMenu('');
setShowProfileModal((prev) => !prev);
setActiveMenu("");
};

// Handle Menu Clicks
const handleMenuClick = (menu) => {
setActiveMenu((prev) => (prev === menu ? '' : menu));
setActiveMenu((prev) => (prev === menu ? "" : menu));
};

// Handle Navigation and Close Menus
const handleNav = () => {
setActiveMenu('');
setActiveMenu("");
};

// Click Outside Handler
useEffect(() => {
const handleClickOutside = (event) => {
// Check if click is inside Profile Modal
const clickedInsideProfile = modalRef.current && modalRef.current.contains(event.target);
const clickedInsideProfile =
modalRef.current && modalRef.current.contains(event.target);

// Check if click is inside any open submenu
let clickedInsideMenu = false;
if (activeMenu === 'study') {
clickedInsideMenu = studyMenuRef.current && studyMenuRef.current.contains(event.target);
} else if (activeMenu === 'coding') {
clickedInsideMenu = codingMenuRef.current && codingMenuRef.current.contains(event.target);
if (activeMenu === "study") {
clickedInsideMenu =
studyMenuRef.current && studyMenuRef.current.contains(event.target);
} else if (activeMenu === "coding") {
clickedInsideMenu =
codingMenuRef.current && codingMenuRef.current.contains(event.target);
}

// If click is outside both Profile Modal and any open submenu, close them
if (!clickedInsideProfile && !clickedInsideMenu) {
setShowProfileModal(false);
setActiveMenu('');
setActiveMenu("");
}
};

// Attach the event listener
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener("mousedown", handleClickOutside);

// Cleanup the event listener on component unmount
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener("mousedown", handleClickOutside);
};
}, [showProfileModal, activeMenu]);

Expand All @@ -88,23 +90,38 @@ export default function Header({ dark }) {
<itemS.InnerContainer $dark={dark}>
<itemS.HeaderWrap>
<itemS.HeaderLeftWrap>
<itemS.StyledLink to="/" style={{ textDecoration: 'none' }}>
<itemS.Rabel src={dark ? '/img/koalalogo_dark.png':'/img/koalalogo.png'} alt='코알라로고' />
<itemS.StyledLink to="/" style={{ textDecoration: "none" }}>
<itemS.Rabel
src={dark ? "/img/koalalogo_dark.png" : "/img/koalalogo.png"}
alt="코알라로고"
/>
</itemS.StyledLink>
</itemS.HeaderLeftWrap>
<itemS.HeaderRightWrap>
<itemS.StyledLink to={isLoggedIn ? "/mystudy" : "/login"}>
<itemS.PageLink>나의 스터디</itemS.PageLink>
</itemS.StyledLink>
<itemS.StyledLink onClick={() => handleMenuClick('study')}>
<itemS.StyledLink onClick={() => handleMenuClick("study")}>
<itemS.PageLink>스터디</itemS.PageLink>
{activeMenu === 'study' && (
{activeMenu === "study" && (
<itemS.SubMenuContaier ref={studyMenuRef}>
<itemS.SubMenu isLoggedIn={isLoggedIn}>
<itemS.StyledLink to={isLoggedIn ? "/apply" : "/login"} onClick={(e) => {e.stopPropagation(); handleNav();}}>
<itemS.StyledLink
to={isLoggedIn ? "/apply" : "/login"}
onClick={(e) => {
e.stopPropagation();
handleNav();
}}
>
<itemS.SubMenuItem>정규 스터디</itemS.SubMenuItem>
</itemS.StyledLink>
<itemS.StyledLink to={isLoggedIn ? "/study" : "/login"} onClick={(e) => {e.stopPropagation(); handleNav();}}>
<itemS.StyledLink
to={isLoggedIn ? "/study" : "/login"}
onClick={(e) => {
e.stopPropagation();
handleNav();
}}
>
<itemS.SubMenuItem>자율 스터디</itemS.SubMenuItem>
</itemS.StyledLink>
</itemS.SubMenu>
Expand All @@ -114,29 +131,37 @@ export default function Header({ dark }) {
<itemS.StyledLink to={"/community"}>
<itemS.PageLink>커뮤니티</itemS.PageLink>
</itemS.StyledLink>
<itemS.StyledLink onClick={() => handleMenuClick('coding')}>
<itemS.StyledLink onClick={() => handleMenuClick("coding")}>
<itemS.PageLink>코딩테스트 분석</itemS.PageLink>
{activeMenu === 'coding' && (
{activeMenu === "coding" && (
<itemS.SubMenuContaier ref={codingMenuRef}>
<itemS.SubMenu isLoggedIn={isLoggedIn}>
<itemS.StyledLink to={isLoggedIn ? "/enterbootlist" : "/login"} onClick={(e) => {e.stopPropagation(); handleNav();}}>
<itemS.SubMenuItem style={{marginBottom:"2.5rem"}}>기업/부트캠프</itemS.SubMenuItem>
<itemS.StyledLink
to={isLoggedIn ? "/enterbootlist" : "/login"}
onClick={(e) => {
e.stopPropagation();
handleNav();
}}
>
<itemS.SubMenuItem style={{ marginBottom: "2.5rem" }}>
기업/부트캠프
</itemS.SubMenuItem>
</itemS.StyledLink>
</itemS.SubMenu>
</itemS.SubMenuContaier>
)}
</itemS.StyledLink>
{isLoggedIn ? (
<div style={{ position: 'relative' }} ref={modalRef}>
<div style={{ position: "relative" }} ref={modalRef}>
<itemS.ProfileBox onClick={toggleProfileModal}>
<itemS.AdminName>안녕하세요, {userName} 님</itemS.AdminName>
<itemS.Arrow src='/img/arrow-bt.svg' alt='화살표' />
<itemS.Arrow src="/img/arrow-bt.svg" alt="화살표" />
</itemS.ProfileBox>
{showProfileModal && (
<ProfileModal
userName={userName}
profileUrl={profileUrl}
setIsLoggedIn={setIsLoggedIn}
<ProfileModal
userName={userName}
profileUrl={profileUrl}
setIsLoggedIn={setIsLoggedIn}
setShowProfileModal={setShowProfileModal}
/>
)}
Expand Down
6 changes: 3 additions & 3 deletions src/APP/user-pages/Langding/Langding.landing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Langding() {
// console.log("스터디 최신 기수 api", response);
setDetailRecentGeneration(response.data.result);
if (response.data["isSuccess"]) {
console.log("api 연동 성공");
// console.log("api 연동 성공");
} else {
console.error("api 연동 실패:", response);
}
Expand All @@ -37,7 +37,7 @@ export default function Langding() {
console.log("최신 기수 스터디 개수 api", response);
setDetailStudyCount(response.data.result);
if (response.data["isSuccess"]) {
console.log("api 연동 성공");
// console.log("api 연동 성공");
} else {
console.error("api 연동 실패:", response);
}
Expand All @@ -48,7 +48,7 @@ export default function Langding() {
const checkLoginStatus = async () => {
try {
const response = await request.get("/member/info");
console.log("로그인 멤버 정보 조회", response);
// console.log("로그인 멤버 정보 조회", response);
if (response["isSuccess"]) {
setIsLoggedIn(true);
localStorage.setItem("memberId", response.result.memberId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import * as ItemS from "./Styled/Mypage.mypage.challenge.rewardprogress.styles";

export default function RewardProgress({
challengeRewardCount,
challengeWinCount,
regularStudyId,
}) {
const navigate = useNavigate();

const handleUseReward = () => {
// id 값이 없는 경우를 대비한 방어 코드
if (!regularStudyId) {
console.error("스터디 ID가 전달되지 않았습니다.");
return;
}

// 로컬 스토리지 키 생성
const storageKey = `activeComponent_${regularStudyId}`;

// 'attendance' 컴포넌트가 보이도록 로컬 스토리지에 값 설정
localStorage.setItem(storageKey, "attendance");

// 페이지 이동
navigate(`/regularstudy/${regularStudyId}`);
};

return (
<ItemS.Container>
<ItemS.TriangleL />
Expand Down Expand Up @@ -57,7 +78,7 @@ export default function RewardProgress({
/> */}
</ItemS.ProgressBarWrapper>

<ItemS.Button>보상 사용하기</ItemS.Button>
<ItemS.Button onClick={handleUseReward}>보상 사용하기</ItemS.Button>
</ItemS.Container>
);
}
4 changes: 3 additions & 1 deletion src/APP/user-pages/Mypage/Mypage.mypage.challenge.table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ export default function ChallengeTable({
logCount,
rewardCount,
winCount,
regularStudyId,
isMemberMatch,
fetchRewardLog,
onChangeLogType,
}) {
// const [count, setCount] = useState(inquiryCount); //TODO - - 임시로 10 넣음
// const [count, setCount] = useState(inquiryCount);
const [challengeRewardCount, setChallengeRewardCount] = useState(rewardCount);
const [challengeWinCount, setChallengeWinCount] = useState(winCount);

Expand Down Expand Up @@ -96,6 +97,7 @@ export default function ChallengeTable({
<RewardProgress
challengeRewardCount={challengeRewardCount}
challengeWinCount={challengeWinCount}
regularStudyId={regularStudyId}
/>
</itemS.TabBox>
</itemS.TabBtnContainer>
Expand Down
27 changes: 21 additions & 6 deletions src/APP/user-pages/Mypage/Mypage.mypage.main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default function MyPage() {
const [logType, setLogType] = useState(""); // "" | "ACQUIRED" | "USED"
const [rewardCount, setRewardCount] = useState(0); // 누적 교환권 수
const [winCount, setWinCount] = useState(0); // 챌린지 win 수
const [regularStudyId, setRegularStudyId] = useState(null); // 참여중인 정규 스터디 id

// 내 스터디, 내가 쓴 글 탭 변경
const [selectedTab, setSelectedTab] = useState("study");
Expand All @@ -40,12 +41,24 @@ export default function MyPage() {
const totalPagesPassStudy = Math.ceil(passStudyList.length / itemsPerPage); // 참여 스터디 총 페이지 수
const totalPagesApplyStudy = Math.ceil(applyStudyList.length / itemsPerPage); // 지원 스터디 총 페이지 수

const fetchInfo = async () => {
try {
const response = await request.get("/member/info");
// console.log("로그인 멤버 정규스터 정보 조회", response);
if (response.isSuccess && response.result.regularStudyId !== null) {
setRegularStudyId(response.result.regularStudyId);
}
} catch (error) {
console.error("로그인 멤버 정보 조회 실패", error);
}
};

const fetchMyInfo = async () => {
try {
const response = await request.get(`/member/${handle}/info`);

if (response.isSuccess) {
console.log("나의 정보 조회 성공", response);
// console.log("나의 정보 조회 성공", response);
setMyInfoData(response.result);
} else {
console.error("나의 정보 조회 실패:", response);
Expand All @@ -60,7 +73,7 @@ export default function MyPage() {
const response = await request.get(`/member/${handle}/study`);

if (response.isSuccess) {
console.log("나의 스터디 조회 성공", response);
// console.log("나의 스터디 조회 성공", response);
setPassStudyList(response.result.passStudyList);
setApplyStudyList(response.result.applyStudyList);
} else {
Expand All @@ -74,7 +87,7 @@ export default function MyPage() {
const fetchBoard = async () => {
try {
const response = await request.get(`/member/${handle}/board`);
console.log("내 게시글 목록 조회 성공", response);
// console.log("내 게시글 목록 조회 성공", response);

if (response.isSuccess) {
setBoards(response.result.boardList);
Expand All @@ -92,7 +105,7 @@ export default function MyPage() {
const fetchinquiry = async () => {
try {
const response = await request.get(`/member/${handle}/inquiry`);
console.log("내 문의하기 목록 조회 성공", response);
// console.log("내 문의하기 목록 조회 성공", response);

if (response.isSuccess) {
setInquiries(response.result.inquiryList);
Expand All @@ -111,7 +124,7 @@ export default function MyPage() {
? `/challenge/reward/log?logType=${type}`
: `/challenge/reward/log`;
const response = await request.get(url);
console.log("보상 로그 조회 성공", response);
// console.log("보상 로그 조회 성공", response);
if (response.isSuccess) {
setRewardLogs(response.result.rewardLogList);
setLogCount(response.result.totalCount);
Expand All @@ -126,7 +139,7 @@ export default function MyPage() {
const fetchRewardStatus = async () => {
try {
const response = await request.get(`/challenge/reward/status`);
console.log("내 챌린지 보상 현황 조회 성공", response);
// console.log("내 챌린지 보상 현황 조회 성공", response);

if (response.isSuccess) {
setRewardCount(response.result.rewardCount);
Expand All @@ -148,6 +161,7 @@ export default function MyPage() {
}, [handle, logType]); // logType이 바뀌면 자동 호출

useEffect(() => {
fetchInfo();
fetchMyInfo();
fetchMyStudy();
fetchBoard();
Expand Down Expand Up @@ -252,6 +266,7 @@ export default function MyPage() {
logCount={logCount}
rewardCount={rewardCount}
winCount={winCount}
regularStudyId={regularStudyId}
isMemberMatch={isMemberMatch}
fetchRewardLog={fetchRewardLog}
onChangeLogType={setLogType}
Expand Down
Loading