Skip to content

Commit

Permalink
Merge pull request #352 from SejongPeer/feature/14
Browse files Browse the repository at this point in the history
feat: [14] 재지원 시 1시간 패널티 alert 처리
  • Loading branch information
AhnRian authored Jul 21, 2024
2 parents 3d680e0 + d306c1b commit adceeda
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 74 deletions.
66 changes: 66 additions & 0 deletions src/pages/study/studyPostDetail/Popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Popup.js
import React from 'react';
import styled from 'styled-components';
import COLORS from '../../../theme';

const Popup = ({ title, message, onClose }) => {
return (
<PopupContainer>
<PopupContent>
<PopupTitle>{title}</PopupTitle>
<PopupMessage>{message}</PopupMessage>
<ConfirmButton onClick={onClose}>확인</ConfirmButton>
</PopupContent>
</PopupContainer>
);
};

export default Popup;

const PopupContainer = styled.div`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
padding: 20px;
background: white;
border: 1px solid #ccc;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
display: flex;
justify-content: center;
flex-direction: row;
`;

const PopupContent = styled.div`
display: flex;
text-align: center;
color: ${COLORS.font1};
flex-direction: column;
`;

const PopupTitle = styled.h2`
font-size: 16px;
font-weight: 600;
margin-bottom: 10px;
`;

const PopupMessage = styled.p`
font-size: 14px;
color: ${COLORS.font2};
line-height: 1.5;
margin-bottom: 20px;
`;

const ConfirmButton = styled.button`
margin-top: 20px;
padding: 10px 20px;
border: none;
border-radius: 5px;
background-color: ${COLORS.main};
color: white;
font-size: 16px;
cursor: pointer;
`;
107 changes: 38 additions & 69 deletions src/pages/study/studyPostDetail/StudyPostDetail.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';

import Popup from './Popup';
import styled from 'styled-components';
import useStore from './useStore';
import COLORS from '../../../theme';
Expand All @@ -8,6 +10,7 @@ import filledHeart from '../../../assets/image/filledHeart.svg';
import {
fetchStudyData,
applyForStudy,
cancelStudyApplication,
toggleScrap,
fetchScrapCount,
} from './api';
Expand All @@ -20,12 +23,14 @@ const StudyListPostDetail = () => {
isApplied,
isScrapped,
scrapCount,
popupTitle,
setPopupVisible,
setPopupMessage,
setStudyData,
setApplied,
setScrapped,
setScrapCount,
setPopupTitle,
} = useStore();

