Skip to content

Commit

Permalink
✨ Feat: Action Items 담당자 지정 api 구현 완료 (#197)
Browse files Browse the repository at this point in the history
* ✨ Feat: Action Items 담당자 지정 api 타입 작성 및 비동기 함수 작성

* 🐛 Fix: Action Items api 오타 수정 및 절대 경로로 수정

* ✨ Feat: Action Items 팀원 get api 연결

* ✨ Feat: Action Items 담당자 지정 api 연결

* ✨ Feat: Action Items 담당자 지정 api 구현 완료
  • Loading branch information
yeneua authored Apr 20, 2024
1 parent 8d18af4 commit d89b504
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 25 deletions.
14 changes: 14 additions & 0 deletions src/api/@types/TeamController.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// 팀원 조회
export interface GetTeamMembersRequest {
teamId: number;
retrospectiveId: number;
Expand Down Expand Up @@ -35,7 +36,20 @@ export interface TemplateNameData {
sequence: number;
}

// put 담당자
export interface PutActionItemsRequest {
teamId: number;
retrospectiveId: number;
sectionId: number;
}

export interface PutActionItemsResponse {
code: number;
message: string;
data: object;
}
export interface TeamControllerClient {
TeamMemberGet(request: GetTeamMembersRequest): Promise<GetTeamMembersResponse>;
TemplateNameGet(request: GetTemplateNameRequest): Promise<GetTemplateNameResponse>;
ActionItemsMemberPut(request: PutActionItemsRequest): Promise<PutActionItemsResponse>;
}
14 changes: 12 additions & 2 deletions src/api/services/TeamController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
GetTemplateNameRequest,
GetTemplateNameResponse,
TeamControllerClient,
} from '../@types/TeamController';
import axiosInstance from '../axiosConfig';
PutActionItemsRequest,
PutActionItemsResponse,
} from '@/api/@types/TeamController';
import axiosInstance from '@/api/axiosConfig';

const TEAMS_ROUTE = 'teams';
const TEMPLATE_ROUTE = 'retrospective-templates';
Expand All @@ -26,4 +28,12 @@ export const TeamControllerServices: TeamControllerClient = {
throw new Error(error as string);
}
},
ActionItemsMemberPut: async (request: PutActionItemsRequest): Promise<PutActionItemsResponse> => {
try {
const response = await axiosInstance.put(`/sections/action-itmes`, request);
return response.data;
} catch (error) {
throw new Error(error as string);
}
},
};
15 changes: 15 additions & 0 deletions src/api/teamControllerApi/getMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GetTeamMembersRequest, GetTeamMembersResponse } from '@/api/@types/TeamController';
import axiosInstance from '@/api/axiosConfig';

export const getMember = async ({
teamId,
retrospectiveId,
}: GetTeamMembersRequest): Promise<GetTeamMembersResponse> => {
try {
const response = await axiosInstance.get<GetTeamMembersResponse>(`/teams/${teamId}/users?${retrospectiveId}=`);
console.log('팀 멤버 조회 성공', response.data);
return response.data;
} catch (error) {
throw new Error('팀 멤버 조회 실패');
}
};
13 changes: 13 additions & 0 deletions src/api/teamControllerApi/putActionItemsMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PutActionItemsRequest, PutActionItemsResponse } from '@/api/@types/TeamController';
import axiosInstance from '@/api/axiosConfig';

export const putActionItemsMember = async (requestData: PutActionItemsRequest): Promise<PutActionItemsResponse> => {
try {
// console.log(requestData);
const response = await axiosInstance.put<PutActionItemsResponse>('/sections/action-items', requestData);
// console.log('action item 멤버 저장 성공', response);
return response.data;
} catch (error) {
throw new Error('action item 멤버 저장 실패');
}
};
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
import React, { FC, useState } from 'react';
import { sectionData } from '@/api/@types/Section';
import UserProfile1 from '@/assets/UserProfile1.png';
import UserProfile2 from '@/assets/UserProfile2.png';
import React, { FC, useState, useEffect } from 'react';
import { TeamControllerServices } from '@/api/services/TeamController';
import Members from '@/components/writeRetro/ActionItems/Members';
import { useCustomToast } from '@/hooks/useCustomToast';
import * as S from '@/styles/writeRetroStyles/Layout.style';

