From 2d611bc3d8473a36bcdb060a0b0d5c2494ff1909 Mon Sep 17 00:00:00 2001 From: jeongmingong Date: Mon, 8 Apr 2024 17:23:27 +0900 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Feat:=20MyPage=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 107 +++++++++--------- src/components/layout/parts/MainNavBar.tsx | 2 +- src/components/layout/parts/ProfileNavBar.tsx | 59 +++++++++- src/components/my/DeleteAccountBox.tsx | 44 ++++--- src/components/my/EmailBox.tsx | 41 ++++--- src/components/my/NicknameBox.tsx | 64 ++++++++++- src/components/my/PasswordBox.tsx | 28 ++++- src/recoil/user/userAtom.tsx | 6 + src/styles/my/myPage.style.ts | 63 +++++++++-- src/styles/user/AmplifyCustomFields.ts | 10 +- src/styles/user/AuthPage.css | 15 +++ yarn.lock | 2 +- 12 files changed, 328 insertions(+), 113 deletions(-) create mode 100644 src/recoil/user/userAtom.tsx diff --git a/src/App.tsx b/src/App.tsx index a4cef74..0242b54 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import React, { ReactElement, useEffect, useState } from 'react'; import { Navigate, useLocation } from 'react-router-dom'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { getCurrentUser } from 'aws-amplify/auth'; +import { RecoilRoot } from 'recoil'; import MainLayout from './components/layout/MainLayout'; import InviteTeamModal from '@/components/inviteTeam/InviteTeamModal'; import SubLayout from '@/components/layout/PageSubLayout'; @@ -52,82 +53,84 @@ const PrivateRoute: React.FC = ({ children }) => { const App = () => { return ( <> - - - }> + + + + }> + + + + } + > + + + + } + > + + + + } + > + - + } > - + } > - + } > - - - - - } - > - - - - } - > - - - - } - > - }> + }> + + + + } + > + + }> + }> + + }> - + } > - - }> - }> - - }> - - - - } - > - - + + + ); }; diff --git a/src/components/layout/parts/MainNavBar.tsx b/src/components/layout/parts/MainNavBar.tsx index 5e14854..84464de 100644 --- a/src/components/layout/parts/MainNavBar.tsx +++ b/src/components/layout/parts/MainNavBar.tsx @@ -32,7 +32,7 @@ const MainNavBar = () => { } }; - // 로그아웃을 처리 함수 + // 로그아웃 처리 함수 async function handleSignOut() { try { await signOut({ global: true }); diff --git a/src/components/layout/parts/ProfileNavBar.tsx b/src/components/layout/parts/ProfileNavBar.tsx index 4ffd4c5..00f4f0c 100644 --- a/src/components/layout/parts/ProfileNavBar.tsx +++ b/src/components/layout/parts/ProfileNavBar.tsx @@ -1,10 +1,63 @@ +import { useState, useEffect } from 'react'; import { Gear, PersonCircle } from 'react-bootstrap-icons'; +import { useNavigate } from 'react-router-dom'; +import { Button } from '@chakra-ui/react'; +import { getCurrentUser, signOut, fetchUserAttributes } from 'aws-amplify/auth'; +import { useRecoilState } from 'recoil'; import LogoBox from './LogoBox'; import MenuBar from './MenuBar'; import Alarm from '@/components/alarm/Alarm'; +import { userNicknameState } from '@/recoil/user/userAtom'; import * as S from '@/styles/layout/layout.style'; const PageNavBar = () => { + const navigate = useNavigate(); + const [isLoggedIn, setIsLoggedIn] = useState(false); + // const [userNickname, setUserNickname] = useState(null); + const [userNickname, setUserNickname] = useRecoilState(userNicknameState); + + const checkLoginStatus = async () => { + try { + await getCurrentUser(); + setIsLoggedIn(true); + } catch (error) { + setIsLoggedIn(false); + } + }; + + const handleLoginOrLogout = () => { + if (isLoggedIn) { + handleSignOut(); // 로그아웃 처리 함수 호출 + } + }; + + // 로그아웃 처리 함수 + async function handleSignOut() { + try { + await signOut({ global: true }); + setIsLoggedIn(false); // 로그인 상태 업데이트 + navigate('/'); // 로그아웃 후 홈으로 리디이렉션 + } catch (error) { + console.log('로그아웃 에러', error); + } + } + + // 닉네임 관련 + async function handleFetchUserAttributes() { + try { + const userAttributes = await fetchUserAttributes(); + console.log(userAttributes); + setUserNickname(userAttributes.nickname || null); + } catch (err) { + console.log(err); + } + } + + useEffect(() => { + checkLoginStatus(); + handleFetchUserAttributes(); + }, []); + return ( <> @@ -29,7 +82,7 @@ const PageNavBar = () => { }} > -

