feat: add parent PIN setup functionality and email notifications
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 23s
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 23s
- Implemented User model updates to include PIN and related fields. - Created email sender utility for sending verification and reset emails. - Developed ParentPinSetup component for setting up a parent PIN with verification code. - Enhanced UserProfile and EntityEditForm components to support new features. - Updated routing to include PIN setup and authentication checks. - Added styles for new components and improved existing styles for consistency. - Introduced loading states and error handling in various components.
This commit is contained in:
@@ -3,8 +3,9 @@ import { ref, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { eventBus } from '@/common/eventBus'
|
||||
import { authenticateParent, isParentAuthenticated, logoutParent } from '../../stores/auth'
|
||||
import '@/assets/modal.css'
|
||||
import '@/assets/actions-shared.css'
|
||||
import '@/assets/styles.css'
|
||||
import '@/assets/colors.css'
|
||||
import ModalDialog from './ModalDialog.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const show = ref(false)
|
||||
@@ -14,6 +15,21 @@ const pinInput = ref<HTMLInputElement | null>(null)
|
||||
const dropdownOpen = ref(false)
|
||||
|
||||
const open = async () => {
|
||||
// Check if user has a pin
|
||||
try {
|
||||
const res = await fetch('/api/user/has-pin', { credentials: 'include' })
|
||||
const data = await res.json()
|
||||
if (!res.ok) throw new Error(data.error || 'Error checking PIN')
|
||||
if (!data.has_pin) {
|
||||
console.log('No PIN set, redirecting to setup')
|
||||
// Route to PIN setup view
|
||||
router.push('/parent/pin-setup')
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = 'Network error'
|
||||
return
|
||||
}
|
||||
pin.value = ''
|
||||
error.value = ''
|
||||
show.value = true
|
||||
@@ -26,22 +42,36 @@ const close = () => {
|
||||
error.value = ''
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
const submit = async () => {
|
||||
const isDigits = /^\d{4,6}$/.test(pin.value)
|
||||
if (!isDigits) {
|
||||
error.value = 'Enter 4–6 digits'
|
||||
return
|
||||
}
|
||||
|
||||
if (pin.value !== '1179') {
|
||||
error.value = 'Incorrect PIN'
|
||||
return
|
||||
try {
|
||||
const res = await fetch('/api/user/check-pin', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ pin: pin.value }),
|
||||
credentials: 'include',
|
||||
})
|
||||
const data = await res.json()
|
||||
if (!res.ok) {
|
||||
error.value = data.error || 'Error validating PIN'
|
||||
return
|
||||
}
|
||||
if (!data.valid) {
|
||||
error.value = 'Incorrect PIN'
|
||||
return
|
||||
}
|
||||
// Authenticate parent and navigate
|
||||
authenticateParent()
|
||||
close()
|
||||
router.push('/parent')
|
||||
} catch (e) {
|
||||
error.value = 'Network error'
|
||||
}
|
||||
|
||||
// Authenticate parent and navigate
|
||||
authenticateParent()
|
||||
close()
|
||||
router.push('/parent')
|
||||
}
|
||||
|
||||
const handleLogout = () => {
|
||||
@@ -117,27 +147,24 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="show" class="modal-backdrop" @click.self="close">
|
||||
<div class="modal">
|
||||
<h3>Enter parent PIN</h3>
|
||||
<form @submit.prevent="submit">
|
||||
<input
|
||||
ref="pinInput"
|
||||
v-model="pin"
|
||||
inputmode="numeric"
|
||||
pattern="\d*"
|
||||
maxlength="6"
|
||||
placeholder="4–6 digits"
|
||||
class="pin-input"
|
||||
/>
|
||||
<div class="actions">
|
||||
<button type="button" class="btn btn-secondary" @click="close">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">OK</button>
|
||||
</div>
|
||||
</form>
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ModalDialog v-if="show" title="Enter parent PIN" @click.self="close" @close="close">
|
||||
<form @submit.prevent="submit">
|
||||
<input
|
||||
ref="pinInput"
|
||||
v-model="pin"
|
||||
inputmode="numeric"
|
||||
pattern="\d*"
|
||||
maxlength="6"
|
||||
placeholder="4–6 digits"
|
||||
class="pin-input"
|
||||
/>
|
||||
<div class="actions modal-actions">
|
||||
<button type="button" class="btn btn-secondary" @click="close">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">OK</button>
|
||||
</div>
|
||||
</form>
|
||||
<div v-if="error" class="error modal-message">{{ error }}</div>
|
||||
</ModalDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user