Skip to content

Commit

Permalink
Merge pull request #196 from KNU-HAEDAL/develop
Browse files Browse the repository at this point in the history
완료한 챌린지 api 호출 기능 수정
  • Loading branch information
Dobbymin authored Oct 15, 2024
2 parents d1e4f49 + 7335b71 commit 9cb4686
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 79 deletions.
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>;
27 changes: 21 additions & 6 deletions src/components/common/cta/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import styled from '@emotion/styled';

type CTAProps = {
theme?: 'primary' | 'secondary';
label: string;
display?: 'flex' | 'block';
disabled?: boolean;
onClick: () => void;
};

const CTA = ({ label, display = 'flex', disabled, onClick }: CTAProps) => {
const CTA = ({
theme = 'primary',
label,
display = 'flex',
disabled,
onClick,
}: CTAProps) => {
return (
<StyledCTA display={display} disabled={disabled} onClick={onClick}>
<StyledCTA
theme={theme}
display={display}
disabled={disabled}
onClick={onClick}
>
{label}
</StyledCTA>
);
Expand All @@ -20,13 +32,17 @@ export default CTA;
export const CTA_CONTAINER_HEIGHT = '4rem';

const StyledCTA = styled.button<{
theme: 'primary' | 'secondary';
display: 'flex' | 'block';
disabled?: boolean;
}>`
border: none;
border: ${({ theme }) =>
theme === 'primary' ? `none` : `1px solid var(--color-green-01)`};
border-radius: 10px;
background-color: var(--color-green-01);
color: var(--color-white);
background-color: ${({ theme }) =>
theme === 'primary' ? `var(--color-green-01)` : `var(--color-white)`};
color: ${({ theme }) =>
theme === 'primary' ? `var(--color-white)` : `var(--color-green-01)`};
outline: none;
${({ display }) =>
Expand All @@ -42,7 +58,6 @@ const StyledCTA = styled.button<{
${({ display }) =>
display === 'block' &&
`
margin: 0 0 0 auto;
padding: 6px 8px;
font-size: var(--font-size-sm);
font-weight: 600;
Expand Down
1 change: 1 addition & 0 deletions src/components/common/empty-state/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ const Wrapper = styled.div`
.highlight {
font-weight: 600;
color: var(--color-green-03);
text-align: center;
}
`;
1 change: 1 addition & 0 deletions src/interface/apis/challenge/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface ChallengeData {
challengeGroupId: number;
challengeId: number;
title: string;
successCount: number;
Expand Down
7 changes: 4 additions & 3 deletions src/pages/challenge-list/components/contents/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react';

import { formatDate } from '@/utils/formatters';
import { Box, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';

Expand Down Expand Up @@ -29,7 +30,7 @@ const Contents = ({
onClick(id);
};

const date = `${startDate} ~ ${endDate}`;
const period = `${formatDate(startDate)} ~ ${formatDate(endDate)}`;

return (
<ContentsBox onClick={handleBoxClick} isClicked={isClicked}>
Expand All @@ -50,9 +51,9 @@ const Contents = ({
</FlexBox>
<Box>
<Text mb={1.5} fontSize='1.2rem' fontWeight='700'>
참여 가능 기간
챌린지 신청 가능 기간
</Text>
<TextItem isClicked={isClicked}>{date}</TextItem>
<TextItem isClicked={isClicked}>{period}</TextItem>
</Box>
</ContentsBox>
);
Expand Down
16 changes: 9 additions & 7 deletions src/pages/challenge-record/components/caution/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ const Caution = () => {
listStyleType='disc'
listStylePosition='inside'
fontSize='var(--font-size-xs)'
css={`
li {
padding-left: 1.4em; /* 들여쓰기 추가 */
text-indent: -1.4em; /* 첫 줄은 들여쓰지 않음 */
}
`}
>
<li>모든 스탬프를 모으면 챌린지를 완수하게 됩니다.</li>
<li>1일 인증 횟수에는 제한이 없습니다.</li>
<li>모든 스탬프를 모으면 챌린지를 완료하게 됩니다.</li>
<li>
스탬프는 하루 1개로 제한됩니다. (동일 챌린지를 하루에 여러 번
인증하더라도 1회만 인정됩니다.)
</li>
<li>
명시된 횟수를 초과한 경우 챌린지 완수로 인정되나 추가 인증에 대한
스탬프나 포인트는 제공되지 않습니다.
완료한 챌린지는 &apos;완료한 챌린지 목록&apos;에서 조회할 수 있습니다.
</li>
<li>
사진 조작, 타인의 계정 이용 등의 부정 행위 적발 시 해당 계정은 강제
Expand Down
49 changes: 24 additions & 25 deletions src/pages/my-challenge-record/components/list-item.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { useNavigate } from 'react-router-dom';
import { useNavigate, Link } from 'react-router-dom';

import ProfileImg from '@/assets/challenge/ZZAN-Green.png';
import CTA from '@/components/common/cta';
import { RouterPath } from '@/routes/path';
import { Image } from '@chakra-ui/react';
import { Box, Image, Text } from '@chakra-ui/react';
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();

const handleChallengeClick = (
const handleViewRecord = (
challengeId: number,
title: string,
category?: string
Expand Down Expand Up @@ -51,22 +49,24 @@ 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>
<ChallengeTitle
onClick={() => handleChallengeClick(challengeId, challengeTitle)}
>
{challengeTitle}
</ChallengeTitle>
<ReviewWriteButton
label='리뷰 쓰기'
display='block'
onClick={() => handleReviewWrite(challengeId, challengeTitle)}
/>
<Link to={`${RouterPath.challenge}/{challengeGroupId}`}>
<ChallengeTitle>{challengeTitle}</ChallengeTitle>
</Link>
<Box display='flex' margin='0 0 0 auto' gap='8px'>
<CTA
theme='secondary'
label='인증 기록'
display='block'
onClick={() => handleViewRecord(challengeId, challengeTitle)}
/>
<CTA
label='리뷰 쓰기'
display='block'
onClick={() => handleReviewWrite(challengeId, challengeTitle)}
/>
</Box>
</ListItemLayout>
);
};
Expand Down Expand Up @@ -100,12 +100,11 @@ const ProfileContainer = styled.div`
padding: 0.5rem;
`;

const ChallengeTitle = styled.button`
const ChallengeTitle = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 600;
font-size: 1rem;
flex: 1;
`;

const ReviewWriteButton = styled(CTA)``;
29 changes: 11 additions & 18 deletions src/pages/my-challenge-record/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
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';
import { Box, Spinner } from '@chakra-ui/react';
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 @@ -54,22 +55,15 @@ 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}
/>
))
) : (
<EmptyState>
<span>
<span className='highlight'>
완료한 챌린지가 존재하지 않습니다.
</span>
<br />
어서 챌린지를 인증하여 스탬프를 채워보세요!
</span>
<p className='highlight'>완료한 챌린지가 존재하지 않습니다.</p>
<p>어서 챌린지를 인증하여 스탬프를 채워보세요!</p>
</EmptyState>
)}
</ChallengeList>
Expand All @@ -86,9 +80,8 @@ const MyChallengeRecord = () => {
export default MyChallengeRecord;

const MyChallengeRecordLayout = styled.div`
min-height: calc(
100vh - ${HEADER_HEIGHT}
); // 부모가 block이므로 해당 요소에 직접 높이 지정
min-height: calc(100vh - ${HEADER_HEIGHT} - ${NAVBAR_HEIGHT});
// 부모가 block이므로 해당 요소에 직접 높이 지정
display: flex;
flex-direction: column;
background-color: var(--color-green-06);
Expand Down
32 changes: 18 additions & 14 deletions src/pages/my-challenge/components/challenge-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom';
import { useNavigate, Link } from 'react-router-dom';

import * as S from './styles';
import NotChallenge from '@/assets/UserImage.svg';
Expand All @@ -11,15 +11,15 @@ import { Box, Image, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';

type ChallengeListProps = {
challenges: ChallengeData[];
challengeList: ChallengeData[];
};

const ChallengeList = ({ challenges }: ChallengeListProps) => {
const ChallengeList = ({ challengeList }: ChallengeListProps) => {
const navigate = useNavigate();

return (
<>
{challenges.length === 0 ? (
{challengeList.length === 0 ? (
<EmptyState>
<Image
opacity='0.5'
Expand All @@ -32,24 +32,28 @@ const ChallengeList = ({ challenges }: ChallengeListProps) => {
</EmptyState>
) : (
<ChallengeListBox>
{challenges.map((challenge, index) => (
{challengeList.map((challenge, index) => (
<ChallengeItem key={index}>
<S.ChallengeImgContainer>
<Image
filter='opacity(0.5) drop-shadow(0 0 0 #c0c0c0)'
src={FinishStamp}
/>
</S.ChallengeImgContainer>
<Text
className='challenge-title'
fontSize='var(--font-size-md)'
fontStyle='normal'
fontWeight='600'
alignSelf='center'
margin='0 auto 0 0'
<Link
to={`/${RouterPath.challenge}/${challenge.challengeGroupId}`}
>
{challenge.title}
</Text>
<Text
className='challenge-title'
fontSize='var(--font-size-md)'
fontStyle='normal'
fontWeight='600'
alignSelf='center'
margin='0 auto 0 0'
>
{challenge.title}
</Text>
</Link>
<RecordButton
label='인증 기록'
display='block'
Expand Down
Loading

0 comments on commit 9cb4686

Please sign in to comment.