212 lines
5.4 KiB
TypeScript
212 lines
5.4 KiB
TypeScript
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',
|
|
},
|
|
});
|