How to disable stripe pay button when payment is processing using reactjs? - reactjs

I have created using reactjs stripe card section and in card section, adding card element and in the checkout form render it and in checkout form pay button is also there but I want to disable the pay button unless response gets from backend?
Here is my code:-
class CheckoutForm extends React.Component {
handleCallback = status => {
if (status === "success") {
message.success("Payment is successfull");
this.props.history.push("/main");
} else {
message.error("Some error occoured");
}
};
handleSubmit = ev => {
ev.preventDefault();
const { userDetails, user, tempPassDate } = this.props;
const { paymentId } = this.props;
this.props.stripe
.createPaymentMethod("card", { billing_details: { name: "Jenny Rosen" } })
.then(({ paymentMethod }) => {
console.log("Received Stripe PaymentMethod:", paymentMethod.id);
this.props.payment(
{
paymentMethodId: paymentMethod.id,
paymentId: paymentId,
},
);
})
.catch(err => console.log(err));
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<CardSection/>
<button>
Pay
</button>
</form>
);
}
}

Manage that in state like:
class CheckoutForm extends React.Component {
constructor(props){
super(props);
this.state = {
disableBtn: false;
}
}
handleCallback = status => {
if (status === "success") {
message.success("Payment is successfull");
this.props.history.push("/main");
} else {
message.error("Some error occoured");
}
};
handleSubmit = ev => {
ev.preventDefault();
this.setState({ disableBtn: true });
const { userDetails, user, tempPassDate } = this.props;
const { paymentId } = this.props;
this.props.stripe
.createPaymentMethod("card", { billing_details: { name: "Jenny Rosen" } })
.then(({ paymentMethod }) => {
console.log("Received Stripe PaymentMethod:", paymentMethod.id);
this.props.payment(
{
paymentMethodId: paymentMethod.id,
paymentId: paymentId,
},
);
this.setState({ disableBtn: false });
})
.catch(err => console.log(err));
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<CardSection/>
<button disabled={this.state.disableBtn}>
Pay
</button>
</form>
);
}
}

Related

How to pass data from Component to form submit in ReactJS?

