moved files to monorepo and updated controllers to start with /api
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
View, Text, TextInput, TouchableOpacity,
|
||||
ActivityIndicator, KeyboardAvoidingView,
|
||||
Platform, ScrollView, useColorScheme,
|
||||
} from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
|
||||
type Mode = "login" | "register";
|
||||
|
||||
export default function AuthGate({ onSuccess }: { onSuccess?: () => void }) {
|
||||
const dark = useColorScheme() === "dark";
|
||||
const { login, register } = useAuth();
|
||||
|
||||
const [mode, setMode] = useState<Mode>("login");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [name, setName] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [showPass, setShowPass] = useState(false);
|
||||
|
||||
const accent = dark ? "#E07B45" : "#C4622D";
|
||||
|
||||
const submit = async () => {
|
||||
setError("");
|
||||
if (!email || !password) { setError("Please fill in all fields."); return; }
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
if (mode === "login") await login({ email, password });
|
||||
else await register({ email, password, name });
|
||||
onSuccess?.();
|
||||
} catch (e: any) {
|
||||
setError(e.message ?? "Something went wrong.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const inputBase = `
|
||||
rounded-xl px-4 py-3.5 text-sm font-sans border
|
||||
${dark
|
||||
? "bg-obsidian-100 border-border-dark text-ink-dark"
|
||||
: "bg-parchment-100 border-border-light text-ink-light"}
|
||||
`;
|
||||
|
||||
return (
|
||||
<SafeAreaView className={`flex-1 ${dark ? "bg-obsidian-200" : "bg-parchment-50"}`}>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === "ios" ? "padding" : undefined}
|
||||
className="flex-1"
|
||||
>
|
||||
<ScrollView
|
||||
contentContainerStyle={{ flexGrow: 1, justifyContent: "center", padding: 24 }}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
{/* Logo / header */}
|
||||
<View className="items-center mb-8">
|
||||
<View
|
||||
className="w-16 h-16 rounded-2xl items-center justify-center mb-4"
|
||||
style={{ backgroundColor: accent + "20" }}
|
||||
>
|
||||
<Text className="text-3xl">📰</Text>
|
||||
</View>
|
||||
<Text
|
||||
className={`text-2xl font-display font-bold ${dark ? "text-ink-dark" : "text-ink-light"}`}
|
||||
>
|
||||
{mode === "login" ? "Welcome back" : "Create account"}
|
||||
</Text>
|
||||
<Text
|
||||
className={`text-sm font-sans mt-1 ${dark ? "text-muted-dark" : "text-muted-light"}`}
|
||||
>
|
||||
{mode === "login"
|
||||
? "Sign in to sync your subscriptions"
|
||||
: "Start reading what matters"}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Card */}
|
||||
<View
|
||||
className={`rounded-2xl p-5 border ${dark
|
||||
? "bg-obsidian-100 border-border-dark"
|
||||
: "bg-surface-light border-border-light"
|
||||
}`}
|
||||
style={{
|
||||
shadowColor: dark ? "#000" : "#1A1714",
|
||||
shadowOpacity: dark ? 0.3 : 0.06,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 10,
|
||||
elevation: 3,
|
||||
}}
|
||||
>
|
||||
|
||||
|
||||
<View className="mb-3">
|
||||
<Text className={`text-xs font-sans font-semibold mb-1.5 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
|
||||
EMAIL
|
||||
</Text>
|
||||
<TextInput
|
||||
className={inputBase}
|
||||
placeholder="you@example.com"
|
||||
placeholderTextColor={dark ? "#706D67" : "#8A8278"}
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoComplete="email"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View className="mb-5">
|
||||
<Text className={`text-xs font-sans font-semibold mb-1.5 ${dark ? "text-muted-dark" : "text-muted-light"}`}>
|
||||
PASSWORD
|
||||
</Text>
|
||||
<View className="relative">
|
||||
<TextInput
|
||||
className={inputBase}
|
||||
placeholder="••••••••"
|
||||
placeholderTextColor={dark ? "#706D67" : "#8A8278"}
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
secureTextEntry={!showPass}
|
||||
autoComplete="password"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowPass((v) => !v)}
|
||||
className="absolute right-3 top-3.5"
|
||||
>
|
||||
<Ionicons
|
||||
name={showPass ? "eye-off-outline" : "eye-outline"}
|
||||
size={18}
|
||||
color={dark ? "#706D67" : "#8A8278"}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{error !== "" && (
|
||||
<View className="mb-4 px-3 py-2.5 rounded-xl bg-red-500/10 border border-red-500/20">
|
||||
<Text className="text-xs font-sans text-red-500">{error}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={submit}
|
||||
disabled={loading}
|
||||
className="py-3.5 rounded-xl items-center"
|
||||
style={{ backgroundColor: accent }}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
{loading
|
||||
? <ActivityIndicator color="#fff" />
|
||||
: <Text className="text-sm font-sans font-semibold text-white">
|
||||
{mode === "login" ? "Sign in" : "Create account"}
|
||||
</Text>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Toggle mode */}
|
||||
<View className="flex-row justify-center mt-5">
|
||||
<Text className={`text-sm font-sans ${dark ? "text-muted-dark" : "text-muted-light"}`}>
|
||||
{mode === "login" ? "Don't have an account? " : "Already have an account? "}
|
||||
</Text>
|
||||
<TouchableOpacity onPress={() => { setMode(mode === "login" ? "register" : "login"); setError(""); }}>
|
||||
<Text className="text-sm font-sans font-semibold" style={{ color: accent }}>
|
||||
{mode === "login" ? "Register" : "Sign in"}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Continue as guest */}
|
||||
<Text
|
||||
className={`text-center text-xs font-sans mt-4 ${dark ? "text-muted-dark" : "text-muted-light"}`}
|
||||
>
|
||||
You can still browse and save locally without signing in.
|
||||
</Text>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user