Flatlist item title display the previous items title property - react-native

ı am trying to create a title property for my recording. When ı type the name of the recording, if it's first on the list the title property became blank. After creating the second recording and typing the name it gets the title of the previous recording object. Tried to change the calling order of the modal function in stopRecording function, but it didn't work. I hope you can help. My code is not clean for now ı will arrange it later, please ignore it
import {
StyleSheet,
Text,
View,
Button,
FlatList,
TextInput,
Modal,
} from "react-native";
import { Audio } from "expo-av";
import { useState } from "react";
import * as Sharing from "expo-sharing";
export default function App() {
const [recording, setRecording] = useState();
const [recordings, setRecordings] = useState([]);
const [message, setMessage] = useState("");
const [modalVisible, setModalVisible] = useState(false);
const [title, setTitle] = useState("");
async function startRecording() {
try {
const permission = await Audio.requestPermissionsAsync();
if (permission.status === "granted") {
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
});
const { recording } = await Audio.Recording.createAsync(
Audio.RecordingOptionsPresets.HIGH_QUALITY
);
setRecording(recording);
} else {
setMessage("Please grant permission to app to access microphone");
}
} catch (err) {
console.error("Failed to start recording", err);
}
}
async function stopRecording() {
setModalVisible(!modalVisible);
setRecording(undefined);
await recording.stopAndUnloadAsync();
let updatedRecordings = [...recordings];
const { sound, status } = await recording.createNewLoadedSoundAsync();
updatedRecordings.push({
sound: sound,
file: recording.getURI(),
id: parseInt(Math.random() * 1000),
title: title,
});
setRecordings(updatedRecordings);
setTitle("");
}
function deleteItem(id) {
const filteredData = recordings.filter((item) => item.id !== id);
setRecordings(filteredData);
}
function recordingView(item) {
console.log(item);
return (
<View style={styles.row}>
<Text style={styles.fill}>{item.item.title}</Text>
<Button
style={styles.button}
onPress={() => item.item.sound.replayAsync()}
title="Play"
></Button>
<Button
style={styles.button}
onPress={() => Sharing.shareAsync(item.item.file)}
title="Share"
></Button>
<Button
style={styles.button}
onPress={() => {
deleteItem(item.item.id);
}}
title="Delete"
></Button>
</View>
);
}
return (
<>
<View style={styles.container}>
<Text>{message}</Text>
<FlatList
data={recordings}
keyExtractor={(item, index) => index}
renderItem={recordingView}
/>
<Button
title={recording ? "Stop Recording" : "Start Recording"}
onPress={recording ? stopRecording : startRecording}
/>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<View>
<View style={styles.generalContainer}>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
placeholder="Recording name"
onChangeText={(title) => {
setTitle(title);
}}
/>
<View style={styles.buttonContainer}>
<Button
title="Add"
onPress={() => setModalVisible(!modalVisible)}
/>
</View>
</View>
</View>
</View>
</Modal>
</View>
</>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
margin: 10,
},
row: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
},
fill: {
flex: 1,
margin: 16,
},
button: {
margin: 16,
},
input: {
textAlignVertical: "top",
fontSize: 17,
width: "100%",
height: 40,
marginTop: 10,
marginBottom: 10,
borderColor: "#ffffff",
width: "100%",
borderWidth: 2,
borderRadius: 15,
padding: 10,
color: "#ffffff",
},
generalContainer: {
margin: 30,
paddingTop: 10,
paddingBottom: 10,
backgroundColor: "gray",
borderRadius: 15,
elevation: 4,
},
inputContainer: {
padding: 20,
alignItems: "center",
},
});

