Files
musicland/src/screens/AccountSettings.js
T
2026-01-12 16:01:32 +01:00

299 lines
7.5 KiB
JavaScript

import * as ImagePicker from 'expo-image-picker'
import { Pressable, Text } from 'react-native'
import useMinuit from 'react-native-minuit/src/hooks/useMinuit.js'
import React, { useGlobal } from 'reactn'
import { responsiveWidth } from '../actions/responsiveSizes.js'
import Page from '../layouts/Page'
import alert from '../components/Alert.js'
import Avatar from '../components/Avatar'
import InputRow from '../components/InputRow'
import ItemRowList from '../components/ItemRowList.js'
import firebase, { usersRef } from '../config/firebase'
import { uploadFileToFirebase } from '../helpers/uploadToFirebase'
import { Routes } from '../navigation/Routes.js'
import { Fonts, gutters, Palette, Style } from '../styles'
import { useUserData } from '../providers/UserDataProvider.js'
export default ({ navigation }) => {
const { setIsLoading, setTooltip } = useMinuit()
const { onSignOut } = useUserData()
const [currentUID] = useGlobal('currentUID')
const [currentUserData] = useGlobal('currentUserData')
const settingsList = [
{
title: 'Nom du compte',
key: 'name',
value: currentUserData?.name || '',
type: 'string',
},
{
title: 'Adresse email',
key: 'email',
value: currentUserData?.email || '',
type: 'string',
},
{
title: 'Mot de passe',
key: 'password',
value: '',
type: 'string',
},
{
title: 'Notifications push',
key: 'notifications',
value: !!currentUserData?.notifications,
type: 'boolean',
},
{
title: 'Notifications par email',
key: 'emailNotifications',
value: !!currentUserData?.emailNotifications,
type: 'boolean',
},
{
title: 'Langue',
key: 'language',
value: currentUserData?.language || '',
type: 'string',
},
]
const destructiveSettingsList = [
{
title: 'Supprimer mon compte',
action: () => onDeleteUserAccount(),
textStyle: {
color: Palette.red,
},
},
].filter(({ condition = true }) => condition)
const onChangePicture = async () => {
try {
setIsLoading(true)
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 4],
quality: 1,
})
if (result?.assets?.[0]?.uri) {
const { resultURI = null } = await uploadFileToFirebase({
uri: result?.assets?.[0]?.uri,
path: `users/${currentUID}/profilePicture.png`,
})
if (resultURI) {
await usersRef.doc(currentUID).update({
profilePictureURL: resultURI,
})
await firebase.auth().currentUser.updateProfile({
photoURL: resultURI,
})
setTooltip({
type: 'success',
text: 'Photo de profil mise à jour',
})
} else {
throw new Error('Erreur changement photo de profil')
}
}
} catch (error) {
console.log(error)
setTooltip({
type: 'error',
text: error.message,
})
} finally {
setIsLoading(false)
}
}
const onUpdateValue = async ({ key, value = null, currentPassword = null }) => {
try {
setIsLoading(true)
const user = firebase.auth().currentUser
const reauthenticateUser = async () => {
try {
const credential = firebase.auth.EmailAuthProvider.credential(
user?.email,
currentPassword
)
await user.reauthenticateWithCredential(credential)
} catch (error) {
throw new Error('Erreur authentification')
}
}
// Validate input except for booleans where false is allowed
const isInvalidString = typeof value === 'string' && value.trim().length === 0
const isNullish = value === null || value === undefined
if (isNullish || isInvalidString) {
throw new Error('Vérifiez les informations saisies')
}
if (key === 'name') {
await user.updateProfile({
displayName: value,
})
}
if (['email', 'password'].includes(key)) {
await reauthenticateUser()
if (key === 'email') {
try {
await user.updateEmail(value)
} catch (e) {
throw new Error('Erreur changement email')
}
}
if (key === 'password') {
try {
await user.updatePassword(value)
} catch (e) {
throw new Error('Erreur changement mot de passe')
}
}
}
if (key !== 'password') {
await usersRef.doc(currentUID).update({
[key]: value,
})
}
setTooltip({
type: 'success',
text: 'Modifications enregistrées',
})
} catch (error) {
console.log(error)
setTooltip({
type: 'error',
text: error.message,
})
} finally {
setIsLoading(false)
}
}
const onDeleteUserAccount = async () => {
alert(
'Êtes-vous sûr?',
'La suppression de votre compte entraînera la suppression de toutes les données liées.',
[
{
text: 'Annuler',
onPress: () => {},
style: 'cancel',
},
{
text: 'Confirmer',
onPress: async () => {
try {
setIsLoading(true)
await firebase.functions().httpsCallable('users-deleteUserAccount')()
await onSignOut()
setTooltip({
type: 'success',
text: 'Compte supprimé avec succès!',
})
navigation.reset({
index: 0,
routes: [
{
name: Routes.Login,
},
],
})
} catch (error) {
setTooltip({
type: 'error',
text: error.message,
})
} finally {
setIsLoading(false)
}
},
style: 'confirm',
},
],
{ cancelable: false }
)
}
return (
<Page headerType="NAVIGATE" title={'Paramètres du compte'} scrollEnabled>
<Pressable
onPress={onChangePicture}
style={[Style.containerCenter, { marginBottom: gutters }]}
>
<Avatar
name={currentUserData?.name}
url={currentUserData?.profilePictureURL || null}
forceRawImage
size={responsiveWidth(30)}
containerStyle={{
marginBottom: gutters / 2,
...Style.defaultShadows,
}}
/>
<Text
style={Fonts({
type: 'section',
style: { color: Palette.primary, textDecorationLine: 'underline' },
})}
>
Modifier
</Text>
</Pressable>
{settingsList.map((setting) => {
const { title, key, value, type } = setting
return (
<InputRow
key={key}
itemKey={key}
value={value}
type={type}
title={title}
onUpdateValue={onUpdateValue}
/>
)
})}
<ItemRowList
title={'Gérer mon abonnement'}
action={() => navigation.navigate(Routes.ManageSubscription)}
containerStyle={{}}
/>
{destructiveSettingsList.map((setting, index) => (
<ItemRowList key={index} {...setting} containerStyle={{}} />
))}
</Page>
)
}