Skip to content

Commit

Permalink
Merge pull request #184 from KNU-HAEDAL/Fix/challenge-record-#182
Browse files Browse the repository at this point in the history
챌린지 인증 수정 #182
  • Loading branch information
joojjang authored Oct 2, 2024
2 parents e75a2a4 + 3954cf7 commit 6f06d83
Show file tree
Hide file tree
Showing 16 changed files with 527 additions and 278 deletions.
27 changes: 0 additions & 27 deletions src/assets/StampActive.svg

This file was deleted.

10 changes: 0 additions & 10 deletions src/assets/StampInactive.svg

This file was deleted.

34 changes: 26 additions & 8 deletions src/components/common/cta/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import styled from '@emotion/styled';

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

const CTA = ({ label, disabled, onClick }: CTAProps) => {
const CTA = ({ label, display = 'flex', disabled, onClick }: CTAProps) => {
return (
<StyledCTA disabled={disabled} onClick={onClick}>
<StyledCTA display={display} disabled={disabled} onClick={onClick}>
{label}
</StyledCTA>
);
Expand All @@ -18,17 +19,34 @@ export default CTA;

export const CTA_CONTAINER_HEIGHT = '4rem';

const StyledCTA = styled.button<{ disabled?: boolean }>`
width: calc(100% - 16px); // 부모 요소의 좌우 padding 빼고
const StyledCTA = styled.button<{
display: 'flex' | 'block';
disabled?: boolean;
}>`
border: none;
border-radius: 10px;
background-color: var(--color-green-01);
color: var(--color-white);
font-size: var(--font-size-md);
font-weight: bold;
outline: none;
padding: 10px 8px;
margin: 0 auto;
${({ display }) =>
display === 'flex' &&
`
width: calc(100% - 16px); // 부모 요소의 좌우 padding 빼고
margin: 0 auto;
padding: 10px 8px;
font-size: var(--font-size-md);
font-weight: bold;
`}
${({ display }) =>
display === 'block' &&
`
margin: 0 0 0 auto;
padding: 6px 8px;
font-size: var(--font-size-sm);
font-weight: 600;
`}
&:disabled {
cursor: not-allowed;
Expand Down
34 changes: 34 additions & 0 deletions src/components/common/empty-state/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { forwardRef } from 'react';

import styled from '@emotion/styled';

interface EmptyStateProps {
children: React.ReactNode;
}

// ref를 전달하기 위해 forwardRef 사용
const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(
({ children }, ref) => {
return <Wrapper ref={ref}>{children}</Wrapper>;
}
);

EmptyState.displayName = 'EmptyState';

export default EmptyState;

// 스타일 정의
const Wrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex: 1;
padding: 0 16px;
font-size: var(--font-size-md);
.highlight {
font-weight: 600;
color: var(--color-green-03);
}
`;
157 changes: 157 additions & 0 deletions src/components/common/form/textarea/tooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { useEffect, useState } from 'react';
import { IoCloseOutline } from 'react-icons/io5';

import styled from '@emotion/styled';

interface TooltipProps {
content: string;
children: React.ReactNode;
direction?: 'top' | 'right' | 'bottom' | 'left';
}

const Tooltip = ({ content, children, direction = 'top' }: TooltipProps) => {
const [isVisible, setIsVisible] = useState(true);

// 툴팁 자동 닫기
useEffect(() => {
const timer = setTimeout(() => {
setIsVisible(false);
}, 5000);

return () => clearTimeout(timer); // 컴포넌트 언마운트 시 타이머 정리
}, []);

const handleClose = () => {
setIsVisible(false);
};

return (
<TooltipWrapper>
{children}
{isVisible && (
<TooltipBox direction={direction}>
{content}
<CloseButton onClick={handleClose}>
<IoCloseOutline size='16px' />
</CloseButton>
</TooltipBox>
)}
</TooltipWrapper>
);
};

export default Tooltip;

// 스타일 정의

const TOOLTIP_COLOR = `var(--color-green-03)`;

const TooltipWrapper = styled.div`
position: relative;
display: inline-block;
`;

const TooltipBox = styled.div<{ direction: string }>`
position: absolute;
padding: 3px 6px;
border-radius: 4px;
background-color: ${TOOLTIP_COLOR};
color: var(--color-white);
font-size: 12px;
font-weight: 500;
white-space: nowrap;
z-index: 10;
display: flex;
align-items: center;
${({ direction }) =>
direction === 'top' &&
`
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin-bottom: 8px;
`}
${({ direction }) =>
direction === 'right' &&
`
top: 50%;
left: 100%;
transform: translateY(-50%);
margin-left: 8px;
`}
${({ direction }) =>
direction === 'bottom' &&
`
top: 100%;
left: 50%;
transform: translateX(-50%);
margin-top: 8px;
`}
${({ direction }) =>
direction === 'left' &&
`
top: 50%;
right: 100%;
transform: translateY(-50%);
margin-right: 8px;
`}
// 꼬리 부분
::after {
content: '';
position: absolute;
border-style: solid;
${({ direction }) =>
direction === 'top' &&
`
top: 100%;
left: 50%;
transform: translateX(-50%);
border-width: 8px 6px 0 6px;
border-color: ${TOOLTIP_COLOR} transparent transparent transparent;
`}
${({ direction }) =>
direction === 'right' &&
`
top: 50%;
left: 0;
transform: translateY(-50%);
border-width: 8px 6px 6px 0;
border-color: transparent ${TOOLTIP_COLOR} transparent transparent;
`}
${({ direction }) =>
direction === 'bottom' &&
`
bottom: 100%;
left: 50%;
transform: translateX(-50%);
border-width: 0 6px 8px 6px;
border-color: transparent transparent ${TOOLTIP_COLOR} transparent;
`}
${({ direction }) =>
direction === 'left' &&
`
top: 50%;
right: 0;
transform: translateY(-50%);
border-width: 6px 0 8px 6px;
border-color: transparent transparent transparent ${TOOLTIP_COLOR};
`}
}
`;

const CloseButton = styled.button`
background: transparent;
border: none;
color: var(--color-white);
cursor: pointer;
margin-left: 6px;
`;
18 changes: 9 additions & 9 deletions src/pages/challenge-detail/ranking-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { RankingItem } from '../components/ranking-item/';
import * as S from './styles';
import { getChallengeRanking } from '@/apis/challenge-detail/challenge.ranking.api';
import { type ChallengeRankingData } from '@/apis/challenge-detail/challenge.ranking.response';
import EmptyState from '@/components/common/empty-state';
import * as Base from '@/styles/baseStyles';

type RankingSectionProps = {
Expand Down Expand Up @@ -67,16 +68,15 @@ export const RankingSection = ({ id }: RankingSectionProps) => {
</>
) : (
// 랭킹 없을 때
<S.Text>
아직 챌린지를 성공한 유저가 없습니다. <br />
챌린지에 참여해{' '}
<S.Text fontWeight='600' color={`var(--color-green-01)`}>
첫 번째 완료자
</S.Text>
가 되어보세요!
</S.Text>
<EmptyState>
<span>
아직 챌린지를 성공한 유저가 없습니다. <br />
챌린지에 참여해 <span className='highlight'>첫 번째 완료자</span>
되어보세요!
</span>
</EmptyState>
)}
<S.Text ref={ref}>{isFetching ? '로딩 중...' : ' '}</S.Text>
<EmptyState ref={ref}>{isFetching ? '로딩 중...' : ' '}</EmptyState>
</S.Wrapper>
);
};
6 changes: 0 additions & 6 deletions src/pages/challenge-detail/ranking-section/styles.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import styled from '@emotion/styled';

export const Text = styled.span<{ fontWeight?: string; color?: string }>`
font-size: var(--font-size-md);
font-weight: ${(props) => props.fontWeight || null};
color: ${(props) => props.color || null};
`;

export const Wrapper = styled.div`
padding: 16px 16px;
display: flex;
Expand Down
18 changes: 9 additions & 9 deletions src/pages/challenge-detail/review-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useNavigate } from 'react-router-dom';
import * as S from './styles';
import { getReview, getChallegeAvgScore } from '@/apis/review/review.api';
import { type ReviewData } from '@/apis/review/review.response';
import EmptyState from '@/components/common/empty-state';
import { StarRating } from '@/components/common/star-rating';
import ReviewItem from '@/pages/review/components/review-item';
import { RouterPath } from '@/routes/path';
Expand Down Expand Up @@ -91,15 +92,14 @@ export const ReviewSection = ({ id, category, title }: ReviewSectionProps) => {
</>
) : (
// 리뷰 없을 때
<S.Text>
아직 리뷰가 없습니다.
<br />
챌린지를 완료하고{' '}
<S.Text fontWeight='600' color={`var(--color-green-01)`}>
첫 번째 리뷰어
</S.Text>
가 되어보세요!
</S.Text>
<EmptyState>
<span>
아직 리뷰가 없습니다.
<br />
챌린지를 완료하고 <span className='highlight'>첫 번째 리뷰어</span>
가 되어보세요!
</span>
</EmptyState>
)}
</S.Wrapper>
);
Expand Down
Loading

0 comments on commit 6f06d83

Please sign in to comment.