Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

B 사이드 토픽 결과 화면 구현 #233

Merged
merged 10 commits into from
Mar 6, 2024
28 changes: 28 additions & 0 deletions src/assets/icons/crown.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ClockIcon from './clock.svg?react';
import CloseIcon from './close.svg?react';
import CommentBoxIcon from './comment-box.svg?react';
import CommentIcon from './comment.svg?react';
import CrownIcon from './crown.svg?react';
import DefaultProfileIcon from './default-profile.svg?react';
import DeleteIcon from './delete.svg?react';
import DownChevronIcon from './down-chevron.svg?react';
Expand Down Expand Up @@ -62,6 +63,7 @@ export {
CheckIcon,
ClockIcon,
CloseIcon,
CrownIcon,
CommentIcon,
CommentBoxIcon,
DefaultProfileIcon,
Expand Down
6 changes: 4 additions & 2 deletions src/components/B/BTopicCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CommentChip from '@components/commons/Chip/CommentChip';
import { Col, Row } from '@components/commons/Flex/Flex';
import Text from '@components/commons/Text/Text';
import { TopicResponse } from '@interfaces/api/topic';
import { TopicStatusType } from '@interfaces/models/topic';

import { colors } from '@styles/theme';

Expand All @@ -17,13 +18,14 @@ import BTopicChoice from './BTopicChoice';

interface BTopicCardProps {
topic: TopicResponse;
topicStatus: TopicStatusType;
}

const BTopicCard = ({ topic }: BTopicCardProps) => {
const BTopicCard = ({ topic, topicStatus }: BTopicCardProps) => {
const navigate = useNavigate();

const handleCardClick = () => {
navigate(`/topics/b/${topic.topicId}`, { state: { topic } });
navigate(`/topics/b/${topic.topicId}`, { state: { topic, topicStatus } });
};

const handleOptionClick = () => {};
Expand Down
42 changes: 42 additions & 0 deletions src/components/B/ResultSlide.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { styled } from 'styled-components';

const SlideContainer = styled.div`
position: relative;
display: flex;
align-items: center;
width: 100%;
height: 148px;
overflow: hidden;
`;

const ASideContainer = styled(SlideContainer)`
position: relative;
justify-content: flex-end;
background-color: #d04376;
border-top-right-radius: 74px;
border-bottom-right-radius: 74px;
`;

const BSideContainer = styled(SlideContainer)`
position: relative;
justify-content: flex-start;
background-color: #1498aa;
border-top-left-radius: 74px;
border-bottom-left-radius: 74px;
`;

const CrownContainer = styled.div`
position: absolute;
top: -26px;
left: 50%;
transform: translate(-50%, 0%);
`;

const ResultSlideTextContainer = styled.div`
z-index: 10;
width: 100%;
padding: 0 20px;
text-align: center;
`;

export { SlideContainer, ASideContainer, BSideContainer, CrownContainer, ResultSlideTextContainer };
75 changes: 75 additions & 0 deletions src/components/B/ResultSlide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Text from '@components/commons/Text/Text';
import { SideImage } from '@components/Home/ChoiceSlide/ChoiceSlide.styles';
import { Choice } from '@interfaces/api/topic';

import { colors } from '@styles/theme';

import { CrownIcon } from '@icons/index';

import {
ASideContainer,
BSideContainer,
CrownContainer,
ResultSlideTextContainer,
} from './ResultSlide.styles';

interface Props {
choice: Choice;
}

const ResultSlide = ({ choice }: Props) => {
const SlideContainer = choice.choiceOption === 'CHOICE_A' ? ASideContainer : BSideContainer;

return (
<div style={{ position: 'relative', marginTop: 50, width: '100%' }}>
<CrownContainer>
<CrownIcon />
</CrownContainer>
<SlideContainer>
<div
style={{
position: 'absolute',
top: -45,
left: '50%',
transform: 'translate(-50%, 0%)',
}}
>
<Text
color={choice.choiceOption === 'CHOICE_A' ? '#e15ba1' : '#19b1be'}
size={200}
weight={900}
>
{choice.choiceOption === 'CHOICE_A' ? 'A' : 'B'}
</Text>
</div>

{choice.content.imageUrl ? (
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
justifyContent: choice.choiceOption === 'CHOICE_A' ? 'flex-end' : 'flex-start',
}}
>
<SideImage src={choice.content.imageUrl} />
</div>
) : (
<ResultSlideTextContainer>
<Text
style={{ wordBreak: 'keep-all', overflowWrap: 'break-word' }}
color={colors.white}
size={choice.content.text && choice.content.text.length >= 21 ? 16 : 20}
weight={600}
align="center"
>
{choice.content.text}
</Text>
</ResultSlideTextContainer>
)}
</SlideContainer>
</div>
);
};

export default ResultSlide;
21 changes: 21 additions & 0 deletions src/components/B/TopicCard.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { styled } from 'styled-components';

const CardContainer = styled.div`
display: flex;
flex-direction: column;
background-color: ${({ theme }) => theme.colors.navy2_60};
backdrop-filter: blur(1.5px);
border-radius: 10px;
`;

const CardFooter = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 9px 22px;
background-color: rgb(100 81 155 / 60%);
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
`;

export { CardContainer, CardFooter };
103 changes: 103 additions & 0 deletions src/components/B/TopicCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';

import CommentChip from '@components/commons/Chip/CommentChip';
import { Col, Row } from '@components/commons/Flex/Flex';
import Text from '@components/commons/Text/Text';
import { TopicResponse } from '@interfaces/api/topic';

import { colors } from '@styles/theme';

import { MeatballIcon } from '@icons/index';

import { getDateDiff } from '@utils/date';

import BTopicChoice from './BTopicChoice';
import { CardContainer, CardFooter } from './TopicCard.styles';

interface VotingCardProps {
topic: TopicResponse;
}

const VotingCard = ({ topic }: VotingCardProps) => {
const navigate = useNavigate();

const handleCardClick = () => {
navigate(`/topics/b/${topic.topicId}`, { state: { topic } });
};

const handleOptionClick = () => {};

return (
<>
<CardContainer onClick={handleCardClick}>
<Col padding={'12px 22px 20px'}>
<Row justifyContent={'space-between'} alignItems={'center'} style={{ marginBottom: 2 }}>
<Row gap={10}>
<Text size={13} color={colors.purple}>
{topic.keyword?.keywordName}
</Text>
<Text size={13} color={colors.white_40}>
{getDateDiff(topic.createdAt)} 전
</Text>
</Row>
{topic.selectedOption && (
<Text
size={13}
weight={600}
color={colors.purple}
noWrap
style={{
borderRadius: 30,
padding: '2px 12px',
backgroundColor: colors.purple_30,
}}
>
선택완료
</Text>
)}
</Row>
<Row justifyContent={'space-between'} alignItems={'center'} style={{ marginBottom: 17 }}>
<Text size={18} weight={600} color={colors.white}>
{topic.topicTitle}
</Text>
{/* TBD: 1차 스펙 아웃 */}
{/* <button onClick={handleOptionClick}>
<MeatballIcon fill={colors.white_60} />
</button> */}
</Row>
<Row gap={5}>
{topic.choices.map((choice) => {
return (
<BTopicChoice
key={choice.choiceId}
side={choice.choiceOption}
content={choice.content.text || ''}
/>
);
})}
</Row>
</Col>
<CardFooter>
<Row gap={5}>
<Text size={13} weight={600} color={colors.white_80}>
선택
</Text>
<Text size={13} weight={600} color={colors.white_40}>
{topic.voteCount.toLocaleString()} 명
</Text>
</Row>
<CommentChip
count={topic.commentCount}
backgroundColor={colors.black_20}
onClick={function (): void {
throw new Error('Function not implemented.');
}}
/>
</CardFooter>
</CardContainer>
</>
);
};

export default VotingCard;
2 changes: 1 addition & 1 deletion src/components/Home/ChoiceSlide/ChoiceSlide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const ChoiceSlide = ({ side, topicContent }: ChoiceSlideProps) => {
justifyContent: side === 'A' ? 'flex-end' : 'flex-start',
}}
>
<SideImage />
<SideImage src={topicContent.imageUrl} />
<SizeUpButton onClick={handleOnClickSizeUpButton}>
<SizeUpIcon />
</SizeUpButton>
Expand Down
6 changes: 4 additions & 2 deletions src/components/commons/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import { Helmet } from 'react-helmet';

import { colors } from '@styles/theme';

import BottomNavigation from '../BottomNavigation/BottomNavigation';

import {
Expand All @@ -16,7 +18,7 @@ interface LayoutProps {
HeaderCenter?: React.ReactNode;
HeaderRight?: React.ReactNode;
hasBottomNavigation?: boolean;
ThemeColor?: string;
themeColor?: string;
children: React.ReactNode;
}

Expand All @@ -26,7 +28,7 @@ const Layout = (props: LayoutProps) => {
return (
<Main>
<Helmet>
<meta name="theme-color" content={props.ThemeColor || '#242036'} />
<meta name="theme-color" content={props.themeColor || colors.navy} />
</Helmet>
<Header>
<HeaderSection style={{ justifySelf: 'start' }}>{HeaderLeft}</HeaderSection>
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/useOAuth/useOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export default function useOAuth({ type }: UseOAuthProps) {
state: { memberId: response.memberId },
});
} else {
if (!response.accessToken || !response.refreshToken || !response.memberId) {
throw new Error('토큰이 올바르지 않습니다.');
}
login(response.accessToken, response.refreshToken, response.memberId);
navigate('/');
}
Expand Down
4 changes: 2 additions & 2 deletions src/interfaces/api/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ export interface OAuthResponse {
newMember: boolean;
memberId: number;
joinStatus: JoinStatus;
accessToken: string;
refreshToken: string;
accessToken?: string;
refreshToken?: string;
}
9 changes: 9 additions & 0 deletions src/interfaces/models/topic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const TopicStatus = {
VOTING: 'VOTING',
CLOSED: 'CLOSED',
} as const;

type TopicStatusType = keyof typeof TopicStatus;

export { TopicStatus };
export type { TopicStatusType };
Loading
Loading