diff --git a/client/src/components/Logins/GoogleSignin.tsx b/client/src/components/Logins/GoogleSignin.tsx index b3a89c25..8cce7821 100644 --- a/client/src/components/Logins/GoogleSignin.tsx +++ b/client/src/components/Logins/GoogleSignin.tsx @@ -3,7 +3,7 @@ import { GoogleOAuthProvider, GoogleLogin, useGoogleOneTapLogin } from "@react-o import { useDispatch } from "react-redux"; import { setLoginState } from "../../reducer/member/loginSlice"; -const GoogleSignInComponent: React.FC = () => { +const GoogleSignIn: React.FC = () => { const dispatch = useDispatch(); // Redux의 dispatch 함수를 사용하기 위해 가져옵니다. // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -37,4 +37,4 @@ const GoogleSignInComponent: React.FC = () => { ); }; -export default GoogleSignInComponent; +export default GoogleSignIn; diff --git a/client/src/components/Logins/OAuthLogin.tsx b/client/src/components/Logins/OAuthLogin.tsx index 75ae5a89..9298f856 100644 --- a/client/src/components/Logins/OAuthLogin.tsx +++ b/client/src/components/Logins/OAuthLogin.tsx @@ -2,7 +2,7 @@ import React from 'react'; import styled from 'styled-components'; import kakaoLogo from '../../asset/images/KakaoLogo.svg'; import axios from 'axios'; - +// import { GoogleOAuthProvider, GoogleLogin, googleLogout } from '@react-oauth/google'; const OAuthLoginModal: React.FC = ({ onClose, onEmailLoginClick, onEmailSignupClick }) => { const titleText = "로그인"; @@ -12,7 +12,9 @@ const OAuthLoginModal: React.FC = ({ onClose, onEmailLoginClick const emailLoginText = "이메일로 로그인"; const emailSignupText = "이메일로 회원가입"; - + // const handleGoogleLogout = async () => { + // googleLogout(); + // } const handleKakaoLogin = async () => { try { @@ -33,7 +35,16 @@ const OAuthLoginModal: React.FC = ({ onClose, onEmailLoginClick × {titleText} - + {/* + { + console.log(credentialResponse); + }} + onError={() => { + console.log('Login Failed'); + }} + />; + ; */} {kakaoLoginText} @@ -101,6 +112,7 @@ const OrText = styled.span` `; + const KakaoButton = styled.button` margin: 10px 0; padding: 10px 20px; diff --git a/client/src/components/Profile/cashModal.tsx b/client/src/components/Profile/cashModal.tsx index 02195472..c2ecee2b 100644 --- a/client/src/components/Profile/cashModal.tsx +++ b/client/src/components/Profile/cashModal.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { useSelector, useDispatch } from 'react-redux'; import { useCreateCash, useGetCash, useResetCash } from '../../hooks/useCash'; import { RootState } from '../../store/config'; -import { setCashId, setCashAmount } from '../../reducer/cash/cashSlice'; +import { setMoneyId, setMoneyAmount } from '../../reducer/cash/cashSlice'; const CashModal: React.FC = ({ onClose }) => { @@ -14,42 +14,42 @@ const CashModal: React.FC = ({ onClose }) => { const resetButtonText = "리셋"; const dispatch = useDispatch(); - const cashId = useSelector((state: RootState) => state.cash.cashId); - const cashAmount = useSelector((state: RootState) => state.cash.cashAmount) || 0; + const moneyId = useSelector((state: RootState) => state.cash.moneyId); + const moneyAmount = useSelector((state: RootState) => state.cash.moneyAmount) || '0'; const createCashMutation = useCreateCash(); - const { data: cashData, isLoading } = useGetCash(cashId); + const { data: cashData, isLoading } = useGetCash(moneyId); const updateCashMutation = useResetCash(); - const [cashInput, setCashInput] = useState(''); - const [initialAmount, setInitialAmount] = useState(0); // 현금 생성을 위한 상태 변수 + const [cashInput, setCashInput] = useState('0'); + const [initialAmount, setInitialAmount] = useState('0'); // 현금 생성을 위한 상태 변수 // 현금 생성 및 cashId 전역 저장 const handleCreateCash = () => { createCashMutation.mutate(initialAmount, { onSuccess: (data) => { - dispatch(setCashId(data.data.cashId)); + dispatch(setMoneyId(data.data.moneyId)); } }); }; // 보유 현금량 조회 및 전역 저장 - if (cashData && cashAmount !== cashData.data.cash) { - dispatch(setCashAmount(cashData.data.cash)); + if (cashData && moneyAmount !== cashData.data.cash) { + dispatch(setMoneyAmount(cashData.data.cash)); } // 현금을 입력한 금액으로 리셋하는 함수 const handleCashReset = () => { - if (cashId) { - const numericCashId = parseInt(cashId, 10); // cashId를 숫자로 변환 - const numericCashAmount = Number(cashInput); // cashInput을 숫자로 변환 - updateCashMutation.mutate({ cashId: numericCashId, cashAmount: numericCashAmount }, { + if (moneyId) { + const numericCashId = parseInt(moneyId, 10); // cashId를 숫자로 변환 + const numericCashAmount =cashInput; // cashInput을 숫자로 변환 + updateCashMutation.mutate({ moneyId: numericCashId, money: numericCashAmount }, { onSuccess: () => { - dispatch(setCashAmount(numericCashAmount)); // 현금 금액을 입력한 금액으로 리셋 + dispatch(setMoneyAmount(numericCashAmount)); // 현금 금액을 입력한 금액으로 리셋 } }); } else { - console.error("cashId is null or not a valid number."); + console.error("moneyId is null or not a valid number."); } }; @@ -63,18 +63,18 @@ const CashModal: React.FC = ({ onClose }) => { {/* 현금 생성 입력창 및 버튼 추가 */}
setInitialAmount(Number(e.target.value))} + onChange={e => setInitialAmount(e.target.value)} placeholder={cashCreationPlaceholder} /> {createCashButtonText}
-

