Activity Hooks
Headless hooks for interactive activities: quizzes, spin wheels, forms, polls, and surveys.
Every activity hook follows the same pattern: accept a config (from useEngagementData), manage interaction state locally, submit to the server on completion, and return actionResults with points awarded, badges unlocked, rewards claimed, and challenge progress.
useQuiz
Full quiz state — question navigation, answer tracking, client-side scoring, and server-side action execution.
const quiz = useQuiz({
engagementId: 'YOUR_UUID',
activityId: 'QUIZ_COMPONENT_ID',
config: quizConfig, // from useEngagementData().getQuizConfig()
});
// Navigation
quiz.currentQuestion // { question: string, options: string[], ... }
quiz.currentIndex // number (0-based)
quiz.totalQuestions // number
quiz.isFirstQuestion // boolean
quiz.isLastQuestion // boolean
quiz.progress // number (0-100)
quiz.next() // Go to next question
quiz.previous() // Go to previous question
quiz.goTo(index) // Jump to specific question
// Answers
quiz.selectedAnswer // number | null (selected option index)
quiz.answers // (number | null)[] (all answers)
quiz.selectAnswer(i) // Select an option
// Submission
quiz.submit() // Submit answers (async — calls server)
quiz.isSubmitting // boolean
// Results (after submit)
quiz.isComplete // boolean
quiz.score // { score, maxScore, percentage, passed }
quiz.feedback // { title, message } (performance-based)
quiz.actionResults // Server results: points, badges, rewards
quiz.reset() // Reset for retryuseSpinWheel
Two-step spin flow: call spin() to get the result from the server, animate your wheel to the target angle, then call confirmResult() to record the completion.
const wheel = useSpinWheel({
engagementId: 'YOUR_UUID',
activityId: 'WHEEL_COMPONENT_ID',
config: spinWheelConfig,
});
// State
wheel.segments // SpinWheelSegment[] — segment labels, colors, weights
wheel.isSpinning // boolean
wheel.result // SpinWheelResult | null (after spin)
wheel.rotation // number — target rotation degrees for CSS animation
wheel.actionResults // Server results after confirmResult()
// Actions
await wheel.spin() // Call server, get result + target rotation
await wheel.confirmResult() // After animation ends — record completion
wheel.reset() // Reset for another spinwheel.rotation with a CSS transform: rotate() transition. Call wheel.confirmResult() in the onTransitionEnd callback.useForm
Form field management with validation, touched tracking, and submission.
const form = useForm({
engagementId: 'YOUR_UUID',
activityId: 'FORM_COMPONENT_ID',
config: formConfig,
});
// Fields
form.fields // FormField[] — field definitions (label, type, required, etc.)
form.values // Record<string, unknown> — current values
form.errors // Record<string, string> — validation errors
form.touched // Record<string, boolean> — which fields have been touched
// State
form.isValid // boolean — all fields pass validation
form.isSubmitting // boolean
form.actionResults // Server results after submit
// Actions
form.setValue(fieldId, value) // Update a field value
form.setTouched(fieldId) // Mark a field as touched (show validation)
form.validate() // Run validation on all fields
form.submit() // Submit the form (async)
form.reset() // Reset all valuesusePoll
Single or multi-select poll with live results.
const poll = usePoll({
engagementId: 'YOUR_UUID',
activityId: 'POLL_COMPONENT_ID',
config: pollConfig,
});
poll.question // string
poll.options // PollOption[] — { id, label }
poll.selectedOptions // string[] — selected option IDs
poll.isMultiSelect // boolean
poll.isSubmitted // boolean
poll.results // PollResults | null — vote counts per option
poll.actionResults // Server results
poll.select(optionId) // Toggle an option
poll.submit() // Submit votes
poll.reset() // ResetuseSurvey
Multi-question survey with navigation and progress tracking.
const survey = useSurvey({
engagementId: 'YOUR_UUID',
activityId: 'SURVEY_COMPONENT_ID',
config: surveyConfig,
});
survey.questions // SurveyQuestion[]
survey.currentIndex // number
survey.totalQuestions // number
survey.progress // number (0-100)
survey.responses // Record<string, unknown>
survey.isComplete // boolean
survey.isSubmitting // boolean
survey.actionResults // Server results
survey.setResponse(questionId, value)
survey.next()
survey.previous()
survey.submit()
survey.reset()