interface Props {
section: sectionData[];
interface ActionItemTaskProps {
tId: number;
rId: number;
sId: number;
}

const ActionItemTask: FC<Props> = ({ section }) => {
// action items 담당자 지정
const ActionItemTask: FC<ActionItemTaskProps> = ({ tId, rId, sId }) => {
const [hoveredUser, setHoveredUser] = useState<string | null>(null);
const [showPopup, setShowPopup] = useState<boolean>(false);
const [selectedUserName, setSelectedUserName] = useState<string | null>(null);
const [selectedUserImg, setSelectedUserImg] = useState<string | null>(null);

const users = [
{ name: 'User 1', image: UserProfile1 },
{ name: 'User 2', image: UserProfile2 },
];
const teamId: number = tId;
const retrospectiveId: number = rId;
const sectionId: number = sId;

const [users, setUsers] = useState<{ name: string; image: string }[]>([]);
const toast = useCustomToast();

const fetchTeamMember = async () => {
try {
if (teamId) {
const data = await TeamControllerServices.TeamMemberGet({ teamId: teamId, retrospectiveId: retrospectiveId });
const userData = data.data.map(member => ({
name: member.username,
image: member.profileImage,
}));
setUsers(userData);
}
return;
} catch (e) {
toast.error('멤버 조회 실패');
}
};
useEffect(() => {
fetchTeamMember();
}, []);

const togglePopup = () => {
setShowPopup(!showPopup);
Expand Down Expand Up @@ -50,15 +71,19 @@ const ActionItemTask: FC<Props> = ({ section }) => {
onMouseLeave={handleMouseLeave}
>
{selectedUserImg ? <img src={selectedUserImg} /> : 'M'}
{hoveredUser && <S.HoverUser>{hoveredUser}</S.HoverUser>} {/* 이름 : {name.username} */}
{hoveredUser && <S.HoverUser>{hoveredUser}</S.HoverUser>}
</S.ManagerButton>
{showPopup && (
<Members users={users} onSelectUserImg={handleSelectUserImg} onSelectUserName={handleSelectUserName} />
<Members
users={users}
onSelectUserImg={handleSelectUserImg}
onSelectUserName={handleSelectUserName}
tId={teamId}
rId={retrospectiveId}
sId={sectionId}
/>
)}
</div>
{section.map(section => (
<S.ManagerText>{section.username}</S.ManagerText>
))}
</S.ManagerStyle>
);
};
Expand Down
35 changes: 31 additions & 4 deletions src/components/writeRetro/ActionItems/Members.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
import { PutActionItemsRequest } from '@/api/@types/TeamController';
import { putActionItemsMember } from '@/api/teamControllerApi/putActionItemsMember';
import UserProfile from '@/assets/UserProfile1.png';
import { useCustomToast } from '@/hooks/useCustomToast';
import * as S from '@/styles/writeRetroStyles/Members.styles';

interface UserListProps {
users: { name: string; image: string }[];
onSelectUserImg: (image: string) => void;
onSelectUserName: (name: string) => void;
tId: number;
rId: number;
sId: number;
}

export const Members: React.FC<UserListProps> = ({ users, onSelectUserImg, onSelectUserName }) => {
const handleUserClick = (name: string, image: string) => {
export const Members: React.FC<UserListProps> = ({ users, onSelectUserImg, onSelectUserName, tId, rId, sId }) => {
const teamId: number = tId;
const retrospectiveId: number = rId;
const sectionId: number = sId;

const toast = useCustomToast();

const putActionItemMember = async () => {
try {
const requestData: PutActionItemsRequest = {
teamId: teamId,
retrospectiveId: retrospectiveId,
sectionId: sectionId,
};
await putActionItemsMember(requestData);
} catch (e) {
toast.error('담당자 지정 실패');
}
};

const handleUserClick = async (name: string, image: string) => {
onSelectUserName(name);
onSelectUserImg(image);
await putActionItemMember();
};

return (
Expand All @@ -20,8 +47,8 @@ export const Members: React.FC<UserListProps> = ({ users, onSelectUserImg, onSel
</S.TitleContainer>
<ul>
{users.map((user, index) => (
<S.ListItem key={index} onClick={() => handleUserClick(user.name, user.image)}>
<S.ProfileImage src={user.image} /> <S.UserName>{user.name}</S.UserName>
<S.ListItem key={index} onClick={() => handleUserClick(user.name, user.image || UserProfile)}>
<S.ProfileImage src={user.image || UserProfile} /> <S.UserName>{user.name}</S.UserName>
</S.ListItem>
))}
</ul>
Expand Down
15 changes: 14 additions & 1 deletion src/components/writeRetro/task/TeamTask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BiLike, BiSolidLike } from 'react-icons/bi';
import { CgProfile } from 'react-icons/cg';
import { FaRegTrashAlt } from 'react-icons/fa';
import { MdAccessAlarm, MdMessage } from 'react-icons/md';
import { useLocation } from 'react-router-dom';
import {
Button,
Flex,
Expand All @@ -19,7 +20,7 @@ import { formattedDate } from './PersonalTask';
import TeamTaskMessage from './taskMessage/TeamTaskMessage';
import { sectionData } from '@/api/@types/Section';
import { SectionServices } from '@/api/services/Section';

import ActionItemTask from '@/components/writeRetro/ActionItems/ActionItemTask';
import ReviseModal from '@/components/writeRetro/task/ReviseModal';
import { useCustomToast } from '@/hooks/useCustomToast';
import * as S from '@/styles/writeRetroStyles/Layout.style';
Expand All @@ -33,6 +34,12 @@ const TeamTask: FC<Props> = ({ section }) => {
const [liked, setLiked] = useState<number>(0);
const [messaged, setMessaged] = useState<boolean>(false);
const [isVisible, setIsVisible] = useState<boolean>(false);
const { search } = useLocation();

const query = search.split(/[=,&]/);
const rId = Number(query[1]); // action-items로 넘겨줄 Id값들
const tId = Number(query[3]);
const sId: number = section.sectionId;

const handleLike = async () => {
try {
Expand Down Expand Up @@ -100,6 +107,12 @@ const TeamTask: FC<Props> = ({ section }) => {
<S.TaskText>
{section.content}
{/* <S.ReviseText>(수정됨)</S.ReviseText> */}
<S.ManagerStyle>
<div>
<ActionItemTask tId={tId} rId={rId} sId={sId} />
</div>
<S.ManagerText>담당자</S.ManagerText>
</S.ManagerStyle>
</S.TaskText>
</PopoverTrigger>
<PopoverContent>
Expand Down
8 changes: 8 additions & 0 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export const SectionHandlers: RequestHandler[] = [
};
return HttpResponse.json(mockLikes);
}),
http.put(`${SECTION_ROUTE}/action-items`, () => {
const mockActionItems = {
code: 0,
message: 'string',
data: {},
};
return HttpResponse.json(mockActionItems);
}),
];

//teamMembers
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9620,7 +9620,7 @@ react-remove-scroll@^2.5.6:

react-router-dom@^6.22.3:
version "6.22.3"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.22.3.tgz#9781415667fd1361a475146c5826d9f16752a691"
integrity sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==
dependencies:
"@remix-run/router" "1.15.3"
Expand Down Expand Up @@ -11469,6 +11469,7 @@ wordwrap@~0.0.2:
integrity sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
name wrap-ansi-cjs
version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand Down

0 comments on commit d89b504

Please sign in to comment.