From ff26beea608ce1e01c8ec405ca279b8ca97965f2 Mon Sep 17 00:00:00 2001 From: hae-on Date: Wed, 13 Sep 2023 18:04:30 +0900 Subject: [PATCH 01/19] =?UTF-8?q?feat:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=ED=95=84=ED=84=B0=20ui=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 이도현 --- .../src/components/Controls/SelectBox.tsx | 4 +- frontend/src/pages/ArticleListPage/index.tsx | 55 +++++++++++++++++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Controls/SelectBox.tsx b/frontend/src/components/Controls/SelectBox.tsx index 7a0fa1edb..4e73a86c2 100644 --- a/frontend/src/components/Controls/SelectBox.tsx +++ b/frontend/src/components/Controls/SelectBox.tsx @@ -46,6 +46,7 @@ interface SelectBoxProps { } const SelectBox: React.VFC = ({ + isClearable = true, isMulti = false, options, placeholder, @@ -75,7 +76,7 @@ const SelectBox: React.VFC = ({ `} > + + ); +}; + +export default ArticleBookmarkFilter; + +const ArticleBookmarkFilterContainer = styled.div` + width: 100px; + border: 1px solid black; + border-radius: 5px; + font-size: 1.5rem; +`; diff --git a/frontend/src/components/Article/ArticleList.tsx b/frontend/src/components/Article/ArticleList.tsx index 5aebbfe49..59fd386ce 100644 --- a/frontend/src/components/Article/ArticleList.tsx +++ b/frontend/src/components/Article/ArticleList.tsx @@ -1,13 +1,12 @@ import * as Styled from './ArticleList.style'; import Article from './Article'; -import { useGetRequestArticleQuery } from '../../hooks/queries/article'; +import { ArticleType } from '../../models/Article'; -const ArticleList = () => { - const { data: articles, isLoading, isError } = useGetRequestArticleQuery(); - - if (isLoading) return
loading...
; - if (isError) return
error...
; +interface ArticleListProps { + articles: ArticleType[]; +} +const ArticleList = ({ articles }: ArticleListProps) => { return ( {articles?.map((article) => ( diff --git a/frontend/src/hooks/queries/article.ts b/frontend/src/hooks/queries/article.ts index cc4eded62..f62cd49f8 100644 --- a/frontend/src/hooks/queries/article.ts +++ b/frontend/src/hooks/queries/article.ts @@ -1,20 +1,20 @@ import { useMutation, useQuery, useQueryClient } from 'react-query'; import { - requestGetArticles, + requestGetFilteredArticle, requestPostArticles, requestPutArticleBookmark, } from '../../apis/articles'; -import { ArticleType } from '../../models/Article'; +import { ArticleType, CourseFilter } from '../../models/Article'; import { ERROR_MESSAGE } from '../../constants'; import { SUCCESS_MESSAGE } from '../../constants/message'; const QUERY_KEY = { - articles: 'articles', + filteredArticles: 'filteredArticles', }; -export const useGetRequestArticleQuery = () => { - return useQuery([QUERY_KEY.articles], async () => { - const response = await requestGetArticles(); +export const useGetFilteredArticleQuery = (course: string, bookmark: boolean) => { + return useQuery([QUERY_KEY.filteredArticles], async () => { + const response = await requestGetFilteredArticle(course, bookmark); return response.data; }); @@ -25,7 +25,7 @@ export const usePostArticlesMutation = () => { return useMutation(requestPostArticles, { onSuccess: () => { - queryClient.invalidateQueries([QUERY_KEY.articles]); + queryClient.invalidateQueries([QUERY_KEY.filteredArticles]); alert(SUCCESS_MESSAGE.CREATE_ARTICLE); }, onError: () => { diff --git a/frontend/src/mocks/db/articles.json b/frontend/src/mocks/db/articles.json index cac0d4f16..182d5e558 100644 --- a/frontend/src/mocks/db/articles.json +++ b/frontend/src/mocks/db/articles.json @@ -3,6 +3,7 @@ "id": 1, "userName": "해온", "title": "Axios", + "isBookMarked": true, "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" @@ -11,6 +12,7 @@ "id": 2, "userName": "패트릭", "title": "CORS", + "isBookMarked": 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" @@ -19,6 +21,7 @@ "id": 3, "userName": "패트릭", "title": "CORS", + "isBookMarked": true, "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" @@ -27,6 +30,7 @@ "id": 4, "userName": "패트릭", "title": "CORS", + "isBookMarked": 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" diff --git a/frontend/src/mocks/handlers/articles.ts b/frontend/src/mocks/handlers/articles.ts index 9419615fb..4ea38b898 100644 --- a/frontend/src/mocks/handlers/articles.ts +++ b/frontend/src/mocks/handlers/articles.ts @@ -24,6 +24,7 @@ export const articlesHandler = [ title: '직렬화, 역직렬화는 무엇일까?', url: 'https://think0wise.tistory.com/107', createdAt: '2023-07-08 16:48', + 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', }; @@ -35,4 +36,13 @@ export const articlesHandler = [ rest.put(`${BASE_URL}/articles/:articleId/bookmark`, (req, res, ctx) => { return res(ctx.status(200)); }), + + rest.get(`${BASE_URL}/articles/filter`, (req, res, ctx) => { + const course = req.url.searchParams.get('course'); + const bookmark = req.url.searchParams.get('bookmark'); + + const filteredArticle = articles.filter((article) => bookmark === String(article.isBookMarked)); + + return res(ctx.status(200), ctx.json(filteredArticle)); + }), ]; diff --git a/frontend/src/models/Article.ts b/frontend/src/models/Article.ts index 1f194f7a5..4bce9855f 100644 --- a/frontend/src/models/Article.ts +++ b/frontend/src/models/Article.ts @@ -8,6 +8,7 @@ export interface ArticleType { id: number; userName: string; title: string; + isBookMarked: false; url: string; createdAt: string; imageUrl: string; @@ -26,3 +27,7 @@ export interface ArticleBookmarkPutRequest { articleId: number; bookmark: boolean; } + +export type Course = '프론트엔드' | '백엔드' | '안드로이드'; + +export type CourseFilter = Course | '전체보기'; diff --git a/frontend/src/pages/ArticleListPage/index.tsx b/frontend/src/pages/ArticleListPage/index.tsx index e4f55745c..2987f7870 100644 --- a/frontend/src/pages/ArticleListPage/index.tsx +++ b/frontend/src/pages/ArticleListPage/index.tsx @@ -8,8 +8,10 @@ import { COLOR, PATH } from '../../constants'; import styled from '@emotion/styled'; import { MainContentStyle } from '../../PageRouter'; import SelectBox from '../../components/Controls/SelectBox'; -import { useState } from 'react'; +import { ChangeEventHandler, useState } from 'react'; import { css } from '@emotion/react'; +import ArticleBookmarkFilter from '../../components/Article/ArticleBookmarkFIlter'; +import { useGetFilteredArticleQuery } from '../../hooks/queries/article'; const CATEGORY_OPTIONS = [ { value: '전체보기', label: '전체보기' }, @@ -23,10 +25,22 @@ type CategoryOptions = typeof CATEGORY_OPTIONS[number]; const ArticleListPage = () => { const history = useHistory(); const goNewArticlePage = () => history.push(PATH.NEW_ARTICLE); - const [selectedOption, setSelectedOption] = useState(CATEGORY_OPTIONS[0]); + const [selectedCourse, setSelectedCourse] = useState(CATEGORY_OPTIONS[0]); + const [checked, setChecked] = useState(false); + + const { data: filteredArticles = [], refetch: getFilteredArticles } = useGetFilteredArticleQuery( + selectedCourse.value, + checked + ); const changeFilterOption: (option: { value: string; label: string }) => void = (option) => { - setSelectedOption(option); + setSelectedCourse(option); + // getFilteredArticles(); + }; + + const handleCheckBookmark: React.ChangeEventHandler = (e) => { + setChecked(e.currentTarget.checked); + // getFilteredArticles(); }; return ( @@ -35,12 +49,13 @@ const ArticleListPage = () => { + - + ); }; From 694c7b1e669c7cca70642a7543d0aa5e6aaafc78 Mon Sep 17 00:00:00 2001 From: hae-on Date: Mon, 18 Sep 2023 15:53:38 +0900 Subject: [PATCH 05/19] =?UTF-8?q?refactor:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 이도현 --- frontend/src/apis/articles.ts | 3 +-- frontend/src/mocks/handlers/articles.ts | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/apis/articles.ts b/frontend/src/apis/articles.ts index 4f4f8bd46..b2f1bace5 100644 --- a/frontend/src/apis/articles.ts +++ b/frontend/src/apis/articles.ts @@ -2,7 +2,6 @@ import { client } from '.'; import { ArticleBookmarkPutRequest, ArticleRequest, - CourseFilter, MetaOgRequest, MetaOgResponse, } from '../models/Article'; @@ -20,5 +19,5 @@ export const requestPutArticleBookmark = ({ articleId, bookmark }: ArticleBookma }; export const requestGetFilteredArticle = (course: string, bookmark: boolean) => { - return client.get(`/articles/filter?course=${course}&bookmark=${bookmark}`); + return client.get(`/articles/filter?course=${course}&onlyBookmarked=${bookmark}`); }; diff --git a/frontend/src/mocks/handlers/articles.ts b/frontend/src/mocks/handlers/articles.ts index 4ea38b898..441dae3e9 100644 --- a/frontend/src/mocks/handlers/articles.ts +++ b/frontend/src/mocks/handlers/articles.ts @@ -39,9 +39,11 @@ export const articlesHandler = [ rest.get(`${BASE_URL}/articles/filter`, (req, res, ctx) => { const course = req.url.searchParams.get('course'); - const bookmark = req.url.searchParams.get('bookmark'); + const onlyBookmarked = req.url.searchParams.get('onlyBookmarked'); - const filteredArticle = articles.filter((article) => bookmark === String(article.isBookMarked)); + const filteredArticle = articles.filter( + (article) => onlyBookmarked === String(article.isBookMarked) + ); return res(ctx.status(200), ctx.json(filteredArticle)); }), From 443bfcf8f2ed990a724c7814ef7a79daeaf4aac0 Mon Sep 17 00:00:00 2001 From: hae-on Date: Mon, 18 Sep 2023 15:54:43 +0900 Subject: [PATCH 06/19] =?UTF-8?q?refactor:=20useEffect=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=81=EB=A7=88=ED=81=AC,=20=ED=95=84=ED=84=B0=20=EC=98=B5?= =?UTF-8?q?=EC=85=98=20api=20=EB=B0=9B=EC=95=84=EC=98=A4=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 이도현 --- frontend/src/pages/ArticleListPage/index.tsx | 34 ++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/ArticleListPage/index.tsx b/frontend/src/pages/ArticleListPage/index.tsx index 2987f7870..bc0ec7f49 100644 --- a/frontend/src/pages/ArticleListPage/index.tsx +++ b/frontend/src/pages/ArticleListPage/index.tsx @@ -8,7 +8,7 @@ import { COLOR, PATH } from '../../constants'; import styled from '@emotion/styled'; import { MainContentStyle } from '../../PageRouter'; import SelectBox from '../../components/Controls/SelectBox'; -import { ChangeEventHandler, useState } from 'react'; +import { useEffect, useState } from 'react'; import { css } from '@emotion/react'; import ArticleBookmarkFilter from '../../components/Article/ArticleBookmarkFIlter'; import { useGetFilteredArticleQuery } from '../../hooks/queries/article'; @@ -35,27 +35,31 @@ const ArticleListPage = () => { const changeFilterOption: (option: { value: string; label: string }) => void = (option) => { setSelectedCourse(option); - // getFilteredArticles(); }; const handleCheckBookmark: React.ChangeEventHandler = (e) => { setChecked(e.currentTarget.checked); - // getFilteredArticles(); }; + useEffect(() => { + getFilteredArticles(); + }, [checked, selectedCourse]); + return (
- - - - + + + + + + + {isLoggedIn && ( + + )}
From b1a13d1270aeb2d90bfaffa6a46b2b670739a304 Mon Sep 17 00:00:00 2001 From: donghae-kim Date: Wed, 20 Sep 2023 17:41:17 +0900 Subject: [PATCH 18/19] =?UTF-8?q?refactor:=20=EC=95=84=ED=8B=B0=ED=81=B4?= =?UTF-8?q?=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20respon?= =?UTF-8?q?se=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../article/application/ArticleService.java | 15 ++++----------- .../article/domain/ArticleFilterType.java | 17 +++++++++++++++++ .../prolog/article/ui/ArticleController.java | 16 +++++----------- .../prolog/article/ui/ArticleResponse.java | 8 +++++--- .../prolog/common/WebConverterConfig.java | 6 +++--- .../article/application/ArticleServiceTest.java | 6 +++--- 6 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 backend/src/main/java/wooteco/prolog/article/domain/ArticleFilterType.java diff --git a/backend/src/main/java/wooteco/prolog/article/application/ArticleService.java b/backend/src/main/java/wooteco/prolog/article/application/ArticleService.java index 3f7ce7cfe..55ec503ce 100644 --- a/backend/src/main/java/wooteco/prolog/article/application/ArticleService.java +++ b/backend/src/main/java/wooteco/prolog/article/application/ArticleService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import wooteco.prolog.article.domain.Article; +import wooteco.prolog.article.domain.ArticleFilterType; import wooteco.prolog.article.domain.repository.ArticleRepository; import wooteco.prolog.article.ui.ArticleRequest; import wooteco.prolog.article.ui.ArticleResponse; @@ -12,7 +13,6 @@ import wooteco.prolog.login.ui.LoginMember; import wooteco.prolog.member.application.MemberService; import wooteco.prolog.member.domain.Member; -import wooteco.prolog.member.domain.MemberGroupType; import java.util.List; @@ -38,13 +38,6 @@ public Long create(final ArticleRequest articleRequest, final LoginMember loginM return articleRepository.save(article).getId(); } - public List getAll() { - return articleRepository.findAllByOrderByCreatedAtDesc() - .stream() - .map(ArticleResponse::from) - .collect(toList()); - } - @Transactional public void update(final Long id, final ArticleRequest articleRequest, final LoginMember loginMember) { @@ -82,15 +75,15 @@ public void bookmarkArticle(final Long id, final LoginMember loginMember, } } - public List filter(final LoginMember member, final MemberGroupType course, final boolean onlyBookmarked) { + public List getFilteredArticles(final LoginMember member, final ArticleFilterType course, final boolean onlyBookmarked) { if (member.isMember() && onlyBookmarked) { return articleRepository.findArticlesByCourseAndMember(course.getGroupName(), member.getId()).stream() - .map(ArticleResponse::from) + .map(article -> ArticleResponse.of(article,member.getId())) .collect(toList()); } return articleRepository.findArticlesByCourse(course.getGroupName()).stream() - .map(ArticleResponse::from) + .map(article -> ArticleResponse.of(article,member.getId())) .collect(toList()); } } diff --git a/backend/src/main/java/wooteco/prolog/article/domain/ArticleFilterType.java b/backend/src/main/java/wooteco/prolog/article/domain/ArticleFilterType.java new file mode 100644 index 000000000..8eddb65f6 --- /dev/null +++ b/backend/src/main/java/wooteco/prolog/article/domain/ArticleFilterType.java @@ -0,0 +1,17 @@ +package wooteco.prolog.article.domain; + +import lombok.Getter; + +@Getter +public enum ArticleFilterType { + ALL(""), + ANDROID("안드로이드"), + BACKEND("백엔드"), + FRONTEND("프론트엔드"); + + private final String groupName; + + ArticleFilterType(String groupName) { + this.groupName = groupName; + } +} diff --git a/backend/src/main/java/wooteco/prolog/article/ui/ArticleController.java b/backend/src/main/java/wooteco/prolog/article/ui/ArticleController.java index 8c5fa5e26..2ac381fd9 100644 --- a/backend/src/main/java/wooteco/prolog/article/ui/ArticleController.java +++ b/backend/src/main/java/wooteco/prolog/article/ui/ArticleController.java @@ -12,9 +12,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import wooteco.prolog.article.application.ArticleService; +import wooteco.prolog.article.domain.ArticleFilterType; import wooteco.prolog.login.domain.AuthMemberPrincipal; import wooteco.prolog.login.ui.LoginMember; -import wooteco.prolog.member.domain.MemberGroupType; import java.net.URI; import java.util.List; @@ -33,12 +33,6 @@ public ResponseEntity createArticles(@RequestBody final ArticleRequest art return ResponseEntity.created(URI.create("/articles/" + id)).build(); } - @GetMapping - public ResponseEntity> getArticles() { - final List allArticles = articleService.getAll(); - return ResponseEntity.ok(allArticles); - } - @PutMapping("/{id}") public ResponseEntity updateArticle(@RequestBody final ArticleRequest articleRequest, @AuthMemberPrincipal final LoginMember member, @@ -62,11 +56,11 @@ public ResponseEntity bookmarkArticle(@PathVariable final Long id, return ResponseEntity.ok().build(); } - @GetMapping("/filter") - public ResponseEntity> filterArticles(@AuthMemberPrincipal final LoginMember member, - @RequestParam("course") final MemberGroupType course, + @GetMapping + public ResponseEntity> getFilteredArticles(@AuthMemberPrincipal final LoginMember member, + @RequestParam("course") final ArticleFilterType course, @RequestParam("onlyBookmarked") boolean onlyBookmarked) { - final List articleResponses = articleService.filter(member, course, onlyBookmarked); + final List articleResponses = articleService.getFilteredArticles(member, course, onlyBookmarked); return ResponseEntity.ok(articleResponses); } diff --git a/backend/src/main/java/wooteco/prolog/article/ui/ArticleResponse.java b/backend/src/main/java/wooteco/prolog/article/ui/ArticleResponse.java index 6d79c7943..19d398ca5 100644 --- a/backend/src/main/java/wooteco/prolog/article/ui/ArticleResponse.java +++ b/backend/src/main/java/wooteco/prolog/article/ui/ArticleResponse.java @@ -16,20 +16,22 @@ public class ArticleResponse { private final String title; private final String url; private final String imageUrl; + private final boolean isBookmarked; @JsonFormat(pattern = "yyyy-MM-dd HH:mm") private final LocalDateTime createdAt; private ArticleResponse() { - this(null, null, null, null, null, null); + this(null, null, null, null, null, false, null); } - public static ArticleResponse from(final Article article) { + public static ArticleResponse of(final Article article, final Long memberId) { final Long id = article.getId(); final String nickName = article.getMember().getNickname(); final String title = article.getTitle().getTitle(); final String url = article.getUrl().getUrl(); final String imageUrl = article.getImageUrl().getUrl(); + final boolean isBookmarked = article.getArticleBookmarks().containBookmark(memberId); final LocalDateTime createdAt = article.getCreatedAt(); - return new ArticleResponse(id, nickName, title, url, imageUrl, createdAt); + return new ArticleResponse(id, nickName, title, url, imageUrl, isBookmarked, createdAt); } } diff --git a/backend/src/main/java/wooteco/prolog/common/WebConverterConfig.java b/backend/src/main/java/wooteco/prolog/common/WebConverterConfig.java index d7d157281..c0277be27 100644 --- a/backend/src/main/java/wooteco/prolog/common/WebConverterConfig.java +++ b/backend/src/main/java/wooteco/prolog/common/WebConverterConfig.java @@ -3,7 +3,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import wooteco.prolog.member.domain.MemberGroupType; +import wooteco.prolog.article.domain.ArticleFilterType; import java.time.LocalDate; import java.time.Month; @@ -21,8 +21,8 @@ public void addFormatters(FormatterRegistry registry) { source -> LocalDate.parse(source, DateTimeFormatter.BASIC_ISO_DATE) ); - registry.addConverter(String.class, MemberGroupType.class, - source -> MemberGroupType.valueOf(source.toUpperCase()) + registry.addConverter(String.class, ArticleFilterType.class, + source -> ArticleFilterType.valueOf(source.toUpperCase()) ); } } diff --git a/backend/src/test/java/wooteco/prolog/article/application/ArticleServiceTest.java b/backend/src/test/java/wooteco/prolog/article/application/ArticleServiceTest.java index 00b94cb45..1d5c4a366 100644 --- a/backend/src/test/java/wooteco/prolog/article/application/ArticleServiceTest.java +++ b/backend/src/test/java/wooteco/prolog/article/application/ArticleServiceTest.java @@ -10,6 +10,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import wooteco.prolog.article.domain.Article; import wooteco.prolog.article.domain.ArticleBookmarks; +import wooteco.prolog.article.domain.ArticleFilterType; import wooteco.prolog.article.domain.ImageUrl; import wooteco.prolog.article.domain.Title; import wooteco.prolog.article.domain.Url; @@ -20,7 +21,6 @@ import wooteco.prolog.login.ui.LoginMember; import wooteco.prolog.member.application.MemberService; import wooteco.prolog.member.domain.Member; -import wooteco.prolog.member.domain.MemberGroupType; import wooteco.prolog.member.domain.Role; import java.util.Arrays; @@ -251,7 +251,7 @@ void filter() { when(articleRepository.findArticlesByCourse(any())).thenReturn(Arrays.asList(article)); //when - final List articleResponses = articleService.filter(unLoginMember, MemberGroupType.BACKEND, false); + final List articleResponses = articleService.getFilteredArticles(unLoginMember, ArticleFilterType.BACKEND, false); //then verify(articleRepository).findArticlesByCourse(any()); @@ -269,7 +269,7 @@ void filter_isBookmarked() { when(articleRepository.findArticlesByCourseAndMember(any(), any())).thenReturn(Arrays.asList(article)); //when - final List articleResponses = articleService.filter(loginMember, MemberGroupType.BACKEND, true); + final List articleResponses = articleService.getFilteredArticles(loginMember, ArticleFilterType.BACKEND, true); //then verify(articleRepository).findArticlesByCourseAndMember(any(), any()); From d9501c1c4b430581cfc514aea0552043f449523b Mon Sep 17 00:00:00 2001 From: hae-on Date: Wed, 20 Sep 2023 17:43:19 +0900 Subject: [PATCH 19/19] =?UTF-8?q?refactor:=20msw=20filtering=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/db/articles-android.json | 29 +++++++++++ frontend/src/mocks/db/articles-backend.json | 29 +++++++++++ frontend/src/mocks/db/articles-frontend.json | 29 +++++++++++ frontend/src/mocks/db/articles.json | 51 ++++++++++++++++++-- frontend/src/mocks/handlers/articles.ts | 32 ++++++++---- 5 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 frontend/src/mocks/db/articles-android.json create mode 100644 frontend/src/mocks/db/articles-backend.json create mode 100644 frontend/src/mocks/db/articles-frontend.json diff --git a/frontend/src/mocks/db/articles-android.json b/frontend/src/mocks/db/articles-android.json new file mode 100644 index 000000000..865954a4c --- /dev/null +++ b/frontend/src/mocks/db/articles-android.json @@ -0,0 +1,29 @@ +[ + { + "id": 7, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" + }, + { + "id": 8, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" + }, + { + "id": 9, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" + } +] diff --git a/frontend/src/mocks/db/articles-backend.json b/frontend/src/mocks/db/articles-backend.json new file mode 100644 index 000000000..f3fdaae4c --- /dev/null +++ b/frontend/src/mocks/db/articles-backend.json @@ -0,0 +1,29 @@ +[ + { + "id": 4, + "userName": "패트릭", + "title": "CORS", + "isBookMarked": 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" + }, + { + "id": 5, + "userName": "패트릭", + "title": "CORS", + "isBookMarked": true, + "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" + }, + { + "id": 6, + "userName": "패트릭", + "title": "CORS", + "isBookMarked": true, + "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" + } +] diff --git a/frontend/src/mocks/db/articles-frontend.json b/frontend/src/mocks/db/articles-frontend.json new file mode 100644 index 000000000..d7da0c5e8 --- /dev/null +++ b/frontend/src/mocks/db/articles-frontend.json @@ -0,0 +1,29 @@ +[ + { + "id": 1, + "userName": "해온", + "title": "Axios", + "isBookMarked": true, + "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" + }, + { + "id": 2, + "userName": "해온", + "title": "Axios", + "isBookMarked": true, + "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" + }, + { + "id": 3, + "userName": "해온", + "title": "Axios", + "isBookMarked": true, + "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" + } +] diff --git a/frontend/src/mocks/db/articles.json b/frontend/src/mocks/db/articles.json index 182d5e558..35b46c204 100644 --- a/frontend/src/mocks/db/articles.json +++ b/frontend/src/mocks/db/articles.json @@ -10,6 +10,24 @@ }, { "id": 2, + "userName": "해온", + "title": "Axios", + "isBookMarked": true, + "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" + }, + { + "id": 3, + "userName": "해온", + "title": "Axios", + "isBookMarked": true, + "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" + }, + { + "id": 4, "userName": "패트릭", "title": "CORS", "isBookMarked": false, @@ -18,7 +36,7 @@ "imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60" }, { - "id": 3, + "id": 5, "userName": "패트릭", "title": "CORS", "isBookMarked": true, @@ -27,12 +45,39 @@ "imageUrl": "https://plus.unsplash.com/premium_photo-1682088845396-1b310a002302?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJTk1JTg0JUVEJThCJUIwJUVEJTgxJUI0fGVufDB8fDB8fHww&auto=format&fit=crop&w=500&q=60" }, { - "id": 4, + "id": 6, "userName": "패트릭", "title": "CORS", - "isBookMarked": false, + "isBookMarked": true, "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" + }, + { + "id": 7, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" + }, + { + "id": 8, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" + }, + { + "id": 9, + "userName": "도밥", + "title": "직렬화, 역직렬화는 무엇일까?", + "url": "https://think0wise.tistory.com/107", + "createdAt": "2023-07-08 16:48", + "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" } ] diff --git a/frontend/src/mocks/handlers/articles.ts b/frontend/src/mocks/handlers/articles.ts index 2302996cc..6571fa4fa 100644 --- a/frontend/src/mocks/handlers/articles.ts +++ b/frontend/src/mocks/handlers/articles.ts @@ -1,15 +1,18 @@ import { rest } from 'msw'; import { BASE_URL } from '../../configs/environment'; import articles from '../db/articles.json'; +import articlesFrontend from '../db/articles-frontend.json'; +import articlesBackend from '../db/articles-backend.json'; +import articlesAndroid from '../db/articles-android.json'; import metaOg from '../db/metaog.json'; 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}/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; @@ -37,13 +40,24 @@ export const articlesHandler = [ return res(ctx.status(200)); }), - rest.get(`${BASE_URL}/articles/`, (req, res, ctx) => { - const course = req.url.searchParams.get('course'); - const onlyBookmarked = req.url.searchParams.get('onlyBookmarked'); + 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; + + const filteredCourse = (course: string) => { + if (course === 'all') return articles; + if (course === 'frontend') return articlesFrontend; + if (course === 'backend') return articlesBackend; + if (course === 'android') return articlesAndroid; + }; + + if (onlyBookmarked === 'false') { + return res(ctx.status(200), ctx.json(filteredCourse(course))); + } - const filteredArticle = articles.filter( - (article) => onlyBookmarked === String(article.isBookMarked) - ); + const filteredArticle = filteredCourse(course)?.filter((article) => { + return onlyBookmarked === String(article.isBookMarked) ? true : false; + }); return res(ctx.status(200), ctx.json(filteredArticle)); }),