The problem with your current code is that in your stopRecording() function, you tried to get the title by having the user key in the name from the modal but it will not work because that portion is synchronous meaning that the code below setModalVisable will already have ran before the user can even input a title. To fix this you must first get the user to key in the title before the recording can be saved.
I have modified the code to fix the issue.
import {
StyleSheet,
Text,
View,
Button,
FlatList,
TextInput,
Modal,
} from 'react-native';
import { Audio } from 'expo-av';
import { useState, useEffect } from 'react';
export default function App() {
const [recording, setRecording] = useState();
const [recordings, setRecordings] = useState([]);
const [isRecording, setIsRecording] = useState(false);
const [message, setMessage] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [title, setTitle] = useState('');
useEffect(() => {
(async () => {
if (!modalVisible && title != '') {
saveRecording();
}
})();
}, [modalVisible]);
async function startRecording() {
try {
const permission = await Audio.requestPermissionsAsync();
if (permission.status === 'granted') {
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
});
const { recording } = await Audio.Recording.createAsync(
Audio.RecordingOptionsPresets.HIGH_QUALITY
);
setRecording(recording);
setIsRecording(true);
} else {
setMessage('Please grant permission to app to access microphone');
}
} catch (err) {
console.error('Failed to start recording', err);
}
}
async function stopRecording() {
try {
await recording.stopAndUnloadAsync();
} catch (error) {
console.log(error);
}
setIsRecording(false);
setModalVisible(!modalVisible);
}
async function saveRecording() {
try {
// setRecording(undefined);
// await recording.stopAndUnloadAsync();
let updatedRecordings = [...recordings];
const { sound, status } = await recording.createNewLoadedSoundAsync();
updatedRecordings.push({
sound: sound,
file: recording.getURI(),
id: parseInt(Math.random() * 1000),
title: title,
});
setRecordings(updatedRecordings);
setTitle('');
} catch (error) {
console.log(error);
}
}
function deleteItem(id) {
const filteredData = recordings.filter((item) => item.id !== id);
setRecordings(filteredData);
}
function recordingView(item) {
console.log(item);
return (
<View style={styles.row}>
<Text style={styles.fill}>{item.item.title}</Text>
<Button
style={styles.button}
onPress={() => item.item.sound.replayAsync()}
title="Play"></Button>
<Button
style={styles.button}
onPress={() => Sharing.shareAsync(item.item.file)}
title="Share"></Button>
<Button
style={styles.button}
onPress={() => {
deleteItem(item.item.id);
}}
title="Delete"></Button>
</View>
);
}
return (
<>
<View style={styles.container}>
<Text>{message}</Text>
<FlatList
data={recordings}
keyExtractor={(item, index) => index}
renderItem={recordingView}
/>
<Button
title={isRecording ? 'Stop Recording' : 'Start Recording'}
onPress={isRecording ? stopRecording : startRecording}
/>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<View>
<View style={styles.generalContainer}>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
placeholder="Recording name"
onChangeText={(title) => {
setTitle(title);
}}
/>
<View style={styles.buttonContainer}>
<Button
title="Add"
onPress={() => setModalVisible(!modalVisible)}
/>
</View>
</View>
</View>
</View>
</Modal>
</View>
</>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
margin: 10,
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
fill: {
flex: 1,
margin: 16,
},
button: {
margin: 16,
},
input: {
textAlignVertical: 'top',
fontSize: 17,
width: '100%',
height: 40,
marginTop: 10,
marginBottom: 10,
borderColor: '#ffffff',
width: '100%',
borderWidth: 2,
borderRadius: 15,
padding: 10,
color: '#ffffff',
},
generalContainer: {
margin: 30,
paddingTop: 10,
paddingBottom: 10,
backgroundColor: 'gray',
borderRadius: 15,
elevation: 4,
},
inputContainer: {
padding: 20,
alignItems: 'center',
},
});

Related

How to Filter List Without Losing Data

