Guests can generate a shareable GSH code for admin fulfillment; sign-in now supports Google, email, phone, and Telegram demos, with the backend spec updated. Co-authored-by: Cursor <cursoragent@cursor.com>
147 lines
4.2 KiB
TypeScript
147 lines
4.2 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import { router } from "expo-router";
|
|
import { Pressable, View } from "react-native";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
import { Button } from "@/components/ui/Button";
|
|
import { AppHeader } from "@/components/ui/Header";
|
|
import { Screen } from "@/components/ui/Screen";
|
|
import { Text } from "@/components/ui/Text";
|
|
import { routes } from "@/lib/routes";
|
|
import { useAuthStore } from "@/lib/stores/authStore";
|
|
import type { AuthProvider } from "@/lib/stores/authStore";
|
|
import { colors, gutter, radii, shadows } from "@/lib/theme";
|
|
|
|
type ProviderOption = {
|
|
id: AuthProvider;
|
|
title: string;
|
|
subtitle: string;
|
|
icon: keyof typeof Ionicons.glyphMap;
|
|
tint: string;
|
|
iconBg: string;
|
|
};
|
|
|
|
const PROVIDERS: ProviderOption[] = [
|
|
{
|
|
id: "google",
|
|
title: "Continue with Google",
|
|
subtitle: "Use your Google account",
|
|
icon: "logo-google",
|
|
tint: "#4285F4",
|
|
iconBg: "#EEF3FE",
|
|
},
|
|
{
|
|
id: "email",
|
|
title: "Continue with Email",
|
|
subtitle: "Sign in with email & password",
|
|
icon: "mail-outline",
|
|
tint: colors.brandText,
|
|
iconBg: colors.brandWash,
|
|
},
|
|
{
|
|
id: "phone",
|
|
title: "Continue with Phone",
|
|
subtitle: "SMS one-time code",
|
|
icon: "call-outline",
|
|
tint: colors.ink,
|
|
iconBg: colors.surfaceAlt,
|
|
},
|
|
{
|
|
id: "telegram",
|
|
title: "Continue with Telegram",
|
|
subtitle: "Log in via Telegram",
|
|
icon: "paper-plane-outline",
|
|
tint: "#2AABEE",
|
|
iconBg: "#E8F6FD",
|
|
},
|
|
];
|
|
|
|
export default function SignInScreen() {
|
|
const { t } = useTranslation();
|
|
const insets = useSafeAreaInsets();
|
|
const setHasOnboarded = useAuthStore((s) => s.setHasOnboarded);
|
|
|
|
return (
|
|
<Screen>
|
|
<AppHeader title={t("common.signIn")} subtitle="Choose how you want to continue" />
|
|
<View
|
|
style={{
|
|
flex: 1,
|
|
paddingHorizontal: gutter,
|
|
paddingBottom: insets.bottom + 16,
|
|
gap: 12,
|
|
}}
|
|
>
|
|
<Text variant="bodySm" color={colors.muted}>
|
|
Demo build — each option signs you in locally. Real OAuth / Telegram Login
|
|
Widget can be wired later.
|
|
</Text>
|
|
|
|
<View style={{ gap: 10, marginTop: 8 }}>
|
|
{PROVIDERS.map((p) => (
|
|
<Pressable
|
|
key={p.id}
|
|
onPress={() =>
|
|
router.push({
|
|
pathname: routes.otp,
|
|
params: { method: p.id },
|
|
} as never)
|
|
}
|
|
style={({ pressed }) => ({
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
gap: 14,
|
|
paddingVertical: 14,
|
|
paddingHorizontal: 14,
|
|
borderRadius: radii.lg,
|
|
backgroundColor: colors.surface,
|
|
borderWidth: 1,
|
|
borderColor: colors.line,
|
|
opacity: pressed ? 0.9 : 1,
|
|
...shadows.xs,
|
|
})}
|
|
>
|
|
<View
|
|
style={{
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: 14,
|
|
backgroundColor: p.iconBg,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<Ionicons name={p.icon} size={22} color={p.tint} />
|
|
</View>
|
|
<View style={{ flex: 1 }}>
|
|
<Text variant="h3">{p.title}</Text>
|
|
<Text variant="caption" color={colors.subtle} style={{ marginTop: 2 }}>
|
|
{p.subtitle}
|
|
</Text>
|
|
</View>
|
|
<Ionicons name="chevron-forward" size={18} color={colors.subtle} />
|
|
</Pressable>
|
|
))}
|
|
</View>
|
|
|
|
<View style={{ flex: 1 }} />
|
|
|
|
<Button
|
|
title={t("common.guest")}
|
|
variant="outline"
|
|
onPress={() => {
|
|
useAuthStore.getState().signIn({
|
|
name: "Guest",
|
|
phone: "",
|
|
isGuest: true,
|
|
authProvider: "guest",
|
|
});
|
|
setHasOnboarded(true);
|
|
router.replace(routes.home);
|
|
}}
|
|
/>
|
|
</View>
|
|
</Screen>
|
|
);
|
|
}
|