react-native-countdown - get onchange tick value - react-native

I was able to implement the react-native-countdown-component successfully, but tried getting the value of the countdown-timer as it ticks from the onChange which i couldent get.
FIND MY CODE BELLOW
<CountDown
until={60 * this.state.assessmentDurationMain + 2}
size={20}
onChange={(time)=>{
console.warn(time)
//AsyncStorage.setItem('startTest_'+this.state.assessmentID,time)
}}
onFinish={() => alert('Finished')}
digitStyle={{backgroundColor: '#f2f2f1'}}
digitTxtStyle={{color: '#80146D'}}
timeToShow={['H','M', 'S']}
timeLabels={{h:'HR',m: 'MM', s: 'SS'}}
/>
the function on the onChange returns null on the console.warn(time) output
.
So my question is, how can i return the time value as it ticks using the react-native-countdown-component package ?

Taking a look at the source code talalmajali/react-native-countdown, you'll notice that it simply calls your callback...
if (this.props.onChange) {
this.props.onChange();
}
So if you need the time to be passed back, you could fork the repo and updated as so (in both places it's called)...
if (this.props.onChange) {
this.props.onChange(this.state.until);
}

Related

Cypress, get the numeric value of an attribute

To avoid going crazy again, is it possible to get the value of the htmlTemplateof this element?
<rect x="303" y="28" height="53" width="10" htmlTemplate="foo: 115" class="foo"></rect>
I would like to get the number of that foo, so just the number 115
If you just want to assert the value foo: 115 then you can do this.
cy.get('rect').invoke('attr', 'htmlTemplate').should('equal', 'foo: 115')
Now if you want to extract the number part, you can do something like this:
cy.get('rect')
.invoke('attr', 'htmlTemplate')
.then((val) => {
cy.log(val.split(' ')[1]) //prints 115
expect(val.split(' ')[1]).to.equal('115')
})
If you have more than one rect and you want to access the first one you can use eq(0)
cy.get('rect').eq(0).invoke('attr', 'htmlTemplate').should('equal', 'foo: 115')
If you want to get the value of all the rects, you can use each(), something like:
cy.get('rect').each(($ele) => {
cy.wrap($ele)
.invoke('attr', 'htmlTemplate')
.then((val) => {
cy.log(val.split(' ')[1]) //prints value one by one
})
})

How can I show days by group like Whatsapp chat screen?

How can I excatly do a similar Date system like the one in the Whatsapp chat screen?
As you can see the messages are in a group by date, I mean they are separated by date.
Here is a ScreenShot that i found for better explanation:
I do this in a FlatList, while rendering the messages one by one.
Here is what i did
let previousDate = "";
if (index > 0) {
previousDate = moment(this.state.messages[index - 1].created_at).format(
"L"
);
} else {
previousDate = moment(this.state.messages.created_at).format("L");
}
let currentDate = moment(item.created_at).format("L");
So, i created a functional component for renderItem prop of the FlatList, so item and index comes from the actual data from the FlatList.
What i'm trying to do here is, basically grabbing the current rendering item's created_at and compare it with the previous item's created_at, and to do that, i'm using the original data which is stored in the state. But unfortunately when the FlatList rendering the very first item which has index number 0 there is no previous element to compare in the original data in state, that's why i checking if is greater than 0 go and grab date from previous indexed item. And in the Else case, which means when rendering the first item, do not look for previous item and just get the created_at.
And below i check if the currentDate and previousDates are NOT the same, render a custom component else do not render anything.
{previousDate && !moment(currentDate).isSame(previousDate, "day") ? ( // custom component) : null}
It's should work like that, but the major problem is, i used inverted FlatList for to able to messages go from bottom of the screen to the top. But now, becouse of it's a inverted flatlist the items being rendering from bottom to the top and it gives me result like this:
NOTE: At the beginning the messages were coming also reversed but i fixed this with sending them also reversed from the DB.
So, i don't know how do i able to achieve my goal, and do it like on the first picture.
Thank you!
I use a helper function (generateItems) to address the problem that you are describing. Here is the code that I use to group my messages by day and then render either a <Message /> or a <Day /> in the renderItem prop. This is using an inverted FlatList as you described.
import moment from 'moment';
function groupedDays(messages) {
return messages.reduce((acc, el, i) => {
const messageDay = moment(el.created_at).format('YYYY-MM-DD');
if (acc[messageDay]) {
return { ...acc, [messageDay]: acc[messageDay].concat([el]) };
}
return { ...acc, [messageDay]: [el] };
}, {});
}
function generateItems(messages) {
const days = groupedDays(messages);
const sortedDays = Object.keys(days).sort(
(x, y) => moment(y, 'YYYY-MM-DD').unix() - moment(x, 'YYYY-MM-DD').unix()
);
const items = sortedDays.reduce((acc, date) => {
const sortedMessages = days[date].sort(
(x, y) => new Date(y.created_at) - new Date(x.created_at)
);
return acc.concat([...sortedMessages, { type: 'day', date, id: date }]);
}, []);
return items;
}
export default generateItems;
For reference here is my list as well as the renderItem function:
<MessageList
data={generatedItems}
extraData={generatedItems}
inverted
keyExtractor={item => item.id.toString()}
renderItem={renderItem}
/>
function renderItem({ item }) {
if (item.type && item.type === 'day') {
return <Day {...item} />;
}
return <Message {...item} />;
}
This is how i did it in react,
Create a new Set() to store dates uniquely
const dates = new Set();
When looping through chats array, check if date already exists in unique Set before rendering date
chats.map((chat) => {
// For easier uniqueness check,
// Formated date string example '16082021'
const dateNum = format(chat.timestamp, 'ddMMyyyy');
return (
<React.Fragment key={chat.chat_key}>
// Do not render date if it already exists in set
{dates.has(dateNum) ? null : renderDate(chat, dateNum)}
<ChatroomChatBubble chat={chat} />
</React.Fragment>
);
});
Finally, when date has been rendered, add date num into array so it doesn't render again
const renderDate = (chat, dateNum) => {
const timestampDate = format(chat.timestamp, 'EEEE, dd/MM/yyyy');
// Add to Set so it does not render again
dates.add(dateNum);
return <Text>{timestampDate}</Text>;
};

How to set an array of multiple data as a state

So basically I want to be able to collect all the values from multiple inputs and set that array as a state. Here is what I am currently working with:
this.state.basket.map(b => {
return (
<View>
<InputSpinner
style={styles.spinnerQty}
max={50}
min={1}
step={1}
rounded={false}
showBorder
colorMax={"#2a292d"}
colorMin={"#2a292d"}
value={b.qty}
onChange={num => {
this.setState({ popUpQty: num });
}}
/>
<View style={styles.hrLine}></View>
</View>
);
});
So I am iterating my basket and setting a spinner with a value from axios output. So there are now multiple InputSpinner with multiple values.
My question is, how can I collect all the values of the onChange, and push it to an array which will eventually become a state. Something like QuantityState: [] would be the values of all the InputSpinner. Hope that made sense. Any help is appreciated. Thanks!
PS. InputSpinner is an npm package from here.
Through this code you can dynamically add/update onChange number on it's particular array instance. num key will be added when a particular onChange trigger so at the end you will get its values which placed on it's index and if key not found that means onChange never triggered for that index
state = {
spinnerData : {},
basket: []
}
this.state.basket.map((b, index) => {
return (
<View>
<InputSpinner
style={styles.spinnerQty}
max={50}
min={1}
step={1}
rounded={false}
showBorder
colorMax={"#2a292d"}
colorMin={"#2a292d"}
value={b.qty}
onChange={num => {
const newbasket = [...this.state.basket];
newbasket[index]["num"] = num;
this.setState({ basket:newbasket });
}}
/>
<View style={styles.hrLine}></View>
</View>
);
});

How to query graphQL with variables from React-Native?

I can't find the problem in my code when trying to query with variables from react-native. A simple Hello World! is working.
The render:
render() {
return (
<AppContext.Consumer>
{context => {
const{ userID,employeeID,salonID,currentDay,serviceTime}=context.state
return (
<Query
query={query}
variables={{userID:userID,employeeID:employeeID,salonID:salonID,day:currentDay,serviceTime:serviceTime}}
>
{(response, error) => {
console.log(`response: ${response.data.listOfAppointments}`);
console.log(`EMPL: ${response.data.employeeInfo}`);
console.log(`\helo: ${response.data.hello}`);
return (
<Grid>
<Col>
<MyHeader
navigation={this.props.navigation}
title={context.state.currentDay
.format("DD.MM.YYYY")
.toString()}
/>
{!response.data.listOfAppointments? (
<CircularProgress />
) : (
<ScheduleList data={response.data.listOfAppointments} />
)}
</Col>
</Grid>
);
}}
</Query>
);
}}
</AppContext.Consumer>
);
}
The Query:
const query =gql`
query Query($userID:String!,$employeeID:String!,$salonID:String!,$day:Int!,$serviceTime:Int){
hello
listOfAppointments(
userID: $userID
employeeID: $employeeID
salonID: $salonID
day: $day
serviceTime: $serviceTime
) {
start
end
status
disabled
}
employeeInfo(employeeID: $employeeID
salonID: $salonID){
token
name
ID
notifyWhenCreated
notifyWhenDeleted
salonName
}
}
`;
The schemas and types:
If I delete listOfAppointments,employeeInfo and the part where I declare the variables the hello is working.
Otherwise it's giving me status code: 400
react-native log-android is not throwing anything.
If I try to console.log() the result it's undefined.
Thanks!
A status code of 400 usually means the query itself is invalid. It could be that the query has a syntax error, or is somehow not passing validation. To get the detailed response from the server, you can either 1) observe the actual response from the server in the network tab of your browser or 2) capture the error from the component itself.
<Query /* props */>
({ data, error }) => {
console.log(error)
return null
}
</Query>
Note that we're only dealing with the first parameter in the render props function and just using destructuring to get its data and error properties.
As far as I can tell, your query does not have any syntax errors, so I suspect the issue is that some or all of the variables you are passing in are in fact undefined, which will cause your query to blow up if any of them are marked as non-null inside the query.

<SelectInput>: how to populate choices depending on record data in Edit component of react-admin?

I need to show different choices based on record's field value.
The code for my needs looks like this:
const myChoicesGenerator = (record) => {
if (record.field === false) {
return ['a', 'b'];
} else {
return ['b', 'c'];
}
<SelectInput ... choices = {myChoicesGenerator}/>
But unfortunately i can't pass functions in "choices" property, so this code doesn't work.
Is there a way to do it?
You may use a <FormDataConsumer /> to get the current record and pass it to your function.
<FormDataConsumer>
{
({formData, ...rest}) =>
<SelectInput
choices={myChoiceGenerator(formData)}
{...rest}
/>
}
</FormDataConsumer>
Doc: https://marmelab.com/react-admin/Inputs.html#linking-two-inputs
I dont' know if the values ['a', 'b'] are valid for <SelectInput />. Consider using a list of tuples (id, name) as described in the documentation.