const { studyId } = useParams();
Expand All @@ -38,11 +43,9 @@ const StudyListPostDetail = () => {
const scrapped = localStorage.getItem(`isScrapped_${studyId}`);
setScrapped(scrapped ? JSON.parse(scrapped) : data.data.isScrapped);
const appliedStatus = localStorage.getItem(`isApplied_${studyId}`);
// console.log(data);
if (appliedStatus) {
setApplied(JSON.parse(appliedStatus));
}
// 스크랩 수 조회
const scrapData = await fetchScrapCount(studyId);
setScrapCount(scrapData.data.scrapCount);
} catch (error) {
Expand All @@ -68,16 +71,26 @@ const StudyListPostDetail = () => {

const applyForStudyHandler = async () => {
try {
const response = await applyForStudy(studyId);
if (response.status === 201) {
togglePopup(
'지원 완료! 모집자가 수락 후, 모집인원이 다 차거나 마감일이 되면 메시지로 오픈채팅 링크가 전달됩니다.'
);
setApplied(true);
localStorage.setItem(`isApplied_${studyId}`, true);
// console.log(response);
if (isApplied) {
const response = await cancelStudyApplication(studyId);
if (response.status === 200) {
togglePopup('지원 취소 완료');
setApplied(false);
localStorage.setItem(`isApplied_${studyId}`, false);
} else {
console.error('Failed to cancel study application:', response);
}
} else {
console.error('Failed to apply for study:', response);
const response = await applyForStudy(studyId);
if (response.status === 201) {
togglePopup(
'지원 완료! 모집자가 수락 후, 모집인원이 다 차거나 마감일이 되면 메시지로 오픈채팅 링크가 전달됩니다.'
);
setApplied(true);
localStorage.setItem(`isApplied_${studyId}`, true);
} else {
console.error('Failed to apply for study:', response);
}
}
} catch (error) {
if (error.response && error.response.status === 409) {
Expand All @@ -87,6 +100,10 @@ const StudyListPostDetail = () => {
} else {
console.error('Error applying for study:', error);
}

if (error.response.status === 403) {
togglePopup('1시간 패널티 부과 중입니다!');
}
}
};

Expand Down Expand Up @@ -160,17 +177,17 @@ const StudyListPostDetail = () => {
<ScrapCount>{scrapCount}</ScrapCount>
</ScrapButton>
<ApplyButton onClick={applyForStudyHandler} isApplied={isApplied}>
{isApplied ? '지원완료' : '지원하기(1/4)'}
{isApplied
? '지원취소'
: `지원하기 (${studyData.data.participantCount} / ${studyData.data.totalRecruitmentCount})`}
</ApplyButton>
</CommentContainer>
{isPopupVisible && (
<Popup>
<PopupContent>
<PopupTitle>스터디 지원 완료</PopupTitle>
<PopupMessage>{popupMessage}</PopupMessage>
<ConfirmButton onClick={closePopup}>확인</ConfirmButton>
</PopupContent>
</Popup>
<Popup
title={popupTitle}
message={popupMessage}
onClose={closePopup}
/>
)}
</div>
</Container>
Expand Down Expand Up @@ -219,7 +236,6 @@ const StudyMethod = styled.div`
margin-right: 10px;
`;


const Nickname = styled(Title2)`
font-weight: 400;
color: ${COLORS.font2};
Expand Down Expand Up @@ -345,7 +361,8 @@ const ApplyButton = styled.button`
flex-shrink: 0;
border-radius: 28px;
background: ${props => (props.isApplied ? COLORS.line2 : COLORS.main)};
color: #fff;
color: ${props =>
props.isApplied ? '#111' : '#fff'}; /* 글씨 색상 조건부 변경 */
text-align: center;
font-size: 18px;
font-style: normal;
Expand All @@ -356,51 +373,3 @@ const ApplyButton = styled.button`
cursor: pointer;
border: none;
`;

const Popup = styled.div`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
padding: 20px;
background: white;
border: 1px solid #ccc;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
display: flex;
justify-content: center;
flex-direction: row;
`;

const PopupContent = styled.div`
display: flex;
text-align: center;
color: ${COLORS.font1};
flex-direction: column;
`;

const PopupTitle = styled.div`
font-size: 16px;
font-weight: 600;
margin-bottom: 10px;
`;

const PopupMessage = styled.div`
font-size: 14px;
color: ${COLORS.font2};
line-height: 1.5;
margin-bottom: 20px;
`;

const ConfirmButton = styled.button`
margin-top: 20px;
padding: 10px 20px;
border: none;
border-radius: 5px;
background-color: ${COLORS.main};
color: white;
font-size: 16px;
cursor: pointer;
`;
33 changes: 30 additions & 3 deletions src/pages/study/studyPostDetail/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const fetchStudyData = async studyId => {
const refreshToken = localStorage.getItem('refreshToken');

if (!accessToken || !refreshToken) {
alert('재로그인 해야합니다!');
throw new Error('토큰이 없음!');
}

Expand All @@ -28,6 +29,7 @@ export const applyForStudy = async studyId => {
const refreshToken = localStorage.getItem('refreshToken');

if (!accessToken || !refreshToken) {
alert('재로그인 해야합니다!');
throw new Error('토큰이 없음!');
}

Expand All @@ -42,7 +44,31 @@ export const applyForStudy = async studyId => {
},
}
);
console.log(response.data);
return response;
};

// 스터디 지원 취소
export const cancelStudyApplication = async studyId => {
const accessToken = localStorage.getItem('accessToken');
const refreshToken = localStorage.getItem('refreshToken');

if (!accessToken || !refreshToken) {
alert('재로그인 해야합니다!');
throw new Error('토큰이 없음!');
}

const response = await axios.delete(
`${process.env.REACT_APP_BACK_SERVER}/study/relations/${studyId}`,
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
'Refresh-token': `${refreshToken}`,
},
}
);
console.log(response.data);
return response;
};

Expand All @@ -51,10 +77,9 @@ export const toggleScrap = async (studyId, isScrapped) => {
const accessToken = localStorage.getItem('accessToken');
const refreshToken = localStorage.getItem('refreshToken');
const scrapId = localStorage.getItem(`scrapId_${studyId}`);
// console.log(accessToken);
// console.log(refreshToken);
// console.log(scrapId);

if (!accessToken || !refreshToken) {
alert('재로그인 해야합니다!');
throw new Error('토큰이 없음!');
}

Expand Down Expand Up @@ -99,6 +124,7 @@ export const fetchScrapCount = async studyId => {
const refreshToken = localStorage.getItem('refreshToken');

if (!accessToken || !refreshToken) {
alert('재로그인 해야합니다!');
throw new Error('토큰이 없음!');
}

Expand All @@ -113,5 +139,6 @@ export const fetchScrapCount = async studyId => {
}
);

// console.log(response.data);
return response.data;
};
6 changes: 4 additions & 2 deletions src/pages/study/studyPostDetail/useStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { create } from 'zustand';
const useStore = create(set => ({
isPopupVisible: false,
popupMessage: '',
popupTitle: '',
studyData: null,
isApplied: false,
isScrapped: false,
scrapCount: 0, // 스크랩 수 상태 추가
scrapCount: 0,
setPopupVisible: isVisible => set({ isPopupVisible: isVisible }),
setPopupMessage: message => set({ popupMessage: message }),
setPopupTitle: title => set({ popupTitle: title }),
setStudyData: data => set({ studyData: data }),
setApplied: isApplied => set({ isApplied }),
setScrapped: isScrapped => set({ isScrapped }),
setScrapCount: count => set({ scrapCount: count }), // 스크랩 수 설정 함수 추가
setScrapCount: count => set({ scrapCount: count }),
}));

export default useStore;

0 comments on commit adceeda

Please sign in to comment.