@magento/venia-sample-payments-cashondelivery 0.0.2-alpha9

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,10 @@
1
+ # venia-sample-payments-cashondelivery
2
+
3
+ This package provides the `Cash On Delivery` payment method for Venia.
4
+
5
+ ## Installation
6
+
7
+ To install this extension, add it as a `devDependency` to your app.
8
+ project:
9
+
10
+ `yarn add -D @magento/venia-sample-payments-cashondelivery`
package/intercept.js ADDED
@@ -0,0 +1,41 @@
1
+ module.exports = targets => {
2
+ const { specialFeatures } = targets.of('@magento/pwa-buildpack');
3
+ specialFeatures.tap(flags => {
4
+ /**
5
+ * Wee need to activate esModules, cssModules and GQL Queries to allow build pack to load our extension
6
+ * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
7
+ */
8
+ flags[targets.name] = {
9
+ esModules: true,
10
+ cssModules: true,
11
+ graphqlQueries: true
12
+ };
13
+ });
14
+
15
+ const {
16
+ checkoutPagePaymentTypes,
17
+ editablePaymentTypes,
18
+ summaryPagePaymentTypes
19
+ } = targets.of('@magento/venia-ui');
20
+ checkoutPagePaymentTypes.tap(payments =>
21
+ payments.add({
22
+ paymentCode: 'cashondelivery',
23
+ importPath:
24
+ '@magento/venia-sample-payments-cashondelivery/src/components/cashondelivery.js'
25
+ })
26
+ );
27
+ editablePaymentTypes.tap(editablePaymentTypes => {
28
+ editablePaymentTypes.add({
29
+ paymentCode: 'cashondelivery',
30
+ importPath:
31
+ '@magento/venia-sample-payments-cashondelivery/src/components/editcod.js'
32
+ });
33
+ });
34
+ summaryPagePaymentTypes.tap(paymentSummaries =>
35
+ paymentSummaries.add({
36
+ paymentCode: 'cashondelivery',
37
+ importPath:
38
+ '@magento/venia-sample-payments-cashondelivery/src/components/summarycod.js'
39
+ })
40
+ );
41
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@magento/venia-sample-payments-cashondelivery",
3
+ "version": "0.0.2-alpha9",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Provides demo Cash On Delivery Payment Method for PWA Studio.",
8
+ "main": "./intercept.js",
9
+ "scripts": {
10
+ "clean": " "
11
+ },
12
+ "repository": "github:magento/pwa-studio",
13
+ "license": "(OSL-3.0 OR AFL-3.0)",
14
+ "peerDependencies": {
15
+ "@magento/peregrine": "15.5.1-alpha9",
16
+ "@magento/pwa-buildpack": "~11.5.4",
17
+ "@magento/venia-ui": "11.7.0-alpha9",
18
+ "react": "~17.0.1",
19
+ "react-intl": "~5.20.0",
20
+ "react-router-dom": "~5.2.0"
21
+ },
22
+ "pwa-studio": {
23
+ "targets": {
24
+ "intercept": "./intercept"
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,12 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Should render CashOnDelivery component correctly`] = `
4
+ <div
5
+ className="cod_root"
6
+ >
7
+ <mock-BillingAddress
8
+ onBillingAddressChangedError={[MockFunction]}
9
+ onBillingAddressChangedSuccess={[MockFunction]}
10
+ />
11
+ </div>
12
+ `;
@@ -0,0 +1,15 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders correctly 1`] = `
4
+ <div
5
+ className="root"
6
+ >
7
+ <mock-CashOnDelivery
8
+ onPaymentError={[MockFunction onPaymentError]}
9
+ onPaymentReady={[MockFunction onPaymentReady]}
10
+ onPaymentSuccess={[MockFunction onPaymentSuccess]}
11
+ resetShouldSubmit={[MockFunction resetShouldSubmit]}
12
+ shouldSubmit={false}
13
+ />
14
+ </div>
15
+ `;
@@ -0,0 +1,67 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders correctly 1`] = `
4
+ <div
5
+ className="root"
6
+ >
7
+ <div
8
+ className="heading_container"
9
+ >
10
+ <h5
11
+ className="heading"
12
+ >
13
+ <div
14
+ componentName="Formatted Message Component"
15
+ defaultMessage="Payment Information"
16
+ id="checkoutPage.paymentInformation"
17
+ />
18
+ </h5>
19
+ <mock-LinkButton
20
+ className="edit_button"
21
+ onClick={[MockFunction onEdit]}
22
+ type="button"
23
+ >
24
+ <mock-Icon
25
+ classes={
26
+ Object {
27
+ "icon": "edit_icon",
28
+ }
29
+ }
30
+ size={16}
31
+ src={
32
+ Object {
33
+ "$$typeof": Symbol(react.forward_ref),
34
+ "propTypes": Object {
35
+ "color": [Function],
36
+ "size": [Function],
37
+ },
38
+ "render": [Function],
39
+ }
40
+ }
41
+ />
42
+ <span
43
+ className="edit_text"
44
+ >
45
+ <div
46
+ componentName="Formatted Message Component"
47
+ defaultMessage="Edit"
48
+ id="global.editButton"
49
+ />
50
+ </span>
51
+ </mock-LinkButton>
52
+ </div>
53
+ <div
54
+ className="cod_details_container"
55
+ >
56
+ <span
57
+ className="payment_type"
58
+ >
59
+ <div
60
+ componentName="Formatted Message Component"
61
+ defaultMessage="Cash On Delivery"
62
+ id="CashOnDelivery.paymentType"
63
+ />
64
+ </span>
65
+ </div>
66
+ </div>
67
+ `;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { createTestInstance } from '@magento/peregrine';
3
+ import { useCashondelivery } from '../../talons/useCashondelivery';
4
+
5
+ import CashOnDelivery from '../cashondelivery';
6
+
7
+ jest.mock('@magento/venia-ui/lib/classify');
8
+ jest.mock('../../talons/useCashondelivery', () => {
9
+ return {
10
+ useCashondelivery: jest.fn().mockReturnValue({
11
+ onBillingAddressChangedError: jest.fn(),
12
+ onBillingAddressChangedSuccess: jest.fn()
13
+ })
14
+ };
15
+ });
16
+
17
+ jest.mock(
18
+ '@magento/venia-ui/lib/components/CheckoutPage/BillingAddress',
19
+ () => props => <mock-BillingAddress {...props} />
20
+ );
21
+
22
+ const useCashondeliveryReturnValue = {
23
+ onBillingAddressChangedError: jest.fn(),
24
+ onBillingAddressChangedSuccess: jest.fn()
25
+ };
26
+
27
+ test('Should render CashOnDelivery component correctly', () => {
28
+ useCashondelivery.mockReturnValueOnce({
29
+ ...useCashondeliveryReturnValue
30
+ });
31
+
32
+ const tree = createTestInstance(<CashOnDelivery />);
33
+
34
+ expect(tree.toJSON()).toMatchSnapshot();
35
+ });
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { createTestInstance } from '@magento/peregrine';
3
+
4
+ import EditCod from '../editcod';
5
+
6
+ jest.mock('@magento/venia-ui/lib/classify');
7
+ jest.mock('../cashondelivery', () => props => (
8
+ <mock-CashOnDelivery {...props} />
9
+ ));
10
+
11
+ const mocks = {
12
+ onPaymentReady: jest.fn().mockName('onPaymentReady'),
13
+ onPaymentSuccess: jest.fn().mockName('onPaymentSuccess'),
14
+ onPaymentError: jest.fn().mockName('onPaymentError'),
15
+ resetShouldSubmit: jest.fn().mockName('resetShouldSubmit')
16
+ };
17
+
18
+ test('renders correctly', () => {
19
+ // Arrange.
20
+ const props = {
21
+ ...mocks,
22
+ shouldSubmit: false
23
+ };
24
+
25
+ // Act.
26
+ const tree = createTestInstance(<EditCod {...props} />);
27
+
28
+ // Assert.
29
+ expect(tree.toJSON()).toMatchSnapshot();
30
+ });
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { createTestInstance } from '@magento/peregrine';
3
+
4
+ import SummaryCod from '../summarycod';
5
+
6
+ jest.mock('@magento/venia-ui/lib/classify');
7
+ jest.mock('react-intl', () => ({
8
+ FormattedMessage: props => (
9
+ <div componentName="Formatted Message Component" {...props} />
10
+ )
11
+ }));
12
+ jest.mock('@magento/venia-ui/lib/components/LinkButton', () => props => (
13
+ <mock-LinkButton {...props} />
14
+ ));
15
+ jest.mock('@magento/venia-ui/lib/components/Icon', () => props => (
16
+ <mock-Icon {...props} />
17
+ ));
18
+
19
+ test('renders correctly', () => {
20
+ // Arrange.
21
+ const props = {
22
+ onEdit: jest.fn().mockName('onEdit')
23
+ };
24
+
25
+ // Act.
26
+ const tree = createTestInstance(<SummaryCod {...props} />);
27
+
28
+ // Assert.
29
+ expect(tree.toJSON()).toMatchSnapshot();
30
+ });
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { useStyle } from '@magento/venia-ui/lib/classify';
3
+ import { shape, string, bool, func } from 'prop-types';
4
+ import BillingAddress from '@magento/venia-ui/lib/components/CheckoutPage/BillingAddress';
5
+ import { useCashondelivery } from '../talons/useCashondelivery';
6
+ import defaultClasses from './cashondelivery.module.css';
7
+
8
+ /**
9
+ * The CashOnDelivery component renders all information to handle cashondelivery payment.
10
+ *
11
+ * @param {Boolean} props.shouldSubmit boolean value which represents if a payment nonce request has been submitted
12
+ * @param {Function} props.onPaymentSuccess callback to invoke when the a payment nonce has been generated
13
+ * @param {Function} props.onPaymentReady callback to invoke when the component is ready
14
+ * @param {Function} props.onPaymentError callback to invoke when component throws an error
15
+ * @param {Function} props.resetShouldSubmit callback to reset the shouldSubmit flag
16
+ */
17
+ const CashOnDelivery = props => {
18
+ const classes = useStyle(defaultClasses, props.classes);
19
+
20
+ const {
21
+ onBillingAddressChangedError,
22
+ onBillingAddressChangedSuccess
23
+ } = useCashondelivery(props);
24
+
25
+ return (
26
+ <div className={classes.cod_root}>
27
+ <BillingAddress
28
+ resetShouldSubmit={props.resetShouldSubmit}
29
+ shouldSubmit={props.shouldSubmit}
30
+ onBillingAddressChangedError={onBillingAddressChangedError}
31
+ onBillingAddressChangedSuccess={onBillingAddressChangedSuccess}
32
+ />
33
+ </div>
34
+ );
35
+ };
36
+
37
+ CashOnDelivery.propTypes = {
38
+ classes: shape({ root: string }),
39
+ shouldSubmit: bool.isRequired,
40
+ onPaymentSuccess: func,
41
+ onPaymentReady: func,
42
+ onPaymentError: func,
43
+ resetShouldSubmit: func.isRequired
44
+ };
45
+
46
+ export default CashOnDelivery;
@@ -0,0 +1,3 @@
1
+ .cod_root {
2
+ padding-top: 1.125rem;
3
+ }
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ import { shape, string, bool, func } from 'prop-types';
3
+
4
+ import { useStyle } from '@magento/venia-ui/lib/classify';
5
+
6
+ import CashOnDelivery from './cashondelivery';
7
+ import defaultClasses from './cashondelivery.module.css';
8
+
9
+ /**
10
+ * The edit view for the Cod payment method.
11
+ */
12
+ const EditCod = props => {
13
+ const {
14
+ onPaymentReady,
15
+ onPaymentSuccess,
16
+ onPaymentError,
17
+ resetShouldSubmit,
18
+ shouldSubmit
19
+ } = props;
20
+
21
+ const classes = useStyle(defaultClasses, props.classes);
22
+
23
+ return (
24
+ <div className={classes.root}>
25
+ <CashOnDelivery
26
+ onPaymentReady={onPaymentReady}
27
+ onPaymentSuccess={onPaymentSuccess}
28
+ onPaymentError={onPaymentError}
29
+ resetShouldSubmit={resetShouldSubmit}
30
+ shouldSubmit={shouldSubmit}
31
+ />
32
+ </div>
33
+ );
34
+ };
35
+
36
+ export default EditCod;
37
+
38
+ EditCod.propTypes = {
39
+ classes: shape({
40
+ root: string
41
+ }),
42
+ onPaymentReady: func.isRequired,
43
+ onPaymentSuccess: func.isRequired,
44
+ onPaymentError: func.isRequired,
45
+ resetShouldSubmit: func.isRequired,
46
+ shouldSubmit: bool
47
+ };
@@ -0,0 +1,42 @@
1
+ .root {
2
+ display: grid;
3
+ gap: 1.125rem;
4
+ padding: 2rem;
5
+ }
6
+
7
+ .heading_container {
8
+ display: grid;
9
+ grid-auto-flow: column;
10
+ grid-template-columns: 1fr;
11
+ }
12
+
13
+ .heading {
14
+ font-weight: 600;
15
+ }
16
+
17
+ .edit_button {
18
+ color: rgb(var(--venia-brand-color-1-700));
19
+ padding: 1rem;
20
+ margin: -1rem;
21
+ }
22
+
23
+ .edit_icon {
24
+ stroke: rgb(var(--venia-brand-color-1-700));
25
+ }
26
+
27
+ .edit_text {
28
+ }
29
+
30
+ .cod_details_container {
31
+ display: grid;
32
+ gap: 0.5rem;
33
+ }
34
+
35
+ .payment_type {
36
+ }
37
+
38
+ @media screen(-lg) {
39
+ .edit_text {
40
+ display: none;
41
+ }
42
+ }
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { func, shape, string } from 'prop-types';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { Edit2 as EditIcon } from 'react-feather';
5
+ import { useStyle } from '@magento/venia-ui/lib/classify';
6
+ import Icon from '@magento/venia-ui/lib/components/Icon';
7
+ import LinkButton from '@magento/venia-ui/lib/components/LinkButton';
8
+
9
+ import defaultClasses from './summary.module.css';
10
+
11
+ /**
12
+ * The SummaryCod component of the Cash On Delivery payment method extension.
13
+ */
14
+ const SummaryCod = props => {
15
+ const { onEdit } = props;
16
+
17
+ const classes = useStyle(defaultClasses, props.classes);
18
+
19
+ return (
20
+ <div className={classes.root}>
21
+ <div className={classes.heading_container}>
22
+ <h5 className={classes.heading}>
23
+ <FormattedMessage
24
+ id={'checkoutPage.paymentInformation'}
25
+ defaultMessage={'Payment Information'}
26
+ />
27
+ </h5>
28
+ <LinkButton
29
+ className={classes.edit_button}
30
+ onClick={onEdit}
31
+ type="button"
32
+ >
33
+ <Icon
34
+ size={16}
35
+ src={EditIcon}
36
+ classes={{ icon: classes.edit_icon }}
37
+ />
38
+ <span className={classes.edit_text}>
39
+ <FormattedMessage
40
+ id={'global.editButton'}
41
+ defaultMessage={'Edit'}
42
+ />
43
+ </span>
44
+ </LinkButton>
45
+ </div>
46
+ <div className={classes.cod_details_container}>
47
+ <span className={classes.payment_type}>
48
+ <FormattedMessage
49
+ id={'CashOnDelivery.paymentType'}
50
+ defaultMessage={'Cash On Delivery'}
51
+ />
52
+ </span>
53
+ </div>
54
+ </div>
55
+ );
56
+ };
57
+
58
+ export default SummaryCod;
59
+
60
+ SummaryCod.propTypes = {
61
+ classes: shape({
62
+ root: string,
63
+ cod_details_container: string,
64
+ edit_button: string,
65
+ edit_icon: string,
66
+ edit_text: string,
67
+ heading_container: string,
68
+ heading: string,
69
+ payment_type: string
70
+ }),
71
+ onEdit: func
72
+ };
@@ -0,0 +1,24 @@
1
+ import { gql } from '@apollo/client';
2
+
3
+ export const SET_COD_PAYMENT_METHOD_ON_CART = gql`
4
+ mutation setPaymentMethodOnCart($cartId: String!) {
5
+ setPaymentMethodOnCart(
6
+ input: {
7
+ cart_id: $cartId
8
+ payment_method: { code: "cashondelivery" }
9
+ }
10
+ ) {
11
+ cart {
12
+ id
13
+ selected_payment_method {
14
+ code
15
+ title
16
+ }
17
+ }
18
+ }
19
+ }
20
+ `;
21
+
22
+ export default {
23
+ setCodPaymentMethodOnCartMutation: SET_COD_PAYMENT_METHOD_ON_CART
24
+ };
@@ -0,0 +1,80 @@
1
+ import { useCallback, useEffect } from 'react';
2
+ import { useMutation } from '@apollo/client';
3
+ import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
4
+ import { useCartContext } from '@magento/peregrine/lib/context/cart';
5
+
6
+ import DEFAULT_OPERATIONS from './cashondelivery.gql';
7
+
8
+ /**
9
+ * Talon to handle cod payment.
10
+ *
11
+ * @param {Boolean} props.shouldSubmit boolean value which represents if a payment nonce request has been submitted
12
+ * @param {Function} props.onPaymentSuccess callback to invoke when the a payment nonce has been generated
13
+ * @param {Function} props.onPaymentError callback to invoke when component throws an error
14
+ * @param {Function} props.resetShouldSubmit callback to reset the shouldSubmit flag
15
+ * @param {DocumentNode} props.operations.setCodPaymentMethodOnCartMutation mutation to set cashondelivery as payment
16
+ *
17
+ * @returns {
18
+ * onBillingAddressChangedError: Function,
19
+ * onBillingAddressChangedSuccess: Function
20
+ * }
21
+ */
22
+ export const useCashondelivery = props => {
23
+ const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
24
+
25
+ const { setCodPaymentMethodOnCartMutation } = operations;
26
+
27
+ const [{ cartId }] = useCartContext();
28
+
29
+ const { resetShouldSubmit, onPaymentSuccess, onPaymentError } = props;
30
+
31
+ const [
32
+ updatePaymentMethod,
33
+ {
34
+ error: paymentMethodMutationError,
35
+ called: paymentMethodMutationCalled,
36
+ loading: paymentMethodMutationLoading
37
+ }
38
+ ] = useMutation(setCodPaymentMethodOnCartMutation);
39
+
40
+ /**
41
+ * This function will be called if cant not set address.
42
+ */
43
+ const onBillingAddressChangedError = useCallback(() => {
44
+ resetShouldSubmit();
45
+ }, [resetShouldSubmit]);
46
+
47
+ /**
48
+ * This function will be called if address was successfully set.
49
+ */
50
+ const onBillingAddressChangedSuccess = useCallback(() => {
51
+ updatePaymentMethod({
52
+ variables: { cartId }
53
+ });
54
+ }, [updatePaymentMethod, cartId]);
55
+
56
+ useEffect(() => {
57
+ const paymentMethodMutationCompleted =
58
+ paymentMethodMutationCalled && !paymentMethodMutationLoading;
59
+
60
+ if (paymentMethodMutationCompleted && !paymentMethodMutationError) {
61
+ onPaymentSuccess();
62
+ }
63
+
64
+ if (paymentMethodMutationCompleted && paymentMethodMutationError) {
65
+ onPaymentError();
66
+ }
67
+ }, [
68
+ paymentMethodMutationError,
69
+ paymentMethodMutationLoading,
70
+ paymentMethodMutationCalled,
71
+ onPaymentSuccess,
72
+ onPaymentError,
73
+ resetShouldSubmit
74
+ ]);
75
+
76
+ return {
77
+ onBillingAddressChangedError,
78
+ onBillingAddressChangedSuccess
79
+ };
80
+ };