mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Replaces the notify-me quiz stub with a full loop: quiz sessions per couple, answer-and-guess flow, dual-direction scoring, and a score-only share card (no question or answer content) captured via ViewShot with Sauci branding. API: migration 0019 (quiz_questions, quiz_sessions, quiz_answers, 12 seeded questions), new quiz domain with session start / current / answers / result routes, couple isolation, route + integration + scoring unit tests. Mobile: src/features/quiz feature (intro, per-question self+guess flow, waiting-for-partner nudge, results with breakdown), quizStore with sign-out clearing, QuizShareModal following SharePreviewModal, discovery QuizTile, analytics events, and tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
107 lines
2.9 KiB
TypeScript
107 lines
2.9 KiB
TypeScript
import { ActivityIndicator, View, StyleSheet } from "react-native";
|
|
import { GradientBackground } from "../../components/ui";
|
|
import { featureColors } from "../../theme";
|
|
import { SwipeNoPartnerState } from "../swipe/components/SwipeNoPartnerState";
|
|
import { useQuizScreen } from "./hooks/useQuizScreen";
|
|
import {
|
|
QuizIntro,
|
|
QuizQuestionCard,
|
|
QuizResults,
|
|
QuizShareModal,
|
|
QuizWaitingState,
|
|
} from "./components";
|
|
|
|
export function QuizScreen() {
|
|
const {
|
|
screenState,
|
|
session,
|
|
result,
|
|
currentStep,
|
|
totalQuestions,
|
|
isStarting,
|
|
isSubmitting,
|
|
isLoadingResult,
|
|
shareModalVisible,
|
|
handleSelectOption,
|
|
handleStart,
|
|
handleNewQuiz,
|
|
handleRefresh,
|
|
handlePairPress,
|
|
handleNudgePartner,
|
|
openShareModal,
|
|
closeShareModal,
|
|
} = useQuizScreen();
|
|
|
|
if (screenState === "not_paired") {
|
|
return <SwipeNoPartnerState hasCouple={false} onPairPress={handlePairPress} />;
|
|
}
|
|
|
|
if (screenState === "loading") {
|
|
return (
|
|
<GradientBackground>
|
|
<View style={styles.loadingContainer}>
|
|
<ActivityIndicator size="large" color={featureColors.quiz.accent} />
|
|
</View>
|
|
</GradientBackground>
|
|
);
|
|
}
|
|
|
|
if (screenState === "intro") {
|
|
return <QuizIntro isStarting={isStarting} onStart={handleStart} />;
|
|
}
|
|
|
|
if (screenState === "waiting") {
|
|
return <QuizWaitingState onNudgePartner={handleNudgePartner} onRefresh={handleRefresh} />;
|
|
}
|
|
|
|
if (screenState === "results") {
|
|
return (
|
|
<>
|
|
<QuizResults
|
|
result={result}
|
|
isLoadingResult={isLoadingResult}
|
|
isStarting={isStarting}
|
|
onNewQuiz={handleNewQuiz}
|
|
onShare={openShareModal}
|
|
/>
|
|
<QuizShareModal
|
|
visible={shareModalVisible}
|
|
onClose={closeShareModal}
|
|
scorePercent={result?.score_percent ?? 0}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// screenState === "answering"
|
|
if (!session || !currentStep || isSubmitting) {
|
|
return (
|
|
<GradientBackground>
|
|
<View style={styles.loadingContainer}>
|
|
<ActivityIndicator size="large" color={featureColors.quiz.accent} />
|
|
</View>
|
|
</GradientBackground>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<QuizQuestionCard
|
|
question={currentStep.question}
|
|
step={currentStep.step}
|
|
questionNumber={currentStep.questionNumber}
|
|
totalQuestions={totalQuestions}
|
|
onSelectOption={handleSelectOption}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
loadingContainer: {
|
|
flex: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
});
|
|
|
|
export default QuizScreen;
|