BigBrainParking/app/src/screens/ProfileScreen.tsx
Hank 2f9f0f604a Add request logging mode, dark mode, Account hub, profile, vehicle CRUD, cards view
- 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>
2026-07-06 10:14:24 -07:00

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' },
});