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

Feat/#1552: 아티클 좋아요 기능 추가와 authorization null 삭제 #1558

Merged
merged 2 commits into from
Sep 27, 2023
Merged
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
7 changes: 6 additions & 1 deletion frontend/src/apis/articles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { client } from '.';
import {
ArticleBookmarkPutRequest,
ArticleLikePutRequest,
ArticleRequest,
MetaOgRequest,
MetaOgResponse,
Expand All @@ -15,9 +16,13 @@ export const requestGetMetaOg = ({ url }: MetaOgRequest) => {
};

export const requestPutArticleBookmark = ({ articleId, bookmark }: ArticleBookmarkPutRequest) => {
return client.put(`/articles/${articleId}/bookmark`, { checked: bookmark });
return client.put(`/articles/${articleId}/bookmark`, { bookmark });
};

export const requestGetFilteredArticle = (course: string, bookmark: boolean) => {
return client.get(`/articles?course=${course}&onlyBookmarked=${bookmark}`);
};

export const requestPutArticleLike = ({ articleId, like }: ArticleLikePutRequest) => {
return client.put(`/articles/${articleId}/like`, { like });
};
10 changes: 7 additions & 3 deletions frontend/src/apis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import axios from 'axios';
import { BASE_URL } from '../configs/environment';
import LOCAL_STORAGE_KEY from '../constants/localStorage';

const accessToken = localStorage.getItem(LOCAL_STORAGE_KEY.ACCESS_TOKEN);

const headers = {
Authorization: `Bearer ${accessToken}`,
};

export const client = axios.create({
baseURL: BASE_URL,
headers: {
Authorization: `Bearer ${localStorage.getItem(LOCAL_STORAGE_KEY.ACCESS_TOKEN)}`,
},
headers: accessToken ? headers : {},
});
3 changes: 2 additions & 1 deletion frontend/src/components/Article/Article.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ export const Title = styled.p`
-webkit-box-orient: vertical;
`;

export const BookmarkWrapper = styled.div`
export const ButtonContainer = styled.div`
width: 100%;
display: flex;
justify-content: flex-end;
gap: 10px;
`;

export const ArticleBookmarkButtonStyle = css`
Expand Down
36 changes: 32 additions & 4 deletions frontend/src/components/Article/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@ import * as Styled from './Article.style';
import type { ArticleType } from '../../models/Article';
import Scrap from '../Reaction/Scrap';
import { useRef, useState } from 'react';
import { usePutArticleBookmarkMutation } from '../../hooks/queries/article';
import {
usePutArticleBookmarkMutation,
usePutArticleLikeMutation,
} from '../../hooks/queries/article';
import debounce from '../../utils/debounce';
import Like from '../Reaction/Like';

const Article = ({ id, title, userName, url, createdAt, imageUrl, isBookMarked }: ArticleType) => {
const Article = ({
id,
title,
userName,
url,
createdAt,
imageUrl,
isBookMarked,
isLiked,
}: ArticleType) => {
const bookmarkRef = useRef(false);
const likeRef = useRef(false);
const [bookmark, setBookmark] = useState(isBookMarked);
const [like, setLike] = useState(isLiked);
const { mutate: putBookmark } = usePutArticleBookmarkMutation();
const { mutate: putLike } = usePutArticleLikeMutation();

const toggleBookmark: React.MouseEventHandler<HTMLButtonElement> = (e) => {
e.preventDefault();
Expand All @@ -21,6 +37,17 @@ const Article = ({ id, title, userName, url, createdAt, imageUrl, isBookMarked }
}, 300);
};

const toggleLike: React.MouseEventHandler<HTMLButtonElement> = (e) => {
e.preventDefault();

likeRef.current = !likeRef.current;
setLike((prev) => !prev);

debounce(() => {
putLike({ articleId: id, like: likeRef.current });
}, 300);
};

return (
<Styled.Container>
<Styled.Anchor href={url} target="_blank" rel="noopener noreferrer">
Expand All @@ -33,13 +60,14 @@ const Article = ({ id, title, userName, url, createdAt, imageUrl, isBookMarked }
<Styled.CreatedAt>{createdAt.split(' ')[0]}</Styled.CreatedAt>
</Styled.ArticleInfoWrapper>
<Styled.Title>{title}</Styled.Title>
<Styled.BookmarkWrapper>
<Styled.ButtonContainer>
<Like liked={like} onClick={toggleLike} />
<Scrap
scrap={bookmark}
onClick={toggleBookmark}
cssProps={Styled.ArticleBookmarkButtonStyle}
/>
</Styled.BookmarkWrapper>
</Styled.ButtonContainer>
</Styled.ArticleInfoContainer>
</Styled.Anchor>
</Styled.Container>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Reaction/Like.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { LikeIconStyle } from './Like.styles';

interface Props {
liked: boolean;
likesCount: number;
likesCount?: number;
onClick: MouseEventHandler<HTMLButtonElement>;
}

Expand All @@ -24,7 +24,7 @@ const Like = ({ liked, likesCount, onClick }: Props) => {
cssProps={LikeIconStyle}
onClick={onClick}
>
{likesCount ?? 0}
{likesCount}
</Button>
);
};
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/hooks/queries/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
requestGetFilteredArticle,
requestPostArticles,
requestPutArticleBookmark,
requestPutArticleLike,
} from '../../apis/articles';
import { ArticleType, CourseFilter } from '../../models/Article';
import { ArticleType } from '../../models/Article';
import { ERROR_MESSAGE } from '../../constants';
import { SUCCESS_MESSAGE } from '../../constants/message';

Expand Down Expand Up @@ -40,3 +41,10 @@ export const usePutArticleBookmarkMutation = () => {
onError: () => {},
});
};