The filter buttons on my React Native work in terms of filtering the data, but it doesn't keep the data that was filtered out, so I can only filter the data once and would have to input them again. I would like it to be able to filter without losing the data, so I can continuously switch between the different filters and show that they all work without needing to add new data.
import React, { useState } from 'react';
import {StyleSheet,Text,View,TextInput,TouchableOpacity,FlatList,Alert,Modal, Dimensions} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
function App() {
const [todoInput, settodoInput] = React.useState('')
const [Todos, setTodos] = React.useState([]);
const [FilterTodos, setFilterTodos] = React.useState([Todos]);
const StatusTab = [
{
status: 'All',
completed: 'All'
},
{
status: 'Complete',
completed: true
},
{
status: 'Incomplete',
completed: false
}
]
const [Status,setStatus] = useState('All');
const setStatusFilter = Status => {
if(Status !== 'All') {
setTodos([...Todos.filter(e => e.completed === Status)])
} else {
setTodos(Todos)
}
setStatus(Status);
};
const [isRender,setisRender] = useState(false);
const [modalVisible, setmodalVisible] = useState(false);
const [editText, seteditText] = useState();
const [editItem, seteditItem] = useState();
React.useEffect(()=>{
GetTasks();
},[]);
React.useEffect(()=>{
SaveTasks(Todos);
},[Todos]);
const ListItem = ({Todo}) => {
return <View style={styles.ListItem}>
<View style={{flex:1}}>
<Text style={[styles.TaskText,{textDecorationLine: Todo?.completed?"line-through":"none"}]}>{Todo?.task}</Text>
</View>
{!Todo?.completed && (
<TouchableOpacity style={[styles.EditIcon]} onPress={()=>completeTodo(Todo?.id)}>
<Icon name='done' size={20} color='#FFFFFF'/>
</TouchableOpacity>
)}
<TouchableOpacity style={[styles.EditIcon,{backgroundColor:'#5D76E8'}]}
onPress={()=>editTodo(Todo?.id)}>
<Icon name='edit' size={20} color='#FFFFFF'/>
</TouchableOpacity>
<TouchableOpacity style={[styles.EditIcon,{backgroundColor:'#D30404'}]}
onPress={()=>deleteTodo(Todo?.id)}>
<Icon name='delete' size={20} color='#FFFFFF'/>
</TouchableOpacity>
</View>
}
const SaveTasks = async Todos =>{
try {
const stringifyTodos = JSON.stringify(Todos)
await AsyncStorage.setItem('Todos', stringifyTodos)
} catch (e) {
console.log(e);
// saving error
}
};
const GetTasks = async () => {
try {
const Todos = await AsyncStorage.getItem('Todos');
if(Todos != null){
setTodos(JSON.parse(Todos));
}
} catch (error) {
console.log(error);
}
};
const addTodo = () =>{
if(todoInput == ""){
Alert.alert("Error","Please Input Task");
}
else{
// console.log(todoInput);
const newTodo = {
id:Math.random(),
task: todoInput,
completed: false,
};
setTodos([...Todos,newTodo])
settodoInput('');
}
}
const completeTodo = (todoID) => {
console.log(todoID);
const newTodos = Todos.map((item)=>{
if(item.id == todoID){
return {...item,completed:true}
}
return item;
});
setTodos(newTodos);
};
const editTodo = (item) => {
setmodalVisible(true);
seteditText(item.text);
seteditItem(item.id);
};
const handleEditItem = (editItem) =>{
const newData =Todos.map(item =>{
if (item.id == editItem) {
item.text = editText;
return item
}
return item;
})
setTodos(newData);
setisRender(!isRender);
}
const onPressSaveEdit = () => {
handleEditItem(editItem);
setmodalVisible(false);
}
const deleteTodo = (todoID) =>{
Alert.alert("Confirm","Delete Task?",[{
text:"Yes",
onPress: () => {const newTodos = Todos.filter(item => item.id != todoID);
setTodos(newTodos)}
},
{text:"No"}
])
};
return (
<View style={styles.Container}>
<View style={styles.Header}>
<TextInput style={styles.SearchBar} placeholder='Add Task'
value={todoInput} onChangeText={(text)=>settodoInput(text)}/>
<TouchableOpacity onPress={addTodo}>
<View style={styles.IconContainer}>
<Icon name="add" color='#FFFFFF' size={30}/>
</View>
</TouchableOpacity>
</View>
<View style={styles.TaskList}>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{padding:20,paddingBottom:100}}
data={Todos}
keyExtractor={(item) => item.id.toString()}
renderItem={({item})=><ListItem Todo={item}/>}
extraData={isRender}/>
<Modal
animationType='fade'
visible={modalVisible}
onRequestClose={() => setmodalVisible(false)}
>
<View style={styles.ModalView}>
<Text style={styles.ModalText}>Change Task:</Text>
<TextInput style={styles.ModalInput}
onChangeText={(text) => seteditText(text)}
defaultValue={editText}
editable={true}
multiline={false}
maxLength={200}/>
<Text style={styles.ModalText}>Task Status:</Text>
<TouchableOpacity style={styles.FilterTab}>
<Text style={styles.TabText}>Complete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.FilterTab}>
<Text style={styles.TabText}>Incomplete</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={()=> onPressSaveEdit()}
style={styles.SaveButton}>
<Text style={styles.ModalText}>Save</Text>
</TouchableOpacity>
</View>
</Modal>
</View>
<View style={styles.Footer}>
{
StatusTab.map(e => (
<TouchableOpacity style={[styles.FilterTab, Status === e.completed && styles.FilterTabActive]}
onPress={() => setStatusFilter(e.completed)}>
<Text style={[styles.TabText, Status === e.status && styles.TabTextActive]}>{e.status}</Text>
</TouchableOpacity>
))
}
</View>
</View>
);
}
const styles = StyleSheet.create({
Container:{
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
Header:{
flexDirection: 'row',
backgroundColor:'#000000',
alignItems: "center",
justifyContent: 'center',
width:'100%'
},
SearchBar:{
borderColor: "#FFFFFF",
backgroundColor: "#DDDDDD",
marginHorizontal: 5,
width: '40%',
height:'80%',
borderRadius: 30
},
IconContainer:{
height: 50,
width: 50,
backgroundColor: '#061380',
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center'
},
TaskList:{
flex: 10,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-around',
alignItems: 'center'
},
ListItem:{
padding:20,
backgroundColor:'#DEDEDE',
flexDirection:'row',
elevation:12,
borderRadius:7,
marginVertical:10
},
TaskText:{
fontWeight:'bold',
fontSize:15,
color:'#000000',
},
EditIcon:{
height:25,
width:25,
backgroundColor:'#1BCC48',
justifyContent:'center',
alignItems:'center',
marginLeft:5,
borderRadius:3
},
ModalView:{
flex:1,
alignItems:'center',
justifyContent:'center'
},
ModalText:{
fontSize:25,
fontWeight:'bold',
marginVertical:30,
marginLeft:10
},
ModalInput:{
width:'90%',
height:70,
borderColor:'#000000',
borderWidth:1,
fontSize:25
},
SaveButton:{
backgroundColor:'#3AE3A0',
paddingHorizontal:100,
alignItems:'center',
marginTop:20
},
Footer:{
flexDirection:'row',
alignSelf:'center',
marginBottom:10
},
FilterTab:{
width:Dimensions.get('window').width / 3.5,
flexDirection:'row',
borderWidth:1,
borderColor:'#4A4A4A',
padding:10,
justifyContent:'center'
},
FilterTabActive:{
backgroundColor:'#F87861'
},
TabText:{
fontSize:16,
},
TabTextActive:{
color:'#FFFFFF'
},
});
export default App;
added a new method and passing it to the Flatlist
const getTodos = (status) => {
return status === 'All'
? Todos
: Todos.filter((item) => item.completed === status);
};
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{ padding: 20, paddingBottom: 100 }}
data={getTodos(Status)}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <ListItem Todo={item} />}
extraData={isRender}
/>
please check this
demo code
I think you are changing the data array when filtering with:
setTodos([...Todos.filter(e => e.completed === Status)])
How I did it (similar) in my app:
const [filtered, setFiltered] = useState(setStatusFilter());
then you should
setFiltered([...Todos.filter(e => e.completed === Status)])
to have the filtered values in const filtered and the source list stay the same as before.. and you can then use the filtered to show in a mapping ..

