Skip to content
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
7 changes: 7 additions & 0 deletions src/api/myProjectList.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ export const getMyProjectLists = async () => {
const response = await httpClient.get<ManagedProject[]>(`/project/my`);
return response.data;
};

export const patchSendResult = async (projectId: number) => {
const response = await httpClient.patch<ManagedProject>(
`/project/${projectId}/is-done`
);
return response.data;
};
4 changes: 4 additions & 0 deletions src/components/common/Button/Button.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ export const CommonButton = styled.button<Omit<ButtonProps, 'children'>>`
border-radius: ${({ theme, radius }) => theme.borderRadius[radius]};
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'auto')};
cursor: ${({ disabled }) => (disabled ? 'none' : 'pointer')};

display: flex;
justify-content: center;
align-items: center;
`;
5 changes: 2 additions & 3 deletions src/components/common/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ButtonHTMLAttributes, ReactNode } from 'react';
import { ButtonHTMLAttributes, PropsWithChildren } from 'react';
import * as S from './Button.styled';
import {
BorderRadiusSize,
Expand All @@ -7,7 +7,6 @@ import {
} from '../../../style/theme';

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: ReactNode;
size: ButtonSize;
schema: ButtonSchema;
radius: BorderRadiusSize;
Expand All @@ -21,7 +20,7 @@ function Button({
radius,
disabled,
...props
}: ButtonProps) {
}: PropsWithChildren<ButtonProps>) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

ButtonHTMLAttributes에는 children이 없으려나요? 👀

return (
<S.CommonButton
size={size}
Expand Down
1 change: 1 addition & 0 deletions src/components/common/infoCard/InfoCard.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const Container = styled.div`
min-width: 530px;
height: 80vh;
padding-bottom: 1rem;
position: relative;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from 'styled-components';

export const DeleteButton = styled.button`
svg {
color: #e69191;
width: 1.2rem;
height: 1.2rem;
}
`;
16 changes: 16 additions & 0 deletions src/components/manageProjects/passNonPassList/DeleteButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ButtonHTMLAttributes } from 'react';
import * as S from './DeleteButton.styled';
import { XCircleIcon } from '@heroicons/react/24/outline';
interface DeleteButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
onClick: () => void;
}

function DeleteButton({ onClick }: DeleteButtonProps) {
return (
<S.DeleteButton onClick={onClick}>
<XCircleIcon />
</S.DeleteButton>
);
}

export default DeleteButton;
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,9 @@ export const ItemWrapper = styled.li`
background-color: ${({ theme }) => theme.color.navy};
color: ${({ theme }) => theme.color.white};
}

svg {
color: #e69191;
width: 1.2rem;
height: 1.2rem;
}
`;

export const NickName = styled.p`
font-size: ${({ theme }) => theme.heading.small.fontSize};
font-weight: 400;
`;

export const DeleteButton = styled.button``;
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { useMutationParams } from '../../../hooks/usePassNonPassMutation';
import { ApplicantInfo } from '../../../models/applicant';
import DeleteButton from './DeleteButton';
import * as S from './PassNonPassItem.styled';
import { XCircleIcon } from '@heroicons/react/24/outline';

interface PassNonPassItemProps {
userInfo: ApplicantInfo;
onClick: ({ status, userId }: useMutationParams) => void;
}

function PassNonPassItem({ userInfo }: PassNonPassItemProps) {
function PassNonPassItem({ userInfo, onClick }: PassNonPassItemProps) {
return (
<S.ItemWrapper>
<S.NickName>{userInfo.User.nickname}</S.NickName>
<S.DeleteButton>
<XCircleIcon />
</S.DeleteButton>
<DeleteButton
onClick={() => onClick({ status: 'WAITING', userId: userInfo.userId })}
/>
</S.ItemWrapper>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { useMutationParams } from '../../../hooks/usePassNonPassMutation';
import { ApplicantInfo } from '../../../models/applicant';
import PassNonPassItem from './PassNonPassItem';
import * as S from './PassNonPassList.styled';

interface PassNonPassListProps {
passNonPassListData: ApplicantInfo[];
onClick: ({ status, userId }: useMutationParams) => void;
}

function PassNonPassList({ passNonPassListData }: PassNonPassListProps) {
function PassNonPassList({
passNonPassListData,
onClick,
}: PassNonPassListProps) {
return (
<S.Wrapper>
{passNonPassListData.map((data) => (
<PassNonPassItem key={data.userId} userInfo={data} />
<PassNonPassItem key={data.userId} onClick={onClick} userInfo={data} />
))}
</S.Wrapper>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styled from 'styled-components';
import Button from '../../common/Button/Button';

export const Wrapper = styled.div`
width: 100%;
display: flex;
justify-content: end;
align-items: center;
position: absolute;
top: 7rem;
right: 2.5rem;
`;

export const SendEmailButton = styled(Button)`
width: 9rem;

