Skip to content

Commit

Permalink
미션 제출 페이지 스타일링 조정 (issue #353) (#357)
Browse files Browse the repository at this point in the history
* remove: front cd yml 파일 삭제 (#341)

* 로그아웃 뮤테이션 생성 및 제출시 로직 개선 (issue #306) (#327)

* feat: 로그아웃 관련 뮤테이션 생성

* refactor: useModal 리팩토링

* refactor: 불필요한 주석 제거

* fix: 미션 제출 후 새로고침 로직 개선

* refactor: 대쉬보드 프로필 레이아웃 수정

* refactor: description null값도 보낼수 있도록 수정

* refactor: 미션명 검증 섹션 추가

* fix: 린트 disable

* refactor: 수정사항 반영

* 해시태그 버튼 및 필터링 구현 (issue #303) (#332)

* feat: 미션 리스트 필터링 기능 구현

* refactor: 미션 호출 api의 url 분리 및 queryKey에 filter 추가

* fix: hashTagButton 충돌 해결

* feat: 전체 데이터 불러오는 'all'로 변경, HashTag 필터링 mock data 임시 구현

* feat: 솔루션 필터링 적용, useSolutions를 useSolutionSummaries로 변경

* design: 솔루션 리스트 디자인 수정

* design: 미션리스트 디자인 수정

* feat: api 배포에 따른 mock data 제거

* test: useMissions 필터링 기능 테스트 코드 추가

* design: 미션, 솔루션 리스트 렌더링 시 애니메이션 효과 적용

* refactor: 'all'을 상수로 변경

* refactor: useToggleHashTag 제거 및 해시태그 토글 상태 추가

* chore: 개발 환경과 배포환경에 따른 백엔드 API 경로 수정 (#344)

* fix: 대시보드 렌더링 분기처리 오류 수정 (#346)

* design: 미션 제출 페이지 중앙 정렬

---------

Co-authored-by: Minji <[email protected]>
  • Loading branch information
brgndyy and chosim-dvlpr committed Aug 21, 2024
1 parent c40d13e commit 68ae00c
Show file tree
Hide file tree
Showing 37 changed files with 498 additions and 164 deletions.
67 changes: 0 additions & 67 deletions .github/workflows/front_cd.yml

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/apis/baseUrl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const BASE_URL = {
dev: 'https://api.devel-up.co.kr',
dev: 'https://dev.api.devel-up.co.kr',
prod: 'https://api.devel-up.co.kr',
} as const;
26 changes: 22 additions & 4 deletions frontend/src/apis/missionAPI.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { develupAPIClient } from './clients/develupClient';
import { PATH } from './paths';
import type { Mission, SubmissionPayload, Submission, MissionWithDescription } from '@/types';
// import type { MissionInProgress } from '@/types/mission';
import type {
Mission,
MissionWithDescription,
SubmissionPayload,
Submission,
HashTag,
} from '@/types';
import MissionListInProgress from '@/mocks/missionInProgress.json';
import { populateMissionDescription } from './utils/populateMissionDescription';
import { HASHTAGS } from '@/constants/hashTags';

interface getMissionByIdResponse {
data: MissionWithDescription;
Expand All @@ -13,8 +19,14 @@ interface getAllMissionResponse {
data: Mission[];
}

export const getAllMissions = async (): Promise<Mission[]> => {
const { data } = await develupAPIClient.get<getAllMissionResponse>(PATH.missionList);
interface getHashTagsResponse {
data: HashTag[];
}

export const getMissions = async (filter: string = HASHTAGS.all): Promise<Mission[]> => {
const { data } = await develupAPIClient.get<getAllMissionResponse>(`${PATH.missionList}`, {
hashTag: filter,
});

return data;
};
Expand Down Expand Up @@ -49,3 +61,9 @@ export const postSubmission = async (payload: SubmissionPayload) => {

return data;
};

export const getHashTags = async (): Promise<HashTag[]> => {
const { data } = await develupAPIClient.get<getHashTagsResponse>(PATH.hashTags);

return data;
};
1 change: 1 addition & 0 deletions frontend/src/apis/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const PATH = {
submitSolution: '/solutions/submit',
startSolution: '/solutions/start',
logout: '/auth/logout',
hashTags: '/hash-tags',
missionInProgress: '/missions/in-progress',
};

Expand Down
12 changes: 9 additions & 3 deletions frontend/src/apis/solutions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { develupAPIClient } from '@/apis/clients/develupClient';
import { PATH } from '@/apis/paths';
import { HASHTAGS } from '@/constants/hashTags';
import SubmittedSolutions from '@/mocks/SubmittedSolutions.json';
import type { HashTag } from '@/types/mission';
import type { HashTag } from '@/types';
import type { Solution, SubmittedSolution } from '@/types/solution';

export interface SolutionSummary {
Expand All @@ -17,8 +18,13 @@ interface GetSolutionSummariesResponse {
data: SolutionSummary[];
}

export const getSolutionSummaries = async (): Promise<SolutionSummary[]> => {
const { data } = await develupAPIClient.get<GetSolutionSummariesResponse>(PATH.solutionSummaries);
export const getSolutionSummaries = async (
filter: string = HASHTAGS.all,
): Promise<SolutionSummary[]> => {
const { data } = await develupAPIClient.get<GetSolutionSummariesResponse>(
`${PATH.solutionSummaries}`,
{ hashTag: filter },
);

return data;
};
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/components/HashTagList/HashTagList.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import styled from 'styled-components';

export const HashTagListContainer = styled.ul`
display: flex;
flex-direction: row;
gap: 1.5rem;
flex-wrap: wrap;
`;
33 changes: 33 additions & 0 deletions frontend/src/components/HashTagList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { HashTag } from '@/types';
import HashTagButton from '../common/HashTagButton';
import * as S from './HashTagList.styled';
import { HASHTAGS } from '@/constants/hashTags';

interface HashTagListProps {
hashTags: HashTag[];
selectedHashTag: string;
setSelectedHashTag: (name: string) => void;
}

export default function HashTagList({
hashTags,
selectedHashTag,
setSelectedHashTag,
}: HashTagListProps) {
return (
<S.HashTagListContainer>
{hashTags.map(({ id, name }) => {
const isSelected = name === selectedHashTag;
return (
<HashTagButton
isSelected={isSelected}
onClick={() => setSelectedHashTag(isSelected ? HASHTAGS.all : name)}
key={id}
>
{name}
</HashTagButton>
);
})}
</S.HashTagListContainer>
);
}
16 changes: 10 additions & 6 deletions frontend/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Link, useLocation } from 'react-router-dom';
import * as S from './Header.styled';
import { ROUTES } from '@/constants/routes';
import NotiModal from './NotiModal';
import { BASE_URL } from '@/apis/baseUrl';
import { PATH } from '@/apis/paths';
import useUserInfo from '@/hooks/useUserInfo';
import HeaderMenu from './HeaderMenu';
import { deleteLogout } from '@/apis/authAPI';
import useLogoutMutation from '@/hooks/useLogoutMutation';
import useModal from '@/hooks/useModal';

export default function Header() {
const { pathname } = useLocation();
const { data: userInfo } = useUserInfo();

const handleUserLogout = async () => {
await deleteLogout();
};
const { handleUserLogout } = useLogoutMutation();
const { isModalOpen, handleModalClose, handleToggleModal } = useModal();

return (
<>
Expand All @@ -28,7 +28,10 @@ export default function Header() {
<HeaderMenu name="솔루션" path={ROUTES.solutions} currentPath={pathname} />
</S.MenuWrapper>
<S.RightPart>
<HeaderMenu name="대시보드" path={ROUTES.dashboardHome} currentPath={pathname} />
{userInfo && <S.BellIcon onClick={handleToggleModal} />}
{userInfo && (
<HeaderMenu name="대시보드" path={ROUTES.dashboardHome} currentPath={pathname} />
)}
{!userInfo ? (
<a href={`${BASE_URL.dev}${PATH.githubLogin}?next=${pathname}`}>
<S.LoginButton>로그인</S.LoginButton>
Expand All @@ -38,6 +41,7 @@ export default function Header() {
)}
</S.RightPart>
</S.Container>
{isModalOpen && <NotiModal closeModal={handleModalClose} />}
<S.Spacer />
</>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Mission/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { PropsWithChildren } from 'react';
import * as S from './Mission.styled';
import { Link } from 'react-router-dom';
import type { HashTag } from '@/types/mission';
import type { HashTag } from '@/types';

interface MissionProps extends PropsWithChildren {
id: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export const HashTagWrapper = styled.ul`

export const MissionDetailButtonsContainer = styled.div`
display: flex;
gap: 2rem;
justify-content: space-between;
align-items: center;
`;
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/components/MissionList/MissionList.styled.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled from 'styled-components';
import styled, { keyframes } from 'styled-components';

export const MissionListContainer = styled.div`
display: flex;
Expand All @@ -15,11 +15,24 @@ export const MissionListTitle = styled.h2`
margin-bottom: 3rem;
`;

const show = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;

export const MissionList = styled.div`
display: flex;
width: 100rem;
column-gap: 5rem;
row-gap: 3.6rem;
animation: ${show} 0.5s;
transition: 0.5s;
`;

export const MissionItemContainer = styled.article`
Expand Down
16 changes: 2 additions & 14 deletions frontend/src/components/MissionSubmit/SubmitButton.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import * as S from './SubmitButton.styled';
import type { ButtonHTMLAttributes } from 'react';
import { useNavigate } from 'react-router-dom';
import { ROUTES } from '@/constants/routes';

interface SubmitButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {}

export default function SubmitButton({ ...props }: SubmitButtonProps) {
const navigate = useNavigate();
const handleNavigateToSubmit = () => {
navigate(`${ROUTES.solutions}`);
};

export default function SubmitButton() {
return (
<S.Container>
<S.Button type="submit" onClick={handleNavigateToSubmit} {...props}>
제출
</S.Button>
<S.Button type="submit">제출</S.Button>
</S.Container>
);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import styled from 'styled-components';

export const Button = styled.div`
background-color: ${(props) => props.theme.colors.primary50};
color: ${(props) => props.theme.colors.black};
interface ButtonProps {
$isSelected: boolean;
}

export const Button = styled.button<ButtonProps>`
background-color: ${(props) =>
props.$isSelected ? props.theme.colors.primary100 : props.theme.colors.primary50};
color: var(--black-color);
transition: 0.2s;
padding: 1rem 1.6rem;
border-radius: 2rem;
display: flex;
justify-content: center;
align-items: center;
${(props) => props.theme.font.badge}
padding: 1rem 1.6rem;
border-radius: 2rem;
&:hover {
background-color: ${(props) =>
props.$isSelected ? props.theme.colors.primary200 : props.theme.colors.primary100};
}
`;
18 changes: 15 additions & 3 deletions frontend/src/components/common/HashTagButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import type { PropsWithChildren } from 'react';
import type { HTMLAttributes, PropsWithChildren } from 'react';
import * as S from './HashTagButton.styled';

export default function HashTagButton({ children }: PropsWithChildren) {
return <S.Button>{children}</S.Button>;
interface HashTagButtonProps extends HTMLAttributes<HTMLButtonElement> {
isSelected?: boolean;
}

export default function HashTagButton({
isSelected = false,
children,
...props
}: PropsWithChildren<HashTagButtonProps>) {
return (
<S.Button $isSelected={isSelected} {...props}>
{children}
</S.Button>
);
}
3 changes: 3 additions & 0 deletions frontend/src/constants/hashTags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const HASHTAGS = {
all: 'all',
};
10 changes: 10 additions & 0 deletions frontend/src/hooks/__tests__/useMissions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,14 @@ describe('useMissions', () => {

expect(result.current.data).toEqual<Mission[]>(missions);
});

it('필터링을 할 수 있다.', async () => {
const filter = missions[0].hashTags[0].name;
const filteredMissions = missions.filter((mission) => mission.hashTags[0].name === filter);
const { result } = renderHook(() => useMissions(filter), { wrapper });

await waitFor(() => expect(result.current.isSuccess).toBe(true));

expect(result.current.data).toEqual<Mission[]>(filteredMissions);
});
});
4 changes: 4 additions & 0 deletions frontend/src/hooks/queries/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export const solutionKeys = {
submitted: ['submitted solutions'],
};

export const hashTagsKeys = {
hashTags: ['hashTags'],
};

export const userKeys = {
info: ['userInfo'],
};
Loading

0 comments on commit 68ae00c

Please sign in to comment.