Last active
December 28, 2020 21:00
-
-
Save jonasgroendahl/6f81b440edfe159932f2bcef2f06fbd5 to your computer and use it in GitHub Desktop.
Picker Modal Gist - React native
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useState} from 'react'; | |
import {View, StyleSheet, ScrollView, Image} from 'react-native'; | |
import Container from '../components/Container'; | |
import Typography from '../components/Typography'; | |
import Paper from '../components/Paper'; | |
import Icon from '../components/Icon'; | |
import TextField from '../components/TextField'; | |
import Spacer from '../components/Spacer'; | |
import Button from '../components/Button'; | |
import Center from '../components/Center'; | |
import ThemeColors from '../utils/Colors'; | |
import ExperienceList from '../components/ExperienceList'; | |
import {StackNavigationProp} from '@react-navigation/stack'; | |
import {RootStackProps} from '../router'; | |
import ImagePicker from 'react-native-image-picker'; | |
import IconButton from '../components/IconButton'; | |
import {useMainContext} from '../hooks/useContext'; | |
import {useFocusEffect} from '@react-navigation/native'; | |
import LoginRequired from '../components/LoginRequired'; | |
import {User} from '../types/types'; | |
import {updateUserBackend} from '../firebase'; | |
import PickerModal from '../components/PickerModal'; | |
import {useTranslation} from '../context/Language'; | |
import Snackbar from 'react-native-snackbar'; | |
type Props = { | |
navigation: StackNavigationProp<RootStackProps, 'Profile'>; | |
}; | |
const Profile: React.FC<Props> = () => { | |
const ctx = useMainContext(); | |
const [user, setUser] = useState<any>({ | |
id: '', | |
name: '', | |
age: '', | |
gender: '', | |
introduction: '', | |
experiences: [], | |
img: '', | |
}); | |
const [editable, setEditable] = useState<boolean>(false); | |
const [showPicker, setShowPicker] = useState<string>(''); | |
const { | |
titleMyProfile, | |
placeholderAge, | |
placeHolderGender, | |
placeholderName, | |
placeholderDescriptionProfile, | |
titleExperience, | |
btnSaveProfile, | |
genderFemale, | |
genderMale, | |
genderOther, | |
profileSaved, | |
} = useTranslation(); | |
const pickerValue = { | |
age: [...new Array(100)].map((value, index) => index.toString()), | |
gender: [genderMale, genderFemale, genderOther], | |
}; | |
useFocusEffect( | |
React.useCallback(() => { | |
if (ctx.user) { | |
setUser(ctx.user); | |
} | |
}, [ctx]), | |
); | |
const handleChange = (fieldName: string, value: string) => { | |
setUser((prevUser: User) => ({...prevUser, [fieldName]: value})); | |
}; | |
const handleUpload = () => { | |
if (editable) { | |
ImagePicker.showImagePicker( | |
{maxHeight: 400, maxWidth: 500}, | |
(response) => { | |
if (response.didCancel) { | |
return; | |
} | |
setUser((prev: User) => ({...prev, img: response.uri})); | |
}, | |
); | |
} | |
}; | |
const handleSubmit = async () => { | |
const newUser = await updateUserBackend(user); | |
ctx.setUser(newUser); | |
Snackbar.show({text: profileSaved, backgroundColor: ThemeColors.purple}); | |
setEditable(false); | |
}; | |
if (!ctx.isLoggedIn) { | |
return <LoginRequired />; | |
} | |
return ( | |
<Container> | |
<ScrollView> | |
<Typography variant="largeTitle">{titleMyProfile}</Typography> | |
<Paper> | |
<View> | |
<View style={styles.abs}> | |
<IconButton | |
onPress={() => setEditable(!editable)} | |
variant="round" | |
style={{padding: 10}}> | |
{editable ? <Icon name="eye" /> : <Icon name="edit" />} | |
</IconButton> | |
</View> | |
</View> | |
<View style={styles.header}> | |
<View style={styles.profileImgContainer}> | |
<IconButton onPress={handleUpload}> | |
{user.img ? ( | |
<Image source={{uri: user.img}} style={styles.profileImg} /> | |
) : ( | |
<Icon name="camera" size={30} color={ThemeColors.white} /> | |
)} | |
</IconButton> | |
</View> | |
<View style={{flex: 1, marginLeft: 10}}> | |
<TextField | |
variant="contained" | |
placeholder={placeholderName} | |
value={user.name} | |
editable={editable} | |
onChangeText={(value: string) => handleChange('name', value)} | |
style={styles.headerSpacing} | |
/> | |
<Button | |
variant="input" | |
size="normal" | |
color="secondary" | |
onPress={() => setShowPicker('age')} | |
disabled={!editable} | |
style={styles.headerSpacing}> | |
{user.age || placeholderAge} | |
</Button> | |
<Button | |
variant="input" | |
color="secondary" | |
onPress={() => setShowPicker('gender')} | |
disabled={!editable}> | |
{user.gender || placeHolderGender} | |
</Button> | |
</View> | |
</View> | |
<Spacer /> | |
<TextField | |
variant="contained" | |
multiline | |
placeholder={placeholderDescriptionProfile} | |
value={user.introduction} | |
editable={editable} | |
onChangeText={(value: string) => | |
handleChange('introduction', value) | |
} | |
textAlignVertical="top" | |
/> | |
<Spacer /> | |
<Center> | |
<Typography color="dark">{titleExperience}</Typography> | |
<Spacer /> | |
</Center> | |
<ExperienceList | |
items={user.experiences} | |
editable={editable} | |
onAdd={(cat) => { | |
setUser((prev: User) => ({ | |
...prev, | |
experiences: prev.experiences.concat(cat), | |
})); | |
}} | |
onDelete={(index: number) => { | |
setUser((prev: User) => ({ | |
...prev, | |
experiences: prev.experiences.filter((_, i) => i !== index), | |
})); | |
}} | |
/> | |
<Spacer /> | |
</Paper> | |
<Spacer /> | |
<Center> | |
<View> | |
<Button onPress={handleSubmit} variant="outlined"> | |
{btnSaveProfile} | |
</Button> | |
</View> | |
</Center> | |
<PickerModal | |
visible={Boolean(showPicker)} | |
title={showPicker} | |
items={showPicker ? pickerValue[showPicker] : []} | |
onClose={() => setShowPicker('')} | |
onSelect={(value) => handleChange(showPicker, value)} | |
value={showPicker ? user[showPicker] : ''} | |
/> | |
</ScrollView> | |
</Container> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
row: { | |
flexDirection: 'row', | |
}, | |
profileImgContainer: { | |
borderRadius: 75, | |
width: 130, | |
height: 130, | |
backgroundColor: 'transparent', | |
borderWidth: 1, | |
borderColor: 'white', | |
justifyContent: 'center', | |
alignItems: 'center', | |
marginBottom: 10, | |
}, | |
profileImg: { | |
width: 130, | |
height: 130, | |
borderRadius: 75, | |
}, | |
header: { | |
flexDirection: 'row', | |
alignItems: 'center', | |
}, | |
headerSpacing: { | |
marginBottom: 5, | |
}, | |
abs: { | |
position: 'absolute', | |
top: -55, | |
right: 0, | |
}, | |
}); | |
export default Profile; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment