Sending field input to firebase from state - react-native

I'm currently working on app that has ability to add new tasks, assign them to others and choose due date.
I'd like to start sending the assignee and due date of the task to my firebase.
This is my dropdowncomponent:
class DropdownComponent extends Component {
constructor(props){
super(props);
this.state = {
assignee: '',
data: [{
value: 'apple',
}, {
value: 'lemon',
}, {
value: 'orange',
}, {
value: 'banana',
}, {
value: 'watermelon',
}],
value: ''
}
}
handleAssigneePicked = value => {
this.setState({ assignee: value })
console.log("Assignee " + value)
};
render() {
return (
<Dropdown
data={this.state.data}
value={this.state.assignee}
onChangeText={this.handleAssigneePicked}
/>
);
}
}
And this is how I render datepicker
<DateTimePicker
isVisible={this.state.isDateTimePickerVisible}
onConfirm={this.handleDatePicked}
onCancel={this.hideDateTimePicker}
/>
handleDatePicked = date => {
console.log("A date has been picked: ", date);
this.hideDateTimePicker();
this.setState({ selectedDate: moment().format('D MMM DD YYYY HH:MM')})
};
When I choose an item from dropdown, it also console logs the corresponding value, meaning the state changed, no issues there.
However, if i'm trying to send that information to firebase, using code below:
const SaveNewTask = (name, body) => {
const { currentUser } = firebase.auth();
// eslint-disable-next-line no-undef
// eslint-disable-next-line no-unused-expressions
!!name && !!body
?
firebase
.database()
.ref(`/users/${currentUser.uid}/tasks`)
.push({
name, body, assignee, selectedDate, timestamp: Date.now(), completed: false, archived: false
})
// eslint-disable-next-line no-undef
: alert('All fields are required.');
};
But I'm getting can't find variable: assignee and selectedDate, can I get some help with this? I must be missing something little.

Looks like you forgot to pass these params to action
const SaveNewTask = (name, body, assignee, selectedDate) => {
const { currentUser } = firebase.auth();
!_.isEmpty(name) && !_.isEmpty(body) && !_.isEmpty(assignee) && selectedDate != undefined
?
firebase
.database()
.ref(`/users/${currentUser.uid}/tasks`)
.push({
name, body, assignee, selectedDate, timestamp: Date.now(), completed: false, archived: false
})
: alert('All fields are required.');
};
you can use _.isEmpty() by lodash

Related

How to re-run useQuery and FlatList?

