252 lines
8.0 KiB
TypeScript
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>
|
|
);
|
|
}
|