From 7eb8ccae48b0cc18a9dcaa9c3626a02df8e6d919 Mon Sep 17 00:00:00 2001 From: JustZvan Date: Fri, 6 Feb 2026 13:22:33 +0100 Subject: feat: initial commit! --- app/(auth)/_layout.tsx | 29 +++++ app/(auth)/signin.tsx | 165 ++++++++++++++++++++++++++ app/(auth)/signup.tsx | 185 +++++++++++++++++++++++++++++ app/(auth)/welcome.tsx | 64 ++++++++++ app/(tabs)/_layout.tsx | 188 +++++++++++++++++++++++++++++ app/(tabs)/alerts.tsx | 114 ++++++++++++++++++ app/(tabs)/contact-detail.tsx | 193 ++++++++++++++++++++++++++++++ app/(tabs)/controls.tsx | 270 ++++++++++++++++++++++++++++++++++++++++++ app/(tabs)/index.tsx | 135 +++++++++++++++++++++ app/(tabs)/settings.tsx | 221 ++++++++++++++++++++++++++++++++++ app/_layout.tsx | 15 +++ 11 files changed, 1579 insertions(+) create mode 100644 app/(auth)/_layout.tsx create mode 100644 app/(auth)/signin.tsx create mode 100644 app/(auth)/signup.tsx create mode 100644 app/(auth)/welcome.tsx create mode 100644 app/(tabs)/_layout.tsx create mode 100644 app/(tabs)/alerts.tsx create mode 100644 app/(tabs)/contact-detail.tsx create mode 100644 app/(tabs)/controls.tsx create mode 100644 app/(tabs)/index.tsx create mode 100644 app/(tabs)/settings.tsx create mode 100644 app/_layout.tsx (limited to 'app') diff --git a/app/(auth)/_layout.tsx b/app/(auth)/_layout.tsx new file mode 100644 index 0000000..e18b629 --- /dev/null +++ b/app/(auth)/_layout.tsx @@ -0,0 +1,29 @@ +import { Redirect, Stack } from "expo-router"; +import { useAuth } from "../../lib/auth"; +import { colors } from "../../lib/theme"; +import { LoadingScreen } from "../../lib/ui"; + +export default function AuthLayout() { + const { isLoading, isAuthenticated } = useAuth(); + + if (isLoading) { + return ; + } + + if (isAuthenticated) { + return ; + } + + return ( + + + + + + ); +} diff --git a/app/(auth)/signin.tsx b/app/(auth)/signin.tsx new file mode 100644 index 0000000..1eac63b --- /dev/null +++ b/app/(auth)/signin.tsx @@ -0,0 +1,165 @@ +import { Ionicons } from "@expo/vector-icons"; +import { router } from "expo-router"; +import { useState } from "react"; +import { + KeyboardAvoidingView, + Platform, + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from "react-native"; +import { SafeAreaView } from "react-native-safe-area-context"; +import { useAuth } from "../../lib/auth"; +import { t } from "../../lib/locales"; +import { colors } from "../../lib/theme"; +import { Button, H1, Muted, TextInput } from "../../lib/ui"; + +export default function SignIn() { + const { signIn } = useAuth(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [emailError, setEmailError] = useState(""); + const [passwordError, setPasswordError] = useState(""); + + const validateForm = () => { + let valid = true; + setEmailError(""); + setPasswordError(""); + + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + setEmailError(t("invalidEmail")); + valid = false; + } + + if (!password) { + setPasswordError(t("passwordRequired")); + valid = false; + } + + return valid; + }; + + const handleSignIn = async () => { + if (!validateForm()) return; + + setLoading(true); + setError(""); + + try { + const result = await signIn(email, password); + if (!result.success) { + setError(result.reason || t("signInError")); + } + } catch (e) { + setError(t("signInError")); + } finally { + setLoading(false); + } + }; + + return ( + + + + router.back()} + > + + + + +

{t("signIn")}

+
+ + + + + + + {error ? {error} : null} + +