From aa3523330befebd5e57d5619ba79577a6bc7b008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=91=ED=98=84?= Date: Sat, 16 Sep 2023 20:37:11 +0900 Subject: [PATCH] =?UTF-8?q?[Fix]=ED=98=84=EA=B8=88=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=A0=95=EC=83=81=ED=99=94=20moneyId=20->cashId,=20moneyAmount?= =?UTF-8?q?=20->money=20=EB=A1=9C=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20useCash=ED=9B=85=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A0=84=EC=97=AD=EB=B3=80=EC=88=98=EB=A5=BC=20=EB=8F=84?= =?UTF-8?q?=EC=9E=85=ED=95=98=EC=97=AC=20=EB=B6=88=EB=9F=AC=EB=82=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20cashModal=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EB=B3=80=EA=B2=BD=20Issues=20#70?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/EntireList/EntireList.tsx | 13 ++- client/src/components/Profile/cashModal.tsx | 58 +++++----- .../src/components/Profile/profileModal.tsx | 19 ++-- client/src/hooks/useCash.ts | 100 ++++++++++++++---- client/src/reducer/cash/cashSlice.ts | 17 ++- 5 files changed, 130 insertions(+), 77 deletions(-) diff --git a/client/src/components/EntireList/EntireList.tsx b/client/src/components/EntireList/EntireList.tsx index 74e0fc27..fadb7dbf 100644 --- a/client/src/components/EntireList/EntireList.tsx +++ b/client/src/components/EntireList/EntireList.tsx @@ -3,7 +3,8 @@ import styled from 'styled-components'; import Header from './Header'; import StockItem from './StockItem'; import useCompanyData from '../../hooks/useCompanyData'; -import { useGetCash } from '../../hooks/useCash'; // 훅 가져오기 +import { useSelector } from 'react-redux'; +import { RootState } from '../../store/config'; const EntireList: React.FC = ({ currentListType, onChangeListType }) => { const [isMenuOpen, setMenuOpen] = useState(false); @@ -16,9 +17,9 @@ const EntireList: React.FC = ({ currentListType, onChangeListTy const companiesList = companies || []; // 현금 보유량 가져오기 - const moneyId = localStorage.getItem('moneyId'); - const { data: cashData } = useGetCash(moneyId); - const holdingsAmount = cashData?.data?.money || "0"; + // 현금 보유량 가져오기: Redux store에서 직접 가져옵니다. + const holdingsAmount = useSelector((state: RootState) => state.cash.money) || "0"; + return ( @@ -51,6 +52,8 @@ const EntireList: React.FC = ({ currentListType, onChangeListTy ); }; +export default EntireList; + // Props와 상태에 대한 타입 정의 type EntireListProps = { currentListType: '전체종목' | '관심종목' | '보유종목'; @@ -99,4 +102,4 @@ const StockList = styled.div` overflow-y: auto; /* 세로 스크롤을 활성화합니다 */ `; -export default EntireList; + diff --git a/client/src/components/Profile/cashModal.tsx b/client/src/components/Profile/cashModal.tsx index 5eb9572d..eff9f907 100644 --- a/client/src/components/Profile/cashModal.tsx +++ b/client/src/components/Profile/cashModal.tsx @@ -3,23 +3,24 @@ import styled from 'styled-components'; import { useSelector, useDispatch } from 'react-redux'; import { useCreateCash, useGetCash, useResetCash } from '../../hooks/useCash'; import { RootState } from '../../store/config'; -import { setMoneyId, setMoneyAmount } from '../../reducer/cash/cashSlice'; +import { setCashId, setMoney } from '../../reducer/cash/cashSlice'; -const CashModal: React.FC = ({ onClose }) => { +const CashModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { + // 상태 및 변수 초기화 const titleText = "현금"; const cashCreationPlaceholder = "생성할 현금 입력"; const createCashButtonText = "현금 생성"; const cashInputPlaceholder = "현금 입력"; const resetButtonText = "리셋"; - const refreshButtonText ="새로고침" + const refreshButtonText ="새로고침"; const dispatch = useDispatch(); - const moneyId = useSelector((state: RootState) => state.cash.moneyId); - const moneyAmount = useSelector((state: RootState) => state.cash.moneyAmount) || '0'; - + const cashId = useSelector((state: RootState) => state.cash.cashId); + const money = useSelector((state: RootState) => state.cash.money) || '0'; + const createCashMutation = useCreateCash(); - const { data: cashData, isLoading } = useGetCash(moneyId); + const cashQuery = useGetCash(); const updateCashMutation = useResetCash(); const [cashInput, setCashInput] = useState('0'); @@ -27,47 +28,41 @@ const CashModal: React.FC = ({ onClose }) => { // 현금 정보 재조회 함수 const refreshCashInfo = () => { - // 여기에 현금 정보를 다시 불러오는 로직을 추가합니다. - // 예: useGetCash() hook을 다시 호출한다던지, 특정 상태를 변경하여 리렌더링을 유발하는 등의 방법이 있습니다. + cashQuery.refetch(); // 현금 정보를 다시 가져옵니다. }; - // 현금 생성 및 cashId 전역 저장 + // 현금 생성 및 cashId 전역 저장 함수 const handleCreateCash = () => { - createCashMutation.mutate(initialAmount, { - onSuccess: (data) => { - dispatch(setMoneyId(data.data.moneyId)); - } - }); + createCashMutation.mutate(initialAmount); }; - // 보유 현금량 조회 및 전역 저장 - if (cashData && moneyAmount !== cashData.data.cash) { - dispatch(setMoneyAmount(cashData.data.cash)); + // 보유 현금량 조회 및 전역 저장 함수 + if (cashQuery.data && money !== cashQuery.data.data.cash) { + dispatch(setMoney(cashQuery.data.data.cash)); } -// 현금을 입력한 금액으로 리셋하는 함수 + // 입력한 금액으로 현금 리셋 함수 const handleCashReset = () => { - if (moneyId) { - const numericCashId = parseInt(moneyId, 10); // cashId를 숫자로 변환 - const numericCashAmount =cashInput; // cashInput을 숫자로 변환 - updateCashMutation.mutate({ moneyId: numericCashId, money: numericCashAmount }, { + if (cashId) { + const numericCashAmount = cashInput; // cashInput을 숫자로 변환 + updateCashMutation.mutate({ money: numericCashAmount }, { onSuccess: () => { - dispatch(setMoneyAmount(numericCashAmount)); // 현금 금액을 입력한 금액으로 리셋 + dispatch(setMoney(numericCashAmount)); // 현금 금액을 입력한 금액으로 리셋 + dispatch(setCashId(cashId) ); } }); } else { - console.error("moneyId is null or not a valid number."); + console.error("cashId is null or not a valid number."); } }; - return ( × {titleText} - {/* 현금 생성 입력창 및 버튼 추가 */} + {/* 현금 생성 입력창 및 버튼 */}
= ({ onClose }) => {

- 현재 현금: {isLoading ? 'Loading...' : moneyAmount.toLocaleString()} + 현재 현금: {cashQuery.isLoading ? 'Loading...' : money.toLocaleString()}

{refreshButtonText}
@@ -99,10 +94,9 @@ const CashModal: React.FC = ({ onClose }) => { export default CashModal; -interface CashModalProps { - onClose: () => void; - moneyId: number | null; -} +// interface CashModalProps { +// onClose: () => void; +// } // Styled Components Definitions: diff --git a/client/src/components/Profile/profileModal.tsx b/client/src/components/Profile/profileModal.tsx index f2c03584..62f0af6c 100644 --- a/client/src/components/Profile/profileModal.tsx +++ b/client/src/components/Profile/profileModal.tsx @@ -1,34 +1,29 @@ import React, { useState } from 'react'; import styled from 'styled-components'; -import { useSelector } from 'react-redux'; import MemberInfoModal from './memberInfoModal'; import MemberWithdrawalModal from './memberWithdrawalModal'; import CashModal from './cashModal'; -import { RootState } from '../../store/config'; const ProfileModal: React.FC = ({ onClose }) => { - const memberInfoText = "회원정보"; const cashText = "현금"; const memberWithdrawText = "회원탈퇴"; - const moneyId = useSelector((state: RootState) => state.cash.moneyId); - const [selectedTab, setSelectedTab] = useState(1); // 1: MemberInfo, 2: CashModal, 3: WithdrawalModal + const [selectedTab, setSelectedTab] = useState(1); return ( - - setSelectedTab(1)}>{memberInfoText} - setSelectedTab(2)}>{cashText} - setSelectedTab(3)}>{memberWithdrawText} - + + setSelectedTab(1)}>{memberInfoText} + setSelectedTab(2)}>{cashText} + setSelectedTab(3)}>{memberWithdrawText} + {selectedTab === 1 && } - {selectedTab === 2 && } + {selectedTab === 2 && } {selectedTab === 3 && } - {/* × */} ); diff --git a/client/src/hooks/useCash.ts b/client/src/hooks/useCash.ts index b2544f0e..d72daafe 100644 --- a/client/src/hooks/useCash.ts +++ b/client/src/hooks/useCash.ts @@ -1,5 +1,9 @@ import { useQuery, useMutation } from 'react-query'; -import axios from 'axios'; +import axios, { AxiosError } from 'axios'; +import { useDispatch } from 'react-redux'; +import { setCashId, setMoney } from '../reducer/cash/cashSlice'; +import { useSelector } from 'react-redux'; +import { RootState } from '../store/config'; const BASE_URL = 'http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080'; @@ -12,37 +16,95 @@ const getAuthHeader = () => { }; export const useCreateCash = () => { + const dispatch = useDispatch(); return useMutation((initialAmount: string) => axios.post(`${BASE_URL}/cash`, { "money": initialAmount }, { headers: getAuthHeader() - })); + }), { + onSuccess: (res) => { + // 200번 응답 처리 + dispatch(setCashId(res.data.cashId)); + dispatch(setMoney(res.data.money)); + }, + onError: (error) => { + const axiosError = error as AxiosError; + if (axiosError?.response?.status === 400 || axiosError?.response?.status === 401) { + // 에러 메시지 출력 + const errorMessage = axiosError?.response?.data?.message || 'Unknown error occurred.'; + alert(errorMessage); + } + } + }); } -export const useGetCash = (moneyId: string | null) => { + + +export const useGetCash = () => { + const dispatch = useDispatch(); const queryFn = () => { - if (!moneyId) { - throw new Error("Cash ID is not provided."); - } return axios.get(`${BASE_URL}/cash`, { headers: getAuthHeader() }); }; - const queryResult = useQuery(['money', moneyId], queryFn, { - enabled: !!moneyId, + return useQuery('money', queryFn, { + onSuccess: (res) => { + // 200번 응답 처리 + dispatch(setCashId(res.data.cashId)); + dispatch(setMoney(res.data.money)); + }, + onError: (error) => { + const axiosError = error as AxiosError; + switch (axiosError?.response?.status) { + case 400: + case 401: + case 404: { + // 중괄호 내에서 변수 선언 + const errorMessage = axiosError?.response?.data?.message || 'Unknown error occurred.'; + alert(errorMessage); + break; + } + default: + alert('Unknown error occurred.'); + break; + } + }, + refetchInterval: false, // 자동 재요청 비활성화 + retry: false // 재시도 비활성화 }); - - if (!moneyId) { - return { - ...queryResult, - data: null - }; - } - - return queryResult; } + export const useResetCash = () => { - return useMutation((data: { moneyId: number, money: string }) => axios.patch(`${BASE_URL}/cash/${data.moneyId}`, { "money": data.money }, { + const cashId = useSelector((state: RootState) => state.cash.cashId); // cashId를 전역 상태에서 가져옵니다. + const dispatch = useDispatch(); + + return useMutation((data: { money: string }) => axios.patch(`${BASE_URL}/cash/${cashId}`, { "money": data.money }, { headers: getAuthHeader() - })); + }), { + onSuccess: (data) => { + // 200번 응답 처리 + dispatch(setCashId(data.data.cashId)); + dispatch(setMoney(data.data.money)); + }, + onError: (error) => { + const axiosError = error as AxiosError; + switch (axiosError?.response?.status) { + case 400: + case 401: + case 404: { + const errorMessage = axiosError?.response?.data?.message || 'Unknown error occurred.'; + alert(errorMessage); + break; + } + default: + alert('Unknown error occurred.'); + break; + } + } + }); } + + +interface ErrorResponse { + message: string; +} \ No newline at end of file diff --git a/client/src/reducer/cash/cashSlice.ts b/client/src/reducer/cash/cashSlice.ts index c0966b59..39f78c3e 100644 --- a/client/src/reducer/cash/cashSlice.ts +++ b/client/src/reducer/cash/cashSlice.ts @@ -1,21 +1,20 @@ -// store/cashSlice.ts import { createSlice } from "@reduxjs/toolkit"; const cashSlice = createSlice({ name: "cash", initialState: { - moneyId: null, - moneyAmount: null, + cashId: null, + money: null, }, reducers: { - setMoneyId: (state, action) => { - state.moneyId = action.payload; + setCashId: (state, action) => { + state.cashId = action.payload; }, - setMoneyAmount: (state, action) => { - state.moneyAmount = action.payload; + setMoney: (state, action) => { + state.money = action.payload; }, }, }); -export const { setMoneyId, setMoneyAmount } = cashSlice.actions; -export default cashSlice.reducer; +export const { setCashId, setMoney } = cashSlice.actions; +export default cashSlice.reducer; \ No newline at end of file