feat: normalize email handling in signup, login, and verification processes; refactor event handling in task and reward components
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 50s
All checks were successful
Gitea Actions Demo / build-and-push (push) Successful in 50s
This commit is contained in:
@@ -32,7 +32,6 @@ const deletingChildId = ref<string | number | null>(null)
|
||||
const deleting = ref(false)
|
||||
|
||||
const openChildEditor = (child: Child, evt?: Event) => {
|
||||
console.log(' opening child editor for child id ', child.id)
|
||||
evt?.stopPropagation()
|
||||
router.push({ name: 'ChildEditView', params: { id: child.id } })
|
||||
}
|
||||
@@ -137,7 +136,6 @@ const fetchChildren = async (): Promise<Child[]> => {
|
||||
return Promise.resolve()
|
||||
}),
|
||||
)
|
||||
console.log(' fetched children list: ', childList)
|
||||
return childList
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Failed to fetch children'
|
||||
@@ -174,7 +172,6 @@ onUnmounted(() => {
|
||||
const shouldIgnoreNextCardClick = ref(false)
|
||||
|
||||
const onDocClick = (e: MouseEvent) => {
|
||||
console.log(' document click detected ')
|
||||
if (activeMenuFor.value !== null) {
|
||||
const path = (e.composedPath && e.composedPath()) || (e as any).path || []
|
||||
const clickedInsideKebab = path.some((node: unknown) => {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import '@/assets/styles.css'
|
||||
import '@/assets/colors.css'
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
@@ -43,6 +45,17 @@ watch(
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import '@/assets/modal.css';
|
||||
@import '@/assets/actions-shared.css';
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 3rem;
|
||||
justify-content: center;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.actions .btn {
|
||||
padding: 1rem 2.2rem;
|
||||
font-weight: 700;
|
||||
font-size: 1.25rem;
|
||||
min-width: 120px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -100,11 +100,12 @@ function onAddImage({ id, file }: { id: string; file: File }) {
|
||||
|
||||
function onCancel() {
|
||||
emit('cancel')
|
||||
router.back()
|
||||
}
|
||||
|
||||
function submit() {
|
||||
emit('submit', { ...formData.value })
|
||||
// After submit, reset isDirty so Save button is disabled until next change
|
||||
isDirty.value = false
|
||||
}
|
||||
|
||||
// Editable field names (exclude custom fields that are not editable)
|
||||
|
||||
@@ -22,22 +22,24 @@ const loading = ref(true)
|
||||
const error = ref<string | null>(null)
|
||||
const selectedItems = ref<string[]>([])
|
||||
|
||||
function refresh() {
|
||||
fetchItems()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
items,
|
||||
selectedItems,
|
||||
refresh,
|
||||
})
|
||||
|
||||
const fetchItems = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
console.log(`Fetching items from: ${props.fetchUrl}`)
|
||||
try {
|
||||
const resp = await fetch(props.fetchUrl)
|
||||
console.log(`Fetch response status: ${resp.status}`)
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
||||
const data = await resp.json()
|
||||
//console log all data
|
||||
console.log('Fetched data:', data)
|
||||
let itemList = data[props.itemKey || 'items'] || []
|
||||
if (props.filterFn) itemList = itemList.filter(props.filterFn)
|
||||
const initiallySelected: string[] = []
|
||||
|
||||
@@ -13,6 +13,7 @@ const pin = ref('')
|
||||
const error = ref('')
|
||||
const pinInput = ref<HTMLInputElement | null>(null)
|
||||
const dropdownOpen = ref(false)
|
||||
const dropdownRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const open = async () => {
|
||||
// Check if user has a pin
|
||||
@@ -83,6 +84,10 @@ function toggleDropdown() {
|
||||
dropdownOpen.value = !dropdownOpen.value
|
||||
}
|
||||
|
||||
function closeDropdown() {
|
||||
dropdownOpen.value = false
|
||||
}
|
||||
|
||||
async function signOut() {
|
||||
try {
|
||||
await fetch('/api/logout', { method: 'POST' })
|
||||
@@ -91,18 +96,31 @@ async function signOut() {
|
||||
} catch {
|
||||
// Optionally show error
|
||||
}
|
||||
dropdownOpen.value = false
|
||||
closeDropdown()
|
||||
}
|
||||
|
||||
function goToProfile() {
|
||||
router.push('/parent/profile')
|
||||
closeDropdown()
|
||||
}
|
||||
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (
|
||||
dropdownOpen.value &&
|
||||
dropdownRef.value &&
|
||||
!dropdownRef.value.contains(event.target as Node)
|
||||
) {
|
||||
closeDropdown()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
eventBus.on('open-login', open)
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
eventBus.off('open-login', open)
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -111,7 +129,7 @@ onUnmounted(() => {
|
||||
<button v-if="!isParentAuthenticated" @click="open" aria-label="Parent login" class="login-btn">
|
||||
Parent
|
||||
</button>
|
||||
<div v-else style="display: inline-block; position: relative">
|
||||
<div v-else style="display: inline-block; position: relative" ref="dropdownRef">
|
||||
<button
|
||||
@click="toggleDropdown"
|
||||
aria-label="Parent menu"
|
||||
@@ -138,7 +156,16 @@ onUnmounted(() => {
|
||||
<button class="menu-item" @click="goToProfile" style="width: 100%; text-align: left">
|
||||
Profile
|
||||
</button>
|
||||
<button class="menu-item" @click="handleLogout" style="width: 100%; text-align: left">
|
||||
<button
|
||||
class="menu-item"
|
||||
@click="
|
||||
() => {
|
||||
handleLogout()
|
||||
closeDropdown()
|
||||
}
|
||||
"
|
||||
style="width: 100%; text-align: left"
|
||||
>
|
||||
Log out
|
||||
</button>
|
||||
<button class="menu-item danger" @click="signOut" style="width: 100%; text-align: left">
|
||||
|
||||
Reference in New Issue
Block a user