Yaltopia-Tickets-App/app/register.tsx

231 lines
7.7 KiB
TypeScript

import React, { useState } from "react";
import {
View,
ScrollView,
Pressable,
TextInput,
ActivityIndicator,
KeyboardAvoidingView,
Platform,
} from "react-native";
import { useSirouRouter } from "@sirou/react-native";
import { AppRoutes } from "@/lib/routes";
import { Text } from "@/components/ui/text";
import { Button } from "@/components/ui/button";
import {
Mail,
Lock,
User,
Phone,
ArrowLeft,
ArrowRight,
TrianglePlanets,
Eye,
EyeOff,
Chrome,
} from "@/lib/icons";
import { ScreenWrapper } from "@/components/ScreenWrapper";
import { useAuthStore } from "@/lib/auth-store";
import { api } from "@/lib/api";
import { useColorScheme } from "nativewind";
import { toast } from "@/lib/toast-store";
export default function RegisterScreen() {
const nav = useSirouRouter<AppRoutes>();
const setAuth = useAuthStore((state) => state.setAuth);
const { colorScheme } = useColorScheme();
const isDark = colorScheme === "dark";
const [form, setForm] = useState({
firstName: "",
lastName: "",
email: "",
phone: "",
password: "",
});
const [showPassword, setShowPassword] = useState(false);
const [loading, setLoading] = useState(false);
const handleRegister = async () => {
const { firstName, lastName, email, phone, password } = form;
if (!firstName || !lastName || !email || !phone || !password) {
toast.error("Required Fields", "Please fill in all fields");
return;
}
setLoading(true);
try {
// Prepend +251 to the phone number for the API
const formattedPhone = `+251${phone}`;
const response = await api.auth.register({
body: {
...form,
phone: formattedPhone,
role: "VIEWER",
},
});
// Store user, access token, and refresh token
setAuth(response.user, response.accessToken, response.refreshToken);
toast.success("Account Created!", "Welcome to Yaltopia.");
nav.go("(tabs)");
} catch (err: any) {
toast.error(
"Registration Failed",
err.message || "Failed to create account",
);
} finally {
setLoading(false);
}
};
const updateForm = (key: keyof typeof form, val: string) =>
setForm((prev) => ({ ...prev, [key]: val }));
return (
<ScreenWrapper className="bg-background">
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="flex-1"
>
<ScrollView
className="flex-1"
contentContainerStyle={{ padding: 24, paddingBottom: 60 }}
keyboardShouldPersistTaps="handled"
>
<View className="mb-10 mt-10">
<Text
variant="h2"
className="mt-6 font-bold text-foreground text-center"
>
Create Account
</Text>
<Text variant="muted" className="mt-2 text-center">
Join Yaltopia and start managing your business
</Text>
</View>
<View className="gap-5">
<View className="flex-row gap-4">
<View className="flex-1">
<Text variant="small" className="font-semibold mb-2 ml-1">
First Name
</Text>
<View className="bg-secondary/30 rounded-xl px-4 border border-border h-12 justify-center">
<TextInput
className="text-foreground"
placeholder="John"
placeholderTextColor={isDark ? "#475569" : "#94a3b8"}
value={form.firstName}
onChangeText={(v) => updateForm("firstName", v)}
/>
</View>
</View>
<View className="flex-1">
<Text variant="small" className="font-semibold mb-2 ml-1">
Last Name
</Text>
<View className="bg-secondary/30 rounded-xl px-4 border border-border h-12 justify-center">
<TextInput
className="text-foreground"
placeholder="Doe"
placeholderTextColor={isDark ? "#475569" : "#94a3b8"}
value={form.lastName}
onChangeText={(v) => updateForm("lastName", v)}
/>
</View>
</View>
</View>
<View>
<Text variant="small" className="font-semibold mb-2 ml-1">
Email Address
</Text>
<View className="flex-row items-center bg-secondary/30 rounded-xl px-4 border border-border h-12">
<Mail size={18} color={isDark ? "#94a3b8" : "#64748b"} />
<TextInput
className="flex-1 ml-3 text-foreground"
placeholder="john@example.com"
placeholderTextColor={isDark ? "#475569" : "#94a3b8"}
value={form.email}
onChangeText={(v) => updateForm("email", v)}
autoCapitalize="none"
keyboardType="email-address"
/>
</View>
</View>
<View>
<Text variant="small" className="font-semibold mb-2 ml-1">
Phone Number
</Text>
<View className="flex-row items-center bg-secondary/30 rounded-xl px-4 border border-border h-12">
<Phone size={18} color={isDark ? "#94a3b8" : "#64748b"} />
<View className="flex-row items-center flex-1 ml-3">
<Text className="text-foreground text-sm font-medium">
+251{" "}
</Text>
<TextInput
className="flex-1 text-foreground"
placeholder="911 234 567"
placeholderTextColor={isDark ? "#475569" : "#94a3b8"}
value={form.phone}
onChangeText={(v) => updateForm("phone", v)}
keyboardType="phone-pad"
/>
</View>
</View>
</View>
<View>
<Text variant="small" className="font-semibold mb-2 ml-1">
Password
</Text>
<View className="flex-row items-center bg-secondary/30 rounded-xl px-4 border border-border h-12">
<Lock size={18} color={isDark ? "#94a3b8" : "#64748b"} />
<TextInput
className="flex-1 ml-3 text-foreground"
placeholder="••••••••"
placeholderTextColor={isDark ? "#475569" : "#94a3b8"}
value={form.password}
onChangeText={(v) => updateForm("password", v)}
secureTextEntry
/>
</View>
</View>
<Button
className="h-14 bg-primary rounded-[10px ] shadow-lg shadow-primary/30 mt-4"
onPress={handleRegister}
disabled={loading}
>
{loading ? (
<ActivityIndicator color="white" />
) : (
<>
<Text className="text-white font-bold text-base mr-2">
Create Account
</Text>
<ArrowRight color="white" size={18} strokeWidth={2.5} />
</>
)}
</Button>
</View>
<Pressable
className="mt-10 items-center justify-center py-2"
onPress={() => nav.go("login")}
>
<Text className="text-muted-foreground">
Already have an account?{" "}
<Text className="text-primary">Sign In</Text>
</Text>
</Pressable>
</ScrollView>
</KeyboardAvoidingView>
</ScreenWrapper>
);
}