Merge pull request 'feature/userInfo-yoo' (#30) from feature/userInfo-yoo into dev

Reviewed-on: #30
This commit is contained in:
swyoo 2025-05-14 17:50:38 +09:00
commit 02283c3b71
9 changed files with 134 additions and 58 deletions

22
package-lock.json generated
View File

@ -20,6 +20,7 @@
"react-to-pdf": "^2.0.0", "react-to-pdf": "^2.0.0",
"sass": "^1.87.0", "sass": "^1.87.0",
"swiper": "^11.2.6", "swiper": "^11.2.6",
"usehooks-ts": "^3.1.1",
"zustand": "^5.0.3" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {
@ -3293,6 +3294,12 @@
"url": "https://opencollective.com/parcel" "url": "https://opencollective.com/parcel"
} }
}, },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"license": "MIT"
},
"node_modules/lodash.includes": { "node_modules/lodash.includes": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@ -4068,6 +4075,21 @@
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/usehooks-ts": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz",
"integrity": "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==",
"license": "MIT",
"dependencies": {
"lodash.debounce": "^4.0.8"
},
"engines": {
"node": ">=16.15.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/utrie": { "node_modules/utrie": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",

View File

@ -21,6 +21,7 @@
"react-to-pdf": "^2.0.0", "react-to-pdf": "^2.0.0",
"sass": "^1.87.0", "sass": "^1.87.0",
"swiper": "^11.2.6", "swiper": "^11.2.6",
"usehooks-ts": "^3.1.1",
"zustand": "^5.0.3" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {

19
pnpm-lock.yaml generated
View File

@ -44,6 +44,9 @@ importers:
swiper: swiper:
specifier: ^11.2.6 specifier: ^11.2.6
version: 11.2.6 version: 11.2.6
usehooks-ts:
specifier: ^3.1.1
version: 3.1.1(react@19.1.0)
zustand: zustand:
specifier: ^5.0.3 specifier: ^5.0.3
version: 5.0.3(@types/react@19.0.12)(react@19.1.0) version: 5.0.3(@types/react@19.0.12)(react@19.1.0)
@ -1082,6 +1085,9 @@ packages:
resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
lodash.includes@4.3.0: lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
@ -1349,6 +1355,12 @@ packages:
undici-types@6.19.8: undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
usehooks-ts@3.1.1:
resolution: {integrity: sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==}
engines: {node: '>=16.15.0'}
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
utrie@1.0.2: utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
@ -2312,6 +2324,8 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.29.2 lightningcss-win32-arm64-msvc: 1.29.2
lightningcss-win32-x64-msvc: 1.29.2 lightningcss-win32-x64-msvc: 1.29.2
lodash.debounce@4.0.8: {}
lodash.includes@4.3.0: {} lodash.includes@4.3.0: {}
lodash.isboolean@3.0.3: {} lodash.isboolean@3.0.3: {}
@ -2581,6 +2595,11 @@ snapshots:
undici-types@6.19.8: {} undici-types@6.19.8: {}
usehooks-ts@3.1.1(react@19.1.0):
dependencies:
lodash.debounce: 4.0.8
react: 19.1.0
utrie@1.0.2: utrie@1.0.2:
dependencies: dependencies:
base64-arraybuffer: 1.0.2 base64-arraybuffer: 1.0.2

View File

@ -0,0 +1,22 @@
import { NextResponse } from 'next/server'
import { axiosInstance } from '@/libs/axios'
export async function POST(req: Request) {
const { loginId, email, pwd, chgPwd } = await req.json()
console.log('🚀 ~ POST ~ loginId:', loginId)
console.log('🚀 ~ POST ~ email:', email)
console.log('🚀 ~ POST ~ pwd:', pwd)
console.log('🚀 ~ POST ~ chgPwd:', chgPwd)
const result = await axiosInstance(`${process.env.NEXT_PUBLIC_QSP_API_URL}`).post(`/api/user/userPwdChg`, {
loginId,
chgType: 'C',
email,
pwd,
chgPwd,
})
console.log('🚀 ~ result ~ result:', result)
return NextResponse.json({ code: 200, data: result.data })
}

View File

@ -3,10 +3,12 @@
import type { SessionData } from '@/types/Auth' import type { SessionData } from '@/types/Auth'
import { useEffect, useReducer, useState } from 'react' import { useEffect, useReducer, useState } from 'react'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useLocalStorage } from 'usehooks-ts'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { axiosInstance } from '@/libs/axios' import { axiosInstance } from '@/libs/axios'
import { useSessionStore } from '@/store/session' import { useSessionStore } from '@/store/session'
import { useUserInfoState } from '@/store/userInfoState'
interface AccountState { interface AccountState {
loginId: string loginId: string
@ -25,7 +27,7 @@ export default function Login() {
const [isLogin, setIsLogin] = useState(false) const [isLogin, setIsLogin] = useState(false)
const { session, setSession } = useSessionStore() const { session, setSession } = useSessionStore()
const { userInfo, setUserInfo } = useUserInfoState() const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' })
const reducer = (state: AccountState, newState: Partial<AccountState>) => ({ ...state, ...newState }) const reducer = (state: AccountState, newState: Partial<AccountState>) => ({ ...state, ...newState })
const [account, setAccount] = useReducer(reducer, { const [account, setAccount] = useReducer(reducer, {
@ -50,7 +52,6 @@ export default function Login() {
loginId: account.loginId, loginId: account.loginId,
pwd: account.pwd, pwd: account.pwd,
}) })
// router.push('/')
return data return data
}, },
@ -63,12 +64,8 @@ export default function Login() {
setIsLogin(false) setIsLogin(false)
if (loginData?.code === 200) { if (loginData?.code === 200) {
// 유저 정보 저장 // 유저 정보 저장
setUserInfo({ setValue({
loginId: account.loginId, indivisualData: account.pwd,
chgType: 'C',
emali: loginData?.result.email || '',
pwd: account.pwd,
chgPwd: '',
}) })
// 세션 정보 저장 // 세션 정보 저장
setSession({ setSession({

View File

@ -2,17 +2,49 @@
import { useState } from 'react' import { useState } from 'react'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useUserInfoState } from '@/store/userInfoState'
import { useLocalStorage } from 'usehooks-ts'
import { axiosInstance } from '@/libs/axios'
import { useSessionStore } from '@/store/session'
export default function PwResetForm() { export default function PwResetForm() {
const [pwShow01, setPwShow01] = useState(false) //비밀번호 확인 보이기 숨기기 const [pwShow01, setPwShow01] = useState<boolean>(false) //비밀번호 확인 보이기 숨기기
const [pwShow02, setPwShow02] = useState(false) //비밀번호 재확인 보이기 숨기기 const [pwShow02, setPwShow02] = useState<boolean>(false) //비밀번호 재확인 보이기 숨기기
const [pwd01, setPwd01] = useState<string>('')
const [pwd02, setPwd02] = useState<string>('')
const router = useRouter() const router = useRouter()
const { userInfo, setUserInfo } = useUserInfoState() const { session } = useSessionStore()
const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' })
const handleReset = () => { const validatePwd = () => {
console.log('reset') if (pwd01 !== pwd02) {
alert('비밀번호가 일치하지 않습니다.')
return false
}
return true
}
const handleReset = async () => {
if (validatePwd()) {
const { data } = await axiosInstance(null).post(`/api/auth/chg-pwd`, {
loginId: session.userId,
email: session.email,
pwd: value.indivisualData,
chgPwd: pwd01,
})
if (data.data.result.resultCode === 'S') {
setValue({ indivisualData: pwd01 })
}
window.neoAlert(data.data.result.resultMsg, () => {
router.back()
})
}
} }
return ( return (
@ -25,7 +57,12 @@ export default function PwResetForm() {
</div> </div>
<div className="data-input"> <div className="data-input">
<div className="login-input pw change"> <div className="login-input pw change">
<input type={`${pwShow01 ? 'text' : 'password'}`} className="login-frame" placeholder="●●●●" /> <input
type={`${pwShow01 ? 'text' : 'password'}`}
className="login-frame"
placeholder="●●●●"
onChange={(e) => setPwd01(e.target.value)}
/>
<button className={`login-icon ${pwShow01 ? 'act' : ''}`} onClick={() => setPwShow01(!pwShow01)}> <button className={`login-icon ${pwShow01 ? 'act' : ''}`} onClick={() => setPwShow01(!pwShow01)}>
<i className="show-icon"></i> <i className="show-icon"></i>
</button> </button>
@ -39,7 +76,12 @@ export default function PwResetForm() {
</div> </div>
<div className="data-input"> <div className="data-input">
<div className="login-input pw change"> <div className="login-input pw change">
<input type={`${pwShow02 ? 'text' : 'password'}`} className="login-frame" placeholder="●●●●" /> <input
type={`${pwShow02 ? 'text' : 'password'}`}
className="login-frame"
placeholder="●●●●"
onChange={(e) => setPwd02(e.target.value)}
/>
<button className={`login-icon ${pwShow02 ? 'act' : ''}`} onClick={() => setPwShow02(!pwShow02)}> <button className={`login-icon ${pwShow02 ? 'act' : ''}`} onClick={() => setPwShow02(!pwShow02)}>
<i className="show-icon"></i> <i className="show-icon"></i>
</button> </button>

View File

@ -3,22 +3,25 @@
import Link from 'next/link' import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation' import { usePathname, useRouter } from 'next/navigation'
import { Swiper, SwiperSlide } from 'swiper/react' import { useLocalStorage } from 'usehooks-ts'
import { useQueryClient } from '@tanstack/react-query' import { useQueryClient } from '@tanstack/react-query'
import { Swiper, SwiperSlide } from 'swiper/react'
import { useSideNavState } from '@/store/sideNavState' import { useSideNavState } from '@/store/sideNavState'
import { useHeaderStore } from '@/store/header' import { useHeaderStore } from '@/store/header'
import { useSessionStore } from '@/store/session' import { useSessionStore } from '@/store/session'
import { usePopupController } from '@/store/popupController'
import { useTitle } from '@/hooks/useTitle' import { useTitle } from '@/hooks/useTitle'
import { axiosInstance } from '@/libs/axios' import { axiosInstance } from '@/libs/axios'
import 'swiper/css' import 'swiper/css'
import { usePopupController } from '@/store/popupController'
export default function Header() { export default function Header() {
const router = useRouter() const router = useRouter()
const pathname = usePathname() const pathname = usePathname()
const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' })
const { sideNavIsOpen, setSideNavIsOpen } = useSideNavState() const { sideNavIsOpen, setSideNavIsOpen } = useSideNavState()
const { backBtn } = useHeaderStore() const { backBtn } = useHeaderStore()
const { getTitle } = useTitle() const { getTitle } = useTitle()
@ -34,6 +37,7 @@ export default function Header() {
const handleLogout = async () => { const handleLogout = async () => {
reset() reset()
removeValue()
const { data } = await axiosInstance(null).get('/api/auth/logout') const { data } = await axiosInstance(null).get('/api/auth/logout')
if (data.code === 200) { if (data.code === 200) {
queryClient.clear() queryClient.clear()

View File

@ -1,14 +1,16 @@
'use client' 'use client'
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
import { useHeaderStore } from '@/store/header' import { useHeaderStore } from '@/store/header'
import { usePopupController } from '@/store/popupController' import { usePopupController } from '@/store/popupController'
import { useSideNavState } from '@/store/sideNavState' import { useSideNavState } from '@/store/sideNavState'
import { usePathname } from 'next/navigation'
import { useEffect } from 'react'
import { useSessionStore } from '@/store/session' import { useSessionStore } from '@/store/session'
declare global { declare global {
interface Window { interface Window {
neoAlert: (msg?: string, alertBtn?: Function) => void
neoConfirm: (msg?: string, alertBtn2Yes?: Function, alertBtn2No?: Function) => boolean neoConfirm: (msg?: string, alertBtn2Yes?: Function, alertBtn2No?: Function) => boolean
} }
} }
@ -55,6 +57,10 @@ export default function EdgeProvider({ children, sessionData }: EdgeProviderProp
window.alert = function (msg, alertBtn = () => setAlert(false)) { window.alert = function (msg, alertBtn = () => setAlert(false)) {
alertFunc(msg, alertBtn) alertFunc(msg, alertBtn)
} }
window.neoAlert = function (msg?: string, alertBtn = () => setAlert(false)) {
if (!msg) return
alertFunc(msg, alertBtn)
}
// confirm 함수 변경해서 바인딩 // confirm 함수 변경해서 바인딩
window.neoConfirm = function (msg: string | undefined, alertBtn2Yes?: Function, alertBtn2No?: Function) { window.neoConfirm = function (msg: string | undefined, alertBtn2Yes?: Function, alertBtn2No?: Function) {
if (!msg) return false if (!msg) return false

View File

@ -1,37 +0,0 @@
import { create } from 'zustand'
type UserInfo = {
loginId: string
chgType: string
emali: string
pwd: string
chgPwd: string
}
type UserInfoState = {
userInfo: UserInfo
setUserInfo: (value: UserInfo) => void
reset: () => void
}
type InitialState = {
loginId: string
chgType: string
emali: string
pwd: string
chgPwd: string
}
const initialState: InitialState = {
loginId: '',
chgType: '',
emali: '',
pwd: '',
chgPwd: '',
}
export const useUserInfoState = create<UserInfoState>((set) => ({
userInfo: initialState,
setUserInfo: (value: UserInfo) => set((state) => ({ ...state, userInfo: { ...state.userInfo, ...value } })),
reset: () => set({ userInfo: initialState }),
}))