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

대시보드 내가 제출한 디스커션 구현 (issue #482) #484

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions frontend/src/apis/dashboardAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { develupAPIClient } from './clients/develupClient';
import type { DashboardDiscussion, DashboardDiscussionComment } from '@/types/dashboard';
import { PATH } from './paths';

export const getDashboardDiscussion = async () => {
const { data } = await develupAPIClient.get<DashboardDiscussion>(PATH.dashboardDiscussion);

return data;
};

export const getDashboardDiscussionComments = async () => {
const { data } = await develupAPIClient.get<DashboardDiscussionComment>(
PATH.dashboardDiscussionComment,
);

return data;
};
2 changes: 2 additions & 0 deletions frontend/src/apis/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const PATH = {
missionInProgress: '/missions/in-progress',
solutions: '/solutions',
mySolutions: '/solutions/mine',
dashboardDiscussion: '/discussions/mine',
dashboardDiscussionComment: '/discussions/comments/mine',
discussions: '/discussions',
submitDiscussion: '/discussions/submit',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,50 @@ import { ROUTES } from '@/constants/routes';
import Button from '@/components/common/Button/Button';

interface NoContentProps {
type: 'submitted' | 'inProgress' | 'comments';
type: 'submitted' | 'inProgress' | 'comments' | 'dashboardDiscussion';
}

const NO_CONTENT_INFO = {
inProgress: {
route: ROUTES.missionList,
mainText: '진행 중인 미션이 없어요',
subText: '새로운 미션을 찾으러 가볼까요?',
buttonText: '미션 둘러보기',
},
submitted: {
route: ROUTES.solutions,
mainText: '제출한 솔루션이 없어요',
subText: '참여할 수 있는 미션을 찾아보러 가볼까요?',
buttonText: '미션 둘러보기',
},
comments: {
route: ROUTES.solutions,
mainText: '제출한 댓글이 없어요',
subText: '댓글을 달아볼까요?',
buttonText: '솔루션 둘러보기',
},
dashboardDiscussion: {
route: '/discussion',
mainText: '제출한 디스커션이 없어요',
subText: '다른 사람들이 작성한 디스커션을 보러 가볼까요?',
buttonText: '디스커션 둘러보기',
},
};

export default function NoContent({ type }: NoContentProps) {
const navigate = useNavigate();
const route =
type === 'inProgress'
? ROUTES.missionList
: type === 'submitted'
? ROUTES.solutions
: ROUTES.solutions;
const { route, mainText, subText, buttonText } = NO_CONTENT_INFO[type];

const handleNavigateToMissionList = () => {
const handleNavigate = () => {
navigate(route);
};

const mainText =
type === 'inProgress'
? '진행 중인 미션이 없어요'
: type === 'submitted'
? '제출한 솔루션이 없어요'
: '제출한 댓글이 없어요';
const subText =
type === 'inProgress'
? '새로운 미션을 찾으러 가볼까요?'
: type === 'submitted'
? '참여할 수 있는 미션을 찾아보러 가볼까요?'
: '댓글을 달아볼까요?';
const buttonText = type === 'comments' ? '솔루션 둘러보기' : '미션 둘러보기';

return (
<S.Container>
<S.NoContent />
<S.MainText>{mainText}</S.MainText>
<S.SubText>{subText}</S.SubText>
<Button onClick={handleNavigateToMissionList}>{buttonText}</Button>
<Button onClick={handleNavigate}>{buttonText}</Button>
{/* <S.Button onClick={handleNavigateToMissionList}>{buttonText}</S.Button> */}
</S.Container>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { styled } from 'styled-components';
import { Link } from 'react-router-dom';

export const HashTagWrapper = styled.div`
display: flex;
margin-bottom: 0.5rem;
`;

export const HashTag = styled.span<{ $isTitle?: boolean }>`
padding: 0.5rem 0.8rem;
border-radius: 2rem;
margin-right: 0.7rem;
background-color: ${(props) => (props.$isTitle ? 'var(--danger-50)' : 'var(--primary-50)')};
`;

export const ImageWrapper = styled.div`
width: 4.2rem;
height: 4.2rem;
border: 0.1rem solid var(--grey-400);
border-radius: 50%;
`;

export const Image = styled.img`
border-radius: 50%;
width: 100%;
height: 100%;
`;

export const Container = styled.div`
width: 67.4rem;
height: 100%;
`;

export const DiscussionWrapper = styled(Link)`
height: 8.5rem;
border-radius: 2.8rem;
background: ${(props) => props.theme.colors.white};
box-shadow: ${(props) => props.theme.boxShadow.shadow04};
padding: 14px 34px 14px 34px;
display: flex;
margin-top: 3rem;
margin-bottom: 1.5rem;
cursor: pointer;
`;

export const CommentCountWrapper = styled.div`
margin-left: 2.8rem;
display: flex;
justify-content: center;
align-items: center;
`;

export const ImageCommentWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
`;

export const TextWrapper = styled.div`
display: flex;
flex-direction: column;
min-width: 50rem;
`;

export const CommentText = styled.span`
${(props) => props.theme.font.body}
margin-bottom: 0.6rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;

export const SubText = styled.span`
${(props) => props.theme.font.badge}
color : var(--grey-400)
`;

export const CommentCountText = styled(SubText)`
margin-left: 0.7rem;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as S from './DashboardDiscussion.styled';
import type { HashTag } from '@/types';
import CommentIcon from '@/assets/images/comment-count.svg';

interface DiscussionItemProps {
id: number;
mission: string;
hashTags: HashTag[];
title: string;
imageUrl: string;
commentCount: number;
}

export default function DiscussionItem({
id,
mission,
hashTags,
title,
imageUrl,
commentCount,
}: DiscussionItemProps) {
return (
<S.DiscussionWrapper to={`/discussions/${id}`}>
<S.TextWrapper>
<S.HashTagWrapper>
<S.HashTag $isTitle>{mission}</S.HashTag>
{hashTags.map((hashTag) => {
return <S.HashTag key={hashTag.id}>{hashTag.name}</S.HashTag>;
})}
</S.HashTagWrapper>
<S.CommentText>{title}</S.CommentText>
</S.TextWrapper>
<S.ImageCommentWrapper>
<S.ImageWrapper>
<S.Image src={imageUrl} width={22} height={22} />
</S.ImageWrapper>
<S.CommentCountWrapper>
<CommentIcon width={14} height={14} />
<S.CommentCountText>{commentCount}</S.CommentCountText>
</S.CommentCountWrapper>
</S.ImageCommentWrapper>
</S.DiscussionWrapper>
);
}
34 changes: 34 additions & 0 deletions frontend/src/components/DashBoard/DashboardDiscussion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Discussion } from '@/types/dashboard';
import NoContent from '../DashBoardMissionList/NoContent';
import * as S from './DashboardDiscussion.styled';
import DiscussionItem from './DiscussionItem';

interface DashBoardDiscussionListProps {
discussionList: Discussion[];
}

export default function DashBoardDiscussionList({ discussionList }: DashBoardDiscussionListProps) {
return (
<>
{!discussionList.length ? (
<NoContent type="dashboardDiscussion" />
) : (
<S.Container>
{discussionList.map((discussion) => {
return (
<DiscussionItem
key={discussion.id}
id={discussion.id}
hashTags={discussion.hashTags}
title={discussion.title}
mission={discussion.mission}
imageUrl={discussion.member.imageUrl}
commentCount={discussion.commentCount}
/>
);
})}
</S.Container>
)}
</>
);
}
36 changes: 36 additions & 0 deletions frontend/src/components/DashBoard/DiscussionComment/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import NoContent from '../DashBoardMissionList/NoContent';
import type { DiscussionComment } from '@/types/dashboard';
import MyComment from '../MyComments/MyComment';
import * as S from '../MyComments/MyComments.styled';

interface DiscussionCommentListProps {
discussionCommentList: DiscussionComment[];
}

export default function DiscussionCommentList({
discussionCommentList,
}: DiscussionCommentListProps) {
return (
<>
{!discussionCommentList.length ? (
<NoContent type="comments" />
) : (
<S.Container>
{discussionCommentList.map((discussionComment) => {
return (
<MyComment
key={discussionComment.id}
type="discussions"
contentId={discussionComment.discussionId}
contentTitle={discussionComment.discussionTitle}
createdAt={discussionComment.createdAt}
content={discussionComment.content}
contentCommentCount={discussionComment.discussionCommentCount}
/>
);
})}
</S.Container>
)}
</>
);
}
26 changes: 18 additions & 8 deletions frontend/src/components/DashBoard/MyComments/MyComment.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import type { MyComments } from '@/types';
import { formatDateString } from '@/utils/formatDateString';
import * as S from './MyComments.styled';
import CommentIcon from '@/assets/images/comment-count.svg';

interface MyCommentProps {
contentId: number;
content: string;
createdAt: string;
contentTitle: string;
contentCommentCount: number;
type: 'solutions' | 'discussions';
}

export default function MyComment({
solutionId,
contentId,
content,
createdAt,
solutionTitle,
solutionCommentCount,
}: Omit<MyComments, 'id'>) {
contentTitle,
contentCommentCount,
type,
}: MyCommentProps) {
const commentDate = formatDateString(createdAt);
const linkUrl = `/${type}/${contentId}`;

return (
<S.CommentWrapper to={`/solutions/${solutionId}`}>
<S.CommentWrapper to={linkUrl}>
<S.TextWrapper>
<S.CommentText>{content}</S.CommentText>
<S.SubText>{commentDate}</S.SubText>
<S.SubText>{solutionTitle}</S.SubText>
<S.SubText>{contentTitle}</S.SubText>
</S.TextWrapper>
<S.CommentCountWrapper>
<CommentIcon width={14} height={14} />
<S.CommentCountText>{solutionCommentCount}</S.CommentCountText>
<S.CommentCountText>{contentCommentCount}</S.CommentCountText>
</S.CommentCountWrapper>
</S.CommentWrapper>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ export default function MyCommentList({ comments }: MyCommentListProps) {
return (
<MyComment
key={comment.id}
solutionId={comment.solutionId}
solutionTitle={comment.solutionTitle}
type={'solutions'}
contentId={comment.solutionId}
contentTitle={comment.solutionTitle}
createdAt={comment.createdAt}
content={comment.content}
solutionCommentCount={comment.solutionCommentCount}
contentCommentCount={comment.solutionCommentCount}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const CommentCountWrapper = styled.div`
export const TextWrapper = styled.div`
display: flex;
flex-direction: column;
min-width: 53rem;
min-width: 54rem;
`;

export const CommentText = styled.span`
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const ROUTES = {
dashboardMissionInProgress: 'in-progress-mission',
dashboardSubmittedSolution: 'submitted-solution',
dashboardComments: 'comments',
dashboardDiscussions: 'discussions',
dashboardDiscussionComments: 'discussion/comments',
about: '/about',
discussions: '/discussions',
submitDiscussion: '/submit/discussion',
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/hooks/queries/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@ export const userKeys = {
export const discussionsKeys = {
all: ['discussions'],
};

export const dashboardKeys = {
default: ['dashboard'],
discussion: () => [...dashboardKeys.default, 'discussions'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[A]
discussion List를 받아오는 쿼리의 key값이라 속성 값 discussion을 복수형인 discussions로 하면 좋을 것 같은데 어떠실까요?!

discussionComments: () => [...dashboardKeys.default, 'discussion', 'comments'],
solutionComments: () => [...dashboardKeys.default, 'solution', 'comments'],
} as const;
Loading
Loading