212 lines
6.3 KiB
TypeScript
212 lines
6.3 KiB
TypeScript
import React from 'react';
|
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
|
|
import { PreferencePill } from '@/components/common/PreferencePill';
|
|
import { ScreenContainer } from '@/components/common/ScreenContainer';
|
|
import { shootingStyleOptions } from '@/data/shootingStyles';
|
|
import { useAppStore } from '@/store/useAppStore';
|
|
import { colors } from '@/theme/colors';
|
|
import { spacing } from '@/theme/spacing';
|
|
import { TargetFacePreference } from '@/types';
|
|
|
|
function formatTargetFace(targetFace: TargetFacePreference): string {
|
|
return targetFace === 'single-face' ? 'Single Face' : 'Multi Face';
|
|
}
|
|
|
|
export function ProfileScreen(): React.JSX.Element {
|
|
const archerProfile = useAppStore((state) => state.archerProfile);
|
|
const toggleStyleEnabled = useAppStore((state) => state.toggleStyleEnabled);
|
|
const setStyleTargetFace = useAppStore((state) => state.setStyleTargetFace);
|
|
const setActiveStyle = useAppStore((state) => state.setActiveStyle);
|
|
|
|
const activePreference = archerProfile.stylePreferences.find(
|
|
(preference) => preference.styleId === archerProfile.activeStyleId
|
|
);
|
|
const activeStyle = shootingStyleOptions.find((style) => style.id === activePreference?.styleId);
|
|
|
|
return (
|
|
<ScreenContainer>
|
|
<Text style={styles.title}>Archer profile</Text>
|
|
<Text style={styles.subtitle}>
|
|
Set up the shooting styles you use locally and choose the default target-face layout for
|
|
each one. Later, practice and league sessions can read these preferences automatically.
|
|
</Text>
|
|
|
|
<View style={styles.summaryCard}>
|
|
<Text style={styles.summaryLabel}>Current default setup</Text>
|
|
<Text style={styles.summaryValue}>
|
|
{activePreference && activeStyle
|
|
? `${activeStyle.label} • ${formatTargetFace(activePreference.defaultTargetFace)}`
|
|
: 'No default shooting style selected yet'}
|
|
</Text>
|
|
</View>
|
|
|
|
<View style={styles.list}>
|
|
{shootingStyleOptions.map((style) => {
|
|
const preference = archerProfile.stylePreferences.find(
|
|
(entry) => entry.styleId === style.id
|
|
);
|
|
const isEnabled = Boolean(preference?.enabled);
|
|
const isActive = archerProfile.activeStyleId === style.id;
|
|
|
|
return (
|
|
<View key={style.id} style={[styles.styleCard, isActive && styles.styleCardActive]}>
|
|
<View style={styles.styleHeader}>
|
|
<View style={styles.styleText}>
|
|
<Text style={styles.styleTitle}>{style.label}</Text>
|
|
<Text style={styles.styleDescription}>{style.description}</Text>
|
|
</View>
|
|
<Pressable
|
|
onPress={() => toggleStyleEnabled(style.id)}
|
|
style={[styles.enableButton, isEnabled && styles.enableButtonEnabled]}
|
|
>
|
|
<Text style={[styles.enableButtonText, isEnabled && styles.enableButtonTextEnabled]}>
|
|
{isEnabled ? 'Enabled' : 'Enable'}
|
|
</Text>
|
|
</Pressable>
|
|
</View>
|
|
|
|
<View style={styles.inlineRow}>
|
|
<PreferencePill
|
|
label="Set Default"
|
|
selected={isActive}
|
|
onPress={() => setActiveStyle(style.id)}
|
|
/>
|
|
<Text style={styles.helperText}>
|
|
{isEnabled
|
|
? 'Ready to be used as the default style for new sessions.'
|
|
: 'Enable this style before making it your default.'}
|
|
</Text>
|
|
</View>
|
|
|
|
<View style={styles.targetFaceSection}>
|
|
<Text style={styles.targetFaceLabel}>Default target face</Text>
|
|
<View style={styles.pillRow}>
|
|
<PreferencePill
|
|
label="Single Face"
|
|
selected={preference?.defaultTargetFace === 'single-face'}
|
|
onPress={() => setStyleTargetFace(style.id, 'single-face')}
|
|
/>
|
|
<PreferencePill
|
|
label="Multi Face"
|
|
selected={preference?.defaultTargetFace === 'multi-face'}
|
|
onPress={() => setStyleTargetFace(style.id, 'multi-face')}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
</ScreenContainer>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
title: {
|
|
fontSize: 30,
|
|
fontWeight: '800',
|
|
color: colors.text,
|
|
},
|
|
subtitle: {
|
|
color: colors.muted,
|
|
lineHeight: 22,
|
|
},
|
|
summaryCard: {
|
|
borderRadius: 20,
|
|
padding: spacing.md,
|
|
backgroundColor: colors.surfaceAlt,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
gap: spacing.xs,
|
|
},
|
|
summaryLabel: {
|
|
color: colors.muted,
|
|
fontSize: 13,
|
|
textTransform: 'uppercase',
|
|
letterSpacing: 1,
|
|
fontWeight: '700',
|
|
},
|
|
summaryValue: {
|
|
color: colors.text,
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
},
|
|
list: {
|
|
gap: spacing.md,
|
|
},
|
|
styleCard: {
|
|
borderRadius: 22,
|
|
padding: spacing.md,
|
|
backgroundColor: colors.surfaceAlt,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
gap: spacing.md,
|
|
},
|
|
styleCardActive: {
|
|
borderColor: colors.primary,
|
|
shadowColor: colors.primary,
|
|
shadowOpacity: 0.18,
|
|
shadowRadius: 14,
|
|
shadowOffset: { width: 0, height: 6 },
|
|
elevation: 3,
|
|
},
|
|
styleHeader: {
|
|
flexDirection: 'row',
|
|
gap: spacing.md,
|
|
alignItems: 'flex-start',
|
|
},
|
|
styleText: {
|
|
flex: 1,
|
|
gap: spacing.xs,
|
|
},
|
|
styleTitle: {
|
|
color: colors.text,
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
},
|
|
styleDescription: {
|
|
color: colors.muted,
|
|
lineHeight: 20,
|
|
},
|
|
enableButton: {
|
|
borderRadius: 999,
|
|
paddingHorizontal: spacing.md,
|
|
paddingVertical: spacing.sm,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
backgroundColor: colors.surface,
|
|
},
|
|
enableButtonEnabled: {
|
|
backgroundColor: colors.primary,
|
|
borderColor: colors.primarySoft,
|
|
},
|
|
enableButtonText: {
|
|
color: colors.text,
|
|
fontWeight: '700',
|
|
},
|
|
enableButtonTextEnabled: {
|
|
color: '#04111F',
|
|
},
|
|
inlineRow: {
|
|
gap: spacing.sm,
|
|
},
|
|
helperText: {
|
|
color: colors.muted,
|
|
lineHeight: 20,
|
|
},
|
|
targetFaceSection: {
|
|
gap: spacing.sm,
|
|
},
|
|
targetFaceLabel: {
|
|
color: colors.text,
|
|
fontWeight: '700',
|
|
},
|
|
pillRow: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
gap: spacing.sm,
|
|
},
|
|
});
|
|
|