11import { checkPassword , patchEditProfile } from '@/apis/user' ;
2- import Button from '@/components/button/Button' ;
3- import Complete from '@/components/loading/Complete' ;
4- import ErrorShake from '@/components/loading/ErrorShake' ;
5- import SpinLoading from '@/components/loading/SpinLoading' ;
6- import CurrentPasswordInput from '@/pages/editprofile/components/CurrentPasswordInput' ;
7- import PasswordConfirmInput from '@/pages/signup/components/PasswordConfirmInput' ;
8- import PasswordInput from '@/pages/signup/components/PasswordInput' ;
2+ import { StatusButton } from '@/components/button' ;
3+ import { CurrentPasswordInput } from '@/pages/editprofile/components' ;
4+ import { PasswordGroupSection } from '@/pages/signup/components' ;
95import { useModalStore } from '@/store/modalStore' ;
6+ import { useMutation } from '@tanstack/react-query' ;
107import { useState } from 'react' ;
118import { useNavigate } from 'react-router' ;
12- import { twMerge } from 'tailwind-merge' ;
13-
14- type ProfileFormType = {
15- password : string ;
16- nickName : string ;
17- spotifyId : string ;
18- title : string ;
19- artist : string ;
20- albumImage : string ;
21- } ;
229
2310function PasswordEditForm ( ) {
2411 const navigate = useNavigate ( ) ;
2512 const { openModal, closeModal } = useModalStore ( ) ; // 모달 관리
2613
27- const [ isLoading , setIsLoading ] = useState ( false ) ;
28- const [ isComplete , setIsComplete ] = useState ( false ) ;
29- const [ isError , setIsError ] = useState ( false ) ;
30- const [ currentPassword , setCurrentPassword ] = useState < string > ( '' ) ;
31- const [ newPassword , setNewPassword ] = useState ( '' ) ;
3214 const [ validity , setValidity ] = useState ( {
15+ currentPassword : false ,
3316 password : false ,
34- passwordConfirm : false ,
3517 } ) ;
3618
37- const validateCurrentPassword = async ( ) => {
38- //현재 비밀번호 확인 api
39- try {
40- const data = await checkPassword ( currentPassword ) ;
41- if ( data . code === 200 ) {
42- return true ;
43- } else if ( data . code === 400 ) {
44- return false ;
45- }
46- } catch {
47- console . error ( '비밀번호 확인도중 에러가 발생했습니다.' ) ;
48- return false ;
49- }
19+ const buttonEnabled = Object . values ( validity ) . every ( Boolean ) ;
20+
21+ // validity 업데이트 함수
22+ const updateValidity = ( key : 'currentPassword' | 'password' , value : boolean ) => {
23+ setValidity ( ( prev ) => {
24+ if ( prev [ key ] === value ) return prev ; // 값이 동일하면 변경 X
25+ return { ...prev , [ key ] : value } ;
26+ } ) ;
5027 } ;
5128
52- const handlePasswordSubmit = async ( ) => {
53- try {
54- setIsLoading ( true ) ;
29+ // 현재 비밀번호 확인 useMutation
30+ const {
31+ mutateAsync : checkCurrentPassword ,
32+ isPending : isCheckingPassword ,
33+ isError : isCheckPasswordError ,
34+ reset,
35+ } = useMutation ( {
36+ mutationFn : async ( password : string ) => {
37+ const res = await checkPassword ( password ) ;
38+ if ( res . code !== 200 ) {
39+ throw new Error ( '비밀번호 틀림' ) ;
40+ }
41+ return res ;
42+ } ,
43+ } ) ;
5544
56- // 현재 비밀번호 확인
57- const isCurrentPasswordValid = await validateCurrentPassword ( ) ;
58- if ( ! isCurrentPasswordValid ) {
59- openModal ( {
60- title : '현재 비밀번호를 다시 확인해주세요' ,
61- onConfirm : ( ) => {
62- closeModal ( ) ;
63- } ,
64- } ) ;
65- return ;
45+ // 비밀번호 변경 useMutation
46+ const {
47+ mutateAsync : changePassword ,
48+ isPending : isChangingPassword ,
49+ isError : isChangePasswordError ,
50+ isSuccess,
51+ } = useMutation ( {
52+ mutationFn : async ( password : string ) => {
53+ const res = await patchEditProfile ( { password } ) ;
54+ if ( res . code !== 200 ) {
55+ throw new Error ( '비밀번호 변경 실패' ) ;
6656 }
57+ return res ;
58+ } ,
59+ } ) ;
6760
68- const updatedData : Partial < ProfileFormType > = {
69- password : newPassword ,
70- } ;
61+ const handleSubmit = async ( e : React . FormEvent < HTMLFormElement > ) => {
62+ e . preventDefault ( ) ;
63+ const formData = new FormData ( e . currentTarget ) ;
64+ const currentPassword = formData . get ( 'current-password' ) as string ;
65+ const password = formData . get ( 'password' ) as string ;
66+ // 현재 비밀번호 확인
67+ try {
68+ await checkCurrentPassword ( currentPassword ) ;
69+ } catch {
70+ openModal ( {
71+ title : '현재 비밀번호를 다시 확인해주세요' ,
72+ onConfirm : ( ) => {
73+ reset ( ) ;
74+ closeModal ( ) ;
75+ } ,
76+ } ) ;
77+ return ;
78+ }
7179
72- // API 호출
73- const data = await patchEditProfile ( updatedData ) ;
80+ // 비밀 번호 변경
81+ try {
82+ await changePassword ( password ) ;
7483
75- if ( data . code === 200 ) {
76- setIsComplete ( true ) ;
77- openModal ( {
78- title : '비밀번호 변경이 완료되었습니다' ,
79- onConfirm : ( ) => {
80- navigate ( '/mypage' ) ;
81- closeModal ( ) ;
82- } ,
83- } ) ;
84- }
85- } catch ( error ) {
86- setIsError ( true ) ;
87- console . error ( '비밀번호 변경 오류:' , error ) ;
84+ openModal ( {
85+ title : '비밀번호 변경이 완료되었습니다' ,
86+ onConfirm : ( ) => {
87+ navigate ( '/mypage' ) ;
88+ closeModal ( ) ;
89+ } ,
90+ } ) ;
91+ } catch {
8892 openModal ( {
8993 title : '비밀번호 변경 실패' ,
9094 message : '잠시 후 다시 시도해주세요.' ,
@@ -93,46 +97,29 @@ function PasswordEditForm() {
9397 navigate ( - 1 ) ;
9498 } ,
9599 } ) ;
96- } finally {
97- setIsLoading ( false ) ;
98100 }
99101 } ;
100102
101- const isPasswordEditable = currentPassword && validity . password && validity . password ;
102- const renderButtonContent = ( ) => {
103- if ( isLoading ) {
104- return < SpinLoading /> ;
105- } else if ( isComplete ) {
106- return < Complete /> ;
107- } else if ( isError ) {
108- return < ErrorShake /> ;
109- } else return < span > 저장하기</ span > ;
110- } ;
111-
112103 return (
113- < form className = "flex flex-col justify-between h-full p-5" onSubmit = { ( e ) => e . preventDefault ( ) } >
114- < div className = "flex flex-col gap-5" >
115- < CurrentPasswordInput setCurrentPassword = { setCurrentPassword } />
116- < PasswordInput
117- label = "새 비밀번호"
118- placeholder = "새 비밀번호를 입력해 주세요"
119- changeFormPassword = { ( password ) => setNewPassword ( password ) }
120- setValidity = { ( password ) => setValidity ( ( prev ) => ( { ...prev , password } ) ) }
121- />
122- < PasswordConfirmInput
123- label = "새 비밀번호 확인"
124- placeholder = "새 비밀번호를 다시 입력해 주세요"
125- setValidity = { ( passwordConfirm ) => setValidity ( ( prev ) => ( { ...prev , passwordConfirm } ) ) }
126- password = { newPassword }
104+ < form className = "flex flex-col justify-between h-full p-5" onSubmit = { handleSubmit } >
105+ < div className = "flex flex-col" >
106+ < CurrentPasswordInput setValidity = { ( value ) => updateValidity ( 'currentPassword' , value ) } />
107+ < PasswordGroupSection
108+ setValidity = { ( value ) => updateValidity ( 'password' , value ) }
109+ passwordLabel = "새 비밀번호"
110+ confirmLabel = "새 비밀번호 확인"
111+ passwordPlaceholder = "새 비밀번호를 입력해 주세요"
112+ confirmPlaceholder = "새 비밀번호를 다시 입력해 주세요"
127113 />
128114 </ div >
129- < Button
130- onClick = { handlePasswordSubmit }
131- variant = { isPasswordEditable ? 'primary' : 'disabled' }
132- className = { twMerge ( 'py-3 body-m mt-5' , isError ? 'bg-functional-danger' : '' ) }
133- >
134- { renderButtonContent ( ) }
135- </ Button >
115+ < StatusButton
116+ isLoading = { isCheckingPassword || isChangingPassword }
117+ isSuccess = { isSuccess }
118+ isError = { isCheckPasswordError || isChangePasswordError }
119+ disabled = { ! buttonEnabled }
120+ type = "submit"
121+ text = "저장하기"
122+ />
136123 </ form >
137124 ) ;
138125}
0 commit comments