= props => {
+ const [isOpen, setIsOpen] = useState(false);
+ return (
+
+
+ {isOpen && setIsOpen(false)} />}
+
+ );
+};
+
+export const Default = Template.bind({});
+Default.args = {
+ children: 'hihi',
+ top: '40px',
+ left: '15px',
+};
diff --git a/frontend/src/layout/header/components/drop-down-box/DropDownBox.style.tsx b/frontend/src/layout/header/components/drop-down-box/DropDownBox.style.tsx
new file mode 100644
index 000000000..d42c0fb76
--- /dev/null
+++ b/frontend/src/layout/header/components/drop-down-box/DropDownBox.style.tsx
@@ -0,0 +1,30 @@
+import { css } from '@emotion/react';
+import styled from '@emotion/styled';
+
+import type { DropDownBoxProps } from '@layout/header/components/drop-down-box/DropDownBox';
+
+export const DropDownBoxContainer = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ background: trnasparent;
+ height: 100%;
+ width: 100vw;
+`;
+
+export const DropDownBox = styled.div>`
+ ${({ theme, top, bottom, left, right }) => css`
+ position: absolute;
+ white-space: nowrap;
+ ${top && `top: ${top};`}
+ ${bottom && `bottom: ${bottom};`}
+ ${left && `left: ${left};`}
+ ${right && `right: ${right};`}
+ padding: 16px;
+
+ border: 1px solid ${theme.colors.secondary.dark};
+ border-radius: 5px;
+ background-color: ${theme.colors.secondary.light};
+ z-index: 3;
+ `}
+`;
diff --git a/frontend/src/layout/header/components/drop-down-box/DropDownBox.tsx b/frontend/src/layout/header/components/drop-down-box/DropDownBox.tsx
new file mode 100644
index 000000000..92370273f
--- /dev/null
+++ b/frontend/src/layout/header/components/drop-down-box/DropDownBox.tsx
@@ -0,0 +1,20 @@
+import * as S from '@layout/header/components/drop-down-box/DropDownBox.style';
+
+export interface DropDownBoxProps {
+ children: React.ReactNode;
+ onOutOfBoxClick: React.MouseEventHandler;
+ top?: string;
+ bottom?: string;
+ left?: string;
+ right?: string;
+}
+
+const DropDownBox: React.FC = ({ children, onOutOfBoxClick, ...positions }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default DropDownBox;
diff --git a/frontend/src/layout/header/logo/Logo.stories.tsx b/frontend/src/layout/header/components/logo/Logo.stories.tsx
similarity index 80%
rename from frontend/src/layout/header/logo/Logo.stories.tsx
rename to frontend/src/layout/header/components/logo/Logo.stories.tsx
index 76b990c56..15f4ead9a 100644
--- a/frontend/src/layout/header/logo/Logo.stories.tsx
+++ b/frontend/src/layout/header/components/logo/Logo.stories.tsx
@@ -1,6 +1,6 @@
import { Story } from '@storybook/react';
-import Logo from '@layout/header/logo/Logo';
+import Logo from '@layout/header/components/logo/Logo';
export default {
title: 'Components/Logo',
diff --git a/frontend/src/layout/header/logo/Logo.style.tsx b/frontend/src/layout/header/components/logo/Logo.style.tsx
similarity index 100%
rename from frontend/src/layout/header/logo/Logo.style.tsx
rename to frontend/src/layout/header/components/logo/Logo.style.tsx
diff --git a/frontend/src/layout/header/logo/Logo.tsx b/frontend/src/layout/header/components/logo/Logo.tsx
similarity index 84%
rename from frontend/src/layout/header/logo/Logo.tsx
rename to frontend/src/layout/header/components/logo/Logo.tsx
index 913a34c7a..f8131b21d 100644
--- a/frontend/src/layout/header/logo/Logo.tsx
+++ b/frontend/src/layout/header/components/logo/Logo.tsx
@@ -1,6 +1,6 @@
import logoImage from '@assets/images/logo.png';
-import * as S from '@layout/header/logo/Logo.style';
+import * as S from '@layout/header/components/logo/Logo.style';
import Image from '@components/image/Image';
diff --git a/frontend/src/layout/header/components/nav-button/NavButton.stories.tsx b/frontend/src/layout/header/components/nav-button/NavButton.stories.tsx
new file mode 100644
index 000000000..06d60c72d
--- /dev/null
+++ b/frontend/src/layout/header/components/nav-button/NavButton.stories.tsx
@@ -0,0 +1,19 @@
+import { Story } from '@storybook/react';
+
+import NavButton from '@layout/header/components/nav-button/NavButton';
+import type { NavButtonProps } from '@layout/header/components/nav-button/NavButton';
+
+export default {
+ title: 'Components/NavButton',
+ component: NavButton,
+ argTypes: {
+ children: { controls: 'text' },
+ },
+};
+
+const Template: Story = props => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ children: '➕ hihi',
+};
diff --git a/frontend/src/layout/header/components/nav-button/NavButton.style.tsx b/frontend/src/layout/header/components/nav-button/NavButton.style.tsx
new file mode 100644
index 000000000..d73067f86
--- /dev/null
+++ b/frontend/src/layout/header/components/nav-button/NavButton.style.tsx
@@ -0,0 +1,37 @@
+import { css } from '@emotion/react';
+import styled from '@emotion/styled';
+
+import { mqDown } from '@utils/index';
+
+export const NavButton = styled.button`
+ ${({ theme }) => css`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ column-gap: 4px;
+
+ padding: 8px 4px;
+
+ color: ${theme.colors.primary.base};
+ border: none;
+ background-color: transparent;
+
+ &:hover {
+ border-bottom: 1px solid ${theme.colors.secondary.base};
+ }
+
+ & > svg {
+ fill: ${theme.colors.primary.base};
+ }
+
+ & > span {
+ color: ${theme.colors.primary.base};
+ }
+ `}
+
+ ${mqDown('md')} {
+ & > span {
+ display: none;
+ }
+ }
+`;
diff --git a/frontend/src/layout/header/components/nav-button/NavButton.tsx b/frontend/src/layout/header/components/nav-button/NavButton.tsx
new file mode 100644
index 000000000..fb15b1215
--- /dev/null
+++ b/frontend/src/layout/header/components/nav-button/NavButton.tsx
@@ -0,0 +1,19 @@
+import { noop } from '@utils/index';
+
+import * as S from '@layout/header/components/nav-button/NavButton.style';
+
+export interface NavButtonProps {
+ children: React.ReactNode;
+ ariaLabel: string;
+ onClick?: React.MouseEventHandler;
+}
+
+const NavButton: React.FC = ({ children, ariaLabel, onClick = noop }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default NavButton;
diff --git a/frontend/src/layout/header/search-bar/SearchBar.stories.tsx b/frontend/src/layout/header/components/search-bar/SearchBar.stories.tsx
similarity index 62%
rename from frontend/src/layout/header/search-bar/SearchBar.stories.tsx
rename to frontend/src/layout/header/components/search-bar/SearchBar.stories.tsx
index cf3b3f238..ac792bb09 100644
--- a/frontend/src/layout/header/search-bar/SearchBar.stories.tsx
+++ b/frontend/src/layout/header/components/search-bar/SearchBar.stories.tsx
@@ -1,7 +1,7 @@
import { Story } from '@storybook/react';
-import SearchBar from '@layout/header/search-bar/SearchBar';
-import type { SearchBarProps } from '@layout/header/search-bar/SearchBar';
+import SearchBar from '@layout/header/components/search-bar/SearchBar';
+import type { SearchBarProps } from '@layout/header/components/search-bar/SearchBar';
export default {
title: 'Components/SearchBar',
diff --git a/frontend/src/layout/header/search-bar/SearchBar.style.tsx b/frontend/src/layout/header/components/search-bar/SearchBar.style.tsx
similarity index 100%
rename from frontend/src/layout/header/search-bar/SearchBar.style.tsx
rename to frontend/src/layout/header/components/search-bar/SearchBar.style.tsx
diff --git a/frontend/src/layout/header/search-bar/SearchBar.tsx b/frontend/src/layout/header/components/search-bar/SearchBar.tsx
similarity index 88%
rename from frontend/src/layout/header/search-bar/SearchBar.tsx
rename to frontend/src/layout/header/components/search-bar/SearchBar.tsx
index 87a789c8a..ebd586799 100644
--- a/frontend/src/layout/header/search-bar/SearchBar.tsx
+++ b/frontend/src/layout/header/components/search-bar/SearchBar.tsx
@@ -1,6 +1,6 @@
import { FiSearch } from 'react-icons/fi';
-import * as S from '@layout/header/search-bar/SearchBar.style';
+import * as S from '@layout/header/components/search-bar/SearchBar.style';
export type SearchBarProps = {
onSubmit: (e: React.FormEvent, inputName: string) => void;
diff --git a/frontend/src/mocks/detail-study-handlers.ts b/frontend/src/mocks/detail-study-handlers.ts
deleted file mode 100644
index 1ebe698e2..000000000
--- a/frontend/src/mocks/detail-study-handlers.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { rest } from 'msw';
-
-import reviewJSON from './reviews.json';
-import studiesJSON from './studies.json';
-
-const detailStudyHandlers = [
- rest.get('/api/studies/:studyId', (req, res, ctx) => {
- const studyId = req.params.studyId;
-
- const study = studiesJSON.studies.find(study => String(study.id) === studyId);
-
- return res(ctx.status(200), ctx.json(study));
- }),
-
- rest.get('/api/studies/:studyId/reviews', (req, res, ctx) => {
- const size = req.url.searchParams.get('size');
- if (size) {
- const sizeNum = Number(size);
- return res(
- ctx.status(200),
- ctx.json({
- reviews: reviewJSON.reviews.slice(0, sizeNum),
- totalResults: reviewJSON.reviews.length,
- }),
- );
- }
- return res(
- ctx.status(200),
- ctx.json({
- reviews: reviewJSON.reviews,
- totalResults: reviewJSON.reviews.length,
- }),
- );
- }),
-];
-
-export default detailStudyHandlers;
diff --git a/frontend/src/mocks/detailStudyHandlers.ts b/frontend/src/mocks/detailStudyHandlers.ts
new file mode 100644
index 000000000..f70a0be27
--- /dev/null
+++ b/frontend/src/mocks/detailStudyHandlers.ts
@@ -0,0 +1,16 @@
+import { rest } from 'msw';
+
+import reviewJSON from './reviews.json';
+import studiesJSON from './studies.json';
+
+const detailStudyHandlers = [
+ rest.get('/api/studies/:studyId', (req, res, ctx) => {
+ const studyId = req.params.studyId;
+
+ const study = studiesJSON.studies.find(study => String(study.id) === studyId);
+
+ return res(ctx.status(200), ctx.json(study));
+ }),
+];
+
+export default detailStudyHandlers;
diff --git a/frontend/src/mocks/handlers.ts b/frontend/src/mocks/handlers.ts
index 042ab60b1..2d98b6a2c 100644
--- a/frontend/src/mocks/handlers.ts
+++ b/frontend/src/mocks/handlers.ts
@@ -1,9 +1,11 @@
import { rest } from 'msw';
-import detailStudyHandlers from './detail-study-handlers';
-import studyJSON from './studies.json';
-import { tagHandlers } from './tagHandlers';
-import { tokenHandlers } from './tokenHandlers';
+import detailStudyHandlers from '@mocks/detailStudyHandlers';
+import { myHandlers } from '@mocks/myHandlers';
+import { reviewHandlers } from '@mocks/reviewHandler';
+import studyJSON from '@mocks/studies.json';
+import { tagHandlers } from '@mocks/tagHandlers';
+import { tokenHandlers } from '@mocks/tokenHandlers';
export const handlers = [
rest.get('/api/studies', (req, res, ctx) => {
@@ -89,4 +91,6 @@ export const handlers = [
...detailStudyHandlers,
...tagHandlers,
...tokenHandlers,
+ ...myHandlers,
+ ...reviewHandlers,
];
diff --git a/frontend/src/mocks/my-studies.json b/frontend/src/mocks/my-studies.json
new file mode 100644
index 000000000..bc254f19b
--- /dev/null
+++ b/frontend/src/mocks/my-studies.json
@@ -0,0 +1,466 @@
+{
+ "studies": [
+ {
+ "id": 53172832,
+ "title": "2022-daily-planner",
+ "studyStatus": "IN_PROGRESS",
+ "currentMemberCount": 5,
+ "maxMemberCount": 23,
+ "startDate": "2022-07-12",
+ "endDate": "2022-08-18",
+ "owner": {
+ "id": 19749913,
+ "username": "xRC3N",
+ "imageUrl": "https://picsum.photos/id/39/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" }
+ ]
+ },
+ {
+ "id": 74198334,
+ "title": "2022-lv3-algorithm-study",
+ "studyStatus": "IN_PROGRESS",
+ "currentMemberCount": 8,
+ "maxMemberCount": 39,
+ "startDate": "2022-07-24",
+ "endDate": "2022-08-08",
+ "owner": {
+ "id": 73846379,
+ "username": "i8ZTZ",
+ "imageUrl": "https://picsum.photos/id/62/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" },
+ { "id": 11, "name": "Network" },
+ { "id": 12, "name": "CS" }
+ ]
+ },
+ {
+ "id": 43942846,
+ "title": "2022-woowahan-bansanghwe",
+ "studyStatus": "PREPARE",
+ "currentMemberCount": 11,
+ "maxMemberCount": 27,
+ "startDate": "2022-07-20",
+ "endDate": "2022-08-31",
+ "owner": {
+ "id": 82157345,
+ "username": "QtbTJ",
+ "imageUrl": "https://picsum.photos/id/36/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" }
+ ]
+ },
+ {
+ "id": 19264566,
+ "title": "2022-gugu-spring-study",
+ "studyStatus": "PREPARE",
+ "currentMemberCount": 36,
+ "maxMemberCount": 37,
+ "startDate": "2022-07-05",
+ "endDate": "2022-08-27",
+ "owner": {
+ "id": 73501209,
+ "username": "xE5Gh",
+ "imageUrl": "https://picsum.photos/id/56/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" }
+ ]
+ },
+ {
+ "id": 26808604,
+ "title": "2022-ConquerCS",
+ "studyStatus": "DONE",
+ "currentMemberCount": 3,
+ "maxMemberCount": 37,
+ "startDate": "2022-07-25",
+ "endDate": "2022-08-18",
+ "owner": {
+ "id": 19148355,
+ "username": "-LBJx",
+ "imageUrl": "https://picsum.photos/id/16/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [{ "id": 1, "name": "JS" }]
+ },
+ {
+ "id": 36977774,
+ "title": "2022-looking-for-the-sound-of-an-object",
+ "studyStatus": "IN_PROGRESS",
+ "currentMemberCount": 40,
+ "maxMemberCount": 40,
+ "startDate": "2022-07-11",
+ "endDate": "2022-08-22",
+ "owner": {
+ "id": 61097544,
+ "username": "50a_j",
+ "imageUrl": "https://picsum.photos/id/12/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" }
+ ]
+ },
+ {
+ "id": 28043313,
+ "title": "2022-kotudy",
+ "studyStatus": "DONE",
+ "currentMemberCount": 5,
+ "maxMemberCount": 36,
+ "startDate": "2022-07-24",
+ "endDate": "2022-08-20",
+ "owner": {
+ "id": 47838157,
+ "username": "-02j_",
+ "imageUrl": "https://picsum.photos/id/48/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" }
+ ]
+ },
+ {
+ "id": 92951646,
+ "title": "2022-no-posting-you-die",
+ "studyStatus": "DONE",
+ "currentMemberCount": 20,
+ "maxMemberCount": 22,
+ "startDate": "2022-07-03",
+ "endDate": "2022-08-11",
+ "owner": {
+ "id": 74007869,
+ "username": "dCMAR",
+ "imageUrl": "https://picsum.photos/id/56/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [{ "id": 1, "name": "JS" }]
+ },
+ {
+ "id": 27364158,
+ "title": "2022-Real-MySQL",
+ "studyStatus": "DONE",
+ "currentMemberCount": 23,
+ "maxMemberCount": 38,
+ "startDate": "2022-07-25",
+ "endDate": "2022-08-02",
+ "owner": {
+ "id": 13018728,
+ "username": "pmnMx",
+ "imageUrl": "https://picsum.photos/id/67/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" },
+ { "id": 11, "name": "Network" }
+ ]
+ },
+ {
+ "id": 87571081,
+ "title": "2022-weekly-log",
+ "studyStatus": "DONE",
+ "currentMemberCount": 16,
+ "maxMemberCount": 31,
+ "startDate": "2022-07-04",
+ "endDate": "2022-08-26",
+ "owner": {
+ "id": 43897221,
+ "username": "cCcfy",
+ "imageUrl": "https://picsum.photos/id/29/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" },
+ { "id": 11, "name": "Network" },
+ { "id": 12, "name": "CS" }
+ ]
+ },
+ {
+ "id": 48700521,
+ "title": "2022-spring-study",
+ "studyStatus": "DONE",
+ "currentMemberCount": 5,
+ "maxMemberCount": 32,
+ "startDate": "2022-07-25",
+ "endDate": "2022-08-06",
+ "owner": {
+ "id": 56121153,
+ "username": "-ShmC",
+ "imageUrl": "https://picsum.photos/id/33/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" }
+ ]
+ },
+ {
+ "id": 37351958,
+ "title": "http-network-basic-level2-study",
+ "studyStatus": "DONE",
+ "currentMemberCount": 17,
+ "maxMemberCount": 31,
+ "startDate": "2022-07-17",
+ "endDate": "2022-08-26",
+ "owner": {
+ "id": 64342856,
+ "username": "udN0b",
+ "imageUrl": "https://picsum.photos/id/62/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" }
+ ]
+ },
+ {
+ "id": 47071629,
+ "title": "2022-code-review-study-2",
+ "studyStatus": "PREPARE",
+ "currentMemberCount": 16,
+ "maxMemberCount": 36,
+ "startDate": "2022-07-06",
+ "endDate": "2022-08-29",
+ "owner": {
+ "id": 16398644,
+ "username": "8yC-b",
+ "imageUrl": "https://picsum.photos/id/28/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" }
+ ]
+ },
+ {
+ "id": 11340744,
+ "title": "2022-http-web-basic-for-all-developer",
+ "studyStatus": "IN_PROGRESS",
+ "currentMemberCount": 39,
+ "maxMemberCount": 39,
+ "startDate": "2022-07-07",
+ "endDate": "2022-08-19",
+ "owner": {
+ "id": 17465872,
+ "username": "qNknz",
+ "imageUrl": "https://picsum.photos/id/93/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [{ "id": 1, "name": "JS" }]
+ },
+ {
+ "id": 37178275,
+ "title": "2022-woowa-retrospect",
+ "studyStatus": "DONE",
+ "currentMemberCount": 26,
+ "maxMemberCount": 38,
+ "startDate": "2022-07-05",
+ "endDate": "2022-08-11",
+ "owner": {
+ "id": 82056531,
+ "username": "XGbcR",
+ "imageUrl": "https://picsum.photos/id/39/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" }
+ ]
+ },
+ {
+ "id": 20176840,
+ "title": "2022-http-network-basic-study",
+ "studyStatus": "DONE",
+ "currentMemberCount": 32,
+ "maxMemberCount": 32,
+ "startDate": "2022-07-05",
+ "endDate": "2022-08-30",
+ "owner": {
+ "id": 68132562,
+ "username": "M9MbV",
+ "imageUrl": "https://picsum.photos/id/84/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" }
+ ]
+ },
+ {
+ "id": 88252874,
+ "title": "2022-lv2-effective-java-interview",
+ "studyStatus": "DONE",
+ "currentMemberCount": 37,
+ "maxMemberCount": 39,
+ "startDate": "2022-07-28",
+ "endDate": "2022-08-06",
+ "owner": {
+ "id": 76714791,
+ "username": "kHuuu",
+ "imageUrl": "https://picsum.photos/id/53/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" },
+ { "id": 11, "name": "Network" }
+ ]
+ },
+ {
+ "id": 35867370,
+ "title": "2022-book-muscle",
+ "studyStatus": "DONE",
+ "currentMemberCount": 10,
+ "maxMemberCount": 21,
+ "startDate": "2022-07-29",
+ "endDate": "2022-08-06",
+ "owner": {
+ "id": 75253381,
+ "username": "N-7qD",
+ "imageUrl": "https://picsum.photos/id/12/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" },
+ { "id": 8, "name": "Alg" },
+ { "id": 9, "name": "Book" },
+ { "id": 10, "name": "Health" },
+ { "id": 11, "name": "Network" }
+ ]
+ },
+ {
+ "id": 95367364,
+ "title": "2022-woowahan-everybook",
+ "studyStatus": "PREPARE",
+ "currentMemberCount": 19,
+ "maxMemberCount": 36,
+ "startDate": "2022-07-29",
+ "endDate": "2022-08-04",
+ "owner": {
+ "id": 98385754,
+ "username": "GwfDt",
+ "imageUrl": "https://picsum.photos/id/56/200/200",
+ "profileUrl": "https://github.com/user/jaejae-yoo"
+ },
+ "tags": [
+ { "id": 1, "name": "JS" },
+ { "id": 2, "name": "Java" },
+ { "id": 3, "name": "React" },
+ { "id": 4, "name": "Spring" },
+ { "id": 5, "name": "TS" },
+ { "id": 6, "name": "JPA" },
+ { "id": 7, "name": "TDD" }
+ ]
+ }
+ ]
+}
diff --git a/frontend/src/mocks/myHandlers.ts b/frontend/src/mocks/myHandlers.ts
new file mode 100644
index 000000000..88067aa01
--- /dev/null
+++ b/frontend/src/mocks/myHandlers.ts
@@ -0,0 +1,9 @@
+import { rest } from 'msw';
+
+import myStudiesJson from '@mocks/my-studies.json';
+
+export const myHandlers = [
+ rest.get('/api/my/studies', (req, res, ctx) => {
+ return res(ctx.status(200), ctx.json(myStudiesJson));
+ }),
+];
diff --git a/frontend/src/pages/create-study-page/CreateStudyPage.stories.tsx b/frontend/src/pages/create-study-page/CreateStudyPage.stories.tsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/frontend/src/pages/create-study-page/components/category/Category.stories.tsx b/frontend/src/pages/create-study-page/components/category/Category.stories.tsx
index 80fe8c8d0..393745573 100644
--- a/frontend/src/pages/create-study-page/components/category/Category.stories.tsx
+++ b/frontend/src/pages/create-study-page/components/category/Category.stories.tsx
@@ -1,20 +1,22 @@
-import Category from '@create-study-page/components/category/Category';
import { Story } from '@storybook/react';
import { css } from '@emotion/react';
+import Category from '@create-study-page/components/category/Category';
+import type { CategoryProps } from '@create-study-page/components/category/Category';
+
export default {
title: 'Components/Category',
component: Category,
};
-const Template: Story = props => (
+const Template: Story = props => (
-
+
);
diff --git a/frontend/src/pages/create-study-page/components/category/Category.tsx b/frontend/src/pages/create-study-page/components/category/Category.tsx
index 06b669d2d..46098a056 100644
--- a/frontend/src/pages/create-study-page/components/category/Category.tsx
+++ b/frontend/src/pages/create-study-page/components/category/Category.tsx
@@ -1,6 +1,3 @@
-import * as S from '@create-study-page/components/category/Category.style';
-import MetaBox from '@create-study-page/components/meta-box/MetaBox';
-
import { css } from '@emotion/react';
import type { Tag } from '@custom-types/index';
@@ -9,7 +6,10 @@ import { useFormContext } from '@hooks/useForm';
import useFetchTagList from '@pages/create-study-page/hooks/useFetchTagList';
-type CategoryProps = {
+import * as S from '@create-study-page/components/category/Category.style';
+import MetaBox from '@create-study-page/components/meta-box/MetaBox';
+
+export type CategoryProps = {
className?: string;
};
diff --git a/frontend/src/pages/main-page/MainPage.tsx b/frontend/src/pages/main-page/MainPage.tsx
index 22c96ba20..1909d9770 100644
--- a/frontend/src/pages/main-page/MainPage.tsx
+++ b/frontend/src/pages/main-page/MainPage.tsx
@@ -2,7 +2,7 @@ import { useContext, useState } from 'react';
import { useInfiniteQuery } from 'react-query';
import { Link, useNavigate } from 'react-router-dom';
-import { DEFAULT_STUDY_CARD_QUERY_PARAM } from '@constants';
+import { DEFAULT_STUDY_CARD_QUERY_PARAM, PATH } from '@constants';
import type { Study, StudyListQueryData, TagInfo } from '@custom-types/index';
@@ -70,7 +70,7 @@ const MainPage: React.FC = () => {
return;
}
window.scrollTo(0, 0);
- navigate('/study/new');
+ navigate(PATH.CREATE_STUDY);
};
return (
diff --git a/frontend/src/pages/main-page/style.ts b/frontend/src/pages/main-page/style.ts
deleted file mode 100644
index 12556e340..000000000
--- a/frontend/src/pages/main-page/style.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import styled from '@emotion/styled';
-
-import { mqDown } from '@utils/index';
-
-export const CardList = styled.ul`
- display: grid;
- grid-template-columns: repeat(4, minmax(auto, 1fr));
- grid-template-rows: 1fr;
- gap: 32px;
- place-items: center;
-
- & > li {
- cursor: pointer;
- }
-
- ${mqDown('lg')} {
- grid-template-columns: repeat(3, 1fr);
- }
- ${mqDown('md')} {
- grid-template-columns: repeat(2, 1fr);
- }
- ${mqDown('sm')} {
- grid-template-columns: repeat(1, 256px);
- place-content: center;
- }
-`;
-
-export const Page = styled.div``;
diff --git a/frontend/src/pages/my-study-page/MyStudyPage.style.tsx b/frontend/src/pages/my-study-page/MyStudyPage.style.tsx
new file mode 100644
index 000000000..4434d1068
--- /dev/null
+++ b/frontend/src/pages/my-study-page/MyStudyPage.style.tsx
@@ -0,0 +1,10 @@
+import styled from '@emotion/styled';
+
+export const PageTitle = styled.h1`
+ font-size: 32px;
+ text-align: center;
+`;
+
+export const SectionContainer = styled.div`
+ margin-bottom: 20px;
+`;
diff --git a/frontend/src/pages/my-study-page/MyStudyPage.tsx b/frontend/src/pages/my-study-page/MyStudyPage.tsx
new file mode 100644
index 000000000..49a85c685
--- /dev/null
+++ b/frontend/src/pages/my-study-page/MyStudyPage.tsx
@@ -0,0 +1,59 @@
+import { useQuery } from 'react-query';
+
+import { css } from '@emotion/react';
+
+import type { MyStudyQueryData } from '@custom-types/index';
+import { MyStudyData } from '@custom-types/index';
+
+import { getMyStudyList } from '@api/getMyStudyList';
+
+import MyStudyCardListSection from '@pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection';
+
+import Divider from '@components/divider/Divider';
+import Wrapper from '@components/wrapper/Wrapper';
+
+import * as S from '@my-study-page/MyStudyPage.style';
+
+const studies: Record> = {
+ prepare: [],
+ inProgress: [],
+ done: [],
+};
+
+const MyStudyPage: React.FC = () => {
+ const { data, isFetching, isError } = useQuery('my-studies', getMyStudyList);
+
+ const myStudies =
+ data?.studies.reduce((acc, study) => {
+ if (study.studyStatus === 'IN_PROGRESS') {
+ acc.inProgress.push(study);
+ }
+ if (study.studyStatus === 'PREPARE') {
+ acc.prepare.push(study);
+ }
+ if (study.studyStatus === 'DONE') {
+ acc.done.push(study);
+ }
+ return acc;
+ }, studies) || studies;
+
+ const mb20 = css`
+ margin-bottom: 20px;
+ `;
+
+ return (
+
+
+ 가입한 스터디 목록
+
+ {isFetching && 로딩 중...
}
+ {isError && 내 스터디 불러오기를 실패했습니다
}
+
+
+
+
+
+ );
+};
+
+export default MyStudyPage;
diff --git a/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.stories.tsx b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.stories.tsx
new file mode 100644
index 000000000..690301733
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.stories.tsx
@@ -0,0 +1,414 @@
+import { Story } from '@storybook/react';
+
+import Wrapper from '@components/wrapper/Wrapper';
+
+import MyStudyCardListSection from '@my-study-page/components/my-study-card-list-section/MyStudyCardListSection';
+import type { MyStudyCardListSectionProps } from '@my-study-page/components/my-study-card-list-section/MyStudyCardListSection';
+
+export default {
+ title: 'Components/MyStudyCardListSection',
+ component: MyStudyCardListSection,
+ argTypes: {
+ sectionTitle: { controls: 'text' },
+ myStudies: { controls: 'object' },
+ },
+};
+
+const Template: Story = props => (
+
+
+
+);
+
+export const Default = Template.bind({});
+Default.args = {
+ sectionTitle: '활동 중!',
+ myStudies: [
+ {
+ id: 53172832,
+ title: '2022-daily-planner',
+ studyStatus: 'IN_PROGRESS',
+ startDate: '2022-07-12',
+ endDate: '2022-08-18',
+ owner: {
+ id: 19749913,
+ username: 'xRC3N',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ ],
+ },
+ {
+ id: 74198334,
+ title: '2022-lv3-algorithm-study',
+ studyStatus: 'IN_PROGRESS',
+ startDate: '2022-07-24',
+ endDate: '2022-08-08',
+ owner: {
+ id: 73846379,
+ username: 'i8ZTZ',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ { id: 11, name: 'Network' },
+ { id: 12, name: 'CS' },
+ ],
+ },
+ {
+ id: 43942846,
+ title: '2022-woowahan-bansanghwe',
+ studyStatus: 'PREPARE',
+ startDate: '2022-07-20',
+ endDate: '2022-08-31',
+ owner: {
+ id: 82157345,
+ username: 'QtbTJ',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ ],
+ },
+ {
+ id: 19264566,
+ title: '2022-gugu-spring-study',
+ studyStatus: 'PREPARE',
+ startDate: '2022-07-05',
+ endDate: '2022-08-27',
+ owner: {
+ id: 73501209,
+ username: 'xE5Gh',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ ],
+ },
+ {
+ id: 26808604,
+ title: '2022-ConquerCS',
+ studyStatus: 'DONE',
+ startDate: '2022-07-25',
+ endDate: '2022-08-18',
+ owner: {
+ id: 19148355,
+ username: '-LBJx',
+ },
+ tags: [{ id: 1, name: 'JS' }],
+ },
+ {
+ id: 36977774,
+ title: '2022-looking-for-the-sound-of-an-object',
+ studyStatus: 'IN_PROGRESS',
+ startDate: '2022-07-11',
+ endDate: '2022-08-22',
+ owner: {
+ id: 61097544,
+ username: '50a_j',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ ],
+ },
+ {
+ id: 28043313,
+ title: '2022-kotudy',
+ studyStatus: 'DONE',
+ startDate: '2022-07-24',
+ endDate: '2022-08-20',
+ owner: {
+ id: 47838157,
+ username: '-02j_',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ ],
+ },
+ {
+ id: 92951646,
+ title: '2022-no-posting-you-die',
+ studyStatus: 'DONE',
+ startDate: '2022-07-03',
+ endDate: '2022-08-11',
+ owner: {
+ id: 74007869,
+ username: 'dCMAR',
+ },
+ tags: [{ id: 1, name: 'JS' }],
+ },
+ {
+ id: 27364158,
+ title: '2022-Real-MySQL',
+ studyStatus: 'DONE',
+ startDate: '2022-07-25',
+ endDate: '2022-08-02',
+ owner: {
+ id: 13018728,
+ username: 'pmnMx',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ { id: 11, name: 'Network' },
+ ],
+ },
+ {
+ id: 87571081,
+ title: '2022-weekly-log',
+ studyStatus: 'DONE',
+ startDate: '2022-07-04',
+ endDate: '2022-08-26',
+ owner: {
+ id: 43897221,
+ username: 'cCcfy',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ { id: 11, name: 'Network' },
+ { id: 12, name: 'CS' },
+ ],
+ },
+ {
+ id: 48700521,
+ title: '2022-spring-study',
+ studyStatus: 'DONE',
+ startDate: '2022-07-25',
+ endDate: '2022-08-06',
+ owner: {
+ id: 56121153,
+ username: '-ShmC',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ ],
+ },
+ {
+ id: 37351958,
+ title: 'http-network-basic-level2-study',
+ studyStatus: 'DONE',
+ startDate: '2022-07-17',
+ endDate: '2022-08-26',
+ owner: {
+ id: 64342856,
+ username: 'udN0b',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ ],
+ },
+ {
+ id: 47071629,
+ title: '2022-code-review-study-2',
+ studyStatus: 'PREPARE',
+ startDate: '2022-07-06',
+ endDate: '2022-08-29',
+ owner: {
+ id: 16398644,
+ username: '8yC-b',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ ],
+ },
+ {
+ id: 11340744,
+ title: '2022-http-web-basic-for-all-developer',
+ studyStatus: 'IN_PROGRESS',
+ startDate: '2022-07-07',
+ endDate: '2022-08-19',
+ owner: {
+ id: 17465872,
+ username: 'qNknz',
+ },
+ tags: [{ id: 1, name: 'JS' }],
+ },
+ {
+ id: 37178275,
+ title: '2022-woowa-retrospect',
+ studyStatus: 'DONE',
+ startDate: '2022-07-05',
+ endDate: '2022-08-11',
+ owner: {
+ id: 82056531,
+ username: 'XGbcR',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ ],
+ },
+ {
+ id: 20176840,
+ title: '2022-http-network-basic-study',
+ studyStatus: 'DONE',
+ startDate: '2022-07-05',
+ endDate: '2022-08-30',
+ owner: {
+ id: 68132562,
+ username: 'M9MbV',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ ],
+ },
+ {
+ id: 88252874,
+ title: '2022-lv2-effective-java-interview',
+ studyStatus: 'DONE',
+ startDate: '2022-07-28',
+ endDate: '2022-08-06',
+ owner: {
+ id: 76714791,
+ username: 'kHuuu',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ { id: 11, name: 'Network' },
+ ],
+ },
+ {
+ id: 35867370,
+ title: '2022-book-muscle',
+ studyStatus: 'DONE',
+ startDate: '2022-07-29',
+ endDate: '2022-08-06',
+ owner: {
+ id: 75253381,
+ username: 'N-7qD',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ { id: 8, name: 'Alg' },
+ { id: 9, name: 'Book' },
+ { id: 10, name: 'Health' },
+ { id: 11, name: 'Network' },
+ ],
+ },
+ {
+ id: 95367364,
+ title: '2022-woowahan-everybook',
+ studyStatus: 'PREPARE',
+ startDate: '2022-07-29',
+ endDate: '2022-08-04',
+ owner: {
+ id: 98385754,
+ username: 'GwfDt',
+ },
+ tags: [
+ { id: 1, name: 'JS' },
+ { id: 2, name: 'Java' },
+ { id: 3, name: 'React' },
+ { id: 4, name: 'Spring' },
+ { id: 5, name: 'TS' },
+ { id: 6, name: 'JPA' },
+ { id: 7, name: 'TDD' },
+ ],
+ },
+ ],
+};
diff --git a/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.style.tsx b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.style.tsx
new file mode 100644
index 000000000..4b38a5096
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.style.tsx
@@ -0,0 +1,33 @@
+import styled from '@emotion/styled';
+
+import { mqDown } from '@utils/index';
+
+export const SectionTitle = styled.h3`
+ margin-bottom: 20px;
+
+ font-size: 24px;
+ font-weight: 700;
+`;
+
+export const MyStudyList = styled.ul`
+ display: grid;
+ grid-template-columns: repeat(3, minmax(auto, 1fr));
+ grid-template-rows: 1fr;
+ gap: 20px;
+
+ & > li {
+ cursor: pointer;
+ width: 100%;
+ }
+
+ ${mqDown('lg')} {
+ grid-template-columns: repeat(2, minmax(auto, 1fr));
+ }
+ ${mqDown('sm')} {
+ grid-template-columns: repeat(1, minmax(auto, 1fr));
+ }
+`;
+
+export const MyStudyCardListSection = styled.section`
+ padding: 8px;
+`;
diff --git a/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.tsx b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.tsx
new file mode 100644
index 000000000..2d278c452
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card-list-section/MyStudyCardListSection.tsx
@@ -0,0 +1,43 @@
+import type { MakeOptional, MyStudyData } from '@custom-types/index';
+
+import MyStudyCard from '@pages/my-study-page/components/my-study-card/MyStudyCard';
+
+import * as S from '@my-study-page/components/my-study-card-list-section/MyStudyCardListSection.style';
+
+export type MyStudyCardListSectionProps = {
+ className?: string;
+ sectionTitle: string;
+ myStudies: Array;
+ disabled: boolean;
+};
+
+type OptionalMyStudyCardListSectionProps = MakeOptional;
+
+const MyStudyCardListSection: React.FC = ({
+ className,
+ sectionTitle,
+ myStudies,
+ disabled = false,
+}) => {
+ return (
+
+ {sectionTitle}
+
+ {myStudies.map(myStudy => (
+
+
+
+ ))}
+
+
+ );
+};
+
+export default MyStudyCardListSection;
diff --git a/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.stories.tsx b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.stories.tsx
new file mode 100644
index 000000000..a3b88ac83
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.stories.tsx
@@ -0,0 +1,40 @@
+import { Story } from '@storybook/react';
+
+import MyStudyCard from '@my-study-page/components/my-study-card/MyStudyCard';
+import type { MyStudyCardProps } from '@my-study-page/components/my-study-card/MyStudyCard';
+
+export default {
+ title: 'Components/MyStudyCard',
+ component: MyStudyCard,
+ argTypes: {
+ title: { controls: 'text' },
+ ownerName: { controls: 'text' },
+ tags: { controls: 'object' },
+ startDate: { controls: 'text' },
+ endDate: { controls: 'text' },
+ },
+};
+
+const Template: Story = props => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ title: '2022 모아모아 스터디',
+ ownerName: 'airman5573',
+ tags: [
+ {
+ id: 1,
+ name: 'Java',
+ },
+ {
+ id: 2,
+ name: 'JS',
+ },
+ {
+ id: 3,
+ name: 'FE',
+ },
+ ],
+ startDate: '2022.08.13',
+ endDate: '2022.08.20',
+};
diff --git a/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.style.tsx b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.style.tsx
new file mode 100644
index 000000000..13a12dd3f
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.style.tsx
@@ -0,0 +1,100 @@
+import { css } from '@emotion/react';
+import type { Theme } from '@emotion/react';
+import styled from '@emotion/styled';
+
+import { MyStudyCardProps } from '@pages/my-study-page/components/my-study-card/MyStudyCard';
+
+export const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: 100%;
+`;
+
+export const Top = styled.div``;
+
+export const Bottom = styled.div`
+ display: flex;
+ justify-content: space-between;
+`;
+
+export const Title = styled.h4`
+ display: -webkit-box;
+ overflow: clip;
+ text-overflow: ellipsis;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 1;
+ word-break: break-all;
+
+ margin-bottom: 12px;
+
+ font-size: 20px;
+ font-weight: 700;
+`;
+
+export const Owner = styled.p`
+ display: flex;
+ align-items: center;
+ column-gap: 2px;
+
+ margin-bottom: 12px;
+
+ & > svg {
+ position: relative;
+ top: -2px;
+ }
+`;
+
+export const Tags = styled.p`
+ margin-bottom: 12px;
+ display: flex;
+ column-gap: 10px;
+ flex-wrap: wrap;
+`;
+
+export const Period = styled.p``;
+
+const disabledStyle = (theme: Theme) => css`
+ border: 3px solid ${theme.colors.secondary.dark};
+ box-shadow: 4px 4px 0 0 ${theme.colors.secondary.base};
+
+ & * {
+ color: ${theme.colors.secondary.dark} !important;
+ }
+ svg {
+ stroke: ${theme.colors.secondary.dark} !important;
+ }
+`;
+
+export const MyStudyCard = styled.div>`
+ ${({ theme, disabled }) => css`
+ position: relative;
+ padding: 12px;
+ overflow: hidden;
+
+ height: 100%;
+
+ border: 3px solid ${theme.colors.primary.base};
+ border-radius: 15px;
+ box-shadow: 4px 4px 0 0 ${theme.colors.secondary.dark};
+
+ ${disabled && disabledStyle(theme)}
+ `}
+`;
+
+export const TrashButton = styled.button`
+ ${({ theme }) => css`
+ background-color: transparent;
+ border: none;
+ outline: none;
+
+ & > svg {
+ stroke: ${theme.colors.primary.base};
+
+ &:hover,
+ &:active {
+ stroke: ${theme.colors.primary.dark};
+ }
+ }
+ `};
+`;
diff --git a/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.tsx b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.tsx
new file mode 100644
index 000000000..7fc553961
--- /dev/null
+++ b/frontend/src/pages/my-study-page/components/my-study-card/MyStudyCard.tsx
@@ -0,0 +1,55 @@
+import { HiOutlineTrash } from 'react-icons/hi';
+import { TbCrown } from 'react-icons/tb';
+
+import { MakeOptional, Tag } from '@custom-types/index';
+
+import * as S from '@my-study-page/components/my-study-card/MyStudyCard.style';
+
+export type MyStudyCardProps = {
+ title: string;
+ ownerName: string;
+ tags: Array>;
+ startDate: string;
+ endDate: string;
+ disabled: boolean;
+};
+
+type OptionalMyStudyCardProps = MakeOptional;
+
+const MyStudyCard: React.FC = ({
+ title,
+ ownerName,
+ tags,
+ startDate,
+ endDate,
+ disabled = false,
+}) => {
+ return (
+
+
+
+ {title}
+
+
+ {ownerName}
+
+
+ {tags.map(tag => (
+ #{tag.name}
+ ))}
+
+
+
+
+ {startDate} ~ {endDate}
+
+
+
+
+
+
+
+ );
+};
+
+export default MyStudyCard;
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 6037db826..ed6aa65b7 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -29,8 +29,10 @@
"@main-page/*": ["pages/main-page/*"],
"@detail-page/*": ["pages/detail-page/*"],
"@create-study-page/*": ["pages/create-study-page/*"],
+ "@my-study-page/*": ["pages/my-study-page/*"],
"@layout/*": ["layout/*"],
- "@hooks/*": ["hooks/*"]
+ "@hooks/*": ["hooks/*"],
+ "@mocks/*": ["mocks/*"]
},
"typeRoots": ["src/custom-types"]
},
diff --git a/frontend/webpack/webpack.common.js b/frontend/webpack/webpack.common.js
index 2ce6151f2..4d272bbad 100644
--- a/frontend/webpack/webpack.common.js
+++ b/frontend/webpack/webpack.common.js
@@ -50,8 +50,10 @@ module.exports = {
'@main-page': resolve(__dirname, '../src/pages/main-page'),
'@detail-page': resolve(__dirname, '../src/pages/detail-page'),
'@create-study-page': resolve(__dirname, '../src/pages/create-study-page'),
+ '@my-study-page': resolve(__dirname, '../src/pages/my-study-page'),
'@layout': resolve(__dirname, '../src/layout'),
'@hooks': resolve(__dirname, '../src/hooks'),
+ '@mocks': resolve(__dirname, '../src/mocks'),
},
},
};