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

[FE] feat: 리뷰 목록 페이지 기능 구현 #90

Merged
merged 20 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9c72fb9
fix: stylelint를 통한 css 속성 정렬 기능 오류 수정
BadaHertz52 Jul 20, 2024
e3e33a6
refactor: stylelint 적용에 따른 css 속성 정렬
BadaHertz52 Jul 20, 2024
ee8b83d
Merge branch 'feat/71-detailed_review_page' of https://github.com/woo…
BadaHertz52 Jul 23, 2024
0a2ab6a
fix : 절대 경로 사용 시 오류 수정
BadaHertz52 Jul 23, 2024
6a51f29
Merge branch 'develop' of https://github.com/woowacourse-teams/2024-r…
BadaHertz52 Jul 23, 2024
8750b3f
chore: eslintrc.cjs 에서 불필요한 코드 삭제
BadaHertz52 Jul 23, 2024
79d1054
feat: DropDown 컴포넌트 구현
soosoo22 Jul 23, 2024
2ccd546
chore: svg 아이콘 크기 수정
soosoo22 Jul 24, 2024
aeeace5
design: Topbar UI 수정
soosoo22 Jul 24, 2024
e71caf1
design: 버튼, 검색창 UI 수정 후 export
soosoo22 Jul 24, 2024
f67438e
feat: ReviewPreviewCard 컴포넌트 구현
soosoo22 Jul 24, 2024
d71ed5f
chore: ReviewPreview 인터페이스 추가
soosoo22 Jul 24, 2024
aac2762
feat: SearchSection 컴포넌트 구현
soosoo22 Jul 24, 2024
163726e
feat: ReviewPreviewListPage 구현 및 모의 데이터 추가
soosoo22 Jul 24, 2024
af2de05
chore: import 중복 및 순서 정리, ReviewPreviewListPage 라우트 추가
soosoo22 Jul 24, 2024
26fb5d7
chore: 여러 개의 요소를 감싸기 때문에 Container로 변경
soosoo22 Jul 25, 2024
042e646
feat: 리뷰 목록 데이터를 서버에서 가져오기 위해 getReviewListApi 함수 추가
soosoo22 Jul 25, 2024
a0aba88
refactor: 상세 리뷰 불러오기 api 엔드포인트 수정
soosoo22 Jul 25, 2024
daee123
refactor: 상세 리뷰 페이지 API 연동 부분 수정
soosoo22 Jul 25, 2024
368870a
Merge branch 'develop' into fe/feat/73-review-list-page
soosoo22 Jul 25, 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
6 changes: 4 additions & 2 deletions frontend/src/apis/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const endPoint = {
postingReview: `${process.env.API_BASE_URL}reviews`,
postingReview: `${process.env.API_BASE_URL}/reviews`,
gettingDetailedReview: (reviewId: number, memberId: number) =>
`${process.env.API_BASE_URL}reviews/${reviewId}?memberId=${memberId}`,
`${process.env.API_BASE_URL}/reviews/${reviewId}?memberId=${memberId}`,
gettingReviewList: (revieweeId: number, lastReviewId: number, memberId: number) =>
`${process.env.API_BASE_URL}/reviews?revieweeId=${revieweeId}&lastReviewId=${lastReviewId}&memberId=${memberId}`,
gettingInfoToWriteReview: (reviewerGroupId: number) => `/reviewer-groups/${reviewerGroupId}`,
gettingKeyword: `${process.env.API_BASE_URL}keywords`,
};
Expand Down
30 changes: 29 additions & 1 deletion frontend/src/apis/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const postReviewApi = async ({ reviewData }: { reviewData: ReviewData })
return data;
};

