How to replace #mention in string with a Text Componet with link - React Native - react-native

I am using React Native. What I need to do is from a text that I extract from the DB to apply a format (font color, link) to make #mentions, when searching if in the text finds 1 single match makes replacement all good, but if there are several #mentions in the text, it throws me an error.
Text example:
hey what happened #-id:1- everything ok ?? and you #-id:2- #-id:3- #-id:4-
//// listusers its array, example: [idusuario: "1", usuario: "#luigbren", format: "#-id:1-".....]
const PatternToComponent = (text, usuarios,) => {
let mentionsRegex = new RegExp(/#-(id:[0-9]+)-/, 'gim');
let matches = text.match(mentionsRegex);
if (matches && matches.length) {
matches = matches.map(function (match, idx) {
let usrTofind = matches[idx]
//////////////////////////////////////////////////////////////////
const mentFormat = listusers.filter(function (item) {
const itemData = item.format;
return itemData.indexOf(usrTofind) > -1;
});
if (mentFormat.length > 0) {
let idusuario = mentFormat[0].idusuario
let replc = mentFormat[0].usuario
console.log(usrTofind) //// here find #-id:1-
console.log(replc) //// here is #luigbren for replace
////////// now here replace part of the string, #-id:1- with a <Text> component
///////// with #luigbren and the link, this is repeated for every #mention found
parts = text.split(usrTofind);
for (var i = 1; i < parts.length; i += 2) {
parts[i] = <Text key={i} style={{ color: '#00F' }} onPress={() => { alert('but this is'); }}>{replc}</Text>;
}
return text = parts;
/////////////////////////////////////////////////////////////////////
} else {
return text
}
});
} else {
return text
}
return text
};
in this way the code works well for me only when in the text there is only one mention, example 'hey what happened #-id:1- everything ok ??' , but when placing more than one mention it gives me an error, example: 'hey what happened #-id:1- everything ok ?? #-id:2- #-id:3-' ...
Error:
TypeError: text.split is not a function
And if instead of placing parts = text.split(usrTofind); I place parts = text.toString().split(usrTofind); it gives me this error:
[Object Object]
Update
I found the solution. I found another simple way to replace part of the text with the <Text> component, using this method:
funcMentToLinks = (text, idusuario) => {
const regex = /\#[id:([0-9]+]/g;
const splitText = text.split(regex)
if (splitText.length <= 1) {
return text;
}
const matches = text.match(regex);
return splitText.reduce(function (arr, element, index) {
if (matches[index]) {
return [arr, element, <Text key={index} style={{ backgroundColor: '#ceedf1', fontWeight: 'bold', color: '#4f73c4' }} onPress={() => this.callmyopc(idusuario)}>{replc}</Text>,]
} else {
return [arr, element]
}
}, []);
}
but now I have a problem, I can't find a way to call a function to navigate to another section or invoke direct the this.props.navigation.navigate('opc'), if i put my function .. example: onPress={() => this.callmyopc(idusuario)} gives me an error
Error:
_this2.callmyopc is not a function
if i put it this way onPress={() => {this.props.navigation.navigate('opc', { idperf: idusuario })}} gives me an error..
Error:
Cannot read property 'navigation' of undefined
Note: the functions this.props.navigation.navigate if they work for me in this same file, I use it in other functions, but in this function I cannot invoke it.

Related

React Native create text highlight styled Text component in Text component by function

I am currently working on small project.
What I am trying to do is to create text hightlight in my speech to text react native app
My project has Flask API server to detect text data whether it is voice phishing or not.
I am using [react-native-voice]https://github.com/react-native-voice/voice for speech to text
my react native app will send text data segment every 5 seconds to Flask API server to find out whether it is voice phishing or not then Flask API server will return score that is 0 to 1 so over 0.5 is voice phishing
anyway what i am trying to say is that when the text data is considered to be voice phishing (score over 0.5) text data on my app will be highlighted
here is my TextBox Component code
is that possible my setHighlight function
input
hi my name is woo young from Well Bing Bank give me your account my number is 112-22314-12314. Thank you.
return
hi my name is woo young from Well Bing Bank
<Text style={styles.highlighted}>
give me your account
<Text>
my number is 112-22314-12314. Thank you.
but it returns
hi my name is woo young from Well Bing Bank
[object Object]
my number is 112-22314-12314. Thank you.
import { Text, View, StyleSheet } from "react-native";
const NO_WIDTH_SPACE = '​';
const highlight = string =>
string.split(' ').map((word, i) => (
<Text key={i}>
<Text style={styles.highlighted}>{word} </Text>
{NO_WIDTH_SPACE}
</Text>
));
export default class TextBox extends Component {
setHighlight = (string, array) => {
for (let i = 0; i < (array.length)/2; i++) {
let seg = string.slice(array[2*i], array[2*i+1])
let firstIdx = string.slice(0, array[2*i-1])
let lastIdx = string.slice(array[2*i+2], array.length)
let segText = highlight(seg)
let result = firstIdx + segText + lastIdx
return result
}
}
render = () => {
return(
<View style={styles.textBox}>
{this.props.partialResults.map((result, index) => {
const hightlightText = this.setHighlight(result,[3,4])
return (
<Text style={styles.resultText} key={`partial-result-${index}`}>
{ hightlightText }
</Text>
)
})}
</View>
)
}
}
const styles = StyleSheet.create({
textBox: {
marginTop: 10,
width: 330,
height: 400,
backgroundColor: "white",
borderWidth: 2,
padding: 10,
borderColor: "dodgerblue"
},
resultText: {
fontSize: 18
},
highlighted: {
padding:2,
backgroundColor: 'red',
},
})
Not sure if your logic is sound but you can return the result as JSON Stringify, that may indicate what that object contains and give you a better idea what to return.
setHighlight = (string, array) => {
for (let i = 0; i < (array.length)/2; i++) {
let seg = string.slice(array[2*i], array[2*i+1])
let firstIdx = string.slice(0, array[2*i-1])
let lastIdx = string.slice(array[2*i+2], array.length)
let segText = highlight(seg)
let result = firstIdx + segText + lastIdx
return JSON.stringify(result)
}
}

Display contentful <ForwardRef /> converted elements to react native

I have the data from contentful, the data is formatted like this and is converted using #contentful/rich-text-react-renderer with this conversion options. By calling the codes below to perform the conversion
import { documentToReactComponents } from '#contentful/rich-text-react-renderer';
const convert = (document: any) => {
const nodes = documentToReactComponents(document?.fields?.html, contentfulToReactnative);
if (nodes && Array.isArray(nodes)) {
const newNodes = nodes.map((component, index) => {
if (index + 1 === nodes.length) {
return component;
}
return <View key={uuid()}>{component}</View>;
});
return newNodes;
}
return nodes;
};
with that, I got arrays of <ForwardRef /> like this
[<ForwardRef />, <ForwardRef(Text) allowFontScaling={false}></ForwardRef(Text)>]
the question is, how should I display ForwardRefs in react native. By doing {elements} (elements is the variable holding that array) won't work.
I don't know yet if these ForwardRefs are the things to display.

React Native TextInput masking is buggy

I'm trying to make a masked TextInput for BRL currency using regex, so every time the user types a number it is formated as follow:
First the number pressed appears inside the TextInput and then you can change the state to your desired value. Isn't there a way to change the text before it is displayed for the user?
Basically what I'm doing is:
const MoneyTextInput = ({onChangeText, ok}) => {
let [text, setText] = useState('00,00');
return (
<TextInput
value={text}
keyboardType="number-pad"
style={{
width: '100%',
height: '100%',
fontSize: 22,
}}
onChange={({nativeEvent}) => {
setText(prettifyCurrency(nativeEvent.text));
onChangeText(prettifyCurrency(nativeEvent.text));
}}
/>
);
};
And the function with the regex is this:
function prettifyCurrency(value: String): String {
if (!value) {
return '00,00';
}
let newText = value.replace(/(\D)/g, '').replace(/^0+/, '');
if (newText.length < 4) {
for (let i = newText.length; i < 4; i++) {
newText = '0' + newText;
}
}
newText = newText
.replace(/(\d{2}$)/g, ',$&')
.replace(/(\d{1})(\d{3})([,])/, '$1.$2$3')
.replace(/(\d{1})(\d{3})([.])/, '$1.$2$3')
.replace(/(\d{1})(\d{3})([.])/, '$1.$2$3');
return newText;
}
Shouldn't it wait for the value prop to be updated? Is there anyway I achieve what I want? Because I know in Android (Java) I had a function to change the text before it was displayed.
PS.: I'm using OnChange function because I found it was a little bit faster than onChangeText

How to use the $filter variable on graphql query under the Connect component?

I have a simple query auto-generated from aws AppSync, and I'm trying to use the Connect Component, with a FlatList and use a TextInput to filter and auto-update the list. But I confess I didn't found out a way to do that... any hints?
Tried to find more information about this without success...
Auto-Generated query:
export const listFood = `query ListFood(
$filter: ModelFoodFilterInput
$limit: Int
$nextToken: String
) {
listFood(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
name
description
...
My current code, which I don't quite know where to place my filter value:
<Connect query={graphqlOperation(queries.listFood)}>
{
( { data: { listFood }, loading, error } ) => {
if(error) return (<Text>Error</Text>);
if(loading || !listFood) return (<ActivityIndicator />);
return (
<FlatList
data={listFood.items}
renderItem={({item}) => {
return (
<View style={styles.hcontainer}>
<Image source={{uri:this.state.logoURL}}
style={styles.iconImage}
/>
<View style={styles.vcontainer}>
<Text style={styles.textH3}>{item.name}</Text>
<Text style={styles.textP}>{item.description}</Text>
</View>
</View>
);
}}
keyExtractor={(item, index) => item.id}
/>
);
}
}
</Connect>
What I aim is mainly to filter by item.name, refreshing the list while typing from a TextInput, probably going somewhere on the $filter variable...
Ok, I think I've figured out the usage with the AWS AppSync Out-of-the-box queries...
query MyFoodList{
listFood(
filter: {
name: {
contains:"a"
}
}
) {
items {
id
name
}
}
}
And it is finally working properly with this disposition on my react-native code:
<Connect query={ this.state.filter!=="" ?
graphqlOperation(queries.listFood, {
filter: {
name: {
contains: this.state.filter
}
}
})
:
graphqlOperation(queries.listFood)
}>
I still didn't manage to make the sort key work yet... will try a little more and open another topic for it if I didn't get anything...
This is filter in use in React / Javascript:
const [findPage, setFindPage] = useState('') // setup
async function findpoints() {
// find user & page if exists read record
try {
const todoData = await API.graphql(graphqlOperation(listActivitys, {filter : {owner: {eq: props.user}, page: {eq: action}}}))
const pageFound = todoData.data.listActivitys.items // get the data
console.log('pageFound 1', pageFound)
setFindPage(pageFound) // set to State
} catch (err) {
console.log(err)
}
}
The async / wait approach means the code will try to operate, and move on to other areas of your code putting data into findPage through setFindPage when and if it finds data

Replace a font style inside tag <Text>

Hello i want to replace a font style inside <Text>,
this assumption variable x is dynamic variable.
for example :
when x="Hell" => Helloooo
when x="He" => Helloooo
when x="lloooo" => Helloooo
I tried with this code :
render() {
var x = "Hell"; // Hell/He/lloooo
var myOldString = "Helloooo";
var reg = new RegExp(x, "g");
var myNewString = myOldString.replace(reg, `<Text style={{fontWeight:'bold'}}>${x}</Text>`);
return (
<View>
<Text>{myNewString}</Text>
</View>
);}
But the result is just an ordinary string :
when x="Hell" => <Text style={{fontWeight:'bold'}}>Hell</Text>ooo
when x="He" => <Text style={{fontWeight:'bold'}}>He</Text>llooo
when x="lloooo" => He<Text style={{fontWeight:'bold'}}>lloooo</Text>
How to render a string inside <Text>, in order to be nested <Text>, not the ordinary string ?
this was a deceptively simple question, after much tinkering I think I have something for you.
This may not be the most efficient/elegant approach, but it worked when I tested it.
First you'll need 2 state values
constructor(props) {
super(props);
this.state = {
textToBold:'ell',
myArr:[],
};
};
One to keep a reference to the parts you are trying to bold and another to keep an array after we split the string.
Next, to fill 'myArr' with values will be done so via this code; all of which takes place at componentWillMount
componentWillMount() {
var reg = new RegExp(this.state.textToBold); //builds a RegExp from what you are trying to bold
var myOldString = "Helloooo"
var res = myOldString.split(reg); //splits the original string based on regex match
this.setState({
myArr: res //now you have an array of all remaining values
})
}
Finally in your render method, include a way to generate Components dynamically based on the array.
render() {
let result = this.state.myArr.map((a, i) => {
if ( i > 0) {
return (
<Text key={i}>
<Text style={{ fontWeight:'bold'}}>{this.state.textToBold}</Text>{ a }
</Text>
)
} else { //Case to accommodate for extra repeating values
return (<Text key={i}>{ a }</Text>)
}
});
return (
<View style={styles.container}>
<Text>
{ result }
</Text>
</View>
)
}
So now to "highlight" whatever text you want, you just change the state value, 'textToBold'.
I have solved the problem with Markdown
Try this code :
render() {
var x = "Hell"; // Hell/He/lloooo
var myOldString = "Helloooo";
var reg = new RegExp(x, "g");
var myNewString = myOldString.replace(reg, `**${x}**`);
return (
<View>
<Markdown>{myNewString}</Markdown>
</View>
);}