Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item Component Collapsed in Flatlist when move to next #35361

Closed
hardikgpatel opened this issue Nov 16, 2022 · 6 comments
Closed

Item Component Collapsed in Flatlist when move to next #35361

hardikgpatel opened this issue Nov 16, 2022 · 6 comments
Labels
Needs: Triage 🔍 Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@hardikgpatel
Copy link

hardikgpatel commented Nov 16, 2022

Description

I am trying to create a slider using a flatlist; it works fine on most devices, but on the iPhone 12, it misbehaves. The first index item appears correctly, but when I move to the next item, the item container view collapses and all items move to the top of the screen. I have tried both vertical and horizontal scrolling directions. Is there anyone who can assist me in resolving this? I have attached some files for your reference.

phone.number.login.--.still.zoom.in.problem.mp4

iPhone 12 device information

Version

0.64.2

Output of npx react-native info

System:
OS: macOS 11.6
CPU: (12) x64 Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz
Memory: 231.70 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 19.0.1 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 8.19.2 - /usr/local/bin/npm
Watchman: 2022.11.07.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.2 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
Android SDK:
API Levels: 23, 25, 28, 30, 31, 32
Build Tools: 29.0.2, 30.0.0, 30.0.2, 30.0.3, 31.0.0, 32.0.0
System Images: android-30 | Google Play Intel x86 Atom
Android NDK: Not Found
IDEs:
Android Studio: 2021.2 AI-212.5712.43.2112.8815526
Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
Languages:
Java: 11.0.15 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: ^17.0.2 => 17.0.2
react-native: ^0.64.2 => 0.64.2
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Steps to reproduce

create a flatlist from the example code given.

Snack, code example, screenshot, or link to a repository

import React, {useContext, useEffect, useRef, useState} from 'react';
import {
View,
SafeAreaView,
FlatList,
TouchableOpacity,
Image,
KeyboardAvoidingView,
Keyboard,
ActivityIndicator,
StyleSheet,
} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import {getFilterIds} from '../../../Actions/FeedActions';
import AppImages from '../../../Theme/AppImages';
import CommonStyle from '../../../Theme/CommonStyle';
import {
currentEnv,
isIOS,
phoneNoVerifyHeaderImages,
phoneNoVerifyScreens,
STORAGE,
width,
} from '../../../Utils/Constant';
import {
CustomPhoneInput,
CustomText,
CustomTextInput,
OtpInput,
PaginatedHeader,
} from '../../CommonComponent';
import {CommonActions} from '@react-navigation/native';
import {getErrorMessage, isValidEmail, showToast} from '../../../Utils/Helper';
import {AppContext} from '../../../AppContext';
import {
addFCMToken,
resendCode,
userLogin,
userVerify,
} from '../../../Services/UserService';
import {updateUserDetail} from '../../../Actions/UserActions';
import {getItemFromStorage, setItemInStorage} from '../../../Utils/Storage';
import {ApiConfig} from '../../../ApiConfig';
import {getOnboardData} from '../../../Actions/OnboardActions';
import DeviceInfo from 'react-native-device-info';

let count = 0;

const VerifyPhone = props => {
const {
route: {params},
} = props;
const {appTheme} = useContext(AppContext);
const {
flexContainer,
bottomContainer,
rowCenter,
errorInput,
verificationText,
flexStyle,
} = CommonStyle;
const {itemContainer, titleText, loader, resendContainer} = styles;
const {navigation} = props;
const {user} = useSelector(state => state.user);
const [listIndex, setListIndex] = useState(params?.index ? params.index : 0);
const [error, setError] = useState({});
const [hasError, setHasError] = useState({
email: false,
code: false,
phone: false,
});
const [toggle, setToggle] = useState(false);
const [userData, setUserData] = useState({
email: user?.email || '',
phone: user?.phone || '',
code: '',
unmaskedPhone: user?.unmaskedPhone || '',
countryCode: user?.countryCode || '',
});
const [sendCode, setSendCode] = useState(false);
const dispatch = useDispatch();
let flatListRef = useRef('');

useEffect(() => {
count = 0;
dispatch(getOnboardData());
}, []);

const onTextChange = (key, text, isValid, unmaskedNo, countryCode) => {
if (key && text) {
userData[key] = text;
if (unmaskedNo && countryCode) {
userData.unmaskedPhone = unmaskedNo;
userData.countryCode = countryCode;
}
setUserData(userData);
if (key === 'email' && listIndex === 0 && !params?.index) {
if (!isValidEmail(text)) {
setErrorData(key, 'Enter valid email.', true);
} else if (isValidEmail(text)) {
setErrorData(key, '', false);
}
}

  if (key === 'phone' && listIndex === 1) {
    if (!isValid) {
      setErrorData(key, 'Enter valid phone number.', true);
    } else {
      setErrorData(key, '', false);
    }
  }

  if (key === 'code' && listIndex === 2) {
    setErrorData(key, '', false);
  }
}

};

const setErrorData = (key, msg, value) => {
let errorData = error;
let hasErrorData = hasError;
errorData[key] = msg;
hasErrorData[key] = value;
setHasError(hasErrorData);
setError(errorData);
setToggle(!toggle);
};

const navigateToRoute = (route, params = {}) => {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{name: route, params: params}],
}),
);
};

