How to use PayPal's Express In-Context Checkout with ReactJS? - javascript

I'm following this PayPal tutorial about how to generate a PayPal button, but nothing works. The code it provides to make the button appear mysteriously worked only once for me, but after a refresh, it disappear and there's no Christ to make it appear again.
This is the code being executed inside of a React component
class Storefronts extends Component {
render() {
return (
<div className="layout-wrapper">
{this.props.location.pathname === '/shops' ? <Shops {...this.props}/> : <Basic {...this.props}/>}
<script>
window.paypalCheckoutReady = function() {
paypal.checkout.setup('MERCHANTID', {
environment: 'sandbox',
container: 'test1',
})
}
</script>
</div>
);
}
}
This is a Storefront component that holds a Shop, and inside this one has a Card component. Basically, it's a shop that shows its products, and each product (Card) needs to have a button:
class Card extends Editor {
render() {
const {list} = this.props;
let img = '/images/logo-v2-small.jpg';
return (
<Row>
{list.map(item =>{
return (
<Col xs={6} md={3}>
<Link to={{ pathname: '/shops/' + item.id }}>
<Thumbnail src={img} alt={item.name}>
<h3>{item.name}</h3>
<p>{this.parseHtmlToReact(item.description)}</p>
<p>{item.address}</p>
<p>
<Button bsStyle="primary">Book</Button>
<a id="test1" href="/checkout"/> // The button should appear here.
<p className="pull-right">
{item.rating}
</p>
</p>
</Thumbnail>
</Link>
</Col>
)
})}
</Row>
);
}
}
There's nothing saying about its usage with React and no recent module for it.

You could create your own PayPal Button component.
class PayPalButton extends React.Component {
constructor() {
super();
// you can take this value from a config.js module for example.
this.merchantId = '6XF3MPZBZV6HU';
}
componentDidMount() {
let container = this.props.id;
let merchantId = this.merchantId;
window.paypalCheckoutReady = function() {
paypal.checkout.setup(merchantId, {
locale: 'en_US',
environment: 'sandbox',
container: container,
});
}
}
render() {
return(
<a id={this.props.id} href="/checkout" />
);
}
}
ReactDOM.render(<PayPalButton id="button" />, document.getElementById('View'));
Working example on JSFiddle.

Related

React Render List Incorrect (List is correct, but render overwrite and duplicate)

