255 lines
11 KiB
TypeScript

import React from "react";
import {
View, Text, ScrollView, TouchableOpacity,
Switch, Modal, useColorScheme,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Ionicons } from "@expo/vector-icons";
import { useAuth } from "../context/AuthContext";
import AuthGate from "./AuthGate";
// ─── Sub-components ────────────────────────────────────────────────────────
type SettingRowProps = {
icon: any;
label: string;
value?: string;
toggle?: boolean;
toggleValue?: boolean;
onToggle?: (v: boolean) => void;
onPress?: () => void;
accent?: string;
};
function SettingRow({ icon, label, value, toggle, toggleValue, onToggle, onPress, accent }: SettingRowProps) {
const dark = useColorScheme() === "dark";
const iconColor = accent ?? (dark ? "#706D67" : "#8A8278");
return (
<TouchableOpacity
onPress={onPress}
activeOpacity={onPress ? 0.7 : 1}
className={`flex-row items-center px-4 py-3.5 border-b ${dark ? "border-border-dark" : "border-border-light"}`}
>
<View
className="w-8 h-8 rounded-xl items-center justify-center mr-3"
style={{ backgroundColor: iconColor + "18" }}
>
<Ionicons name={icon} size={16} color={iconColor} />
</View>
<Text className={`flex-1 text-sm font-sans ${dark ? "text-ink-dark" : "text-ink-light"}`}>
{label}
</Text>
{toggle ? (
<Switch
value={toggleValue}
onValueChange={onToggle}
trackColor={{ true: dark ? "#E07B45" : "#C4622D", false: dark ? "#2C2A27" : "#E8E2D5" }}
thumbColor="#FFFFFF"
/>
) : value ? (
<Text className={`text-sm font-sans ${dark ? "text-muted-dark" : "text-muted-light"}`}>{value}</Text>
) : (
<Ionicons name="chevron-forward" size={14} color={dark ? "#706D67" : "#8A8278"} />
)}
</TouchableOpacity>
);
}
function SectionLabel({ title }: { title: string }) {
const dark = useColorScheme() === "dark";
return (
<Text className={`px-4 pt-5 pb-2 text-xs font-sans font-bold tracking-widest uppercase ${dark ? "text-muted-dark" : "text-muted-light"}`}>
{title}
</Text>
);
}
// ─── Guest profile (logged out) ────────────────────────────────────────────
function GuestProfile({ onSignIn }: { onSignIn: () => void }) {
const dark = useColorScheme() === "dark";
const accent = dark ? "#E07B45" : "#C4622D";
return (
<ScrollView contentContainerStyle={{ paddingBottom: 48 }} showsVerticalScrollIndicator={false}>
{/* Avatar block */}
<View
className={`items-center pt-8 pb-6 mx-4 mt-4 rounded-3xl ${dark ? "bg-obsidian-100" : "bg-surface-light"}`}
style={{
shadowColor: dark ? "#000" : "#1A1714",
shadowOpacity: dark ? 0.35 : 0.06,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 10,
elevation: 3,
}}
>
{/* Anonymous avatar */}
<View
className={`w-20 h-20 rounded-full items-center justify-center mb-3 ${dark ? "bg-obsidian-50" : "bg-parchment-200"}`}
>
<Ionicons name="person-outline" size={36} color={dark ? "#706D67" : "#8A8278"} />
</View>
<Text className={`text-xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}>
Guest
</Text>
<Text className={`text-sm font-sans mt-1 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
Sign in to sync your reading
</Text>
</View>
{/* Settings available to guests */}
<View
className={`mx-4 mt-5 rounded-2xl overflow-hidden border ${dark ? "bg-obsidian-100 border-border-dark" : "bg-surface-light border-border-light"}`}
>
<SectionLabel title="General" />
<SettingRow icon="help-circle-outline" label="Help & support" onPress={() => {}} />
<SettingRow icon="information-circle-outline" label="About" onPress={() => {}} />
</View>
{/* Sign in / Register CTA */}
<TouchableOpacity
onPress={onSignIn}
className="mx-4 mt-4 py-4 rounded-2xl items-center"
style={{ backgroundColor: accent }}
activeOpacity={0.8}
>
<View className="flex-row items-center gap-2">
<Ionicons name="log-in-outline" size={18} color="#fff" />
<Text className="text-sm font-sans font-semibold text-white">
Sign in / Register
</Text>
</View>
</TouchableOpacity>
<Text className={`text-center text-xs font-sans mt-3 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
You can still browse and save locally without an account.
</Text>
</ScrollView>
);
}
// ─── Authenticated profile (logged in) ────────────────────────────────────
function AuthenticatedProfile({ onSignOut }: { onSignOut: () => void }) {
const dark = useColorScheme() === "dark";
const { user } = useAuth();
const [notifications, setNotifications] = React.useState(true);
const [digest, setDigest] = React.useState(false);
return (
<ScrollView contentContainerStyle={{ paddingBottom: 48 }} showsVerticalScrollIndicator={false}>
{/* Avatar + name block */}
<View
className={`items-center pt-8 pb-6 mx-4 mt-4 rounded-3xl ${dark ? "bg-obsidian-100" : "bg-surface-light"}`}
style={{
shadowColor: dark ? "#000" : "#1A1714",
shadowOpacity: dark ? 0.35 : 0.06,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 10,
elevation: 3,
}}
>
<View className={`w-20 h-20 rounded-full items-center justify-center mb-3 ${dark ? "bg-accent-dark/20" : "bg-accent/10"}`}>
<Text className="text-3xl">📰</Text>
</View>
<Text className={`text-xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}>
{user?.email?.split("@")[0] ?? "Reader"}
</Text>
<Text className={`text-sm font-sans mt-1 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
{user?.email}
</Text>
{/* Stats row */}
<View className="flex-row mt-5 gap-8">
{[
{ label: "Subscribed", value: "5" },
{ label: "Read", value: "128" },
{ label: "Saved", value: "34" },
].map((stat) => (
<View key={stat.label} className="items-center">
<Text className={`text-xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}>
{stat.value}
</Text>
<Text className={`text-xs font-sans mt-0.5 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
{stat.label}
</Text>
</View>
))}
</View>
</View>
{/* Settings sections */}
<View
className={`mx-4 mt-5 rounded-2xl overflow-hidden border ${dark ? "bg-obsidian-100 border-border-dark" : "bg-surface-light border-border-light"}`}
>
<SectionLabel title="Notifications" />
<SettingRow
icon="notifications-outline" label="Push notifications"
toggle toggleValue={notifications} onToggle={setNotifications}
accent={dark ? "#E07B45" : "#C4622D"}
/>
<SettingRow
icon="mail-outline" label="Daily digest email"
toggle toggleValue={digest} onToggle={setDigest}
accent={dark ? "#5E9EF4" : "#3B7DD8"}
/>
<SectionLabel title="Subscriptions" />
<SettingRow
icon="bookmark-outline" label="Manage subscriptions"
onPress={() => {}} accent={dark ? "#4EC992" : "#2E9E6B"}
/>
<SectionLabel title="Account" />
<SettingRow icon="person-outline" label="Edit profile" onPress={() => {}} />
<SettingRow icon="help-circle-outline" label="Help & support" onPress={() => {}} />
</View>
{/* Sign out */}
<TouchableOpacity
onPress={onSignOut}
className={`mx-4 mt-4 py-4 rounded-2xl items-center border ${dark ? "border-red-900/40 bg-red-950/20" : "border-red-200 bg-red-50"}`}
activeOpacity={0.7}
>
<View className="flex-row items-center gap-2">
<Ionicons name="log-out-outline" size={16} color="#ef4444" />
<Text className="text-sm font-sans font-semibold text-red-500">Sign out</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
}
// ─── Root export ───────────────────────────────────────────────────────────
export default function Profile() {
const dark = useColorScheme() === "dark";
const { user, logout } = useAuth();
const [showAuth, setShowAuth] = React.useState(false);
return (
<SafeAreaView className={`flex-1 ${dark ? "bg-obsidian-200" : "bg-parchment-50"}`}>
{user
? <AuthenticatedProfile onSignOut={logout} />
: <GuestProfile onSignIn={() => setShowAuth(true)} />
}
{/* Login / Register modal */}
<Modal
visible={showAuth}
animationType="slide"
presentationStyle="pageSheet"
onRequestClose={() => setShowAuth(false)}
>
{/* Close handle */}
<View className={`pt-3 pb-1 items-center ${dark ? "bg-obsidian-200" : "bg-parchment-50"}`}>
<View className={`w-10 h-1 rounded-full ${dark ? "bg-obsidian-50" : "bg-parchment-300"}`} />
</View>
{/* AuthGate auto-closes the modal on success because user becomes non-null */}
<AuthGate onSuccess={() => setShowAuth(false)} />
</Modal>
</SafeAreaView>
);
}