96 lines
4.4 KiB
JavaScript
96 lines
4.4 KiB
JavaScript
import React, { useRef, useEffect } from 'react';
|
|
import { View, Text, StyleSheet, Animated } from 'react-native';
|
|
import Button from '../Button';
|
|
import { colors, fonts, spacing, borderRadius } from '../../utils/theme';
|
|
import { getResultMessage, getStatLabel } from '../../services/gameService';
|
|
|
|
export default function GameResult({ gameType, score, details, onSave, onRetry, saving }) {
|
|
const fadeIn = useRef(new Animated.Value(0)).current;
|
|
const scaleScore = useRef(new Animated.Value(0)).current;
|
|
|
|
useEffect(() => {
|
|
Animated.sequence([
|
|
Animated.timing(fadeIn, { toValue: 1, duration: 400, useNativeDriver: true }),
|
|
Animated.spring(scaleScore, { toValue: 1, useNativeDriver: true, speed: 10, bounciness: 12 }),
|
|
]).start();
|
|
}, []);
|
|
|
|
const message = getResultMessage(gameType, score);
|
|
const statLabel = getStatLabel(gameType);
|
|
|
|
return (
|
|
<Animated.View style={[styles.container, { opacity: fadeIn }]}>
|
|
<Text style={styles.title}>Challenge Complete</Text>
|
|
|
|
<Animated.View style={[styles.scoreCard, { transform: [{ scale: scaleScore }] }]}>
|
|
<Text style={styles.scoreLabel}>Score</Text>
|
|
<Text style={styles.scoreValue}>{score}</Text>
|
|
<Text style={styles.statBonus}>+{statLabel}</Text>
|
|
</Animated.View>
|
|
|
|
<Text style={styles.message}>{message}</Text>
|
|
|
|
{details && (
|
|
<View style={styles.detailsCard}>
|
|
{details.avgReaction && (
|
|
<DetailRow label="Avg Reaction" value={`${details.avgReaction}ms`} />
|
|
)}
|
|
{details.rounds && (
|
|
<DetailRow label="Rounds" value={details.rounds} />
|
|
)}
|
|
{details.successes !== undefined && (
|
|
<DetailRow label="Successes" value={`${details.successes}/${details.rounds}`} />
|
|
)}
|
|
{details.perfects !== undefined && (
|
|
<>
|
|
<DetailRow label="Perfect" value={details.perfects} color={colors.accent} />
|
|
<DetailRow label="Good" value={details.goods} color={colors.success} />
|
|
<DetailRow label="Miss" value={details.misses} color={colors.error} />
|
|
</>
|
|
)}
|
|
{details.correct !== undefined && (
|
|
<DetailRow label="Correct" value={`${details.correct}/${details.rounds}`} />
|
|
)}
|
|
</View>
|
|
)}
|
|
|
|
<View style={styles.actions}>
|
|
<Button title="Save & Exit" onPress={onSave} loading={saving} style={styles.btn} />
|
|
<Button title="Play Again" onPress={onRetry} variant="secondary" style={styles.btn} />
|
|
</View>
|
|
</Animated.View>
|
|
);
|
|
}
|
|
|
|
function DetailRow({ label, value, color }) {
|
|
return (
|
|
<View style={styles.detailRow}>
|
|
<Text style={styles.detailLabel}>{label}</Text>
|
|
<Text style={[styles.detailValue, color && { color }]}>{value}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: spacing.lg },
|
|
title: { color: colors.accent, fontSize: fonts.sizes.xs, fontWeight: fonts.weights.bold, letterSpacing: 3, textTransform: 'uppercase', marginBottom: spacing.xl },
|
|
scoreCard: {
|
|
backgroundColor: colors.surface, borderRadius: borderRadius.xl, paddingVertical: spacing.xl, paddingHorizontal: spacing.xxl,
|
|
alignItems: 'center', borderWidth: 1, borderColor: colors.primary, marginBottom: spacing.lg,
|
|
shadowColor: colors.primary, shadowOffset: { width: 0, height: 0 }, shadowOpacity: 0.3, shadowRadius: 20, elevation: 8,
|
|
},
|
|
scoreLabel: { color: colors.textSecondary, fontSize: fonts.sizes.sm, marginBottom: spacing.xs },
|
|
scoreValue: { color: colors.text, fontSize: 56, fontWeight: fonts.weights.bold },
|
|
statBonus: { color: colors.primary, fontSize: fonts.sizes.sm, fontWeight: fonts.weights.semibold, marginTop: spacing.xs },
|
|
message: { color: colors.text, fontSize: fonts.sizes.md, textAlign: 'center', lineHeight: 24, marginBottom: spacing.xl, paddingHorizontal: spacing.md },
|
|
detailsCard: {
|
|
backgroundColor: colors.surface, borderRadius: borderRadius.md, padding: spacing.lg,
|
|
width: '100%', borderWidth: 1, borderColor: colors.border, marginBottom: spacing.xl,
|
|
},
|
|
detailRow: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: spacing.sm },
|
|
detailLabel: { color: colors.textSecondary, fontSize: fonts.sizes.sm },
|
|
detailValue: { color: colors.text, fontSize: fonts.sizes.sm, fontWeight: fonts.weights.semibold },
|
|
actions: { width: '100%' },
|
|
btn: { marginBottom: spacing.sm },
|
|
});
|