Initial commit: expo-popcore project
This commit is contained in:
211
app/settings/index.tsx
Normal file
211
app/settings/index.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import Ionicons from '@expo/vector-icons/Ionicons';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { type Href, useRouter } from 'expo-router';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { authClient } from '@/lib/auth/client';
|
||||
|
||||
type Palette = {
|
||||
canvas: string;
|
||||
card: string;
|
||||
textPrimary: string;
|
||||
textSecondary: string;
|
||||
icon: string;
|
||||
stroke: string;
|
||||
buttonBackground: string;
|
||||
buttonText: string;
|
||||
};
|
||||
|
||||
type SettingDestination = {
|
||||
key: string;
|
||||
label: string;
|
||||
route?: Href;
|
||||
};
|
||||
|
||||
const palettes: Record<'dark' | 'light', Palette> = {
|
||||
dark: {
|
||||
canvas: '#050505',
|
||||
card: '#141417',
|
||||
textPrimary: '#F5F5F7',
|
||||
textSecondary: '#8E8E93',
|
||||
icon: '#F5F5F7',
|
||||
stroke: '#232327',
|
||||
buttonBackground: '#FFFFFF',
|
||||
buttonText: '#050505',
|
||||
},
|
||||
light: {
|
||||
canvas: '#F7F7F9',
|
||||
card: '#FFFFFF',
|
||||
textPrimary: '#131318',
|
||||
textSecondary: '#5C5C67',
|
||||
icon: '#131318',
|
||||
stroke: '#E4E4EA',
|
||||
buttonBackground: '#131318',
|
||||
buttonText: '#FFFFFF',
|
||||
},
|
||||
};
|
||||
|
||||
const destinations: SettingDestination[] = [
|
||||
{ key: 'change-password', label: 'Change Password', route: '/settings/account' },
|
||||
{ key: 'terms', label: 'Terms and Policies' },
|
||||
{ key: 'support', label: 'Feedback and Support' },
|
||||
];
|
||||
|
||||
export default function SettingsHomeScreen() {
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
const palette = palettes['dark'];
|
||||
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
||||
|
||||
const topInset = Math.max(insets.top, 16);
|
||||
const bottomInset = Math.max(insets.bottom + 16, 40);
|
||||
|
||||
const handleNavigate = (destination: SettingDestination) => {
|
||||
if (!destination.route) {
|
||||
return;
|
||||
}
|
||||
router.push(destination.route);
|
||||
};
|
||||
|
||||
const handleLogOut = async () => {
|
||||
if (isLoggingOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoggingOut(true);
|
||||
|
||||
try {
|
||||
await authClient.signOut();
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : 'Please try again in a moment.';
|
||||
Alert.alert('Unable to log out', message);
|
||||
} finally {
|
||||
setIsLoggingOut(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[styles.screen, { paddingTop: topInset, backgroundColor: palette.canvas }]}>
|
||||
<StatusBar style={'light'} />
|
||||
|
||||
<View style={styles.headerRow}>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
style={styles.headerControl}
|
||||
onPress={() => router.back()}
|
||||
>
|
||||
<Ionicons name="chevron-back" size={22} color={palette.icon} />
|
||||
</Pressable>
|
||||
<Text style={[styles.headerTitle, { color: palette.textPrimary }]}>set up</Text>
|
||||
<View style={styles.headerControl} />
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={[styles.card, { backgroundColor: palette.card }]}>
|
||||
{destinations.map((destination, index) => {
|
||||
const isLast = index === destinations.length - 1;
|
||||
return (
|
||||
<Pressable
|
||||
key={destination.key}
|
||||
accessibilityRole={destination.route ? 'button' : 'none'}
|
||||
disabled={!destination.route}
|
||||
onPress={() => handleNavigate(destination)}
|
||||
style={({ pressed }) => [
|
||||
styles.optionRow,
|
||||
!isLast && { borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: palette.stroke },
|
||||
pressed && destination.route && { opacity: 0.6 },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.optionLabel, { color: palette.textPrimary }]}>
|
||||
{destination.label}
|
||||
</Text>
|
||||
<Ionicons name="chevron-forward" size={18} color={palette.textSecondary} />
|
||||
</Pressable>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={[styles.footer, { paddingBottom: bottomInset }]}>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
disabled={isLoggingOut}
|
||||
onPress={handleLogOut}
|
||||
style={({ pressed }) => [
|
||||
styles.logoutButton,
|
||||
{ backgroundColor: palette.buttonBackground },
|
||||
pressed && { opacity: 0.9 },
|
||||
]}
|
||||
>
|
||||
{isLoggingOut ? (
|
||||
<ActivityIndicator size="small" color={palette.buttonText} />
|
||||
) : (
|
||||
<Text style={[styles.logoutLabel, { color: palette.buttonText }]}>Log out</Text>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
screen: {
|
||||
flex: 1,
|
||||
},
|
||||
headerRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 32,
|
||||
},
|
||||
headerControl: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
letterSpacing: 0.4,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
card: {
|
||||
borderRadius: 18,
|
||||
},
|
||||
optionRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: 64,
|
||||
},
|
||||
optionLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
},
|
||||
footer: {
|
||||
paddingTop: 32,
|
||||
},
|
||||
logoutButton: {
|
||||
borderRadius: 26,
|
||||
height: 56,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
logoutLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user