Dra*_*era 1 javascript stripe-payments typescript reactjs
我有 PaymentMethodPage,如下所示:
import React, { FC, useState } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import {
getClientSecret,
} from '../../api/PaymentCalls/PaymentCalls';
import PaymentMethodSetupForm from './PaymentMethodSetupForm/PaymentMethodSetupForm';
import AddPaymentMethodContainer from './AddPaymentMethodContainer/AddPaymentMethodContainer';
import {
ClientSecretResponse,
} from '../../interfaces/paymentMethod.interface';
const stripePromise = loadStripe(
process.env.REACT_APP_STRIPE_PUBLIC_KEY as string
);
const PaymentMethodPage: FC = () => {
const [enableAddPaymentMethod, setEnableAddPaymentMethod] =
useState<boolean>(false);
const {
data: clientSecretKeyData,
}: UseQueryResult<ClientSecretResponse, ExtendedError> = useQuery<
ClientSecretResponse,
ExtendedError
>('getClientSecret', getClientSecret, {
retry: false,
refetchOnWindowFocus: false,
enabled: enableAddPaymentMethod,
onError: (error: ExtendedError) => {
if (error) {
console.log(error)
}
},
});
const options = {
clientSecret: clientSecretKeyData?.client_secret,
};
const addPaymentMethodHandler = (): void => {
setEnableAddPaymentMethod(!enableAddPaymentMethod);
};
return (
<AppDrawer onLogOut={logoutHandler}>
{paymentMethodData.default_payment_method !== null ? (
<Box>
<Typography>
Payment Method
</Typography>
</Box>
) : (
<Box>
<AddPaymentMethodContainer
addButtonHandler={addPaymentMethodHandler}
/>
</Box>
{clientSecretKeyData && (
<Elements stripe={stripePromise} options={options}>
<PaymentMethodSetupForm
isOpenPaymentDialog={enableAddPaymentMethod}
handleClose={addPaymentMethodHandler}
setPaymentDialogOpen={addPaymentMethodHandler}
/>
</Elements>
)}
</AppDrawer>
);
};
export default PaymentMethodPage;
Run Code Online (Sandbox Code Playgroud)
如果没有付款方式,我将呈现 AddPaymentMethodContainer。看起来像这样:
import React, { FC } from 'react';
import { Box, Typography, Button } from '@mui/material';
interface AddPaymentMethodContainerProps {
addButtonHandler: () => void;
}
const AddPaymentMethodContainer: FC<AddPaymentMethodContainerProps> = ({
addButtonHandler,
}) => {
return (
<Box >
<Box >
<img
src={someImage}
alt="no-payment-method"
/>
</Box>
<Typography>
No payment method found. Click the button below to provide one.
</Typography>
<Box sx={styles.addButtonContainer}>
<Button
sx={styles.addButton}
variant="contained"
onClick={addButtonHandler}
>
Add Payment
</Button>
</Box>
</Box>
);
};
export default AddPaymentMethodContainer;
Run Code Online (Sandbox Code Playgroud)
单击添加按钮后,我将呈现付款表单,其中包含 Stipe PaymentElement...该组件如下所示:
import React, { FC, useState } from 'react';
import {
PaymentElement,
useStripe,
useElements,
} from '@stripe/react-stripe-js';
import { useMutation, UseMutationResult, useQueryClient } from 'react-query';
import { Dialog, DialogTitle, DialogContent } from '@mui/material';
interface PaymentMethodSetupFormProps {
isOpenPaymentDialog: boolean;
handleClose: () => void;
setPaymentDialogOpen: (e: boolean) => void;
}
const PaymentMethodSetupForm: FC<PaymentMethodSetupFormProps> = ({
isOpenPaymentDialog,
setPaymentDialogOpen,
handleClose,
}) => {
const stripe = useStripe();
const elements = useElements();
const [isLoading, setIsLoading] = useState<boolean>(false);
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
const handleSubmit = async (event: React.SyntheticEvent) => {
event.preventDefault();
if (!stripe || !elements) {
// eslint-disable-next-line no-useless-return
return;
}
setIsLoading(true);
const result = await stripe.confirmSetup({
elements,
confirmParams: {
return_url: 'http://localhost:3000/payment-status/',
},
redirect: 'if_required',
});
if (result.error) {
console.log(`${result.error.message}`)
} else {
console.log('All okay!')
setPaymentDialogOpen(false);
}
setIsLoading(false);
};
return (
<Dialog
open={isOpenPaymentDialog}
onClose={handleClose}
>
<DialogTitle>
Payment Methods:
</DialogTitle>
<DialogContent>
<form onSubmit={handleSubmit}>
<PaymentElement />
<CustomSubmitButton
cypressId="credit-card-submit-button"
isLoading={isLoading}
text="Save"
style={{ margin: '2rem auto', fontWeight: 'bolder' }}
disabled={isLoading}
/>
</form>
</DialogContent>
</Dialog>
);
};
export default PaymentMethodSetupForm;
Run Code Online (Sandbox Code Playgroud)
这里我禁用了handleSubmit的函数返回类型,因为我不知道应该是什么类型......它是一个Promise<>,所以如果有人有任何想法(请帮助)。一般来说,一切工作正常,我不喜欢的是当我单击“ADD”按钮打开表单并关闭它时,在按下按钮的第二次尝试时,控制台中出现警告:
Unsupported prop change: options.clientSecret is not a mutable property.
Run Code Online (Sandbox Code Playgroud)
此外,还有关于 PaymentElement 内图像的警告(用于卡号):
Each dictionary in the list "icons" should contain a non-empty UTF8 string field "type".
Run Code Online (Sandbox Code Playgroud)
最后一件事,非常烦人。根据他们的文档,我可以禁用表单中的提交/保存/付款按钮,如下所示:
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button disabled={!stripe}>Submit</button>
{/* Show error message to your customers */}
{errorMessage && <div>{errorMessage}</div>}
</form>
)
Run Code Online (Sandbox Code Playgroud)
但看起来这个物体总是真实的。我试着把它做成这样:
return (
<form onSubmit={handleSubmit}>
{!stripe && (
<PaymentElement />
<button>Submit</button>
{/* Show error message to your customers */}
{errorMessage && <div>{errorMessage}</div>}
)}
</form>
)
Run Code Online (Sandbox Code Playgroud)
因为当我可以在条纹可用时渲染它时,为什么我应该禁用它。但看起来它不是那样工作的。提交按钮始终存在,突然出现付款表格......这不太好。作为用户,我有一个按钮,有时会显示表单。好吧,不需要那么多时间,但在我看来,这并不酷。
添加key={clientSecret}到<Elements>组件。
也可以使用更新 PaymentIntent或确认 PaymentIntent
Stripe 团队对此是这么说的:
我们目前不支持更新 clientSecret 属性,任何尝试的更新都将被忽略。这是尝试更新 clientSecret 时记录到控制台的警告:
Unsupported prop change: options.clientSecret is not a mutable property.
Run Code Online (Sandbox Code Playgroud)
不过,我们确实有一些正在进行的工作来解决您的具体用例(创建后更新 PaymentIntent 上的金额)。同时,一个可能的解决方法是,当客户端密钥发生变化时,通过更新提供程序的密钥来重新安装提供程序并进行相应的操作:
-<Elements options={options} stripe={stripePromise}>
+<Elements options={options} stripe={stripePromise} key={clientSecret}>
Run Code Online (Sandbox Code Playgroud)
https://githubhot.com/repo/stripe/react-stripe-js/issues/246
| 归档时间: |
|
| 查看次数: |
3779 次 |
| 最近记录: |