init claude-code
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import { useCallback, useReducer } from 'react'
|
||||
|
||||
export type AnswerValue = string
|
||||
|
||||
export type QuestionState = {
|
||||
selectedValue?: string | string[]
|
||||
textInputValue: string
|
||||
}
|
||||
|
||||
type State = {
|
||||
currentQuestionIndex: number
|
||||
answers: Record<string, AnswerValue>
|
||||
questionStates: Record<string, QuestionState>
|
||||
isInTextInput: boolean
|
||||
}
|
||||
|
||||
type Action =
|
||||
| { type: 'next-question' }
|
||||
| { type: 'prev-question' }
|
||||
| {
|
||||
type: 'update-question-state'
|
||||
questionText: string
|
||||
updates: Partial<QuestionState>
|
||||
isMultiSelect: boolean
|
||||
}
|
||||
| {
|
||||
type: 'set-answer'
|
||||
questionText: string
|
||||
answer: string
|
||||
shouldAdvance: boolean
|
||||
}
|
||||
| { type: 'set-text-input-mode'; isInInput: boolean }
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
switch (action.type) {
|
||||
case 'next-question':
|
||||
return {
|
||||
...state,
|
||||
currentQuestionIndex: state.currentQuestionIndex + 1,
|
||||
isInTextInput: false,
|
||||
}
|
||||
|
||||
case 'prev-question':
|
||||
return {
|
||||
...state,
|
||||
currentQuestionIndex: Math.max(0, state.currentQuestionIndex - 1),
|
||||
isInTextInput: false,
|
||||
}
|
||||
|
||||
case 'update-question-state': {
|
||||
const existing = state.questionStates[action.questionText]
|
||||
const newState: QuestionState = {
|
||||
selectedValue:
|
||||
action.updates.selectedValue ??
|
||||
existing?.selectedValue ??
|
||||
(action.isMultiSelect ? [] : undefined),
|
||||
textInputValue:
|
||||
action.updates.textInputValue ?? existing?.textInputValue ?? '',
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
questionStates: {
|
||||
...state.questionStates,
|
||||
[action.questionText]: newState,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
case 'set-answer': {
|
||||
const newState = {
|
||||
...state,
|
||||
answers: {
|
||||
...state.answers,
|
||||
[action.questionText]: action.answer,
|
||||
},
|
||||
}
|
||||
|
||||
if (action.shouldAdvance) {
|
||||
return {
|
||||
...newState,
|
||||
currentQuestionIndex: newState.currentQuestionIndex + 1,
|
||||
isInTextInput: false,
|
||||
}
|
||||
}
|
||||
|
||||
return newState
|
||||
}
|
||||
|
||||
case 'set-text-input-mode':
|
||||
return {
|
||||
...state,
|
||||
isInTextInput: action.isInInput,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const INITIAL_STATE: State = {
|
||||
currentQuestionIndex: 0,
|
||||
answers: {},
|
||||
questionStates: {},
|
||||
isInTextInput: false,
|
||||
}
|
||||
|
||||
export type MultipleChoiceState = {
|
||||
currentQuestionIndex: number
|
||||
answers: Record<string, AnswerValue>
|
||||
questionStates: Record<string, QuestionState>
|
||||
isInTextInput: boolean
|
||||
nextQuestion: () => void
|
||||
prevQuestion: () => void
|
||||
updateQuestionState: (
|
||||
questionText: string,
|
||||
updates: Partial<QuestionState>,
|
||||
isMultiSelect: boolean,
|
||||
) => void
|
||||
setAnswer: (
|
||||
questionText: string,
|
||||
answer: string,
|
||||
shouldAdvance?: boolean,
|
||||
) => void
|
||||
setTextInputMode: (isInInput: boolean) => void
|
||||
}
|
||||
|
||||
export function useMultipleChoiceState(): MultipleChoiceState {
|
||||
const [state, dispatch] = useReducer(reducer, INITIAL_STATE)
|
||||
|
||||
const nextQuestion = useCallback(() => {
|
||||
dispatch({ type: 'next-question' })
|
||||
}, [])
|
||||
|
||||
const prevQuestion = useCallback(() => {
|
||||
dispatch({ type: 'prev-question' })
|
||||
}, [])
|
||||
|
||||
const updateQuestionState = useCallback(
|
||||
(
|
||||
questionText: string,
|
||||
updates: Partial<QuestionState>,
|
||||
isMultiSelect: boolean,
|
||||
) => {
|
||||
dispatch({
|
||||
type: 'update-question-state',
|
||||
questionText,
|
||||
updates,
|
||||
isMultiSelect,
|
||||
})
|
||||
},
|
||||
[],
|
||||
)
|
||||
|
||||
const setAnswer = useCallback(
|
||||
(questionText: string, answer: string, shouldAdvance: boolean = true) => {
|
||||
dispatch({
|
||||
type: 'set-answer',
|
||||
questionText,
|
||||
answer,
|
||||
shouldAdvance,
|
||||
})
|
||||
},
|
||||
[],
|
||||
)
|
||||
|
||||
const setTextInputMode = useCallback((isInInput: boolean) => {
|
||||
dispatch({ type: 'set-text-input-mode', isInInput })
|
||||
}, [])
|
||||
|
||||
return {
|
||||
currentQuestionIndex: state.currentQuestionIndex,
|
||||
answers: state.answers,
|
||||
questionStates: state.questionStates,
|
||||
isInTextInput: state.isInTextInput,
|
||||
nextQuestion,
|
||||
prevQuestion,
|
||||
updateQuestionState,
|
||||
setAnswer,
|
||||
setTextInputMode,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user