const getComponentFromType = (item, index) => {
if (item.type === 'textInput') {
return (
<CustomTextInput
placeholder={item.placeholder}
keyboardType={item.keyboardType}
onTextChange={text => {
onTextChange(item.key, text);
}}
value={user[item.key]}
autoCapitalize={'none'}
/>
);
} else if (item.type === 'phoneInput') {
return (
<CustomPhoneInput
onTextChange={(text, isVerified, unmaskedNo, countryCode) => {
onTextChange(item.key, text, isVerified, unmaskedNo, countryCode);
}}
userData={userData}
/>
);
} else {
return (
<OtpInput
digits={6}
value={userData.code}
onChangeOtp={text => onTextChange(item.key, text)}
/>
);
}
};

const updateStorage = async data => {
setItemInStorage('token', data?.token);
ApiConfig.token = data.token;
ApiConfig.streamKey = data.user.streamAppKey;
ApiConfig.streamToken = data.user.streamToken;
};

const clearOTP = () => {
userData.code = '';
error.code = '';
hasError.code = '';
setUserData(userData);
setError(error);
setHasError(hasError);
};

const registerUser = async () => {
try {
if (count === 0) {
count = count + 1;
let registerData = userData;
if (user.provider) {
registerData.provider = user.provider;
registerData.providerId = user.providerId;
}
registerData.register = true;
console.log('registerData', registerData);
const response = await userLogin(registerData);
if (response.status === 'success') {
count = 0;
moveToNext();
// ApiConfig.token = response.data.userItem.activationToken;
// setItemInStorage('token', response.data.userItem.activationToken);
// dispatch(updateUserDetail(response.data.userItem));
// showToast(response.data.code);
}
}
} catch (err) {
if (err?.response?.data) {
count = 0;
setErrorData('phone', getErrorMessage(err), true);
}
}
};

const updateFCMToken = async () => {
const localToken = await getItemFromStorage(STORAGE.fcmToken);
console.log('localToken', localToken);
try {
if (localToken) {
const deviceId = await DeviceInfo.getDeviceId();
const data = {
token: localToken,
platform: isIOS ? 'ios' : 'android',
environment: currentEnv,
deviceId: deviceId,
};
console.log('data register firebase', data);
const repoonse = await addFCMToken(data);
console.log('repoonse', repoonse);
}
} catch (e) {
console.log(e);
}
};

const verifyUser = async () => {
try {
if (count === 0) {
count = count + 1;
let verificationData = userData;
verificationData.register = true;
console.log('verificationData', verificationData);
let response = await userVerify(verificationData);
if (response.status === 'success') {
console.log('response', response);
updateStorage(response.data);
ApiConfig.token = response.data.user.activationToken;
setItemInStorage('token', response.data.user.activationToken);
dispatch(
updateUserDetail({
...userData,
...response?.data?.user,
}),
);
if (response?.data?.user?.isProfileCompleted) {
makeTogetherCall(response?.data?.user);
showToast(
'Phone number already exists. Redirecting to together feeds.',
);
updateFCMToken();
navigateToRoute('Home');
} else {
showToast(response?.message);
navigateToRoute('SignUp');
}
}
}
} catch (err) {
if (err?.response?.data) {
count = 0;
userData.code = '';
setUserData(userData);
setErrorData('code', getErrorMessage(err), true);
}
}
};

