Skip to content

Commit

Permalink
회원정보 전송 및 화면에 구현
Browse files Browse the repository at this point in the history
로그인 시 회원 Id를 이용하여 회원정보를 hook에 저장
회원정보 조회 시 hook에 저장된 회원 정보를 불러옴
회원정보 페이지 구현
Issues #70
  • Loading branch information
김병현 authored and 김병현 committed Sep 10, 2023
1 parent 2af19ec commit 770d5be
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 61 deletions.
20 changes: 15 additions & 5 deletions client/src/components/Headers/LoginHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@

import React, { useState } from 'react';
import styled from 'styled-components';
import StockHolmLogo from "../../asset/images/StockHolmLogo.png";
import SampleProfile from "../../asset/images/ProfileSample.png";
import { useNavigate } from "react-router-dom";
import AlarmImage from "../../asset/images/alarm.png";
import ProfileModal from "../Profile/profileModal";


// 로그인 상태일 때의 헤더 컴포넌트
const LoginHeader: React.FC<LoginHeaderProps> = ({ onLogoutClick }) => {
const [isProfileModalOpen, setProfileModalOpen] = useState(false); // 프로필 모달 상태
const [searchValue, setSearchValue] = useState<string>(''); // 검색어 상태
const navigate = useNavigate(); // 페이지 이동 함수

Expand All @@ -17,6 +20,15 @@ const LoginHeader: React.FC<LoginHeaderProps> = ({ onLogoutClick }) => {
};

const logoutText = "로그아웃";
// 프로필 모달 열기 함수
const handleProfileOpen = () => {
setProfileModalOpen(true);
};

// 프로필 모달 닫기 함수
const handleProfileClose = () => {
setProfileModalOpen(false);
};

// 로고 클릭 처리 함수
const handleLogoClick = () => {
Expand All @@ -33,9 +45,10 @@ const LoginHeader: React.FC<LoginHeaderProps> = ({ onLogoutClick }) => {
<NotificationButton>
<img src={AlarmImage} alt="Notification" />
</NotificationButton>
<ProfileButton>
<ProfileButton onClick={handleProfileOpen}>
<ProfileImage src={SampleProfile} />
</ProfileButton>
{isProfileModalOpen && <ProfileModal onClose={handleProfileClose} />}
<LogoutButton onClick={onLogoutClick}>{logoutText}</LogoutButton>
</UserActions>
</HeaderContainer>
Expand All @@ -47,6 +60,7 @@ export default LoginHeader;
// 로그아웃 클릭 이벤트 타입 정의
interface LoginHeaderProps {
onLogoutClick: () => void;
onProfileClick: () => void;
}

// 헤더 컨테이너 스타일
Expand Down Expand Up @@ -140,7 +154,3 @@ const LogoutButton = styled.button`
`;






49 changes: 36 additions & 13 deletions client/src/components/Logins/LoginConfirmatationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
// LoginConfirmationModal.tsx
import React from 'react';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { useSelector, useDispatch } from 'react-redux';
import { setMemberInfo } from '../../reducer/member/memberInfoSlice.ts';
import useGetMemberInfo from '../../hooks/useGetmemberInfo.ts';
import { RootState } from '../../reducer/member/rootReducer';

const LoginConfirmationModal: React.FC<LoginConfirmationProps> = ({ onClose }) => {
const messageText = "로그인이 성공적으로 완료되었습니다!";
const confirmText = "확인"
const messageText = "로그인이 성공적으로 완료되었습니다!";
const confirmText = "확인"
const loadingText = "로딩 중...";
const errorText = "데이터를 가져오는 중 문제가 발생했습니다.";

return (
<ModalBackground>
<ModalContainer>
<Message>{messageText}</Message>
<ConfirmButton onClick={onClose}>{confirmText}</ConfirmButton>
</ModalContainer>
</ModalBackground>
);
const memberId: number | null = useSelector((state: RootState) => state.login.memberId);

const { data, error, isLoading } = useGetMemberInfo(memberId);

const dispatch = useDispatch();

useEffect(() => {
if (data) {
dispatch(setMemberInfo(data));
}
}, [data, dispatch]);

return (
<ModalBackground>
<ModalContainer>
{isLoading ? (
<Message>{loadingText}</Message>
) : error ? (
<Message>{errorText}</Message>
) : (
<Message>{messageText}</Message>
)}
<ConfirmButton onClick={onClose}>{confirmText}</ConfirmButton>
</ModalContainer>
</ModalBackground>
);
};

export default LoginConfirmationModal;

interface LoginConfirmationProps {
onClose: () => void;
onClose: () => void;
}

// ... Styled Components for ModalBackground, ModalContainer, Message, ConfirmButton ...
Expand Down
40 changes: 14 additions & 26 deletions client/src/components/Profile/memberInfoModal.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import axios from 'axios';
import React from 'react';
import styled from 'styled-components';
import { useSelector } from 'react-redux';
import useGetMemberInfo from '../../hooks/useGetmemberInfo';
import { RootState } from '../../store/config';

const MemberInfoModal: React.FC<MemberInfoModalProps> = ({ onClose, memberId }) => {
const [memberInfo, setMemberInfo] = useState<MemberData | null>(null); // Use the MemberData type
const MemberInfoModal: React.FC<MemberInfoModalProps> = ({ onClose }) => {
// loginSlice에서 memberId 값을 가져옵니다.
const memberId = useSelector((state: RootState) => state.login.memberId);

// memberId 값을 useGetMemberInfo 훅에 전달하여 회원 정보를 가져옵니다.
const { data: memberInfo } = useGetMemberInfo(memberId);

const titleText = "회원정보";
const loadingText = "Loading...";
const nameText = "이름: ";
const emailText = "이메일: ";
const createdAtText = "회원 가입 일시: ";
const memberIdText = "회원 ID: ";

useEffect(() => {
// Fetch member info when the modal is opened
axios.get<MemberData>(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com/members/${memberId}`)
.then(response => {
setMemberInfo(response.data);
})
.catch(error => {
console.error("Error fetching member info:", error);
});
}, [memberId]);

return (
<ModalBackground>
<ModalContainer>
<CloseButton onClick={onClose}>&times;</CloseButton>
<Title>{titleText}</Title>
{memberInfo ? (
<div>
{/* Display member information */}
<p>{memberIdText}{memberInfo.memberId}</p>
<p>{nameText}{memberInfo.name}</p>
<p>{emailText}{memberInfo.email}</p>
<p>{createdAtText}{memberInfo.createdAt}</p>
</div>
) : (
<p>{loadingText}</p>
<div>Data not available</div>
)}
</ModalContainer>
</ModalBackground>
Expand All @@ -46,15 +39,10 @@ const MemberInfoModal: React.FC<MemberInfoModalProps> = ({ onClose, memberId })

interface MemberInfoModalProps {
onClose: () => void;
memberId: string;
}
interface MemberData {
memberId: number;
email: string;
name: string;
createdAt: string;
}



// Styled Components Definitions:

const ModalBackground = styled.div`
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Profile/profileModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import MemberInfoModal from './memberInfoModal'; // 경로는 실제 파일 위치에 따라 수정해야 합니다.

const ProfileModal: React.FC<ProfileModalProps> = ({ onClose }) => {
const [selectedTab, setSelectedTab] = useState<number>(1);
Expand All @@ -14,12 +15,11 @@ const ProfileModal: React.FC<ProfileModalProps> = ({ onClose }) => {
<CloseButton onClick={onClose}>&times;</CloseButton>
<Tabs>
<TabButton active={selectedTab === 1} onClick={() => handleTabChange(1)}>회원정보</TabButton>

<TabButton active={selectedTab === 2} onClick={() => handleTabChange(2)}>현금</TabButton>
<TabButton active={selectedTab === 3} onClick={() => handleTabChange(3)}>회원탈퇴</TabButton>
</Tabs>
<TabContent>
{selectedTab === 1 && <div>회원정보 Content</div>}
{selectedTab === 1 && <MemberInfoModal onClose={onClose}/>}
{selectedTab === 2 && <div>현금 Content</div>}
{selectedTab === 3 && <div>회원탈퇴 Content</div>}
</TabContent>
Expand Down
16 changes: 16 additions & 0 deletions client/src/hooks/useGetMemberInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useQuery } from 'react-query';
import axios from 'axios';

function useGetMemberInfo(memberId: number | null) {
return useQuery(['member', memberId], async () => {
const response = await axios.get(`http://ec2-13-125-246-160.ap-northeast-2.compute.amazonaws.com:8080/members/${memberId}`);

if (response.status === 200) {
return response.data;
} else {
throw new Error('Failed to fetch member data');
}
});
}

export default useGetMemberInfo;
14 changes: 11 additions & 3 deletions client/src/page/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import CompareChartSection from "../components/CompareChartSection/Index";
import StockOrderSection from "../components/StockOrderSection/Index";
import Welcome from "../components/Signups/Welcome";

import ProfileModal from "../components/Profile/profileModal";

import { StateProps } from "../models/stateProps";

import { TabContainerPage } from "./TabPages/TabContainerPage";
Expand All @@ -29,6 +31,7 @@ const MainPage = () => {
const [isEmailSignupModalOpen, setEmailSignupModalOpen] = useState(false);
const [userEmail, setUserEmail] = useState("");
const [isWelcomeModalOpen, setWelcomeModalOpen] = useState(false);
const [isProfileModalOpen, setProfileModalOpen] = useState(false); //프로필 모달 보이기/숨기기

const openOAuthModal = useCallback(() => {
setOAuthModalOpen(true);
Expand Down Expand Up @@ -91,7 +94,10 @@ const MainPage = () => {

const [isLoggedIn, setIsLoggedIn] = useState(false); // 로그인 상태 관리


//프로필 모달 열고닫는 매커니즘
const openProfileModal = useCallback(() => {
setProfileModalOpen(true);
}, []);

const [isLoginConfirmationModalOpen, setLoginConfirmationModalOpen] = useState(false);

Expand All @@ -117,7 +123,7 @@ const MainPage = () => {

return (
<Container>
{isLoggedIn ? <LoginHeader onLogoutClick={handleLogout} /> : <LogoutHeader onLoginClick={openOAuthModal} />}
{isLoggedIn ? <LoginHeader onLogoutClick={handleLogout} onProfileClick={openProfileModal} /> : <LogoutHeader onLoginClick={openOAuthModal} />}
<Main>
<CompareChartSection />
{!expandScreen.left && (
Expand Down Expand Up @@ -152,7 +158,9 @@ const MainPage = () => {
closeWelcomeModal();
}}
/>
)}
)}
{isProfileModalOpen && <ProfileModal onClose={() => setProfileModalOpen(false)} />} //프로필 모달 컴포넌트 렌더링

</Container>
);
};
Expand Down
26 changes: 14 additions & 12 deletions client/src/reducer/member/memberInfoSlice.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// memberInfoSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { createSlice, PayloadAction} from '@reduxjs/toolkit';

interface MemberInfo {
memberId: number;
email: string;
name: string;
password: string;
confirmPassword: string;
createdAt: string;
}

interface MemberInfoState {
Expand All @@ -20,16 +20,18 @@ const initialState: MemberInfoState = {
};

const memberInfoSlice = createSlice({
name: 'memberInfo',
initialState,
reducers: {
setMemberInfo: (state, action: PayloadAction<MemberInfo>) => {
state.memberInfo = action.payload;
name: 'memberInfo',
initialState,
reducers: {
setMemberInfo: (state, action: PayloadAction<MemberInfo>) => {
state.memberInfo = action.payload;
},
setEmailForVerification: (state, action: PayloadAction<string>) => {
state.emailForVerification = action.payload;
},
},
setEmailForVerification: (state, action: PayloadAction<string>) => {
state.emailForVerification = action.payload; // 액션 추가
},
},


});

export const { setMemberInfo, setEmailForVerification } = memberInfoSlice.actions;
Expand Down
11 changes: 11 additions & 0 deletions client/src/reducer/member/rootReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { combineReducers } from '@reduxjs/toolkit';
import loginReducer from './loginSlice';
import memberInfoReducer from './memberInfoSlice';

const rootReducer = combineReducers({
login: loginReducer,
memberInfo: memberInfoReducer,

});

export type RootState = ReturnType<typeof rootReducer>;
2 changes: 2 additions & 0 deletions client/src/store/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ const store = configureStore({
});

export default store;

export type RootState = ReturnType<typeof store.getState>;

0 comments on commit 770d5be

Please sign in to comment.