mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
feat(quiz): couples quiz with shareable watermarked results card
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>
This commit is contained in:
1 parent
30aa7bc386
commit
6523ddeb1c
40 files changed
+2973
-237
No files matched your search
@@ -0,0 +1,106 @@
|
||||
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;
|
||||
Reference in new issue
Block a user