* create and delete app passwords * add randomly generated name * Tweak copy and layout of app passwords * Improve app passwords on desktop web * Rearrange settings * Change app-passwords route and add to backend * Fix link * Fix some more desktop web * Remove log --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
216 lines
5.8 KiB
TypeScript
216 lines
5.8 KiB
TypeScript
import React, {useState} from 'react'
|
|
import {StyleSheet, TextInput, View, TouchableOpacity} from 'react-native'
|
|
import {Text} from '../util/text/Text'
|
|
import {Button} from '../util/forms/Button'
|
|
import {s} from 'lib/styles'
|
|
import {useStores} from 'state/index'
|
|
import {usePalette} from 'lib/hooks/usePalette'
|
|
import {isDesktopWeb} from 'platform/detection'
|
|
import {
|
|
FontAwesomeIcon,
|
|
FontAwesomeIconStyle,
|
|
} from '@fortawesome/react-native-fontawesome'
|
|
import Clipboard from '@react-native-clipboard/clipboard'
|
|
import * as Toast from '../util/Toast'
|
|
|
|
export const snapPoints = ['70%']
|
|
|
|
const shadesOfBlue: string[] = [
|
|
'AliceBlue',
|
|
'Aqua',
|
|
'Aquamarine',
|
|
'Azure',
|
|
'BabyBlue',
|
|
'Blue',
|
|
'BlueViolet',
|
|
'CadetBlue',
|
|
'CornflowerBlue',
|
|
'Cyan',
|
|
'DarkBlue',
|
|
'DarkCyan',
|
|
'DarkSlateBlue',
|
|
'DeepSkyBlue',
|
|
'DodgerBlue',
|
|
'ElectricBlue',
|
|
'LightBlue',
|
|
'LightCyan',
|
|
'LightSkyBlue',
|
|
'LightSteelBlue',
|
|
'MediumAquaMarine',
|
|
'MediumBlue',
|
|
'MediumSlateBlue',
|
|
'MidnightBlue',
|
|
'Navy',
|
|
'PowderBlue',
|
|
'RoyalBlue',
|
|
'SkyBlue',
|
|
'SlateBlue',
|
|
'SteelBlue',
|
|
'Teal',
|
|
'Turquoise',
|
|
]
|
|
|
|
export function Component({}: {}) {
|
|
const pal = usePalette('default')
|
|
const store = useStores()
|
|
const [name, setName] = useState(
|
|
shadesOfBlue[Math.floor(Math.random() * shadesOfBlue.length)],
|
|
)
|
|
const [appPassword, setAppPassword] = useState<string>()
|
|
const [wasCopied, setWasCopied] = useState(false)
|
|
|
|
const onCopy = React.useCallback(() => {
|
|
if (appPassword) {
|
|
Clipboard.setString(appPassword)
|
|
Toast.show('Copied to clipboard')
|
|
setWasCopied(true)
|
|
}
|
|
}, [appPassword])
|
|
|
|
const onDone = React.useCallback(() => {
|
|
store.shell.closeModal()
|
|
}, [store])
|
|
|
|
const createAppPassword = async () => {
|
|
try {
|
|
const newPassword = await store.me.createAppPassword(name)
|
|
if (newPassword) {
|
|
setAppPassword(newPassword.password)
|
|
} else {
|
|
Toast.show('Failed to create app password.')
|
|
// TODO: better error handling (?)
|
|
}
|
|
} catch (e) {
|
|
Toast.show('Failed to create app password.')
|
|
store.log.error('Failed to create app password', {e})
|
|
}
|
|
}
|
|
|
|
return (
|
|
<View style={[styles.container, pal.view]} testID="addAppPasswordsModal">
|
|
<View>
|
|
{!appPassword ? (
|
|
<Text type="lg">
|
|
Please enter a unique name for this App Password. We have generated
|
|
a random name for you.
|
|
</Text>
|
|
) : (
|
|
<Text type="lg">
|
|
<Text type="lg-bold">Here is your app password.</Text> Use this to
|
|
sign into the other app along with your handle.
|
|
</Text>
|
|
)}
|
|
{!appPassword ? (
|
|
<View style={[pal.btn, styles.textInputWrapper]}>
|
|
<TextInput
|
|
style={[styles.input, pal.text]}
|
|
onChangeText={setName}
|
|
value={name}
|
|
placeholder="Enter a name for this App Password"
|
|
placeholderTextColor={pal.colors.textLight}
|
|
autoCorrect={false}
|
|
autoComplete="off"
|
|
autoCapitalize="none"
|
|
autoFocus={true}
|
|
selectTextOnFocus={true}
|
|
multiline={true} // need this to be true otherwise selectTextOnFocus doesn't work
|
|
numberOfLines={1} // hack for multiline so only one line shows (android)
|
|
scrollEnabled={false} // hack for multiline so only one line shows (ios)
|
|
blurOnSubmit={true} // hack for multiline so it submits
|
|
editable={!appPassword}
|
|
returnKeyType="done"
|
|
onEndEditing={createAppPassword}
|
|
/>
|
|
</View>
|
|
) : (
|
|
<TouchableOpacity
|
|
style={[pal.border, styles.passwordContainer, pal.btn]}
|
|
onPress={onCopy}>
|
|
<Text type="2xl-bold">{appPassword}</Text>
|
|
{wasCopied ? (
|
|
<Text style={[pal.textLight]}>Copied</Text>
|
|
) : (
|
|
<FontAwesomeIcon
|
|
icon={['far', 'clone']}
|
|
style={pal.text as FontAwesomeIconStyle}
|
|
size={18}
|
|
/>
|
|
)}
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
{appPassword ? (
|
|
<Text type="lg" style={[pal.textLight, s.mb10]}>
|
|
For security reasons, you won't be able to view this again. If you
|
|
lose this password, you'll need to generate a new one.
|
|
</Text>
|
|
) : null}
|
|
<View style={styles.btnContainer}>
|
|
<Button
|
|
type="primary"
|
|
label={!appPassword ? 'Create App Password' : 'Done'}
|
|
style={styles.btn}
|
|
labelStyle={styles.btnLabel}
|
|
onPress={!appPassword ? createAppPassword : onDone}
|
|
/>
|
|
</View>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
paddingBottom: isDesktopWeb ? 0 : 50,
|
|
marginHorizontal: 16,
|
|
},
|
|
textInputWrapper: {
|
|
borderRadius: 8,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginTop: 16,
|
|
marginBottom: 8,
|
|
},
|
|
input: {
|
|
flex: 1,
|
|
width: '100%',
|
|
paddingVertical: 10,
|
|
paddingHorizontal: 8,
|
|
marginTop: 6,
|
|
fontSize: 17,
|
|
letterSpacing: 0.25,
|
|
fontWeight: '400',
|
|
borderRadius: 10,
|
|
},
|
|
passwordContainer: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
paddingVertical: 8,
|
|
paddingHorizontal: 16,
|
|
alignItems: 'center',
|
|
borderRadius: 10,
|
|
marginTop: 16,
|
|
marginBottom: 12,
|
|
},
|
|
btnContainer: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'center',
|
|
marginTop: 12,
|
|
},
|
|
btn: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
borderRadius: 32,
|
|
paddingHorizontal: 60,
|
|
paddingVertical: 14,
|
|
},
|
|
btnLabel: {
|
|
fontSize: 18,
|
|
},
|
|
groupContent: {
|
|
borderTopWidth: 1,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
})
|