import React, {useState, useEffect} from 'react'
import {
ActivityIndicator,
KeyboardAvoidingView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
useWindowDimensions,
} from 'react-native'
import Svg, {Circle, Line, Text as SvgText} from 'react-native-svg'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import * as EmailValidator from 'email-validator'
import {observer} from 'mobx-react-lite'
import {Picker} from '../com/util/Picker'
import {s, colors} from '../lib/styles'
import {useStores} from '../../state'
import {ServiceDescription} from '../../state/models/session'
enum ScreenState {
SigninOrCreateAccount,
Signin,
CreateAccount,
}
const Logo = () => {
return (
)
}
const SigninOrCreateAccount = ({
onPressSignin,
onPressCreateAccount,
}: {
onPressSignin: () => void
onPressCreateAccount: () => void
}) => {
const winDim = useWindowDimensions()
const halfWidth = winDim.width / 2
return (
<>
Bluesky
[ private beta ]
Create a new account
or
Sign in
>
)
}
const Signin = ({onPressBack}: {onPressBack: () => void}) => {
const store = useStores()
const [isProcessing, setIsProcessing] = useState(false)
const [error, setError] = useState('')
const [handle, setHandle] = useState('')
const [password, setPassword] = useState('')
const onPressNext = async () => {
setError('')
setIsProcessing(true)
try {
await store.session.login({
service: 'http://localhost:2583/',
handle,
password,
})
} catch (e: any) {
const errMsg = e.toString()
console.log(e)
setIsProcessing(false)
if (errMsg.includes('Authentication Required')) {
setError('Invalid username or password')
} else if (errMsg.includes('Network request failed')) {
setError(
'Unable to contact your service. Please check your Internet connection.',
)
} else {
setError(errMsg.replace(/^Error:/, ''))
}
}
}
return (
Sign in
{error ? (
{error}
) : undefined}
Back
{isProcessing ? (
) : (
Next
)}
)
}
const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
const store = useStores()
const [isProcessing, setIsProcessing] = useState(false)
const [error, setError] = useState('')
const [serviceDescription, setServiceDescription] = useState<
ServiceDescription | undefined
>(undefined)
const [userDomain, setUserDomain] = useState('')
const [inviteCode, setInviteCode] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [handle, setHandle] = useState('')
useEffect(() => {
let aborted = false
if (serviceDescription || error) {
return
}
store.session.describeService('http://localhost:2583/').then(
desc => {
if (aborted) return
setServiceDescription(desc)
setUserDomain(desc.availableUserDomains[0])
},
err => {
if (aborted) return
console.error(err)
setError(
'Unable to contact your service. Please check your Internet connection.',
)
},
)
return () => {
aborted = true
}
}, [])
const onPressNext = async () => {
if (!email) {
return setError('Please enter your email.')
}
if (!EmailValidator.validate(email)) {
return setError('Your email appears to be invalid.')
}
if (!password) {
return setError('Please choose your password.')
}
if (!handle) {
return setError('Please choose your username.')
}
setError('')
setIsProcessing(true)
try {
await store.session.createAccount({
service: 'http://localhost:2583/',
email,
handle: `${handle}.${userDomain}`,
password,
inviteCode,
})
} catch (e: any) {
const errMsg = e.toString()
console.log(e)
setIsProcessing(false)
// if (errMsg.includes('Authentication Required')) {
// setError('Invalid username or password')
// } else if (errMsg.includes('Network request failed')) {
// setError(
// 'Unable to contact your service. Please check your Internet connection.',
// )
// } else {
setError(errMsg.replace(/^Error:/, ''))
// }
}
}
const InitialLoadView = () => (
<>
{error ? (
<>
{error}
Back
>
) : (
)}
>
)
return (
{serviceDescription ? (
<>
{error ? (
{error}
) : undefined}
Create a new account
{serviceDescription?.inviteCodeRequired ? (
) : undefined}
Choose your username
setHandle(cleanUsername(v))}
editable={!isProcessing}
/>
{serviceDescription.availableUserDomains.length > 1 && (
({
label: `.${d}`,
value: d,
}))}
onChange={itemValue => setUserDomain(itemValue)}
enabled={!isProcessing}
/>
)}
Your full username will be{' '}
@{handle}.{userDomain}
Back
{isProcessing ? (
) : (
Next
)}
>
) : (
)}
)
}
function cleanUsername(v: string): string {
v = v.trim()
if (v.length > 63) {
v = v.slice(0, 63)
}
return v.toLowerCase().replace(/[^a-z0-9-]/g, '')
}
export const Login = observer(
(/*{navigation}: RootTabsScreenProps<'Login'>*/) => {
// const store = useStores()
const [screenState, setScreenState] = useState(
ScreenState.SigninOrCreateAccount,
)
return (
{screenState === ScreenState.SigninOrCreateAccount ? (
setScreenState(ScreenState.Signin)}
onPressCreateAccount={() =>
setScreenState(ScreenState.CreateAccount)
}
/>
) : undefined}
{screenState === ScreenState.Signin ? (
setScreenState(ScreenState.SigninOrCreateAccount)
}
/>
) : undefined}
{screenState === ScreenState.CreateAccount ? (
setScreenState(ScreenState.SigninOrCreateAccount)
}
/>
) : undefined}
)
},
)
const styles = StyleSheet.create({
outer: {
flex: 1,
},
hero: {
flex: 2,
justifyContent: 'center',
},
logoHero: {
paddingTop: 30,
paddingBottom: 40,
},
logo: {
flexDirection: 'row',
justifyContent: 'center',
},
title: {
textAlign: 'center',
color: colors.white,
fontSize: 68,
fontWeight: 'bold',
},
subtitle: {
textAlign: 'center',
color: colors.white,
fontSize: 18,
},
btn: {
borderWidth: 1,
borderColor: colors.white,
borderRadius: 10,
paddingVertical: 16,
marginBottom: 20,
marginHorizontal: 20,
backgroundColor: colors.blue3,
},
btnLabel: {
textAlign: 'center',
color: colors.white,
fontSize: 18,
fontWeight: 'bold',
},
or: {
marginBottom: 20,
},
orLine: {
position: 'absolute',
top: 10,
},
orLabel: {
textAlign: 'center',
color: colors.white,
fontSize: 16,
},
group: {
borderWidth: 1,
borderColor: colors.white,
borderRadius: 10,
marginBottom: 20,
marginHorizontal: 20,
backgroundColor: colors.blue3,
},
groupTitle: {
paddingVertical: 8,
paddingHorizontal: 12,
},
groupContent: {
borderTopWidth: 1,
borderTopColor: colors.blue1,
flexDirection: 'row',
alignItems: 'center',
},
groupContentIcon: {
color: 'white',
marginLeft: 10,
},
textInput: {
flex: 1,
width: '100%',
backgroundColor: colors.blue3,
color: colors.white,
paddingVertical: 10,
paddingHorizontal: 12,
fontSize: 18,
borderRadius: 10,
},
picker: {
flex: 1,
width: '100%',
backgroundColor: colors.blue3,
color: colors.white,
paddingVertical: 10,
paddingHorizontal: 12,
fontSize: 18,
borderRadius: 10,
},
pickerLabel: {
color: colors.white,
fontSize: 18,
},
pickerIcon: {
color: colors.white,
},
error: {
borderTopWidth: 1,
borderTopColor: colors.blue1,
flexDirection: 'row',
alignItems: 'center',
marginTop: 5,
backgroundColor: colors.blue2,
paddingHorizontal: 8,
paddingVertical: 5,
},
errorFloating: {
borderWidth: 1,
borderColor: colors.blue1,
marginBottom: 20,
marginHorizontal: 20,
borderRadius: 8,
},
errorIcon: {
borderWidth: 1,
borderColor: colors.white,
color: colors.white,
borderRadius: 30,
width: 16,
height: 16,
alignItems: 'center',
justifyContent: 'center',
marginRight: 5,
},
})