The first problem: when opening a modal with editing an avatar, 2 requests are sent to the server.
The second problem: the avatar is not updated. The answer comes that the email should be specified, but I just pass the string. The full text of the error is shown in the screenshot.
Sending an avatar change request
import { BottomSheet } from '#rneui/themed'
import { FC, useState } from 'react'
import { useForm } from 'react-hook-form'
import { Pressable, ScrollView, View } from 'react-native'
import GestureRecognizer from 'react-native-swipe-gestures'
import { IUser } from '#/types/user.inteerface'
import { IAvatarEdit } from '#/components/screens/profile/avatarEdit/avatarEdit.interface'
import { useAvatar } from '#/components/screens/profile/avatarEdit/useAvatar'
import { Avatars, Button, Heading, Layout } from '#/components/ui'
import { getModalStyle, modalStyle } from '#/components/ui/style'
type AvatarData = {
image_url: string
}
const dataList: AvatarData[] = [
{
image_url:
'https://cdn.pixabay.com/photo/2017/03/01/22/18/avatar-2109804_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2012/04/18/18/07/user-37448_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
}
]
const AvatarEdit: FC<IAvatarEdit> = ({ onClose, isVisible, ...props }) => {
const { setValue } = useForm<IUser>()
const { onSubmit, user } = useAvatar(setValue)
const [selected, setSelected] = useState<string>(user?.avatar || '')
const onAvatarSubmit = () => {
onSubmit({ avatar: selected } as IUser)
onClose()
}
return (
<GestureRecognizer
onSwipeDown={onClose}
config={{
velocityThreshold: 0.3,
directionalOffsetThreshold: 80
}}
style={{
flex: 1
}}
>
<BottomSheet
backdropStyle={{
backgroundColor: 'rgba(0, 0, 0, 0.5)'
}}
onBackdropPress={onClose}
isVisible={isVisible}
{...props}
>
<Layout
style={{
...getModalStyle(modalStyle)
}}
>
<View
style={{
flex: 1,
paddingHorizontal: 20,
paddingVertical: 20
}}
>
<Heading className='pb-3' title='Edit' />
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start'
}}
>
<Avatars
rounded={true}
size={100}
source={selected ? { uri: selected } : { uri: user?.avatar }}
/>
<View
style={{
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end'
}}
>
<Button style={{ marginRight: 10 }} onPress={onAvatarSubmit}>
Save
</Button>
</View>
</View>
</View>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
>
{dataList.map((item, index) => (
<Pressable key={index}>
<Avatars
onPress={() => setSelected(item.image_url)}
rounded={true}
key={index}
size={60}
source={{ uri: item.image_url }}
/>
</Pressable>
))}
</ScrollView>
</Layout>
</BottomSheet>
</GestureRecognizer>
)
}
export default AvatarEdit
import { IAuthFormData } from '#/types/auth.interface'
import { IUser } from '#/types/user.inteerface'
import { getUserUrl } from '#/config/api.config'
import { request } from '#/services/api/request.api'
export const UserService = {
async getAll(searchTerm?: string) {
return request<IUser[]>({
url: getUserUrl(''),
method: 'GET',
params: searchTerm ? { searchTerm } : {}
})
},
async getProfile() {
return request<IUser>({
url: getUserUrl('profile'),
method: 'GET'
})
},
async getById(_id: string) {
return request<IUser>({
url: getUserUrl(`${_id}`),
method: 'GET'
})
},
async updateProfile(data: IAuthFormData) {
return request<IUser>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateUser(data: IAuthFormData, _id: string) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateAvatar(data: IUser) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async deleteUser(_id: string) {
return request<string>({
url: getUserUrl(`${_id}`),
method: 'DELETE'
})
}
// async getFavorites() {
// return request<IUser>({
// url: getUserUrl('profile/favorites'),
// method: 'GET'
// })
// },
}
import { useMutation, useQuery } from '#tanstack/react-query'
import { SubmitHandler, UseFormSetValue } from 'react-hook-form'
import Toast from 'react-native-toast-message'
import { IUser } from '#/types/user.inteerface'
import { UserService } from '#/services/user/user.service'
export const useAvatar = (setValue: UseFormSetValue<IUser>) => {
const { isLoading, data: user } = useQuery(
['avatar'],
() => UserService.getProfile(),
{
onSuccess: ({ avatar }) => {
setValue('avatar', avatar)
}
}
)
const { mutateAsync } = useMutation(
['update avatar'],
(data: IUser) => UserService.updateAvatar(data),
{
onSuccess: ({}) => {
Toast.show({
type: 'success',
text1: 'avatar update',
text2: 'avatar update was successful'
})
}
}
)
const onSubmit: SubmitHandler<IUser> = async data => {
await mutateAsync(data)
}
return { onSubmit, isLoading, user }
}
Related
I wanted to how to solve this error... this is not my code I am fixing bugs in someone else's code. "I wanted to how to dispatch to store with use effect Hook".
as I researched it says it says I can dispatch to store inside a function without a use effect Hook I wanted to know how to modify it in this code,
also if someone know how to getrid of "MapStateToProps" with the useSelect hook that will also be more helpfull for me inorder to improve this code...
LoginScreen.js
import React, { Component } from 'react';
import {
View, Text,
Image,
Dimensions,
ImageBackground,
SafeAreaView,
Alert,
Modal, Button,
StatusBar,
TextInput,
TextInputComponent,
Linking,
StyleSheet
} from 'react-native';
// import { PropTypes } from 'prop-types';
// import NetInfo from "#react-native-community/netinfo";
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from 'react-native-responsive-screen';
// import * as Animatable from 'react-native-animatable';
import AsyncStorage from '#react-native-community/async-storage'
import { showMessage, hideMessage } from "react-native-flash-message";
const { width, height } = Dimensions.get('window');
import styles from './styles';
import Buttons from '../../../uiElements/Buttons/RoundButtons'
import VerificationCodeText from '../../../uiElements/VerificationCodeText'
import { connect } from 'react-redux';
import startUpActions from '../../../redux/StartUp/actions';
import Loading from '../../../uiElements/Loading';
import { ScrollView, TouchableHighlight, TouchableOpacity } from 'react-native-gesture-handler';
import { textFocusColor, textDefaultColor } from '../../../contents'
import TextInputField from '../../../uiElements/TextInput';
const { loginApp, getCustomerDetailsByEmail, clearProps, getAgentExposableId } = startUpActions;
const imageWidth = Dimensions.get('window').width;
// const imageWidth = Dimensions.get('window').width;
class StartScreen extends Component {
constructor(props) {
super(props);
this.state = {
hasFocusPhoneNo: false,
iseyeactivenew: true,
iseyeactivecurrent: true,
userId: '',
password: '',
hasFocusUsername: false,
hasFocusPassword: false,
}
}
static getStateFromProps(props, state) {
if (props.jwttoken != undefined) {
if (props.jwttoken == 'errlogin') {
}
}
}
static getDerivedStateFromProps(props, state) {
if (props.jwttoken != undefined) {
if (props.jwttoken == 'errlogin') {
showMessage({
textStyle: { paddingLeft: 10 },
titleStyle: { paddingLeft: 10 },
message: "Error",
description: "Username or Password incorrect",
type: "default",
backgroundColor: "red", // background color
color: "#ffffff",
duration: 3850
});
_storeAccess = async () => {
props.dispatch(clearProps())
}
_storeAccess()
} else {
_storeAccess = async () => {
await AsyncStorage.setItem('access_token', props.jwttoken);
const appIdRequest = await AsyncStorage.getItem('appIdrequest')
props.dispatch(getCustomerDetailsByEmail(props.jwttoken, '', state.userId))
//props.dispatch(clearProps())
}
_storeAccess();
}
}
if (props.customerDetailsAllResult != undefined) {
// console.log(props.customerDetailsAllResult.responseDto.customerDetailsId)
if (props.customerDetailsAllResult.responseDto == null) {
props.dispatch(clearProps())
} else {
_storeAccess = async () => {
await AsyncStorage.setItem('customerWalletId', props.customerDetailsAllResult.responseDto.agentSenderDetailsId.toString());
await AsyncStorage.setItem('email', props.customerDetailsAllResult.responseDto.email.toString()) //not change
await AsyncStorage.setItem('useremail', props.customerDetailsAllResult.responseDto.email.toString()) //when change coporate mail this will change
await AsyncStorage.setItem('agentSenderDetails', JSON.stringify(props.customerDetailsAllResult.responseDto))
const access_token = await AsyncStorage.getItem('access_token')
Console.log("navigate", access_token)
if (access_token != null) {
props.navigation.navigate('TabView')
}
// props.navigation.navigate('MoneyTransfer2')
props.dispatch(clearProps())
}
_storeAccess();
}
}
if (props.agentExposableId != undefined) {
if (props.agentExposableId == null) {
props.dispatch(clearProps()) //loginurl https://qabankingauth.monexfintech.com/v1/auth/authenticate
} else {
_storeAccess = async () => { await AsyncStorage.setItem('agentExposableId', props.agentExposableId); }
// props.navigation.navigate('MoneyTransfer2')
props.dispatch(clearProps())
}
_storeAccess();
}
return null;
}
componentDidMount() {
// console.log('lll')
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.customerDetailsAllResult !== this.props.customerDetailsAllResult) {
}
if (prevProps.jwttoken !== this.props.jwttoken) {
console.log(this.props.jwttoken)
}
}
getData = async () => {
try {
const accesstoken = await AsyncStorage.getItem('access_token')
if (accesstoken !== null) {
this.props.dispatch(userShow(accesstoken))
this.setState({ islogin: true })
console.log('jjj')
// this.props.navigation.navigate('TabView')
} else {
this.props.dispatch(getBranchesList())
this.setState({ islogin: false })
// this.props.navigation.navigate('TabView')
}
} catch (e) {
console.log(e)
}
}
onChangeText = (key, val) => {
this.setState({ [key]: val }, () => {
})
}
onpressphoneno = () => {
this.setState({ hasFocusPhoneNo: true })
this.setState({ postcodeerror: false })
}
btnPress = async () => {
this.props.navigation.navigate('LoginScr')
if (this.state.userId == '' || this.state.password == '') {
showMessage({
textStyle: { paddingLeft: 10 },
titleStyle: { paddingLeft: 10 },
message: "Error",
description: "Please enter Username and Password",
type: "default",
backgroundColor: "red", // background color
color: "#ffffff",
duration: 3850
});
} else {
try {
const obj = {
username: this.state.userId,
password: this.state.password,
grantType: 'Agent Customer',
agentRegNumber: 'MXAG01'
}
await AsyncStorage.setItem('email', this.state.userId);
await AsyncStorage.setItem('useremail', this.state.userId);
await AsyncStorage.setItem('password', this.state.password);
await AsyncStorage.setItem('access_token', ' eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjaGF0aHVyYW5nYUBjb2RlbGFudGljLmNvbSIsInVzZXJfaWQiOjMsImV4cCI6MTYxNTQzODI4NywiaXNfdGZhX2VuYWJsZWQiOm51bGwsImlhdCI6MTYxNTQzNDY4NywidGZhRGVmYXVsdFR5cGUiOm51bGwsImNsaWVudF9jb2RlIjoiTU4ifQ.lncV1VQ-T0dNPsME0_FvRF-2TQShHiwP66aFoT0fhV58QaR-Sn0ZVEBPSiGxxQ9NWnzbaCpev61Hkex6EPBxNA');
// this.props.dispatch(getFirstValue());
this.props.dispatch(getAgentExposableId());
this.props.dispatch(loginApp(obj))
this.props.dispatch(clearProps());
} catch (error) {
console.log(error);
}
//this.props.navigation.navigate('LoginScr')
}
}
clickPrivacypolicy() {
Linking.canOpenURL("https://spoton.money/policy-procedures-refund-terms-gdpr").then(supported => {
if (supported) {
Linking.openURL("https://spoton.money/policy-procedures-refund-terms-gdpr");
} else {
console.log("Don't know how to open URI: " + this.props.url);
}
});
}
render() {
// const { navigate } = this.props.navigation;
return (
<SafeAreaView style={style.container}>
<ScrollView style={{ backgroundColor: '#343A4F', }}>
<View style={{ backgroundColor: '#343A4F', height: '100%' }}>
<ImageBackground source={require('../../../images/ellipse.png')} style={{ width: '100%', height: '60%' }}>
<View style={{ alignItems: 'center', paddingTop: wp('15%') }}>
<Image
style={{ width: wp('45%'), height: wp('15%') }}
source={require('../../../images/spotonmoneylogo.png')}
/>
</View>
{this.props.loading && <Loading navigation={this.props.navigation} animating={true} />}
<View style={{ paddingLeft: wp('5%'), paddingRight: wp('5%'), backgroundColor: '#343A4F', marginTop: wp('50%') }}>
{/* <TextInput
placeholder="Username"
placeholderTextColor={textDefaultColor}
onFocus={() =>this.setState({ hasFocusUsername: true })}
onBlur={() => this.setState({ hasFocusUsername: false })}
onChangeText={(val) => this.setState({ userId: val })}
style={
this.state.hasFocusUsername ?
styles.focusedTextInput :
styles.txtstyle
}
/> */}
<TextInputField
placeholdertext="Username"
valuetext={this.state.email}
onFocusFunc={() => this.setState({ hasFocusUserName: true })}
onBlurFunc={() => this.setState({ hasFocusUserName: false })}
onChangeTextFunc={value => this.onChangeText('userId', value)}
iserrortext={this.state.errorlastnamestate}
editabletext={false}
keyboardType1='email'
// texterror={this.state.errorlastnametextstate}
// hasFocustext={this.state.hasFocusUserName}
/>
<TextInputField
placeholdertext="Password"
valuetext={this.state.password}
onFocusFunc={() => this.setState({ hasFocusPassword: true })}
onBlurFunc={() => this.setState({ hasFocusPassword: false })}
onChangeTextFunc={value => this.onChangeText('password', value)}
iserrortext={this.state.errorlastnamestate}
editabletext={false}
secureTextEntrytxt={true}
// texterror={this.state.errorlastnametextstate}
hasFocustext={this.state.hasFocusPassword}
/>
{/* <TextInput
placeholder="Password"
placeholderTextColor={textDefaultColor}
secureTextEntry={true}
onFocus={() => this.setState({ hasFocusPassword: true })}
onBlur={() => this.setState({ hasFocusPassword: false })}
onChangeText={(val) => this.setState({ password: val })}
style={
this.state.hasFocusPassword ?
styles.focusedTextInput :
styles.txtstyle
}
/> */}
</View>
<View style={{ paddingTop: wp('10%'), alignItems: 'center' }}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Verification')}>
<Text style={{ color: 'white' }}>Forgot Password</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.btnPress()}>
<Buttons text="Log In" btnfontSize={wp('4%')}
btnbackgroundColor='#F15622'
btntxtncolor="#ffffff"
btnMarginRight={imageWidth / 1000}
btnMarginLeft={imageWidth / 1000}
onPress={() => this.btnPress()} />
</TouchableOpacity>
<View style={{ paddingTop: wp('4%') }}>
<Text style={{ color: 'white', fontSize: wp('4%') }}>Don't have an account?
<TouchableOpacity onPress={() => this.props.navigation.navigate('VerificationSignUp')}>
<Text style={{ color: '#2793E1', fontWeight: 'bold', textDecorationLine: 'underline' }}>
Sign Up
</Text>
</TouchableOpacity>
</Text>
</View>
<View style={{ padding: wp('4%'), marginTop: hp('4%'), alignContent: 'center' }}>
<TouchableOpacity >
<Text style={{ color: 'white', fontSize: wp('3%') }}>By logging in you agree to the Spoton money
<TouchableOpacity onPress={() => this.clickPrivacypolicy()}>
<Text style={{ color: '#2793E1', fontSize: wp('3%'), paddingTop: wp('1%') }}>
Privacy policy .
</Text>
</TouchableOpacity>
and acknowledge our
<TouchableOpacity onPress={() => this.clickPrivacypolicy()}>
<Text style={{ color: '#2793E1', fontSize: wp('3%'), paddingTop: wp('1%') }}>
Terms & Conditions.
</Text>
</TouchableOpacity>
</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
</ScrollView>
</SafeAreaView>
);
}
}
const mapStateToProps = state => {
return {
...state.startUpReducer
}
// loading: state.startUpReducer.loading,
// jwttoken: state.startUpReducer.jwttoken,
// customerDetailsAllResult: state.startUpReducer.customerDetailsAllResult,
// agentExposableId: state.startUpReducer.exposable_id
};
export default connect(mapStateToProps)(StartScreen);
const style = StyleSheet.create({
container: {
backgroundColor: '#343A4F',
height: wp()
}
})
redux/Actions.js
loginApp: (value) => ({
type: actions.LOGIN_SCREEN,
value
}),
redux/reducer.js
case startUpActions.LOGIN_SCREEN:
return{
...state,
loading:true
}
case startUpActions.LOGIN_SCREEN_RESULT:
return{
loading:false,
jwttoken:action.result.jwttoken
}
case startUpActions.LOGIN_SCREEN_ERROR:
return{
loading:false,
jwttoken:'errlogin'
}
redux/saga.js
export function* loginApp(){
yield takeEvery(actions.LOGIN_SCREEN, function* (payload) {
const requestBody=payload.value
const url = loginURL;
console.log(requestBody);
console.log(url);
try {
const response = yield fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody)
});
console.log(response)
const result = yield response.json();
console.log(result)
if (response.ok) {
yield put({ type: actions.LOGIN_SCREEN_RESULT, result });
} else {
yield put({
type: actions.LOGIN_SCREEN_ERROR,
result
});
}
} catch (error) {
yield put({ type: actions.LOGIN_SCREEN_ERROR });
}
});
}
In flatlist scroll to offset is not working properly when the no of items are less than 3. If the no of items are greater or equal to 3 than it is working exactly fine.
import React, { Component } from 'react'
import { Animated, Dimensions, RefreshControl, StyleSheet, View, TouchableOpacity } from 'react-native'
import { HEADER_HEIGHT } from '.'
import { CustomText, FlatListWrapper, FlatListWrapperProps } from '../../../common-library/components'
import { ScrollValueContext } from './Context'
import { get } from 'lodash'
import { CENTER, colors, dimens, ROW, SPACE_BETWEEN } from '../../../common-library/config'
import { TAB_BAR_HEIGHT } from './CommunityHeaderComponent'
import { IconButtonWrapper } from '../generic'
import { icons } from '../../common'
import { log } from '../../config'
const labels = {
GO_TO_TOP: 'Go to Top'
}
const styles = StyleSheet.create({
contentStyle: {
paddingTop: HEADER_HEIGHT
},
scrollToTopContainer: {
position: 'absolute',
top: TAB_BAR_HEIGHT,
alignItems: 'center',
left: 0,
right: 0,
zIndex: 999
},
buttonsContainer: {
borderColor: colors.DuckBlue,
backgroundColor: colors.DuckBlue,
borderRadius: dimens.size25,
width: 110,
flexDirection: ROW,
justifyContent: SPACE_BETWEEN,
paddingVertical: dimens.size10,
alignItems: CENTER
},
buttonCta: {
paddingLeft: dimens.size15
},
goToTopLabel: {
color: colors.White,
textAlign: CENTER
},
crossIconCta: {
justifyContent: CENTER,
alignItems: CENTER,
paddingRight: dimens.size15
// paddingTop: dimens.size2
}
})
interface State {
shouldRefresh?: boolean
showScrollToTopView?: boolean
dontShowGoToTop?: boolean
}
interface Props extends FlatListWrapperProps {
uniqueKey?: string
getFlatListRef?: (ref) => any
getScrolledPosition?: (contentOffset) => any
onPullToRefresh?: () => any
renderScrollToTopView?: boolean
}
export class StickyScrollableFlatlistComponent extends Component<Props, State> {
flatListRef
scrolledValue
timerRef
state = {
shouldRefresh: false,
showScrollToTopView: false,
dontShowGoToTop: false
}
componentDidUpdate(prevProps) {
const { showScrollToTopView, dontShowGoToTop } = this.state
if ((!prevProps.isFetching && this.props.isFetching) || (prevProps.isFetching && !this.props.isFetching)) {
if ((showScrollToTopView || dontShowGoToTop) && this.props.renderScrollToTopView) {
this.setState({
showScrollToTopView: false,
dontShowGoToTop: false
})
}
setTimeout(() => {
log('setTileout is called', this.scrolledValue > HEADER_HEIGHT, this.scrolledValue)
this.flatListRef.scrollToOffset({
offset: this.scrolledValue > HEADER_HEIGHT ? HEADER_HEIGHT : HEADER_HEIGHT,
animated: false
})
}, 2000)
}
}
onRefresh = () => {
const { onPullToRefresh } = this.props
if (onPullToRefresh) {
this.setState({
shouldRefresh: true
})
onPullToRefresh().then(() => {
this.setState({
shouldRefresh: false
})
})
}
}
showScrollToTopView = () => {
const { showScrollToTopView } = this.state
const DEVICE_HEIGHT = Dimensions.get('window').height
if (this.scrolledValue >= 2 * DEVICE_HEIGHT - HEADER_HEIGHT && !showScrollToTopView) {
this.setState({
showScrollToTopView: true
})
} else if (this.scrolledValue <= DEVICE_HEIGHT - HEADER_HEIGHT && showScrollToTopView) {
this.setState({
showScrollToTopView: false
})
}
}
onClikCrossIcon = () => {
this.setState({
dontShowGoToTop: true,
showScrollToTopView: false
})
}
moveToTop = () => {
this.flatListRef.scrollToOffset({
offset: HEADER_HEIGHT,
animated: true
})
}
renderScrollToTopView = () => {
return (
<View style={styles.scrollToTopContainer}>
<View style={styles.buttonsContainer}>
<TouchableOpacity onPress={this.moveToTop} style={styles.buttonCta} activeOpacity={1}>
<CustomText textStyle={styles.goToTopLabel}>{labels.GO_TO_TOP}</CustomText>
</TouchableOpacity>
<TouchableOpacity onPress={this.onClikCrossIcon} style={styles.crossIconCta} activeOpacity={1}>
<IconButtonWrapper iconImage={icons.CROSSWHITE_ICON} iconHeight={dimens.size10} iconWidth={dimens.size10} />
</TouchableOpacity>
</View>
</View>
)
}
render() {
const { shouldRefresh, showScrollToTopView, dontShowGoToTop } = this.state
const { getFlatListRef, uniqueKey, getScrolledPosition, renderScrollToTopView = false } = this.props
return (
<ScrollValueContext.Consumer>
{(context) => (
<>
{showScrollToTopView && !dontShowGoToTop && renderScrollToTopView && this.renderScrollToTopView()}
<FlatListWrapper
{...this.props}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: context.scrollYValue } } }], {
useNativeDriver: true,
listener: ({ nativeEvent }) => {
const yOffsetValue = get(nativeEvent, 'contentOffset.y', 0)
log('Flatlist wrapper on event is called', yOffsetValue)
this.scrolledValue = yOffsetValue
// context.scrollYValue.setValue(this.scrolledValue)
{
renderScrollToTopView && this.showScrollToTopView()
}
if (getScrolledPosition) {
getScrolledPosition(yOffsetValue)
}
}
})}
refreshControl={
<RefreshControl
refreshing={shouldRefresh}
progressViewOffset={HEADER_HEIGHT}
onRefresh={() => {
this.onRefresh()
}}
/>
}
showCustomizedAnimatedFlatList={true}
contentContainerStyle={[styles.contentStyle, this.props.contentContainerStyle]}
scrollEventThrottle={16}
inputRef={(ref) => {
log('inputRefinputRefis called')
if (ref) {
this.flatListRef = ref
if (getFlatListRef) {
getFlatListRef(ref)
}
context.addFlatListRef(this.flatListRef, uniqueKey)
}
}}
onMomentumScrollEnd={({ nativeEvent }) => {
const { contentOffset } = nativeEvent
if (contentOffset.y === 0) {
log('inside onMomentumScrollEnd')
context.flatListRef.forEach((item) => {
if (item.key !== uniqueKey) {
item.value.scrollToOffset({
offset: 0,
animated: false
})
}
})
}
}}
/>
</>
)}
</ScrollValueContext.Consumer>
)
}
}
So my code is like this. where flatlist wrapper is just the wrapper of flatlist.
In flatlist scroll to offset is not working properly when the no of items are less than 3. If the no of items are greater or equal to 3 than it is working exactly fine.
Image of Error
I am using ios emulator and keep on receiving this error when i go to run the profile page. It first loads for a little bit then stops and the error pops up it says it's on the 'this.state.user.avatar' but i can't seem to see what i wrong with it? what am i doing wrong? if someone can help me that would be great!
This is my ProfileScreen.js file
import React from "react";
import {View, Text, StyleSheet, TouchableOpacity, Button, Image } from "react-native";
import Fire from '../utilities/Fire';
export default class ProfileScreen extends React.Component {
state = {
user: {}
};
unsubscribe = null;
componentDidMount() {
const user = this.props.uid || Fire.shared.uid
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
}
componentWillUnmount() {
this.unsubscribe();
};
render() {
return(
<View style={styles.container}>
<View style = {{ MarginTop: 64, alignItems: "Center" }}>
<View style={styles.avatarContainer}>
<Image style={styles.avatar} source={this.state.user.avatar ? { uri: this.state.user.avatar } : require("../assets/avatar.png")}
/>
</View>
<Text style={styles.name}>{this.state.user.name}</Text>
</View>
<View style={styles.subContainer}>
<View style={styles.stat}>
<Text style={styles.info}>8/10</Text>
<Text style={styles.Title}>Rewards</Text>
</View>
<View style={styles.stat}>
<Text style={styles.info}>80/100</Text>
<Text style={styles.Title}>Badges</Text>
</View>
</View>
<Button onPress={() => {Fire.shared.signOUt()}} title="Log Out" />
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
},
avatarContainer:{
shadowColor: "#151734",
shadowRadius: 15,
shadowOpacity: 0.4
},
avatar: {
width: 136,
height: 136,
borderRadius: 68
},
name: {
marginTop: 24,
fontSize: 16,
fontWeight: "600"
},
subContainer: {
flexDirection: "row",
justifyContent: "space-between",
margin: 32,
},
stat: {
alignItems:"center",
},
info: {
color: "#4F566D",
fontSize: 18,
fontWeight: "300"
},
Title: {
color: "#C3C5CD",
fontSize: 12,
fontWeight: "500",
marginTop: 4
}
});
This is my Fire.js file
import FirebaseKeys from '../config';
import firebase from 'firebase';
require("firebase/firestore");
class Fire{
constructor() {
firebase.initializeApp(FirebaseKeys);
}
addPost = async({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri, 'photos/${this.uid}/${Date.now()}');
return new Promise ((res, rej) => {
this.firestore
.collection("posts")
.add ({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
};
uploadPhotoAsync = async (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
};
createUser = async user => {
let remoteUri = null
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
let db = this.firestore.collection("users").doc(this.uid)
db.set({
name: user.name,
email: user.email,
avatar: null
})
if (user.avatar) {
remoteUri = await this.uploadPhotoAsync(user.avatar, 'avatars/${this.uid}')
db.set({avatar: remoteUri }, { merge: true})
}
} catch (error) {
alert("Error: ", error);
}
};
signOut = () => {
firebase.auth().signOut();
};
get firestore(){
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
If you want to set the state like that you need to do it in the constructor like this:
constructor(props) {
super(props);
this.state = {
user: {}
}
}
So add that code to the top of the class and it should actually set the user to an empty object..
Everywhere else in the app you use setState....
Try to change user{} by user[]
I'm trying to execute a function and navigate to the next screen using React-navigation and creating an Axios post
I've already tried combining both function's but It doesn't seem to execute the createOrder function
If I run the createOrder function alone it does work
onPress={
() => {
this.createOrder
this.props.navigation.navigate('Cart', {
order : this.state.order
});
}
}
import React from 'react';
import {
View,
StyleSheet,
Text,
Image,
TouchableOpacity
} from 'react-native';
//Redux
import { connect } from 'react-redux';
import { addItemToCart, removeItem } from '../../actions/ProductActionCreators';
//Products
import Products from '../../components/products/Products';
// Api Url
import ApiUrl from '../../helpers/ApiUrl'
//UI LIBRARY
import { Input, Button } from 'react-native-elements';
import {LinearGradient} from "../../components/LinearGradient";
import { ButtonGroup } from 'react-native-elements';
import Icon from "react-native-vector-icons/Ionicons";
//AXIOS
import axios from 'axios';
export class ProductsListView extends React.Component {
constructor(props) {
super(props);
const { rows } = this.props.navigation.state.params;
const arrays = Object.values( {rows});
this.state = {
arrays,
filteredProducts: arrays,
selectedIndex: 2
};
this.updateIndex = this.updateIndex.bind(this)
}
createOrder () {
axios.post( ApiUrl + 'api/order/post', {
code: "4f",
status: "waiting",
user_name: "salman",
user_id: 1,
club_id: 1,
})
.then(response => {
this.setState({
order: response.data,
});
console.log('created order',this.state.order)
})
.catch(function (error) {
console.log('error',error);
})
}
updateIndex (selectedIndex) {
this.setState({selectedIndex})
}
filterAll(){
}
filterStrong(){
this.setState({
arrays: this.state.arrays[0].products.filter(item => item.type == "strong" )
})
console.log(this.state.arrays)
}
filterNormal(){
}
render() {
const component1 = () => <Icon
name="ios-star"
size={15}
color="gold"
/>
const component2 = () => <Icon
name="ios-beer"
size={15}
color="gold"
onPress={() => this.filterStrong}
/>
const component3 = () => <Icon
name="ios-wine"
size={15}
color="gold"
/>
const buttons = [{ element: component1 }, { element: component2 }, { element: component3 }]
const { selectedIndex } = this.state
return (
<View style={styles.container} >
<Image
style={styles.imageCard}
source={
{
uri:
this.state.arrays[0].image
}
}
/>
<Text style={styles.title} >
{this.state.arrays[0].name}
</Text>
<Products
products={this.state.arrays[0].products}
addItemToCart={this.props.addItemToCart}
removeItem={this.props.removeItem}
/>
<View style={{
justifyContent:'center',
width: '100%',
padding: 50,
paddingTop:20,
}}>
<Button
title="Go to my cart"
containerStyle={{ flex: -1 }}
buttonStyle={styles.signUpButton}
linearGradientProps={{
colors: ['#dd016b', '#dd016b'],
start: [1, 0],
end: [0.2, 0],
}}
ViewComponent={LinearGradient}
titleStyle={styles.signUpButtonText}
// onPress={this.createOrder}
onPress={
() => {
this.createOrder
this.props.navigation.navigate('Cart', {order : this.state.order});
}
}
/>
</View>
</View>
)
}
}
const mapDispatchToProps = {
addItemToCart,
removeItem
}
export default connect(null, mapDispatchToProps) (ProductsListView);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
width:'100%',
backgroundColor: 'black',
},
signUpButtonText: {
// fontFamily: 'bold',
fontSize: 13,
},
signUpButton: {
width: 250,
borderRadius: 50,
height: 45,
},
title: {
color:'white',
fontSize:32,
height: 100,
position: 'relative',
backgroundColor: '#00000054',
width: "100%",
textAlign: 'center',
paddingTop: 30,
},
imageCard:{
height:100,
width:'100%',
position: "absolute",
top: 0,
backgroundColor: 'white'
},
button: {
padding: 5,
borderRadius: 25,
margin: 5,
backgroundColor: '#DD016B',
color: 'white',
alignItems: 'center',
justifyContent: 'center',
},
})
I'm trying to navigate to the next screen with the data from I get from my Axios post.
You are not calling the createOrder function.
Try this:
<Button
title="Go to my cart"
containerStyle={{ flex: -1 }}
buttonStyle={styles.signUpButton}
linearGradientProps={{
colors: ["#dd016b", "#dd016b"],
start: [1, 0],
end: [0.2, 0]
}}
ViewComponent={LinearGradient}
titleStyle={styles.signUpButtonText}
// onPress={this.createOrder}
onPress={this.onGoToMyCartPressed}
/>;
And onGoToMyCartPressed would look like:
onGoToMyCartPressed = () => {
this.createOrder(); // <- Call the function
this.props.navigation.navigate("Cart", { order: this.state.order });
};
And, if you want to navigate after the order has been created, then, have your createOrder return the promise, and you can chain off of it in the onGoToMyCartPressed
Like so:
createOrder() {
// Return the promise from here
return axios.post( ApiUrl + 'api/order/post', {
code: "4f",
status: "waiting",
user_name: "salman",
user_id: 1,
club_id: 1,
}).then(response => {
this.setState({
order: response.data,
});
console.log('created order',this.state.order)
}).catch(function (error) {
console.log('error',error);
})
}
And modify the onGoToMyCartPressed to use the promise returned.
onGoToMyCartPressed = () => {
// CHange the page once the order has been craeted
this.createOrder().then(() => {
this.props.navigation.navigate("Cart", { order: this.state.order });
})
};
Click here to View Page
I need your help here. I want to add Activity indicator with timeout after Login button is pressed but login button is already configured to loginUser() function! I just need to show activity indicator for some secs and login the user when button is pressed! Thankyou I been trying for week. I'm helpless. So please help me!
import React, { Component } from 'react';
import { StyleSheet, View, Text, Alert, TouchableOpacity, ActivityIndicator } from 'react-native';
import { Form, Input, Item, Button, Label, Body, } from 'native-base';
import { login } from "../actions";
import { Actions } from "react-native-router-flux";
import { connect } from "react-redux";
import { colors } from "../../../colors";
class UserLoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
};
this.loginUser = this.loginUser.bind(this);
this.loginSuccessCallback = this.loginSuccessCallback.bind(this);
this.loginErrorCallback = this.loginErrorCallback.bind(this);
}
forgotPassword() {
Actions.ForgotPassword();
};
loginSuccessCallback(user) {
};
loginErrorCallback(error) {
switch (error.code) {
case 'auth/user-not-found':
Alert.alert('Error', 'User not found. New user? SignUp');
break;
case 'auth/wrong-password':
Alert.alert('Error', 'Wrong Password');
break;
}
};
loginUser() {
const { email, password } = this.state;
const data = { email, password };
this.props.dispatch(login(data, this.loginSuccessCallback, this.loginErrorCallback));
};
render() {
return (
<View style={styles.container}>
<Form>
<Item floatingLabel>
<Label>Email</Label>
<Input
autoCorrect={false}
autoCapitalize="none"
returnKeyType="done"
onChangeText={(email) => this.setState({ email })} />
</Item>
<Item floatingLabel>
<Label>Password</Label>
<Input
secureTextEntry={true}
autoCorrect={false}
autoCapitalize="none"
returnKeyType="go"
onSubmitEditing={this.loginUser}
onChangeText={(password) => this.setState({ password })} />
</Item>
<Button style={styles.loginButton}
full
rounded
onPress={this.loginUser}>
<Text style={{ fontWeight: 'bold', color: 'white', fontSize: 20 }}>Login</Text>
</Button>
<TouchableOpacity onPress={this.forgotPassword}>
<Text style={styles.forgotButton}>Forgot Password?</Text>
</TouchableOpacity>
<--------------Loading Component ------------------>
<View style={styles.loading}>
<ActivityIndicator
animating={this.state.animating}
style={[{ height: 80 }]}
color="#C00"
size="large"
hidesWhenStopped={true} />
<Text style={{ color: 'red' }}>loading..</Text>
</View>
<------------------------------------------------------------------->
</Form>
</View>
);
}
}
function mapStateToProps(state, props) {
return {
user: state.authReducer.user,
};
}
export default connect(
mapStateToProps,
null
)(UserLoginForm);
const styles = StyleSheet.create({
container: {
marginTop: 10
},
loginButton: {
alignSelf: 'center',
marginTop: 10,
width: 250
},
forgotButton: {
alignSelf: 'center',
marginTop: 15,
color: colors.white
},
loading: {
position: 'absolute',
opacity: 0.5,
height: '50%',
width: '35%',
backgroundColor: 'black',
alignSelf: 'center',
alignItems: 'center',
borderBottomLeftRadius: 20,
borderBottomRightRadius: 20,
borderTopRightRadius: 20,
borderTopLeftRadius: 20,
}
})
Login function goes here..
<--------------------------------------------------------------------------------------------------->
import * as t from "./actionTypes";
import {auth} from "../../config/firebase";
import * as api from "./api";
export function register(data, successCB, errorCB) {
return dispatch => {
api.register(data, function (success, data, error) {
if (success) {
successCB(data);
} else if (error) errorCB(error);
});
};
}
export function checkLoginStatus(callback) {
return dispatch => {
auth.onAuthStateChanged(authUser => {
let isLoggedIn = authUser !== null;
if (isLoggedIn) {
api.getUser(authUser, function (success, {exists, user}, error) {
if (success) {
if (exists) {
dispatch({type: t.USER_LOGGED_IN, data: user});
callback(true, 'user');
}
else {
api.getEmployee(authUser, function (success, {exists, user}, error) {
if (success && exists) {
dispatch({type: t.EMPLOYEE_LOGGED_IN, data: user});
callback(true, 'employee');
} else {
dispatch({type: t.LOGGED_OUT});
callback(false);
}
})
}
} else if (error) {
//unable to get user
dispatch({type: t.LOGGED_OUT});
callback(false);
}
});
} else {
dispatch({type: t.LOGGED_OUT});
callback(false);
}
});
};
}
export function login(data, successCB, errorCB) {
return dispatch => {
api.login(data, function (success, data, error) {
if (success) {
if (data.exists) dispatch({type: t.USER_LOGGED_IN, data: data.user});
successCB(data);
} else if (error) errorCB(error);
});
};
}
export function logout(errorCB) {
return dispatch => {
api.logout(function (success, data, error) {
if (success) {
dispatch({type: t.LOGGED_OUT});
} else if (error) errorCB(error);
});
};
}
export function loginEmployee(data, successCB, errorCB) {
return dispatch => {
api.loginEmployee(data, function (success, data, error) {
if (success) {
if (data.exists) dispatch({type: t.EMPLOYEE_LOGGED_IN, data: data.user});
successCB(data);
} else if (error) errorCB(error);
});
};
}