diff --git a/package-lock.json b/package-lock.json index f2c0d4f..07a4241 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "react-to-pdf": "^2.0.0", "sass": "^1.87.0", "swiper": "^11.2.6", + "usehooks-ts": "^3.1.1", "zustand": "^5.0.3" }, "devDependencies": { @@ -3293,6 +3294,12 @@ "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": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -4068,6 +4075,21 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "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": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", diff --git a/package.json b/package.json index 7d5da52..d00c56c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "react-to-pdf": "^2.0.0", "sass": "^1.87.0", "swiper": "^11.2.6", + "usehooks-ts": "^3.1.1", "zustand": "^5.0.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ebc4c8..74c7972 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: swiper: specifier: ^11.2.6 version: 11.2.6 + usehooks-ts: + specifier: ^3.1.1 + version: 3.1.1(react@19.1.0) zustand: specifier: ^5.0.3 version: 5.0.3(@types/react@19.0.12)(react@19.1.0) @@ -1082,6 +1085,9 @@ packages: resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} engines: {node: '>= 12.0.0'} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -1349,6 +1355,12 @@ packages: undici-types@6.19.8: 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: resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} @@ -2312,6 +2324,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.29.2 lightningcss-win32-x64-msvc: 1.29.2 + lodash.debounce@4.0.8: {} + lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -2581,6 +2595,11 @@ snapshots: 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: dependencies: base64-arraybuffer: 1.0.2 diff --git a/src/app/api/auth/chg-pwd/route.ts b/src/app/api/auth/chg-pwd/route.ts new file mode 100644 index 0000000..436f101 --- /dev/null +++ b/src/app/api/auth/chg-pwd/route.ts @@ -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 }) +} diff --git a/src/components/Login.tsx b/src/components/Login.tsx index 0bb7c66..5f086af 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -3,10 +3,12 @@ import type { SessionData } from '@/types/Auth' import { useEffect, useReducer, useState } from 'react' import { useRouter } from 'next/navigation' + +import { useLocalStorage } from 'usehooks-ts' import { useQuery } from '@tanstack/react-query' + import { axiosInstance } from '@/libs/axios' import { useSessionStore } from '@/store/session' -import { useUserInfoState } from '@/store/userInfoState' interface AccountState { loginId: string @@ -25,7 +27,7 @@ export default function Login() { const [isLogin, setIsLogin] = useState(false) const { session, setSession } = useSessionStore() - const { userInfo, setUserInfo } = useUserInfoState() + const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' }) const reducer = (state: AccountState, newState: Partial) => ({ ...state, ...newState }) const [account, setAccount] = useReducer(reducer, { @@ -50,7 +52,6 @@ export default function Login() { loginId: account.loginId, pwd: account.pwd, }) - // router.push('/') return data }, @@ -63,12 +64,8 @@ export default function Login() { setIsLogin(false) if (loginData?.code === 200) { // 유저 정보 저장 - setUserInfo({ - loginId: account.loginId, - chgType: 'C', - emali: loginData?.result.email || '', - pwd: account.pwd, - chgPwd: '', + setValue({ + indivisualData: account.pwd, }) // 세션 정보 저장 setSession({ diff --git a/src/components/pw-reset/PwResetForm.tsx b/src/components/pw-reset/PwResetForm.tsx index 65bc3c0..b332de4 100644 --- a/src/components/pw-reset/PwResetForm.tsx +++ b/src/components/pw-reset/PwResetForm.tsx @@ -2,17 +2,49 @@ import { useState } from 'react' 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() { - const [pwShow01, setPwShow01] = useState(false) //비밀번호 확인 보이기 숨기기 - const [pwShow02, setPwShow02] = useState(false) //비밀번호 재확인 보이기 숨기기 + const [pwShow01, setPwShow01] = useState(false) //비밀번호 확인 보이기 숨기기 + const [pwShow02, setPwShow02] = useState(false) //비밀번호 재확인 보이기 숨기기 + + const [pwd01, setPwd01] = useState('') + const [pwd02, setPwd02] = useState('') + const router = useRouter() - const { userInfo, setUserInfo } = useUserInfoState() + const { session } = useSessionStore() + const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' }) - const handleReset = () => { - console.log('reset') + const validatePwd = () => { + 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 ( @@ -25,7 +57,12 @@ export default function PwResetForm() {
- + setPwd01(e.target.value)} + /> @@ -39,7 +76,12 @@ export default function PwResetForm() {
- + setPwd02(e.target.value)} + /> diff --git a/src/components/ui/common/Header.tsx b/src/components/ui/common/Header.tsx index eb365b8..da3cf49 100644 --- a/src/components/ui/common/Header.tsx +++ b/src/components/ui/common/Header.tsx @@ -3,22 +3,25 @@ import Link from 'next/link' import { usePathname, useRouter } from 'next/navigation' -import { Swiper, SwiperSlide } from 'swiper/react' +import { useLocalStorage } from 'usehooks-ts' import { useQueryClient } from '@tanstack/react-query' +import { Swiper, SwiperSlide } from 'swiper/react' import { useSideNavState } from '@/store/sideNavState' import { useHeaderStore } from '@/store/header' import { useSessionStore } from '@/store/session' +import { usePopupController } from '@/store/popupController' + import { useTitle } from '@/hooks/useTitle' import { axiosInstance } from '@/libs/axios' import 'swiper/css' -import { usePopupController } from '@/store/popupController' export default function Header() { const router = useRouter() const pathname = usePathname() + const [value, setValue, removeValue] = useLocalStorage<{ indivisualData: string }>('hanasysIndivisualState', { indivisualData: '' }) const { sideNavIsOpen, setSideNavIsOpen } = useSideNavState() const { backBtn } = useHeaderStore() const { getTitle } = useTitle() @@ -34,6 +37,7 @@ export default function Header() { const handleLogout = async () => { reset() + removeValue() const { data } = await axiosInstance(null).get('/api/auth/logout') if (data.code === 200) { queryClient.clear() diff --git a/src/providers/EdgeProvider.tsx b/src/providers/EdgeProvider.tsx index 424ab2d..4cfd67e 100644 --- a/src/providers/EdgeProvider.tsx +++ b/src/providers/EdgeProvider.tsx @@ -1,14 +1,16 @@ 'use client' +import { useEffect } from 'react' +import { usePathname } from 'next/navigation' + import { useHeaderStore } from '@/store/header' import { usePopupController } from '@/store/popupController' import { useSideNavState } from '@/store/sideNavState' -import { usePathname } from 'next/navigation' -import { useEffect } from 'react' import { useSessionStore } from '@/store/session' declare global { interface Window { + neoAlert: (msg?: string, alertBtn?: Function) => void 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)) { alertFunc(msg, alertBtn) } + window.neoAlert = function (msg?: string, alertBtn = () => setAlert(false)) { + if (!msg) return + alertFunc(msg, alertBtn) + } // confirm 함수 변경해서 바인딩 window.neoConfirm = function (msg: string | undefined, alertBtn2Yes?: Function, alertBtn2No?: Function) { if (!msg) return false diff --git a/src/store/userInfoState.ts b/src/store/userInfoState.ts deleted file mode 100644 index 275c2b1..0000000 --- a/src/store/userInfoState.ts +++ /dev/null @@ -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((set) => ({ - userInfo: initialState, - setUserInfo: (value: UserInfo) => set((state) => ({ ...state, userInfo: { ...state.userInfo, ...value } })), - reset: () => set({ userInfo: initialState }), -}))