diff --git a/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.styled.ts b/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.styled.ts new file mode 100644 index 00000000..69367b27 --- /dev/null +++ b/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.styled.ts @@ -0,0 +1,106 @@ +import styled from 'styled-components'; + +export const MyMissionCompletedContainer = styled.div` + display: flex; + flex-direction: column; + gap: 3.5rem; +`; + +export const MissionCardListWrapper = styled.div` + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 2.7rem; +`; + +export const MissionCardWrapper = styled.div` + min-height: 32.6rem; + border-radius: 0.8rem; + + display: flex; + flex-direction: column; + background-color: var(--grey-50); + + position: relative; + box-sizing: border-box; +`; + +export const MissionCardHeaderWrapper = styled.div` + display: flex; + position: relative; + height: 50%; +`; + +export const MissionCardContentWrapper = styled.div` + width: 100%; + height: 50%; + + display: flex; + flex-direction: column; + justify-content: space-between; + + box-sizing: border-box; + padding: 0.8rem 1.7rem; +`; + +export const Title = styled.h2` + font-size: 3.2rem; + font-weight: bold; +`; + +export const MissionLanguageBox = styled.div` + background-color: var(--primary-300); + position: absolute; + top: 0.8rem; + right: 0.8rem; + + padding: 0.3rem 1.2rem; + box-sizing: border-box; + border-radius: 0.4rem; + + font-size: 1.4rem; + font-weight: 500; +`; + +export const ThumbnailImg = styled.img` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + object-fit: cover; + border-radius: 0.8rem 0.8rem 0 0; +`; + +export const MissionTitle = styled.h3` + font-size: 2.2rem; + font-weight: bold; +`; + +export const MissionDate = styled.p` + font-size: 1.4rem; + font-weight: 500; + color: var(--grey-400); +`; + +export const PrButtonWrapper = styled.div` + display: flex; + gap: 0.7rem; + justify-content: start; +`; + +export const PrButton = styled.button` + background-color: var(--grey-200); + width: fit-content; + padding: 0.6rem 1.9rem; + border-radius: 0.4rem; + + display: flex; + gap: 0.4rem; + justify-content: center; + align-items: center; + + white-space: nowrap; + font-size: 1.2rem; + font-weight: bold; +`; diff --git a/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.tsx b/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.tsx new file mode 100644 index 00000000..378cb283 --- /dev/null +++ b/frontend/src/components/myMission/myMissionCompleted/MyMissionCompleted.tsx @@ -0,0 +1,105 @@ +import { Link, useNavigate } from 'react-router-dom'; +import * as S from './MyMissionCompleted.styled'; + +const mocks = [ + { + id: 1, + mission: { + id: 1, + title: '루터회관 흡연 단속', + language: 'JAVA', + description: '루터회관 흡연 벌칙 프로그램을 구현한다.', + thumbnail: + 'https://dszw1qtcnsa5e.cloudfront.net/community/20231115/ccefd368-2687-4d26-954d-712315f38fea/2232611625864AF59FF189AB61A75869.jpeg', + url: 'https://github.com/develup-mission/java-smoking', + }, + myPrLink: 'https://github.com/develup-mission/java-smoking/pull/1', + pairPrLink: 'https://github.com/develup-mission/java-smoking/pull/2', + status: '리뷰 완료', + }, + { + id: 2, + mission: { + id: 2, + title: '루터회관 흡연 단속 2', + language: 'JAVA', + description: '루터회관 흡연 벌칙 프로그램을 구현한다.', + thumbnail: + 'https://dszw1qtcnsa5e.cloudfront.net/community/20231115/ccefd368-2687-4d26-954d-712315f38fea/2232611625864AF59FF189AB61A75869.jpeg', + url: 'https://github.com/develup-mission/java-smoking', + }, + myPrLink: 'https://github.com/develup-mission/java-smoking/pull/1', + pairPrLink: 'https://github.com/develup-mission/java-smoking/pull/2', + status: '리뷰 완료', + }, + { + id: 3, + mission: { + id: 2, + title: '루터회관 흡연 단속 3', + language: 'JAVA', + description: '루터회관 흡연 벌칙 프로그램을 구현한다.', + thumbnail: + 'https://dszw1qtcnsa5e.cloudfront.net/community/20231115/ccefd368-2687-4d26-954d-712315f38fea/2232611625864AF59FF189AB61A75869.jpeg', + url: 'https://github.com/develup-mission/java-smoking', + }, + myPrLink: 'https://github.com/develup-mission/java-smoking/pull/1', + pairPrLink: 'https://github.com/develup-mission/java-smoking/pull/2', + status: '리뷰 완료', + }, + { + id: 4, + mission: { + id: 2, + title: '루터회관 흡연 단속 4', + language: 'JAVA', + description: '루터회관 흡연 벌칙 프로그램을 구현한다.', + thumbnail: + 'https://dszw1qtcnsa5e.cloudfront.net/community/20231115/ccefd368-2687-4d26-954d-712315f38fea/2232611625864AF59FF189AB61A75869.jpeg', + url: 'https://github.com/develup-mission/java-smoking', + }, + myPrLink: 'https://github.com/develup-mission/java-smoking/pull/1', + pairPrLink: 'https://github.com/develup-mission/java-smoking/pull/2', + status: '리뷰 완료', + }, +]; + +export default function MyMissionCompleted() { + const navigate = useNavigate(); + + const handleMissionClick = (id: number) => { + navigate(`/missions/${id}`); + }; + + return ( + + 완료한 미션 + + {mocks.map(({ id, mission, pairPrLink, myPrLink }) => ( + handleMissionClick(id)}> + + + {mission.language} + + + + + {mission.title} + 2024.07.17 ~ 2024.07.24 + + + + e.stopPropagation()}> + 페어 PR 이동 + + e.stopPropagation()}> + 내 PR 이동 + + + + + ))} + + + ); +} diff --git a/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.styled.ts b/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.styled.ts new file mode 100644 index 00000000..5d702124 --- /dev/null +++ b/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.styled.ts @@ -0,0 +1,105 @@ +import GithubLogo from '@/assets/images/githubLogo.svg'; +import styled from 'styled-components'; + +export const MyMissionInProgressContainer = styled.div` + display: flex; + flex-direction: column; + gap: 3.5rem; +`; + +export const MyMissionInProgressWrapper = styled.div` + background-color: var(--grey-50); + width: 100%; + height: 24rem; + + display: grid; + grid-template-columns: 1fr 1.5fr 1fr; + gap: 2.7rem; + padding: 3.2rem 4.1rem; + box-sizing: border-box; + border-radius: 0.8rem; +`; + +export const MissionContentWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; +`; + +export const MissionButtonWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; +`; + +export const PrButtonWrapper = styled.div` + display: flex; + gap: 0.7rem; + justify-content: flex-end; +`; + +export const MissionCompleteWrapper = styled.div` + display: flex; + justify-content: flex-end; +`; + +export const ThumbnailImg = styled.img` + width: 100%; + height: -webkit-fill-available; // Chrome, Safari + height: -moz-available; // Firefox + overflow: hidden; + object-fit: cover; + border-radius: 0.8rem; +`; + +export const Title = styled.h2` + font-size: 3.2rem; + font-weight: bold; +`; + +export const MissionTitle = styled.h3` + font-size: 2.4rem; + font-weight: bold; +`; + +export const MissionDate = styled.p` + font-size: 1.8rem; + font-weight: 500; + color: var(--grey-400); +`; + +export const GithubIcons = styled(GithubLogo)` + height: 100%; +`; + +export const PrButton = styled.button` + background-color: var(--grey-200); + width: fit-content; + padding: 0.6rem 1.9rem; + border-radius: 0.4rem; + + display: flex; + gap: 0.4rem; + justify-content: center; + align-items: center; + + white-space: nowrap; + font-size: 1.4rem; + font-weight: bold; +`; + +export const MissionCompleteButton = styled.button` + background-color: var(--primary-200); + width: fit-content; + padding: 0.6rem 1.9rem; + border-radius: 0.4rem; + + display: flex; + gap: 0.4rem; + justify-content: center; + align-items: center; + + white-space: nowrap; + font-size: 1.4rem; + font-weight: bold; +`; diff --git a/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.tsx b/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.tsx new file mode 100644 index 00000000..b3ebb5cf --- /dev/null +++ b/frontend/src/components/myMission/myMissionInProgress/MyMissionInProgress.tsx @@ -0,0 +1,33 @@ +import * as S from './MyMissionInProgress.styled'; + +export default function MyMissionInProgress() { + return ( + + 진행 중인 미션 + + + + + + 숫자 야구 게임 미션 + 2024.07.17 ~ 2024.07.24 23:59 + + + + + + + 페어 PR 이동 + + + 내 PR 이동 + + + + 리뷰 완료 + + + + + ); +} diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index f907d806..5d18b87a 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -4,4 +4,5 @@ export const ROUTES = { missionDetail: '/missions/:id', profile: '/profile', guide: '/guide', + myMission: '/my-mission', } as const; diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index a2b3c9b4..faf420f6 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -8,6 +8,7 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import MissionDetailPage from './pages/MissionDetailPage'; import MissionListPage from './pages/MissionListPage'; import MissionSubmitPage from './pages/MissionSubmitPage'; +import MyMissionPage from './pages/MyMissionPage'; import UserProfilePage from './pages/UserProfilePage'; import GuidePage from './pages/GuidePage'; @@ -57,6 +58,14 @@ const routes = [ ), }, + { + path: ROUTES.myMission, + element: ( + + + + ), + }, ]; const router = createBrowserRouter(routes, { diff --git a/frontend/src/pages/MyMissionPage.styled.ts b/frontend/src/pages/MyMissionPage.styled.ts new file mode 100644 index 00000000..ca686327 --- /dev/null +++ b/frontend/src/pages/MyMissionPage.styled.ts @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export const MyMissionPageContainer = styled.div` + width: 100rem; + margin: 4rem auto; + + display: flex; + flex-direction: column; + gap: 7rem; +`; diff --git a/frontend/src/pages/MyMissionPage.tsx b/frontend/src/pages/MyMissionPage.tsx new file mode 100644 index 00000000..bea07661 --- /dev/null +++ b/frontend/src/pages/MyMissionPage.tsx @@ -0,0 +1,12 @@ +import MyMissionInProgress from '@/components/myMission/myMissionInProgress/MyMissionInProgress'; +import MyMissionCompleted from '@/components/myMission/myMissionCompleted/MyMissionCompleted'; +import * as S from './MyMissionPage.styled'; + +export default function MyMissionPage() { + return ( + + + + + ); +}