svg {
width: 1.5rem;
margin-left: 0.5rem;
}
&:hover {
opacity: 0.8;
}
`;
24 changes: 24 additions & 0 deletions src/components/manageProjects/passNonPassList/SendResultButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ButtonHTMLAttributes } from 'react';
import * as S from './SendResultButton.styled';
import { EnvelopeIcon } from '@heroicons/react/24/outline';
export interface SendResultButtonProps
extends ButtonHTMLAttributes<HTMLButtonElement> {
onSubmit: () => void;
}

function SendResultButton({ onSubmit }: SendResultButtonProps) {
return (
<S.Wrapper>
<S.SendEmailButton
size='primary'
schema='primary'
radius='primary'
onClick={onSubmit}
>
결과 전송 <EnvelopeIcon />
</S.SendEmailButton>
</S.Wrapper>
);
}

export default SendResultButton;
5 changes: 5 additions & 0 deletions src/constants/modalMessage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
export const MODAL_MESSAGE = {
pass: '지원자를 합격 리스트에 추가했습니다.',
nonPass: '지원자를 불합격 리스트에 추가했습니다.',
waiting: '지원자를 대기리스트에 추가했습니다',
equalStatus: '이미 동일한 리스트에 추가하신 상태입니다.',
signUp: '회원가입에 성공하셨습니다!',
login: '로그인 되었습니다.',
sendResult: '지원자들에게 이메일로 결과를 전송했어요!',
needAuth: '권한이 없어요!',
signUpSuccess: '회원가입 완료되었습니다.',
signUpFail: '회원가입 실패하였습니다.',
changePasswordSuccess: '비밀번호가 성공적으로 재설정 되었습니다.',
Expand Down
34 changes: 24 additions & 10 deletions src/hooks/usePassNonPassMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { AxiosError } from 'axios';
import { applicantKey } from './queries/keys';
import { MODAL_MESSAGE } from '../constants/modalMessage';

interface useMutationParams {
isPass: boolean;
export interface useMutationParams {
status: 'ACCEPTED' | 'REJECTED' | 'WAITING';
userId: number;
}

Expand All @@ -16,19 +16,33 @@ export const usePassNonPassMutation = (
const queryClient = useQueryClient();

const passNonPassMutation = useMutation<void, AxiosError, useMutationParams>({
mutationFn: async ({ isPass, userId }: useMutationParams) => {
const data = { status: isPass ? 'ACCEPTED' : 'REJECTED' };
mutationFn: async ({ status, userId }: useMutationParams) => {
const data = { status: status };
await patchPassNonPassStatus(data, projectId, userId);
},

onSuccess: (_, { isPass }) => {
onSuccess: (_, { status }) => {
queryClient.invalidateQueries({
queryKey: [applicantKey.all, projectId],
});

const successMessage = isPass
? MODAL_MESSAGE.pass
: MODAL_MESSAGE.nonPass;
queryClient.invalidateQueries({
queryKey: [applicantKey.passNonPass, projectId],
});

let successMessage;
switch (status) {
case 'ACCEPTED':
successMessage = MODAL_MESSAGE.pass;
break;
case 'REJECTED':
successMessage = MODAL_MESSAGE.nonPass;
break;
case 'WAITING':
successMessage = MODAL_MESSAGE.waiting;
break;
}

openModal(successMessage);
},

Expand All @@ -38,8 +52,8 @@ export const usePassNonPassMutation = (
},
});

const handlePassNonPassStatus = (isPass: boolean, userId: number) => {
passNonPassMutation.mutate({ isPass, userId });
const handlePassNonPassStatus = ({ status, userId }: useMutationParams) => {
passNonPassMutation.mutate({ status, userId });
};

return { handlePassNonPassStatus };
Expand Down
30 changes: 30 additions & 0 deletions src/hooks/useSendResultMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useMutation } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { patchSendResult } from '../api/myProjectList.api';
import { MODAL_MESSAGE } from '../constants/modalMessage';

export const useSendResultMutation = (
projectId: number,
openModal: (message: string) => void
) => {
const sendResultMutaition = useMutation<void, AxiosError>({
mutationFn: async () => {
await patchSendResult(projectId);
},

onSuccess: () => {
openModal(MODAL_MESSAGE.sendResult);
},

onError: (error) => {
console.error(error);
openModal(MODAL_MESSAGE.needAuth);
},
});

const handleSendResult = () => {
sendResultMutaition.mutate();
};

return { handleSendResult };
};
3 changes: 2 additions & 1 deletion src/mock/browser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { setupWorker } from 'msw/browser';
import { myProjectList } from './manageProjectList';
import { myProjectList, sendResult } from './manageProjectList';
import {
applicantInfo,
applicantList,
Expand Down Expand Up @@ -31,6 +31,7 @@ export const handlers = [
fetchPositionTag,
fetchSkillTag,
passNonPassList,
sendResult,
myProjectList,
applicantList,
projectDetail,
Expand Down
12 changes: 12 additions & 0 deletions src/mock/manageProjectList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@ export const myProjectList = http.get(
});
}
);

export const sendResult = http.patch(
`${import.meta.env.VITE_API_BASE_URL}/project/:projectId/is-done`,
() => {
return HttpResponse.json(
{ message: '지원자들에게 결과를 전송했어요' },
{
status: 200,
}
);
}
);
Loading