// 상세리뷰
// 상세 리뷰
export const getDetailedReviewApi = async ({ reviewId, memberId }: { reviewId: number; memberId: number }) => {
const response = await fetch(endPoint.gettingDetailedReview(reviewId, memberId), {
method: 'GET',
Expand All @@ -49,3 +49,31 @@ export const getDetailedReviewApi = async ({ reviewId, memberId }: { reviewId: n
const data = await response.json();
return data;
};

// 리뷰 리스트
export const getReviewListApi = async ({
revieweeId,
lastReviewId,
memberId,
}: {
revieweeId: number;
lastReviewId: number;
memberId: number;
}) => {
const response = await fetch(
`/api/reviews?revieweeId=${revieweeId}&lastReviewId=${lastReviewId}&memberId=${memberId}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
},
);

if (!response.ok) {
throw new Error('리뷰 리스트를 불러오는 데 실패했습니다.');
}

const data = await response.json();
return data;
};
4 changes: 2 additions & 2 deletions frontend/src/assets/lock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/src/assets/unLock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions frontend/src/components/ReviewPreviewCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import GithubLogo from '@/assets/githubLogo.svg';
import Lock from '@/assets/lock.svg';
import UnLock from '@/assets/unLock.svg';

import * as S from './styles';

interface ReviewPreviewCardProps {
reviewerGroup: {
name: string;
};
createdAt: string;
contentPreview: string;
keywords: { id: number; content: string }[];
Copy link
Contributor

Choose a reason for hiding this comment

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

키워드 관련 타입이나 인터페이스는 따로 없나요? 리터럴을 의도했다면 그 이유가 궁금해요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

키워드 인터페이스가 정의되어 있네요~~
아래와 같이 수정했어요~~

export interface Keyword {
  id: number;
  content: string;
}

export interface ReviewPreview {
  id: number;
  isPublic: boolean;
  reviewerGroup: {
    id: number;
    name: string;
    thumbnailUrl: string;
  };
  createdAt: string;
  contentPreview: string;
  keywords: Keyword[];
}

isPublic: boolean;
}

const ReviewPreviewCard = ({
reviewerGroup,
createdAt,
contentPreview,
keywords,
isPublic,
}: ReviewPreviewCardProps) => {
return (
<S.Layout>
<S.Header>
<S.HeaderContainer>
Copy link
Contributor

Choose a reason for hiding this comment

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

HeaderContainer가 Header보다 상위에 있는 네이밍이라고 생각해요.
컴포넌트 트리상 Header가 HeaderContainer 의 부모 컴포넌트라서 네이밍상 안맞는 느낌이 드네요. 쑤쑤의 생각은 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

생각해보니 HeaderContainerHeader보다 하위에 있는 부분이 어색하네요.

HeaderContent로 바꾸어 볼게요~

<Layout>
 <Header>
  <HeaderContent />
 </Header>
 <Main />
</Layout>

<div>
<img src={GithubLogo} />
</div>
<div>
<S.Title>{reviewerGroup.name}</S.Title>
<S.SubTitle>{createdAt}</S.SubTitle>
</div>
</S.HeaderContainer>
<S.Visibility>
<img src={isPublic ? UnLock : Lock} />
Copy link
Contributor

Choose a reason for hiding this comment

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

img 태그에 접근성도 챙겨주면 좋을 것 같아요!

Copy link
Contributor

Choose a reason for hiding this comment

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

img에 alt가 없네요

<span>{isPublic ? '공개' : '비공개'}</span>
</S.Visibility>
</S.Header>
<S.Main>
<span>{contentPreview}</span>
<S.Keyword>
{keywords.map((keyword) => (
<div key={keyword.id}>{keyword.content}</div>
))}
</S.Keyword>
</S.Main>
</S.Layout>
);
};

export default ReviewPreviewCard;
85 changes: 85 additions & 0 deletions frontend/src/components/ReviewPreviewCard/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import styled from '@emotion/styled';

export const Layout = styled.div`
display: flex;
flex-direction: column;

width: 100%;

border: 1px solid ${({ theme }) => theme.colors.lightGray};
border-radius: 8px;

&:hover {
cursor: pointer;
border: 1px solid ${({ theme }) => theme.colors.primaryHover};

& > div:first-of-type {
background-color: ${({ theme }) => theme.colors.primaryHover};
}
}
`;

export const Header = styled.div`
display: flex;
justify-content: space-between;

height: 6rem;
padding: 1rem 3rem;

background-color: ${({ theme }) => theme.colors.lightGray};
border-top-left-radius: 0.8rem;
border-top-right-radius: 0.8rem;
Comment on lines +30 to +31
Copy link
Contributor

Choose a reason for hiding this comment

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

border-radius: 0.8rem 0.8rem 0 0;으로 한 번에 표시해줄 수 있을 것 같아요 :)

`;

export const HeaderContainer = styled.div`
display: flex;
gap: 1rem;

img {
width: 4rem;
}
`;

export const Title = styled.div`
font-size: 1.6rem;
font-weight: 700;
`;

export const SubTitle = styled.div`
font-size: 1.2rem;
`;

export const Visibility = styled.div`
display: flex;
gap: 0.6rem;
align-items: center;
font-size: 1.6rem;
font-weight: 700;

img {
width: 2rem;
}
`;

export const Main = styled.div`
display: flex;
flex-direction: column;
gap: 2rem;

padding: 2rem 3rem;

font-size: 1.6rem;
`;

export const Keyword = styled.div`
display: flex;
gap: 3rem;
align-items: center;
font-size: 1.4rem;

div {
padding: 0.5rem 3rem;
background-color: ${({ theme }) => theme.colors.primaryHover};
border-radius: 0.8rem;
}
`;
2 changes: 1 addition & 1 deletion frontend/src/components/common/Button/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const Button = styled.button<{ buttonType: ButtonType }>`

width: 10rem;
height: 4rem;
padding: 2rem;
padding: 1rem 2rem;

border: 0.1rem solid ${({ theme }) => theme.colors.primary};
border-radius: 0.8rem;
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/components/common/DropDown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as S from './styles';

interface DropDownProps {
onChange: (value: string) => void;
options: string[];
}

const DropDown = ({ onChange, options }: DropDownProps) => {
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
onChange(e.target.value);
};

return (
<S.Container onChange={handleChange}>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</S.Container>
);
};

export default DropDown;
11 changes: 11 additions & 0 deletions frontend/src/components/common/DropDown/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from '@emotion/styled';

export const Container = styled.select`
width: 12rem;
padding: 8px;
Copy link
Contributor

Choose a reason for hiding this comment

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

잡았다'px'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

아이고😅


font-size: 1.6rem;

border: 1px solid ${({ theme }) => theme.colors.placeholder};
border-radius: 0.8rem;
`;
7 changes: 6 additions & 1 deletion frontend/src/components/common/SearchInput/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ export const Input = styled.input<InputProps>`
padding: 1.6rem;

border: 1px solid ${({ theme }) => theme.colors.black};
border-radius: 1.5rem;
border-radius: 0.8rem;

&::placeholder {
Copy link
Contributor

Choose a reason for hiding this comment

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

placeholder를 따로 스타일링할 수 있군요!
몰라서 따로 스타일 설정을 못 했는데 하나 배워가요😊😊

font-size: 1.2rem;
color: ${({ theme }) => theme.colors.placeholder};
}
`;
2 changes: 2 additions & 0 deletions frontend/src/components/common/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { default as Button } from './Button';
export { default as DropDown } from './DropDown';
export { default as SearchInput } from './SearchInput';
export { default as ProjectImg } from './ProjectImg';
export { default as ReviewDate } from './ReviewDate';
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/layouts/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import * as S from './styles';
const PATH = {
myPage: '/user/mypage',
reviewWriting: '/user/review-writing',
allReview: '/user/all-review',
detailedReview: '/user/detailed-review/0?memberId=1',
reviewPreviewList: '/user/review-preview-list',
detailedReview: '/user/detailed-review',
reviewGroupManagement: '/user/review-group-management',
};

Expand All @@ -25,7 +25,7 @@ const Sidebar = ({ isSidebarOpen, closeSidebar }: SidebarProps) => {
const menuItems = [
{ path: PATH.myPage, label: PAGE.myPage },
{ path: PATH.reviewWriting, label: PAGE.reviewWriting },
{ path: PATH.allReview, label: PAGE.allReview },
{ path: PATH.reviewPreviewList, label: PAGE.reviewPreviewList },
{ path: PATH.detailedReview, label: PAGE.detailedReview },
{ path: PATH.reviewGroupManagement, label: PAGE.reviewGroupManagement },
];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import styled from '@emotion/styled';

export const HamburgerButton = styled.button`
width: 3.7rem;
height: 3.7rem;
width: 2.3rem;
height: 2.3rem;

img {
width: 100%;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/layouts/Topbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Topbar = ({ openSidebar }: TopbarProps) => {
<Logo />
</S.Container>
<S.Container>
<SearchInput $width="15rem" $height="3.6rem" placeholder={USER_SEARCH_PLACE_HOLDER} />
<SearchInput $width="30rem" $height="3.6rem" placeholder={USER_SEARCH_PLACE_HOLDER} />
<S.UserProfile src={UserProfileIcon} alt="로그인한 사용자 깃허브 프로필" />
</S.Container>
</S.Layout>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/layouts/Topbar/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export const Layout = styled.section`

box-sizing: border-box;
width: 100%;
height: 8rem;
padding: 1.8rem 2.5rem;
height: 7rem;
padding: 2rem 2.5rem;

border-bottom: 0.1rem solid ${({ theme }) => theme.colors.lightGray};
`;

export const Container = styled.div`
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/constants/page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const PAGE = {
myPage: '마이페이지',
reviewWriting: '리뷰 작성하기',
allReview: '전체 리뷰 보기',
reviewPreviewList: '전체 리뷰 보기',
detailedReview: '상세 리뷰 보기',
reviewGroupManagement: '리뷰 그룹 관리',
};
8 changes: 4 additions & 4 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App from '@/App';

import DetailedReviewPage from './pages/DetailedReviewPage';
import ReviewPreviewListPage from './pages/ReviewPreviewListPage';
import ReviewWritingPage from './pages/ReviewWriting';
import ReviewWritingCompletePage from './pages/ReviewWritingCompletePage';
import globalStyles from './styles/globalStyles';
import theme from './styles/theme';

Expand All @@ -25,11 +25,11 @@ const router = createBrowserRouter([
element: <ReviewWritingPage />,
},
{
path: 'user/review-writing-complete',
element: <ReviewWritingCompletePage />,
path: 'user/review-preview-list',
element: <ReviewPreviewListPage />,
},
{
path: 'user/detailed-review/:id',
path: 'user/detailed-review',
element: <DetailedReviewPage />,
},
],
Expand Down
Loading