Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 리뷰 재촉 기능(#747) #757

Merged
merged 16 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion frontend/src/@types/alaram.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export type AlarmActionType = "REVIEW_COMPLETE" | "REVIEW_URGE";

export interface AlarmCount {
count: number;
}

export interface AlarmItemData {
alarmId: number;
actionType: string;
actionType: AlarmActionType;
actor: {
memberId: number;
username: string;
Expand All @@ -27,3 +29,8 @@ export interface AlarmAsRead {
alarmId: number;
alarmType: "USER";
}

export interface ReviewReminderAlarm {
roomId: number;
reviewerId: number;
}
1 change: 1 addition & 0 deletions frontend/src/apis/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const API_ENDPOINTS = {
REVIEWERS: (roomId: number) => `/rooms/${roomId}/reviewers`,
REVIEWEES: (roomId: number) => `/rooms/${roomId}/reviewees`,
REVIEW_COMPLETE: "/review/complete",
REVIEW_URGE: "/review/urge",

// profile
PROFILE: "/user/profile",
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/apis/reviews.api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReviewInfo } from "../@types/review";
import apiClient from "./apiClient";
import { API_ENDPOINTS } from "./endpoints";
import { ReviewReminderAlarm } from "@/@types/alaram";
import MESSAGES from "@/constants/message";

export const getMyReviewers = async (roomId: number): Promise<ReviewInfo[]> => {
Expand Down Expand Up @@ -31,3 +32,14 @@ export const postReviewComplete = async (roomId: number, revieweeId: number): Pr
errorMessage: MESSAGES.ERROR.POST_REVIEW_COMPLETE,
});
};

export const postReviewUrge = async ({
roomId,
reviewerId,
}: ReviewReminderAlarm): Promise<void> => {
return apiClient.post({
endpoint: API_ENDPOINTS.REVIEW_URGE,
body: { roomId, reviewerId },
errorMessage: MESSAGES.ERROR.POST_REVIEW_URGE,
});
};
1 change: 1 addition & 0 deletions frontend/src/components/common/button/Button.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const sizeStyles = {
padding: 1rem 0.3rem;

font: ${({ theme }) => theme.TEXT.semiSmall};
white-space: nowrap;

border-radius: 4px;
`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import useMutateReviewComplete from "@/hooks/mutations/useMutateReview";
import useMutateReview from "@/hooks/mutations/useMutateReview";
import { useFetchReviewee } from "@/hooks/queries/useFetchReviewee";
import Button from "@/components/common/button/Button";
import Icon from "@/components/common/icon/Icon";
Expand All @@ -18,7 +18,7 @@ interface MyRevieweeProps {
const MyReviewee = ({ roomInfo }: MyRevieweeProps) => {
const navigate = useNavigate();
const { data: revieweeData } = useFetchReviewee(roomInfo);
const { postReviewCompleteMutation } = useMutateReviewComplete(roomInfo.id);
const { postReviewCompleteMutation } = useMutateReview(roomInfo.id);
const [loadingButtonId, setLoadingButtonId] = useState<number[]>([]);

// 피드백 페이지 이동 함수
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,12 @@ export const ExtraInformation = styled.span`
font: ${({ theme }) => theme.TEXT.xSmall};
color: ${({ theme }) => theme.COLOR.grey2};
`;

export const ContentWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;

font: ${({ theme }) => theme.TEXT.semiSmall};
color: ${({ theme }) => theme.COLOR.black};
`;
29 changes: 28 additions & 1 deletion frontend/src/components/roomDetailPage/myReviewer/MyReviewer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import useMutateReview from "@/hooks/mutations/useMutateReview";
import { useFetchReviewer } from "@/hooks/queries/useFetchReviewer";
import Button from "@/components/common/button/Button";
import Icon from "@/components/common/icon/Icon";
Expand All @@ -17,6 +19,8 @@ interface MyReviewerProps {
const MyReviewer = ({ roomInfo }: MyReviewerProps) => {
const navigate = useNavigate();
const { data: reviewerData } = useFetchReviewer(roomInfo);
const { postReviewUrgeMutation } = useMutateReview(roomInfo.id);
const [loadingButtonId, setLoadingButtonId] = useState<number[]>([]);

// 피드백 페이지 이동 함수
const handleNavigateFeedbackPage = (reviewInfo: ReviewInfo) => {
Expand All @@ -42,6 +46,22 @@ const MyReviewer = ({ roomInfo }: MyReviewerProps) => {
// return <p>피드백을 작성하지 않았어요</p>;
// }

// 코드리뷰 재촉
const handleReviewUrgeClick = (reviewer: ReviewInfo) => {
if (loadingButtonId.includes(reviewer.userId)) return;
setLoadingButtonId((prev) => [...prev, reviewer.userId]);

postReviewUrgeMutation.mutate(
{ roomId: roomInfo.id, reviewerId: reviewer.userId },
{
onSuccess: () => {
setLoadingButtonId((prev) => prev.filter((id) => id !== reviewer.userId));
},
onError: () => setLoadingButtonId((prev) => prev.filter((id) => id !== reviewer.userId)),
},
);
};

return reviewer.isReviewed ? (
<Button
size="xSmall"
Expand All @@ -52,7 +72,14 @@ const MyReviewer = ({ roomInfo }: MyReviewerProps) => {
{buttonText}
</Button>
) : (
<p>리뷰어가 리뷰 중이에요!</p>
<Button
size="xSmall"
variant="secondary"
onClick={() => handleReviewUrgeClick(reviewer)}
outline={true}
>
<S.ContentWrapper>리뷰 재촉하기</S.ContentWrapper>
</Button>
);
};

Expand Down
9 changes: 2 additions & 7 deletions frontend/src/components/shared/roomCard/RoomCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* eslint-disable react/display-name */
import React, { useState } from "react";
import React from "react";
import useModal from "@/hooks/common/useModal";
import Icon from "@/components/common/icon/Icon";
import ImageWithFallback from "@/components/common/img/ImageWithFallback";
import Label from "@/components/common/label/Label";
import ConfirmModal from "@/components/common/modal/confirmModal/ConfirmModal";
import ClassificationBadge from "@/components/shared/classificationBadge/ClassificationBadge";
import * as S from "@/components/shared/roomCard/RoomCard.style";
import RoomCardModal from "@/components/shared/roomCardModal/RoomCardModal";
Expand Down Expand Up @@ -74,11 +73,7 @@ const RoomCard = React.memo(({ roomInfo }: RoomCardProps) => {
<>
<RoomCardModal isOpen={isModalOpen} onClose={handleCloseModal} roomInfo={roomInfo} />

<S.RoomCardContainer
onClick={
roomInfo.roomStatus === "OPEN" && roomInfo.isPrivate ? handleNoticeModal : handleOpenModal
}
>
<S.RoomCardContainer onClick={handleOpenModal}>
<S.ClassificationBadgeWrapper>
<ClassificationBadge text={roomInfo.classification} />
</S.ClassificationBadgeWrapper>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/constants/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const ERROR_MESSAGES = {
POST_REVIEW_COMPLETE: "코드리뷰 완료 요청에 실패했습니다.",
GET_MY_REVIEWERS: "리뷰어 목록을 불러오는 도중 에러가 발생하였습니다.",
GET_MY_REVIEWEES: "리뷰이 목록을 불러오는 도중 에러가 발생하였습니다.",
POST_REVIEW_URGE: "코드리뷰 재촉 요청에 실패했습니다.",

// profile
GET_PROFILE: "프로필 불러오는 도중 에러가 발생하였습니다.",
Expand Down Expand Up @@ -81,6 +82,7 @@ const SUCCESS_MESSAGES = {
DELETE_PARTICIPATE_IN: "정상적으로 방 참여를 취소하였습니다.",
DELETE_PARTICIPATED_ROOM: "정상적으로 방을 삭제하였습니다.",
PUT_REVIEW_FEEDBACK: "정상적으로 피드백을 수정하였습니다.",
POST_REVIEW_URGE: "정상적으로 코드리뷰 재촉하기를 했습니다.",
};

const MESSAGES = {
Expand Down
33 changes: 29 additions & 4 deletions frontend/src/hooks/mutations/useMutateReview.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import useMutateHandlers from "./useMutateHandlers";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import useToast from "@/hooks/common/useToast";
import { ReviewReminderAlarm } from "@/@types/alaram";
import QUERY_KEYS from "@/apis/queryKeys";
import { postReviewComplete } from "@/apis/reviews.api";
import { postReviewComplete, postReviewUrge } from "@/apis/reviews.api";
import MESSAGES from "@/constants/message";

const useMutateReviewComplete = (roomId: number) => {
const useMutateReview = (roomId: number) => {
const { handleMutateError } = useMutateHandlers();
const { openToast } = useToast("success");

Expand All @@ -16,12 +17,36 @@ const useMutateReviewComplete = (roomId: number) => {
postReviewComplete(roomId, revieweeId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.REVIEWEES, roomId] });
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.ALARM_COUNT],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.ALARM_LIST],
});
openToast(MESSAGES.SUCCESS.POST_REVIEW_COMPLETE);
},
onError: (error) => handleMutateError(error),
});

return { postReviewCompleteMutation };
const postReviewUrgeMutation = useMutation({
mutationFn: ({ roomId, reviewerId }: ReviewReminderAlarm) =>
postReviewUrge({ roomId, reviewerId }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.REVIEWERS, roomId],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.ALARM_COUNT],
});
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.ALARM_LIST],
});
openToast(MESSAGES.SUCCESS.POST_REVIEW_URGE);
},
onError: (error) => handleMutateError(error),
});

