Files
casadoc-app/src/components/AuthShell.tsx
T
2026-08-26 23:01:07 +03:00

110 lines
2.9 KiB
TypeScript

import React from 'react';
import {
KeyboardAvoidingView,
Platform,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import { colors, fontSize, radii, spacing } from '@/theme';
/** Shared frame for the signed-out screens: brand, title, scrollable body. */
export function AuthShell({
title,
subtitle,
back,
error,
children,
}: {
title: string;
subtitle?: string;
back?: boolean;
error?: string | null;
children: React.ReactNode;
}) {
const insets = useSafeAreaInsets();
const router = useRouter();
return (
<KeyboardAvoidingView
style={{ flex: 1, backgroundColor: colors.surface }}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
>
<ScrollView
contentContainerStyle={[
styles.container,
{ paddingTop: insets.top + spacing[5], paddingBottom: insets.bottom + spacing[6] },
]}
keyboardShouldPersistTaps="handled"
>
{back ? (
<Pressable onPress={() => router.back()} hitSlop={12} style={styles.back}>
<Ionicons name="chevron-back" size={24} color={colors.ink} />
</Pressable>
) : null}
<View style={styles.head}>
<View style={styles.mark}>
<Ionicons name="home" size={24} color={colors.onDark} />
</View>
<Text style={styles.title}>{title}</Text>
{subtitle ? <Text style={styles.subtitle}>{subtitle}</Text> : null}
</View>
{error ? (
<View style={styles.errorBox}>
<Ionicons name="alert-circle-outline" size={18} color={colors.dangerText} />
<Text style={styles.errorText}>{error}</Text>
</View>
) : null}
{children}
</ScrollView>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
container: { paddingHorizontal: spacing[5], flexGrow: 1 },
back: { alignSelf: 'flex-start', marginLeft: -6, marginBottom: spacing[2] },
head: { alignItems: 'center', marginBottom: spacing[7] },
mark: {
width: 54,
height: 54,
borderRadius: 16,
backgroundColor: colors.ink900,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: fontSize['2xl'],
fontWeight: '700',
color: colors.ink,
marginTop: spacing[4],
textAlign: 'center',
},
subtitle: {
fontSize: fontSize.sm,
color: colors.textMuted,
textAlign: 'center',
marginTop: 8,
maxWidth: 300,
lineHeight: 20,
},
errorBox: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: colors.dangerBg,
borderRadius: radii.md,
padding: spacing[3],
marginBottom: spacing[4],
},
errorText: { color: colors.dangerText, fontSize: fontSize.sm, flex: 1 },
});