mojmajstor/app/(auth)/register.tsx
2026-06-04 20:37:09 +02:00

230 lines
8.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import {
View,
Text,
KeyboardAvoidingView,
Platform,
ScrollView,
Alert,
Pressable,
} from "react-native";
import { useRouter } from "expo-router";
import { useMutation, useAction } from "convex/react";
import { api } from "../../convex/_generated/api";
import { Input } from "../../components/ui/input";
import { Button } from "../../components/ui/button";
import { useTheme } from "../../components/theme";
import { useAuth } from "../_layout";
type Role = "handyman" | "customer";
export default function RegisterScreen() {
const theme = useTheme();
const router = useRouter();
const { login } = useAuth();
const registerMutation = useMutation(api.auth.register);
const hashPassword = useAction(api.auth.hashPassword);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [password, setPassword] = useState("");
const [role, setRole] = useState<Role>("customer");
const [loading, setLoading] = useState(false);
async function handleRegister() {
if (!name || !email || !password) {
Alert.alert("Грешка", "Пополнете ги сите задолжителни полиња");
return;
}
if (password.length < 8) {
Alert.alert("Грешка", "Лозинката мора да има најмалку 8 карактери");
return;
}
setLoading(true);
try {
const passwordHash = await hashPassword({ password });
const result = await registerMutation({
name,
email,
passwordHash,
role,
phone: phone || undefined,
});
await login(result.token, result.user!._id);
router.replace("/(tabs)/(home)");
} catch (e: any) {
Alert.alert("Регистрација неуспешна", e.message || "Обидете се повторно");
} finally {
setLoading(false);
}
}
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={{ flex: 1, backgroundColor: theme.colors.background }}
>
<ScrollView
contentContainerStyle={{ flexGrow: 1, padding: theme.spacing.lg }}
keyboardShouldPersistTaps="handled"
>
<View style={{
backgroundColor: theme.colors.card,
borderRadius: theme.radius.xl,
padding: theme.spacing.lg,
borderWidth: 1,
borderColor: theme.colors.borderLight,
...theme.shadows.md,
gap: theme.spacing.md,
}}>
<View style={{ alignItems: "center", marginBottom: theme.spacing.sm }}>
<View
style={{
width: 64,
height: 64,
borderRadius: 32,
backgroundColor: theme.colors.primaryLight,
alignItems: "center",
justifyContent: "center",
marginBottom: theme.spacing.md,
}}
>
<Text style={{ fontSize: 32 }}>👤</Text>
</View>
<Text style={{ ...theme.typography.h1, color: theme.colors.text }}>
Креирајте профил
</Text>
<Text selectable style={{ ...theme.typography.body, color: theme.colors.textSecondary, marginTop: theme.spacing.xs }}>
Изберете ја вашата улога
</Text>
</View>
<View style={{ flexDirection: "row", gap: theme.spacing.md }}>
<Pressable
accessible
accessibilityLabel="Изберете улога: Клиент"
accessibilityRole="button"
onPress={() => setRole("customer")}
style={{
flex: 1,
paddingVertical: theme.spacing.lg,
paddingHorizontal: theme.spacing.sm,
borderRadius: theme.radius.md,
borderWidth: 2,
borderColor: role === "customer" ? theme.colors.primary : theme.colors.borderLight,
backgroundColor: role === "customer" ? theme.colors.primaryLight : theme.colors.surface,
alignItems: "center",
gap: theme.spacing.sm,
}}
>
<View
style={{
width: 48,
height: 48,
borderRadius: 24,
backgroundColor: role === "customer" ? theme.colors.primary + "20" : theme.colors.surfaceAlt,
alignItems: "center",
justifyContent: "center",
}}
>
<Text style={{ fontSize: 24 }}>🏠</Text>
</View>
<Text style={{ fontWeight: "600", fontSize: 15, color: theme.colors.text }}>Клиент</Text>
<Text style={{ fontSize: 12, color: theme.colors.textSecondary, textAlign: "center" }}>
Барајте мајстори
</Text>
</Pressable>
<Pressable
accessible
accessibilityLabel="Изберете улога: Мајстор"
accessibilityRole="button"
onPress={() => setRole("handyman")}
style={{
flex: 1,
paddingVertical: theme.spacing.lg,
paddingHorizontal: theme.spacing.sm,
borderRadius: theme.radius.md,
borderWidth: 2,
borderColor: role === "handyman" ? theme.colors.primary : theme.colors.borderLight,
backgroundColor: role === "handyman" ? theme.colors.primaryLight : theme.colors.surface,
alignItems: "center",
gap: theme.spacing.sm,
}}
>
<View
style={{
width: 48,
height: 48,
borderRadius: 24,
backgroundColor: role === "handyman" ? theme.colors.primary + "20" : theme.colors.surfaceAlt,
alignItems: "center",
justifyContent: "center",
}}
>
<Text style={{ fontSize: 24 }}>🔧</Text>
</View>
<Text style={{ fontWeight: "600", fontSize: 15, color: theme.colors.text }}>Мајстор</Text>
<Text style={{ fontSize: 12, color: theme.colors.textSecondary, textAlign: "center" }}>
Нудете услуги
</Text>
</Pressable>
</View>
<Input
placeholder="Име и презиме"
value={name}
onChangeText={setName}
accessibilityLabel="Име и презиме"
label="Име и презиме"
/>
<Input
placeholder="your@email.com"
value={email}
onChangeText={setEmail}
autoCapitalize="none"
keyboardType="email-address"
accessibilityLabel="Е-пошта"
label="Е-пошта"
/>
<Input
placeholder="+389 70 123 456"
value={phone}
onChangeText={setPhone}
keyboardType="phone-pad"
accessibilityLabel="Телефонски број"
label="Телефон (незадолжително)"
/>
<Input
placeholder="Минимум 8 карактери"
value={password}
onChangeText={setPassword}
secureTextEntry
accessibilityLabel="Лозинка"
label="Лозинка"
/>
<Button loading={loading} onPress={handleRegister} accessibilityLabel="Регистрирај се" size="lg" fullWidth>
Регистрирај се
</Button>
<View style={{ flexDirection: "row", justifyContent: "center", marginTop: theme.spacing.sm }}>
<Text style={{ color: theme.colors.textSecondary }}>Веќе имате профил? </Text>
<Text
accessible
accessibilityLabel="Најавете се"
accessibilityRole="link"
style={{ color: theme.colors.primary, fontWeight: "600" }}
onPress={() => router.back()}
>
Најавете се
</Text>
</View>
</View>
</ScrollView>
</KeyboardAvoidingView>
);
}