return { postReviewCompleteMutation, postReviewUrgeMutation };
};

export default useMutateReviewComplete;
export default useMutateReview;
16 changes: 16 additions & 0 deletions frontend/src/mocks/mockResponse/alarmInfos.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@
"isRead": false,
"createAt": "2024-1008T00:01:59.4122",
"alarmType": "USER"
},
{
"alarmId": 3,
"actionType": "REVIEW_URGE",
"actor": {
"memberId": 2,
"username": "ashs",
"thumbnailUrl": "www.myProfile.jpg"
},
"interaction": {
"interactionId": 1,
"info": "TDD 자바 TDD 자바 TDD 자바[]"
},
"isRead": false,
"createAt": "2024-1008T00:01:59.4122",
"alarmType": "USER"
}
]
}
16 changes: 15 additions & 1 deletion frontend/src/pages/alarm/AlarmPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@ const AlarmPage = () => {
if (actionType === "REVIEW_COMPLETE") {
return (
<>
<span>{username}</span> 님이 <span>{info}</span> 미션에 대해 코드리뷰를 완료했습니다.
<span>{username}</span> 님이 <span>{info}</span> 미션에 대해 <span>코드리뷰를 완료</span>
했습니다.
Comment on lines +32 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드리뷰 완료도 굵게 처리 되었으면 좋겠다고 피드백이 들어 왔었는데 바로 반영해주셨네요👍👍

</>
);
}

if (actionType === "REVIEW_URGE") {
return (
<>
<span>{username}</span> 님이 <span>{info}</span> 미션에 대해 <span>코드리뷰를 재촉</span>
했습니다.
</>
);
}
Expand All @@ -40,6 +50,10 @@ const AlarmPage = () => {
if (actionType === "REVIEW_COMPLETE") {
return `/rooms/${interactionId}`;
}

if (actionType === "REVIEW_URGE") {
return `/rooms/${interactionId}`;
}
return "";
};

Expand Down
Loading