Skip to content

Commit

Permalink
Merge pull request #119 from DDD-Community/feat/#118
Browse files Browse the repository at this point in the history
Feat/#118
  • Loading branch information
G-hoon authored Nov 4, 2024
2 parents 48061ca + 351e5d6 commit ddddae4
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 15 deletions.
19 changes: 19 additions & 0 deletions src/api/nickname.ts
Original file line number Diff line number Diff line change
@@ -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<NickNameModificationResData> => {
try {
const res = await axiosInstance.put(`/users/${uid}/nickname`, {
nickname: newNickName,
})
return res.data
} catch (e) {
throw e
}
}
3 changes: 3 additions & 0 deletions src/assets/icons/arrow-small-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions src/components/Modal/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -17,6 +18,7 @@ export const modals = {
ToWithdrawModal: ToWithdrawModal,
postureGuideModal: GoodPostureGuidePopupModal,
reportModal: ReportModal,
nickNameModal: NickNameModal,
}

const Modals = (): React.ReactNode => {
Expand Down Expand Up @@ -45,9 +47,9 @@ const Modals = (): React.ReactNode => {
close(Component)
}

const handleSubmit = async (): Promise<void> => {
const handleSubmit = async (value?: any): Promise<void> => {
if (typeof onSubmit === "function") {
await onSubmit()
await onSubmit(value)
}
handleClose()
}
Expand Down
55 changes: 55 additions & 0 deletions src/components/Modal/NickNameModal.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<ModalContainer onClose={onClose}>
<div className="flex flex-col items-center">
{/* header */}
<div className="flex items-center">
<div className="text-xl font-bold text-zinc-900">닉네임</div>
</div>

<div className="flex w-full flex-col gap-1 pb-6 pt-10">
<input
className={`w-full rounded-xl border border-gray-200 p-3 font-normal focus:outline-none focus:ring-2 ${
nickName.length > 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)}
/>
<div className="mt-1 h-6">
{nickName.length > 200 && (
<span className={`text-[14px] font-semibold text-red-500 `}>닉네임은 200자를 초과할 수 없어요.</span>
)}
</div>
</div>

{/* button */}
<div className="pb-10">
<button
className="w-[256px] rounded-[40px] bg-[#1A75FF] px-10 py-3 text-base font-semibold text-white disabled:bg-zinc-300"
onClick={onClickModifyNickNameButton}
disabled={!nickName}
>
변경하기
</button>
</div>
</div>
</ModalContainer>
)
}

export default NickNameModal
20 changes: 12 additions & 8 deletions src/components/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand Down Expand Up @@ -86,12 +88,14 @@ export default function SideNav(): React.ReactElement {
</div>

{/* User Info */}
<div className="pl-6 pt-2">
<div className="text-sm text-gray-400">바른자세 똑딱똑딱</div>
<div>
<span className="text-sm font-bold">{nickname}</span>
<span className="text-sm text-gray-400"></span>
</div>
<div className="flex flex-col gap-[2px] pl-6 pt-2">
<div className="text-base text-zinc-500">바른자세 똑딱똑딱</div>
<Link to={RoutePath.MYPAGE} className="flex items-center">
<span className="max-w-[200px] overflow-hidden text-ellipsis whitespace-nowrap text-lg font-bold">
{nickname}
</span>
<RightSmallArrow />
</Link>
</div>

{/* Navigation Links */}
Expand All @@ -100,7 +104,7 @@ export default function SideNav(): React.ReactElement {
{navItems.map(({ icon: Icon, label, link }) => {
const isActive = location.pathname.includes(link)
return (
<li key={label} className={`mb-1 rounded-r-md ${isActive ? "bg-gray-700" : "hover:bg-gray-700"}`}>
<li key={label} className={`mb-1 rounded-r-md ${isActive ? "bg-zinc-700" : "hover:bg-zinc-700"}`}>
<Link to={link} className={`nav-item flex w-full items-center p-3 ${isActive ? "active" : ""}`}>
<Icon className="ml-3 mr-3 h-5 w-5" />
<span className={isActive ? "font-bold" : ""}>{label}</span>
Expand All @@ -126,7 +130,7 @@ export default function SideNav(): React.ReactElement {
</div>

{/* Footer Text */}
<div className="text-xs text-gray-500">
<div className="text-xs text-zinc-500">
© 2024 주인공.
<br />
All rights reserved.
Expand Down
3 changes: 2 additions & 1 deletion src/constants/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"CREW": "/crew",
"MYCREW": "/crew/my",
"HOME": "/home",
"SOCKET": "/socket"
"SOCKET": "/socket",
"MYPAGE": "/mypage"
}
2 changes: 1 addition & 1 deletion src/contexts/ModalsContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<any>
Expand Down
48 changes: 48 additions & 0 deletions src/pages/MyPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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 { user, setNickName } = useAuthStore()

const { openModal } = useModals()

const onClickModifyNickName = () => {
openModal(modals.nickNameModal, {
onSubmit: (newNickName) => {
if (user && newNickName) {
modifyNickName(user.uid, newNickName).then(({ data }) => {
setNickName(data.nickname)
})
}
},
})
}

return (
<div className="bg-gray-50 pl-[110px] pt-12">
<h1 className="text-[22px] font-bold text-zinc-900">마이 페이지</h1>
<div className="flex flex-col gap-4 pt-11">
<div className="flex h-[56px] max-w-[998px] items-center justify-between rounded-xl border border-gray-200 bg-white pl-6">
<div className="flex items-center gap-6">
<div className="text-sm">닉네임</div>
<div>{user?.nickname}</div>
</div>
<div className="pr-[27px]">
<button
className="rounded-full bg-[#1A75FF] px-[22px] py-[6px] text-[13px] font-semibold text-white"
onClick={onClickModifyNickName}
>
변경하기
</button>
</div>
</div>
<div className="flex h-[56px] max-w-[998px] items-center gap-6 rounded-xl border border-gray-200 bg-white pl-6">
<div className="text-sm">로그인 수단</div>
<div>카카오 계정</div>
</div>
</div>
</div>
)
}
2 changes: 2 additions & 0 deletions src/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -23,6 +24,7 @@ const Router: React.FC = () => {

<Route element={<AuthRoute />}>
<Route element={<BaseLayout />}>
<Route path={RoutePath.MYPAGE} element={<MyPage />} />
<Route element={<MonitoringLayout />}>
<Route path={RoutePath.MONITORING} element={<MonitoringPage />} />
</Route>
Expand Down
15 changes: 12 additions & 3 deletions src/store/AuthStore.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { create } from "zustand"
import { persist } from "zustand/middleware"

interface UserInfo {
uid: number
nickname: string
}
interface AuthState {
isAuthenticated: boolean
user: any
user: UserInfo | null
accessToken: string
setUser: (user: any, accessToken: string) => void
setUser: (user: UserInfo, accessToken: string) => void
setNickName: (nickname: string) => void
logout: (callback: () => void) => void
}

Expand All @@ -16,12 +21,16 @@ export const useAuthStore = create(
isAuthenticated: false,
user: null,
accessToken: "",
setUser: (user: any, accessToken: string) =>
setUser: (user: UserInfo, accessToken: string) =>
set({
user,
isAuthenticated: true,
accessToken,
}),
setNickName: (nickname: string) =>
set((state) => ({
user: state.user ? { ...state.user, nickname } : null,
})),
logout: (callback) => {
set({
user: null,
Expand Down

0 comments on commit ddddae4

Please sign in to comment.