Skip to content

Commit

Permalink
feat: 나눔 상태 변경, 나눔 신청, 나눔 신청 취소 API 연동 (#41)
Browse files Browse the repository at this point in the history
* refactor: type import 수정

* style: RadioButtonField component style 수정

* chore: eslint @typescript-eslint/no-misused-promises off

* feat: usePutShareStatus hook 생성

* feat: 나눔 상태 변경 API 연동

* feat: ShareStatusBadge component 생성, 적용

* feat: useApplyShare, useDeleteApplyShare hook 생성

* feat: 나눔 신청, 나눔 신청 취소 API 연동
  • Loading branch information
hyeseon-han authored Mar 1, 2024
1 parent 8ac1dd4 commit 6370504
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 54 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ module.exports = {
'prettier/prettier': ['error', { endOfLine: 'auto' }],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-misused-promises': 'off',
},
};
2 changes: 1 addition & 1 deletion src/components/atoms/RadioButtonField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const RadioButtonField: React.FC<{
checked: boolean;
}> = ({ label, onClick, checked }) => {
return (
<button onClick={onClick} className="flex flex-1 w-screen px-[20px] py-[24px] justify-between">
<button onClick={onClick} className="flex flex-1 w-full px-[20px] py-[24px] justify-between">
<p className="heading3-semibold">{label}</p>
<Radio checked={checked} />
</button>
Expand Down
35 changes: 35 additions & 0 deletions src/components/atoms/ShareStatusBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useMemo } from 'react';

import type { ShareStatusType } from '@/types/friendship';

const ShareStatusBadge: React.FC<{ status: ShareStatusType }> = ({ status }) => {
const text = useMemo(() => {
switch (status) {
case 'SHARE_START':
return '나눔 신청';
case 'SHARE_IN_PROGRESS':
return '나눔 중';
case 'SHARE_COMPLETE':
return '나눔 완료';
default:
return '';
}
}, [status]);

const className = useMemo(() => {
switch (status) {
case 'SHARE_START':
return 'bg-[#DCF3ED] text-primary2';
case 'SHARE_IN_PROGRESS':
return 'bg-[#FFEBE6] text-point3';
case 'SHARE_COMPLETE':
return 'bg-gray0 text-gray4';
default:
return '';
}
}, [status]);

return <div className={`px-[8px] py-[4px] rounded-[6px] body2-medium ${className} `}>{text}</div>;
};

export default ShareStatusBadge;
1 change: 1 addition & 0 deletions src/components/atoms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export { default as MiniButton } from './MiniButton';
export { default as ExclamationAlertSpan } from './ExclamationAlertSpan';
export { default as Lottie } from './Lottie';
export { default as CheckBox } from './CheckBox';
export { default as ShareStatusBadge } from './ShareStatusBadge';
52 changes: 38 additions & 14 deletions src/components/organisms/ShareDetailAuthorBottomWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { Button, RadioButtonField } from '@/components/atoms';
import { Modal, ModalBody, ModalContent, ModalOverlay, useDisclosure } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';
import { useGetShareApplicants, usePutShareStatus } from '@/hooks/queries/share';

import { Button, RadioButtonField } from '@/components/atoms';
import React from 'react';
import { type SortLabel } from '@/types/common';
import { useGetShareApplicants } from '@/hooks/queries/share';
import ShareApplicantListItem from './ShareApplicantListItem';
import type { ShareStatusType } from '@/types/friendship';

export interface ShareStatusKeyValue {
label: string;
value: ShareStatusType;
}

const SHARE_STATUSES = [
{ label: '나눔 신청', value: 'enroll' },
{ label: '나눔 중', value: 'proceeding' },
{ label: '나눔 완료', value: 'complete' },
const SHARE_STATUSES: ShareStatusKeyValue[] = [
{ label: '나눔 신청', value: 'SHARE_START' },
{ label: '나눔 중', value: 'SHARE_IN_PROGRESS' },
{ label: '나눔 완료', value: 'SHARE_COMPLETE' },
];

const ShareDetailAuthorBottomWrapper: React.FC<{
id: string | string[] | undefined;
curStatus: SortLabel;
onChangeStatus: React.Dispatch<React.SetStateAction<SortLabel>>;
}> = ({ id, curStatus, onChangeStatus }) => {
refetch: () => void;
curStatus: ShareStatusType;
}> = ({ id, refetch, curStatus }) => {
const [selectedStatus, setSelectedStatus] = useState<ShareStatusKeyValue>(
SHARE_STATUSES.find((ele) => ele.value === curStatus) as ShareStatusKeyValue,
);
const { isOpen: isStatusModalOpen, onOpen: onStatusModalOpen, onClose: onStatusModalClose } = useDisclosure();
const {
isOpen: isParticipantsModalOpen,
Expand All @@ -25,6 +33,22 @@ const ShareDetailAuthorBottomWrapper: React.FC<{
} = useDisclosure();

const applicants = useGetShareApplicants({ id });
const modifyShareStatus = usePutShareStatus({
id: Number(id),
status: selectedStatus.value as ShareStatusType,
onSuccessParam: refetch,
});

const onModifyShareStatus = () => {
onStatusModalClose();
modifyShareStatus.mutate({});
};

useEffect(() => {
const initialStatus = SHARE_STATUSES.find((ele) => ele.value === curStatus);
console.log(initialStatus);
setSelectedStatus(initialStatus as { label: string; value: ShareStatusType });
}, []);

return (
<>
Expand Down Expand Up @@ -53,13 +77,13 @@ const ShareDetailAuthorBottomWrapper: React.FC<{
key={ele.value}
label={ele.label}
onClick={() => {
onChangeStatus(ele);
setSelectedStatus(ele);
}}
checked={ele.value === curStatus.value}
checked={ele.value === selectedStatus.value}
/>
))}
<div className="px-[20px] pb-[32px]">
<Button className="block w-full bg-primary2" text={'선택 완료'} onClick={onStatusModalClose} />
<Button className="block w-full bg-primary2" text={'선택 완료'} onClick={onModifyShareStatus} />
</div>
</ModalBody>
</ModalContent>
Expand Down
61 changes: 61 additions & 0 deletions src/components/organisms/ShareDetailFriendBottomWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useApplyShare, useDeleteApplyShare } from '@/hooks/queries/share';

import React from 'react';
import type { ShareStatusType } from '@/types/friendship';
import useToast from '@/hooks/useToast';

const APPLY_SUCCESS_MESSAGE = '나눔 신청이 완료되었습니다.';
const APPLY_DELETE_SUCCESS_MESSAGE = '나눔 신청이 취소되었습니다.';

const ShareDetailFriendBottomWrapper: React.FC<{
id: string | string[] | undefined;
isApplied: boolean;
curStatus: ShareStatusType;
refetch: () => void;
}> = ({ id, isApplied, curStatus, refetch }) => {
const { showToast } = useToast();
const applyShare = useApplyShare({
onSuccess: () => {
showToast(APPLY_SUCCESS_MESSAGE, 'success');
refetch();
},
});
const deleteShare = useDeleteApplyShare({
id: Number(id),
onSuccess: () => {
showToast(APPLY_DELETE_SUCCESS_MESSAGE, 'success');
refetch();
},
});

const onApply = () => {
applyShare.mutate({ shareId: Number(id) });
};

const onApplyCancel = () => {
deleteShare.mutate({});
};

if (curStatus === 'SHARE_COMPLETE') {
return (
<div className="fixed w-full max-w-[480px] bottom-0 p-[20px] pb-[32px] z-300 bg-gray1">
<p className="w-full text-center py-[16px] rounded-[12px] text-gray0 bg-gray3 heading4-semibold">
나눔 신청 종료
</p>
</div>
);
}

return (
<div className="fixed w-full max-w-[480px] bottom-0 p-[20px] pb-[32px] z-300 bg-gray1">
<button
onClick={isApplied ? onApplyCancel : onApply}
className="w-full text-center py-[16px] rounded-[12px] text-white bg-primary2 heading4-semibold"
>
{isApplied ? '나눔 신청 완료' : '나눔 신청'}
</button>
</div>
);
};

export default ShareDetailFriendBottomWrapper;
1 change: 1 addition & 0 deletions src/components/organisms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { default as FriendListItem } from './FriendListItem';
export { default as BulletNoticeBox } from './BulletNoticeBox';
export { default as SelectFridgeModal } from './SelectFridgeModal';
export { default as SelectFridgeBoard } from './SelectFridgeBoard';
export { default as ShareDetailFriendBottomWrapper } from './ShareDetailFriendBottomWrapper';
3 changes: 3 additions & 0 deletions src/hooks/queries/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const queryKeys = {
SHARE_APPLICANTS: () => ['shareApplicants'],
UPLOAD: () => ['upload'],
ADD_SHARE: () => ['addShare'],
MODIFY_SHARE_STATUS: () => ['modify_share_status'],
APPLY_SHARE: () => ['apply_share'],
DELETE_APPLY_SHARE: () => ['delete_share'],
} as const;

export type QueryKeys = (typeof queryKeys)[keyof typeof queryKeys];
3 changes: 3 additions & 0 deletions src/hooks/queries/share/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ export { default as useGetShareDetail } from './useGetShareDetail';
export { default as useGetShareApplicants } from './useGetShareApplicants';
export { default as usePostUpload } from './usePostUpload';
export { default as usePostShare } from './usePostShare';
export { default as usePutShareStatus } from './usePutShareStatus';
export { default as useApplyShare } from './useApplyShare';
export { default as useDeleteApplyShare } from './useDeleteApplyShare';
7 changes: 7 additions & 0 deletions src/hooks/queries/share/useApplyShare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { queryKeys } from '../queryKeys';
import { useBaseMutation } from '../useBaseMutation';

const useApplyShare = ({ onSuccess }: { onSuccess: () => void }) => {
return useBaseMutation<{ shareId: number }>(queryKeys.APPLY_SHARE(), `/shares/applies`, onSuccess);
};
export default useApplyShare;
7 changes: 7 additions & 0 deletions src/hooks/queries/share/useDeleteApplyShare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { queryKeys } from '../queryKeys';
import { useBaseMutation } from '../useBaseMutation';

const useDeleteApplyShare = ({ id, onSuccess }: { id: number; onSuccess: () => void }) => {
return useBaseMutation(queryKeys.DELETE_APPLY_SHARE(), `/shares/applies/${id}`, onSuccess, 'DELETE');
};
export default useDeleteApplyShare;
4 changes: 2 additions & 2 deletions src/hooks/queries/share/useGetShareDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const useGetShareDetail = ({ id }: { id: string | string[] | undefined }) => {
if (typeof id !== 'string') {
return null;
}
const { data } = useBaseQuery<ShareDetailData>(queryKeys.SHARE_DETAIL(), `/shares/${id}`);
const { data, refetch } = useBaseQuery<ShareDetailData>(queryKeys.SHARE_DETAIL(), `/shares/${id}`);

return data?.data;
return { data, refetch };
};

export default useGetShareDetail;
26 changes: 26 additions & 0 deletions src/hooks/queries/share/usePutShareStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { ShareStatusType } from '@/types/friendship';
import { queryClient } from '@/pages/_app';
import { queryKeys } from '../queryKeys';
import { useBaseMutation } from '../useBaseMutation';

const usePutShareStatus = ({
id,
status,
onSuccessParam,
}: {
id: number;
status: ShareStatusType;
onSuccessParam: () => void;
}) => {
const onSuccess = () => {
onSuccessParam();
void queryClient.invalidateQueries();
};
return useBaseMutation(
queryKeys.MODIFY_SHARE_STATUS(),
`/shares/${id}/status?updateShareStatusRequest=${status}`,
onSuccess,
'PUT',
);
};
export default usePutShareStatus;
Loading

0 comments on commit 6370504

Please sign in to comment.