tooot/src/screens/Me/Root/Login.tsx

169 lines
4.5 KiB
TypeScript

import React, { useCallback, useEffect, useState } from 'react'
import { StyleSheet, Text, TextInput, View } from 'react-native'
import { useQuery } from 'react-query'
import { debounce } from 'lodash'
import { instanceFetch } from 'src/utils/fetches/instanceFetch'
import client from 'src/api/client'
import * as AuthSession from 'expo-auth-session'
import { useDispatch } from 'react-redux'
import { updateLocal } from 'src/utils/slices/instancesSlice'
import { useNavigation } from '@react-navigation/native'
import { useTheme } from 'src/utils/styles/ThemeManager'
import { useTranslation } from 'react-i18next'
import { StyleConstants } from 'src/utils/styles/constants'
import { ButtonRow } from 'src/components/Button'
const Login: React.FC = () => {
const { t } = useTranslation('meRoot')
const { theme } = useTheme()
const navigation = useNavigation()
const dispatch = useDispatch()
const [instance, setInstance] = useState('')
const [applicationData, setApplicationData] = useState<{
clientId: string
clientSecret: string
}>()
const { isSuccess, refetch, data } = useQuery(
['Instance', { instance }],
instanceFetch,
{
enabled: false,
retry: false
}
)
const onChangeText = useCallback(
debounce(
text => {
setInstance(text)
setApplicationData(undefined)
refetch()
},
1000,
{
leading: true
}
),
[]
)
const createApplication = async () => {
if (applicationData) {
return Promise.resolve()
}
const formData = new FormData()
formData.append('client_name', 'test_dudu')
formData.append('redirect_uris', 'exp://127.0.0.1:19000')
formData.append('scopes', 'read write follow push')
const res = await client({
method: 'post',
instance: 'remote',
instanceDomain: instance,
url: `apps`,
body: formData
})
if (res.body?.client_id.length > 0) {
setApplicationData({
clientId: res.body.client_id,
clientSecret: res.body.client_secret
})
return Promise.resolve()
} else {
return Promise.reject()
}
}
const [request, response, promptAsync] = AuthSession.useAuthRequest(
{
clientId: applicationData?.clientId!,
clientSecret: applicationData?.clientSecret,
scopes: ['read', 'write', 'follow', 'push'],
redirectUri: 'exp://127.0.0.1:19000'
},
{
authorizationEndpoint: `https://${instance}/oauth/authorize`
}
)
useEffect(() => {
;(async () => {
if (request?.clientId) {
await promptAsync()
}
})()
}, [request])
useEffect(() => {
;(async () => {
if (response?.type === 'success') {
const { accessToken } = await AuthSession.exchangeCodeAsync(
{
clientId: applicationData?.clientId!,
clientSecret: applicationData?.clientSecret,
scopes: ['read', 'write', 'follow', 'push'],
redirectUri: 'exp://127.0.0.1:19000',
code: response.params.code,
extraParams: {
grant_type: 'authorization_code'
}
},
{
tokenEndpoint: `https://${instance}/oauth/token`
}
)
dispatch(updateLocal({ url: instance, token: accessToken }))
navigation.navigate('Screen-Local-Root')
}
})()
}, [response])
return (
<View style={styles.base}>
<TextInput
style={{
height: 50,
color: theme.primary,
borderColor: theme.border,
borderWidth: 1,
padding: StyleConstants.Spacing.M
}}
onChangeText={onChangeText}
autoCapitalize='none'
autoCorrect={false}
autoFocus
clearButtonMode='unless-editing'
keyboardType='url'
textContentType='URL'
onSubmitEditing={async () =>
isSuccess && data && data.uri && (await createApplication())
}
placeholder={t('content.login.server.placeholder')}
placeholderTextColor={theme.secondary}
returnKeyType='go'
/>
<ButtonRow
onPress={async () => await createApplication()}
text={t('content.login.button')}
disabled={!data?.uri}
/>
{isSuccess && data && data.uri && (
<View>
<Text style={{ color: theme.primary }}>{data.title}</Text>
</View>
)}
</View>
)
}
const styles = StyleSheet.create({
base: {
padding: StyleConstants.Spacing.Global.PagePadding
}
})
export default Login