const makeTogetherCall = userObj => {
dispatch(getFilterIds({user: userObj}));
};

const moveToNext = () => {
flatListRef?.scrollToIndex({index: listIndex + 1});
setListIndex(listIndex + 1);
};

const scrollToNext = () => {
Keyboard.dismiss();
if (listIndex === 1) {
registerUser();
} else if (listIndex === 2) {
console.log('asdfasdfadsf');
verifyUser();
} else {
moveToNext();
}
};

const scrollToPrevious = () => {
count = 0;
Keyboard.dismiss();
if (listIndex !== 0) {
if (listIndex === 2) {
clearOTP();
}
flatListRef?.scrollToIndex({index: listIndex - 1});
setListIndex(listIndex - 1);
} else {
navigation.goBack();
}
};

const checkError = () => {
let key =
(listIndex !== 0 && ((listIndex === 1 && 'phone') || 'code')) || 'email';

if (key !== 'phone') {
  let condition =
    key === 'email'
      ? hasError[key] || !userData[key]
      : hasError[key] || !userData[key] || userData[key].length !== 6;
  if (condition) {
    return true;
  }
  return false;
} else {
  if (hasError[key] || !userData.unmaskedPhone || !userData.countryCode) {
    return true;
  }
  return false;
}

};

const resendOTP = async () => {
try {
console.log(userData);
setSendCode(true);
const data = {phone: userData.phone, register: true};
const response = await resendCode(data);
if (response.status === 'success') {
clearOTP();
setSendCode(false);
// showToast(response.data.code);
}
} catch (error) {
setSendCode(false);
}
};

const renderItem = ({item, index}) => {
return (


{item.title}

{getComponentFromType(item, index)}
{(hasError[item.key] && (

{error[item.key]}

)) ||
null}
{(item.key === 'code' && (
<TouchableOpacity
style={[rowCenter, resendContainer]}
onPress={() => resendOTP()}>
{(sendCode && (
<ActivityIndicator
size={'small'}
color={appTheme.theme}
style={loader}
/>
)) ||
null}

{sendCode
? 'Sending Verification Code'
: 'Resend Verification Code'}


)) ||
null}

);
};

return (

<KeyboardAvoidingView
behavior={'padding'}
style={flexStyle}
keyboardVerticalOffset={isIOS ? '' : -500}>
<PaginatedHeader
headerImages={phoneNoVerifyHeaderImages}
activeIndex={listIndex}
onPressBack={() => {
scrollToPrevious();
}}
/>

<FlatList
showsHorizontalScrollIndicator={false}
data={phoneNoVerifyScreens}
renderItem={renderItem}
keyExtractor={item => item.id}
horizontal={true}
scrollEnabled={false}
ref={ref => {
flatListRef = ref;
}}
initialScrollIndex={params?.index ? params?.index : 0}
keyboardShouldPersistTaps={'always'}
/>

{(!checkError() && (
<TouchableOpacity
onPress={() => {
scrollToNext();
}}>
<Image
source={{uri: AppImages.next}}
style={CommonStyle.nextImage}
resizeMode="contain"
/>

)) || (
<Image
source={{uri: AppImages.disabled}}
style={CommonStyle.nextImage}
resizeMode="contain"
/>
)}




);
};

const styles = StyleSheet.create({
itemContainer: {
flex: 1,
width: width,
paddingHorizontal: 16,
marginTop: '10%',
},
titleText: {
marginBottom: '10%',
},
loader: {
marginRight: 10,
},
resendContainer: {
marginTop: 10,
},
});

export default VerifyPhone;

@Ahmed-Imam
Copy link

@hardikgpatel any updates on this ??

@hardikgpatel
Copy link
Author

Nop

@Ahmed-Imam
Copy link

@hardikgpatel we found the issue its cause of behavior={'padding'} if you would remove that it will work.
check the comment here for more info #29974 (comment)

@hardikgpatel
Copy link
Author

Okay i will check that

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jul 25, 2023
@github-actions
Copy link

github-actions bot commented Aug 1, 2023

This issue was closed because it has been stalled for 7 days with no activity.

@github-actions github-actions bot closed this as completed Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Triage 🔍 Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

2 participants