我正在学习一个教程,其中老师正在将 PayPal 集成到电子商务网站中。问题是,我只有 2 个按钮(图 1),但讲师有 3 个。 (图片 2)我试图一步一步地跟随他,但也许这是 react-paypal-button-v2 库的更新版本或类似的问题。其他 2 个按钮正在正确显示。 (即使它会很好,如果“借记卡或信用卡”按钮有说明)正如您所看到的,我还缺少按钮下方的“由 PayPal 提供支持”行。我已经通过沙箱帐户测试了主要 PayPal 按钮的功能,在这方面一切正常。有人可以帮我解决这个问题吗?非常感谢您的最终帮助。
这些是我当前的 PayPal 按钮 -(图片 0)
更新 - 从代码中删除注释(我将它们留在 SO 上的位置,所以我可以看到它们的位置)后,我已经解决了这个问题 “由 PayPal 提供支持”和“借记卡或信用卡”行。所以现在我的按钮看起来像这样 -(图 1)
这是想要的结果 -(图片 2)
OrderScreen.js -(请注意,尽管事实上,Stack Overflow 上的某些注释不是灰色的,但在我的 IDE 中它们实际上是灰色的)
import React, { useState, useEffect } from "react";
import { Button, Row, Col, ListGroup, Image, Card } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { PayPalButton } from 'react-paypal-button-v2'
import Message from "../components/Message";
import Loader from '../components/Loader'
import { getOrderDetails, payOrder } from "../actions/orderActions";
import { ORDER_PAY_RESET } from '../constants/orderConstants'
function OrderScreen({ match }) {
const orderId = match.params.id
const dispatch = useDispatch();
const [sdkReady, setSdkReady] = useState(false)
//we are updating the setSdkReady
//false is the default value, but once we load the setSdkReady, then it will be set to true
//if we are not ready, then we will not add the button, but if we are ready, we will add the button
//that is going to depend on whether successPay is true or not (?)
const orderDetails = useSelector(state => state.orderDetails)
const {order, error, loading} = orderDetails
const orderPay = useSelector(state => state.orderPay)
const { loading:loadingPay, success:successPay } = orderPay //here we are setting a custom name for the loading
if(!loading && !error){
order.itemsPrice = order.orderItems
.reduce((acc, item) => acc + item.price * item.qty, 0)
.toFixed(2);
//acc znamená accumulator, toFixed(2) znamená, že výsledné číslo bude mít maximálně jen 2 decimal places
} //orderItems gets calculated only once we have that order
const addPayPalScript = () => { //this function is going to be dependent on our order status
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://www.paypal.com/sdk/js?client-id=AVrrJLnByiAFSjPZ91_-o5OeBqUzCQulKVl0aly2FyVOQfZ9cHn2kvUSDNvSJqMv8S9KzBc2_lxRBnuV'
script.async = true
script.onload = () => {
setSdkReady(true)
}
document.body.appendChild(script) //we are appending the script to the dom
}
useEffect(() => {
if (!order || successPay || order._id !== Number(orderId)){ //we are going to dispatch this, if we don´t have an order or if the order id is not here yet
dispatch({ type:ORDER_PAY_RESET })
dispatch(getOrderDetails(orderId)) //this is going to make the api call using that id
//we only get the order details when we don´t have that information yet
} else if(!order.isPaid){ //if order is not paid
if(!window.paypal){
addPayPalScript() //if the script is not there, then add it
} else {
setSdkReady(true) //this gets our script ready
}
}
}, [dispatch, order, orderId, successPay]) //uvnitř hranatých závorek jsou dependencies
const successPaymentHandler = (paymentResult) => {
//paymentResult is going to be the data, that the paypal will give us
//it will be the response from paypal
dispatch(payOrder(orderId, paymentResult)) //payOrder is taking in 2 parameters
//payOrder sends our API call and it goes and updates our database
}
return loading ? ( //we are checking, if (?) we are loading
<Loader/> //load spinner
) : error ? ( //if we are not loading, then (else je :) we will check for an error
<Message variant='danger'>{error}</Message> //if there is an error, let´s throw out that message
) : ( //if none of the above are true, then pass in the final component
<div>
<h1>Order: {order._id}</h1>
<Row>
<Col md={8}>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Shipping</h2>
<p><strong>Name: </strong> {order.user.name}</p>
<p><strong>Email: </strong><a href={`mailto:${order.user.email}`}>{order.user.email}</a></p>
<p>
<strong>Shipping: </strong>
{order.shippingAddress.address}, {order.shippingAddress.city}
{" "}
{order.shippingAddress.postalCode},{" "}
{order.shippingAddress.country}
</p>
{order.isDelivered ? ( //this will be updated from the admin panel
<Message variant='success'>Delivered on {order.deliveredAt}</Message>
) : ( // if this is not delivered, then the else statement will take place
<Message variant='warning'>Not Delivered</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method: </strong>
{order.paymentMethod}
</p>
{order.isPaid ? ( //this will be updated from the admin panel
<Message variant='success'>Paid on {order.paidAt}</Message>
) : ( // if this is not paid, then the else statement will take place
<Message variant='warning'>Not Paid</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Order Items</h2>
{order.orderItems.length === 0 ? (
<Message variant="info">Order is empty</Message>
) : (
<ListGroup variant="flush">
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={1}>
<Image
src={item.image}
alt={item.name}
fluid
rounded
/>
</Col>
<Col>
<Link to={`/product/${item.product}`}>
{item.name}
</Link>
</Col>
<Col md={4}>
{item.qty} X ${item.price} = $
{(item.qty * item.price).toFixed(2)}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Order Summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Items:</Col>
<Col>${order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>${order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>${order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>${order.totalPrice}</Col>
</Row>
</ListGroup.Item>
{!order.isPaid && (
<ListGroup.Item>
{loadingPay && <Loader/>}
{!sdkReady ? ( //while we are loading, then output the loader
<Loader/>
) : ( //else
<PayPalButton
amount={order.totalPrice}
onSuccess={successPaymentHandler}
/>
)}
</ListGroup.Item>
)}
</ListGroup>
</Card>
</Col>
</Row>
</div>
);
}
export default OrderScreen;