feat: remove hashed passwords feature spec and migrate to archive
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 2m6s

fix: update login token expiration to 62 days

chore: bump version to 1.0.5RC1

test: add isParentPersistent to LoginButton.spec.ts

refactor: rename Assign Tasks button to Assign Chores in ParentView.vue

refactor: rename Assign Tasks to Assign Chores in TaskAssignView.vue

feat: add stay in parent mode checkbox and badge in LoginButton.vue

test: enhance LoginButton.spec.ts with persistent mode tests

test: add authGuard.spec.ts for logoutParent and enforceParentExpiry

feat: implement parent mode expiry logic in auth.ts

test: add auth.expiry.spec.ts for parent mode expiry tests

chore: create template for feature specs
This commit is contained in:
2026-02-20 16:31:13 -05:00
parent ba909100a7
commit 55e7dc7568
15 changed files with 657 additions and 38 deletions

View File

@@ -5,6 +5,7 @@ import { eventBus } from '@/common/eventBus'
import {
authenticateParent,
isParentAuthenticated,
isParentPersistent,
logoutParent,
logoutUser,
} from '../../stores/auth'
@@ -16,6 +17,7 @@ const router = useRouter()
const show = ref(false)
const pin = ref('')
const error = ref('')
const stayInParentMode = ref(false)
const pinInput = ref<HTMLInputElement | null>(null)
const dropdownOpen = ref(false)
const dropdownRef = ref<HTMLElement | null>(null)
@@ -102,6 +104,7 @@ const open = async () => {
const close = () => {
show.value = false
error.value = ''
stayInParentMode.value = false
}
const submit = async () => {
@@ -131,7 +134,7 @@ const submit = async () => {
return
}
// Authenticate parent and navigate
authenticateParent()
authenticateParent(stayInParentMode.value)
close()
router.push('/parent')
} catch (e) {
@@ -281,6 +284,12 @@ onUnmounted(() => {
/>
<span v-else class="avatar-text">{{ profileLoading ? '...' : avatarInitial }}</span>
</button>
<span
v-if="isParentAuthenticated && isParentPersistent"
class="persistent-badge"
aria-label="Persistent parent mode active"
>🔒</span
>
<Transition name="slide-fade">
<div
@@ -371,6 +380,10 @@ onUnmounted(() => {
placeholder="46 digits"
class="pin-input"
/>
<label class="stay-label">
<input type="checkbox" v-model="stayInParentMode" class="stay-checkbox" />
Stay in parent mode on this device
</label>
<div class="actions modal-actions">
<button type="button" class="btn btn-secondary" @click="close">Cancel</button>
<button type="submit" class="btn btn-primary" :disabled="pin.length < 4">OK</button>
@@ -445,11 +458,40 @@ onUnmounted(() => {
font-size: 1rem;
border-radius: 8px;
border: 1px solid #e6e6e6;
margin-bottom: 0.6rem;
margin-bottom: 0.8rem;
box-sizing: border-box;
text-align: center;
}
.stay-label {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
color: var(--form-label, #444);
cursor: pointer;
margin-bottom: 1rem;
user-select: none;
}
.stay-checkbox {
width: 16px;
height: 16px;
accent-color: var(--btn-primary, #667eea);
cursor: pointer;
flex-shrink: 0;
}
.persistent-badge {
position: absolute;
bottom: -2px;
left: -2px;
font-size: 10px;
line-height: 1;
pointer-events: none;
user-select: none;
}
.dropdown-menu {
position: absolute;
right: 0;