I’m trying to make a simple order system, when user selects QTY and click “Add to Order”, the information of the selected dish will be shown in the “Your Order” area (click “Refresh Order” to see). What I’m doing is to insert the dish information (from MenuEdit component) into a list (in CustomerOrder component).
My question is as following: I add “Moo Goo Guy Pan” QTY:1 to order, it will be inserted to the list, and then I add “Teriyaki Chicken” QTY:2, it will be inserted to the list, and I add “Moo Goo Guy Pan” again but QTY:3 to order, it will be inserted to the list. The uid is a timestamp when user click “Add to Order”. The list is working fine (I use lodash to deep copy), but when render all the item of the list is not good. I cannot think of a proper way to solve it. I’m willing to provide more information as you request. Thank you for your time and help.
I made a GIF to demonstrate the step and you can see the list changing in the console.
link: https://github.com/Dungyichao/COVID19_Reporting_Web/blob/master/img/EggrollChenOrderSC.gif
User click the “Add to Order”, the first and the second step are doing good.
The render steps of the Cart (Your Order), the first and the second step are doing good.
The following is the list that is passed to the component for rendering. Note the qty is different, and this is the correct list which I want and already passed into CartList components.
My Codes and Components structure is as follow
Order.js
export default class CustomerOrder extends Component {
constructor(props) {
super(props);
this.firebase = props.firebase;
this.sendinfo_toCart_handle = this.sendinfo_toCart_handle.bind(this);
this.Cart_new_item_arrive = this.Cart_new_item_arrive.bind(this);
this.remove_item = this.remove_item.bind(this);
this.state = {
Cart_data: [],
Cart_new_item: '',
}
this.refresh_cart_handle = this.refresh_cart_handle.bind(this);
}
remove_item(e){
console.log("Remove item uid: ", e);
}
refresh_cart_handle(){
let {Cart_data} = this.state;
console.log("Current Cart Data: ", Cart_data);
}
Cart_new_item_arrive(e){
//console.log("Cart_new_item_arrive: ", e);
this.setState({Cart_new_item: e}, () => {
//after setstate
this.sendinfo_toCart_handle();
});
}
sendinfo_toCart_handle(){
let {Cart_new_item, Cart_data} = this.state;
let deepcopy_list = _.cloneDeep(Cart_data);
deepcopy_list.push(Cart_new_item);
this.setState({Cart_data: deepcopy_list});
}
render() {
let {Cart_data} = this.state;
return (
<div style={order_style}>
<div style={{
}}>
<h3>Menu</h3>
<MenuEdit firebase={this.firebase} CartAdd={this.Cart_new_item_arrive} />
</div>
<div style={{
}}>
<h3>Your Order</h3>
<Cart data_array={Cart_data} remove_item={this.remove_item} /> {/*remove_item={this.remove_item}*/}
<Button onClick={this.refresh_cart_handle}>Refresh Order</Button>
</div>
</div>
);
}
}
Cart.js
export default class Cart extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div>
<Scroll>
<CartList data_array={this.props.data_array} remove_item={this.props.remove_item} /> {/*remove_item={this.props.remove_item}*/}
</Scroll>
</div>
<div>
<div><Button>Refresh</Button></div>
<div>
<Button>Cancel</Button> {' '}
<Button>Place Order</Button>
</div>
</div>
</div>
);
}
}
CartList.js
export default class CartList extends Component {
constructor(props) {
super(props);
}
render(){
let display_data = this.props.data_array;
let null_page = [];
console.log("Data in CartList.js: ", display_data)
if(display_data[0]){
return(
display_data.map(
(cart_item, idx) => {
//console.log("In Map", idx, ' Item: ', cart_item);
return(
<div>
<CartItem key={idx} u_key={idx + 1}
Cart_item_info={cart_item}
remove_item={this.props.remove_item} /> {/*remove_item={this.props.remove_item}*/}
</div>
);
}
)
)
}
else{
return(
<div>
<p>Add Your Favorite Dishes to Here</p>
</div>
);
}
}
}
CartItem.js (which render each item in the list)
export default class CartItem extends Component {
constructor(props) {
super(props);
this.state = {
show_toggle: true,
cart_item_info: this.props.Cart_item_info,
u_key: this.props.u_key,
}
//cart_item_info: this.props.Cart_item_info,
this.remove_item_handle = this.remove_item_handle.bind(this);
}
remove_item_handle(){
let {cart_item_info} = this.state;
this.props.remove_item(cart_item_info.uid);
}
render() {
let {cart_item_info, u_key} = this.state;
//console.log("Return CartItem")
return (
<div key={u_key} >
<Accordion>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="0">
<div style={item_style}>
<div style={{flex: '1'}}>{u_key}.</div>
<div style={{flex: '7'}}> {cart_item_info.dish_name}</div>
<div style={{flex: '2'}}>X {cart_item_info.qty}</div>
<div style={{flex: '2'}}>${cart_item_info.Tprice}</div>
</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<Button onClick={this.remove_item_handle} >Remove</Button>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
);
}
}
Update your cartItem.js file. It should be functional component.
const CartItems = (props) => {
console.log(props.Cart_item_info);
return (
<div key={props.u_key} >
<Accordion>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="0">
<div>
<div style={{ flex: '1' }}>{props.u_key}.</div>
<div style={{ flex: '7' }}> {props.Cart_item_info.dish_name}</div>
<div style={{ flex: '2' }}>X {props.Cart_item_info.qty}</div>
<div style={{ flex: '2' }}>${props.Cart_item_info.Tprice}</div>
</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey="0">
<Card.Body>
<div>No</div>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
);
}
I finally find the root cause of the problem which I didn't reveal it in the question because I don't even think that would cause a problem
The problem is from the MenuItem component (Menu item which user can click Add to Order). The correct way is to clear all data (which is going to insert to list in Order.js) hold in the state of the MenuItem component whenever it has already already inserted. By doing so you can prevent any original data being sent again.
Also in the chat room with Deepak, he suggest some following tips:
When you want to just show something and no state management than prefer functional component.
key help react to identity the item change in the list.

