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

서술형 커뮤니티화 #114

Merged
merged 35 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
78c0939
:construction: Work in progress
Kim-Hyunjo Sep 9, 2023
6fa280d
:bento: Add button svgs
Kim-Hyunjo Nov 26, 2023
d806194
:recycle: Seperate description box
Kim-Hyunjo Nov 26, 2023
434c3f6
:art: Seperate PostBox
Kim-Hyunjo Nov 26, 2023
2fa22ff
:lipstick: Update Postbox UI
Kim-Hyunjo Nov 26, 2023
eb81aae
:lipstick: Give font-family to every tag
Kim-Hyunjo Nov 26, 2023
ffc35ac
:lipstick: Add PostInput
Kim-Hyunjo Nov 26, 2023
6c597b5
:lipstick: Add xsmall button size
Kim-Hyunjo Nov 26, 2023
b540c15
:lipstick: Add CommentInput
Kim-Hyunjo Nov 26, 2023
aa57a08
:sparkles: Add addCommentButton
Kim-Hyunjo Nov 26, 2023
7fc36b8
:sparkles: Add api functions
Kim-Hyunjo Nov 26, 2023
b2c84ea
:lipstick: Update addComment button font
Kim-Hyunjo Nov 26, 2023
e5b5562
:construction: Adding community post add api
Kim-Hyunjo Nov 28, 2023
e51748b
:sparkles: Add bookmark, like feature
Kim-Hyunjo Nov 29, 2023
7ccb785
:sparkles: Add answerCount to problemTitle
Kim-Hyunjo Nov 29, 2023
36b60af
:sparkles: Refetch posts when new post added
Kim-Hyunjo Nov 30, 2023
c19a8c1
:sparkles: Add addComment mutation
Kim-Hyunjo Nov 30, 2023
f80ee4c
:sparkles: Add likePost mutations
Kim-Hyunjo Nov 30, 2023
dbea2aa
:lipstick: Update my input UI
Kim-Hyunjo Dec 10, 2023
e1c7097
:hammer: Sort comments by createdAt
Kim-Hyunjo Dec 10, 2023
dab198d
:hammer: Block like, bookmark button when not login
Kim-Hyunjo Dec 10, 2023
3b46d41
:hammer: Show post input when logined
Kim-Hyunjo Dec 10, 2023
27870dd
:hammer: Show comment input when logined
Kim-Hyunjo Dec 10, 2023
db9fe70
Merge branch 'dev' into feat/428
Kim-Hyunjo Dec 10, 2023
6bea535
:mute: Remove console.log
Kim-Hyunjo Dec 17, 2023
c94cfd3
:recycle: Add isLogin util function
Kim-Hyunjo Dec 17, 2023
52aee35
:pencil2: Fix AUTHORIZTION -> AUTHORIZATION
Kim-Hyunjo Dec 17, 2023
09196f1
:bulb: Update Link to profile page into comment
Kim-Hyunjo Dec 17, 2023
86404a1
:wheelchair: Show metaTag keyword only truthy
Kim-Hyunjo Dec 17, 2023
b536499
:adhesive_bandage: Remove unneccesary div when community post does no…
Kim-Hyunjo Dec 17, 2023
5ab0049
🔀 Merge branch 'dev' into feat/428
Kim-Hyunjo Dec 17, 2023
82661df
:sparkles: Link nickname with user profile page
Kim-Hyunjo Jan 14, 2024
44da20d
:recycle: Add getSingleInputValueOnSubmit util function
Kim-Hyunjo Jan 14, 2024
0e35c7c
:heavy_plus_sign: Add vitest
Kim-Hyunjo Jan 14, 2024
37dfbf6
:white_check_mark: Add parseDateTime util test
Kim-Hyunjo Jan 14, 2024
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
10 changes: 10 additions & 0 deletions packages/service/src/Component/Button/TextButton/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ export const textButtonSizeStyle = styleVariants({
borderRadius: '8px',
},
],
xsmall: [
{
width: '3.5rem',
height: '1.5rem',
fontWeight: '500',
fontSize: '0.75rem',
lineHeight: '1rem',
borderRadius: '4px',
},
],
});

