@graphcommerce/magento-payment-klarna 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/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # Magento Payment Klarna
2
+
3
+ Integrates GraphCommerce with the Magento Klarna module.
4
+
5
+ ## Installation
6
+
7
+ 1. Find current version of your `@graphcommerce/magento-cart-payment-method` in
8
+ your package.json.
9
+ 2. `yarn add @graphcommerce/magento-payment-klarna@1.2.3` (replace 1.2.3 with
10
+ the version of the step above)
11
+
12
+ This package uses GraphCommerce plugin systems, so there is no code modification
13
+ required.
@@ -0,0 +1,26 @@
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 Script from 'next/script'
5
+ import klarnaMark from '../../icons/klarna.png'
6
+
7
+ export function KlarnaPaymentActionCard(props: PaymentMethodActionCardProps) {
8
+ const iconSize = useIconSvgSize('large')
9
+
10
+ return (
11
+ <>
12
+ <Script src='https://x.klarnacdn.net/kp/lib/v1/api.js' strategy='lazyOnload' />
13
+ <ActionCard
14
+ {...props}
15
+ image={
16
+ <Image
17
+ layout='fixed'
18
+ sx={{ width: iconSize, height: iconSize, objectFit: 'contain' }}
19
+ unoptimized
20
+ src={klarnaMark}
21
+ />
22
+ }
23
+ />
24
+ </>
25
+ )
26
+ }
@@ -0,0 +1,13 @@
1
+ mutation KlarnaPaymentOptions($cartId: String!) {
2
+ createKlarnaPaymentsSession(input: { cart_id: $cartId }) {
3
+ client_token
4
+ payment_method_categories {
5
+ asset_urls {
6
+ descriptive
7
+ standard
8
+ }
9
+ identifier
10
+ name
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,42 @@
1
+ import { useFormAutoSubmit, useFormCompose } from '@graphcommerce/ecommerce-ui'
2
+ import { useFormGqlMutationCart } from '@graphcommerce/magento-cart'
3
+ import type { PaymentOptionsProps } from '@graphcommerce/magento-cart-payment-method'
4
+ import { KlarnaPaymentOptionsDocument } from './KlarnaPaymentOptions.gql'
5
+
6
+ export function KlarnaPaymentOptions(props: PaymentOptionsProps) {
7
+ const { code, step } = props
8
+
9
+ const form = useFormGqlMutationCart(KlarnaPaymentOptionsDocument, {
10
+ onBeforeSubmit: (variables) => ({
11
+ ...variables,
12
+ }),
13
+ onComplete: async (result) => {
14
+ if (result.errors) return
15
+
16
+ const clientToken = result.data?.createKlarnaPaymentsSession?.client_token
17
+
18
+ try {
19
+ Klarna.Payments.init({ client_token: clientToken })
20
+ Klarna.Payments.load({ container: '#klarna-payments-container' }, {}, (res) => {
21
+ console.info(res)
22
+ })
23
+ } catch (e) {
24
+ console.error(e)
25
+ }
26
+ },
27
+ mode: 'onChange',
28
+ })
29
+
30
+ const submit = form.handleSubmit(() => {})
31
+ useFormAutoSubmit({ form, submit, forceInitialSubmit: true })
32
+
33
+ const key = `PaymentMethodOptions_${code}`
34
+ useFormCompose({ form, step, submit, key })
35
+
36
+ return (
37
+ <form onSubmit={submit} noValidate>
38
+ <input type='hidden' value={code} />
39
+ <div id='klarna-payments-container' />
40
+ </form>
41
+ )
42
+ }
@@ -0,0 +1,12 @@
1
+ mutation KlarnaPaymentPlaceOrder($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,102 @@
1
+ import { useFormCompose } from '@graphcommerce/ecommerce-ui'
2
+ import { useCartQuery, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
3
+ import { BillingPageDocument } from '@graphcommerce/magento-cart-checkout'
4
+ import type { PaymentPlaceOrderProps } from '@graphcommerce/magento-cart-payment-method'
5
+ import { usePaymentMethodContext } from '@graphcommerce/magento-cart-payment-method'
6
+ import { useRouter } from 'next/router'
7
+ import { useKlarnaCartLock } from '../../hooks/useKlarnaCartLock'
8
+ import type { KlarnaResponse } from '../../klarna.d'
9
+ import { KlarnaPaymentPlaceOrderDocument } from './KlarnaPaymentPlaceOrder.gql'
10
+
11
+ export function KlarnaPaymentPlaceOrder(props: PaymentPlaceOrderProps) {
12
+ const { code, step } = props
13
+ const [, lock, unlock] = useKlarnaCartLock()
14
+ const { reload } = useRouter()
15
+ const { onSuccess } = usePaymentMethodContext()
16
+ const cart = useCartQuery(BillingPageDocument)
17
+
18
+ const klarnaPaymentsAuthorize = () =>
19
+ new Promise<KlarnaResponse>((resolve, reject) => {
20
+ try {
21
+ Klarna.Payments.authorize(
22
+ {
23
+ payment_method_category: 'pay_later',
24
+ },
25
+ {
26
+ billing_address: {
27
+ given_name: cart.data?.cart?.billing_address?.firstname.toUpperCase(),
28
+ family_name: cart.data?.cart?.billing_address?.lastname.toUpperCase(),
29
+ email: cart.data?.cart?.email ?? undefined,
30
+ street_address: cart.data?.cart?.billing_address?.street.join(' ').toUpperCase(),
31
+ postal_code: cart.data?.cart?.billing_address?.postcode ?? undefined,
32
+ phone: cart.data?.cart?.billing_address?.telephone ?? undefined,
33
+ region: cart.data?.cart?.billing_address?.region?.code,
34
+ city: cart.data?.cart?.billing_address?.city.toUpperCase(),
35
+ country: cart.data?.cart?.billing_address?.country.code,
36
+ },
37
+ shipping_address: {
38
+ given_name: cart.data?.cart?.shipping_addresses[0]?.firstname.toUpperCase(),
39
+ family_name: cart.data?.cart?.shipping_addresses[0]?.lastname.toUpperCase(),
40
+ email: cart.data?.cart?.email ?? undefined,
41
+ street_address: cart.data?.cart?.shipping_addresses[0]?.street
42
+ .join(' ')
43
+ .toUpperCase(),
44
+ postal_code: cart.data?.cart?.shipping_addresses[0]?.postcode ?? undefined,
45
+ phone: cart.data?.cart?.shipping_addresses[0]?.telephone ?? undefined,
46
+ region: cart.data?.cart?.shipping_addresses[0]?.region?.code,
47
+ city: cart.data?.cart?.shipping_addresses[0]?.city.toUpperCase(),
48
+ country: cart.data?.cart?.shipping_addresses[0]?.country.code,
49
+ },
50
+ customer: { type: 'person' },
51
+ },
52
+ (response: KlarnaResponse) => {
53
+ resolve(response)
54
+ },
55
+ )
56
+ } catch (error) {
57
+ reject(error)
58
+ }
59
+ })
60
+
61
+ const form = useFormGqlMutationCart(KlarnaPaymentPlaceOrderDocument, {
62
+ onBeforeSubmit: async (variabless) => {
63
+ try {
64
+ await lock({ method: code })
65
+ const response = await klarnaPaymentsAuthorize()
66
+ if (response.approved === false) {
67
+ await unlock({})
68
+ reload()
69
+ }
70
+ return {
71
+ cartId: variabless.cartId,
72
+ paymentMethod: {
73
+ code,
74
+ klarna: {
75
+ authorization_token: response.authorization_token ?? '',
76
+ },
77
+ },
78
+ }
79
+ } catch (error) {
80
+ await unlock({})
81
+ throw error
82
+ }
83
+ },
84
+ onComplete: async (result) => {
85
+ if (result.errors || !result.data?.placeOrder?.order) {
86
+ await unlock({})
87
+ return
88
+ }
89
+
90
+ await onSuccess(result.data?.placeOrder?.order.order_number)
91
+ },
92
+ })
93
+
94
+ const submit = form.handleSubmit(() => {})
95
+ useFormCompose({ form, step, submit, key: `KlarnaPaymentPlaceOrder_${code}` })
96
+
97
+ return (
98
+ <form onSubmit={submit} noValidate>
99
+ <input type='hidden' value={code} />
100
+ </form>
101
+ )
102
+ }
@@ -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 KlarnaLockState = CartLockState & {
5
+ clientToken?: string | null
6
+ authorizationToken?: string | 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 useKlarnaCartLock = () => useCartLock<KlarnaLockState>()
Binary file
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {}
package/klarna.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ export type KlarnaResponse = {
2
+ approved?: boolean
3
+ finalize_required?: boolean
4
+ authorization_token: string
5
+ show_form?: boolean
6
+ }
7
+
8
+ declare global {
9
+ namespace Klarna {
10
+ const Payments: {
11
+ init: (options: { client_token: string | null | undefined }) => void
12
+ load: (
13
+ options: { container: string },
14
+ data: Record<string, unknown>,
15
+ callback: (res: unknown) => void,
16
+ ) => void
17
+ authorize: (
18
+ options: { payment_method_category: string },
19
+ data: Record<string, unknown>,
20
+ callback: (response: KlarnaResponse) => void,
21
+ ) => void
22
+ }
23
+ }
24
+ }
package/methods.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { PaymentModule } from '@graphcommerce/magento-cart-payment-method'
2
+ import { KlarnaPaymentActionCard } from './components/KlarnaPaymentActionCard/KlarnaPaymentActionCard'
3
+ import { KlarnaPaymentOptions } from './components/KlarnaPaymentOptions/KlarnaPaymentOptions'
4
+ import { KlarnaPaymentPlaceOrder } from './components/KlarnaPaymentPlaceOrder/KlarnaPaymentPlaceOrder'
5
+
6
+ export const component = 'PaymentMethodContextProvider'
7
+ export const exported = '@graphcommerce/magento-cart-payment-method'
8
+
9
+ const KlarnaModule: PaymentModule = {
10
+ PaymentOptions: KlarnaPaymentOptions,
11
+ PaymentActionCard: KlarnaPaymentActionCard,
12
+ PaymentPlaceOrder: KlarnaPaymentPlaceOrder,
13
+ }
14
+
15
+ export const klarna: Record<string, PaymentModule> = {
16
+ klarna_kco: KlarnaModule,
17
+ klarna_pay_now: KlarnaModule,
18
+ klarna_pay_later: KlarnaModule,
19
+ klarna_pay_over_time: KlarnaModule,
20
+ }
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,40 @@
1
+ {
2
+ "name": "@graphcommerce/magento-payment-klarna",
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/AddKlarnaMethods": "./plugins/AddKlarnaMethods.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-checkout": "^10.0.0-canary.72",
25
+ "@graphcommerce/magento-cart-payment-method": "^10.0.0-canary.72",
26
+ "@graphcommerce/magento-store": "^10.0.0-canary.72",
27
+ "@graphcommerce/next-ui": "^10.0.0-canary.72",
28
+ "@graphcommerce/prettier-config-pwa": "^10.0.0-canary.72",
29
+ "@graphcommerce/react-hook-form": "^10.0.0-canary.72",
30
+ "@graphcommerce/typescript-config-pwa": "^10.0.0-canary.72",
31
+ "@lingui/core": "^5",
32
+ "@lingui/macro": "^5",
33
+ "@lingui/react": "^5",
34
+ "@mui/material": "^7.0.0",
35
+ "framer-motion": "^11.0.0",
36
+ "next": "*",
37
+ "react": "^19.2.0",
38
+ "react-dom": "^19.2.0"
39
+ }
40
+ }
@@ -0,0 +1,13 @@
1
+ import type { PaymentMethodContextProviderProps } from '@graphcommerce/magento-cart-payment-method'
2
+ import type { PluginProps } from '@graphcommerce/next-config'
3
+ import { klarna } from '../methods'
4
+
5
+ export const component = 'PaymentMethodContextProvider'
6
+ export const exported = '@graphcommerce/magento-cart-payment-method'
7
+
8
+ function AddKlarnaMethods(props: PluginProps<PaymentMethodContextProviderProps>) {
9
+ const { modules, Prev, ...rest } = props
10
+ return <Prev {...rest} modules={{ ...modules, ...klarna }} />
11
+ }
12
+
13
+ export const Plugin = AddKlarnaMethods
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
+ }