From 75bd6eb8d2dab9a9942394fe3f5c2970e434f442 Mon Sep 17 00:00:00 2001 From: HiHoi Date: Mon, 4 Mar 2024 15:54:03 +0900 Subject: [PATCH 1/4] feat: show team member list button add --- src/app/teams/[id]/panel/TeamInfoContainer.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/teams/[id]/panel/TeamInfoContainer.tsx b/src/app/teams/[id]/panel/TeamInfoContainer.tsx index a5dfc2d8c..d94a1aa48 100644 --- a/src/app/teams/[id]/panel/TeamInfoContainer.tsx +++ b/src/app/teams/[id]/panel/TeamInfoContainer.tsx @@ -1,7 +1,7 @@ import { useRouter } from 'next/navigation' import useSWR from 'swr' import { useEffect } from 'react' -import { Stack, Typography } from '@mui/material' +import { Button, Stack, Typography } from '@mui/material' import useAxiosWithAuth from '@/api/config' import CuCircularProgress from '@/components/CuCircularProgress' import CuAvatar from '@/components/CuAvatar' @@ -48,7 +48,7 @@ const TeamInfoContainer = ({ id }: { id: number }) => { return ( <> - + {isLoading || !data ? ( ) : ( @@ -71,7 +71,12 @@ const TeamInfoContainer = ({ id }: { id: number }) => { - + + + + From bdfe70a49d1da4298c9ea6cdc54967868255455b Mon Sep 17 00:00:00 2001 From: HiHoi Date: Sun, 10 Mar 2024 16:26:40 +0900 Subject: [PATCH 2/4] feat: team list popover add and connect to back end api --- .../teams/[id]/panel/TeamInfoContainer.tsx | 91 ++++++++++++++++++- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/src/app/teams/[id]/panel/TeamInfoContainer.tsx b/src/app/teams/[id]/panel/TeamInfoContainer.tsx index d94a1aa48..d1d405d0b 100644 --- a/src/app/teams/[id]/panel/TeamInfoContainer.tsx +++ b/src/app/teams/[id]/panel/TeamInfoContainer.tsx @@ -1,7 +1,7 @@ import { useRouter } from 'next/navigation' import useSWR from 'swr' -import { useEffect } from 'react' -import { Button, Stack, Typography } from '@mui/material' +import { MouseEvent, useEffect, useState } from 'react' +import { Button, Card, Popover, Stack, Typography } from '@mui/material' import useAxiosWithAuth from '@/api/config' import CuCircularProgress from '@/components/CuCircularProgress' import CuAvatar from '@/components/CuAvatar' @@ -10,15 +10,44 @@ import { ITeamInfo } from '@/types/ITeamInfo' import { StatusIcon, IconInfo } from './TeamInfoComponent' import * as style from './TeamInfoContainer.style' import { isAxiosError } from 'axios' +import OthersProfile from '@/app/panel/OthersProfile' +import { AccountBox } from '@/icons' + +interface ITeamMemberInfo { + id: number + name: string + role: string +} const TeamInfoContainer = ({ id }: { id: number }) => { const axiosInstance = useAxiosWithAuth() + // 팀의 정보를 불러오는 API 호출 const { data, error, isLoading } = useSWR( `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/${id}`, (url: string) => axiosInstance(url).then((res) => res.data), ) + // 팀원의 정보를 불러오는 API 호출 -> 추후 API 통합이 필요 + const { data: memberData, isLoading: memberIsLoading } = useSWR< + Array + >( + `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/member/${id}`, + (url: string) => axiosInstance(url).then((res) => res.data), + ) const { setHeaderTitle } = useHeaderStore() const router = useRouter() + // 멤버 리스트를 보여주기 위한 popover 관련 객체 + const [popOverAnchorEl, setPopOverAnchorEl] = + useState(null) + + const handlePopoverOpen = (event: MouseEvent) => { + setPopOverAnchorEl(event.currentTarget) + } + + const handlePopoverClose = () => { + setPopOverAnchorEl(null) + } + + const open = Boolean(popOverAnchorEl) // set header useEffect(() => { @@ -73,9 +102,65 @@ const TeamInfoContainer = ({ id }: { id: number }) => { - + + + + + 멤버 리스트 + + + + {memberIsLoading || !memberData ? ( + + ) : ( + memberData.map((member) => ( + + + + {member.role === 'LEADER' && ( + + )} + + {member.name} + + + + + + )) + )} + + + From 1b46d994e5055f26b824992f8caed93b6c8cf831 Mon Sep 17 00:00:00 2001 From: HiHoi Date: Mon, 11 Mar 2024 14:14:31 +0900 Subject: [PATCH 3/4] feat: team member list ver pc and mobile is added --- .../teams/[id]/panel/TeamInfoContainer.tsx | 157 ++++++------- src/app/teams/[id]/panel/TeamMemberList.tsx | 217 ++++++++++++++++++ 2 files changed, 290 insertions(+), 84 deletions(-) create mode 100644 src/app/teams/[id]/panel/TeamMemberList.tsx diff --git a/src/app/teams/[id]/panel/TeamInfoContainer.tsx b/src/app/teams/[id]/panel/TeamInfoContainer.tsx index d1d405d0b..0d4de90d2 100644 --- a/src/app/teams/[id]/panel/TeamInfoContainer.tsx +++ b/src/app/teams/[id]/panel/TeamInfoContainer.tsx @@ -1,7 +1,7 @@ import { useRouter } from 'next/navigation' import useSWR from 'swr' -import { MouseEvent, useEffect, useState } from 'react' -import { Button, Card, Popover, Stack, Typography } from '@mui/material' +import { useEffect } from 'react' +import { Stack, Typography } from '@mui/material' import useAxiosWithAuth from '@/api/config' import CuCircularProgress from '@/components/CuCircularProgress' import CuAvatar from '@/components/CuAvatar' @@ -10,44 +10,87 @@ import { ITeamInfo } from '@/types/ITeamInfo' import { StatusIcon, IconInfo } from './TeamInfoComponent' import * as style from './TeamInfoContainer.style' import { isAxiosError } from 'axios' -import OthersProfile from '@/app/panel/OthersProfile' -import { AccountBox } from '@/icons' +import useMedia from '@/hook/useMedia' +import { TeamMemberListMobile, TeamMemberListPc } from './TeamMemberList' -interface ITeamMemberInfo { +export interface ITeamMemberInfo { id: number name: string role: string } const TeamInfoContainer = ({ id }: { id: number }) => { + const { isPc } = useMedia() const axiosInstance = useAxiosWithAuth() // 팀의 정보를 불러오는 API 호출 const { data, error, isLoading } = useSWR( `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/${id}`, (url: string) => axiosInstance(url).then((res) => res.data), ) - // 팀원의 정보를 불러오는 API 호출 -> 추후 API 통합이 필요 - const { data: memberData, isLoading: memberIsLoading } = useSWR< - Array - >( - `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/member/${id}`, - (url: string) => axiosInstance(url).then((res) => res.data), - ) - const { setHeaderTitle } = useHeaderStore() - const router = useRouter() - // 멤버 리스트를 보여주기 위한 popover 관련 객체 - const [popOverAnchorEl, setPopOverAnchorEl] = - useState(null) + // // 팀원의 정보를 불러오는 API 호출 -> 추후 API 통합이 필요 + // const { data: memberData, isLoading: memberIsLoading } = useSWR< + // Array + // >( + // `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/member/${id}`, + // (url: string) => axiosInstance(url).then((res) => res.data), + // ) - const handlePopoverOpen = (event: MouseEvent) => { - setPopOverAnchorEl(event.currentTarget) - } + // 테스트용 데이터 + const mockData: Array = [ + { + id: 1, + name: '테스트1', + role: 'LEADER', + }, + { + id: 2, + name: '테스트2', + role: 'MEMBER', + }, + { + id: 3, + name: '테스트3', + role: 'MEMBER', + }, + { + id: 4, + name: '테스트4', + role: 'MEMBER', + }, + { + id: 5, + name: '테스트5', + role: 'MEMBER', + }, + { + id: 6, + name: '테스트6', + role: 'MEMBER', + }, + { + id: 7, + name: '테스트7', + role: 'MEMBER', + }, + { + id: 8, + name: '테스트8', + role: 'MEMBER', + }, + { + id: 9, + name: '테스트9', + role: 'MEMBER', + }, + { + id: 10, + name: '테스트10테스트10테스트10테스트10테스트10테스트10', + role: 'MEMBER', + }, + ] - const handlePopoverClose = () => { - setPopOverAnchorEl(null) - } - - const open = Boolean(popOverAnchorEl) + const { setHeaderTitle } = useHeaderStore() + const router = useRouter() // set header useEffect(() => { @@ -102,65 +145,11 @@ const TeamInfoContainer = ({ id }: { id: number }) => { - - - - - - 멤버 리스트 - - - - {memberIsLoading || !memberData ? ( - - ) : ( - memberData.map((member) => ( - - - - {member.role === 'LEADER' && ( - - )} - - {member.name} - - - - - - )) - )} - - - + {isPc ? ( + + ) : ( + + )} diff --git a/src/app/teams/[id]/panel/TeamMemberList.tsx b/src/app/teams/[id]/panel/TeamMemberList.tsx new file mode 100644 index 000000000..299117a61 --- /dev/null +++ b/src/app/teams/[id]/panel/TeamMemberList.tsx @@ -0,0 +1,217 @@ +'use client' + +import { Button, Card, Popover, Stack, Typography } from '@mui/material' +import { ITeamMemberInfo } from './TeamInfoContainer' +import CuCircularProgress from '@/components/CuCircularProgress' +import { AccountBox } from '@/icons' +import { MouseEvent, useState } from 'react' +import useNicknameStore from '@/states/useNicknameStore' +import { useRouter } from 'next/navigation' +import ReportModal from '@/components/ReportModal' +import ExternalMessageModal from '@/app/panel/ExternalMessageModal' +import CuModal from '@/components/CuModal' + +// 팀원 리스트를 보여주는 컴포넌트의 props interface +interface ITeamMemberListProps { + members: Array +} + +// 공통으로 사용되는 컴포넌트 +// 1. 프로필 보기 버튼, 쪽지 보내기 버튼, 신고하기 버튼을 보여주는 컴포넌트 +const MemberButtonGroup = ({ + userId, + name, +}: { + userId: string + name: string +}) => { + const router = useRouter() + const myNickname = useNicknameStore.getState().nickname + + // 쪽지와 신고를 보내기 위한 모달 + const [modalType, setModalType] = useState('' as string) + const messageOpen = () => { + setModalType('message') + } + const reportOpen = () => { + setModalType('report') + } + const handleModalClose = () => { + setModalType('') + } + + // 남의 프로필 보기 + const goOthersProfile = () => { + router.push(`/profile/${userId}`) + } + // 자기 자신의 프로필 보기 + const goMypage = () => { + router.push('/my-page') + } + + // 유령 회원 처리 + if (Number(userId) === -1) return <> + + return ( + <> + {myNickname !== name ? ( + <> + + + + + ) : ( + + )} + + + + ) +} + +// 2. 팀원의 이름과 역할, 프로필 보기 버튼을 보여주는 컴포넌트 +const MemberInfo = ({ member }: { member: ITeamMemberInfo }) => { + return ( + + + + + {member.name} + + {member.role === 'LEADER' && ( + + )} + + + + + + + ) +} + +// 모바일에선 버튼을 클릭하여 모달을 통해 멤버 리스트를 보여준다. +const TeamMemberListMobile = ({ members }: ITeamMemberListProps) => { + const [open, setOpen] = useState(false) + + // 모달 관련 함수 + const handleOpen = () => { + setOpen(true) + } + const handleClose = () => { + setOpen(false) + } + return ( + <> + + + + {!members ? ( + + ) : ( + members.map((member) => ( + + )) + )} + + + + ) +} + +// PC에선 popover를 사용하여 멤버 리스트를 보여준다. +const TeamMemberListPc = ({ members }: ITeamMemberListProps) => { + // 멤버 리스트를 보여주기 위한 popover 관련 객체 + // mui의 기본 예제 참고 + const [popOverAnchorEl, setPopOverAnchorEl] = + useState(null) + + const handlePopoverOpen = (event: MouseEvent) => { + setPopOverAnchorEl(event.currentTarget) + } + + const handlePopoverClose = () => { + setPopOverAnchorEl(null) + } + + const open = Boolean(popOverAnchorEl) + + return ( + <> + + + + + 멤버 리스트 + + + {!members ? ( + + ) : ( + members.map((member) => ( + + )) + )} + + + + + ) +} + +export { TeamMemberListPc, TeamMemberListMobile } From f57115b0c6e68bdebd5a06eb3f8596a9a00e8f8c Mon Sep 17 00:00:00 2001 From: HiHoi Date: Mon, 11 Mar 2024 14:20:09 +0900 Subject: [PATCH 4/4] feat: connected to backend api --- .../teams/[id]/panel/TeamInfoContainer.tsx | 81 ++++--------------- 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/src/app/teams/[id]/panel/TeamInfoContainer.tsx b/src/app/teams/[id]/panel/TeamInfoContainer.tsx index 0d4de90d2..d635fc534 100644 --- a/src/app/teams/[id]/panel/TeamInfoContainer.tsx +++ b/src/app/teams/[id]/panel/TeamInfoContainer.tsx @@ -27,67 +27,13 @@ const TeamInfoContainer = ({ id }: { id: number }) => { `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/${id}`, (url: string) => axiosInstance(url).then((res) => res.data), ) - // // 팀원의 정보를 불러오는 API 호출 -> 추후 API 통합이 필요 - // const { data: memberData, isLoading: memberIsLoading } = useSWR< - // Array - // >( - // `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/member/${id}`, - // (url: string) => axiosInstance(url).then((res) => res.data), - // ) - - // 테스트용 데이터 - const mockData: Array = [ - { - id: 1, - name: '테스트1', - role: 'LEADER', - }, - { - id: 2, - name: '테스트2', - role: 'MEMBER', - }, - { - id: 3, - name: '테스트3', - role: 'MEMBER', - }, - { - id: 4, - name: '테스트4', - role: 'MEMBER', - }, - { - id: 5, - name: '테스트5', - role: 'MEMBER', - }, - { - id: 6, - name: '테스트6', - role: 'MEMBER', - }, - { - id: 7, - name: '테스트7', - role: 'MEMBER', - }, - { - id: 8, - name: '테스트8', - role: 'MEMBER', - }, - { - id: 9, - name: '테스트9', - role: 'MEMBER', - }, - { - id: 10, - name: '테스트10테스트10테스트10테스트10테스트10테스트10', - role: 'MEMBER', - }, - ] + // 팀원의 정보를 불러오는 API 호출 -> 추후 API 통합이 필요 + const { data: memberData, isLoading: memberIsLoading } = useSWR< + Array + >( + `${process.env.NEXT_PUBLIC_CSR_API}/api/v1/team/main/member/${id}`, + (url: string) => axiosInstance(url).then((res) => res.data), + ) const { setHeaderTitle } = useHeaderStore() const router = useRouter() @@ -112,7 +58,7 @@ const TeamInfoContainer = ({ id }: { id: number }) => { return } - if (!isLoading && !data) { + if (!isLoading && !data && !memberIsLoading && !memberData) { alert('팀 페이지에 접근할 수 없습니다.') router.push('/team-list') return @@ -145,11 +91,12 @@ const TeamInfoContainer = ({ id }: { id: number }) => { - {isPc ? ( - - ) : ( - - )} + {memberData && + (isPc ? ( + + ) : ( + + ))}