I cannot get my api call from google-translate to work - javascript

I cannot figure out how to display the word that I am translating with my google-translate API ... I want to display the translated word from function newText to get displayed in the Text tag where I call that function.. (also the word to translate it's coming from the TextInput 'word to translate'
const Main = ({ navigation }) => {
let apiKey = "AIzaasdfasdfasdfasdfasdfsdc";
let googleTranslate = require("google-translate")(apiKey);
const [text, setText] = useState("");
const newText = () => {
googleTranslate.translate(text, "es", function (err, translation) {
return translation.translatedText;
});
};
const onChangeText = (text) => setText(text);
return (
<View style={styles.screen}>
<ImageBackground
source={require("./assets/book.png")}
style={styles.backgroundImage}
>
<View style={styles.innerText}>
<Text style={{ fontSize: 20 }}>Welcome back Elisa, </Text>
<Text>let's practice that pronunciation...</Text>
<TextInput
placeholder="Word to translate"
style={styles.input}
onChangeText={onChangeText}
/>
</View>
<Text style={styles.output}>{newText()}</Text>
<View style={styles.button}>
<Button
title="START"
onPress={() => navigation.navigate("BACK_HOME")}
/>
</View>
</ImageBackground>
</View>
);
};

I've converted newText() into an async function.
You can either call newText() with a onClick event, or use onChange as I've modified your codes below.
Google translate will be called whenever your input change (it's not a good idea because it means if you type 100 characters, it translate 100 times.).
I suggest you to add a button like this.
<button onClick={() => newText(text)}>Translate Me!</button>
const Main = ({ navigation }) => {
let apiKey = "AIzaasdfasdfasdfasdfasdfsdc";
let googleTranslate = require("google-translate")(apiKey);
const [text, setText] = useState("");
const [ translated, setTranslated ] = useState('');
const newText = async (toBeTranslated) => {
await googleTranslate.translate(toBeTranslated, "es", function (err, translation) {
setTranslated(translation.translatedText)
});
};
const onChangeText = (text) => {
setText(text);
//handle translation when text change.
newText(text);
}
return (
<View style={styles.screen}>
<ImageBackground
source={require("./assets/book.png")}
style={styles.backgroundImage}
>
<View style={styles.innerText}>
<Text style={{ fontSize: 20 }}>Welcome back Elisa, </Text>
<Text>let's practice that pronunciation...</Text>
<TextInput
placeholder="Word to translate"
style={styles.input}
onChangeText={onChangeText}
/>
</View>
<Text style={styles.output}>{translated}</Text>
<View style={styles.button}>
<Button
title="START"
onPress={() => navigation.navigate("BACK_HOME")}
/>
</View>
</ImageBackground>
</View>
);
};

Related

How do I get the document ID of a specific document in Firebase on React Native?

I'm working on a project that allows users to write anonymous letters addressed to people by name and I want to add a like/dislike functionality to the app. I was confused on how to get the specific document ID for that post and also incrementing the likeCount by 1 (in the areas where the "????" are at in the code below) ? I want it to update the field "likeCount" in firebase by 1 when the thumbs up icon is pressed.
This is the portion of my code that contains the posts (data from firebase) that is mapped for each firebase document:
function Home() {
const [posts, setPosts] = useState([]);
const [searchValue, setSearchValue] = useState("");
const [filteredPosts, setFilteredPosts] = useState([]);
const collectionRef = collection(db, "posts");
useEffect(() => {
const getPosts = async () => {
const data = await getDocs(collectionRef);
const filteredRef = query(
collectionRef,
where(`recipiant`, "==", `${searchValue}`)
);
const querySnapshot = await getDocs(filteredRef);
let posts = [];
querySnapshot.forEach((doc) => {
posts.push(doc.data());
});
setFilteredPosts(posts);
setPosts(
searchValue
? filteredPosts
: data.docs.map((doc) => ({ ...doc.data() }))
);
};
getPosts();
}, [searchValue, filteredPosts]);
return (
<ImageBackground source={image} style={styles.image}>
<SafeAreaView style={styles.container}>
<ScrollView>
<View style={styles.header}>
<Text style={styles.title}>Home</Text>
</View>
<Pressable>
<Input
placeholder="Search for a name"
inputContainerStyle={styles.searchbar}
inputStyle={styles.searchInput}
placeholderTextColor="gray"
onChangeText={(text) => setSearchValue(text)}
/>
</Pressable>
{posts.map((post, key) => {
return (
<View style={styles.postWrapper} key={key}>
<View style={styles.btnWrapper}>
<View style={styles.likeBtn}>
<Icon
name="thumbs-up"
size={25}
color="#fff"
onPress={() => {
const postRef = doc(db, "posts", `????`);
updateDoc(postRef, {
likeCount: ????,
});
}}
/>
<Text style={styles.likeCount}>{post.likeCount}</Text>
</View>
<Icon
name="thumbs-down"
size={25}
color="#fff"
onPress={() => {}}
/>
</View>
<Card
containerStyle={{
backgroundColor: "rgba( 255, 255, 255, 0.5 )",
borderRadius: 50,
height: 300,
marginBottom: 25,
width: 330,
backdropFilter: "blur( 20px )",
padding: 20,
}}
>
<Card.Title style={styles.notepadHeader}>Message.</Card.Title>
<View style={styles.center}>
<ScrollView>
<Text style={styles.notepadText}>
To: <Text style={styles.name}>{post.recipiant}</Text>
</Text>
<Text style={styles.notepadTextLetter}>
{post.letter}
</Text>
<Text style={styles.notepadFooter}>
From:{" "}
<Text
style={{
color: "#9e4aba",
fontSize: 20,
}}
>
{post.displayName}
</Text>
</Text>
</ScrollView>
</View>
</Card>
</View>
);
})}
</ScrollView>
</SafeAreaView>
</ImageBackground>
);
}
This is how my Firestore looks like and I want to retrieve the document id in the circle.
First, you can add the document ID in 'posts' array as shown below:
const posts = querySnapshot.docs.map((d) => ({ id: d.id, ...d.data() }));
setFilteredPosts(posts);
Then you can read post ID when required:
<Icon
name = "thumbs-up"
size = {25}
color = "#fff"
onPress = {() => {
const postRef = doc(db, "posts", post.id);
updateDoc(postRef, {
likeCount: ?? ?? ,
});
}
}
/>
This will give you the particular doc and perform updateDoc query accordingly.
query(collections('collection_name), where(documentId(), '==', 'your_post_id'))

How to pass up nested state and avoid useCallback in react native

I have a parent and nest child component hierarchy of QuestionsAndAnswersScreen -> QuestionInput -> QuestionSelector -> AnswerSelector. I need to pass the question and answer object back up to the QuestionAndAnswerScreen in order to show it on the view. However I cannot find a way without going into deep nested callbacks.
Here is my code for the QuestionAnswerScreen and AnswerSelector:
function QuestionsAndAnswers() {
const {shell, body} = styles;
return (
<View style={shell}>
<SignUpHeader title="Add your answers" page={5}/>
<View style={body}>
{qAndA[1] ? <Answer question={qAndA[1].question} answer={qAndA[1].answer}/> : <QuestionInput />}
{qAndA[2] ? <Answer question={qAndA[2].question} answer={qAndA[2].answer}/> : <QuestionInput />}
{qAndA[3] ? <Answer question={qAndA[3].question} answer={qAndA[3].answer}/> : <QuestionInput />}
</View>
<SignUpFooter
title={`Questions\n& Answers`}
buttonTitle={"Done"}
disabled={false}
route="QuestionsAndAnswers"
/>
</View>
);
}
function AnswerInput(props: AnswerInputProps) {
const {question, visible, answerModalVisible} = props;
const {pickAnAnswer, doneButton, answerTextInput, questionStyle, shell, buttonText} = styles;
const [modalVisible, setModalVisible] = useState(visible)
const [answer, setAnswer] = useState('');
const navigation = useNavigation();
useEffect(() => {
setModalVisible(visible)
}, [visible])
function answerQuestion() {
setModalVisible(false);
navigation.navigate('QuestionsAndAnswers');
}
return (
<View>
<Modal style={shell}
isVisible={modalVisible}
onBackdropPress={() => {
setModalVisible(false);
answerModalVisible(false);
}}
>
<View>
<Text style={pickAnAnswer}>Add answer</Text>
</View>
<View>
<Text style={questionStyle}>{question}</Text>
</View>
<View>
<TextInput
style={answerTextInput}
placeholder="Add your answer here..."
placeholderTextColor="#878787"
onChangeText={(text: string) => setAnswer(text)}
/>
<View style={{alignItems: 'flex-end', marginTop: 44}}>
<TouchableOpacity style={doneButton} onPress={() => answerQuestion()}>
<Text style={buttonText}>
Done
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
}
As you can see I get my Question and Answer in the AnswerInput but then need to navigate back to the main screen in order to display them. Any help would be great thanks :)

change Icon after clicking on it

I have a component that looks like this:
const criteriaList = [
'Nur Frauen',
'Freunde Zweiten Grades',
];
export const FilterCriteriaList: React.FunctionComponent = () => {
const [state, setState] = useState(false);
useEffect(() => {
console.log('state is,', state);
});
const myFunction = () => {
console.log('checking state', state);
if (state == false) {
setState(true);
} else {
setState(false);
}
};
return (
<View style={styles.container}>
<View style={styles.horizontalLine} />
{criteriaList.map((item: string, index: number) => (
<View key={index}>
<View style={styles.criteriaRow}>
<TouchableOpacity
onPress={() => {
myFunction();
}}>
<Icon
name="circle-thin"
color="#31C283"
size={moderateScale(20)}
/>
</TouchableOpacity>
<Text style={styles.text}>{item}</Text>
</View>
<View style={styles.horizontalLine} />
</View>
))}
</View>
);
};
Currently, I am using the circle-thin icon. I want to change it such that everytime I click on an icon, it changes to the dot-circle-o icon. Like radio buttons. However, I am not quite sure how to do so.
I thought of using ternary operators but since I am mapping my fields Idk how to setStates collectively. Maybe using the index? I don't want to make a separate state for each field. Here's a similar snack demo:
https://snack.expo.io/toTSYc2fD
I want to be able to select multiple/unselect options. I don't want to apply the same rule on all fields together.
Note: the onPress function can also be used on the Icon directly instead of the TouchableOpacity (though it is not preferred)
Using a ternary sounds like the right approach to me. Can you not do something like:
name={state ? 'dot-circle-o' : 'circle-thin'}
You could also refactor your function:
const myFunction = () => {
console.log('checking state', state);
setState(!state)
};
If you have multiple fields then there are many ways to handle it. You could call useState multiple times, eg:
const [field1, setField1] = useState(false);
const [field2, setField2] = useState(false);
You could also store all fields in the same state:
const [state, setState] = useState({field1: false, field2: false});
...
const myFunction = (fieldName) => {
console.log('checking state', state);
setState({...state, [fieldName]: !state[fieldName]})
};
I guess you'd then use the item as the "fieldName? In which case:
return (
<View style={styles.container}>
<View style={styles.horizontalLine} />
{criteriaList.map((item: string, index: number) => (
<View key={index}>
<View style={styles.criteriaRow}>
<TouchableOpacity
onPress={() => {
myFunction(item);
}}>
<Icon
name={state[item] ? 'dot-circle-o' : 'circle-thin'}
color="#31C283"
size={moderateScale(20)}
/>
</TouchableOpacity>
<Text style={styles.text}>{item}</Text>
</View>
<View style={styles.horizontalLine} />
</View>
))}
</View>
);
And to create the initial state:
const initialState = {}
criteriaList.forEach(item => initialState[item] = false)
const [state, setState] = useState(initialState);
The code would be something like below.
You have to set the index of the selected item as the state and use it to chose the icon.
const criteriaList = [
{title:'My List',checked:false},
{title:'Friends listt',checked:false},
{title:'Not Good',checked:false},
{title:'Sweet and sour',checked:false},
{title:'Automatic',checked:false},
];
export const FilterCriteriaList: React.FunctionComponent = () => {
const [state, setState] = useState(criteriaList);
useEffect(() => {
console.log('state is,', state);
});
const myFunction = (index) => {
console.log('checking state', state);
const arr=[...state];
arr[index].checked=arr[index].checked?false:true;
setState(arr);
};
return (
<View style={styles.container}>
<View style={styles.horizontalLine} />
{criteriaList.map((item: Any,index:number) => (
<View key={item}>
<View key={item} style={styles.criteriaRow}>
<Icon
style={styles.icon}
name={item.checked?"circle":"circle-thin"}
color="#31C283"
size={moderateScale(20)}
onPress= {()=>myFunction(index)}
/>
<Text style={styles.text}>{item.title}</Text>
</View>
<View style={styles.horizontalLine} />
</View>
))}
</View>
);
};

pass data between screens with getParamas

I'm rendering a few items in my map in ContactListand upon clicking on the thumbnail, I want to navigate to a new screen UserDetailsScreen such that the data about the clicked item is also passed along.
Previously I was using modals, but now I trying to switch to react-navigation.
ContactList.tsx:
export const ContactList: React.FunctionComponent<UserProps> = ({
data,
onDeleteContact,
}) => {
const [isUserVisible, setIsUserVisible] = useState(false);
//const [visibleUser, setVisibleUser] = useState<any>();
const navigation = useNavigation();
return (
<View style={styles.users}>
{data.users.nodes[0].userRelations.map(
(item: { relatedUser: RelatedUser; id: number }) => {
const numberOfFriends = item.relatedUser.userRelations.length;
const numberPlate = 'WHV AB 123';
return (
<View style={styles.item} key={item.id}>
{/* <TouchableOpacity onPress={() => setIsUserVisible(true)}> */}
<TouchableOpacity
onPress={() =>
navigation.navigate('UserDetailsScreen', {
firstName: item.relatedUser.firstName,
rating: item.relatedUser.rating,
numberOfFriends: numberOfFriends,
onDeleteContact: onDeleteContact,
isUserVisible: isUserVisible,
setIsUserVisible: setIsUserVisible,
numberPlate: numberPlate,
navigation: navigation,
})
}>
<Thumbnail
}}></Thumbnail>
</TouchableOpacity>
<View style={styles.nameNumber}>
<Text style={styles.userName}>{userName}</Text>
</View>
{/* <UserDetails
firstName={item.relatedUser.firstName}
rating={item.relatedUser.rating}
numberOfFriends={numberOfFriends}
onDeleteContact={onDeleteContact}
isUserVisible={isUserVisible}
setIsUserVisible={setIsUserVisible}
numberPlate={numberPlate}>
</UserDetails> */}
</View>
);
},
)}
</View>
);
};
UserDetailsScreen:
export const UserDetailsScreen: React.FunctionComponent<UserProps> = ({
firstName,
rating,
numberOfFriends,
numberPlate,
onDeleteContact,
navigation,
// isUserVisible,
// setIsUserVisible,
}) => {
//const navigation = useNavigation();
const fName = navigation.getParam('firstName')
return (
// <Modal visible={isUserVisible}>
<View style={styles.container}>
<View>
<TouchableOpacity
style={styles.cross}
//onPress={() => setIsUserVisible(false)}>
onPress={() => navigation.navigate('Whitelist')}>
<Thumbnail></Thumbnail>
</TouchableOpacity>
</View>
<View style={styles.searchLocationContainer}>
<UserInfoContainer
firstName={firstName}
rating={rating}
numberPlate={numberPlate}
numberOfFriends={numberOfFriends}></UserInfoContainer>
</View>
</View>
// </Modal>
);
};
Similarly, when I click on the thumbnail on this screen, I want to go back to my previous page where I can click on another object.
However, I keep getting an error that navigation.getParam is undefined. How can I fix this?
Hi you will get the data sent in the navigation params in
props.route.params

Render via map instead of for loop

I am currently using this function to render some elements & display results after a graphql query:
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
for (var i = 0; i < numberOfUsers; i++) {
const userName = data.users.nodes[i].firstName
.concat(' ')
.concat(data.users.nodes[i].lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(data.users.nodes[i].id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
}
},
[createUserRelationMutation, userData, numberOfUsers],
);
I have read that using a for loop isn't a good idea. Hence, I am trying to switch to a map but I am unable to. I couldn't figure out how to use variables like const userNamewhile using a map.
Currently, I can only test with numberOfUsers = 1so it works fine but in reality, I want all of the item contained in the Viewwhich is styled as friends. For now, there will be a separate <View style={styles.friends}>for each item. However, I want to map all items inside one single <View style={styles.friends}>
Map takes a function as its argument, which means that you can use that same code from the for loop inside of the function passed to the map, like this:
data.users.map((user) => {
const userName = user.firstName
.concat(' ')
.concat(user.lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(user.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
Just replace all instances of data.users.nodes[i] with user since that's what each object in the array is passed into the function as.
For more info about this, check this part of the React docs.
If you want everything to be contained inside the view styled as friends this is how the code should be.
You should have the map inside the view as JS code and access properties from the item variable.
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
return (
<View style={styles.friends}>
{
data.users.nodes.map(item => {
const userName = item.firstName
.concat(' ')
.concat(item.lastName);
return (<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(item.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>);
})
}
</View>
);
}
},
[createUserRelationMutation, userData, numberOfUsers],
);

Categories

Resources