From abfaa16f3c5bff57ab892904e7ba5851482ec13a Mon Sep 17 00:00:00 2001 From: jerry Date: Sat, 14 Sep 2024 23:10:37 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20Toast=20mds=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=20=EB=B0=8F=20UX=20=EB=9D=BC=EC=9D=B4=ED=8C=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feed/common/hooks/useReportFeed.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/feed/common/hooks/useReportFeed.ts b/src/components/feed/common/hooks/useReportFeed.ts index 51163cef1..1e05d21cf 100644 --- a/src/components/feed/common/hooks/useReportFeed.ts +++ b/src/components/feed/common/hooks/useReportFeed.ts @@ -1,9 +1,8 @@ +import { useToast } from '@sopt-makers/ui'; import { useCallback } from 'react'; import { usePostReportPostMutation } from '@/api/endpoint/feed/postReportPost'; -import useAlert from '@/components/common/Modal/useAlert'; import useConfirm from '@/components/common/Modal/useConfirm'; -import usePopup from '@/components/common/Modal/usePopup'; interface Options { postId: string; @@ -12,15 +11,14 @@ interface Options { export const useReportFeed = () => { const { confirm } = useConfirm(); - const { alert } = useAlert(); const { mutate } = usePostReportPostMutation(); - const { popup } = usePopup(); + const { open } = useToast(); const handleReport = useCallback( async (options: Options) => { const result = await confirm({ title: '이 글을 신고하시겠습니까?', - description: '글을 신고할 경우, 메이커스에서 검토를 거쳐 적절한 조치 및 게시자 제재를 취해요.', + description: '글을 신고할 경우, 메이커스에서 검토를 거쳐 적절한 조치 및 게시자 제재를 취할 예정이에요.', okButtonText: '신고하기', cancelButtonText: '취소', maxWidth: 324, @@ -29,19 +27,22 @@ export const useReportFeed = () => { if (result) { mutate(options.postId, { onSuccess: () => { - popup({ - icon: '/icons/check_box_field.svg', - title: '신고해주셔서 감사해요', - description: - '메이커스에서 빠르게 검토 후 적절한 조치를 취할게요 :) 건전한 커뮤니티를 만드는데 기여해주셔서 감사해요!', - maxWidth: 324, + open({ + icon: 'success', + content: '신고가 완료되었어요.\n건전한 커뮤니티를 함께 만들어주셔서 감사해요!', + style: { + content: { + whiteSpace: 'pre-wrap', + }, + }, }); + options.onSuccess?.(); }, }); } }, - [confirm, alert, mutate], + [confirm, open, mutate], ); return { handleReport }; From e8bcab17aebd18c01a4b26c69d7657423c607889 Mon Sep 17 00:00:00 2001 From: jerry Date: Sat, 14 Sep 2024 23:36:49 +0900 Subject: [PATCH 02/18] =?UTF-8?q?fix:=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EB=B7=B0=EC=97=90=EC=84=9C=20=ED=97=A4=EB=8D=94=EB=B3=B4?= =?UTF-8?q?=EB=8B=A4=20=EB=86=92=EC=9D=B4=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?zIndex=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/common/hooks/useReportFeed.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/feed/common/hooks/useReportFeed.ts b/src/components/feed/common/hooks/useReportFeed.ts index 1e05d21cf..cf89dc677 100644 --- a/src/components/feed/common/hooks/useReportFeed.ts +++ b/src/components/feed/common/hooks/useReportFeed.ts @@ -3,6 +3,7 @@ import { useCallback } from 'react'; import { usePostReportPostMutation } from '@/api/endpoint/feed/postReportPost'; import useConfirm from '@/components/common/Modal/useConfirm'; +import { zIndex } from '@/styles/zIndex'; interface Options { postId: string; @@ -22,6 +23,7 @@ export const useReportFeed = () => { okButtonText: '신고하기', cancelButtonText: '취소', maxWidth: 324, + zIndex: zIndex.헤더, }); if (result) { From 6efe29760fa9d6bd795e69c689ca655108c902bd Mon Sep 17 00:00:00 2001 From: jerry Date: Sat, 14 Sep 2024 23:55:09 +0900 Subject: [PATCH 03/18] =?UTF-8?q?fix:=20dialog=20=EB=AA=A8=EB=B0=94?= =?UTF-8?q?=EC=9D=BC=20=ED=8F=B0=ED=8A=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Modal/useConfirm.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/common/Modal/useConfirm.tsx b/src/components/common/Modal/useConfirm.tsx index f9fd6acfb..f3046f7a8 100644 --- a/src/components/common/Modal/useConfirm.tsx +++ b/src/components/common/Modal/useConfirm.tsx @@ -75,4 +75,8 @@ const StyleModalDescription = styled.div` line-height: 26px; white-space: pre-wrap; color: ${colors.gray100}; + + @media ${MOBILE_MEDIA_QUERY} { + ${fonts.BODY_14_R} + } `; From d51b5e4e50edd011c9e69317426a38f186fed2e3 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 00:03:58 +0900 Subject: [PATCH 04/18] =?UTF-8?q?fix:=20maxWidth=20400=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/common/hooks/useReportFeed.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/feed/common/hooks/useReportFeed.ts b/src/components/feed/common/hooks/useReportFeed.ts index cf89dc677..3b2be68c6 100644 --- a/src/components/feed/common/hooks/useReportFeed.ts +++ b/src/components/feed/common/hooks/useReportFeed.ts @@ -22,7 +22,7 @@ export const useReportFeed = () => { description: '글을 신고할 경우, 메이커스에서 검토를 거쳐 적절한 조치 및 게시자 제재를 취할 예정이에요.', okButtonText: '신고하기', cancelButtonText: '취소', - maxWidth: 324, + maxWidth: 400, zIndex: zIndex.헤더, }); From 018239306dd72978aab0b59d1a22a0384ee8f799 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 00:51:42 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A9=94=EB=89=B4=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=82=B4=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=EC=9D=B8=EC=A7=80=20=EC=97=AC=EB=B6=80=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=EC=84=9C=20=EC=88=98=EC=A0=95/=EB=A9=94=EB=89=B4=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icons/icon-dots-vertical.svg | 8 +++++ .../detail/ActivitySection/MemberDetail.tsx | 32 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 public/icons/icon-dots-vertical.svg diff --git a/public/icons/icon-dots-vertical.svg b/public/icons/icon-dots-vertical.svg new file mode 100644 index 000000000..1abc38443 --- /dev/null +++ b/public/icons/icon-dots-vertical.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index d77083f9f..d58e6e278 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -9,7 +9,6 @@ import CallIcon from 'public/icons/icon-call.svg'; import EditIcon from 'public/icons/icon-edit.svg'; import MailIcon from 'public/icons/icon-mail.svg'; import ProfileIcon from 'public/icons/icon-profile.svg'; -import IconCoffee from '@/public/icons/icon-coffee.svg'; import { FC, useMemo } from 'react'; import { useGetMemberCrewInfiniteQuery } from '@/api/endpoint/members/getMemberCrew'; @@ -31,6 +30,8 @@ import { DEFAULT_DATE } from '@/components/members/upload/constants'; import { playgroundLink } from '@/constants/links'; import useEnterScreen from '@/hooks/useEnterScreen'; import { useRunOnce } from '@/hooks/useRunOnce'; +import IconCoffee from '@/public/icons/icon-coffee.svg'; +import IconMore from '@/public/icons/icon-dots-vertical.svg'; import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery'; import { textStyles } from '@/styles/typography'; import { safeParseInt } from '@/utils'; @@ -147,7 +148,7 @@ const MemberDetail: FC = ({ memberId }) => { - {profile.isMine && ( + {profile.isMine ? ( { router.push(playgroundLink.memberEdit()); @@ -156,6 +157,10 @@ const MemberDetail: FC = ({ memberId }) => { > + ) : ( + + + )} @@ -423,7 +428,7 @@ const EditButton = styled.div` const NameWrapper = styled.div` display: flex; gap: 12px; - align-items: flex-end; + align-items: center; .name { line-height: 100%; @@ -626,3 +631,24 @@ const IconContainer = styled.div` } } `; + +const MoreIconContainer = styled.div` + width: 100%; + height: 171px; + text-align: right; + + @media ${MOBILE_MEDIA_QUERY} { + height: auto; + } +`; + +const StyledIconMore = styled(IconMore)` + cursor: pointer; + padding-top: 12px; + width: 24px; + height: 24px; + + @media ${MOBILE_MEDIA_QUERY} { + padding-top: 4px; + } +`; From 1946950c1b64cd4d0f9565df8bd380dfc2c0fe60 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 19:58:43 +0900 Subject: [PATCH 06/18] =?UTF-8?q?feat:=20Dropdown=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B6=94=EA=B0=80=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/common/FeedDropdown.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/feed/common/FeedDropdown.tsx b/src/components/feed/common/FeedDropdown.tsx index 00387502f..6c3d760d9 100644 --- a/src/components/feed/common/FeedDropdown.tsx +++ b/src/components/feed/common/FeedDropdown.tsx @@ -1,3 +1,4 @@ +import { css } from '@emotion/react'; import styled from '@emotion/styled'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { m } from 'framer-motion'; @@ -10,14 +11,20 @@ const DropdownPortal = dynamic(() => import('@radix-ui/react-dropdown-menu').the interface FeedDropdownProps { trigger?: ReactNode; + style?: React.CSSProperties; } -const Base = ({ trigger, children }: PropsWithChildren) => { +const Base = ({ trigger, style, children }: PropsWithChildren) => { return ( {trigger} - + {children} From 48e0b674c142ded239c0474c1855efd5d6c0b1ea Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 20:00:28 +0900 Subject: [PATCH 07/18] =?UTF-8?q?feat:=20Dropdown=20UI=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=8B=A0=EA=B3=A0,=20=EC=B0=A8=EB=8B=A8=20Item=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=B0=98=EC=9D=91=ED=98=95=20?= =?UTF-8?q?width=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/ActivitySection/MemberDetail.tsx | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index d58e6e278..cb5afef23 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -9,7 +9,7 @@ import CallIcon from 'public/icons/icon-call.svg'; import EditIcon from 'public/icons/icon-edit.svg'; import MailIcon from 'public/icons/icon-mail.svg'; import ProfileIcon from 'public/icons/icon-profile.svg'; -import { FC, useMemo } from 'react'; +import { CSSProperties, FC, useEffect, useMemo, useState } from 'react'; import { useGetMemberCrewInfiniteQuery } from '@/api/endpoint/members/getMemberCrew'; import { useGetMemberOfMe } from '@/api/endpoint/members/getMemberOfMe'; @@ -18,6 +18,7 @@ import Loading from '@/components/common/Loading'; import ResizedImage from '@/components/common/ResizedImage'; import Text from '@/components/common/Text'; import useEventLogger from '@/components/eventLogger/hooks/useEventLogger'; +import FeedDropdown from '@/components/feed/common/FeedDropdown'; import MemberDetailSection from '@/components/members/detail/ActivitySection/MemberDetailSection'; import MemberMeetingCard from '@/components/members/detail/ActivitySection/MemberMeetingCard'; import MemberProjectCard from '@/components/members/detail/ActivitySection/MemberProjectCard'; @@ -60,6 +61,13 @@ const MemberDetail: FC = ({ memberId }) => { }, }); + const [dropdownOpenStyle, setDropdownOpenStyle] = useState({ + position: 'absolute', + right: '-12px', + top: '10px', + minWidth: '133px', + }); + const { data: profile, isLoading, @@ -91,6 +99,19 @@ const MemberDetail: FC = ({ memberId }) => { } }, [profile, memberId]); + useEffect(() => { + const resizeMenuWidth = () => { + setDropdownOpenStyle((prevStyle) => ({ + ...prevStyle, + minWidth: window.innerWidth <= 768 ? '100px' : '133px', + })); + }; + + resizeMenuWidth(); + + window.addEventListener('resize', resizeMenuWidth); + }, []); + if (profileError?.response?.status === 400 || (axios.isAxiosError(crewError) && crewError.response?.status === 400)) { return ; } @@ -159,7 +180,10 @@ const MemberDetail: FC = ({ memberId }) => { ) : ( - + } style={dropdownOpenStyle}> + 신고 + 차단 + )} @@ -633,6 +657,7 @@ const IconContainer = styled.div` `; const MoreIconContainer = styled.div` + position: relative; width: 100%; height: 171px; text-align: right; From 0f01610d484973b9090771530294b2466fa1e1a2 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 20:42:43 +0900 Subject: [PATCH 08/18] =?UTF-8?q?fix:=20=EB=AA=A8=EB=8B=AC=20Title=20?= =?UTF-8?q?=ED=8F=B0=ED=8A=B8=20=EB=B0=98=EC=9D=91=ED=98=95=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Modal/parts/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/common/Modal/parts/index.tsx b/src/components/common/Modal/parts/index.tsx index d0f9cbfef..a195e6330 100644 --- a/src/components/common/Modal/parts/index.tsx +++ b/src/components/common/Modal/parts/index.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; +import { fonts } from '@sopt-makers/fonts'; import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery'; import { textStyles } from '@/styles/typography'; @@ -16,7 +17,11 @@ export const ModalTitle = styled.h1` margin-bottom: 12px; line-height: 24px; - ${textStyles.SUIT_18_B} + ${fonts.TITLE_20_SB} + + @media ${MOBILE_MEDIA_QUERY} { + ${fonts.TITLE_18_SB} + } `; export const ModalDescription = styled.div` From 77b159fef881174574c649b73c184f0312f8d245 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 20:45:40 +0900 Subject: [PATCH 09/18] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=EC=8B=A0?= =?UTF-8?q?=EA=B3=A0=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/endpoint/members/postReportMember.ts | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/api/endpoint/members/postReportMember.ts diff --git a/src/api/endpoint/members/postReportMember.ts b/src/api/endpoint/members/postReportMember.ts new file mode 100644 index 000000000..87dcd0c56 --- /dev/null +++ b/src/api/endpoint/members/postReportMember.ts @@ -0,0 +1,23 @@ +import { useMutation } from '@tanstack/react-query'; +import { z } from 'zod'; + +import { createEndpoint } from '@/api/typedAxios'; + +interface RequestBody { + reportMemberId: number; +} + +export const postReportMember = createEndpoint({ + request: (requestBody: RequestBody) => ({ + method: 'POST', + url: `api/v1/members/report`, + data: requestBody, + }), + serverResponseScheme: z.unknown(), +}); + +export const usePostReportMemberMutation = () => { + return useMutation({ + mutationFn: (requestBody: RequestBody) => postReportMember.request(requestBody), + }); +}; From 44ee9cf00f91c29163c98914875b95910752afa3 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 20:46:39 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat:=20useReportMember=20=ED=9B=85=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=A4=EB=B2=84=20=EC=8B=A0=EA=B3=A0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/ActivitySection/MemberDetail.tsx | 11 ++++- .../members/hooks/useReportMember.ts | 43 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/components/members/hooks/useReportMember.ts diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index cb5afef23..f1d9f2751 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -27,6 +27,7 @@ import EmptyProfile from '@/components/members/detail/EmptyProfile'; import InfoItem from '@/components/members/detail/InfoItem'; import InterestSection from '@/components/members/detail/InterestSection'; import SoptActivitySection from '@/components/members/detail/SoptActivitySection'; +import { useReportMember } from '@/components/members/hooks/useReportMember'; import { DEFAULT_DATE } from '@/components/members/upload/constants'; import { playgroundLink } from '@/constants/links'; import useEnterScreen from '@/hooks/useEnterScreen'; @@ -112,6 +113,8 @@ const MemberDetail: FC = ({ memberId }) => { window.addEventListener('resize', resizeMenuWidth); }, []); + const { handleReportMember } = useReportMember(); + if (profileError?.response?.status === 400 || (axios.isAxiosError(crewError) && crewError.response?.status === 400)) { return ; } @@ -181,7 +184,13 @@ const MemberDetail: FC = ({ memberId }) => { ) : ( } style={dropdownOpenStyle}> - 신고 + { + handleReportMember(safeParseInt(memberId) ?? undefined); + }} + > + 신고 + 차단 diff --git a/src/components/members/hooks/useReportMember.ts b/src/components/members/hooks/useReportMember.ts new file mode 100644 index 000000000..0b5687638 --- /dev/null +++ b/src/components/members/hooks/useReportMember.ts @@ -0,0 +1,43 @@ +import { useToast } from '@sopt-makers/ui'; + +import { usePostReportMemberMutation } from '@/api/endpoint/members/postReportMember'; +import useConfirm from '@/components/common/Modal/useConfirm'; + +export const useReportMember = () => { + const { confirm } = useConfirm(); + const { open } = useToast(); + const { mutate } = usePostReportMemberMutation(); + + const handleReportMember = async (memberId?: number) => { + if (!memberId) throw new Error('Invalid Member id'); + + const result = await confirm({ + title: '이 멤버를 신고하시겠습니까?', + description: '멤버를 신고할 경우, 메이커스에서 검토를 거쳐 적절한 조치 및 제재를 취할 예정이에요.', + okButtonText: '신고하기', + cancelButtonText: '취소', + maxWidth: 400, + }); + + if (result) { + mutate( + { reportMemberId: memberId }, + { + onSuccess: () => { + open({ + icon: 'success', + content: '신고가 완료되었어요.\n건전한 커뮤니티를 함께 만들어주셔서 감사해요!', + style: { + content: { + whiteSpace: 'pre-wrap', + }, + }, + }); + }, + }, + ); + } + }; + + return { handleReportMember }; +}; From 5f6104b947bcb1151e3473506d348f41028c9c3e Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 22:30:12 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=EC=B0=A8?= =?UTF-8?q?=EB=8B=A8=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/endpoint/members/postBlockMember.ts | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/api/endpoint/members/postBlockMember.ts diff --git a/src/api/endpoint/members/postBlockMember.ts b/src/api/endpoint/members/postBlockMember.ts new file mode 100644 index 000000000..4cdb159d5 --- /dev/null +++ b/src/api/endpoint/members/postBlockMember.ts @@ -0,0 +1,24 @@ +import { useMutation } from '@tanstack/react-query'; +import { z } from 'zod'; + +import { createEndpoint } from '@/api/typedAxios'; + +interface RequestBody { + blockedMemberId: number; +} + +export const postBlockMember = createEndpoint({ + request: (requestBody: RequestBody) => ({ + method: 'PATCH', + url: `api/v1/members/block/activate`, + data: requestBody, + }), + serverResponseScheme: z.unknown(), +}); + +export const usePostBlockMemberMutation = () => { + console.log('in hook'); + return useMutation({ + mutationFn: (requestBody: RequestBody) => postBlockMember.request(requestBody), + }); +}; From ccb3a6702bae875e31e29e6f41c6bb8a7154e438 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 22:30:54 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat:=20useBlockMember=20=ED=9B=85=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=A4=EB=B2=84=20=EC=B0=A8=EB=8B=A8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/ActivitySection/MemberDetail.tsx | 11 +++- .../members/hooks/useBlockMember.ts | 53 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/components/members/hooks/useBlockMember.ts diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index f1d9f2751..7066f08e6 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -27,6 +27,7 @@ import EmptyProfile from '@/components/members/detail/EmptyProfile'; import InfoItem from '@/components/members/detail/InfoItem'; import InterestSection from '@/components/members/detail/InterestSection'; import SoptActivitySection from '@/components/members/detail/SoptActivitySection'; +import { useBlockMember } from '@/components/members/hooks/useBlockMember'; import { useReportMember } from '@/components/members/hooks/useReportMember'; import { DEFAULT_DATE } from '@/components/members/upload/constants'; import { playgroundLink } from '@/constants/links'; @@ -114,6 +115,7 @@ const MemberDetail: FC = ({ memberId }) => { }, []); const { handleReportMember } = useReportMember(); + const { handleBlockMember } = useBlockMember(); if (profileError?.response?.status === 400 || (axios.isAxiosError(crewError) && crewError.response?.status === 400)) { return ; @@ -191,7 +193,14 @@ const MemberDetail: FC = ({ memberId }) => { > 신고 - 차단 + { + handleBlockMember(safeParseInt(memberId) ?? undefined); + }} + > + 차단 + )} diff --git a/src/components/members/hooks/useBlockMember.ts b/src/components/members/hooks/useBlockMember.ts new file mode 100644 index 000000000..b4e74d318 --- /dev/null +++ b/src/components/members/hooks/useBlockMember.ts @@ -0,0 +1,53 @@ +import { colors } from '@sopt-makers/colors'; +import { useToast } from '@sopt-makers/ui'; +import { useQueryClient } from '@tanstack/react-query'; +import { useRouter } from 'next/router'; +import { playgroundLink } from 'playground-common/export'; + +import { usePostBlockMemberMutation } from '@/api/endpoint/members/postBlockMember'; +import useConfirm from '@/components/common/Modal/useConfirm'; + +export const useBlockMember = () => { + const router = useRouter(); + const queryClient = useQueryClient(); + + const { confirm } = useConfirm(); + const { open } = useToast(); + const { mutate } = usePostBlockMemberMutation(); + + const handleBlockMember = async (memberId?: number) => { + if (!memberId) throw new Error('Invalid Member id'); + + const result = await confirm({ + title: '이 멤버를 차단하시겠습니까?', + description: + '차단 시 멤버 리스트는 유지되지만, 이 멤버의 게시글과 댓글이 보이지 않게 돼요. 한 번 차단한 멤버는 다시 해제할 수 없어요.', + okButtonText: '차단하기', + okButtonColor: colors.error, + okButtonTextColor: colors.white, + cancelButtonText: '취소', + maxWidth: 400, + }); + + if (result) { + mutate( + { blockedMemberId: memberId }, + { + onSuccess: async () => { + queryClient.invalidateQueries({ + predicate: (query) => query.queryKey.some((key) => String(key).includes('community')), + }); + await router.push(playgroundLink.memberList()); + + open({ + icon: 'success', + content: '멤버가 차단되었어요.', + }); + }, + }, + ); + } + }; + + return { handleBlockMember }; +}; From 6c57f725509d87b113a5b948027f93b23bfc5b93 Mon Sep 17 00:00:00 2001 From: jerry Date: Sun, 15 Sep 2024 23:58:12 +0900 Subject: [PATCH 13/18] =?UTF-8?q?chore:=20=EC=BD=98=EC=86=94=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/endpoint/members/postBlockMember.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/endpoint/members/postBlockMember.ts b/src/api/endpoint/members/postBlockMember.ts index 4cdb159d5..77ed32694 100644 --- a/src/api/endpoint/members/postBlockMember.ts +++ b/src/api/endpoint/members/postBlockMember.ts @@ -17,7 +17,6 @@ export const postBlockMember = createEndpoint({ }); export const usePostBlockMemberMutation = () => { - console.log('in hook'); return useMutation({ mutationFn: (requestBody: RequestBody) => postBlockMember.request(requestBody), }); From 2c8f9510162faf206ea0134d3be37325b158a1ca Mon Sep 17 00:00:00 2001 From: jerry Date: Tue, 17 Sep 2024 00:39:05 +0900 Subject: [PATCH 14/18] =?UTF-8?q?chore:=20sopt-makers/icons=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + yarn.lock | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/package.json b/package.json index 46697a105..8972fc662 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@radix-ui/react-tooltip": "^1.0.5", "@sopt-makers/colors": "^3.0.0", "@sopt-makers/fonts": "^1.0.0", + "@sopt-makers/icons": "^1.0.5", "@sopt-makers/ui": "^2.0.5", "@tanstack/react-query": "^5.4.3", "@toss/emotion-utils": "^1.1.10", diff --git a/yarn.lock b/yarn.lock index 832847019..489f6a48f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6247,6 +6247,15 @@ __metadata: languageName: node linkType: hard +"@sopt-makers/icons@npm:^1.0.5": + version: 1.0.5 + resolution: "@sopt-makers/icons@npm:1.0.5" + peerDependencies: + react: ^18.2.0 + checksum: 6dbaa9748508adb4fa21042789c0a2c3a3c1c586e45355b76280cba0e30d2da0414c288605fa841b76b71dec993a2d2fcec5b26aaf2fd4d0c8be8cd2c99f01db + languageName: node + linkType: hard + "@sopt-makers/playground-common@workspace:playground-common": version: 0.0.0-use.local resolution: "@sopt-makers/playground-common@workspace:playground-common" @@ -19737,6 +19746,7 @@ __metadata: "@radix-ui/react-tooltip": ^1.0.5 "@sopt-makers/colors": ^3.0.0 "@sopt-makers/fonts": ^1.0.0 + "@sopt-makers/icons": ^1.0.5 "@sopt-makers/ui": ^2.0.5 "@storybook/addon-actions": ^7.0.23 "@storybook/addon-docs": ^7.0.23 From cc206574fae26d2fb4c60eaa3308bd57febe88a7 Mon Sep 17 00:00:00 2001 From: jerry Date: Tue, 17 Sep 2024 00:47:37 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EB=A9=94=EB=89=B4=20?= =?UTF-8?q?=EB=93=9C=EB=A1=AD=EB=8B=A4=EC=9A=B4=EC=8B=9C=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20=ED=91=9C=EA=B8=B0=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../members/detail/ActivitySection/MemberDetail.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index 7066f08e6..8f05ef1d0 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -1,5 +1,7 @@ import styled from '@emotion/styled'; import { colors } from '@sopt-makers/colors'; +import { IconAlertTriangle, IconUserX } from '@sopt-makers/icons'; +import { Flex } from '@toss/emotion-utils'; import axios from 'axios'; import dayjs from 'dayjs'; import { uniq } from 'lodash-es'; @@ -191,7 +193,10 @@ const MemberDetail: FC = ({ memberId }) => { handleReportMember(safeParseInt(memberId) ?? undefined); }} > - 신고 + + + 신고 + = ({ memberId }) => { handleBlockMember(safeParseInt(memberId) ?? undefined); }} > - 차단 + + 차단 + From b3d21b85c2c3637dab6c8cc4ceec113dcf912fab Mon Sep 17 00:00:00 2001 From: jerry Date: Tue, 17 Sep 2024 17:17:26 +0900 Subject: [PATCH 16/18] =?UTF-8?q?fix:=20=EC=95=84=EC=9D=B4=EC=BD=98?= =?UTF-8?q?=EA=B3=BC=20=EA=B8=80=EC=9E=90=20=EC=82=AC=EC=9D=B4=20gap=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../members/detail/ActivitySection/MemberDetail.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/members/detail/ActivitySection/MemberDetail.tsx b/src/components/members/detail/ActivitySection/MemberDetail.tsx index 8f05ef1d0..d6e09f171 100644 --- a/src/components/members/detail/ActivitySection/MemberDetail.tsx +++ b/src/components/members/detail/ActivitySection/MemberDetail.tsx @@ -193,7 +193,7 @@ const MemberDetail: FC = ({ memberId }) => { handleReportMember(safeParseInt(memberId) ?? undefined); }} > - + 신고 @@ -204,7 +204,7 @@ const MemberDetail: FC = ({ memberId }) => { handleBlockMember(safeParseInt(memberId) ?? undefined); }} > - + 차단 From 2facec0d6a859c5f9313c251e4368d33b6afb927 Mon Sep 17 00:00:00 2001 From: jerry Date: Tue, 17 Sep 2024 17:34:22 +0900 Subject: [PATCH 17/18] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A9=94=EB=89=B4=20=EB=93=9C=EB=A1=AD?= =?UTF-8?q?=EB=8B=A4=EC=9A=B4=EC=8B=9C=20=EC=95=84=EC=9D=B4=EC=BD=98=20?= =?UTF-8?q?=ED=91=9C=EA=B8=B0=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/detail/FeedDetail.tsx | 50 ++++++++++++++-------- src/components/feed/list/FeedListItems.tsx | 25 ++++++++--- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/components/feed/detail/FeedDetail.tsx b/src/components/feed/detail/FeedDetail.tsx index 060c781b7..1837a4a0d 100644 --- a/src/components/feed/detail/FeedDetail.tsx +++ b/src/components/feed/detail/FeedDetail.tsx @@ -1,4 +1,7 @@ +import { colors } from '@sopt-makers/colors'; +import { IconAlertTriangle, IconTrash, IconWrite } from '@sopt-makers/icons'; import { useQueryClient } from '@tanstack/react-query'; +import { Flex } from '@toss/emotion-utils'; import { ErrorBoundary } from '@toss/error-boundary'; import Link from 'next/link'; import { playgroundLink } from 'playground-common/export'; @@ -75,30 +78,43 @@ const FeedDetail = ({ postId, renderCategoryLink, renderBackLink }: FeedDetailPr } > {postData.isMine ? ( - - 수정 - - ) : null} - {postData.isMine ? ( + <> + + + + + 수정 + + + + + { + e.stopPropagation(); + handleDeleteFeed({ postId }); + }} + > + + + 삭제 + + + + ) : ( { e.stopPropagation(); - handleDeleteFeed({ postId }); + handleReportFeed({ postId }); }} > - 삭제 + + + 신고 + - ) : null} - { - e.stopPropagation(); - handleReportFeed({ postId }); - }} - > - 신고 - + )} } diff --git a/src/components/feed/list/FeedListItems.tsx b/src/components/feed/list/FeedListItems.tsx index 91bbf0ba1..a24981942 100644 --- a/src/components/feed/list/FeedListItems.tsx +++ b/src/components/feed/list/FeedListItems.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; import { colors } from '@sopt-makers/colors'; +import { IconAlertTriangle, IconShare, IconTrash, IconWrite } from '@sopt-makers/icons'; import { useQuery } from '@tanstack/react-query'; import { Flex } from '@toss/emotion-utils'; import Link from 'next/link'; @@ -160,10 +161,16 @@ const FeedListItems: FC = ({ categoryId, renderFeedDetailLin } + style={{ minWidth: '133px', position: 'relative', top: '10px', right: '52px' }} > {post.isMine ? ( - 수정 + + + + 수정 + + ) : null} @@ -173,7 +180,10 @@ const FeedListItems: FC = ({ categoryId, renderFeedDetailLin handleShareFeed(`${post.id}`); }} > - 공유 + + + 공유 + {post.isMine ? ( @@ -189,18 +199,23 @@ const FeedListItems: FC = ({ categoryId, renderFeedDetailLin }} type='danger' > - 삭제 + + + 삭제 + ) : null} {!post.isMine ? ( { e.stopPropagation(); handleReport({ postId: `${post.id}` }); }} > - 신고 + + + 신고 + ) : null} From f925388aaaf5d923d52315d53cae639ad6d1c724 Mon Sep 17 00:00:00 2001 From: jerry Date: Tue, 17 Sep 2024 17:41:20 +0900 Subject: [PATCH 18/18] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/feed/common/FeedDropdown.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/feed/common/FeedDropdown.tsx b/src/components/feed/common/FeedDropdown.tsx index 6c3d760d9..eb309191b 100644 --- a/src/components/feed/common/FeedDropdown.tsx +++ b/src/components/feed/common/FeedDropdown.tsx @@ -1,4 +1,3 @@ -import { css } from '@emotion/react'; import styled from '@emotion/styled'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { m } from 'framer-motion';