| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- <template>
- <main class="user--main">
- <div class="join--container">
- <div class="title--wrap">
- <h1>새 비밀번호 설정</h1>
- <p class="mt--9">새로 사용할 비밀번호를 입력해주세요.</p>
- </div>
- <div class="login--wrap mt--20">
- <form @submit.prevent="handleReset">
- <!-- 새 비밀번호 -->
- <div class="input--wrap mt--18 pw--input--wrap">
- <label for="reset--pw">새 비밀번호</label>
- <input
- id="reset--pw"
- v-model="password"
- :type="showPw ? 'text' : 'password'"
- placeholder="비밀번호를 입력해 주세요"
- autocomplete="new-password"
- maxlength="30"
- >
- <button
- type="button"
- class="pw--toggle--btn"
- :aria-label="showPw ? '비밀번호 숨기기' : '비밀번호 표시'"
- @click="showPw = !showPw"
- >
- <img v-if="showPw" src="/img/ico--pw.svg" alt="비밀번호 표시" />
- <img v-else src="/img/ico--pw--off.svg" alt="비밀번호 숨김" />
- </button>
- </div>
- <p class="input--info" :style="passwordInvalid ? 'color:#e5484d;' : ''">
- 영문(소문자)+숫자+특수문자 조합 8자 이상
- </p>
- <!-- 새 비밀번호 확인 -->
- <div class="input--wrap mt--18 pw--input--wrap">
- <label for="reset--pw2">새 비밀번호 확인</label>
- <input
- id="reset--pw2"
- v-model="password2"
- :type="showPw2 ? 'text' : 'password'"
- placeholder="비밀번호를 다시 입력해 주세요"
- autocomplete="new-password"
- maxlength="30"
- >
- <button
- type="button"
- class="pw--toggle--btn"
- :aria-label="showPw2 ? '비밀번호 숨기기' : '비밀번호 표시'"
- @click="showPw2 = !showPw2"
- >
- <img v-if="showPw2" src="/img/ico--pw.svg" alt="비밀번호 표시" />
- <img v-else src="/img/ico--pw--off.svg" alt="비밀번호 숨김" />
- </button>
- </div>
- <p v-if="password2 && password !== password2" class="input--info" style="color:#e5484d;">
- 비밀번호가 일치하지 않습니다.
- </p>
- <div class="change--pw--box mt--25">
- <span>🔒 비밀번호 규칙</span>
- <ul>
- <li>8자 이상</li>
- <li>영문 소문자 + 숫자 + 특수문자 조합</li>
- <li>이전 비밀번호와 달라야 함</li>
- <li>아이디 포함 불가</li>
- </ul>
- </div>
- <div class="float--btn--wrap">
- <a
- href="#"
- :class="{ disabled: !canSubmit || submitting }"
- @click.prevent="handleReset"
- >{{ submitting ? '변경 중...' : '비밀번호 변경' }}</a>
- </div>
- </form>
- </div>
- </div>
- <AppAlertModal
- v-model="modal.show"
- :icon-type="modal.iconType"
- :title="modal.title"
- :message="modal.message"
- />
- </main>
- </template>
- <script setup>
- import { ref, computed, reactive, onMounted } from 'vue'
- import { useRouter } from 'vue-router'
- import AppAlertModal from '~/components/AppAlertModal.vue'
- const router = useRouter()
- const { post } = useApi()
- const password = ref('')
- const password2 = ref('')
- const showPw = ref(false)
- const showPw2 = ref(false)
- const submitting = ref(false)
- const resetToken = ref('')
- const modal = reactive({ show: false, iconType: 'error', title: '', message: '' })
- const showAlert = (title, message, iconType = 'error') => {
- modal.title = title
- modal.message = message
- modal.iconType = iconType
- modal.show = true
- }
- const PASSWORD_RE = /^(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>/?]).{8,}$/
- const passwordInvalid = computed(() =>
- password.value !== '' && !PASSWORD_RE.test(password.value)
- )
- const canSubmit = computed(() =>
- PASSWORD_RE.test(password.value) && password.value === password2.value
- )
- onMounted(() => {
- resetToken.value = sessionStorage.getItem('reset_token') || ''
- if (!resetToken.value) {
- // 인증 토큰 없으면 본인확인부터 다시
- showAlert('잘못된 접근', '본인 확인부터 진행해 주세요.')
- setTimeout(() => router.replace('/login/find'), 1000)
- }
- })
- const handleReset = async () => {
- if (!canSubmit.value || submitting.value) return
- submitting.value = true
- try {
- const { data, error } = await post('/users/reset-password', {
- reset_token: resetToken.value,
- new_password: password.value,
- })
- if (error || !data?.success) {
- return showAlert('변경 실패', error?.message || data?.message || '비밀번호 변경에 실패했습니다.')
- }
- sessionStorage.removeItem('reset_token')
- sessionStorage.removeItem('reset_username')
- router.push('/login/findPwComplete')
- } catch (e) {
- console.error(e)
- showAlert('오류', '서버 오류가 발생했습니다.')
- } finally {
- submitting.value = false
- }
- }
- </script>
|