Looped TextInput have the copy each other

this may sound stupid for the most of you but I'm new when it comes to using API and react native. My situation is the next. From my data I try to display questions and a text field so the customer can answer and therefore I retrieve the data. But my problem is the next on when I display and try to write in the TextInput no matter how I have they will all copy what I write in which ever one I'm writing on. I don't get what I am doing wrong. I tried with looping but I can't seem to get the right answer to solve my problem. Here's my code if someone can help me.
//import liraries
import React, { Component, useEffect, useState } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TextInput,
Picker,
} from 'react-native';
// create a component
const Get = ({ navigation }) => {
const [user, setUser] = useState();
// const [text, onChangeText] = React.useState(null);
const [selectedValue, setSelectedValue] = useState("Test");
const [text, onChangeText] = useState('');
const getUserData = async () => {
try {
let response = await fetch('https://survey-back-nmucl6ui6q-ey.a.run.app/survey/7b504f09-7a67-4f99-a402-c15a9388446c', {
headers: new Headers({
'Authorization': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTUxNTU1MjMsImlhdCI6MTY1NTA2OTExOCwic3ViIjoxfQ.eoLaDT4wP99yjC38DN2Zck2sgwXFvcRYrfzxszHkQvc',
'Content-Type': 'application/x-www-form-urlencoded'
}),
});
let json = await response.json();
console.log(json.question)
setUser(json.question);
} catch (error) {
console.error(error);
}
};
useState(() => {
getUserData();
}, []);
const renderItem = ({ item }) => {
return (
<View
style={{
borderBottomWidth: 1,
borderBottomColor: '#ccc',
padding: 5,
}}>
{item.question_type == 'text-field' ?
<View style={styles.questions}>
<Text style={styles.label}>{item.name}</Text>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
placeholder="Entrez votre réponse"
/>
</View>
: <Text>Erreur</Text>}
{item.question_type == 'select' ?
<View style={styles.questions}>
<Text style={styles.label}>{item.name}</Text>
<Picker
selectedValue={selectedValue}
onValueChange={(itemValue, itemIndex) =>
setSelectedValue(itemValue)}
>
{Object.keys(item.choice).map(key =>{
return (
<Picker.Item label={key} value={key} key={key} />
)
})}
</Picker>
</View>
: <Text style={{display: 'none'}}>Erreur</Text>}
<View>
{item.question_type == 'comboboxMulti' ?
<Text style={{ fontWeight: 'bold' }}>{item.name}</Text>
: <Text style={{display: 'none'}}>Ça marche pas</Text>}
</View>
</View>
);
};
return (
<View style={styles.container}>
<FlatList
data={user}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
// define your styles
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
borderRadius: 5,
marginLeft: 0,
},
label: {
textTransform: 'capitalize',
},
questions: {
justifyContent: 'center',
alignItems: 'start',
}
});
//make this component available to the app
export default Get;

