From 1724ae305fd91993dd1ce7ee1d0eb81c2148c6ac Mon Sep 17 00:00:00 2001 From: G-hoon Date: Tue, 5 Nov 2024 02:05:52 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20mypage=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/nickname.ts | 19 +++++++++ src/assets/icons/arrow-small-right.svg | 3 ++ src/components/Modal/Modals.tsx | 6 ++- src/components/Modal/NickNameModal.tsx | 55 ++++++++++++++++++++++++++ src/components/SideNav.tsx | 20 ++++++---- src/constants/routes.json | 3 +- src/contexts/ModalsContext.ts | 2 +- src/pages/MyPage.tsx | 46 +++++++++++++++++++++ src/routes/Router.tsx | 2 + src/store/AuthStore.ts | 5 ++- 10 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 src/api/nickname.ts create mode 100644 src/assets/icons/arrow-small-right.svg create mode 100644 src/components/Modal/NickNameModal.tsx create mode 100644 src/pages/MyPage.tsx diff --git a/src/api/nickname.ts b/src/api/nickname.ts new file mode 100644 index 0000000..179cc42 --- /dev/null +++ b/src/api/nickname.ts @@ -0,0 +1,19 @@ +import axiosInstance from "./axiosInstance" + +export interface NickNameModificationResData { + data: { + id: 0 + nickname: "string" + } +} + +export const modifyNickName = async (uid: number, newNickName: string): Promise => { + try { + const res = await axiosInstance.put(`/users/${uid}/nickname`, { + nickname: newNickName, + }) + return res.data + } catch (e) { + throw e + } +} diff --git a/src/assets/icons/arrow-small-right.svg b/src/assets/icons/arrow-small-right.svg new file mode 100644 index 0000000..bb2df7c --- /dev/null +++ b/src/assets/icons/arrow-small-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Modal/Modals.tsx b/src/components/Modal/Modals.tsx index 0719b29..030bc95 100644 --- a/src/components/Modal/Modals.tsx +++ b/src/components/Modal/Modals.tsx @@ -8,6 +8,7 @@ import JoinCrewModal from "./JoinCrewModal" import ReportModal from "./ReportModal" import ToWithdrawModal from "./ToWithdrawModal" import WithdrawCrewModal from "./WithdrawCrewModal" +import NickNameModal from "./NickNameModal" export const modals = { createCrewModal: CreateCrewModal, @@ -17,6 +18,7 @@ export const modals = { ToWithdrawModal: ToWithdrawModal, postureGuideModal: GoodPostureGuidePopupModal, reportModal: ReportModal, + nickNameModal: NickNameModal, } const Modals = (): React.ReactNode => { @@ -45,9 +47,9 @@ const Modals = (): React.ReactNode => { close(Component) } - const handleSubmit = async (): Promise => { + const handleSubmit = async (value?: any): Promise => { if (typeof onSubmit === "function") { - await onSubmit() + await onSubmit(value) } handleClose() } diff --git a/src/components/Modal/NickNameModal.tsx b/src/components/Modal/NickNameModal.tsx new file mode 100644 index 0000000..a7a0813 --- /dev/null +++ b/src/components/Modal/NickNameModal.tsx @@ -0,0 +1,55 @@ +import { ModalProps } from "@/contexts/ModalsContext" +import ModalContainer from "@components/ModalContainer" +import { useState } from "react" + +const NickNameModal = (props: ModalProps & { id: string }): React.ReactElement => { + const { onClose, onSubmit } = props + const [nickName, setNickName] = useState("") + + const onClickModifyNickNameButton = () => { + if (nickName && nickName.length <= 200) { + onSubmit?.(nickName) + } + } + + return ( + +
+ {/* header */} +
+
닉네임
+
+ +
+ 200 + ? "border-red-500 focus:border-red-500 focus:ring-red-200" + : "focus:border-blue-500 focus:ring-blue-200" + }`} + placeholder="닉네임을 입력해 주세요." + onChange={(e) => setNickName(e.target.value)} + /> +
+ {nickName.length > 200 && ( + 닉네임은 200자를 초과할 수 없어요. + )} +
+
+ + {/* button */} +
+ +
+
+
+ ) +} + +export default NickNameModal diff --git a/src/components/SideNav.tsx b/src/components/SideNav.tsx index 0d3e52b..59ec856 100644 --- a/src/components/SideNav.tsx +++ b/src/components/SideNav.tsx @@ -5,10 +5,12 @@ import LogoImage from "@assets/icons/side-nav-logo.svg?react" import AnalysisIcon from "@assets/icons/side-nav-analysis-icon.svg?react" import CrewIcon from "@assets/icons/side-nav-crew-icon.svg?react" import MonitoringIcon from "@assets/icons/side-nav-monitor-icon.svg?react" +import RightSmallArrow from "@assets/icons/arrow-small-right.svg?react" import { useMemo } from "react" import { Link, useLocation, useNavigate } from "react-router-dom" import { useModals } from "@/hooks/useModals" import { modals } from "./Modal/Modals" +import RoutePath from "@/constants/routes.json" const navItems = [ { @@ -86,12 +88,14 @@ export default function SideNav(): React.ReactElement { {/* User Info */} -
-
바른자세 똑딱똑딱
-
- {nickname} - -
+
+
바른자세 똑딱똑딱
+ + + {nickname} + + +
{/* Navigation Links */} @@ -100,7 +104,7 @@ export default function SideNav(): React.ReactElement { {navItems.map(({ icon: Icon, label, link }) => { const isActive = location.pathname.includes(link) return ( -
  • +
  • {label} @@ -126,7 +130,7 @@ export default function SideNav(): React.ReactElement {
  • {/* Footer Text */} -
    +
    © 2024 주인공.
    All rights reserved. diff --git a/src/constants/routes.json b/src/constants/routes.json index 805e521..5d7834e 100644 --- a/src/constants/routes.json +++ b/src/constants/routes.json @@ -6,5 +6,6 @@ "CREW": "/crew", "MYCREW": "/crew/my", "HOME": "/home", - "SOCKET": "/socket" + "SOCKET": "/socket", + "MYPAGE": "/mypage" } diff --git a/src/contexts/ModalsContext.ts b/src/contexts/ModalsContext.ts index 13e7df8..550944d 100644 --- a/src/contexts/ModalsContext.ts +++ b/src/contexts/ModalsContext.ts @@ -3,7 +3,7 @@ import { ComponentType, createContext } from "react" export type ModalProps = { id?: number onClose?: () => void - onSubmit?: () => void + onSubmit?: (value?: string) => void } export type ModalComponent = ComponentType diff --git a/src/pages/MyPage.tsx b/src/pages/MyPage.tsx new file mode 100644 index 0000000..db17076 --- /dev/null +++ b/src/pages/MyPage.tsx @@ -0,0 +1,46 @@ +import { modifyNickName } from "@/api/nickname" +import { modals } from "@/components/Modal/Modals" +import { useModals } from "@/hooks/useModals" +import { useAuthStore } from "@/store" + +export default function MyPage() { + const userInfo = useAuthStore((state) => state.user) + + const { openModal } = useModals() + + const onClickModifyNickName = () => { + openModal(modals.nickNameModal, { + onSubmit: (newNickName) => { + if (userInfo && newNickName) { + modifyNickName(userInfo.uid, newNickName) + } + }, + }) + } + + return ( +
    +

    마이 페이지

    +
    +
    +
    +
    닉네임
    +
    {userInfo?.nickname}
    +
    +
    + +
    +
    +
    +
    로그인 수단
    +
    카카오 계정
    +
    +
    +
    + ) +} diff --git a/src/routes/Router.tsx b/src/routes/Router.tsx index 1115e49..9392a6e 100644 --- a/src/routes/Router.tsx +++ b/src/routes/Router.tsx @@ -5,6 +5,7 @@ import BaseLayout from "@/layouts/BaseLayout" import MonitoringLayout from "@/layouts/MonitoringLayout" import { AnalysisDashboard, AuthPage, Crew, HomePage, MonitoringPage } from "@/pages" import MyCrew from "@/pages/MyCrew" +import MyPage from "@/pages/MyPage" import AuthRoute from "@/routes/AuthRoute" import { useAuthStore } from "@/store/AuthStore" import React from "react" @@ -23,6 +24,7 @@ const Router: React.FC = () => { }> }> + } /> }> } /> diff --git a/src/store/AuthStore.ts b/src/store/AuthStore.ts index eb55966..1834fb5 100644 --- a/src/store/AuthStore.ts +++ b/src/store/AuthStore.ts @@ -3,7 +3,10 @@ import { persist } from "zustand/middleware" interface AuthState { isAuthenticated: boolean - user: any + user: { + uid: number + nickname: string + } | null accessToken: string setUser: (user: any, accessToken: string) => void logout: (callback: () => void) => void From 351e5d6950f44b156b971c9b9a31260b5cb1fd36 Mon Sep 17 00:00:00 2001 From: G-hoon Date: Tue, 5 Nov 2024 02:12:52 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20nickname=EC=9D=B4=20store=EC=97=90?= =?UTF-8?q?=20=EC=A0=81=EC=A0=88=ED=95=98=EA=B2=8C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MyPage.tsx | 10 ++++++---- src/store/AuthStore.ts | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/pages/MyPage.tsx b/src/pages/MyPage.tsx index db17076..809a3f3 100644 --- a/src/pages/MyPage.tsx +++ b/src/pages/MyPage.tsx @@ -4,15 +4,17 @@ import { useModals } from "@/hooks/useModals" import { useAuthStore } from "@/store" export default function MyPage() { - const userInfo = useAuthStore((state) => state.user) + const { user, setNickName } = useAuthStore() const { openModal } = useModals() const onClickModifyNickName = () => { openModal(modals.nickNameModal, { onSubmit: (newNickName) => { - if (userInfo && newNickName) { - modifyNickName(userInfo.uid, newNickName) + if (user && newNickName) { + modifyNickName(user.uid, newNickName).then(({ data }) => { + setNickName(data.nickname) + }) } }, }) @@ -25,7 +27,7 @@ export default function MyPage() {
    닉네임
    -
    {userInfo?.nickname}
    +
    {user?.nickname}