- Client: logRequests option + redacted request/response logging (setLogRequests to toggle at runtime); enabled via app extra.debugHttp for on-device 401 debugging - Dark mode (persisted) via ThemeProvider + React Navigation theme - New "Account" tab: Profile (view), Vehicles (full CRUD), Payment methods (view-only), About, dark-mode + request-logging toggles, sign out Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import React, { useCallback, useState } from 'react';
|
|
import { ActivityIndicator, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
import { useFocusEffect } from '@react-navigation/native';
|
|
import { ps } from '@/api/client';
|
|
import { useTheme } from '@/theme/ThemeContext';
|
|
import type { UserDetail } from 'parksmarter-client';
|
|
|
|
export function ProfileScreen() {
|
|
const { colors } = useTheme();
|
|
const [user, setUser] = useState<UserDetail | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
setLoading(true);
|
|
ps.getUserDetail()
|
|
.then(setUser)
|
|
.catch(() => setUser(null))
|
|
.finally(() => setLoading(false));
|
|
}, []),
|
|
);
|
|
|
|
if (loading) {
|
|
return (
|
|
<View style={[styles.center, { backgroundColor: colors.bg }]}>
|
|
<ActivityIndicator color={colors.primary} />
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const Row = ({ label, value }: { label: string; value?: string | number }) => (
|
|
<View style={[styles.row, { borderBottomColor: colors.border }]}>
|
|
<Text style={[styles.label, { color: colors.subtext }]}>{label}</Text>
|
|
<Text style={[styles.value, { color: colors.text }]}>{value ?? '—'}</Text>
|
|
</View>
|
|
);
|
|
|
|
return (
|
|
<ScrollView
|
|
style={{ backgroundColor: colors.bg }}
|
|
contentContainerStyle={{ padding: 16 }}
|
|
>
|
|
<View style={[styles.card, { backgroundColor: colors.card }]}>
|
|
<Row label="Email" value={user?.PersonalEmailAddress} />
|
|
<Row label="Phone" value={user?.PersonalPhone} />
|
|
<Row label="Vehicles" value={user?.VehicleDetails?.length ?? 0} />
|
|
<Row label="Cards" value={user?.CreditCardDetails?.length ?? 0} />
|
|
<Row
|
|
label="Marketing offers"
|
|
value={user?.OffersOptIn ? 'On' : 'Off'}
|
|
/>
|
|
</View>
|
|
</ScrollView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
|
|
card: { borderRadius: 12, paddingHorizontal: 16 },
|
|
row: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
paddingVertical: 14,
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
},
|
|
label: { fontSize: 14 },
|
|
value: { fontSize: 15, fontWeight: '600', maxWidth: '60%', textAlign: 'right' },
|
|
});
|