Skip to content

Commit

Permalink
Merge pull request #195 from KNU-HAEDAL/Feat/issue-#194
Browse files Browse the repository at this point in the history
완료한 챌린지 api 호출 기능 수정
  • Loading branch information
Dobbymin authored Oct 15, 2024
2 parents f274365 + a4b4174 commit 7335b71
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 25 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ https://zzansuni-fe-vercel.vercel.app/
사용자들에게 챌린지에 대해 공유 할 수 있으며, 랭킹을 통해 서로 경쟁할 수
있습니다.

### 개발자 소개

| 백엔드 | 백엔드 | 프론트엔드 | 프론트엔드 | 백엔드 |
| :----------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: |
| [<img src="https://github.com/momnpa333.png" width="100px">](https://github.com/momnpa333) | [<img src="https://github.com/kwonssshyeon.png" width="100px">](https://github.com/kwonssshyeon) | [<img src="https://github.com/Dobbymin.png" width="100px">](https://github.com/Dobbymin) | [<img src="https://github.com/joojjang.png" width="100px">](https://github.com/joojjang) | [<img src="https://github.com/bayy1216.png" width="100px">](https://github.com/bayy1216) |
| 권다운 | 권수현 | 김강민 | 김민주 | 손홍석 |

### 개발 동기

기획 단계에서 팀원들과 다양한 아이디어에 대해 생각을 해 보았고, 공통적으로
Expand All @@ -27,3 +34,20 @@ https://zzansuni-fe-vercel.vercel.app/
그 결과 다양한 주제의 챌린지를 진행할 수 있는 '짠순이' 라는 서비스를 기획하게
되었습니다.

## 기술 스택

- Frontend: `React`, `vite`, `typescript`, `@emotion/styled`, `@emotion/react`
- Backend: `Spring`, `JPA`, `MySQL`, `S3`

## 아키텍쳐
![image](https://github.com/user-attachments/assets/e0bfee6d-4de3-448b-ae20-f78936a7074e)


## ERD

![image](https://github.com/user-attachments/assets/8cd2aa03-9bd1-4ee0-a511-451711da40bb)


## CLASS DIAGRAM

![image](https://github.com/user-attachments/assets/60e5ea66-eb87-4f9f-84bd-94eb2e70963e)
27 changes: 27 additions & 0 deletions src/apis/challenge-completes/challenge-completes.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { axiosClient } from '../AxiosClient';
import { ChallengeCompletesResponse } from './challenge-completes.response';
import { useQuery } from '@tanstack/react-query';

export const challengeCompletesPath = () => '/api/user/challenges/completes';

export const ChallengeCompletesQueryKey = [challengeCompletesPath()];

export const getChallengeCompletes = async (
page: number,
size: number
): Promise<ChallengeCompletesResponse> => {
const response = await axiosClient.get(challengeCompletesPath(), {
params: {
page,
size,
},
});
return response.data;
};

export const useGetChallengeCompletes = (page: number, size: number) => {
return useQuery<ChallengeCompletesResponse, Error>({
queryKey: [ChallengeCompletesQueryKey, page, size],
queryFn: () => getChallengeCompletes(page, size),
});
};
18 changes: 18 additions & 0 deletions src/apis/challenge-completes/challenge-completes.response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import ApiResponse from '../ApiResponse';

export type ChallengeData = {
id: number;
challengeGroupId: number;
title: string;
successDate: string;
category: 'HEALTH' | 'ECHO' | 'SHARE' | 'VOLUNTEER';
reviewWritten: boolean;
};

export type ChallengeCompletes = {
totalPage: number;
hasNext: boolean;
data: ChallengeData[];
};

export type ChallengeCompletesResponse = ApiResponse<ChallengeCompletes>;
15 changes: 12 additions & 3 deletions src/components/common/star-rating/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ interface StarRatingProps {
export const StarRating = ({ rating, size = 24, onClick }: StarRatingProps) => {
const [ratingToPercent, setRatingToPercent] = useState<number>(0);

// rating 새로 전달받을 때마다 퍼센테이지 계산
useEffect(() => {
if (rating !== undefined) {
setRatingToPercent((rating / 5) * 100);
}
}, [rating]);

const handleClick = (rating: number) => {
// 별점 클릭 핸들러
const handleClickStar = (rating: number, e: React.MouseEvent) => {
e.preventDefault();
if (onClick) {
onClick(rating + 1); // 클릭한 별점 값 전달 (1부터 시작)
}
Expand All @@ -27,14 +30,20 @@ export const StarRating = ({ rating, size = 24, onClick }: StarRatingProps) => {
<Wrapper size={size}>
<FilledStars ratingToPercent={ratingToPercent}>
{[...Array(5)].map((_, index) => (
<Star key={`fill-${index}`} onClick={() => handleClick(index)}>
<Star
key={`fill-${index}`}
onClick={(e) => handleClickStar(index, e)}
>
</Star>
))}
</FilledStars>
<BaseStars>
{[...Array(5)].map((_, index) => (
<Star key={`base-${index}`} onClick={() => handleClick(index)}>
<Star
key={`base-${index}`}
onClick={(e) => handleClickStar(index, e)}
>
</Star>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const TooltipBox = styled.div<{ direction: string }>`
font-size: 12px;
font-weight: 500;
white-space: nowrap;
z-index: 10;
z-index: 5;
display: flex;
align-items: center;
Expand Down
2 changes: 1 addition & 1 deletion src/components/features/layout/nav-bar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const NavBar = () => {
return (
<Wrapper as='nav'>
{navBarData.map((item) => (
<Tab key={item.title} onClick={() => handleNav(item.path)}>
<Tab as='a' key={item.title} onClick={() => handleNav(item.path)}>
<IconImage src={item.icon} alt={item.title} />
</Tab>
))}
Expand Down
2 changes: 1 addition & 1 deletion src/components/features/layout/top-bar/page-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const PageBarLayout = styled(Box)<{
padding: 0.5rem;
gap: 1rem;
background-color: ${(props) => props.backgroundColor};
z-index: 1;
z-index: 10;
position: sticky;
top: ${({ show }) => (show ? '0' : '-100px')};
transition: top 0.3s;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/challenge-record/records/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ChallengeRecordData,
ChallengeRecordDetailData,
} from '@/apis/challenge-record/challenge.record.response';
import Tooltip from '@/components/common/form/textarea/tooltip';
import Tooltip from '@/components/common/tooltip';
import { formatDate } from '@/utils/formatters';
import { Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
Expand Down
12 changes: 3 additions & 9 deletions src/pages/my-challenge-record/components/list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import styled from '@emotion/styled';
type Props = {
challengeId: number;
challengeTitle: string;
userNickname: string;
profileImageUrl?: string | null;
};

const ListItem = ({ challengeId, challengeTitle, profileImageUrl }: Props) => {
sessionStorage.setItem('activeTab', '0'); // 선택 탭 초기화
const ListItem = ({ challengeId, challengeTitle }: Props) => {
sessionStorage.setItem('activeTab', '0');

const navigate = useNavigate();

Expand Down Expand Up @@ -51,11 +49,7 @@ const ListItem = ({ challengeId, challengeTitle, profileImageUrl }: Props) => {
return (
<ListItemLayout>
<ProfileContainer>
<Image
src={profileImageUrl || ProfileImg}
alt='profile'
width='1.5rem'
/>
<Image src={ProfileImg} alt='profile' width='1.5rem' />
</ProfileContainer>
<Link to={`${RouterPath.challenge}/{challengeGroupId}`}>
<ChallengeTitle>{challengeTitle}</ChallengeTitle>
Expand Down
14 changes: 6 additions & 8 deletions src/pages/my-challenge-record/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCallback, useEffect, useState } from 'react';

import ListItem from './components/list-item';
import { useGetReview } from '@/apis/my-challenge-record/getReview.api';
import { ChallengeData } from '@/apis/my-challenge-record/getReview.response';
import { useGetChallengeCompletes } from '@/apis/challenge-completes/challenge-completes.api';
import { ChallengeData } from '@/apis/challenge-completes/challenge-completes.response';
import EmptyState from '@/components/common/empty-state';
import { NAVBAR_HEIGHT } from '@/components/features/layout/nav-bar';
import TopBar, { HEADER_HEIGHT } from '@/components/features/layout/top-bar';
Expand All @@ -12,7 +12,7 @@ import styled from '@emotion/styled';
const MyChallengeRecord = () => {
const [page, setPage] = useState(0);
const [allChallenges, setAllChallenges] = useState<ChallengeData[]>([]);
const { data, isLoading } = useGetReview(page, 20);
const { data, isLoading } = useGetChallengeCompletes(page, 20);

const loadMoreChallenges = useCallback(() => {
if (data?.data.hasNext && !isLoading) {
Expand Down Expand Up @@ -55,11 +55,9 @@ const MyChallengeRecord = () => {
{allChallenges.length > 0 ? (
allChallenges.map((challenge, index) => (
<ListItem
key={`${challenge.challengeId}-${index}`}
challengeId={challenge.challengeId}
challengeTitle={challenge.challengeTitle}
userNickname={challenge.user.nickname}
profileImageUrl={challenge.user.profileImageUrl}
key={`${challenge.id}-${index}`}
challengeId={challenge.challengeGroupId}
challengeTitle={challenge.title}
/>
))
) : (
Expand Down
2 changes: 1 addition & 1 deletion src/pages/rank/components/all/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const AllRank = () => {

useEffect(() => {
const fetchUserRanking = async () => {
const response: UserRankingResponse = await getUserRanking(1, 10);
const response: UserRankingResponse = await getUserRanking(0, 10);
const pageData = response.data;
const allUserData: User[] = pageData.data.map((user: UserData) => ({
...user,
Expand Down
6 changes: 6 additions & 0 deletions src/pages/review-write/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { postReview } from '@/apis/review/review.api';
import ChallengeTitle from '@/components/common/challenge-title';
import CTA, { CTAContainer } from '@/components/common/cta';
import Textarea from '@/components/common/form/textarea';
import { StarRating } from '@/components/common/star-rating';
import TopBar, { HEADER_HEIGHT } from '@/components/features/layout/top-bar';
import { RouterPath } from '@/routes/path';
import {
formatRating,
formatDifficulty,
Expand Down Expand Up @@ -35,6 +37,7 @@ const ReviewWrite = () => {
const [content, setContent] = useState('');
const [isContentValid, setIsContentValid] = useState(true);
const [isButtonDisabled, setIsButtonDisabled] = useState(true);
const navigate = useNavigate();

const handleDifficultyClick = (difficulty: number) => {
setSelectedDifficulty(difficulty);
Expand Down Expand Up @@ -83,6 +86,7 @@ const ReviewWrite = () => {
})
.then(() => {
alert('리뷰가 등록되었습니다!');
navigate(`/${RouterPath.challenge}/${RouterPath.myRecord}`);
})
.catch((error) => {
// API에서 받은 오류 객체일 경우
Expand Down Expand Up @@ -242,6 +246,8 @@ const Chip = styled.button<{ isSelected: boolean }>`
font-size: var(--font-size-sm);
font-weight: 600;
text-align: center;
cursor: pointer;
outline: none;
${({ isSelected }) =>
isSelected &&
`
Expand Down

0 comments on commit 7335b71

Please sign in to comment.