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

마인더 정산신청 페이지 무한스크롤 오류 해결 및 DTO 업데이트 #415

Merged
merged 7 commits into from
Nov 6, 2024
4 changes: 2 additions & 2 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { BuyerMypage } from 'pages/Buyer/BuyerMypage';
import { BuyerSearch } from 'pages/Buyer/BuyerSearch';
import { BuyerSearchResult } from 'pages/Buyer/BuyerSearchResult';
import { BuyerSignup } from 'pages/Buyer/BuyerSignup';
import { SellerCaculateManagement } from 'pages/Seller/SellerCalculateManagement';
import { SellerConsult } from 'pages/Seller/SellerConsult';
import { SellerHome } from 'pages/Seller/SellerHome';
import { SellerLetter } from 'pages/Seller/SellerLetter';
Expand Down Expand Up @@ -56,6 +55,7 @@ import SellerProfitBankAccount from 'pages/Seller/SellerProfitBankAccount';
import ServerDown from 'pages/Common/ServerDown';
import SellerUpdateFail from 'pages/Seller/SellerUpdateFail';
import { BuyerManyLovedCounselor } from 'pages/Buyer/BuyerManyLovedCounselor';
import SellerCalculateManagement from 'pages/Seller/SellerCalculateManagement';

const Router = () => {
return (
Expand Down Expand Up @@ -164,7 +164,7 @@ const Router = () => {
{/* 판매자 : 수익 관리 */}
<Route
path="/minder/calculatemanagement"
element={<SellerCaculateManagement />}
element={<SellerCalculateManagement />}
/>
{/* 판매자 : 마인더 인증 */}
<Route path="/minder/education/*" element={<SellerVerifyMaterial />} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function CompleteApplyPopup({
width="calc(100% - 3.2rem)"
onClick={() => {
setIsCompleteApplyManage(false);
window.location.reload();
Copy link
Contributor

Choose a reason for hiding this comment

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

혹시 여기서 reload 가 필요한 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

정산신청버튼을 누르고 팝업을 닫았을 경우에 데이터 최신화가 안되는 이슈가 있어서 reload()를 넣었습니다.. ㅎㅎ

정산예정 항목을 정산신청했을 경우에는 정산 중 항목으로 정산 예정항목이 넘어가게 되는데,
"정산 신청이 완료 되었습니다" 팝업을 닫았을 떄 페이지 새로고침을 강제하여 데이터가 최신화되게 하였습니다.

Reload하지말고 애초에 정산신청 클릭했을 때 manageList서 필터링하는게 나을거같긴 한데 바꿀까요?

Copy link
Contributor

Choose a reason for hiding this comment

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

일단 filter한 list로 set해주는 로직 확인하였습니다 🫡

만약 react-query를 사용한다면, invalidateQueries를 사용하면 쉽게 구현할 수 있을 것 같네요!

예를 들어 기존의 코드가 이렇게 구현되있다면, 먼저 useQuery로 GET 요청을 하여 가져오는 로직으로 수정하고, 정산 신청 시 해당 queryKeyinvalidateQueries로 처리하면, 알아서 useQuery에서 해당 요청이 invalidate해진 걸 인지하고 다시 get 요청을 하게 됩니다.

  useEffect(() => {
    fetchManagements(0);
  }, [sortType, manageStatus]);
  const query = useQuery({
    queryKey: ["getPaymentsCounselors"],
    queryFn: getMaymentMinder
  })
  
  ...
  
  const queryClient = useQueryClient()
  
  onClick={() => {
          setIsCompleteApplyManage(false);
         queryClient.invalidateQueries({ queryKey: ['getPaymentsCounselors'] })
         }}
  

이런 식으로 react-query로 구현하면 안정성 있게 구현할 수 있을 것 같네요!
코스트가 많이 들 것 같다면 일단 머지하면 될 것 같습니다 고생하셨습니닷🫡

Copy link
Contributor Author

Choose a reason for hiding this comment

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

코드 가독성과 안정성 측면에서 여러모로 tanstack-query 도입이 필요할 거 같습니다... 일단은 머지하고 마인더 쪽 코드에서 tanstack-query 리팩토링은 이슈 등록해서 한번에 진행해보겠습니다

}}
/>
</CompleteApplyPopupBox>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ interface SellerCalulateCardProps {
salePrice: number;
commission: number;
paymentDate: string;
consultDate: string;
paymentAccount: string;
id: number;
calculateActivate: boolean;
isShowPopup: boolean;
setIsShowPopup: any;
manageStatus: string;
}

export const SellerCalulateCard = ({
Expand All @@ -28,10 +30,12 @@ export const SellerCalulateCard = ({
commission,
paymentAccount,
paymentDate,
consultDate,
calculateActivate,
id,
isShowPopup,
setIsShowPopup,
manageStatus,
}: SellerCalulateCardProps) => {
const applyManagement = async (id: number) => {
const res: any = await patchApplyPayments(id);
Expand Down Expand Up @@ -81,7 +85,11 @@ export const SellerCalulateCard = ({
<Body3>{commission.toLocaleString()} 원</Body3>
</ConsultEarnInfoItem>
<ConsultEarnInfoItem>
<Body3 color={Grey3}>지급일자</Body3>
<Body3 color={Grey3}>상담일자</Body3>
<Body3>{consultDate}</Body3>
</ConsultEarnInfoItem>
<ConsultEarnInfoItem>
<Body3 color={Grey3}>지급예정</Body3>
<Body3>{paymentDate}</Body3>
</ConsultEarnInfoItem>
<ConsultEarnInfoItem>
Expand Down
190 changes: 78 additions & 112 deletions src/pages/Seller/SellerCalculateManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,13 @@ import { LoadingSpinner } from 'utils/LoadingSpinner';
import useIntersectionObserver from 'hooks/useIntersectionObserver';
import { BackDrop } from 'components/Common/BackDrop';

//
//
//

const manageStatusMap = {
const STATUS_MAP = {
'정산 중': 'SETTLEMENT_ONGOING',
'정산 예정': 'SETTLEMENT_WAITING',
완료: 'SETTLEMENT_COMPLETE',
};

const sortTypeMap = ['WEEK', 'MONTH', 'ALL'];

//
//
//
const SORT_OPTIONS = ['WEEK', 'MONTH', 'ALL'];

interface ManageItem {
paymentId: number;
Expand All @@ -38,45 +30,34 @@ interface ManageItem {
profit: number;
cost: number;
fee: number;
approvedAt: null;
account: null;
total: number;
consultedAt: string;
settledAt: string;
account: string;
}

type ManageList = ManageItem[];

//
//
//

export const SellerCaculateManagement = () => {
export default function SellerCalculateManagement() {
const navigate = useNavigate();

// 상단 탭의 상태
const [manageStatus, setManageStatus] = useState<string>('완료');

// 드롭다운 메뉴, 최근 일주일 : 0 , 최근 1개월 : 1, 전체 : 2
const [sortType, setSortType] = useState<number>(0);
const [isModalOpen, setIsModalOpen] = useRecoilState<boolean>(
isConsultModalOpenState,
);
const [isLastElem, setIsLastElem] = useState<boolean>(false);
const [isModalOpen, setIsModalOpen] = useRecoilState(isConsultModalOpenState);
const [isLastElem, setIsLastElem] = useState(false);
const [managementList, setManagementList] = useState<ManageList>([]);
const [toatlMoney, setTotalMoney] = useState<number>(0);
const [totalMoney, setTotalMoney] = useState(0);
const [isCompleteApplyManage, setIsCompleteApplyManage] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [lastId, setLastId] = useState(0);

//scorll 막기
const setScrollLock = useSetRecoilState(scrollLockState);

const preventRef = useRef(true);

// 스크롤 인터섹션 콜백
const onIntersect: IntersectionObserverCallback = async (entry) => {
if (entry[0].isIntersecting && !isLastElem && preventRef.current) {
preventRef.current = false;
await fetchManagements(
managementList[managementList.length - 1].paymentId,
);
await fetchManagements(lastId);
preventRef.current = true;
}
};
Expand All @@ -88,43 +69,32 @@ export const SellerCaculateManagement = () => {
onIntersect,
});

/**
*
*/
const fetchManagements = async (lastId: number) => {
const params = {
status: manageStatusMap[manageStatus as keyof typeof manageStatusMap],
sort: sortTypeMap[sortType],
status: STATUS_MAP[manageStatus as keyof typeof STATUS_MAP],
sort: SORT_OPTIONS[sortType],
paymentId: lastId,
};
const res: any = await getPaymentsMinder({ params });

try {
if (res?.status === 200) {
if (res.data.length !== 0) {
if (lastId === 0) {
setManagementList(res.data);
let totalEarnMoney = 0;
res?.data?.forEach((item: ManageItem) => {
totalEarnMoney += Number(item?.profit);
});
setTotalMoney(totalEarnMoney);
} else {
const updatedManages = [...managementList, ...res.data];
setManagementList(updatedManages);
let totalEarnMoney = 0;
res?.data?.forEach((item: ManageItem) => {
totalEarnMoney += Number(item?.profit);
});
setTotalMoney(totalEarnMoney);
}
const res: any = await getPaymentsMinder({ params });

if (res.status === 200) {
const responses = res.data.paymentGetCounselorResponses;
const isInitialLoad = lastId === 0;
setTotalMoney(res.data.total);
if (responses.length) {
setManagementList(
isInitialLoad ? responses : [...managementList, ...responses],
);
setLastId(responses[responses.length - 1].paymentId);
setIsLastElem(false);
} else {
setManagementList(res.data);
setManagementList(
isInitialLoad ? [] : [...managementList, ...responses],
);
setLastId(0);
setIsLastElem(true);
let totalEarnMoney = 0;
res?.data?.forEach((item: ManageItem) => {
totalEarnMoney += Number(item?.profit);
});
setTotalMoney(totalEarnMoney);
}
} else {
alert('판매 정보가 아직 등록되지 않았어요!');
Expand All @@ -133,22 +103,13 @@ export const SellerCaculateManagement = () => {
} catch (err) {
alert(err);
} finally {
if (lastId === 0) {
setIsLoading(false);
}
if (lastId === 0) setIsLoading(false);
}
};

//
//
//
useEffect(() => {
fetchManagements(0);
}, [manageStatus, sortType, isCompleteApplyManage, navigate]);

//
//
//
}, [sortType, manageStatus]);

return (
<>
Expand All @@ -158,10 +119,11 @@ export const SellerCaculateManagement = () => {
setManageStatus={setManageStatus}
sortType={sortType}
/>

{isLoading ? (
<div style={{ display: 'flex', alignItems: 'center', height: '70vh' }}>
<CenteredContainer>
<LoadingSpinner />
</div>
</CenteredContainer>
) : (
<>
<TotalEarnMoney>
Expand All @@ -172,45 +134,38 @@ export const SellerCaculateManagement = () => {
? '정산 중 금액 합계'
: '정산예정 금액 합계'}
</Heading>
<Subtitle color={Red}>{toatlMoney?.toLocaleString()} 원</Subtitle>
<Subtitle color={Red}>{totalMoney?.toLocaleString()} 원</Subtitle>
</TotalEarnMoney>
{/* 내역이 없을시 */}
{managementList?.length === 0 ? (

{managementList.length === 0 ? (
<NoCalculationGraphic status={manageStatus} />
) : (
<>
<SellerCalculateCardList>
{/* //정산 예정일일 경우 calculateActivate false true로~*/}
{managementList?.map((item) => (
<SellerCalulateCard
key={item?.paymentId}
id={item?.paymentId}
customerName={item?.nickname}
calculateActivate={
manageStatus === '정산 예정' ? true : false
}
consultType={item?.isChat ? '채팅' : '편지'}
netProfit={item?.profit}
commission={item?.fee}
paymentAccount={item?.account ?? '계좌 명시안됨'}
paymentDate={item?.approvedAt ?? '지급 일자 명시안됨'}
salePrice={item?.cost}
isShowPopup={isCompleteApplyManage}
setIsShowPopup={setIsCompleteApplyManage}
/>
))}
</SellerCalculateCardList>
{!isLastElem ? (
<div ref={setTarget} style={{ height: '3.5rem' }} />
) : (
<div style={{ height: '3.5rem' }} />
)}
</>
<SellerCalculateCardList>
{managementList.map((item) => (
<SellerCalulateCard
key={item.paymentId}
manageStatus={manageStatus}
id={item.paymentId}
customerName={item.nickname}
calculateActivate={manageStatus === '정산 예정'}
consultType={item.isChat ? '채팅' : '편지'}
netProfit={item.profit}
commission={item.fee}
paymentAccount={item.account ?? '계좌 명시안됨'}
consultDate={item.consultedAt ?? '상담 일자 명시안됨'}
paymentDate={item.settledAt ?? '지급 일자 명시안됨'}
salePrice={item.cost}
isShowPopup={isCompleteApplyManage}
setIsShowPopup={setIsCompleteApplyManage}
/>
))}
{!isLastElem && <IntersectionTarget ref={setTarget} />}
</SellerCalculateCardList>
)}
</>
)}

{isModalOpen ? (
{isModalOpen && (
<>
<BackDrop
onClick={() => {
Expand All @@ -224,22 +179,33 @@ export const SellerCaculateManagement = () => {
setSortType={setSortType}
/>
</>
) : null}
)}
</>
);
};
}

// 스타일 컴포넌트 정의
const CenteredContainer = styled.div`
display: flex;
align-items: center;
height: 70vh;
`;

const TotalEarnMoney = styled.div`
display: flex;
align-items: center;
gap: 0.8rem;
margin: 1.2rem 2rem 1.2rem;
margin: 1.2rem 2rem;
`;

const SellerCalculateCardList = styled.div`
display: flex;
gap: 1rem;
margin: 1.4rem 0rem;
align-items: center;
flex-direction: column;
align-items: center;
gap: 1rem;
margin: 1.4rem 0;
`;

const IntersectionTarget = styled.div`
height: 3.5rem;
`;
Loading