현재 현금: {isLoading ? 'Loading...' : cashAmount.toLocaleString()}

+

현재 현금: {isLoading ? 'Loading...' : moneyAmount.toLocaleString()}

setCashInput(e.target.value)} placeholder={cashInputPlaceholder} @@ -88,7 +88,7 @@ const CashModal: React.FC = ({ onClose }) => { interface CashModalProps { onClose: () => void; - cashId: string | null; + moneyId: number | null; } // Styled Components Definitions: @@ -106,6 +106,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + z-index: 11; position: relative; background-color: white; padding: 20px; diff --git a/client/src/components/Profile/memberInfoModal.tsx b/client/src/components/Profile/memberInfoModal.tsx index 787c3521..8162766c 100644 --- a/client/src/components/Profile/memberInfoModal.tsx +++ b/client/src/components/Profile/memberInfoModal.tsx @@ -52,6 +52,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + z-index: 11; position: relative; background-color: white; padding: 20px; diff --git a/client/src/components/Profile/memberWithdrawalModal.tsx b/client/src/components/Profile/memberWithdrawalModal.tsx index 2d141f07..f1c66353 100644 --- a/client/src/components/Profile/memberWithdrawalModal.tsx +++ b/client/src/components/Profile/memberWithdrawalModal.tsx @@ -57,6 +57,7 @@ const ModalBackground = styled.div` `; const ModalContainer = styled.div` + z-index: 11; position: relative; background-color: white; padding: 20px; diff --git a/client/src/components/Profile/profileModal.tsx b/client/src/components/Profile/profileModal.tsx index e4c81231..1f339f9d 100644 --- a/client/src/components/Profile/profileModal.tsx +++ b/client/src/components/Profile/profileModal.tsx @@ -10,41 +10,37 @@ const ProfileModal: React.FC = ({ onClose }) => { const memberInfoText = "회원정보"; const cashText = "현금"; - const memberWithdrawText = "회원탈퇴" - const [selectedTab, setSelectedTab] = useState(1); - const cashId = useSelector((state: RootState) => state.cash.cashId); // Get cashId from Redux store + const memberWithdrawText = "회원탈퇴"; + const moneyId = useSelector((state: RootState) => state.cash.moneyId); - const handleTabChange = (tabNumber: number) => { - setSelectedTab(tabNumber); - }; + const [selectedTab, setSelectedTab] = useState(1); // 1: MemberInfo, 2: CashModal, 3: WithdrawalModal return ( - × - handleTabChange(1)}>{memberInfoText} - handleTabChange(2)}>{cashText} - handleTabChange(3)}>{memberWithdrawText} + setSelectedTab(1)}>{memberInfoText} + setSelectedTab(2)}>{cashText} + setSelectedTab(3)}>{memberWithdrawText} - {selectedTab === 1 && } - {selectedTab === 2 && } - {selectedTab === 3 && } + {selectedTab === 1 && } + {selectedTab === 2 && } + {selectedTab === 3 && } + {/* × */} ); -} +}; interface ProfileModalProps { onClose: () => void; } - // 모달 배경 스타일 const ModalBackground = styled.div` - z-index:10; + z-index: 1000; display: flex; justify-content: center; align-items: center; @@ -56,53 +52,58 @@ const ModalBackground = styled.div` background-color: rgba(0, 0, 0, 0.5); `; -// 모달 컨테이너 스타일 const ModalContainer = styled.div` - z-index: 11; + z-index: 1001; position: relative; - background-color: white; padding: 20px; width: 400px; border-radius: 10px; display: flex; flex-direction: column; align-items: center; + background-color: transparent; // 배경색을 투명하게 설정 + border: none; // 테두리를 없앱니다. `; + const Tabs = styled.div` display: flex; justify-content: space-between; width: 100%; margin-bottom: 20px; + z-index: 1002; // 이 값을 추가하여 Tabs를 최상위로 올립니다. `; -// 모달 닫기 버튼 스타일 -const CloseButton = styled.button` - position: absolute; - top: 10px; - right: 10px; - background: #FFFFFF; - border: 1px solid lightgray; - font-size: 1.5rem; - cursor: pointer; -`; +// // 모달 닫기 버튼 스타일 +// const CloseButton = styled.button` +// position: absolute; +// top: 10px; +// right: 10px; +// background: #FFFFFF; +// border: 1px solid lightgray; +// font-size: 1.5rem; +// cursor: pointer; +// `; -interface TabButtonProps { - active?: boolean; -} - -const TabButton = styled.button` +const TabButton = styled.button` flex: 1; padding: 10px; border: 1px solid lightgray; border-radius: 5px; cursor: pointer; - background-color: ${({ active }) => (active ? 'darkslategray' : '#FFFFFF')}; - color: ${({ active }) => (active ? '#FFFFFF' : 'darkslategray')}; + background-color: #FFFFFF; + color: darkslategray; `; const TabContent = styled.div` width: 100%; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + overflow-y: auto; + position: relative; + min-height: 200px; `; - -export default ProfileModal; \ No newline at end of file +export default ProfileModal; diff --git a/client/src/hooks/useCash.ts b/client/src/hooks/useCash.ts index 660422f8..6f2cff81 100644 --- a/client/src/hooks/useCash.ts +++ b/client/src/hooks/useCash.ts @@ -1,36 +1,37 @@ -// hooks/useCash.ts import { useQuery, useMutation } from 'react-query'; import axios from 'axios'; +const BASE_URL = 'http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080'; + const getAuthHeader = () => { const authToken = localStorage.getItem('authToken'); return { 'Authorization': `${authToken}` }; + }; export const useCreateCash = () => { - return useMutation((initialAmount: number) => axios.post('http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com/cash', { cash: initialAmount }, { + return useMutation((initialAmount: string) => axios.post(`${BASE_URL}/cash`, { "money": initialAmount }, { headers: getAuthHeader() })); - } -export const useGetCash = (cashId: string | null) => { +export const useGetCash = (moneyId: string | null) => { const queryFn = () => { - if (!cashId) { + if (!moneyId) { throw new Error("Cash ID is not provided."); } - return axios.get(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com/cash/${cashId}`, { + return axios.get(`${BASE_URL}/cash`, { headers: getAuthHeader() }); }; - const queryResult = useQuery(['cash', cashId], queryFn, { - enabled: !!cashId, + const queryResult = useQuery(['money', moneyId], queryFn, { + enabled: !!moneyId, }); - if (!cashId) { + if (!moneyId) { return { ...queryResult, data: null @@ -41,7 +42,7 @@ export const useGetCash = (cashId: string | null) => { } export const useResetCash = () => { - return useMutation((data: { cashId: number, cashAmount: number }) => axios.patch(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com/cash/${data.cashId}`, { cash: data.cashAmount }, { + return useMutation((data: { moneyId: number, money: string }) => axios.patch(`${BASE_URL}/cash/${data.moneyId}`, { "money": data.money }, { headers: getAuthHeader() })); } diff --git a/client/src/page/MainPage.tsx b/client/src/page/MainPage.tsx index c5814360..a9e4e784 100644 --- a/client/src/page/MainPage.tsx +++ b/client/src/page/MainPage.tsx @@ -33,6 +33,7 @@ const MainPage = () => { const [isWelcomeModalOpen, setWelcomeModalOpen] = useState(false); const [isProfileModalOpen, setProfileModalOpen] = useState(false); //프로필 모달 보이기/숨기기 + const openOAuthModal = useCallback(() => { setOAuthModalOpen(true); }, []); @@ -95,17 +96,20 @@ const MainPage = () => { // 🔴 로그인 지역 상태 제거 → 전역 상태로 대체 (지역 상태 관련된 코드 싹 다 지워야함... -> 전역 상태 만들었으니 전역 상태로 활용) const dispatch = useDispatch(); const isLogin = useSelector((state: StateProps) => state.login); - const [isLoggedIn, setIsLoggedIn] = useState(false); // 로그인 상태 관리 - // 🔴 새로고침 되면 로그인 해제되면서 액세스 토큰도 같이 삭제됨 + // 🔴 페이지 로드 시 로컬 스토리지의 토큰을 기반으로 로그인 상태를 확인합니다. useEffect(() => { - // const authToken = localStorage.getItem("authToken"); + const authToken = localStorage.getItem("authToken"); + if (authToken !== null) { + dispatch(setLoginState()); + } + },); - // if (authToken !== null) { - // dispatch(setLoginState()); - // } + // 🔴 로그아웃 시 로컬스토리지에 있는 Auth 토큰 제거 + const handleLogout = () => { + dispatch(setLogoutState()); localStorage.removeItem("authToken"); - }, []); + }; //프로필 모달 열고닫는 매커니즘 const openProfileModal = useCallback(() => { @@ -117,11 +121,12 @@ const MainPage = () => { const handleLogin = () => { closeEmailLoginModal(); setLoginConfirmationModalOpen(true); + dispatch(setLoginState()); }; + const handleLoginConfirmationClose = () => { setLoginConfirmationModalOpen(false); - setIsLoggedIn(true); }; const [selectedMenu, setSelectedMenu] = useState<"관심목록" | "투자목록">("투자목록"); // Default menu is 관심목록 @@ -130,11 +135,7 @@ const MainPage = () => { setSelectedMenu(menu); }; - // 🔴 로그 아웃 시 로컬데이터 토큰 제거 - const handleLogout = () => { - dispatch(setLogoutState()); - localStorage.removeItem("authToken"); - }; + return ( diff --git a/client/src/reducer/cash/cashSlice.ts b/client/src/reducer/cash/cashSlice.ts index f141e507..919dd987 100644 --- a/client/src/reducer/cash/cashSlice.ts +++ b/client/src/reducer/cash/cashSlice.ts @@ -4,18 +4,18 @@ import { createSlice } from '@reduxjs/toolkit'; const cashSlice = createSlice({ name: 'cash', initialState: { - cashId: null, - cashAmount: null, + moneyId: null, + moneyAmount: null, }, reducers: { - setCashId: (state, action) => { - state.cashId = action.payload; + setMoneyId: (state, action) => { + state.moneyId = action.payload; }, - setCashAmount: (state, action) => { - state.cashAmount = action.payload; + setMoneyAmount: (state, action) => { + state.moneyAmount = action.payload; }, }, }); -export const { setCashId, setCashAmount } = cashSlice.actions; +export const { setMoneyId, setMoneyAmount } = cashSlice.actions; export default cashSlice.reducer; \ No newline at end of file