Return

All tests / src/hooks useSurvey.ts

89.18% Statements 33/37
78.94% Branches 15/19
100% Functions 7/7
88.23% Lines 30/34

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 1101x 1x 1x 1x                                   1x             1x 12x 12x 12x   12x             1x         11x 11x     11x         17x                 1x 20x       20x 20x     20x   20x   20x   20x 2x     20x 1x       20x         11x   20x                         20x    
import { useRouter } from 'next/router';
import { useMemo, useReducer } from 'react';
import { buildSurveyQuestions, sanitizeSurveyName, DEFAULT_SURVEY_NAME, type Question } from '@/constants/survey';
import surveyCopy from '../intl/survey';
 
interface Answer {
    question: string;
    answer: string;
    isCorrect: boolean;
    questionNum: number;
}
 
interface SurveyState {
    currentQuestion: number;
    questionsDone: number;
    success: boolean;
    answers: Answer[];
}
 
type SurveyAction = { type: 'NEXT_QUESTION' } | { type: 'PREVIOUS_QUESTION' } | { type: 'ADD_ANSWER'; payload: Answer };
 
const initialState: SurveyState = {
    currentQuestion: 0,
    questionsDone: 0,
    success: false,
    answers: [],
};
 
const reducer = (state: SurveyState, action: SurveyAction): SurveyState => {
    const { questionNum } = 'payload' in action ? action.payload : ({} as Partial<Answer>);
    const { answers, questionsDone, currentQuestion } = state;
    const newAnswers: Answer[] = [...answers];
 
    switch (action.type) {
        case 'NEXT_QUESTION':
            return {
                ...state,
                currentQuestion: currentQuestion + 1,
            };
        case 'PREVIOUS_QUESTION':
            return {
                ...state,
                currentQuestion: currentQuestion - 1,
            };
        case 'ADD_ANSWER':
            if (questionNum !== undefined) {
                newAnswers[questionNum] = {
                    ...action.payload,
                };
                return {
                    ...state,
                    answers: newAnswers,
                    currentQuestion: currentQuestion + 1,
                    questionsDone: questionNum > questionsDone ? questionNum : questionsDone,
                    success: newAnswers.every((answer) => answer.isCorrect) && currentQuestion === 10,
                };
            }
            return state;
        default:
            return state;
    }
};
 
const useSurvey = () => {
    const { query, locale } = useRouter();
    // SDD-L07: the default only covered the non-array branch. `?name=` repeated in the query string
    // gives Next an array, and an empty one gives `undefined` — which then reached
    // `sanitizeSurveyName` as a string it was not typed to receive.
    const rawName = (Array.isArray(query.name) ? query.name[0] : query.name) ?? DEFAULT_SURVEY_NAME;
    const name = sanitizeSurveyName(rawName);
    // SDD-L08-T7: the whole questionnaire was Spanish literals. The copy now follows the route's
    // locale; which answers count as a match does not, and stays in constants/survey.tsx.
    const copy = surveyCopy(locale);
 
    const [state, dispatch] = useReducer(reducer, initialState);
 
    const questions = useMemo(() => buildSurveyQuestions(name, state.success, copy), [name, state.success, copy]);
 
    const handlePreviousQuestion = () => {
        if (state.currentQuestion > 1) dispatch({ type: 'PREVIOUS_QUESTION' });
    };
 
    const handleNextQuestion = () => {
        Iif (state.currentQuestion !== 0 && state.questionsDone >= state.currentQuestion)
            dispatch({ type: 'NEXT_QUESTION' });
    };
 
    const handleAnswerOptionClick = (payload: {
        question: string;
        answer: string;
        isCorrect: boolean;
        questionNum: number;
    }) => dispatch({ type: 'ADD_ANSWER', payload });
 
    return {
        questions,
        answers: state.answers,
        surveySuccess: state.success,
        currentQuestionNum: state.currentQuestion,
        questionsDoneNum: state.questionsDone,
        totalQuestions: questions.length,
        handleAnswerOptionClick,
        handleNextQuestion,
        handlePreviousQuestion,
    };
};
 
export default useSurvey;
export type { Question };