From 10bb398d247929afcef34ec5c5e3c14032c10306 Mon Sep 17 00:00:00 2001 From: seungchanwoo Date: Sun, 18 Aug 2024 11:50:21 +0900 Subject: [PATCH 1/4] =?UTF-8?q?UI:=20#72=20=EC=9C=A0=EC=A0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=84=A4=EC=A0=95=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=8C=80=20=EC=84=A4=EC=A0=95=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/mockData.ts | 19 ++++++- src/pages/setting/TeamSettingPage.tsx | 71 ++++++++++++++++++++++++++- src/types/TeamType.tsx | 6 +++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/mocks/mockData.ts b/src/mocks/mockData.ts index eafaef50..d1df4e0e 100644 --- a/src/mocks/mockData.ts +++ b/src/mocks/mockData.ts @@ -1,7 +1,7 @@ import type { ProjectStatus } from '@/types/ProjectStatusType'; import { Project } from '@/types/ProjectType'; import type { TaskListWithStatus } from '@/types/TaskType'; -import { Team } from '@/types/TeamType'; +import { Team, TeamInvitation } from '@/types/TeamType'; export const USER_DUMMY = [ { @@ -35,6 +35,23 @@ export const USER_INFO_DUMMY = { links: ['momoco@github.com'], }; +export const TEAM_INVITATION_DUMMY: TeamInvitation[] = [ + { + teamId: 1, + teamName: 'Team One', + teamContent: '프로젝트 관리 사이드 프로젝트 진행중!', + }, + { + teamId: 2, + teamName: 'Team Two', + teamContent: '모임 / 이벤트 관리 프로젝트', + }, + { + teamId: 2, + teamName: 'Team Three', + teamContent: '사이드 프로젝트 관련 여러 프로젝트 진행중!', + }, +]; export const TEAM_DUMMY: Team[] = [ { teamId: 1, diff --git a/src/pages/setting/TeamSettingPage.tsx b/src/pages/setting/TeamSettingPage.tsx index ea578756..70ee0499 100644 --- a/src/pages/setting/TeamSettingPage.tsx +++ b/src/pages/setting/TeamSettingPage.tsx @@ -1,3 +1,72 @@ +import { useState } from 'react'; +import { TEAM_DUMMY, TEAM_INVITATION_DUMMY } from '@/mocks/mockData'; + export default function TeamSettingPage() { - return
TeamSettingPage
; + const [view, setView] = useState<'joined' | 'invited'>('joined'); + + return ( +
+
+
+ + +
+
+ +
+ {/* 가입현황 layout */} + {view === 'joined' && ( +
+
    + {TEAM_DUMMY.map((team) => ( +
  • +
    + team + {team.name} +
    +
    {team.content}
    + {/* ToDo:탈퇴하기 기능 추가 */} + +
  • + ))} +
+
+ )} + {/* 대기현황 layout */} + {view === 'invited' && ( +
+
    + {TEAM_INVITATION_DUMMY.map((invite) => ( +
  • +
    + team + {invite.teamName} +
    +
    {invite.teamContent}
    +
    + {/* ToDo: 수락하기 , 거부하기 기능 추가 */} + + +
    +
  • + ))} +
+
+ )} +
+
+ ); } diff --git a/src/types/TeamType.tsx b/src/types/TeamType.tsx index 18f445d2..65273ec8 100644 --- a/src/types/TeamType.tsx +++ b/src/types/TeamType.tsx @@ -4,3 +4,9 @@ export type Team = { name: string; content: string; }; + +export interface TeamInvitation { + teamId: number; + teamName: string; + teamContent: string; +} From 3352efebc08aac098c2fd8f93935c57f78315eae Mon Sep 17 00:00:00 2001 From: seungchanwoo Date: Wed, 21 Aug 2024 20:11:44 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Feat:=20#72=20=ED=8C=80=20=EC=B4=88?= =?UTF-8?q?=EB=8C=80=20=EB=B0=8F=20=EA=B0=80=EC=9E=85=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EB=A5=BC=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20API=20Handle?= =?UTF-8?q?r=20=EC=B6=94=EA=B0=80=20&=20=ED=8C=80=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20UI=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mocks/mockData.ts | 50 +++++++-------- src/mocks/services/userServiceHandler.ts | 46 ++++++++++++++ src/pages/setting/TeamSettingPage.tsx | 78 +++++++++++++++--------- src/services/userService.ts | 13 ++++ src/types/TeamType.tsx | 7 ++- 5 files changed, 139 insertions(+), 55 deletions(-) diff --git a/src/mocks/mockData.ts b/src/mocks/mockData.ts index 3e28020d..a2b7c8c6 100644 --- a/src/mocks/mockData.ts +++ b/src/mocks/mockData.ts @@ -9,7 +9,7 @@ type TeamUser = { teamId: number; userId: number; roleId: number; - regStatus: boolean; + isPendingApproval: boolean; }; type ProjectUser = { @@ -18,8 +18,7 @@ type ProjectUser = { roleId: number; }; -export const JWT_TOKEN_DUMMY = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +export const JWT_TOKEN_DUMMY = 'mocked-header.mocked-payload-4.mocked-signature'; export const USER_INFO_DUMMY = { provider: 'LOCAL', @@ -226,117 +225,117 @@ export const TEAM_USER_DUMMY: TeamUser[] = [ teamId: 1, userId: 1, roleId: 1, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 3, - roleId: 1, - regStatus: true, + roleId: 2, + isPendingApproval: true, }, { teamId: 1, userId: 4, roleId: 3, - regStatus: false, + isPendingApproval: false, }, { teamId: 1, userId: 8, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 9, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 11, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 12, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 13, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 14, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 1, userId: 15, roleId: 3, - regStatus: true, + isPendingApproval: true, }, // 팀2 소속 유저 정보 { teamId: 2, userId: 3, roleId: 2, - regStatus: true, + isPendingApproval: true, }, { teamId: 2, userId: 4, roleId: 1, - regStatus: true, + isPendingApproval: true, }, { teamId: 2, userId: 5, roleId: 3, - regStatus: false, + isPendingApproval: false, }, { teamId: 2, userId: 7, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 2, userId: 10, roleId: 3, - regStatus: true, + isPendingApproval: true, }, // 팀3 소속 유저 정보 { teamId: 3, userId: 1, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 3, userId: 2, roleId: 3, - regStatus: true, + isPendingApproval: true, }, { teamId: 3, userId: 5, roleId: 2, - regStatus: false, + isPendingApproval: false, }, { teamId: 3, userId: 6, roleId: 1, - regStatus: true, + isPendingApproval: true, }, ] as const; @@ -345,17 +344,20 @@ export const TEAM_DUMMY: Team[] = [ { teamId: 1, name: 'GU99', - content: '사이드 프로젝트 팀원 모집 / 프로젝트 관리 서비스 등을 만드는 팀', + content: '사이드 프로젝트 팀원 모집 / 프로젝트 관리 서비스 등을 만드는 팀 ', + creatorId: 1, }, { teamId: 2, name: '오늘볼래', content: '모임/이벤트/소개팅 등 사람과 사람을 이어주는 서비스를 만드는 팀', + creatorId: 4, }, { teamId: 3, name: '고인물', content: '게임 리뷰/정보공유/모임 등을 위한 서바스를 개발하고 있는 팀', + creatorId: 6, }, ] as const; diff --git a/src/mocks/services/userServiceHandler.ts b/src/mocks/services/userServiceHandler.ts index 947e3e58..6bc70486 100644 --- a/src/mocks/services/userServiceHandler.ts +++ b/src/mocks/services/userServiceHandler.ts @@ -1,7 +1,12 @@ import { http, HttpResponse } from 'msw'; +import { ROLE_DUMMY, TEAM_DUMMY, TEAM_USER_DUMMY, USER_DUMMY } from '@mocks/mockData'; +import type { Team } from '@/types/TeamType'; +import type { Role } from '@/types/RoleType'; +import type { User } from '@/types/UserType'; const BASE_URL = import.meta.env.VITE_BASE_URL; +// ToDo: Dummy 데이터 Hash화 한 곳으로 모으기 const userServiceHandler = [ // 유저 검색 API // ToDo: 내부 구현 사항 채울 것 @@ -14,6 +19,47 @@ const userServiceHandler = [ return HttpResponse.json([]); }), + // 가입한 팀 목록 조회 API + http.get(`${BASE_URL}/user/team`, ({ request }) => { + const accessToken = request.headers.get('Authorization'); + + if (!accessToken) return new HttpResponse(null, { status: 401 }); + + const [header, payload, signature] = accessToken.split('.'); + const userId = payload.replace('mocked-payload-', ''); + + // 유저가 속한 모든 팀 목록 추출 + const teamUserList = TEAM_USER_DUMMY.filter((row) => row.userId === Number(userId)); + console.log(teamUserList); + // 유저 정보 Hash 형태로 추출 + const USERS: { [key: string | number]: User } = {}; + USER_DUMMY.forEach((user) => (USERS[user.userId] = user)); + + // 역할 정보 Hash 형태로 추출 + const ROLES: { [key: string | number]: Role } = {}; + ROLE_DUMMY.forEach((role) => (ROLES[role.roleId] = role)); + + // 팀 정보 Hash 형태로 추출 + const TEAMS: { [key: string | number]: Team } = {}; + TEAM_DUMMY.forEach((team) => (TEAMS[team.teamId] = team)); + + const teamJoinStatusList = teamUserList.map((teamUser) => { + const user = USERS[teamUser.userId]; + const role = ROLES[teamUser.roleId]; + const team = TEAMS[teamUser.teamId]; + + return { + teamId: team.teamId, + name: team.name, + content: team.content, + creator: user.nickname, + isPendingApproval: teamUser.isPendingApproval, + roleName: role.roleName, + }; + }); + + return HttpResponse.json(teamJoinStatusList); + }), ]; export default userServiceHandler; diff --git a/src/pages/setting/TeamSettingPage.tsx b/src/pages/setting/TeamSettingPage.tsx index 49c465a9..92d7e4f0 100644 --- a/src/pages/setting/TeamSettingPage.tsx +++ b/src/pages/setting/TeamSettingPage.tsx @@ -1,63 +1,83 @@ -import { useState } from 'react'; -import { TEAM_DUMMY, TEAM_INVITATION_DUMMY } from '@/mocks/mockData'; +import { useEffect, useState } from 'react'; +import useAxios from '@/hooks/useAxios'; +import { findTeamList } from '@/services/userService'; + +enum TeamStatus { + JOINED, + INVITED, +} export default function TeamSettingPage() { - const [view, setView] = useState<'joined' | 'invited'>('joined'); + const [view, setView] = useState(TeamStatus.JOINED); + + // ToDo: useAxios 부분을 react query로 변경할 것 + const { data, loading, fetchData } = useAxios(findTeamList); + const joinedTeamList = data?.filter((data) => data.isPendingApproval === true); + const invitedTeamList = data?.filter((data) => data.isPendingApproval === false); + useEffect(() => { + fetchData(); + }, [fetchData]); return (
-
- -
- {/* 가입현황 layout */} - {view === 'joined' && ( + {/* 가입현황 레이아웃 */} + {view === TeamStatus.JOINED && (
    - {TEAM_DUMMY.map((team) => ( -
  • -
    - team + {joinedTeamList?.map((team) => ( +
  • +
    + team {team.name}
    -
    {team.content}
    - {/* ToDo:탈퇴하기 기능 추가 */} - +
    {team.content}
    +
    + +
  • ))}
)} - {/* 대기현황 layout */} - {view === 'invited' && ( + + {/* 대기현황 레이아웃 */} + {view === TeamStatus.INVITED && (
    - {TEAM_INVITATION_DUMMY.map((invite) => ( + {invitedTeamList?.map((invite) => (
  • -
    +
    team {invite.name}
    -
    {invite.content}
    -
    - {/* ToDo: 수락하기 , 거부하기 기능 추가 */} - -
    diff --git a/src/services/userService.ts b/src/services/userService.ts index a52a440c..d96649c5 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -1,6 +1,7 @@ import { authAxios } from '@services/axiosProvider'; import type { AxiosRequestConfig } from 'axios'; import type { User } from '@/types/UserType'; +import type { TeamListWithApproval } from '@/types/TeamType'; /** * 유저 목록을 검색하는 API @@ -14,3 +15,15 @@ import type { User } from '@/types/UserType'; async function findUser(nickname: string, axiosConfig: AxiosRequestConfig = {}) { return authAxios.get(`/user/search?nickname=${nickname}`, axiosConfig); } + +/** + * 가입한 팀과 초대된 팀 전체 목록 조회 API + * + * @export + * @async + * @param {AxiosRequestConfig} [axiosConnfig={}] - axios 요청 옵션 설정 객체 + * @returns {Promise>} + */ +export async function findTeamList(axiosConnfig: AxiosRequestConfig = {}) { + return authAxios.get('/user/team', axiosConnfig); +} diff --git a/src/types/TeamType.tsx b/src/types/TeamType.tsx index 42fffddd..58b885e9 100644 --- a/src/types/TeamType.tsx +++ b/src/types/TeamType.tsx @@ -1,8 +1,11 @@ +import { Role } from './RoleType'; + // ToDo: API 설계 완료시 데이터 타입 변경할 것 export type Team = { teamId: number; + creatorId: number; name: string; content: string; - creator: string; - isPendingApproval: boolean; }; + +export type TeamListWithApproval = Team & Pick & { isPendingApproval: boolean }; From 809bec944d7066b1f1c45396ca74a7ea93baa98c Mon Sep 17 00:00:00 2001 From: seungchanwoo Date: Thu, 22 Aug 2024 22:14:53 +0900 Subject: [PATCH 3/4] =?UTF-8?q?UI:=20#72=20=ED=8C=80=20head=20UI=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20&=20style=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/sidebar/ListSidebar.tsx | 2 +- src/layouts/page/ProjectLayout.tsx | 2 +- src/layouts/page/SettingLayout.tsx | 2 +- src/layouts/page/TeamLayout.tsx | 2 +- src/mocks/services/userServiceHandler.ts | 6 +- src/pages/setting/TeamSettingPage.tsx | 95 +++++++++++++++--------- src/types/TeamType.tsx | 3 +- 7 files changed, 71 insertions(+), 41 deletions(-) diff --git a/src/components/sidebar/ListSidebar.tsx b/src/components/sidebar/ListSidebar.tsx index 116f4822..b7b52b87 100644 --- a/src/components/sidebar/ListSidebar.tsx +++ b/src/components/sidebar/ListSidebar.tsx @@ -15,7 +15,7 @@ export default function ListSidebar({ label, title, children, showButton, text, }; return ( -