Refactor and enhance various components and tests
All checks were successful
Chore App Build and Push Docker Images / build-and-push (push) Successful in 1m23s

- Remove OverrideEditModal.spec.ts test file.
- Update ParentPinSetup.vue to handle Enter key for code and PIN inputs.
- Modify ChildEditView.vue to add maxlength for age input.
- Enhance ChildView.vue with reward confirmation and cancellation dialogs.
- Update ParentView.vue to handle pending rewards and confirm edits.
- Revise PendingRewardDialog.vue to accept a dynamic message prop.
- Expand ChildView.spec.ts to cover reward dialog interactions.
- Add tests for ParentView.vue to validate pending reward handling.
- Update UserProfile.vue to simplify button styles.
- Adjust RewardView.vue to improve delete confirmation handling.
- Modify ChildrenListView.vue to clarify child creation instructions.
- Refactor EntityEditForm.vue to improve input handling and focus management.
- Enhance ItemList.vue to support item selection.
- Update LoginButton.vue to focus PIN input on error.
- Change ScrollingList.vue empty state color for better visibility.
- Remove capture attribute from ImagePicker.vue file input.
- Update router/index.ts to redirect logged-in users from auth routes.
- Add authGuard.spec.ts to test router authentication logic.
This commit is contained in:
2026-02-19 09:57:59 -05:00
parent 31ea76f013
commit 725bf518ea
21 changed files with 630 additions and 445 deletions

View File

@@ -4,6 +4,8 @@ import { useRoute, useRouter } from 'vue-router'
import ChildDetailCard from './ChildDetailCard.vue'
import ScrollingList from '../shared/ScrollingList.vue'
import StatusMessage from '../shared/StatusMessage.vue'
import RewardConfirmDialog from './RewardConfirmDialog.vue'
import ModalDialog from '../shared/ModalDialog.vue'
import { eventBus } from '@/common/eventBus'
//import '@/assets/view-shared.css'
import '@/assets/styles.css'
@@ -31,6 +33,9 @@ const rewards = ref<string[]>([])
const loading = ref(true)
const error = ref<string | null>(null)
const childRewardListRef = ref()
const showRewardDialog = ref(false)
const showCancelDialog = ref(false)
const dialogReward = ref<RewardStatus | null>(null)
function handleTaskTriggered(event: Event) {
const payload = event.payload as ChildTaskTriggeredEventPayload
@@ -193,6 +198,60 @@ const triggerReward = (reward: RewardStatus) => {
window.speechSynthesis.speak(utter)
}
}
if (reward.redeeming) {
dialogReward.value = reward
showCancelDialog.value = true
return
}
if (reward.points_needed <= 0) {
dialogReward.value = reward
showRewardDialog.value = true
}
}
function cancelRedeemReward() {
showRewardDialog.value = false
dialogReward.value = null
}
function closeCancelDialog() {
showCancelDialog.value = false
dialogReward.value = null
}
async function confirmRedeemReward() {
if (!child.value?.id || !dialogReward.value) return
try {
const resp = await fetch(`/api/child/${child.value.id}/request-reward`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reward_id: dialogReward.value.id }),
})
if (!resp.ok) return
} catch (err) {
console.error('Failed to redeem reward:', err)
} finally {
showRewardDialog.value = false
dialogReward.value = null
}
}
async function cancelPendingReward() {
if (!child.value?.id || !dialogReward.value) return
try {
const resp = await fetch(`/api/child/${child.value.id}/cancel-request-reward`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reward_id: dialogReward.value.id }),
})
if (!resp.ok) throw new Error('Failed to cancel pending reward')
} catch (err) {
console.error('Failed to cancel pending reward:', err)
} finally {
showCancelDialog.value = false
dialogReward.value = null
}
}
async function fetchChildData(id: string | number) {
@@ -392,6 +451,32 @@ onUnmounted(() => {
</div>
</div>
</div>
<!-- Redeem reward dialog -->
<RewardConfirmDialog
v-if="showRewardDialog"
:reward="dialogReward"
:childName="child?.name"
@confirm="confirmRedeemReward"
@cancel="cancelRedeemReward"
/>
<!-- Cancel pending reward dialog -->
<ModalDialog
v-if="showCancelDialog && dialogReward"
:imageUrl="dialogReward.image_url"
:title="dialogReward.name"
subtitle="Reward Pending"
@backdrop-click="closeCancelDialog"
>
<div class="modal-message">
This reward is pending.<br />Would you like to cancel the request?
</div>
<div class="modal-actions">
<button @click="cancelPendingReward" class="btn btn-primary">Yes</button>
<button @click="closeCancelDialog" class="btn btn-secondary">No</button>
</div>
</ModalDialog>
</template>
<style scoped>
@@ -480,4 +565,16 @@ onUnmounted(() => {
pointer-events: none;
filter: grayscale(0.7);
}
.modal-message {
margin-bottom: 1.2rem;
font-size: 1rem;
color: var(--modal-message-color, #333);
}
.modal-actions {
display: flex;
gap: 1rem;
justify-content: center;
}
</style>