diff --git a/.github/workflows/web-client-deploy-development.yml b/.github/workflows/web-client-deploy-development.yml index d8ada122..80aed0bb 100644 --- a/.github/workflows/web-client-deploy-development.yml +++ b/.github/workflows/web-client-deploy-development.yml @@ -32,5 +32,5 @@ jobs: key: ${{ secrets.SSH_PEM_KEY }} port: ${{ secrets.SSH_PORT }} source: ./apps/web-client/build/* - target: ~/dialga/apps/web-client/build + target: ~/k8s/dialga/build strip_components: 3 diff --git a/apps/web-client/src/components/board/BoardJobWriteSection.tsx b/apps/web-client/src/components/board/BoardJobWriteSection.tsx index 923131db..1f22645f 100644 --- a/apps/web-client/src/components/board/BoardJobWriteSection.tsx +++ b/apps/web-client/src/components/board/BoardJobWriteSection.tsx @@ -1,4 +1,4 @@ -import { FormEventHandler, useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { Editor } from '@toast-ui/react-editor'; import { useForm, zodResolver } from '@mantine/form'; import { z } from 'zod'; @@ -8,6 +8,7 @@ import { Link, useHistory } from 'react-router-dom'; import { stringify } from 'qs'; import { createStyles } from 'antd-style'; import { UploadOutlined } from '@ant-design/icons'; +import { useQueryClient } from '@tanstack/react-query'; import { ApiError, CustomApi, PostControllerService, PostCreateRequest, queryKey, useAppMutation, useAppQuery } from '~/lib/api-v2'; import { Block, WhiteBlock } from '~/styles/common/Block.styles'; import { MENU } from '~/constants/menus'; @@ -57,6 +58,7 @@ export default function BoardJobWriteSection({ postId }: { postId: number }) { const { styles } = useStyles(); const message = useMessage(); const history = useHistory(); + const queryClient = useQueryClient(); const editorRef = useRef(null); const form = useForm>({ @@ -113,8 +115,7 @@ export default function BoardJobWriteSection({ postId }: { postId: number }) { const fields: { value: string }[] = [{ value: '웹' }, { value: '모바일' }, { value: '인공지능' }, { value: '데이터사이언스' }, { value: '블록체인' }, { value: '시스템' }, { value: '기타' }]; // methods - // NOTE 에디터에서 값을 직접 가져올 수 없어서 이벤트 버블링 이용 - const onEditorInput: FormEventHandler = () => { + const onEditorChange = () => { form.setValues({ body: editorRef.current?.getInstance().getHTML(), }); @@ -165,7 +166,11 @@ export default function BoardJobWriteSection({ postId }: { postId: number }) { { onSuccess() { message.success('글이 수정되었습니다.'); - history.push(`/${MENU.BOARD}/${postId}`); + queryClient + .invalidateQueries({ + queryKey: queryKey.post.post(postId), + }) + .then(() => history.push(`/${MENU.BOARD}/${postId}`)); }, }, ); @@ -190,7 +195,11 @@ export default function BoardJobWriteSection({ postId }: { postId: number }) { { onSuccess() { message.success('글이 작성되었습니다.'); - history.push(`/${MENU.BOARD}?${stringify({ boardType: 'JOB' })}`); + queryClient + .invalidateQueries({ + queryKey: queryKey.post.all('JOB', 0), + }) + .then(() => history.push(`/${MENU.BOARD}?${stringify({ boardType: 'JOB' })}`)); }, }, ); @@ -267,8 +276,8 @@ export default function BoardJobWriteSection({ postId }: { postId: number }) { date && form.setFieldValue('deadline', date)} /> -
- +
+
false} onChange={onUploadChange} fileList={getUploadFileList()}> diff --git a/apps/web-client/src/components/board/BoardNormalWriteSection.tsx b/apps/web-client/src/components/board/BoardNormalWriteSection.tsx index 4db30994..fa07dc5e 100644 --- a/apps/web-client/src/components/board/BoardNormalWriteSection.tsx +++ b/apps/web-client/src/components/board/BoardNormalWriteSection.tsx @@ -1,4 +1,4 @@ -import { FormEventHandler, useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { Editor } from '@toast-ui/react-editor'; import { useForm, zodResolver } from '@mantine/form'; import { z } from 'zod'; @@ -9,6 +9,7 @@ import { stringify } from 'qs'; import { createStyles } from 'antd-style'; import { match } from 'ts-pattern'; import { UploadOutlined } from '@ant-design/icons'; +import { useQueryClient } from '@tanstack/react-query'; import { ApiError, CustomApi, PostControllerService, queryKey, useAppMutation, useAppQuery } from '~/lib/api-v2'; import { Block, WhiteBlock } from '~/styles/common/Block.styles'; import { MENU } from '~/constants/menus'; @@ -55,6 +56,7 @@ export default function BoardNormalWriteSection({ boardType, postId }: { boardTy const history = useHistory(); const message = useMessage(); const loginId = useAppSelector((state) => state.auth.user.memberId); + const queryClient = useQueryClient(); const editorRef = useRef(null); @@ -96,8 +98,7 @@ export default function BoardNormalWriteSection({ boardType, postId }: { boardTy }); // methods - // NOTE 에디터에서 값을 직접 가져올 수 없어서 이벤트 버블링 이용 - const onEditorInput: FormEventHandler = () => { + const onEditorChange = () => { form.setValues({ body: editorRef.current?.getInstance().getMarkdown(), }); @@ -119,7 +120,11 @@ export default function BoardNormalWriteSection({ boardType, postId }: { boardTy { onSuccess() { message.success('글이 수정되었습니다.'); - history.push(`/${MENU.BOARD}/${postId}`); + queryClient + .invalidateQueries({ + queryKey: queryKey.post.post(postId), + }) + .then(() => history.push(`/${MENU.BOARD}/${postId}`)); }, }, ); @@ -140,7 +145,11 @@ export default function BoardNormalWriteSection({ boardType, postId }: { boardTy { onSuccess() { message.success('글이 작성되었습니다.'); - history.push(`/${MENU.BOARD}?${stringify({ boardType })}`); + queryClient + .invalidateQueries({ + queryKey: queryKey.post.all(boardType, 0), + }) + .then(() => history.push(`/${MENU.BOARD}?${stringify({ boardType })}`)); }, }, ); @@ -225,8 +234,8 @@ export default function BoardNormalWriteSection({ boardType, postId }: { boardTy -
- +
+
false} onChange={onUploadChange} fileList={getUploadFileList()}> diff --git a/apps/web-client/src/components/members/MemberCard/MemberCard.jsx b/apps/web-client/src/components/members/MemberCard/MemberCard.jsx deleted file mode 100644 index 7a7c86a1..00000000 --- a/apps/web-client/src/components/members/MemberCard/MemberCard.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import colors from '~/lib/styles/colors'; -import { randomNumber } from '~/lib/utils/random'; -import { getProfileImageUrl } from '~/lib/utils/getProfileImageUrl'; - -import { MemberCardBlock, MemberCardMajor, MemberCardName, MemberCardStatus, MemberCardText, MemberCardThumbnail, MemberItem, StyledLink } from './MemberCard.styles'; -import { MENU } from '~/constants/menus'; - -const MemberCard = ({ member }) => { - const { loginID, name, department, isAdmin, profileImageURL } = member; - return ( - - - - - - - {name} - {isAdmin && PoolC 임원} - - {department} - - - - - ); -}; - -export default MemberCard; diff --git a/apps/web-client/src/components/members/MemberCard/MemberCard.styles.js b/apps/web-client/src/components/members/MemberCard/MemberCard.styles.ts similarity index 100% rename from apps/web-client/src/components/members/MemberCard/MemberCard.styles.js rename to apps/web-client/src/components/members/MemberCard/MemberCard.styles.ts diff --git a/apps/web-client/src/components/members/MemberCard/MemberCard.tsx b/apps/web-client/src/components/members/MemberCard/MemberCard.tsx new file mode 100644 index 00000000..42927fa0 --- /dev/null +++ b/apps/web-client/src/components/members/MemberCard/MemberCard.tsx @@ -0,0 +1,39 @@ +import colors from '~/lib/styles/colors'; +import { randomNumber } from '~/lib/utils/random'; +import { getProfileImageUrl } from '~/lib/utils/getProfileImageUrl'; + +import { MemberCardBlock, MemberCardMajor, MemberCardName, MemberCardStatus, MemberCardText, MemberCardThumbnail, MemberItem, StyledLink } from './MemberCard.styles'; +import { MENU } from '~/constants/menus'; + +const MemberCard = ({ + member: { loginID, name, department, isAdmin, profileImageURL }, +}: { + member: { + loginID: string; + name: string; + department: string; + isAdmin: boolean; + profileImageURL: string; + }; +}) => ( + + + + + + + {name} + {isAdmin && PoolC 임원} + + {department} + + + + +); + +export default MemberCard; diff --git a/apps/web-client/src/components/members/MemberDetail/MemberDetail.jsx b/apps/web-client/src/components/members/MemberDetail/MemberDetail.jsx deleted file mode 100644 index a857c94b..00000000 --- a/apps/web-client/src/components/members/MemberDetail/MemberDetail.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import Icon from '@ant-design/icons'; -import Avatar from 'antd/es/avatar/avatar'; -import { Block, WhiteBlock } from '../../../styles/common/Block.styles'; -import ActivityCard from '../../activity/ActivityCard/ActivityCard'; -import ProjectCard from '../../projects/ProjectCard/ProjectCard'; -import { - Activities, - ActivityContainer, - ContentContainer, - Department, - DepartmentContainer, - ImageContainer, - Introduction, - IntroductionContainer, - Name, - NameContainer, - Status, - StyledImage, - TextContainer, -} from './MemberDetail.styles'; -import { getProfileImageUrl } from '~/lib/utils/getProfileImageUrl'; -import getFileUrl from '~/lib/utils/getFileUrl'; - -const MemberDetail = ({ member }) => { - const { name, department, profileImageURL, isAdmin, introduction, projects, hostActivities, participantActivities, badge } = member; - return ( - - - - - - - - - {name} - {isAdmin && PoolC임원} - {badge && } - - - {department && ( - <> -

전공

- {department} - - )} -
- - {introduction && ( - <> - - {introduction} - - - )} - -
-
- -

참여 활동

- - {projects?.map((project) => ( - - ))} - {hostActivities?.map((activity) => ( - - ))} - {participantActivities?.map((activity) => ( - - ))} - -
-
-
- ); -}; - -const QuoteLeftIcon = () => ( - - - -); - -const QuoteRightIcon = () => ( - - - -); - -export default MemberDetail; diff --git a/apps/web-client/src/components/members/MemberDetail/MemberDetail.tsx b/apps/web-client/src/components/members/MemberDetail/MemberDetail.tsx new file mode 100644 index 00000000..51f2aea9 --- /dev/null +++ b/apps/web-client/src/components/members/MemberDetail/MemberDetail.tsx @@ -0,0 +1,21 @@ +import { Suspense } from 'react'; +import { useParams } from 'react-router'; +import { Block, WhiteBlock } from '../../../styles/common/Block.styles'; +import Spinner from '~/components/common/Spinner/Spinner'; +import MemberDetailContent from './MemberDetailContent'; + +const MemberDetail = () => { + const { memberID } = useParams<{ memberID: string }>(); + + return ( + + + }> + + + + + ); +}; + +export default MemberDetail; diff --git a/apps/web-client/src/components/members/MemberDetail/MemberDetail.styles.js b/apps/web-client/src/components/members/MemberDetail/MemberDetailContent.styles.ts similarity index 100% rename from apps/web-client/src/components/members/MemberDetail/MemberDetail.styles.js rename to apps/web-client/src/components/members/MemberDetail/MemberDetailContent.styles.ts diff --git a/apps/web-client/src/components/members/MemberDetail/MemberDetailContent.tsx b/apps/web-client/src/components/members/MemberDetail/MemberDetailContent.tsx new file mode 100644 index 00000000..a8dfeb9a --- /dev/null +++ b/apps/web-client/src/components/members/MemberDetail/MemberDetailContent.tsx @@ -0,0 +1,91 @@ +import Icon from '@ant-design/icons'; +import { Avatar } from 'antd'; +import ActivityCard from '~/components/activity/ActivityCard/ActivityCard'; +import ProjectCard from '~/components/projects/ProjectCard/ProjectCard'; +import getFileUrl from '~/lib/utils/getFileUrl'; +import { getProfileImageUrl } from '~/lib/utils/getProfileImageUrl'; +import { + ContentContainer, + ImageContainer, + StyledImage, + TextContainer, + NameContainer, + Name, + Status, + DepartmentContainer, + Department, + IntroductionContainer, + Introduction, + ActivityContainer, + Activities, +} from './MemberDetailContent.styles'; +import { MemberControllerService, MemberResponse, queryKey, useAppSuspenseQuery } from '~/lib/api-v2'; + +export default function MemberDetailContent({ loginId }: { loginId: string }) { + const { data: _member } = useAppSuspenseQuery({ + queryKey: queryKey.member.id(loginId), + queryFn: () => MemberControllerService.getMemberWithProjectAndActivityUsingGet({ loginId }), + }); + + const member = _member as unknown as Required; + + return ( + <> + + + + + + + {member.name} + {member.isAdmin && PoolC임원} + {member.badge && } + + + {member.department && ( + <> +

전공

+ {member.department} + + )} +
+ + {member.introduction && ( + <> + + {member.introduction} + + + )} + +
+
+ +

참여 활동

+ + {member.projects?.map((project) => )} + {/* TODO: fill undefined props */} + {member.hostActivities?.map((activity) => ( + + ))} + {/* TODO: fill undefined props */} + {member.participantActivities?.map((activity) => ( + + ))} + +
+ + ); +} + +const QuoteLeftIcon = () => ( + + + +); + +const QuoteRightIcon = () => ( + + + +); diff --git a/apps/web-client/src/components/members/MemberList/MemberList.jsx b/apps/web-client/src/components/members/MemberList/MemberList.jsx deleted file mode 100644 index e039a9b5..00000000 --- a/apps/web-client/src/components/members/MemberList/MemberList.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import { UNAUTHORIZED_MEMBER_ROLES } from '../../../constants/memberRoles'; -import { Block, WhiteBlock } from '../../../styles/common/Block.styles'; -import Spinner from '../../common/Spinner/Spinner'; -import MemberCard from '../MemberCard/MemberCard'; -import { MemberListHeader, StyledMemberList } from './MemberList.styles'; - -const MemberList = ({ members, loading }) => ( - - - -

회원 목록

-
- {loading && } - {!loading && ( - - {members - .filter((member) => !UNAUTHORIZED_MEMBER_ROLES.includes(member.role)) - .map((member) => ( - - ))} - - )} -
-
-); - -export default MemberList; diff --git a/apps/web-client/src/components/members/MemberList/MemberList.styles.js b/apps/web-client/src/components/members/MemberList/MemberList.styles.js deleted file mode 100644 index c3a6bdb2..00000000 --- a/apps/web-client/src/components/members/MemberList/MemberList.styles.js +++ /dev/null @@ -1,23 +0,0 @@ -import styled from '@emotion/styled'; - -export const MemberListHeader = styled.header` - display: flex; - max-width: 1200px; - justify-content: center; - margin-bottom: 50px; - & > .member_list_title { - display: flex; - align-items: center; - justify-content: center; - flex: 1; - font-weight: 700; - } -`; - -export const StyledMemberList = styled.ul` - width: 100%; - max-width: 1200px; - display: flex; - flex-wrap: wrap; - justify-content: center; -`; diff --git a/apps/web-client/src/components/members/MemberList/MemberList.styles.ts b/apps/web-client/src/components/members/MemberList/MemberList.styles.ts new file mode 100644 index 00000000..37ee1fb7 --- /dev/null +++ b/apps/web-client/src/components/members/MemberList/MemberList.styles.ts @@ -0,0 +1,16 @@ +import styled from '@emotion/styled'; + +export const MemberListHeader = styled.header` + display: flex; + max-width: 1200px; + justify-content: center; + margin-bottom: 50px; +`; + +export const MemberListTitle = styled.h2` + display: flex; + align-items: center; + justify-content: center; + flex: 1; + font-weight: 700; +`; diff --git a/apps/web-client/src/components/members/MemberList/MemberList.tsx b/apps/web-client/src/components/members/MemberList/MemberList.tsx new file mode 100644 index 00000000..03dc8a77 --- /dev/null +++ b/apps/web-client/src/components/members/MemberList/MemberList.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react'; +import { Block, WhiteBlock } from '../../../styles/common/Block.styles'; +import { MemberListHeader, MemberListTitle } from './MemberList.styles'; +import Spinner from '~/components/common/Spinner/Spinner'; +import MemberListContent from './MemberListContent'; + +const MemberList = () => ( + + + + 회원 목록 + + }> + + + + +); + +export default MemberList; diff --git a/apps/web-client/src/components/members/MemberList/MemberListContent.styles.ts b/apps/web-client/src/components/members/MemberList/MemberListContent.styles.ts new file mode 100644 index 00000000..52d3b389 --- /dev/null +++ b/apps/web-client/src/components/members/MemberList/MemberListContent.styles.ts @@ -0,0 +1,9 @@ +import styled from '@emotion/styled'; + +export const StyledMemberList = styled.ul` + width: 100%; + max-width: 1200px; + display: flex; + flex-wrap: wrap; + justify-content: center; +`; diff --git a/apps/web-client/src/components/members/MemberList/MemberListContent.tsx b/apps/web-client/src/components/members/MemberList/MemberListContent.tsx new file mode 100644 index 00000000..56262fbc --- /dev/null +++ b/apps/web-client/src/components/members/MemberList/MemberListContent.tsx @@ -0,0 +1,25 @@ +import { MemberControllerService, MemberResponse, queryKey, useAppSuspenseQuery } from '~/lib/api-v2'; +import { StyledMemberList } from './MemberListContent.styles'; +import { UNAUTHORIZED_MEMBER_ROLES } from '~/constants/memberRoles'; +import MemberCard from '../MemberCard/MemberCard'; + +export default function MemberListContent() { + const { + data: { data: _members }, + } = useAppSuspenseQuery({ + queryKey: queryKey.member.all, + queryFn: MemberControllerService.getAllMembersUsingGet, + }); + + const members = _members as unknown as Required[]; + + return ( + + {members + .filter((member) => !UNAUTHORIZED_MEMBER_ROLES.includes(member.role)) + .map((member) => ( + + ))} + + ); +} diff --git a/apps/web-client/src/containers/member/MemberDetailContainer/MemberDetailContainer.jsx b/apps/web-client/src/containers/member/MemberDetailContainer/MemberDetailContainer.jsx deleted file mode 100644 index c181164a..00000000 --- a/apps/web-client/src/containers/member/MemberDetailContainer/MemberDetailContainer.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useEffect, useState } from 'react'; -import { withRouter } from 'react-router-dom'; -import MemberDetail from '../../../components/members/MemberDetail/MemberDetail'; -import * as memberAPI from '../../../lib/api/member'; -import { MENU } from '../../../constants/menus'; -import Spinner from '../../../components/common/Spinner/Spinner'; -import { SUCCESS } from '../../../constants/statusCode'; - -const MemberDetailContainer = ({ match, history }) => { - const { memberID } = match.params; - const [member, setMember] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - memberAPI - .getMember(memberID) - .then((res) => { - if (res.status === SUCCESS.OK) { - setMember(res.data); - setLoading(false); - } - }) - .catch(() => { - history.push(`/${MENU.FORBIDDEN}`); - }); - }, [memberID, history]); - - return ( - <> - {loading && } - {!loading && } - - ); -}; - -export default withRouter(MemberDetailContainer); diff --git a/apps/web-client/src/containers/member/MemberListContainer/MemberListContainer.jsx b/apps/web-client/src/containers/member/MemberListContainer/MemberListContainer.jsx deleted file mode 100644 index 528e70ec..00000000 --- a/apps/web-client/src/containers/member/MemberListContainer/MemberListContainer.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useEffect, useState } from 'react'; -import { withRouter } from 'react-router-dom'; -import MemberList from '../../../components/members/MemberList/MemberList'; -import * as memberAPI from '../../../lib/api/member'; -import { MENU } from '../../../constants/menus'; -import { SUCCESS } from '../../../constants/statusCode'; - -const MemberListContainer = ({ history }) => { - const [members, setMembers] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - memberAPI - .getMembers() - .then((res) => { - if (res.status === SUCCESS.OK) { - setMembers(res.data.data); - setLoading(false); - } - }) - .catch(() => { - history.push(`/${MENU.FORBIDDEN}`); - }); - }, [history]); - - return ; -}; - -export default withRouter(MemberListContainer); diff --git a/apps/web-client/src/lib/api-v2/queryKey.ts b/apps/web-client/src/lib/api-v2/queryKey.ts index d35c1ece..bee78dbd 100644 --- a/apps/web-client/src/lib/api-v2/queryKey.ts +++ b/apps/web-client/src/lib/api-v2/queryKey.ts @@ -5,6 +5,7 @@ export const queryKey = { hour: ['member.hour'] as const, me: ['member.me'] as const, all: ['member.all'] as const, + id: (loginId: string) => ['member.id', loginId] as const, }, badge: { badge: ['badge.badge'] as const, diff --git a/apps/web-client/src/pages/board/BoardDetailPage.tsx b/apps/web-client/src/pages/board/BoardDetailPage.tsx index 1b8038b0..0498439a 100644 --- a/apps/web-client/src/pages/board/BoardDetailPage.tsx +++ b/apps/web-client/src/pages/board/BoardDetailPage.tsx @@ -7,6 +7,7 @@ import { useForm, zodResolver } from '@mantine/form'; import { z } from 'zod'; import { Viewer } from '@toast-ui/react-editor'; import { FolderOpenTwoTone } from '@ant-design/icons'; +import { useQueryClient } from '@tanstack/react-query'; import { Block, WhiteBlock } from '~/styles/common/Block.styles'; import { MENU } from '~/constants/menus'; import { getBoardTitleByBoardType } from '~/lib/utils/boardUtil'; @@ -19,7 +20,6 @@ import { noop } from '~/lib/utils/noop'; import { getProfileImageUrl } from '~/lib/utils/getProfileImageUrl'; import { convertPositionToText } from '~/lib/utils/positionUtil'; import { useAppSelector } from '~/hooks/useAppSelector'; -import { queryClient } from '~/lib/utils/queryClient'; const useStyles = createStyles(({ css }) => ({ wrapper: css` @@ -126,6 +126,7 @@ export default function BoardDetailPage() { const { styles, cx } = useStyles(); const message = useMessage(); const history = useHistory(); + const queryClient = useQueryClient(); const params = useParams<{ id: string }>(); const postId = Number(params.id); @@ -240,7 +241,13 @@ export default function BoardDetailPage() { { onSuccess() { message.success('삭제되었습니다.'); - history.go(-1); + // TODO: assert 이용해서 수정 + const boardType = post!.boardType!; + queryClient + .invalidateQueries({ + queryKey: queryKey.post.all(boardType, 0), + }) + .then(() => history.push(`/${MENU.BOARD}?${stringify({ boardType })}`)); }, }, ); diff --git a/apps/web-client/src/pages/member/MemberDetailPage.jsx b/apps/web-client/src/pages/member/MemberDetailPage.jsx index 61e15635..b6ef6995 100644 --- a/apps/web-client/src/pages/member/MemberDetailPage.jsx +++ b/apps/web-client/src/pages/member/MemberDetailPage.jsx @@ -1,5 +1,5 @@ -import MemberDetailContainer from '../../containers/member/MemberDetailContainer/MemberDetailContainer'; +import MemberDetail from '~/components/members/MemberDetail/MemberDetail'; -const MemberDetailPage = () => ; +const MemberDetailPage = () => ; export default MemberDetailPage; diff --git a/apps/web-client/src/pages/member/MemberListPage.jsx b/apps/web-client/src/pages/member/MemberListPage.jsx index c52bee69..06e560e9 100644 --- a/apps/web-client/src/pages/member/MemberListPage.jsx +++ b/apps/web-client/src/pages/member/MemberListPage.jsx @@ -1,5 +1,5 @@ -import MemberListContainer from '../../containers/member/MemberListContainer/MemberListContainer'; +import MemberList from '~/components/members/MemberList/MemberList'; -const MemberListPage = () => ; +const MemberListPage = () => ; export default MemberListPage;