I have created Dropdown which extends Component. In this I am fetching muliple dropdown values an storing it in const data. I want pass this data from Dropdown Component to another Component in the form of function.
Any help would be really great as I am new to React and facing bit challenge.
export class CascadingDropdown extends Component {
constructor(props) {
super(props)
this.state = {
...
dropdown_data: []
}
}
componentDidMount() {
axios.get('/api/fetchCategory').then(response => {
this.setState({
CategoryData: response.data
});
});
}
ChangeSubCategory = (e) => {
this.setState({
category_id: e.target.value
});
axios.get('/api/fetchSubCategory?category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
SubCategoryData: response.data,
});
});
}
ChangeSubject = (e) => {
this.setState({
sub_category_id: e.target.value
});
axios.get('/api/fetchSubjects?sub_category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
subject: response.data
});
});
}
storeData = (e) => {
this.setState({
subject_id: e.target.value
});
}
render() {
const dropdown_data = {
category_id: this.state.category_id,
sub_category_id: this.state.sub_category_id,
subject_id: this.state.subject_id
}
console.log(dropdown_data)
return (
<div className ="row">
. . .
</div>
)
}
}
export default CascadingDropdown
The value from dropdown_data should be passed to a function and below is the code that I have tried.
function CreateTicket() {
const [ticketInput, setTicketInput] = useState({
category_id: '',
sub_category_id: '',
subject_id: '',
other_subject: '',
file: '',
auto_message: '',
});
const handleTicketInput = (e) => {
e.persist();
setTicketInput({...ticketInput, [e.target.name]: e.target.value })
}
const submitTicket = (e) => {
e.preventDefault();
const data = {
...
}
axios.post(`/api/store-ticket`, data).then(res => {
console.log(res.data);
. . .
})
}
return (
<div className ="container">
<form onSubmit ={handleSubmit}>
<input id="emp_name" type="text" name="employee_name" className ="form-control" disabled = "disabled" onChange = {handleTicketInput} value = {empname} />
<CascadingDropdown />
<input id="form_other_subject" type="text" name="other_subject" disabled = "disabled" className ="form-control" value = {ticketInput.other_subject} onChange = {handleTicketInput} />
</form>
</div>
)
}
export default CreateTicket;
This is what i can do for nested state,
and update states, i have used single json object dropdown_data and passed down to children, its getting complex to update state of it but easy to prop down the children,
Soution 1 (OLD):
export class CascadingDropdown extends Component {
constructor(props) {
super(props)
this.state = {
dropdown_data: {
subject_id, category_id, sub_category_id
},
CategoryData,
SubCategoryData,
subject
}
}
this.ChangeSubCategory = this.ChangeSubCategory.bind(this);
this.ChangeSubject = this.ChangeSubject.bind(this);
this.storeData = this.storeData.bind(this);
componentDidMount() {
axios.get('/api/fetchCategory').then(response => {
this.setState({
...this.state,
CategoryData: response.data
});
});
}
ChangeSubCategory = (e) => {
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
category_id: e.target.value
}
});
axios.get('/api/fetchSubCategory?category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
...this.state,
SubCategoryData: response.data,
});
});
}
ChangeSubject = (e) => {
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
sub_category_id: e.target.value
}
});
axios.get('/api/fetchSubjects?sub_category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
...this.state,
subject: response.data
});
});
}
storeData = (e) => {
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
subject_id: e.target.value
}
});
}
render() {
console.log(this.state.dropdown_data)
return (
<div className ="row">
<CreateTicket dropdown_data={this.state.dropdown_data}/>
</div>
)
}
}
export default CascadingDropdown
you can even pass function callbacks too,
<CreateTicket dropdown_data={this.state.dropdown_data} ChangeSubCategory={ChangeSubCategory} ChangeSubject={ChangeSubject} storeData={storeData}/
this is how you can get your parent state down into functional componenet
function CreateTicket(props) {
const [dropdown_data, setDropdown_data] = useState(props.dropdown_data); // use hooks now
//const dropdown_data = this.props.dropdown_data;
}
my new edited answer as per your new question is as follows,
Soution 2 (NEW):
export class CascadingDropdown extends Component {
constructor(props) {
super(props)
this.state = {
dropdown_data: {
subject_id:this.props.subject_id, category_id:this.props.category_id, sub_category_id:this.props.sub_category_id
},
CategoryData,
SubCategoryData,
subject
}
}
// this.ChangeSubCategory = this.ChangeSubCategory.bind(this);
// this.ChangeSubject = this.ChangeSubject.bind(this);
// this.storeData = this.storeData.bind(this);
componentDidMount() {
axios.get('/api/fetchCategory').then(response => {
this.setState({
...this.state,
CategoryData: response.data
});
});
}
ChangeSubCategory = (e) => {
this.props.ChangeSubCategory(e.target.value)
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
category_id: e.target.value
}
});
axios.get('/api/fetchSubCategory?category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
...this.state,
SubCategoryData: response.data,
});
});
}
ChangeSubject = (e) => {
this.props.ChangeSubject(e.target.value);
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
sub_category_id: e.target.value
}
});
axios.get('/api/fetchSubjects?sub_category_id=' + e.target.value).then(response => {
// console.log(response.data);
this.setState({
...this.state,
subject: response.data
});
});
}
storeData = (e) => {
this.props.storeData(e.target.value);
this.setState({
...this.state,
dropdown_data: {
...this.state.dropdown_data,
subject_id: e.target.value
}
});
}
render() {
console.log(this.state.dropdown_data)
return (
<div className ="row">
<CreateTicket />
</div>
)
}
}
export default CascadingDropdown
and its parent function is,
function CreateTicket(props) {
const [dropdown_data, setDropdown_data] = useState({
subject_id:"", category_id:"", sub_category_id:""
}); // use hooks now
ChangeSubCategory=(category_id)=>{
setDropdown_data({...dropdown_data,category_id})
}
ChangeSubject=(sub_category_id)=>{
setDropdown_data({...dropdown_data,sub_category_id})
}
storeData=(subject_id)=>{
setDropdown_data({...dropdown_data,subject_id})
}
return (
<div className ="container">
<form onSubmit ={handleSubmit}>
<input id="emp_name" type="text" name="employee_name" className ="form-control" disabled = "disabled" onChange = {handleTicketInput} value = {empname} />
<CascadingDropdown dropdown_data={dropdown_data} ChangeSubCategory={ChangeSubCategory} ChangeSubject={ChangeSubject} storeData={storeData}/>
<input id="form_other_subject" type="text" name="other_subject" disabled = "disabled" className ="form-control" value = {ticketInput.other_subject} onChange = {handleTicketInput} />
</form>
</div>
)
}
i hope this will work now,

