medusa-plugin-paypal
v0.1.4
Published
Paypal payment provider for Medusa v2
Maintainers
Readme
Medusa-plugin-paypal
medusa-plugin-paypal is a integration of payment provider for Paypal.
⚠️ Warn
| Requires Medusa v2.10.4 or later.
Installaction
npm i medusa-plugin-paypalBackend
// medusa-config.js
const { loadEnv, defineConfig, Modules } = require("@medusajs/framework/utils");
// ...
modules:[
[Modules.PAYMENT]: {
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "medusa-plugin-paypal/providers/paypal-payment",
id: "payment-paypal",
options: {
intent: "CAPTURE",
clientId: process.env.PAYPAL_CLIENT_ID,
clientSecret: process.env.PAYPAL_CLIENT_SECRET,
sandbox: true,
webhookId: process.env.PAYPAL_WEBHOOK_ID,
}
}
]
}
}
]
plugins: [
{
resolve: "medusa-paypal-payment",
options: {
intent: "CAPTURE",
clientId: process.env.PAYPAL_CLIENT_ID,
clientSecret: process.env.PAYPAL_CLIENT_SECRET,
sandbox: true,
webhookId: process.env.PAYPAL_WEBHOOK_ID,
},
}
]
Store
- Create
/src/modules/checkout/components/payment-wrapper/paypal-wrapper.tsx
"use client"
import { HttpTypes } from "@medusajs/types"
import { createContext } from "react"
import {
PayPalScriptProvider,
ReactPayPalScriptOptions,
} from "@paypal/react-paypal-js"
type PaypalWrapperProps = {
paymentSession: HttpTypes.StorePaymentSession
clientId: string
children: React.ReactNode
}
export const PaypalContext = createContext(false)
const PaypalWrapper: React.FC<PaypalWrapperProps> = ({
paymentSession,
clientId,
children,
}) => {
const initialOptions: ReactPayPalScriptOptions = {
clientId,
currency: paymentSession.currency_code.toLocaleUpperCase(),
intent: "capture",
components:"buttons",
debug:false
}
return (
<PayPalScriptProvider deferLoading={false} options={initialOptions}>
{children}
</PayPalScriptProvider>
)
}
export default PaypalWrapper
- Update
/src/modules/checkout/components/payment-wrapper/index.tsx
// add
// !!!isPaypal() is 'pp_paypal'
if (isPaypal(paymentSession?.provider_id) && paymentSession) {
return (
<PaypalWrapper
paymentSession={paymentSession}
clientId={paypaylClientId}
>
{children}
</PaypalWrapper>
)
}
- Update
/src/modules/checkout/components/payment-button/index.tsx
// add paypal button
const PaypalPaymentButton = ({
cart,
notReady,
"data-testid": dataTestId,
}: {
cart: HttpTypes.StoreCart
notReady: boolean
"data-testid"?: string
}) => {
const [submitting, setSubmitting] = useState(false)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const onPaymentCompleted = async () => {
await placeOrder()
}
const handlePayment = async (
_data: OnApproveData,
actions: OnApproveActions
) => {
setSubmitting(true)
await actions?.order
?.capture()
.then((authorization) => {
if (authorization.status !== "COMPLETED") {
setSubmitting(false)
setErrorMessage(`An error occurred, status: ${authorization.status}`)
return
}
onPaymentCompleted()
})
.catch((error) => {
setErrorMessage(`An unknown error occurred, please try again.`)
setSubmitting(false)
})
}
const session = cart.payment_collection?.payment_sessions?.find(
(s) => s.status === "pending"
)
return (
<>
<PayPalButtons
disabled={submitting}
createOrder={async (data, actions) => {
return session?.data.id as string
}}
onApprove={handlePayment}
onError={(err) => {
console.error("PayPal Checkout onError", err)
}}
style={styles}
/>
<ErrorMessage
error={errorMessage}
data-testid="paypal-payment-error-message"
/>
</>
)
}
// Update PaymentButton
const PaymentButton: React.FC<PaymentButtonProps> = ({
...
switch (true) {
...
case isPaypal(paymentSession?.provider_id):
return (
<PaypalPaymentButton
notReady={notReady}
cart={cart}
data-testid={dataTestId}
/>
)
...
}
...
})