136 lines
4.2 KiB
TypeScript
136 lines
4.2 KiB
TypeScript
import { useState } from 'react'
|
||
import {
|
||
ActivityIndicator,
|
||
KeyboardAvoidingView,
|
||
Linking,
|
||
Modal,
|
||
Platform,
|
||
Pressable,
|
||
StyleSheet,
|
||
Text,
|
||
TextInput,
|
||
View,
|
||
} from 'react-native'
|
||
|
||
import { useAuth } from '@/context/AuthContext'
|
||
import { theme } from '@/constants/theme'
|
||
|
||
const VIP_URL = 'https://vip.hackrobot.cn/'
|
||
|
||
export function PocketBaseAuthModal() {
|
||
const { loginVisible, closeLogin, login } = useAuth()
|
||
const [email, setEmail] = useState('')
|
||
const [password, setPassword] = useState('')
|
||
const [busy, setBusy] = useState(false)
|
||
const [err, setErr] = useState<string | null>(null)
|
||
|
||
const onSubmit = async () => {
|
||
setErr(null)
|
||
setBusy(true)
|
||
try {
|
||
await login(email.trim(), password)
|
||
setPassword('')
|
||
} catch (e) {
|
||
setErr(e instanceof Error ? e.message : String(e))
|
||
} finally {
|
||
setBusy(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Modal visible={loginVisible} animationType="fade" transparent onRequestClose={closeLogin}>
|
||
<KeyboardAvoidingView
|
||
style={styles.backdrop}
|
||
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
||
>
|
||
<Pressable style={styles.scrim} onPress={closeLogin} />
|
||
<View style={styles.sheet}>
|
||
<Text style={styles.title}>会员授权</Text>
|
||
<Text style={styles.sub}>
|
||
开始或重新开始直播前,请使用异度星球账号登录。授权保存在本机,可随时在首页退出。
|
||
</Text>
|
||
{err ? <Text style={styles.err}>{err}</Text> : null}
|
||
<Text style={styles.lbl}>邮箱</Text>
|
||
<TextInput
|
||
style={styles.input}
|
||
value={email}
|
||
onChangeText={setEmail}
|
||
placeholder="you@example.com"
|
||
placeholderTextColor={theme.muted}
|
||
autoCapitalize="none"
|
||
autoCorrect={false}
|
||
keyboardType="email-address"
|
||
/>
|
||
<Text style={styles.lbl}>密码</Text>
|
||
<TextInput
|
||
style={styles.input}
|
||
value={password}
|
||
onChangeText={setPassword}
|
||
placeholder="••••••••"
|
||
placeholderTextColor={theme.muted}
|
||
secureTextEntry
|
||
/>
|
||
<Pressable
|
||
style={[styles.btn, busy && styles.btnDisabled]}
|
||
disabled={busy}
|
||
onPress={() => void onSubmit()}
|
||
>
|
||
{busy ? (
|
||
<ActivityIndicator color="#fff" />
|
||
) : (
|
||
<Text style={styles.btnText}>登录并授权</Text>
|
||
)}
|
||
</Pressable>
|
||
<View style={styles.row}>
|
||
<Pressable onPress={() => void Linking.openURL(VIP_URL)}>
|
||
<Text style={styles.link}>注册</Text>
|
||
</Pressable>
|
||
<Text style={styles.sep}>·</Text>
|
||
<Pressable onPress={closeLogin}>
|
||
<Text style={styles.linkMuted}>取消</Text>
|
||
</Pressable>
|
||
</View>
|
||
</View>
|
||
</KeyboardAvoidingView>
|
||
</Modal>
|
||
)
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
backdrop: { flex: 1, justifyContent: 'center', padding: 20 },
|
||
scrim: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.55)' },
|
||
sheet: {
|
||
borderRadius: 16,
|
||
padding: 20,
|
||
backgroundColor: theme.bgCard,
|
||
borderWidth: 1,
|
||
borderColor: theme.border,
|
||
},
|
||
title: { fontSize: 18, fontWeight: '700', color: theme.text, marginBottom: 8 },
|
||
sub: { fontSize: 13, color: theme.muted, lineHeight: 20, marginBottom: 14 },
|
||
err: { color: theme.danger, fontSize: 13, marginBottom: 10 },
|
||
lbl: { fontSize: 12, fontWeight: '600', color: theme.muted, marginBottom: 6 },
|
||
input: {
|
||
borderWidth: 1,
|
||
borderColor: theme.border,
|
||
borderRadius: 10,
|
||
padding: 12,
|
||
color: theme.text,
|
||
marginBottom: 12,
|
||
backgroundColor: theme.bg,
|
||
},
|
||
btn: {
|
||
backgroundColor: theme.accent,
|
||
paddingVertical: 14,
|
||
borderRadius: 12,
|
||
alignItems: 'center',
|
||
marginTop: 4,
|
||
},
|
||
btnDisabled: { opacity: 0.6 },
|
||
btnText: { color: '#fff', fontWeight: '700', fontSize: 15 },
|
||
row: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginTop: 16, gap: 8 },
|
||
link: { color: theme.accent, fontWeight: '600', fontSize: 14 },
|
||
linkMuted: { color: theme.muted, fontSize: 14 },
|
||
sep: { color: theme.muted },
|
||
})
|