I am unable to delete items in my React Native app

I am unable to delete items.
This is App.js file main file:
import { useState } from "react";
import {
StyleSheet,
Text,
View,
Button,
TextInput,
FlatList,
} from "react-native";
import Goalresults from "./Componets/Goalresult";
export default function App() {
const [comingdata, SetData] = useState("");
const [listdata, setlistdata] = useState([]);
function fetchText(enteredText) {
SetData(enteredText);
}
function buttonPress() {
setlistdata((newdata) => [
...newdata,
{ text: comingdata, id: Math.random.toString() },
]);
}
I am passing id as parameter here and used filter method so that it filter all the id and delete id from the array list.
function deleteitem(id) {
setlistdata((newdata) => {
return newdata.filter((goal) => goal.id !== id);
});
}
return (
<View style={styles.container}>
<View>
<Text style={styles.goalsc}>Your Goals</Text>
</View>
<View style={styles.container1}>
<TextInput
style={styles.textInput}
placeholder="Add Your Goals here..."
onChangeText={fetchText}
/>
<Button title="Add Goal" onPress={buttonPress} />
</View>
<View style={styles.hello}>
<FlatList
data={listdata}
renderItem={(itemdata) => {
return (
<Goalresults
id={itemdata.item.id}
onDeleteItem={deleteitem}
text={itemdata.item.text}
/>
);
}}
keyExtractor={(item, index) => {
return item.id;
}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 16,
},
container1: {
flex: 1,
height: 120,
// paddingTop: 10,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: "#808080",
},
textInput: {
width: "70%",
borderWidth: 1,
borderRadius: 10,
marginRight: 10,
padding: 8,
},
hello: {
flex: 3,
},
goalsc: {
fontSize: 20,
fontWeight: "bold",
paddingLeft: 140,
},
});
Second separated file:
import { View, Text, StyleSheet,Pressable} from "react-native";
function Goalresults(props) {
I used bind there to bind id:
return (
<Pressable onPress={props.onDeleteItem.bind(this,props.id)}>
<View style={styles.goalInput}>
<Text style={styles.textcolor}>{props.text}</Text>
</View>
</Pressable>
);
}
export default Goalresults;
const styles = StyleSheet.create({
goalInput: {
flex: 5,
borderRadius: 5,
paddingTop: 10,
backgroundColor: "#A020F0",
padding: 10,
margin: 10,
},
textcolor: {
color: "white",
},
});
There are a few issues with your code. I will list them as follows.
Inside Goalresults function change the bind on Pressable as
follows: <Pressable onPress={props.onDeleteItem.bind(props, props.id)}>
Inside buttonPress function correct this line { text: comingdata, id: Math.random().toString() }, you missed '()' paranthesis on random
Also on Goalresults add a key={itemdata.item.id}. It will help resolve the warning "duplicate keys".
Following is the complete code
App.js
export default function App() {
const [comingdata, SetData] = useState("");
const [listdata, setlistdata] = useState([]);
function fetchText(enteredText) {
SetData(enteredText);
}
function buttonPress() {
setlistdata((newdata) => [
...newdata,
{ text: comingdata, id: Math.random().toString() },
]);
}
function deleteitem(id) {
console.log('id: ', id)
setlistdata((newdata) => {
return newdata.filter((goal) => goal.id !== id);
});
}
return (
<View style={styles.container}>
<View>
<Text style={styles.goalsc}>Your Goals</Text>
</View>
<View style={styles.container1}>
<TextInput
style={styles.textInput}
placeholder="Add Your Goals here..."
onChangeText={fetchText}
/>
<Button title="Add Goal" onPress={buttonPress} />
</View>
<View style={styles.hello}>
<FlatList
data={listdata}
renderItem={(itemdata) => {
return (
<Goalresults
key={itemdata.item.id}
id={itemdata.item.id}
onDeleteItem={deleteitem}
text={itemdata.item.text}
/>
);
}}
keyExtractor={(item, index) => {
return item.id;
}}
/>
</View>
</View>
);
}
GoalResults.js
function Goalresults(props) {
return (
<Pressable onPress={props.onDeleteItem.bind(props, props.id)}>
<View style={styles.goalInput}>
<Text style={styles.textcolor}>{props.text}</Text>
</View>
</Pressable>
);
}