export const unactivatedStyle = style({
Expand Down
3 changes: 3 additions & 0 deletions packages/service/src/Organism/ProblemTitle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface IProblemDetail {
score: string;
correctSubmission: string;
correctUserCnt: string;
answerCount: string;
}

interface IProblemDetailDescription {
Expand Down Expand Up @@ -61,6 +62,8 @@ const problemDetailMap: Record<
isStringNotEmpty(num) ? { label: '정답', value: num, unit: '' } : null,
correctUserCnt: (num: string | undefined) =>
isStringNotEmpty(num) ? { label: '맞힌 사람 수', value: num, unit: '명' } : null,
answerCount: (num: string | undefined) =>
isStringNotEmpty(num) ? { label: '답변 수', value: num, unit: '' } : null,
};

function ProblemTitle(props: IProblemTitle) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { boxStyle } from './style.css';

type Props = {
children: React.ReactNode;
className?: string;
};

const Box = ({ children, className }: Props) => {
return <div className={`${boxStyle} ${className}`}>{children}</div>;
};

export default Box;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { style } from '@vanilla-extract/css';
import { themeColors } from '../../../../../styles/theme.css';

export const boxStyle = style({
padding: '24px',
border: `1px solid ${themeColors.line.d}`,
borderRadius: '8px',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { QueryObserverResult, useMutation } from 'react-query';
import { communityApiWrapper } from '../../../../../api/wrapper/community/communityApiWrapper';
import { TextButton } from '../../../../../Component/Button';
import { LongProblemPost } from '../../../../../types/api/community';
import { textareaStyle, textareaWrapStyle, wrapStyle } from './style.css';

type Props = {
postId: number;
refetchCommunityPost: () => Promise<QueryObserverResult<LongProblemPost[], unknown>>;
};

const CommentInput = ({ postId, refetchCommunityPost }: Props) => {
const { mutate: addComment } = useMutation(communityApiWrapper.addComment, {
onSuccess: () => refetchCommunityPost(),
});
return (
<form
onSubmit={(e) => {
e.preventDefault();
const formElement = e.target as HTMLFormElement;
const data = new FormData(formElement);
const content = data.get('comment-input')?.toString();
if (!content) return;
addComment({ postId: postId, content });
formElement.reset();
}}
>
<div className={wrapStyle}>
<div className={textareaWrapStyle}>
<textarea className={textareaStyle} id='comment-input' name='comment-input' />
</div>
<TextButton theme='primary' size='xsmall' type='submit'>
제출하기
</TextButton>
</div>
</form>
);
};
export default CommentInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { style } from '@vanilla-extract/css';
import { themeColors } from '../../../../../styles/theme.css';

export const wrapStyle = style({
display: 'flex',
alignItems: 'center',
gap: '1rem',
marginTop: '1rem',
});

export const textareaWrapStyle = style({
flex: 1,
padding: '0.5rem',
border: `1px solid ${themeColors.line.d}`,
borderRadius: '4px',
});

export const textareaStyle = style({
width: '100%',
fontSize: '1rem',
fontWeight: 400,
lineHeight: '1.25rem',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import Box from '../Box';
import IconButton from '../IconButton';
import { ReactComponent as StarIcon } from '../../../../../assets/icons/star.svg';
import { ReactComponent as ThumbUpIcon } from '../../../../../assets/icons/thumb_up.svg';
import { COLOR } from '../../../../../constants/color';
import { buttonWrap, descriptionWrap, topWrap, wrap } from './style.css';
import { QueryObserverResult, useMutation } from 'react-query';
import { problemApiWrapper } from '../../../../../api/wrapper/problem/problemApiWrapper';
import { ILongProblemDetailResponseData } from '../../../../../types/api/problem';
import { communityApiWrapper } from '../../../../../api/wrapper/community/communityApiWrapper';
import PostInput from '../PostInput';
import { LongProblemPost } from '../../../../../types/api/community';
import { getUserInfo } from 'auth/utils/userInfo';

type Props = {
id: string;
description: string;
isLiked: boolean;
likeCount: number;
isBookmarked: boolean;
bookmarkCount: number;
refetchProblemDetail: () => Promise<QueryObserverResult<ILongProblemDetailResponseData, unknown>>;
refetchCommunityPost: () => Promise<QueryObserverResult<LongProblemPost[], unknown>>;
};

const DescriptionBox = ({
id,
description,
isLiked,
likeCount,
isBookmarked,
bookmarkCount,
refetchProblemDetail,
refetchCommunityPost,
}: Props) => {
const isLogin = !!getUserInfo()?.id;
const { mutate: likeProblem } = useMutation(
['likeProblem', id],
() => problemApiWrapper.likeProblem({ problemId: id }),
{ onSuccess: () => refetchProblemDetail() },
);
const { mutate: bookmarkProblem } = useMutation(
['bookmarkProblem', id],
() => problemApiWrapper.bookmarkProblem({ problemId: id }),
{ onSuccess: () => refetchProblemDetail() },
);
const { mutate: addPost } = useMutation(communityApiWrapper.addPost, {
onSuccess: () => refetchCommunityPost(),
});

return (
<Box className={wrap}>
<div className={topWrap}>
<div>문제 설명</div>
<div className={buttonWrap}>
<IconButton
text={bookmarkCount.toString()}
onClick={() => {
bookmarkProblem();
}}
>
<StarIcon fill={isBookmarked ? COLOR.PRIMARY : COLOR.GRAY} width='2rem' height='2rem' />
</IconButton>
<IconButton
text={likeCount.toString()}
onClick={() => {
likeProblem();
}}
>
<ThumbUpIcon fill={isLiked ? COLOR.PRIMARY : COLOR.GRAY} width='2rem' height='2rem' />
</IconButton>
</div>
</div>
<div className={descriptionWrap}>{description}</div>
{isLogin && (
<form
onSubmit={(e) => {
e.preventDefault();
const formElement = e.target as HTMLFormElement;
const data = new FormData(formElement);
const content = data.get('post-input')?.toString();
if (!content) return;
addPost({ problemId: parseInt(id), content });
formElement.reset();
Copy link
Member

Choose a reason for hiding this comment

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

postInput이랑 거의 겹치는데 이거 공통화는 어려울까용

Copy link
Member Author

Choose a reason for hiding this comment

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

다음주에 보겠습니다ㅠㅠ

Copy link
Member Author

Choose a reason for hiding this comment

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

singleInputValue를 submit할때에 대한 util함수를 생성해보았습니다,,

}}
>
<PostInput />
</form>
)}
</Box>
);
};

export default DescriptionBox;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { style } from '@vanilla-extract/css';

export const wrap = style({
marginTop: '24px',
});

export const topWrap = style({
display: 'flex',
justifyContent: 'space-between',
fontSize: '1.75rem',
fontWeight: 700,
lineHeight: '2rem',
});

export const buttonWrap = style({
display: 'flex',
gap: '8px',
});

export const descriptionWrap = style({
marginTop: '12px',
fontSize: '1.25rem',
fontStyle: 'normal',
fontWeight: 400,
lineHeight: '1.5rem',
whiteSpace: 'pre-wrap',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getUserInfo } from 'auth/utils/userInfo';
import { MouseEvent } from 'react';
import { toast } from 'react-toastify';
import { iconButtonStyle } from './style.css';

type Props = {
children: React.ReactNode;
text: string;
onClick: (e: MouseEvent) => void;
};

const IconButton = ({ children, text, onClick }: Props) => {
const onClickWithLoginStatus = (e: MouseEvent) => {
const isLogin = !!getUserInfo()?.id;
console.log(isLogin);
kshired marked this conversation as resolved.
Show resolved Hide resolved
if (isLogin) {
onClick(e);
return;
}
toast('로그인 후 이용해주세요');
};

return (
<button type='button' onClick={onClickWithLoginStatus} className={iconButtonStyle}>
{children}
<div>{text}</div>
</button>
);
};

export default IconButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { style } from '@vanilla-extract/css';
import { themeColors } from '../../../../../styles/theme.css';

export const iconButtonStyle = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '0 4px 4px',
color: themeColors.text[2],
fontSize: '1rem',
fontWeight: 700,
lineHeight: '1.2rem',
});
Loading