ADD:API RESET -request and password and Refresh access token

This commit is contained in:
supalerk-ar66 2026-01-15 11:06:44 +07:00
parent c557c383e3
commit ae771420be
8 changed files with 55 additions and 29 deletions

View file

@ -1 +1 @@
{"id":"dev","timestamp":1768447757574}
{"id":"dev","timestamp":1768449730995}

View file

@ -1 +1 @@
{"id":"dev","timestamp":1768447757574,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
{"id":"dev","timestamp":1768449730995,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}

View file

@ -1,5 +1,5 @@
{
"date": "2026-01-15T03:29:24.697Z",
"date": "2026-01-15T04:02:21.792Z",
"preset": "nitro-dev",
"framework": {
"name": "nuxt",
@ -9,9 +9,9 @@
"nitro": "2.12.8"
},
"dev": {
"pid": 15120,
"pid": 1972,
"workerAddress": {
"socketPath": "\\\\.\\pipe\\nitro-worker-15120-1-1-7719.sock"
"socketPath": "\\\\.\\pipe\\nitro-worker-1972-1-1-5250.sock"
}
}
}

View file

@ -1,7 +1,7 @@
/// <reference types="quasar" />
/// <reference types="@nuxtjs/tailwindcss" />
/// <reference types="nuxt-quasar-ui" />
/// <reference types="@nuxt/devtools" />
/// <reference types="@nuxtjs/tailwindcss" />
/// <reference types="@nuxt/telemetry" />
/// <reference path="types/builder-env.d.ts" />
/// <reference types="nuxt" />

View file

@ -1,4 +1,4 @@
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 15/1/2569 10:29:18
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 15/1/2569 11:02:11
import "@nuxtjs/tailwindcss/config-ctx"
import configMerger from "@nuxtjs/tailwindcss/merger";

View file

@ -183,7 +183,7 @@ export const useAuth = () => {
}
// Confirm Reset Password
const confirmResetPassword = async (payload: { id: number; token: string; password: string }) => {
const confirmResetPassword = async (payload: { token: string; password: string }) => {
try {
const { error } = await useFetch(`${API_BASE_URL}/auth/reset-password`, {
method: 'POST',

View file

@ -24,7 +24,25 @@ const forgotForm = reactive({
})
const forgotRules = {
email: { rules: { required: true, email: true }, label: 'อีเมล' }
email: {
rules: {
required: true,
email: true,
custom: (val: string) => /[\u0E00-\u0E7F]/.test(val) ? 'ห้ามใส่ภาษาไทย' : null
},
label: 'อีเมล'
}
}
const handleInput = (val: string) => {
forgotForm.email = val
if (/[\u0E00-\u0E7F]/.test(val)) {
errors.value.email = 'ห้ามใส่ภาษาไทย'
} else {
if (errors.value.email === 'ห้ามใส่ภาษาไทย') {
clearFieldError('email')
}
}
}
const { requestPasswordReset } = useAuth()
@ -68,29 +86,19 @@ const sendResetLink = async () => {
<form v-if="forgotStep === 'initial'" @submit.prevent="sendResetLink">
<p class="text-slate-700 dark:text-slate-400 text-sm mb-6">กรณากรอกอเมลเพอรบลงกเซตรหณผาน</p>
<FormInput
v-model="forgotForm.email"
:model-value="forgotForm.email"
label="อีเมล"
type="email"
placeholder="student@example.com"
:error="errors.email"
required
@update:model-value="clearFieldError('email')"
@update:model-value="handleInput"
/>
<button type="submit" class="btn btn-primary w-full mb-4" :disabled="isLoading">
<LoadingSpinner v-if="isLoading" size="sm" />
<span v-else>ส่งลิงก์รีเซ็ต</span>
</button>
</form>
<!-- Step 2: Success Message -->
<div v-else style="text-align: center;">
<div style="font-size: 40px; margin-bottom: 16px;">📧</div>
<h3 class="font-bold mb-2">งลงกเรยบรอยแล</h3>
<p class="text-sm text-muted mb-6">กรณาตรวจสอบกลองจดหมายในอเมลของคณเพอดำเนนการรเซตรหสผาน</p>
<!-- Simulation: redirect to reset-password for demo -->
<NuxtLink to="/reset-password" class="btn btn-primary w-full mb-4">จำลองการคลกลงก (เพอการสาธ)</NuxtLink>
</div>
<!-- Navigation Links -->
<div class="text-center mt-6">
<NuxtLink to="/auth/login" class="text-sm font-bold text-slate-500 hover:text-slate-800 transition-colors">

View file

@ -26,12 +26,32 @@ const resetForm = reactive({
})
const resetRules = {
password: { rules: { required: true, minLength: 8 }, label: 'รหัสผ่านใหม่' },
password: {
rules: {
required: true,
minLength: 8,
custom: (val: string) => /[\u0E00-\u0E7F]/.test(val) ? 'ห้ามใส่ภาษาไทย' : null
},
label: 'รหัสผ่านใหม่'
},
confirmPassword: { rules: { required: true, match: 'password' }, label: 'ยืนยันรหัสผ่าน' }
}
const handlePasswordInput = (field: keyof typeof resetForm, val: string) => {
resetForm[field] = val
if (/[\u0E00-\u0E7F]/.test(val)) {
if (field === 'password') errors.value.password = 'ห้ามใส่ภาษาไทย'
// We don't necessarily need to flag confirmPassword individually if it just needs to match, but let's be consistent if we want
} else {
// Clear error if it was "Thai characters"
if (field === 'password' && errors.value.password === 'ห้ามใส่ภาษาไทย') {
clearFieldError('password')
}
}
}
onMounted(() => {
if (!route.query.token || !route.query.id) {
if (!route.query.token) {
alert('ลิงก์รีเซ็ตรหัสผ่านไม่ถูกต้องหรือหมดอายุ')
router.push('/auth/login')
}
@ -40,11 +60,10 @@ onMounted(() => {
const resetPassword = async () => {
if (!validate(resetForm, resetRules)) return
// Extract token and id from query
// Extract token from query
const token = route.query.token as string
const id = Number(route.query.id)
if (!token || !id) {
if (!token) {
alert('ข้อมูลสำหรับรีเซ็ตไม่ครบถ้วน')
return
}
@ -52,7 +71,6 @@ const resetPassword = async () => {
isLoading.value = true
const result = await confirmResetPassword({
id,
token,
password: resetForm.password
})
@ -90,13 +108,13 @@ const resetPassword = async () => {
<!-- New Password -->
<FormInput
v-model="resetForm.password"
:model-value="resetForm.password"
label="รหัสผ่านใหม่"
type="password"
placeholder="••••••••"
:error="errors.password"
required
@update:model-value="clearFieldError('password')"
@update:model-value="(val) => handlePasswordInput('password', val)"
/>
<!-- Confirm New Password -->