diff --git a/src/app/(team)/team/_components/MemberList/BreakEmail.tsx b/src/app/(team)/team/_components/MemberList/BreakEmail.tsx deleted file mode 100644 index 65ccaf1f..00000000 --- a/src/app/(team)/team/_components/MemberList/BreakEmail.tsx +++ /dev/null @@ -1,49 +0,0 @@ -'use client'; -import { useEffect, useRef, useState } from 'react'; - -const BreakEmail = ({ email }: { email: string }) => { - const [shouldBreak, setShouldBreak] = useState(null); - const wrapperRef = useRef(null); - const textRef = useRef(null); - - useEffect(() => { - const handleResize = () => { - const wrapper = wrapperRef.current; - const text = textRef.current; - if (!wrapper || !text) return; - - const isOverflowing = text.scrollWidth > wrapper.clientWidth; - setShouldBreak(isOverflowing); - }; - - handleResize(); - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, [email]); - - const [local, domain] = email.includes('@') ? email.split('@') : [email]; - - return ( -
- - {email} - - - {shouldBreak && email.includes('@') ? ( -

- {local} - {'\n'}@{domain} -

- ) : ( - - {email} - - )} -
- ); -}; - -export default BreakEmail; diff --git a/src/app/(team)/team/_components/MemberList/MemberCard.tsx b/src/app/(team)/team/_components/MemberList/MemberCard.tsx index 019c328e..5bdead5a 100644 --- a/src/app/(team)/team/_components/MemberList/MemberCard.tsx +++ b/src/app/(team)/team/_components/MemberList/MemberCard.tsx @@ -1,5 +1,4 @@ import UserIcon from '@/components/user/UserIcon'; -import BreakEmail from '@/app/(team)/team/_components/MemberList/BreakEmail'; import MemberMenu from '@/app/(team)/team/_components/MemberList/MemberMenu'; import MemberProfileModal from '@/components/common/Modal/content/MemberProfileModal'; import { useModalStore } from '@/store/useModalStore'; @@ -8,7 +7,9 @@ import { GroupResponse } from '@/lib/apis/group/type'; import { memberCardContainerStyle, memberCardItemWrapperStyle, - memberCardTextWrapperStyle, + memberCardProfileWrapperStyle, + memberCardNameStyle, + memberCardEmailStyle, } from '@/app/(team)/team/_components/MemberList/styles'; import { toast } from 'react-toastify'; import { TOAST_MESSAGES } from '@/constants/messages'; @@ -68,28 +69,25 @@ const MemberCard = ({ }} className={`${memberCardContainerStyle}`} > - {/* 아이템 래퍼 */} + {/* left item */}
-
- {/* 프로필 아이콘 */} + {/* 프로필 아이콘 */} +
- - {/* 이름 + 이메일 */} -
-

{name}

- -
- - {/* 메뉴 버튼 */} - {isAdmin && userId !== memberId && ( - - )} + {/* 이름 */} +

{name}

+ {/* 이메일 */} +

{email}

+ {/* 메뉴 버튼 */} + {isAdmin && userId !== memberId && ( + + )}
); }; diff --git a/src/app/(team)/team/_components/MemberList/MemberMenu.tsx b/src/app/(team)/team/_components/MemberList/MemberMenu.tsx index 39e9a2b6..814f0dda 100644 --- a/src/app/(team)/team/_components/MemberList/MemberMenu.tsx +++ b/src/app/(team)/team/_components/MemberList/MemberMenu.tsx @@ -25,7 +25,7 @@ const MemberMenu = ({ memberId, name, onDelete }: MemberMenuProps) => { return ( - + diff --git a/src/app/(team)/team/_components/MemberList/styles.ts b/src/app/(team)/team/_components/MemberList/styles.ts index a33c3096..a67c443d 100644 --- a/src/app/(team)/team/_components/MemberList/styles.ts +++ b/src/app/(team)/team/_components/MemberList/styles.ts @@ -21,18 +21,28 @@ export const memberCardContainerStyle = clsx( 'flex items-center justify-center', 'laptop:max-w-[384px] tablet:h-[73px] h-[68px] min-w-0', 'bg-slate-800', - 'p-3 rounded-[16px]', + 'px-6 rounded-[16px]', 'cursor-pointer' ); -export const memberCardItemWrapperStyle = clsx( - 'flex items-center justify-between', - 'laptop:max-w-[336px] h-full', - 'w-full' +export const memberCardItemWrapperStyle = + 'grid grid-cols-[min-content_1fr] grid-rows-[auto_auto] gap-x-3 w-full'; + +export const memberCardProfileWrapperStyle = clsx( + 'tablet:row-span-2 tablet:items-center', + 'flex flex-col col-span-1 row-span-1 items-start justify-center' ); -export const memberCardTextWrapperStyle = clsx( - 'flex flex-col justify-center gap-0.5', - 'laptop:max-w-[200px] tablet:max-w-[120px] max-w-[85px]', - 'w-full' +export const memberCardNameStyle = clsx( + 'text-md-medium', + 'col-span-1 col-start-2 row-span-1 row-start-1 self-center text-left', + 'truncate' +); + +export const memberCardEmailStyle = clsx( + 'text-xs-regular text-slate-300', + 'tablet:col-span-1 tablet:col-start-2', + 'col-span-2 col-start-1 row-span-1 row-start-2 text-left', + 'mt-0.5', + 'truncate' ); diff --git a/src/app/(team)/team/_components/ReportBanner/styles.ts b/src/app/(team)/team/_components/ReportBanner/styles.ts index 5bb93261..c13d6b71 100644 --- a/src/app/(team)/team/_components/ReportBanner/styles.ts +++ b/src/app/(team)/team/_components/ReportBanner/styles.ts @@ -37,7 +37,7 @@ export const reportCardsWrapperStyle = clsx( export const reportCardContainerStyle = clsx( 'flex items-center justify-center', 'max-w-[400px]', - 'laptop:h-[76.5px] h-[80px] w-full min-w-0 p-4', + 'h-[77px] w-full min-w-0 p-4', 'bg-slate-700', RADIUS ); diff --git a/src/app/(team)/team/_components/TeamBanner/TeamBannerMenu.tsx b/src/app/(team)/team/_components/TeamBanner/TeamBannerMenu.tsx new file mode 100644 index 00000000..07bea328 --- /dev/null +++ b/src/app/(team)/team/_components/TeamBanner/TeamBannerMenu.tsx @@ -0,0 +1,71 @@ +import DropDown from '@/components/common/Dropdown'; +import IconRenderer from '@/components/common/Icons/IconRenderer'; +import { useIsAdmin } from '@/hooks/useIsAdmin'; +import { deleteGroupMemberById } from '@/lib/apis/group'; +import { GroupResponse } from '@/lib/apis/group/type'; +import { useModalStore } from '@/store/useModalStore'; +import { useRouter } from 'next/navigation'; +import { ROUTES } from '@/constants/routes'; +import { toast } from 'react-toastify'; + +interface TeamBannerMenuProps { + group: GroupResponse; + userId: number; +} + +const TeamBannerMenu = ({ group, userId }: TeamBannerMenuProps) => { + const router = useRouter(); + const isAdmin = useIsAdmin({ membersData: group.members, userId }); + const { openModal } = useModalStore(); + + const handleTeamLeave = async () => { + try { + await deleteGroupMemberById({ groupId: group.id, memberId: userId }); + router.push(ROUTES.HOME); + toast.success(`'${group.name}' 팀을 탈퇴했습니다.`); + } catch (error) { + console.error('탈퇴 실패', error); + toast.error('탈퇴에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + } + }; + + const openTeamLeaveModal = () => { + openModal({ + variant: 'danger', + title: `'${group.name}' 팀에서 나가시겠어요?`, + button: { + number: 2, + text: '확인', + onRequest: () => handleTeamLeave(), + }, + }); + }; + + if (isAdmin) { + return ( + router.push(ROUTES.TEAM_EDIT(group.id))} + name="GearIcon" + className="cursor-pointer" + /> + ); + } + + return ( + + + + + + + 탈퇴하기 + + + + ); +}; + +export default TeamBannerMenu; diff --git a/src/app/(team)/team/_components/TeamBanner/TeamMenu.tsx b/src/app/(team)/team/_components/TeamBanner/TeamMenu.tsx deleted file mode 100644 index 089e414a..00000000 --- a/src/app/(team)/team/_components/TeamBanner/TeamMenu.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useRouter } from 'next/navigation'; -import { ROUTES } from '@/constants/routes'; -import DropDown from '@/components/common/Dropdown'; -import IconRenderer from '@/components/common/Icons/IconRenderer'; -import { dropdownMenuStyle, dropdownItemStyle } from '@/app/styles/dropdown'; - -const TeamMenu = ({ group }: { group: { id: number } }) => { - const router = useRouter(); - - return ( - - - - - - router.push(ROUTES.TEAM_EDIT(group.id))} - className={`${dropdownItemStyle}`} - > - 수정하기 - - router.push(ROUTES.TEAM_EDIT(group.id))} - className={`${dropdownItemStyle}`} - > - 삭제하기 - - - - ); -}; - -export default TeamMenu; diff --git a/src/app/(team)/team/_components/TeamBanner/index.tsx b/src/app/(team)/team/_components/TeamBanner/index.tsx index f599e983..1712f5b0 100644 --- a/src/app/(team)/team/_components/TeamBanner/index.tsx +++ b/src/app/(team)/team/_components/TeamBanner/index.tsx @@ -1,8 +1,7 @@ 'use client'; import Image from 'next/image'; -import TeamDropdownMenu from '@/app/(team)/team/_components/TeamBanner/TeamMenu'; +import TeamBannerMenu from '@/app/(team)/team/_components/TeamBanner/TeamBannerMenu'; import GradientScrollable from '@/components/common/Scroll/GradientScrollable'; -import { useIsAdmin } from '@/hooks/useIsAdmin'; import { GroupResponse } from '@/lib/apis/group/type'; import { teamBannerWrapperStyle, @@ -17,8 +16,6 @@ const TeamBanner = ({ group: GroupResponse; userId: number; }) => { - const isAdmin = useIsAdmin({ membersData: group.members, userId }); - return (
{group.name}
- {isAdmin && } + ); };