Function to replace alert

I want to roll my own custom alert, but don't want to touch the render or state of components that currently call the default window.alert().
I'm using React 15.x
function injectDialogComponent(message: string){
const modal = <Modal>{message}</Modal>
document.body.appendChild(modal) //this errors, but how would I do something like this?
}
I've tried
ReactDOM.render(modal,document.body.appendChild(document.createElement('div)
but doesn't work
You can create you html node, append it to you root element and then append your React <Modal> in you newly created div modal :
React.render(<Modal>{message}</Modal>, document.getElementById('modal'))
class Modal extends React.Component {
render() {
return (
<dialog id='modal' style={{width: "80%", height: "80%", marginTop: 10, backgroundColor: '#eee'}} open
>
<p>{this.props.children}</p>
</dialog>
);
}
}
class App extends React.Component {
openModal = message => {
let modal = document.createElement('div');
modal.id = 'modal';
document.getElementById('root').appendChild(modal)
React.render(<Modal>{message}</Modal>, document.getElementById('modal'));
}
render() {
return (
<div>
<button onClick={() => this.openModal("Hello")}>Open Modal</button>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>

onClick import of css doesn't work as expected in reactjs

I have 2 components in my react app for now: App and Navbar
I am trying to dynamically load css (4 different themes from bootswatch) on user click (theming in short)
Below are the components:
App.js
class App extends Component {
state = {};
availableThemes = ["lux", "sketchy", "flatly", "darkly"];
constructor() {
super();
this.changeTheme("flatly");
ReactDOM.findDOMNode;
}
changeTheme = themeName => {
console.log("Theme", themeName);
if (this.availableThemes.indexOf(themeName) < 0) {
alert("Theme not available");
} else {
import(`./themes/${themeName}/bootstrap.min.css`)
.then(() => {
console.log("Theme loaded", themeName);
})
.catch(() => {});
}
};
render() {
return (
<NavBar
themesList={this.availableThemes}
onThemeChange={this.changeTheme}
/>
);
}
}
Navbar.jsx:
class NavBar extends Component {
state = {};
render() {
const { themesList, onThemeChange } = this.props;
return (
<Navbar bg="dark" variant="dark" expand="lg">
<Navbar.Brand>WiLite</Navbar.Brand>
<Navbar.Collapse style={{ paddingLeft: 25 + "%" }}>
<Form inline>
<FormGroup>
<FormControl
type="text"
placeholder="Search"
className="mr-sm-2"
/>
<Button variant="outline-light">Search</Button>
</FormGroup>
</Form>
<Nav>
<NavDropdown title="Theme">
{themesList.map(theme => {
return (
<NavDropdown.Item
key={v4()}
onClick={() => {
onThemeChange(theme);
}}
>
{theme}
</NavDropdown.Item>
);
})}
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
Now the output of changeTheme is very random. Sometimes the theme gets applied, sometimes it doesn't and sometimes I get a mixture of both the themes (the one I requested and the one which was already loaded).
Can someone please suggest how can I accomplish this?

React: How to add an infinite an infinite amount of components with onClick?

I am new to React and am building a form. The form consists of a collection made up of several Components. One of the Components is textfield.
I want to create a button that simply adds an infinite amount of the same textfield component on click. I'm stumped on how to do this and cannot find any information online.
My code thus far is:
constructor(props) {
super(props);
this.handleClickDestination = this.handleClickDestination.bind(this);
}
static defaultProps = {
}
static propTypes = {
}
handleClickDestination() {
console.log('click');
}
render() {
const {
className
} = this.props;
return (
<div className={className}>
<DestinationSearchInput />
<Grid item margin="normal">
</Grid>
<Grid container spacing={12} alignItems="flex-end">
<Button onClick={this.handleClickDestination} color="primary">
Add another destination
</Button>
</Grid>
<div>
// extra <DestinationSearchInput /> components to go here
</div>
<DatePicker />
<TravellerCounter />
</div>
);
}
}
Would anyone be able to point me in the right direction on how to achieve this?
You can use states to let your component know how many destination fields are to be rendered
In this case I have just used an array of dummy items to render the fields for that many times.
constructor() {
this.state = {
items: ['dummy']
}
}
handleClickDestination() {
this.setState({items: this.state.items.concat('dummy') })
}
render() {
const {
className
} = this.props;
return (
<div className={className}>
<DestinationSearchInput />
<Grid item margin="normal">
</Grid>
<Grid container spacing={12} alignItems="flex-end">
<Button onClick={this.handleClickDestination} color="primary">
Add another destination
</Button>
</Grid>
<div>
// use this block here
{
this.state.items.map((_, index) =>
<DestinationSearchInput
key={index}
/>
)
}
// use this block here
</div>
<DatePicker />
<TravellerCounter />
</div>
);
}
or simply use a number and then render using it
// in constructor
this.state = {items: 0}
// inside handle click
this.setState({items: this.state.items + 1})
// in render
new Array(this.state.items).fill(0).map((_,index) =>
<DestinationSearchInput
key={index}
/>
)
I think you can do like:
onClick(){this.setState({textFields: [...text}); onClick(); }
On Render method you can use:
const TextComponent = this.state.textFields.map(item => . . . .
Your component here)
You can put random position for you component as well.

How do I clear the the array of a state?

So this is my code :
import React from "react";
import Navigation from './Navigation';
import Foot from './Foot';
import MovieCard from './MovieCard';
class Favorites extends React.Component {
render() {
const { onSearch, favorites, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate} />
<div className="container">
<button onClick={()=> this.clearFavorites(favorites)}> Clear all movies </button>
{(favorites.length < 1) ?
<h1 style={{ fontSize: '13px', textAlign: 'center' }}>Please mark some of the movies as favorites!</h1>
:
<ul
className="movies">
{favorites
.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
}
<Foot />
</div>
</div>
);
}
}
const clearFavorites = (favorites) => {
this.setState({ favorites: [] });
}
The thing I need for the button to do is that when i click it that it clears the whole state of favorites. The clearFavorites function is used to clear everything but when I try this I get an error:
Why doesn't this clear the state of favorites?
You have two problems:
clearFavorites function is not in your class. So you should put it inside.
You are trying to clear the data inside the favorites array, which is not part of your state, using the function clearFavorites. So, first of all, you should add favorites array to your state and then you can manipulate the information. I suggest you to use the function getDerivedStateFromProps.
As others mentioned, first moving clearFavorites function into Favorites class.
Second, your favorites list is not part of state object, but instead you pull it out from this.props.favorites, so instead of using this.setState, we should just change the props value.
Third, since you're emptying the array, the parameter in your clearFavorites probably not needed? Please refer to below:
First we define a constructor to get the value from props and pass it to state in the constructor as below:
constructor(props) {
super(props);
this.state = {favorites: this.props.favorites}
}
clearFavorites = () => {
this.setState({favorites: []});
};
Then at last in your render method change to following:
const { onSearch, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
const favorites = this.state.favorites;// Or in your ul tag, instead of using favorites, change it to this.state.favorites
You can try to move the clearFavorites into your component
import React from "react";
import Navigation from "./Navigation";
import Foot from "./Foot";
import MovieCard from "./MovieCard";
class Favorites extends React.Component {
render() {
const {
onSearch,
favorites,
favoriteCallback,
totalFavorites,
searchKeyUpdate
} = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate}
/>
<div className="container">
<button onClick={() => this.clearFavorites(favorites)}>
{" "}
Clear all movies{" "}
</button>
{favorites.length < 1 ? (
<h1 style={{ fontSize: "13px", textAlign: "center" }}>
Please mark some of the movies as favorites!
</h1>
) : (
<ul className="movies">
{favorites.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
)}
<Foot />
</div>
</div>
);
}
clearFavorites = favorites => {
this.setState({ favorites: [] });
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Categories

Resources