Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 18x 18x 1x 1x 12x 12x 18x 28x 28x 28x 28x 28x 28x 28x 3x 3x 3x 3x 3x 1x 1x 1x 2x 3x 28x 2x 2x 2x 28x 28x 28x 28x 28x 3x 3x 3x 3x 3x 1x 1x 1x 2x 3x 28x 2x 2x 2x 28x 28x 28x 28x 10x 10x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x | 'use client'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { api } from '@/lib/queryClient'
import { entryPromptKeys } from '@/lib/queryKeys'
export interface EntryPrompt {
id: string
teacherId: string
playerId: string
classroomId: string
expiresAt: string
status: 'pending' | 'accepted' | 'declined' | 'expired'
createdAt: string
player: {
id: string
name: string
emoji: string
}
classroom: {
id: string
name: string
}
teacher: {
displayName: string
}
}
/**
* Hook for parents to manage entry prompts for their children
*
* - Fetches pending entry prompts
* - Provides accept/decline mutations
* - Real-time updates handled by useParentSocket via query invalidation
*/
export function useEntryPrompts(enabled = true) {
const queryClient = useQueryClient()
// Fetch pending prompts
const {
data: prompts = [],
isLoading,
error,
} = useQuery({
queryKey: entryPromptKeys.pending(),
queryFn: async () => {
const response = await api('entry-prompts')
if (!response.ok) {
throw new Error('Failed to fetch entry prompts')
}
const data = await response.json()
return data.prompts as EntryPrompt[]
},
enabled,
refetchInterval: 30000, // Refresh every 30s to catch expired prompts
})
// Accept mutation
const acceptPrompt = useMutation({
mutationFn: async (promptId: string) => {
const response = await api(`entry-prompts/${promptId}/respond`, {
method: 'POST',
body: JSON.stringify({ action: 'accept' }),
})
if (!response.ok) {
const data = await response.json()
throw new Error(data.error || 'Failed to accept prompt')
}
return response.json()
},
onSuccess: () => {
// Invalidate prompts query to refresh the list
queryClient.invalidateQueries({ queryKey: entryPromptKeys.pending() })
},
})
// Decline mutation
const declinePrompt = useMutation({
mutationFn: async (promptId: string) => {
const response = await api(`entry-prompts/${promptId}/respond`, {
method: 'POST',
body: JSON.stringify({ action: 'decline' }),
})
if (!response.ok) {
const data = await response.json()
throw new Error(data.error || 'Failed to decline prompt')
}
return response.json()
},
onSuccess: () => {
// Invalidate prompts query to refresh the list
queryClient.invalidateQueries({ queryKey: entryPromptKeys.pending() })
},
})
// Filter out expired prompts on the client side
const activePrompts = prompts.filter((p) => {
const expiresAt = new Date(p.expiresAt)
return expiresAt > new Date() && p.status === 'pending'
})
return {
prompts: activePrompts,
isLoading,
error,
acceptPrompt: acceptPrompt.mutateAsync,
declinePrompt: declinePrompt.mutateAsync,
isAccepting: acceptPrompt.isPending,
isDeclining: declinePrompt.isPending,
acceptingPromptId: acceptPrompt.isPending ? acceptPrompt.variables : null,
decliningPromptId: declinePrompt.isPending ? declinePrompt.variables : null,
}
}
|