I use FlatList with useState.
const [state, setState] = useState(route);
<FlatList
keyboardDismissMode={true}
showsVerticalScrollIndicator={false}
data={state}
keyExtractor={(comment) => "" + comment.id}
renderItem={renderComment}
/>
When I change the datㅁ which is contained in state, I want to re-run Flatlist with new data.
So after I mutate my data, I try to rerun useQuery first in order to change state. I put refetch module here.
1)
const { data: updatePhoto, refetch } = useQuery(SEE_PHOTO_QUERY, {
variables: {
id: route?.params?.photoId,
},
});
If I put button, this onValid function will executed.
<ConfirmButton onPress={handleSubmit(onValid)}>
onValid function changes data and after all finished, as you can see I put refetch().
=> all this process is for that if I add comment and press confirm button, UI (flatlist) should be changed.
const onValid = async ({ comments }) => {
await createCommentMutation({
variables: {
photoId: route?.params?.photoId,
payload: comments,
},
});
await refetch();
console.log(updatePhoto);
};
But when I console.log data after all, it doesnt' contain added data..
what is the problem here?
If you need more explanation, I can answer in real time.
please help me.
add full code
export default function Comments({ route }) {
const { data: userData } = useMe();
const { register, handleSubmit, setValue, getValues } = useForm();
const [state, setState] = useState(route);
const [update, setUpdate] = useState(false);
const navigation = useNavigation();
useEffect(() => {
setState(route?.params?.comments);
}, [state, route]);
const renderComment = ({ item: comments }) => {
return <CommentRow comments={comments} photoId={route?.params?.photoId} />;
};
const { data: updatePhoto, refetch } = useQuery(SEE_PHOTO_QUERY, {
variables: {
id: route?.params?.photoId,
},
});
const createCommentUpdate = (cache, result) => {
const { comments } = getValues();
const {
data: {
createComment: { ok, id, error },
},
} = result;
if (ok) {
const newComment = {
__typename: "Comment",
createdAt: Date.now() + "",
id,
isMine: true,
payload: comments,
user: {
__typename: "User",
avatar: userData?.me?.avatar,
username: userData?.me?.username,
},
};
const newCacheComment = cache.writeFragment({
data: newComment,
fragment: gql`
fragment BSName on Comment {
id
createdAt
isMine
payload
user {
username
avatar
}
}
`,
});
cache.modify({
id: `Photo:${route?.params?.photoId}`,
fields: {
comments(prev) {
return [...prev, newCacheComment];
},
commentNumber(prev) {
return prev + 1;
},
},
});
}
};
const [createCommentMutation] = useMutation(CREATE_COMMENT_MUTATION, {
update: createCommentUpdate,
});
const onValid = async ({ comments }) => {
await createCommentMutation({
variables: {
photoId: route?.params?.photoId,
payload: comments,
},
});
await refetch();
console.log(updatePhoto);
};

Call useUpdateMany callback with data

Reading the docs it seems that whenever I import useUpdateMany I already have to pass the data it's going to send. My question is, is it possible to pass the data on the callback?
I want to call the updateMany in a handleSubmit function, so I will only have the data when the function is called:
export const ChangeStatus = (props) => {
const { record, version } = props;
const { t } = useTranslation('admin');
const classes = useStyles();
const refresh = useRefresh();
const notify = useNotify();
const [componentStatus, setComponentStatus] = useState(null);
const [updateMany, { loading, error }] = useUpdateMany('orders', props.selectedIds, {componentStatus });
const defaultSubscription = {
submitting: true,
pristine: true,
valid: true,
invalid: true,
};
const handleSubmit = ({ status }) => {
setComponentStatus({ status });
updateMany();
refresh();
};
return (
<Form
initialValues={record}
subscription={defaultSubscription}
key={version}
onSubmit={handleSubmit}
render={(formProps) => (
<form onSubmit={formProps.handleSubmit} className={classes.form}>
<SelectInput
label="Status"
variant="outlined"
source="status"
className={classes.selectField}
FormHelperTextProps={{ className: classes.selectHelperText }}
choices={[
{ id: 'created', name: 'Created' },
{ id: 'canceled', name: 'Canceled' },
{ id: 'active', name: 'Active' },
{ id: 'awaiting', name: 'Awaiting allocation' },
{ id: 'processing', name: 'Processing' },
{ id: 'review', name: 'Review' },
{ id: 'completed', name: 'Completed' },
]}
/>
<Button variant="contained" color="secondary" type="submit" disabled={loading}>
{t('Confirm')}
</Button>
</form>
)}
/>
);
};
Right now I'm updating a state and then calling the updateMany, but it would be much easier if I could call the updateMany passing the data:
const handleSubmit = ({ status }) =>
updateMany({status});
};
Is it possible to do it?
Thanks!
You can override the params when calling updateMany function but you have to respect the mutation params format.
In your example you can do updateMany({ payload: { data: { componentStatus } } });
Indeed useUpdateMany call useMutation under the hood and this hook allow merge with callTimeQuery
You can find some references here :
https://marmelab.com/react-admin/Actions.html#usemutation-hook
useMutation accepts a variant call where the parameters are passed to the callback instead of when calling the hook. Use this variant when some parameters are only known at call time.
https://github.com/marmelab/react-admin/blob/bdf941315be7a2a35c8da7925a2a179dbcb607a1/packages/ra-core/src/dataProvider/useMutation.ts#L299
Also there is an issue wich foresees a more logical signature at call time : https://github.com/marmelab/react-admin/issues/6047
(Update : And now this is merged for a future release: https://github.com/marmelab/react-admin/pull/6168 )

email Validation on React native with tcomb package

i want to validate email in react native, but it still didn't work for me
this is my code
const Email = t.subtype(t.Str, (email) => {
const reg = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return reg.test(email);
});
componentWillReceiveProps(newProps) {
let data_cars = this.carOptions(newProps.cars);
let data_year = this.yearCarOptions();
if (Object.keys(newProps.car_brand).length && Object.keys(newProps.user).length) {
let form = t.struct({
name: t.String,
email: Email,
phone: t.Number,
plate: t.enums(data_cars),
carbrand: t.enums(newProps.car_brand),
carclass: t.enums(newProps.car_class),
year: t.enums(data_year),
})
this.setState({ form })
this.setState({ value: {
name : newProps.user.name,
email : newProps.user.email,
phone : newProps.user.phone
} });
}
}
const options = {
auto: 'none',
fields: {
name: {
label: 'Name',
placeholder: 'name',
placeholderTextColor: 'rgba(255,255,255,0.6)',
error: 'enter your name'
},
email: {
label: 'Email',
placeholder: 'e.g: abc#gmail.com',
placeholderTextColor: 'rgba(255,255,255,0.6)',
error: 'Insert a valid email'
},
},
stylesheet: formStyle.underline(colors.dark),
};
const Form = t.form.Form;
if i submitting the data, it could still return not an email
like this
how do i achieve to validate email?
Use code like below
validate = (text) => {
console.log(text);
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (reg.test(text) === false) {
console.log("Email is Not Correct");
this.setState({ email: text })
return false;
}
else {
this.setState({ email: text })
console.log("Email is Correct");
}
}
<TextInput
placeholder="Email ID"
onChangeText={(text) => this.validate(text)}
value={this.state.email}
/>
onPressOfButton = () => {
this.validate(this.state.email);
}

Cannot read property 'id' of undefined. Variable 'id' has coerced Null value for NonNull type 'ID!'

I am using react native gifted chat and I am trying to figure out how to set _id, text, createdAt, userid, and name to the parameters of my mutation. I have been getting the following errors variable id has coerced null value or cannot read property 'id' is undefined. The main question I have is what to set messageid and messagetext to. I am using react native gifted chat with AWS.
export const createMessage = `mutation createMessage($id: ID! $groupchatid: ID! $message: String! $createdUser: String! $createdTime: String!) {
createMessage(input:{ id:$id groupchatid:$groupchatid, message:$message, createdUser: $createdUser createdTime: $createdTime}) {
id
groupchatid
message
createdUser
createdTime
}
}`;
const user = Auth.currentAuthenticatedUser();
this.setState({ username: user.username});
}
MessagesMutation = async () => {
const AddMessage = { message: this.state.messages, createdUser: this.state.username, groupchatid: this.state.groupchatname };
const newGroupChatMessage = await API.graphql(graphqlOperation(createMessage, AddMessage));
console.log(JSON.stringify(newGroupChatMessage));
};
componentWillMount() {
this.setState({
messages: [
{
_id: id,
text: message,
createdAt: new Date(),
user: {
_id: createdUser,
name: createdUser,
avatar: 'https://placeimg.com/140/140/any',
},
},
],
})
}
componentDidMount() {
const { navigation } = this.props;
const value = navigation.getParam('value')
this.setState({groupchatname: value})
}
onSend(messages = []) {
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
}
render(){
const { groupchatname} = this.state;
return (
<SafeAreaView style={{ flex: 1 }}>
<Header style={styles.headerColor}>
<Text style={styles.text}>{groupchatname}</Text>
</Header>
<GiftedChat
messages={this.state.messages}
renderUsernameOnMessage={true}
onSend={messages => this.onSend(messages), this.MessagesMutation}
user={{
_id: this.user,
name: this.user,
avatar: 'https://placeimg.com/140/140/any'
}}```
You 've defined id as a parameter
createMessage($id: ID! $groupchatid: ID! $message: String! $createdUser: String!
$createdTime: String!)
and have forgotten to pass an argument
const AddMessage = {
id:"valu...." //here
message: this.state.messages,
createdUser: this.state.username,
groupchatid: this.state.groupchatname
};

Storing a value in Redux

I am building a React Native app, mainly for verifying tickets, to be used by event administrators. The back-end is served by a Laravel app with a working OAuth2-server. I have a working login against that server but now I need to store the access token, to request data, such as events, and to verify if a ticket is matched for a given event.
I'm trying to implement Redux to store the access token etc. The login form I have updates the store via actions correctly, but I can't get it to work with the access token.
Here is the login screen:
import React, { Component } from 'react';
import { Text, View, TextInput, Button } from 'react-native';
import { connect } from 'react-redux'
import StringifyBody from './../lib/oauth2/StringifyBody'
import { login, storeTokens } from '../redux/actions/auth.js'
class Login extends Component {
constructor (props) {
super(props);
this.state = {
route: 'Login',
loading: false,
email: '',
password: '',
accessToken: '',
};
}
handleClick (e) {
e.preventDefault();
return new Promise(function(resolve, reject) {
var data = StringifyBody(this.state.password, this.state.email)
// XHR settings
var xhr = new XMLHttpRequest()
xhr.withCredentials = true
xhr.onerror = function() {
reject(Error('There was a network error.'))
}
xhr.open("POST", "http://192.168.0.141/oauth/access_token")
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")
xhr.send(data)
xhr.onloadend = function() {
if (xhr.status === 200) {
var parsedJson = JSON.parse(xhr.response)
responseArray = []
for(var i in parsedJson) {
responseArray.push([parsedJson [i]])
}
// assign values to appropriate variables
let accessToken = responseArray[0];
console.log('access token is: ' + accessToken)
accessToken => this.setState({ access_token: accessToken })
this.props.tokenStore(this.state.accessToken) // This doesn't work: "cannot read property 'tokenStore' of undefined"
resolve(xhr.response)
} else {
reject(Error('Whoops! something went wrong. Error: ' + xhr.statusText))
}
}
})
.done(() => {
this.props.onLogin(this.state.email, this.state.password); // This works
})
}
render() {
return (
<View style={{padding: 20}}>
<Text style={{fontSize: 27}}>{this.state.route}</Text>
<TextInput
placeholder='Email'
autoCapitalize='none'
autoCorrect={false}
keyboardType='email-address'
value={this.state.email}
onChangeText={(value) => this.setState({ email: value })} />
<TextInput
placeholder='Password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
value={this.state.password}
onChangeText={(value) => this.setState({ password: value })} />
<View style={{margin: 7}}/>
<Button onPress={(e) => this.handleClick(e)} title={this.state.route}/>
</View>
);
}
}
const mapStateToProps = state => {
return {
isLoggedIn: state.auth.isLoggedIn,
access_token: state.auth.access_token,
}
}
const mapDispatchToProps = (dispatch) => {
return {
onLogin: (email, password) => { dispatch(login(email, password)); },
tokenStore: (accessToken) => { dispatch(storeTokens(accessToken)) },
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
Redux actions:
export const login = (email, password) => {
return {
type: 'LOGIN',
email: email,
password: password
};
};
export const logout = () => {
return {
type: 'LOGOUT'
};
};
export const storeTokens = () => {
return {
type: 'STORE_TOKENS',
access_token: accessToken,
}
}
And finally the reducers:
const defaultState = {
isLoggedIn: false,
email: '',
password: '',
access_token: '',
};
export default function reducer(state = defaultState, action) {
switch (action.type) {
case 'LOGIN':
return Object.assign({}, state, {
isLoggedIn: true,
email: action.email,
password: action.password
});
case 'LOGOUT':
return Object.assign({}, state, {
isLoggedIn: false,
email: '',
password: ''
});
case 'STORE_TOKENS':
return Object.assign({}, state, {
access_token: action.accessToken,
})
default:
return state;
}
}
I've also tried passing the data to this.props.storeTokens (the actual action) in a componentDidMount() which gives me the error undefined is not a function (evaluating 'this.props.storeTokens()') componentDidMount Login.js:57:8
My question then is: How do I store the variable I get from my XHR POST in the redux store? Why is this.props.tokenStore and this.props.storeToken not defined?
Hey thats a mistake owing to javascript concept. You are calling
this.props.tokenStore(this..state.accessToken) // This doesn't work: "cannot read property 'tokenStore' of undefined"
inside a function defined using ES5 syntax. either you store the reference of this outside the function in some variable and then use that variable instead of this. The other option is define arrow function instead. So change your function keyword into
() =>
and this should work. this as of now in your implementation doesn't point to component that you are thinking