page.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. 'use client';
  2. import './style.scss';
  3. import Link from 'next/link';
  4. import { useState, useEffect, useCallback } from 'react';
  5. import { useConfigContext } from '@/contexts/configProvider';
  6. import { useMemberContext } from '@/contexts/memberProvider';
  7. import { ChangePasswordRequest } from '@/dtos/request/account';
  8. import { fetchChangePassword } from '@/lib/api/account';
  9. import { getPasswordPolicyMessage } from '@/lib/utils/client';
  10. import NavTabs from '../navTabs';
  11. export default function ChangePassword()
  12. {
  13. const config = useConfigContext();
  14. const { member } = useMemberContext();
  15. const [error, setError] = useState<string>('');
  16. const [isComplete, setComplete] = useState<boolean>(false);
  17. const [formData, setFormData] = useState({
  18. currentPassword: '',
  19. newPassword: '',
  20. confirmPassword: ''
  21. });
  22. useEffect(() => {
  23. if (error) {
  24. alert(error);
  25. setError('');
  26. }
  27. }, [error]);
  28. const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
  29. e.preventDefault();
  30. if (!member) {
  31. return;
  32. }
  33. if (formData.newPassword !== formData.confirmPassword) {
  34. setError("새 비밀번호가 일치하지 않습니다.");
  35. return;
  36. }
  37. if (formData.currentPassword === formData.newPassword) {
  38. setError("새 비밀번호는 현재 비밀번호와 달라야 합니다.");
  39. return;
  40. }
  41. fetchChangePassword({
  42. ID: member.id,
  43. CurrentPassword: formData.currentPassword,
  44. NewPassword: formData.newPassword,
  45. ConfirmPassword: formData.confirmPassword
  46. } as ChangePasswordRequest).then((res) => {
  47. if (!res.ok) {
  48. throw new Error(res.message!);
  49. }
  50. setComplete(true);
  51. }).catch(err => {
  52. setError(err.message);
  53. });
  54. }
  55. const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
  56. const { id, value } = e.target;
  57. setFormData(prev => ({ ...prev, [id]: value}));
  58. }, []);
  59. useEffect(() => {
  60. if (isComplete)
  61. {
  62. // 입력 초기화
  63. setFormData({
  64. currentPassword: '',
  65. newPassword: '',
  66. confirmPassword: ''
  67. });
  68. setComplete(false);
  69. alert("비밀번호가 변경되었습니다.");
  70. }
  71. }, [isComplete]);
  72. const txtPasswordGuide = getPasswordPolicyMessage({
  73. passwordUppercaseLength: config.account.passwordUppercaseLength,
  74. passwordNumbersLength: config.account.passwordNumbersLength,
  75. passwordSpecialcharsLength: config.account.passwordSpecialcharsLength
  76. });
  77. return (
  78. <>
  79. <NavTabs />
  80. <div id="changePassword">
  81. <h1>비밀번호 변경</h1>
  82. <form id="fChangePassword" method="post" acceptCharset="utf-8" autoComplete="off" onSubmit={handleSubmit}>
  83. <table className="table-auto max-xl:w-full lg:w-[600px]">
  84. <caption>
  85. 비밀번호는 { config.account.passwordMinLength }자 이상 20자 이하로 설정 가능합니다.<br />
  86. { txtPasswordGuide }
  87. </caption>
  88. <colgroup>
  89. <col width="30%"/>
  90. <col width="60%"/>
  91. <col width="10%"/>
  92. </colgroup>
  93. <tbody>
  94. <tr>
  95. <th>현재 비밀번호</th>
  96. <td>
  97. <input type="password" id="currentPassword" value={formData.currentPassword} onChange={handleChange} placeholder="현재 비밀번호" required />
  98. </td>
  99. <td>&nbsp;</td>
  100. </tr>
  101. <tr>
  102. <th>새 비밀번호</th>
  103. <td>
  104. <input type="password" id="newPassword" value={formData.newPassword} onChange={handleChange} placeholder="새 비밀번호" required />
  105. </td>
  106. <td>&nbsp;</td>
  107. </tr>
  108. <tr>
  109. <th>새 비밀번호 확인</th>
  110. <td>
  111. <input type="password" id="confirmPassword" value={formData.confirmPassword} onChange={handleChange} placeholder="새 비밀번호 확인" required />
  112. </td>
  113. <td>&nbsp;</td>
  114. </tr>
  115. </tbody>
  116. <tfoot>
  117. <tr>
  118. <td colSpan={3}>
  119. <div className="flex justify-center gap-2">
  120. <button type="submit" className="btn btn-submit">확인</button>
  121. <Link href="/profile" className="btn btn-default">취소</Link>
  122. </div>
  123. </td>
  124. </tr>
  125. </tfoot>
  126. </table>
  127. </form>
  128. </div>
  129. </>
  130. );
  131. }