@graphcommerce/magento-payment-afterpay 10.0.0-canary.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # @graphcommerce/magento-payment-afterpay
2
+
3
+ ## 10.0.0-canary.72
4
+
5
+ ## 10.0.0-canary.71
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Magento Payment Afterpay
2
+
3
+ Integrates GraphCommerce with the Magento Afterpay module.
4
+
5
+ It requires [Afterpay](https://github.com/afterpay/afterpay-magento-2) module to
6
+ be installed before using this package.
7
+
8
+ ## Installation
9
+
10
+ 1. Find current version of your `@graphcommerce/magento-cart-payment-method` in
11
+ your package.json.
12
+ 2. `yarn add @graphcommerce/magento-payment-afterpay@1.2.3` (replace 1.2.3 with
13
+ the version of the step above)
14
+
15
+ This package uses GraphCommerce plugin systems, so there is no code modification
16
+ required.
@@ -0,0 +1,22 @@
1
+ import { Image } from '@graphcommerce/image'
2
+ import type { PaymentMethodActionCardProps } from '@graphcommerce/magento-cart-payment-method'
3
+ import { ActionCard, useIconSvgSize } from '@graphcommerce/next-ui'
4
+ import afterpayMark from '../../icons/afterpay.png'
5
+
6
+ export function AfterpayPaymentActionCard(props: PaymentMethodActionCardProps) {
7
+ const iconSize = useIconSvgSize('large')
8
+
9
+ return (
10
+ <ActionCard
11
+ {...props}
12
+ image={
13
+ <Image
14
+ layout='fixed'
15
+ sx={{ width: iconSize, height: iconSize, objectFit: 'contain' }}
16
+ unoptimized
17
+ src={afterpayMark}
18
+ />
19
+ }
20
+ />
21
+ )
22
+ }
@@ -0,0 +1,12 @@
1
+ mutation AfterpayPaymentHandler($cartId: String!, $paymentMethod: PaymentMethodInput!) {
2
+ setPaymentMethodOnCart(input: { cart_id: $cartId, payment_method: $paymentMethod }) {
3
+ cart {
4
+ ...PaymentMethodUpdated
5
+ }
6
+ }
7
+ placeOrder(input: { cart_id: $cartId }) {
8
+ order {
9
+ order_number
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,58 @@
1
+ import { ApolloErrorSnackbar } from '@graphcommerce/ecommerce-ui'
2
+ import { useMutation } from '@graphcommerce/graphql'
3
+ import { useCurrentCartId } from '@graphcommerce/magento-cart'
4
+ import type { PaymentHandlerProps } from '@graphcommerce/magento-cart-payment-method'
5
+ import { usePaymentMethodContext } from '@graphcommerce/magento-cart-payment-method'
6
+ import { useRouter } from 'next/router'
7
+ import { useEffect } from 'react'
8
+ import { useAfterpayCartLock } from '../../hooks/useAfterpayCartLock'
9
+ import { AfterpayPaymentHandlerDocument } from './AfterpayPaymentHandler.gql'
10
+
11
+ export function AfterpayPaymentHandler(props: PaymentHandlerProps) {
12
+ const { code } = props
13
+ const { push } = useRouter()
14
+ const [lockStatus, , unlock] = useAfterpayCartLock()
15
+ const { onSuccess } = usePaymentMethodContext()
16
+ const { currentCartId: cartId } = useCurrentCartId()
17
+
18
+ const { orderToken, status, locked, justLocked, method } = lockStatus
19
+ const [placeOrder, { error, called }] = useMutation(AfterpayPaymentHandlerDocument, {
20
+ variables: {
21
+ cartId,
22
+ paymentMethod: {
23
+ code,
24
+ afterpay: {
25
+ afterpay_token: orderToken ?? '',
26
+ },
27
+ },
28
+ },
29
+ errorPolicy: 'all',
30
+ })
31
+
32
+ useEffect(() => {
33
+ if (locked && !justLocked && status === 'CANCELLED')
34
+ void unlock({ orderToken: null, status: null })
35
+ }, [status, code, justLocked, locked, method, unlock])
36
+
37
+ // If successfull we clear it's cart and redirect to the success page.
38
+ useEffect(() => {
39
+ if (!orderToken || status !== 'SUCCESS' || called) return
40
+ if (!cartId) return
41
+
42
+ const fetchData = async () => {
43
+ const res = await placeOrder()
44
+
45
+ if (res.error || !res.data?.placeOrder?.order) {
46
+ await unlock({ orderToken: null, status: null })
47
+ return
48
+ }
49
+
50
+ await onSuccess(res.data?.placeOrder?.order.order_number)
51
+ }
52
+
53
+ void fetchData()
54
+ }, [status, called, cartId, onSuccess, placeOrder, push, orderToken, unlock])
55
+
56
+ if (error) return <ApolloErrorSnackbar error={error} />
57
+ return null
58
+ }
@@ -0,0 +1,6 @@
1
+ mutation AfterpayPaymentPlaceOrder($cartId: String!, $redirect_path: AfterpayRedirectPathInput!) {
2
+ createAfterpayCheckout(input: { cart_id: $cartId, redirect_path: $redirect_path }) {
3
+ afterpay_redirectCheckoutUrl
4
+ afterpay_token
5
+ }
6
+ }
@@ -0,0 +1,43 @@
1
+ import { useFormCompose } from '@graphcommerce/ecommerce-ui'
2
+ import { useFormGqlMutationCart } from '@graphcommerce/magento-cart'
3
+ import type { PaymentPlaceOrderProps } from '@graphcommerce/magento-cart-payment-method'
4
+ import { useRouter } from 'next/router'
5
+ import { useAfterpayCartLock } from '../../hooks/useAfterpayCartLock'
6
+ import { AfterpayPaymentPlaceOrderDocument } from './AfterpayPaymentPlaceOrder.gql'
7
+
8
+ export function AfterpayPaymentPlaceOrder(props: PaymentPlaceOrderProps) {
9
+ const { code, step } = props
10
+ const [, lock] = useAfterpayCartLock()
11
+ const { push } = useRouter()
12
+
13
+ const form = useFormGqlMutationCart(AfterpayPaymentPlaceOrderDocument, {
14
+ onBeforeSubmit: (variables) => ({
15
+ ...variables,
16
+ redirect_path: { cancel_path: `checkout/payment`, confirm_path: `checkout/payment` },
17
+ }),
18
+ onComplete: async (result) => {
19
+ if (result.errors) return
20
+
21
+ const start = result.data?.createAfterpayCheckout?.afterpay_redirectCheckoutUrl
22
+ const orderToken = result.data?.createAfterpayCheckout?.afterpay_token
23
+
24
+ if (!start)
25
+ throw Error(
26
+ 'Error while starting the Afterpay payment, please try again with a different payment method',
27
+ )
28
+
29
+ await lock({ orderToken, method: code })
30
+ // We are going to redirect, but we're not waiting, because we need to complete the submission to release the buttons
31
+ void push(start)
32
+ },
33
+ })
34
+
35
+ const submit = form.handleSubmit(() => {})
36
+ useFormCompose({ form, step, submit, key: `AfterpayPaymentPlaceOrder_${code}` })
37
+
38
+ return (
39
+ <form onSubmit={submit} noValidate>
40
+ <input type='hidden' value={code} />
41
+ </form>
42
+ )
43
+ }
@@ -0,0 +1,16 @@
1
+ import type { CartLockState } from '@graphcommerce/magento-cart-payment-method'
2
+ import { useCartLock } from '@graphcommerce/magento-cart-payment-method'
3
+
4
+ type AfterpayLockState = CartLockState & {
5
+ orderToken?: string | null
6
+ status?: 'SUCCESS' | 'CANCELLED' | null
7
+ }
8
+
9
+ /**
10
+ * The cart lock situation is a bit odd since are unable to actually influence the return URL we
11
+ * can't safely remember the cart ID.
12
+ *
13
+ * This is a potential bug because when the customer is returning from an icognito session, the cart
14
+ * ID is not available.
15
+ */
16
+ export const useAfterpayCartLock = () => useCartLock<AfterpayLockState>()
Binary file
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {}
package/next-env.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/types/global" />
3
+ /// <reference types="next/image-types/global" />
4
+ /// <reference types="@graphcommerce/next-ui/types" />
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@graphcommerce/magento-payment-afterpay",
3
+ "homepage": "https://www.graphcommerce.org/",
4
+ "repository": "github:graphcommerce-org/graphcommerce",
5
+ "version": "10.0.0-canary.72",
6
+ "sideEffects": false,
7
+ "prettier": "@graphcommerce/prettier-config-pwa",
8
+ "eslintConfig": {
9
+ "extends": "@graphcommerce/eslint-config-pwa",
10
+ "parserOptions": {
11
+ "project": "./tsconfig.json"
12
+ }
13
+ },
14
+ "exports": {
15
+ ".": "./index.ts",
16
+ "./plugins/AddAfterpayMethods": "./plugins/AddAfterpayMethods.tsx"
17
+ },
18
+ "peerDependencies": {
19
+ "@graphcommerce/ecommerce-ui": "^10.0.0-canary.72",
20
+ "@graphcommerce/eslint-config-pwa": "^10.0.0-canary.72",
21
+ "@graphcommerce/graphql": "^10.0.0-canary.72",
22
+ "@graphcommerce/image": "^10.0.0-canary.72",
23
+ "@graphcommerce/magento-cart": "^10.0.0-canary.72",
24
+ "@graphcommerce/magento-cart-payment-method": "^10.0.0-canary.72",
25
+ "@graphcommerce/magento-store": "^10.0.0-canary.72",
26
+ "@graphcommerce/next-ui": "^10.0.0-canary.72",
27
+ "@graphcommerce/prettier-config-pwa": "^10.0.0-canary.72",
28
+ "@graphcommerce/react-hook-form": "^10.0.0-canary.72",
29
+ "@graphcommerce/typescript-config-pwa": "^10.0.0-canary.72",
30
+ "@lingui/core": "^5",
31
+ "@lingui/macro": "^5",
32
+ "@lingui/react": "^5",
33
+ "@mui/material": "^7.0.0",
34
+ "framer-motion": "^11.0.0",
35
+ "next": "*",
36
+ "react": "^19.2.0",
37
+ "react-dom": "^19.2.0"
38
+ }
39
+ }
@@ -0,0 +1,23 @@
1
+ import type { PaymentMethodContextProviderProps } from '@graphcommerce/magento-cart-payment-method'
2
+ import { PaymentMethodOptionsNoop } from '@graphcommerce/magento-cart-payment-method'
3
+ import type { PluginProps } from '@graphcommerce/next-config'
4
+ import { AfterpayPaymentActionCard } from '../components/AfterpayPaymentActionCard/AfterpayPaymentActionCard'
5
+ import { AfterpayPaymentHandler } from '../components/AfterpayPaymentHandler/AfterpayPaymentHandler'
6
+ import { AfterpayPaymentPlaceOrder } from '../components/AfterpayPaymentPlaceOrder/AfterpayPaymentPlaceOrder'
7
+
8
+ export const component = 'PaymentMethodContextProvider'
9
+ export const exported = '@graphcommerce/magento-cart-payment-method'
10
+
11
+ const afterpay = {
12
+ PaymentOptions: PaymentMethodOptionsNoop,
13
+ PaymentActionCard: AfterpayPaymentActionCard,
14
+ PaymentHandler: AfterpayPaymentHandler,
15
+ PaymentPlaceOrder: AfterpayPaymentPlaceOrder,
16
+ }
17
+
18
+ function AddAfterpayMethods(props: PluginProps<PaymentMethodContextProviderProps>) {
19
+ const { modules, Prev, ...rest } = props
20
+ return <Prev {...rest} modules={{ ...modules, afterpay }} />
21
+ }
22
+
23
+ export const Plugin = AddAfterpayMethods
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "exclude": ["node_modules"],
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "extends": "@graphcommerce/typescript-config-pwa/nextjs.json"
5
+ }