export const usePutArticleLikeMutation = () => {
return useMutation(requestPutArticleLike, {
onSuccess: () => {},
onError: () => {},
});
};
3 changes: 3 additions & 0 deletions frontend/src/mocks/db/articles-android.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"title": "직렬화, 역직렬화는 무엇일까?",
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isLiked": false,
"isBookMarked": false,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
},
Expand All @@ -14,6 +15,7 @@
"title": "직렬화, 역직렬화는 무엇일까?",
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isLiked": false,
"isBookMarked": true,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
},
Expand All @@ -23,6 +25,7 @@
"title": "직렬화, 역직렬화는 무엇일까?",
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isLiked": false,
"isBookMarked": false,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
}
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/mocks/db/articles-backend.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": false,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -13,6 +14,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": true,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -22,6 +24,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": true,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/mocks/db/articles-frontend.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -13,6 +14,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -22,6 +24,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/mocks/db/articles.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -13,6 +14,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -22,6 +24,7 @@
"userName": "해온",
"title": "Axios",
"isBookMarked": true,
"isLiked": false,
"url": "https://hae-on.tistory.com/104",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -31,6 +34,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": false,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -40,6 +44,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": true,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -49,6 +54,7 @@
"userName": "패트릭",
"title": "CORS",
"isBookMarked": true,
"isLiked": false,
"url": "https://pgccoding.tistory.com/66",
"createdAt": "2023-07-24 18:18",
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
Expand All @@ -60,6 +66,7 @@
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isBookMarked": false,
"isLiked": false,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
},
{
Expand All @@ -69,6 +76,7 @@
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isBookMarked": true,
"isLiked": false,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
},
{
Expand All @@ -78,6 +86,7 @@
"url": "https://think0wise.tistory.com/107",
"createdAt": "2023-07-08 16:48",
"isBookMarked": false,
"isLiked": false,
"imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60"
}
]
9 changes: 5 additions & 4 deletions frontend/src/mocks/handlers/articles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import { ArticleType } from '../../models/Article';
const articleUrl = 'https://think0wise.tistory.com/107';

export const articlesHandler = [
// rest.get(`${BASE_URL}/articles`, (req, res, ctx) => {
// return res(ctx.status(200), ctx.json(articles));
// }),

rest.get(`${BASE_URL}/meta-og?url=${articleUrl}`, async (req, res, ctx) => {
const data = metaOg;

Expand All @@ -28,6 +24,7 @@ export const articlesHandler = [
url: 'https://think0wise.tistory.com/107',
createdAt: '2023-07-08 16:48',
isBookMarked: false,
isLiked: false,
imageUrl:
'https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60',
};
Expand All @@ -40,6 +37,10 @@ export const articlesHandler = [
return res(ctx.status(200));
}),

rest.put(`${BASE_URL}/articles/:articleId/like`, (req, res, ctx) => {
return res(ctx.status(200));
}),

rest.get(`${BASE_URL}/articles`, (req, res, ctx) => {
const course = req.url.searchParams.get('course') ?? 'all';
const onlyBookmarked = req.url.searchParams.get('onlyBookmarked') as string;
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/models/Article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface ArticleType {
userName: string;
title: string;
isBookMarked: boolean;
isLiked: boolean;
url: string;
createdAt: string;
imageUrl: string;
Expand All @@ -28,6 +29,11 @@ export interface ArticleBookmarkPutRequest {
bookmark: boolean;
}

export interface ArticleLikePutRequest {
articleId: number;
like: boolean;
}

export type Course = '프론트엔드' | '백엔드' | '안드로이드';

export type CourseFilter = Course | '전체보기';