Clayton Santos

+

{userNickname}

@@ -37,7 +90,9 @@ const PageNavBar = () => { - Logout +
diff --git a/src/components/my/DeleteAccountBox.tsx b/src/components/my/DeleteAccountBox.tsx index 8c97628..516bb76 100644 --- a/src/components/my/DeleteAccountBox.tsx +++ b/src/components/my/DeleteAccountBox.tsx @@ -1,6 +1,6 @@ import { InfoCircle } from 'react-bootstrap-icons'; +import { AccountSettings } from '@aws-amplify/ui-react'; import { - Button, Modal, ModalCloseButton, ModalContent, @@ -9,10 +9,24 @@ import { ModalOverlay, useDisclosure, } from '@chakra-ui/react'; +import { deleteUser } from 'aws-amplify/auth'; import * as S from '@/styles/my/myPage.style'; +import '@/styles/user/AuthPage.css'; const DeleteAccountButton = () => { - const { isOpen, onOpen, onClose } = useDisclosure(); + const { isOpen, onClose } = useDisclosure(); + + const handleSuccess = () => { + alert('성공적으로 탈퇴되었습니다.'); + }; + + async function handleDelete() { + try { + await deleteUser(); + } catch (error) { + console.log(error); + } + } return ( <> @@ -24,23 +38,25 @@ const DeleteAccountButton = () => { 삭제 후 복구 할 수 없습니다. -
- - 계정 삭제 - -
+ + + - 진심이지? + 계정을 삭제하시겠습니까? - - - - + diff --git a/src/components/my/EmailBox.tsx b/src/components/my/EmailBox.tsx index ed3266b..182086b 100644 --- a/src/components/my/EmailBox.tsx +++ b/src/components/my/EmailBox.tsx @@ -1,22 +1,35 @@ -import google from '@/../public/google.png'; -import kakao from '@/../public/kakao.png'; +import { useState, useEffect } from 'react'; +import { IoMailOutline } from 'react-icons/io5'; +import { fetchUserAttributes } from 'aws-amplify/auth'; import * as S from '@/styles/my/myPage.style'; + const EmailBox = () => { + const [userEmail, setUserEmail] = useState(null); + + async function handleFetchUserAttributes() { + try { + const userAttributes = await fetchUserAttributes(); + console.log(userAttributes); + setUserEmail(userAttributes.email || null); + } catch (err) { + console.log(err); + } + } + + useEffect(() => { + handleFetchUserAttributes(); + }, []); + return ( <> - 이메일 + 이메일 - - Clayton@gmail.com - - - - Clayton@gmail.com - - - - Clayton@gmail.com - + + + +
{userEmail}
+
+
); }; diff --git a/src/components/my/NicknameBox.tsx b/src/components/my/NicknameBox.tsx index a095994..d054844 100644 --- a/src/components/my/NicknameBox.tsx +++ b/src/components/my/NicknameBox.tsx @@ -1,15 +1,67 @@ -import { Editable, EditableInput, EditablePreview } from '@chakra-ui/react'; +import { useState, useEffect } from 'react'; +import { Input, Button } from '@aws-amplify/ui-react'; +import { fetchUserAttributes, updateUserAttributes } from 'aws-amplify/auth'; +import { useRecoilState } from 'recoil'; +import { userNicknameState } from '@/recoil/user/userAtom'; import * as S from '@/styles/my/myPage.style'; const NicknameBox = () => { + // const [userNickname, setUserNickname] = useState(null); + const [userNickname, setUserNickname] = useRecoilState(userNicknameState); + const [newNickname, setNewNickname] = useState(''); + + async function handleFetchUserAttributes() { + try { + const userAttributes = await fetchUserAttributes(); + console.log(userAttributes); + setUserNickname(userAttributes.nickname || null); + } catch (err) { + console.log(err); + } + } + + useEffect(() => { + handleFetchUserAttributes(); + }, []); + + async function handleUpdateNicknameAttributes(updatedNickname: string) { + try { + await updateUserAttributes({ + userAttributes: { + nickname: newNickname, + }, + }); + alert('닉네임이 수정되었습니다.'); + setUserNickname(updatedNickname); + setNewNickname(''); + // console.log(updatedNickname); + } catch (error) { + console.log(error); + } + } + const handleNewNicknameChange = (event: React.ChangeEvent) => { + setNewNickname(event.target.value); + }; + return ( <> - 닉네임 + 닉네임 - - - - + + + + + + + + ); }; diff --git a/src/components/my/PasswordBox.tsx b/src/components/my/PasswordBox.tsx index 62222d7..68f366a 100644 --- a/src/components/my/PasswordBox.tsx +++ b/src/components/my/PasswordBox.tsx @@ -1,10 +1,16 @@ -import { Asterisk } from 'react-bootstrap-icons'; -import ChangePWButton from '@/components/my/component/ChangePWButton'; -import CurrentPasswordInput from '@/components/my/component/CurrentPasswordInput'; -import NewPasswordInput from '@/components/my/component/NewPasswordInput'; +// import { Asterisk } from 'react-bootstrap-icons'; +import { AccountSettings } from '@aws-amplify/ui-react'; +// import { updatePassword, type UpdatePasswordInput } from 'aws-amplify/auth'; +// import ChangePWButton from '@/components/my/component/ChangePWButton'; +// import CurrentPasswordInput from '@/components/my/component/CurrentPasswordInput'; +// import NewPasswordInput from '@/components/my/component/NewPasswordInput'; import * as S from '@/styles/my/myPage.style'; const PasswordBox = () => { + const handleSuccess = () => { + alert('비밀번호가 성공적으로 변경되었습니다.'); + }; + return ( <> @@ -13,7 +19,17 @@ const PasswordBox = () => { 비밀번호를 변경하면 이 장치에서는 로그인 상태로 유지되지만 다른 장치에서는 로그아웃될 수 있습니다. - + + + {/*
현재 비밀번호 @@ -29,7 +45,7 @@ const PasswordBox = () => {
-
+
*/}
); diff --git a/src/recoil/user/userAtom.tsx b/src/recoil/user/userAtom.tsx new file mode 100644 index 0000000..d2d14b7 --- /dev/null +++ b/src/recoil/user/userAtom.tsx @@ -0,0 +1,6 @@ +import { atom } from 'recoil'; + +export const userNicknameState = atom({ + key: 'userNicknameState', + default: null, +}); diff --git a/src/styles/my/myPage.style.ts b/src/styles/my/myPage.style.ts index 7304e6c..dd52b8a 100644 --- a/src/styles/my/myPage.style.ts +++ b/src/styles/my/myPage.style.ts @@ -8,11 +8,11 @@ export const ProfileContainer = styled.div` display: flex; width: 100%; background-color: #111b47; - height: 100px; + height: 4rem; color: white; justify-items: center; align-items: center; - font-size: 60px; + font-size: 40px; margin: 10px 0; `; @@ -21,8 +21,10 @@ export const MyPageContainer = styled.div` flex-direction: column; justify-items: center; width: 800px; - background-color: #e6e6e6; - margin: auto 0; + background-color: rgba(251, 251, 251, 1); + /* margin: auto 0; */ + margin-top: 2rem; + margin-bottom: 8rem; border: 1px solid #505f98; border-radius: 5%; padding: 20px 50px; @@ -66,9 +68,33 @@ export const ImageButtonBox = styled.div` margin: 0 auto; `; -export const NicknameInput = styled.input` - margin: 5px 10px; - font-size: 20px; +export const NicknameContainer = styled.div` + display: flex; + flex-direction: column; +`; + +// export const NicknameBox = styled.div` +// margin-top: 1rem; +// margin-bottom: 2rem; +// font-size: 18px; +// border: 1px solid #717171; +// border-radius: 10px; +// background-color: white; +// width: 98%; +// height: 45px; +// display: flex; +// align-items: center; +// padding: 0 1rem; +// `; + +export const NicknameUpdateBox = styled.div` + margin-top: 1rem; + margin-bottom: 2rem; +`; + +export const UpdateButton = styled.div` + display: flex; + justify-content: flex-end; `; export const SubName = styled.h2<{ fontSize: string }>` @@ -77,16 +103,25 @@ export const SubName = styled.h2<{ fontSize: string }>` font-size: ${props => props.fontSize}; `; +export const LoginContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; +`; + export const LoginBox = styled.div<{ background_color: string }>` display: flex; flex-direction: row; + align-items: center; background-color: ${props => props.background_color}; - margin: 5px 0px; + margin-top: 1rem; + margin-bottom: 2rem; border: 1px solid #717171; - width: 80%; - height: 50px; + width: 98%; + height: 45px; border-radius: 45px; - padding: auto 0; + padding: 0 1rem; + /* font-size: 18px; */ `; export const KakaoIcon = styled.img` @@ -108,3 +143,9 @@ export const PWInput = styled.input` margin: 5px 10px; width: 150px; `; + +export const deleteContainer = styled.div` + margin-top: 1rem; + display: flex; + justify-content: flex-end; +`; diff --git a/src/styles/user/AmplifyCustomFields.ts b/src/styles/user/AmplifyCustomFields.ts index 1a965a9..fd8b570 100644 --- a/src/styles/user/AmplifyCustomFields.ts +++ b/src/styles/user/AmplifyCustomFields.ts @@ -20,12 +20,10 @@ const amplifyCustomFields = { label: 'Confirm Password', placeholder: '비밀번호를 다시 한 번 더 입력해주세요.', }, - // 'custom:customField': { - // label: 'Nickname', - // placeholder: '닉네임을 입력해주세요.', - // isRequired: true, - // order: 1, - // }, + nickname: { + order: 1, + placeholder: '사용할 닉네임을 입력해주세요.', + }, }, forgotPassword: { username: { diff --git a/src/styles/user/AuthPage.css b/src/styles/user/AuthPage.css index 1229311..4bf31a1 100644 --- a/src/styles/user/AuthPage.css +++ b/src/styles/user/AuthPage.css @@ -15,3 +15,18 @@ .amplify-button--small { color: var(--amplify-colors-blue-90); } + +/* MyPage 관련 */ +.amplify-card { + background-color: var(--amplify-internal-button-disabled-background-color); +} + +.amplify-card .amplify-flex { + display: flex; + align-items: flex-end; +} + +.amplify-input--quiet { + margin-bottom: 1rem; + /* width: 85%; */ +} diff --git a/yarn.lock b/yarn.lock index ff0f5e9..cb50db0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9716,7 +9716,7 @@ rechoir@^0.8.0: recoil@^0.7.7: version "0.7.7" - resolved "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz" + resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.7.7.tgz#c5f2c843224384c9c09e4a62c060fb4c1454dc8e" integrity sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ== dependencies: hamt_plus "1.0.2"