React Native - Refresh current expendable list view screen using class component?

My code for expendable list view using class component. i want to referesh screen on press of button press.
import React, { Component } from 'react';
import { LayoutAnimation, RefreshControl, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity, Platform } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
class ExpandableItemComponent extends Component {
constructor() {
super();
this.state = {
layoutHeight: 0,
};
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.item.isExpanded) {
this.setState(() => {
return { layoutHeight: null };
});
} else {
this.setState(() => {
return { layoutHeight: 0 };
});
}
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.layoutHeight !== nextState.layoutHeight) {
return true;
}
return false;
}
refreshScreen = (od_id) => {
let order_id = od_id;
var dataToSend = {
order_id: order_id,
};
var formBody = [];
for (var key in dataToSend) {
var encodedKey = encodeURIComponent(key);
var encodedValue = encodeURIComponent(dataToSend[key]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
fetch('Api call update status', {
method: 'POST',
body: formBody,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if (responseJson.status == 'true') {
this.setState({ successtext: 'Order Cancelled.' });
this.setState({ apiStatus: true });
} else {
this.setState({ errortext: 'Something went wrong.' });
}
});
}
render() {
let order_no = '';
if (this.props.item.orderno != '') {
order_no = 'ORDER : OD' + this.props.item.orderno;
}
return (
<View>
<TouchableOpacity activeOpacity={0.8} onPress={this.props.onClickFunction} style={styles.header}>
<Text style={(styles.headerText, { flex: 1 })}>{order_no}</Text>
<Text style={{ textAlign: 'center', flex: 1 }}>{this.props.item.order_status}</Text>
<Text style={{ textAlign: 'right', flex: 1 }}> {this.props.item.order_date} </Text>
</TouchableOpacity>
<View style={{ height: this.state.layoutHeight, overflow: 'hidden' }}>
<View>
<TouchableOpacity style={styles.content}>
<Text style={styles.text}> {' '}{this.props.item.item_list.replace(/\s+/g, ' ')}{' '} </Text>
<Text style={styles.text}> {' '}{this.props.item.address.trim()}{' '} </Text>
<Text style={styles.text}> {this.props.item.note.trim()} </Text>
</TouchableOpacity>
</View>
<View style={{ flexDirection: 'row', backgroundColor: '#F5F5F5' }}>
<TouchableOpacity style={(styles.cancelBtn, { flex: 1, justifyContent: 'center', alignItems: 'center' })} >
{(this.props.item.order_status == 'Processing' || this.props.item.order_status == 'Delivered') ? null : <Text style={styles.text} onPress={() => { this.refreshScreen(this.props.item.id) }} >Cancel</Text>}
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
export default class OrderListScreenCustomer extends React.Component {
constructor() {
super();
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
this.state = {
listDataSource: [],
userId: '',
apiStatus: false,
};
}
async componentDidMount() {
const output = await AsyncStorage.getItem('user_id');
this.setState({ userId: output });
const response = await fetch("Api call get list?userid=" + output, {
"method": "GET",
})
const responseJson = await response.json();
this.setState({
listDataSource: responseJson,
});
console.log(output);
}
updateLayout = (index) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const array = [...this.state.listDataSource];
array[index].isExpanded = !array[index].isExpanded;
this.setState(() => {
return { listDataSource: array, };
});
};
render() {
return (
<View style={styles.container}>
<ScrollView>
{this.state.listDataSource.map((item, key) => (
<ExpandableItemComponent key={item.id} onClickFunction={this.updateLayout.bind(this, key)} item={item} />
))}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30,
backgroundColor: '#F5FCFF',
},
topHeading: {
paddingLeft: 10,
fontSize: 20,
},
header: {
backgroundColor: '#C0C0C0',
padding: 16,
borderBottomColor: '#ccc',
borderBottomWidth: 1,
marginBottom: 3,
flexDirection: 'row',
},
headerText: {
fontSize: 16,
fontWeight: '500',
},
separator: {
height: 0.5,
backgroundColor: '#808080',
width: '95%',
marginRight: 10,
},
text: {
fontSize: 16,
color: '#606070',
padding: 10,
textAlign: 'left',
},
content: {
paddingLeft: 10,
paddingRight: 10,
backgroundColor: '#fff',
},
});

How to Choose File From Button next to input filed in the form in react native. (See image for better understanding)

I am new to react native. and I have created A form. Now in that form I want A choose file button next to the input filed. And when user click on that Choose file button. Either camera will open or gallery will open(as per user choice) and then When user click on choose file button A small image or just image name comes below the choose file button
here is my image for better understanding
here is my code
import React, {useState, Component} from 'react';
import {Picker, Text, StyleSheet, View,
TextInput, Button, KeyboardAvoidingView,
ScrollView, Alert, alert, TouchableOpacity, Dimensions,} from 'react-native';
import { StackNavigator, navigation} from "react-navigation";
import { Card, Badge, Block, } from "../components";
import { theme, mocks } from "../constants";
import DigSign from "./DigSign"
import { Ionicons } from '#expo/vector-icons';
const { height } = Dimensions.get("window");
const { width } = Dimensions.get("window");
class PickerDemo extends Component{
constructor(props) {
super(props);
this.state={
};
}
validateInputs = () => {
// if (!this.state.accountNo.trim())
if (!/[A-Z]{5}[0-9]{4}[A-Z]{1}/.test(this.state.PAN))
{
this.setState({ PANError: 'Please enter valid PAN Number' })
return;
}
if (!/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/.test(this.state.GST))
{
this.setState({ GSTError: 'Please enter valid GST Number' })
return;
}
if (!/^[2-9]{1}[0-9]{3}\\s[0-9]{4}\\s[0-9]{4}$/.test(this.state.Aadhar))
{
this.setState({ AadharError: 'Please enter valid Aadhar Number' })
return;
}
else {
Alert.alert("All fields validated")
return;
}
}
handlePAN = (text) => {
this.setState({ PANError: '' })
this.setState({ PAN: text })
}
handleGST = (text) => {
this.setState({ GSTError: '' })
this.setState({ GST: text })
}
handleAadhar = (text) => {
this.setState({ AadharError: '' })
this.setState({ Aadhar: text })
}
render(){
const offset = (Platform.OS === 'android') ? -200 : 0;
const { navigation } = this.props;
return (
<View style={{flex: 1}}>
<View style={styles.header}>
<Ionicons style={{paddingLeft:20}} name="arrow-back" size={40}
color="black" onPress={() => navigation.navigate("FormItems")} />
<Text style={{fontSize:20, paddingLeft: 70, paddingTop: 10}}>KYC Details</Text>
</View>
<KeyboardAvoidingView keyboardVerticalOffset={offset} style={styles.form} behavior='padding'>
<Text style={styles.formLabel}> OTHER INFORMATION Form </Text>
<ScrollView style={{flex: 1,}} showsVerticalScrollIndicator={false}>
<View style={{flexDirection:'row'}}>
<TextInput maxLength={30} placeholder="PAN Card Number *" style={styles.inputStyle}
onChangeText={this.handlePAN} />
<View style={{justifyContent:"center"}}>
<Button title={'Choose File'}/>
</View>
</View>
<Text>{this.state.PANError}</Text>
<View style={{flexDirection:'row'}}>
<TextInput maxLength={30} placeholder="GSTIN Number*" style={styles.inputStyle}
onChangeText={this.handleGST} />
<View style={{justifyContent:"center"}}>
<Button title={'Choose File'}/>
</View>
</View>
<Text>{this.state.GSTError}</Text>
<View style={{flexDirection:'row'}}>
<TextInput maxLength={30} placeholder="Aadhar Card Number*" style={styles.inputStyle}
onChangeText={this.handleAadhar} />
<View style={{justifyContent:"center"}}>
<Button title={'Choose File'}/>
</View>
</View>
<Text>{this.state.AadharError}</Text>
<TouchableOpacity
onPress={() => navigation.navigate("DigSign")}
>
<Card center middle shadow style={styles.category}>
<Text medium height={1} size={1}>
Digital Signature
</Text>
</Card>
</TouchableOpacity>
<TouchableOpacity
onPress={() => navigation.navigate("ImgpickWithCam")}
>
<Card center middle shadow style={styles.category}>
<Text medium height={1} size={1}>
Pick An Image From Camera
</Text>
</Card>
</TouchableOpacity>
</ScrollView>
<View style={{ height: 30 }} />
<Button style={styles.inputStyleB}
title="Submit"
color="#808080"
onPress={() => this.validateInputs()}
/>
</KeyboardAvoidingView>
</View>
);
};
}
const styles = StyleSheet.create({
form: {
flex: 1,
justifyContent: "center",
flex: 1,
backgroundColor: "rgb(247, 146, 57)",
alignItems: 'center',
paddingTop: 50,
},
container: {
flex: 1,
backgroundColor: "rgb(247, 146, 57)",
alignItems: 'center',
// justifyContent: 'center',
paddingTop: 15
},
formLabel: {
fontSize: 20,
color: 'rgb(10, 10, 10)',
},
inputStyle: {
marginTop: 20,
width: 220,
height: 40,
paddingHorizontal: 10,
borderRadius: 50,
backgroundColor: 'rgb(255, 252, 252)',
},
formText: {
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: 20,
},
text: {
color: '#fff',
fontSize: 20,
},
category: {
marginTop: 20,
// this should be dynamic based on screen width
minWidth: (width - theme.sizes.padding * -10 - theme.sizes.base) / 2,
maxWidth: (width - theme.sizes.padding * -10 - theme.sizes.base) / 2,
maxHeight: (height - theme.sizes.padding * -50 - theme.sizes.base) / 2,
},
header:{
flexDirection: 'row'
}
});
export default PickerDemo;
Here is the solution based on the previous examples that I have given you.
You just had to implement the conditional rendering to it.
Just a couple of lines of code what was needed :)
Working Example: Expo Snack
import React, { useState, useEffect } from 'react';
import {
StyleSheet,
View,
Button,
Image,
FlatList,
Text,
TextInput,
} from 'react-native';
import { Camera } from 'expo-camera';
import { Ionicons } from '#expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
export default function Add() {
const [cameraPermission, setCameraPermission] = useState(null);
const [galleryPermission, setGalleryPermission] = useState(null);
const [showCamera, setShowCamera] = useState(false);
const [camera, setCamera] = useState(null);
const [imageUri, setImageUri] = useState([]);
const [type, setType] = useState(Camera.Constants.Type.back);
const [imageArray, setImageArray] = useState([]);
const permisionFunction = async () => {
// here is how you can get the camera permission
const cameraPermission = await Camera.requestPermissionsAsync();
console.log('camera permission:', cameraPermission.status);
setCameraPermission(cameraPermission.status === 'granted');
const imagePermission = await ImagePicker.getMediaLibraryPermissionsAsync();
console.log('permission:', imagePermission.status);
setGalleryPermission(imagePermission.status === 'granted');
if (
imagePermission.status !== 'granted' &&
cameraPermission.status !== 'granted'
) {
alert('Permission for media access needed.');
}
};
useEffect(() => {
permisionFunction();
}, []);
const takePicture = async () => {
if (camera) {
const data = await camera.takePictureAsync(null);
console.log(data.uri);
setImageUri(data.uri);
setImageArray([...imageArray, data.uri]);
setShowCamera(false);
}
};
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
});
console.log(result.uri);
if (!result.cancelled) {
setImageArray([...imageArray, result.uri]);
}
};
return (
<View style={styles.container}>
{showCamera && (
<Camera ref={(ref) => setCamera(ref)} style={{ flex: 1 }} type={type} />
)}
{showCamera && <Button title={'Click'} onPress={takePicture} />}
{!showCamera && (
<>
<View
style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<TextInput placeholder={'Enter PAN Number'} />
<View style={{ flexDirection: 'row' }}>
<Button
title={'Camera'}
onPress={() => {
setShowCamera(true);
}}
/>
<Button title={'Gallery'} onPress={pickImage} />
</View>
</View>
{imageArray.length > 0 && (
<View style={{ height: 110 }}>
<FlatList
horizontal
data={imageArray}
renderItem={({ item }) => (
<Image
source={{ uri: item }}
style={{
width: 100,
height: 100,
borderRadius: 10,
margin: 5,
}}
/>
)}
/>
</View>
)}
</>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 30,
flex: 1,
},
fixedRatio: {
flex: 1,
},
});