I'am unable to Select only one Radio Button from this Context API list so that I can do more actions on that specific id

I'am unable to Select only one Radio Button from this Context API list so that I can do more actions on that specific id.I want to change the name of the selected radio button as I want after selecting specific id.
import React from 'react'
import './Boxes.css'
export default class Boxes extends React.Component {
constructor(props) {
super(props)
this.state = {
users: [],
selectedID: ''
}
this.changeSelectedId = (e, id) => {
if (e.target.checked == true) {
this.setState({ selectedID: id })
console.log(this.state.users)
}
}
}
componentDidMount() {
axios.get('https:jsonplaceholder.typicode.com/users')
.then(response => {
console.log(response.data)
this.setState({ users: response.data })
})
.catch(error => {
console.log('Error .....')
})
}
render() {
const { users, selectedID } = this.state
const selectedRadio = selectedID == users.id
return (
<>
{users.map((item, index) =>
<div className='boxes' key={index}>{<h4>Name:- {item.name}</h4>}
<input type='radio' names='Userradio' checked={selectedRadio}
onChange={(e) => { this.changeSelectedId(e, users.id) }} />
</div>)}
</>
)
}
};
Try this:
export const Boxes = ({}) => {
const [users, setUsers] = useState([]);
const [selectedId, setSelectedId] = useState('');
const changeSelectedId = (e, id) => {
if (e.target.checked) {
setSelectedId(id)
}
}
useEffect(() => {
axios.get('https:jsonplaceholder.typicode.com/users')
.then(response => {
console.log(response.data);
setUsers(response.data);
})
.catch(error => {
console.log('Error .....')
})
}, []);
return (
<>
{users.map((item, index) => (
<div className='boxes' key={index}>
<h4>Name:- {item.name}</h4>
<input
type='radio'
names='Userradio'
checked={item.id === selectedId}
onChange={(e) => changeSelectedId(e, item.id)}
/>
</div>
)}
</>
);
};

Warning: Can't perform a React state update on an unmounted component....componentWillUnmount method

I'm very new to React and React Native and I am getting this warning when I switch screens. Also, the console.log keeps repeating infinitely, how do I fix it?
class DecodeScreen extends Component {
state = {
data: this.props.navigation.getParam("data", "NO-QR"),
bookData: '',
bookFound: false
}
bookSearch = () => {
query = `https://librarydb-19b20.firebaseio.com/books/${this.state.data}.json`,
axios.get(query)
.then((response) => {
const data = response.data ? response.data : false
console.log(data)
if (data) {
this.setState({
bookData: data,
bookFound: true
})
}
}).catch((error) => {
this.setState({
bookFound: false
})
})
}
renderContent = () => {
if (this.state.bookFound) {
return(
<View>
<TextH5>{this.state.bookData.title}</TextH5>
<TextH5>{this.state.bookData.author}</TextH5>
<TextH5>{this.state.bookData.publisher}</TextH5>
<TextH5>{this.state.bookData.isbn}</TextH5>
</View>
)
}
else {
return <TextH5>beer not found</TextH5>
}
}
componentDidMount() {
this.bookSearch()
}
render() {
{this.bookSearch()}
return (
<Container>
<TextH5>{this.state.data}</TextH5>
{this.renderContent()}
</Container>
);
}}
export default DecodeScreen;
the console.log outputthe warning
You can try this approach to see if it fixes the problem.
isMounted = false;
class DecodeScreen extends Component {
state = {
data: this.props.navigation.getParam("data", "NO-QR"),
bookData: "",
bookFound: false,
};
bookSearch = () => {
this.isMounted = true;
(query = `https://librarydb-19b20.firebaseio.com/books/${this.state.data}.json`),
axios
.get(query)
.then((response) => {
const data = response.data ? response.data : false;
console.log(data);
if (data) {
if (this.isMounted) {
this.setState({
bookData: data,
bookFound: true,
});
}
}
})
.catch((error) => {
this.setState({
bookFound: false,
});
});
};
renderContent = () => {
if (this.state.bookFound) {
return (
<View>
<TextH5>{this.state.bookData.title}</TextH5>
<TextH5>{this.state.bookData.author}</TextH5>
<TextH5>{this.state.bookData.publisher}</TextH5>
<TextH5>{this.state.bookData.isbn}</TextH5>
</View>
);
} else {
return <TextH5>beer not found</TextH5>;
}
};
componentDidMount() {
this.isMounted = true;
this.bookSearch();
}
componentWillUnmount() {
this.isMounted = false;
}
render() {
{
this.bookSearch();
}
return (
<Container>
<TextH5>{this.state.data}</TextH5>
{this.renderContent()}
</Container>
);
}
}
export default DecodeScreen;
You have to use componentDidMount method to do api call
componentDidMount() {
this.bookSearch()
}
Read about react life cycle method

context in componentDidMount appears as null

I currently have a context provider.
componentDidMount() {
if (this.state.memberID === null) {
try {
this.checkAuthUser();
} catch (e) {
console.error(e);
}
}
}
checkAuthUser = () => {
new Promise((resolve, reject) => {
this.props.firebase.auth.onAuthStateChanged(authUser => {
if(authUser) {
resolve(authUser);
} else {
reject(new Error("Not authorized"));
}
})
})
.then( authDetails => {
this.props.firebase.getOrgID(authDetails.uid).on('value', snapshot => {
const setSnapshot = snapshot.val();
const getOrganizationID = Object.keys(setSnapshot)[0];
this.setState({ memberID: authDetails.uid, orgID: getOrganizationID })
})
})
.catch(err => console.log(err))
}
When I try to use this in another component:
static contextType = AuthDetailsContext;
componentDidMount() {
console.log('here is context: ' + this.context.orgID);
if(this.context.orgID) {
this.setState({currentOrganization: this.context.orgID, loading: true}, () => {
this.getMembersInDB('1');
})
}
}
My console.log is null. Means the context isn't registering yet. Any idea what I'm doing wrong?
Your design here seems flawed i.e. when your provider is mounted you send the API request and then when your descendant component is mounted you try to use it - these operations will happen in quick succession, far quicker than it would take for an API call to return from a server.
In your provider, if you must have a user before the component mounts then you need to delay rendering the child components until your API response completes i.e.
const AuthDetailsContext = React.createContext(null);
class AuthDetailsProvider extends PureComponent {
...
componentDidMount() {
const { firebase } = this.props;
firebase.auth.onAuthStateChanged(authUser => {
if (!authUser) {
// Maybe set some other state state to inform the user?
this.setState({ authError: new Error('Not Authorised') });
return;
}
firebase.getOrgID(authUser.uid)
.on('value', snapshot => {
const setSnapshot = snapshot.val();
const getOrganizationID = Object.keys(setSnapshot)[0];
this.setState({
authError: null,
memberID: authUsermemberID.uid,
orgID: getOrganizationID
});
});
})
}
render() {
if (this.state.authError) return <b style={{ color: red }}>{this.state.error.message}</b>;
if (!this.state.memberID) return <b>Authenticating...</b>
return (
<AuthDetailsContext.Provider value={this.state}>
{this.props.children}
</AuthDetailsContext.Provider>
);
}
}

How can I save previous props to be used in componentDidUpdate()?

import React, { Component } from "react";
import Sidebar from "../../components/Sidebar";
import API from "../../utils/API";
import PostContainer from "../../components/PostContainer"
import { withRouter } from 'react-router'
import "./index.css";
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
posts: [],
carMake: "",
carModel: "",
carYear: 0
};
}
componentDidMount() {
const { carMake, carModel, carYear } = this.props.match.params;
if (carMake && carModel && carYear) {
console.log("component mounted, calling loadPostsMakeModelYear");
console.log(carMake, carModel, carYear);
this.loadPostsMakeModelYear(carMake, carModel, carYear);
} else if (carMake && carModel) {
console.log("component mounted, calling loadPostsMakeModel");
console.log(carMake, carModel, carYear);
this.loadPostsMakeModel(carMake, carModel);
} else if (carMake) {
console.log("component mounted, calling loadPostsMake");
console.log(carMake, carModel, carYear);
this.loadPostsMake(carMake);
} else {
console.log("component mounted, calling loadPosts");
console.log(carMake, carModel, carYear);
this.loadPosts();
}
}
componentDidUpdate() {
//???
}
loadPosts = () => {
API.getAllPosts({})
.then(resp => {
this.setState({
posts: resp.data
});
})
.catch(function (error) {
console.log(error);
});
}
loadPostsMake = (carMake) => {
API.getPostByMake(carMake)
.then(resp => {
console.log("loadPostsMake success");
this.setState({
posts: resp.data,
carMake: ""
});
})
.catch(function (error) {
console.log(error);
});
}
loadPostsMakeModel = (carMake, carModel) => {
API.getPostByMakeModel(carMake, carModel)
.then(resp => {
console.log("loadPostsMakeModel success");
this.setState({
posts: resp.data,
carMake: "",
carModel: ""
})
})
.catch(function (error) {
console.log(error);
});
}
loadPostsMakeModelYear = (carMake, carModel, carYear) => {
API.getPostByMakeModelYear(carMake, carModel, carYear)
.then(resp => {
console.log("loadPostsMakeModelYear success");
this.setState({
posts: resp.data,
carMake: "",
carModel: "",
carYear: 0
})
})
.catch(function (error) {
console.log(error);
});
}
handleInputChange = event => {
const { name, value } = event.target;
console.log("input Changed " + name + " " + value)
this.setState({
[name]: value
});
};
handleFormSubmit = event => {
event.preventDefault();
console.log("Handling form submit");
const { carMake, carModel, carYear } = this.state;
const { history } = this.props
if (carMake && carModel && carYear) {
history.push('/search/' + carMake + '/' + carModel + '/' + carYear)
} else if (carMake && carModel) {
history.push('/search/' + carMake + '/' + carModel)
} else if (carMake) {
history.push('/search/' + carMake)
} else {
history.push('/')
}
}
render() {
return (
<div>
<div className="container-fluid">
<div className="row">
<div className="col-2">
<Sidebar
handleInputChange={this.handleInputChange}
handleFormSubmit={this.handleFormSubmit}
/>
</div>
<div className="col-8 offset-1">
{this.state.posts.map(post => (
<PostContainer post={post} />
))}
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Posts);
I am trying to create a way for users to filter through posts based on 3 different parameters. Depending on how many of the 3 they decide to use, a different API call will be made accordingly. The current code works to bring up all posts on initial render, and the search function works only one time.
If the user attempts to use the search function without returning home, the state and URL update, but the components do not update.
I read that I may be able to use something like componentDidUpdate(), but I don't understand how I can get the previous props, or even the previous state.
componentDidUpdate(prevProps, prevState, snapshot) where prevProps is the props of your component before update, same with the prevState, this.state and this.props are fields of your current component. You can compare them to know you fetched something (prevProps.field !== this.props.field && this.props.field === something good), for example

Resources