Amba-Agent-App/app/(root)/auth/agent-signup.tsx
2026-01-16 00:22:35 +03:00

252 lines
8.0 KiB
TypeScript

import React, { useState, useEffect, useRef } from "react";
import {
View,
Keyboard,
Platform,
Image,
TouchableOpacity,
KeyboardAvoidingView,
TouchableWithoutFeedback,
} from "react-native";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { Text } from "~/components/ui/text";
import { router } from "expo-router";
import { ROUTES } from "~/lib/routes";
import { Icons } from "~/assets/icons";
import { useGlobalLoading } from "~/lib/hooks/useGlobalLoading";
import { AuthService } from "~/lib/services/authServices";
import ModalToast from "~/components/ui/toast";
import ScreenWrapper from "~/components/ui/ScreenWrapper";
import { useAuthStore } from "~/lib/stores/authStore";
export default function AgentSignup() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [loading, setLoading] = useState(false);
const { withLoading } = useGlobalLoading();
const { setUser } = useAuthStore();
const [toastVisible, setToastVisible] = useState(false);
const [toastTitle, setToastTitle] = useState("");
const [toastDescription, setToastDescription] = useState<string | undefined>(
undefined
);
const [toastVariant, setToastVariant] = useState<
"success" | "error" | "warning" | "info"
>("info");
const toastTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const showToast = (
title: string,
description?: string,
variant: "success" | "error" | "warning" | "info" = "info"
) => {
if (toastTimeoutRef.current) {
clearTimeout(toastTimeoutRef.current);
}
setToastTitle(title);
setToastDescription(description);
setToastVariant(variant);
setToastVisible(true);
toastTimeoutRef.current = setTimeout(() => {
setToastVisible(false);
toastTimeoutRef.current = null;
}, 2500);
};
const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleSignUp = async () => {
Keyboard.dismiss();
// Validation
if (!email.trim()) {
showToast("Error", "Please enter your email", "warning");
return;
}
if (!validateEmail(email.trim())) {
showToast("Error", "Please enter a valid email address", "warning");
return;
}
if (!password.trim()) {
showToast("Error", "Please enter a password", "warning");
return;
}
if (password.length < 6) {
showToast("Error", "Password must be at least 6 characters", "warning");
return;
}
if (password !== confirmPassword) {
showToast("Error", "Passwords do not match", "warning");
return;
}
setLoading(true);
try {
const result = await withLoading(() =>
AuthService.signUpAgent(email.trim(), password)
);
if (result.error) {
showToast("Sign Up Error", result.error, "error");
return;
}
if (result.user) {
// Set user in auth store
setUser(result.user);
// Navigate to home
router.replace(ROUTES.HOME);
}
} catch (error) {
console.error("Agent signup error:", error);
showToast(
"Error",
error instanceof Error ? error.message : "Failed to sign up",
"error"
);
} finally {
setLoading(false);
}
};
useEffect(() => {
return () => {
if (toastTimeoutRef.current) {
clearTimeout(toastTimeoutRef.current);
}
};
}, []);
return (
<ScreenWrapper edges={[]}>
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="flex-1"
keyboardVerticalOffset={Platform.OS === "ios" ? 10 : 0}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View className="flex-1 justify-between">
<View className="items-center">
<View className="flex flex-col space-y-6 items-center mb-10 mt-10">
<Image
source={Icons.mainAmbapayLogo}
style={{ width: 96, height: 96 }}
resizeMode="contain"
/>
<View className="flex flex-row space-x-1 pt-10 items-center">
<Text className="text-[30px] font-dmsans-extrabold text-primary">
amba
</Text>
<Text className="text-[30px] font-dmsans-extrabold text-secondary">
pay
</Text>
</View>
<Text className="text-lg font-dmsans-medium text-gray-600">
Agent Sign Up
</Text>
</View>
<View className="w-full px-5 space-y-3">
<Label className="text-base font-dmsans-medium">Email</Label>
<View className="h-2" />
<Input
placeholder="Enter your email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
autoComplete="email"
containerClassName="w-full"
borderClassName="border-[#D9DBE9] bg-white"
placeholderColor="#7E7E7E"
textClassName="text-[#000] pt-3 text-sm"
/>
<Label className="text-base font-dmsans-medium mt-4">
Password
</Label>
<View className="h-2" />
<Input
placeholder="Enter your password"
value={password}
onChangeText={setPassword}
secureTextEntry
autoCapitalize="none"
autoComplete="password"
containerClassName="w-full"
borderClassName="border-[#D9DBE9] bg-white"
placeholderColor="#7E7E7E"
textClassName="text-[#000] pt-3 text-sm"
/>
<Label className="text-base font-dmsans-medium mt-4">
Confirm Password
</Label>
<View className="h-2" />
<Input
placeholder="Confirm your password"
value={confirmPassword}
onChangeText={setConfirmPassword}
secureTextEntry
autoCapitalize="none"
containerClassName="w-full"
borderClassName="border-[#D9DBE9] bg-white"
placeholderColor="#7E7E7E"
textClassName="text-[#000] pt-3 text-sm"
/>
</View>
</View>
<View className="w-full px-5 pb-6">
<Button
className="bg-primary rounded-[8px] w-full"
onPress={handleSignUp}
disabled={loading || !email.trim() || !password.trim() || !confirmPassword.trim()}
>
<Text className="font-dmsans text-white text-sm">
{loading ? "Signing up..." : "Sign Up"}
</Text>
</Button>
<View className="flex-row justify-center items-center mt-4">
<Text className="text-gray-600 font-dmsans text-sm">
Already have an account?{" "}
</Text>
<TouchableOpacity
onPress={() => router.push("/auth/agent-signin")}
>
<Text className="text-primary font-dmsans-medium text-sm">
Sign In
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
<ModalToast
visible={toastVisible}
title={toastTitle}
description={toastDescription}
variant={toastVariant}
/>
</ScreenWrapper>
);
}