@automattic/newspack-blocks 2.6.2 → 3.0.0-alpha.1

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.
Files changed (99) hide show
  1. package/.cache/babel/135eb7c6e583be53418b26a29fcc4d81.json.gz +0 -0
  2. package/.cache/babel/2bec24377bb9890c2268bcd4c8f3953c.json.gz +0 -0
  3. package/.cache/babel/9ba57ee86df44178ceb255eaf0e770e3.json.gz +0 -0
  4. package/.cache/babel/a804bf1963e56137e59e37a567cb5e2e.json.gz +0 -0
  5. package/.cache/babel/b94e6dc0852876a37bd23ec88c5b2583.json.gz +0 -0
  6. package/.cache/babel/c04d2af94bb0f10f408a15534301cc86.json.gz +0 -0
  7. package/.cache/babel/c8d4b9ae4be3002e8507d71f1136ebc6.json.gz +0 -0
  8. package/.cache/babel/d21f5515648ce2a2349b0ee5cc787fce.json.gz +0 -0
  9. package/.cache/babel/d3eee0c40fc44bc734dee21a645a4f7d.json.gz +0 -0
  10. package/.cache/babel/d661309b03e38954105e706a32ef09f6.json.gz +0 -0
  11. package/.cache/babel/e2dd36051554e75a2bf087b85c11e43d.json.gz +0 -0
  12. package/.hooks/pre-push +2 -2
  13. package/CHANGELOG.md +21 -0
  14. package/composer.lock +38 -36
  15. package/dist/donate/view.asset.php +1 -1
  16. package/dist/donate/view.css +1 -1
  17. package/dist/donate/view.rtl.css +1 -1
  18. package/dist/editor.asset.php +1 -1
  19. package/dist/editor.css +1 -1
  20. package/dist/editor.js +11 -11
  21. package/dist/editor.rtl.css +1 -1
  22. package/dist/frequencyBased.asset.php +1 -1
  23. package/dist/frequencyBased.css +1 -1
  24. package/dist/frequencyBased.rtl.css +1 -1
  25. package/dist/modalCheckout.asset.php +1 -1
  26. package/dist/modalCheckout.css +1 -1
  27. package/dist/modalCheckout.rtl.css +1 -1
  28. package/dist/tiersBased.asset.php +1 -1
  29. package/dist/tiersBased.css +1 -1
  30. package/dist/tiersBased.js +1 -1
  31. package/dist/tiersBased.rtl.css +1 -1
  32. package/includes/class-modal-checkout.php +11 -14
  33. package/includes/class-newspack-blocks.php +87 -43
  34. package/languages/newspack-blocks-de_DE.po +0 -40
  35. package/languages/newspack-blocks-es_ES.po +0 -40
  36. package/languages/newspack-blocks-fr_BE.po +0 -40
  37. package/languages/newspack-blocks-pt_PT.po +0 -40
  38. package/languages/newspack-blocks.pot +0 -38
  39. package/newspack-blocks.php +2 -14
  40. package/package.json +7 -8
  41. package/src/blocks/checkout-button/edit.js +5 -1
  42. package/src/blocks/donate/block.json +0 -12
  43. package/src/blocks/donate/edit/FrequencyBasedLayout.tsx +61 -106
  44. package/src/blocks/donate/edit/TierBasedLayout.tsx +7 -26
  45. package/src/blocks/donate/edit/components/index.tsx +0 -1
  46. package/src/blocks/donate/edit/index.tsx +157 -152
  47. package/src/blocks/donate/frequency-based/style.scss +5 -0
  48. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-base.php +33 -147
  49. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-frequency-based.php +21 -10
  50. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-tiers-based.php +3 -50
  51. package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer.php +1 -14
  52. package/src/blocks/donate/styles/editor.scss +6 -28
  53. package/src/blocks/donate/styles/style-variations.scss +17 -8
  54. package/src/blocks/donate/styles/view.scss +9 -0
  55. package/src/blocks/donate/tiers-based/style.scss +0 -11
  56. package/src/blocks/donate/tiers-based/utils.test.js +38 -0
  57. package/src/blocks/donate/tiers-based/utils.ts +1 -2
  58. package/src/blocks/donate/tiers-based/view.ts +0 -33
  59. package/src/blocks/donate/types.ts +0 -16
  60. package/src/blocks/donate/utils.ts +31 -0
  61. package/src/blocks/homepage-articles/block.json +18 -0
  62. package/src/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php +1 -1
  63. package/src/blocks/homepage-articles/edit.js +3 -0
  64. package/src/blocks/homepage-articles/utils.ts +4 -0
  65. package/src/blocks/homepage-articles/view.php +4 -4
  66. package/src/components/query-controls.js +41 -8
  67. package/src/modal-checkout/checkout.scss +4 -5
  68. package/src/types/index.d.ts +4 -3
  69. package/vendor/autoload.php +1 -1
  70. package/vendor/composer/autoload_real.php +4 -4
  71. package/vendor/composer/autoload_static.php +2 -2
  72. package/vendor/composer/installed.php +2 -2
  73. package/webpack.config.js +0 -1
  74. package/.cache/babel/18dda1142078f066419138e7284f03bf.json.gz +0 -0
  75. package/.cache/babel/1f43960564787ebde7c6d44957cddf0e.json.gz +0 -0
  76. package/.cache/babel/225618337c609eed2be110274ff82be1.json.gz +0 -0
  77. package/.cache/babel/29d960d2fc51492a4bea1f4f165810fb.json.gz +0 -0
  78. package/.cache/babel/2f22325668b5763f8f2c9557833af36f.json.gz +0 -0
  79. package/.cache/babel/39bcc541624feefe54d1493493ae1ce8.json.gz +0 -0
  80. package/.cache/babel/4d450b37d365154f05b17cbf6a009255.json.gz +0 -0
  81. package/.cache/babel/87e2dc4a961b25b0de8d1a8ac88eea13.json.gz +0 -0
  82. package/.cache/babel/91884d41523f3790da70ea305ee187f2.json.gz +0 -0
  83. package/.cache/babel/b1ac90699e641ff99e1449b5d7b686e5.json.gz +0 -0
  84. package/.cache/babel/c5a441fdf7d90d45d2cbeb89967c61fe.json.gz +0 -0
  85. package/.cache/babel/c7cfb8590e887722a3e715c72ee99bac.json.gz +0 -0
  86. package/.cache/babel/e1d8932bb19afa36f476f107dbc6ca39.json.gz +0 -0
  87. package/.cache/babel/f60f8c23ec2b4448cb2815d79207d8c0.json.gz +0 -0
  88. package/dist/donateStreamlined.asset.php +0 -1
  89. package/dist/donateStreamlined.css +0 -1
  90. package/dist/donateStreamlined.js +0 -1
  91. package/dist/donateStreamlined.rtl.css +0 -1
  92. package/src/blocks/donate/class-wp-rest-newspack-donate-controller.php +0 -206
  93. package/src/blocks/donate/edit/components/AdditionalFields.tsx +0 -282
  94. package/src/blocks/donate/streamlined/index.test.js +0 -132
  95. package/src/blocks/donate/streamlined/index.ts +0 -356
  96. package/src/blocks/donate/streamlined/style.scss +0 -306
  97. package/src/blocks/donate/streamlined/utils.test.js +0 -18
  98. package/src/blocks/donate/streamlined/utils.ts +0 -217
  99. package/src/blocks/donate/tiers-based/view.test.js +0 -209
@@ -1,282 +0,0 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { __ } from '@wordpress/i18n';
5
- import { TextControl, ToggleControl, Button, ButtonGroup, MenuItem } from '@wordpress/components';
6
- import { moreVertical, chevronUp, chevronDown } from '@wordpress/icons';
7
- import { useState } from '@wordpress/element';
8
- import { ESCAPE } from '@wordpress/keycodes';
9
-
10
- /**
11
- * External dependencies
12
- */
13
- import { omit } from 'lodash';
14
- import classnames from 'classnames';
15
-
16
- /**
17
- * Internal dependencies
18
- */
19
- import type { AdditionalField, EditProps } from '../../types';
20
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
21
- // @ts-ignore – these *are* exported by newspack-components.
22
- import { Modal, Popover } from 'newspack-components';
23
-
24
- const getUniqID = () => Math.random().toString( 36 ).substring( 2, 7 );
25
- const BASE_CSS_CLASSNAME = 'newspack-blocks-additional-fields-editor';
26
-
27
- type EditableKey = keyof Omit< AdditionalField, 'type' >;
28
- const FIELD_PROPS = [
29
- [ 'label', __( 'Label', 'newspack-blocks' ) ],
30
- [
31
- 'name',
32
- __( 'Name', 'newspack-blocks' ),
33
- __(
34
- 'Name of the field which will be sent to the payment procesor and other third parties. Field names must be unique.',
35
- 'newspack-blocks'
36
- ),
37
- ],
38
- ] as [ EditableKey, string, string ][];
39
-
40
- const FieldOptions = ( { onEdit, onRemove }: { onEdit: () => void; onRemove: () => void } ) => {
41
- const [ isVisible, setIsVisible ] = useState( false );
42
- const toggleVisible = () => setIsVisible( ! isVisible );
43
- return (
44
- <div>
45
- <Button
46
- onClick={ toggleVisible }
47
- icon={ moreVertical }
48
- label={ __( 'Options', 'newspack-blocks' ) }
49
- />
50
- { isVisible && (
51
- <Popover
52
- position="bottom left"
53
- onFocusOutside={ toggleVisible }
54
- onKeyDown={ ( event: KeyboardEvent ) => ESCAPE === event.keyCode && toggleVisible }
55
- className={ `${ BASE_CSS_CLASSNAME }__options-popover` }
56
- >
57
- <MenuItem onClick={ onEdit } isLink>
58
- { __( 'Edit', 'newspack-blocks' ) }
59
- </MenuItem>
60
- <MenuItem
61
- isDestructive
62
- onClick={ () => {
63
- onRemove();
64
- toggleVisible();
65
- } }
66
- isLink
67
- >
68
- { __( 'Remove', 'newspack-blocks' ) }
69
- </MenuItem>
70
- </Popover>
71
- ) }
72
- </div>
73
- );
74
- };
75
-
76
- const FieldEditor = ( {
77
- attributes,
78
- setAttributes,
79
- field,
80
- closeEditor,
81
- updateField,
82
- }: Pick< EditProps, 'attributes' | 'setAttributes' > & {
83
- field: AdditionalField;
84
- closeEditor: () => void;
85
- updateField: ( key: EditableKey ) => ( value: string | boolean | number ) => void;
86
- } ) => {
87
- const onSave = () => {
88
- const fieldToSave = omit( field, [ 'isNew', 'fieldIndex' ] );
89
- setAttributes( {
90
- additionalFields: field.isNew
91
- ? [ ...attributes.additionalFields, fieldToSave ]
92
- : attributes.additionalFields.map( ( _field, i ) =>
93
- field.fieldIndex === i ? fieldToSave : _field
94
- ),
95
- } );
96
- closeEditor();
97
- };
98
- const onRemove = () => {
99
- setAttributes( {
100
- additionalFields: attributes.additionalFields.filter( ( { name } ) => name !== field.name ),
101
- } );
102
- closeEditor();
103
- };
104
- const getValidationMessage = ( key: EditableKey ) => {
105
- switch ( key ) {
106
- case 'name':
107
- const isValid =
108
- attributes.additionalFields.filter(
109
- ( { name }, i ) => i !== field.fieldIndex && name === field.name
110
- ).length === 0;
111
- return ! isValid ? __( 'Name already exists.', 'newspack-blocks' ) : '';
112
- }
113
- };
114
- return (
115
- <>
116
- { FIELD_PROPS.map( ( [ key, label, help ] ) => {
117
- const validationMessage = getValidationMessage( key );
118
- return (
119
- <div key={ key }>
120
- <TextControl
121
- label={ label }
122
- placeholder={ label }
123
- value={ field[ key ] }
124
- onChange={ updateField( key ) }
125
- className={ classnames( {
126
- [ `${ BASE_CSS_CLASSNAME }__field-edited--name` ]: key === 'name',
127
- [ `${ BASE_CSS_CLASSNAME }__field-edited--invalid` ]: validationMessage,
128
- } ) }
129
- />
130
- { validationMessage && (
131
- <div className={ `${ BASE_CSS_CLASSNAME }__field-edited__validation-message` }>
132
- { validationMessage }
133
- </div>
134
- ) }
135
- { help && (
136
- <div className={ `${ BASE_CSS_CLASSNAME }__field-edited__help` }>{ help }</div>
137
- ) }
138
- </div>
139
- );
140
- } ) }
141
- <ToggleControl
142
- label={ __( 'Required', 'newspack-blocks' ) }
143
- checked={ field.isRequired }
144
- onChange={ updateField( 'isRequired' ) }
145
- />
146
- <div className={ `${ BASE_CSS_CLASSNAME }__field-edited__width` }>
147
- <div>{ __( 'Field width:', 'newspack-blocks' ) }</div>
148
- <ButtonGroup>
149
- { [ 100, 66.66, 50, 33.33 ].map( width => (
150
- <Button
151
- key={ width }
152
- onClick={ () => updateField( 'width' )( width ) }
153
- isPrimary={ field.width === width }
154
- >
155
- { Math.round( width ) }%
156
- </Button>
157
- ) ) }
158
- </ButtonGroup>
159
- </div>
160
- <div className={ `${ BASE_CSS_CLASSNAME }__edit-buttons` }>
161
- <Button isLink onClick={ closeEditor }>
162
- { __( 'Cancel', 'newspack-blocks' ) }
163
- </Button>
164
- { ! field.isNew && (
165
- <Button variant="secondary" isDestructive onClick={ onRemove }>
166
- { __( 'Remove', 'newspack-blocks' ) }
167
- </Button>
168
- ) }
169
- <Button isPrimary onClick={ onSave }>
170
- { field.isNew ? __( 'Save', 'newspack-blocks' ) : __( 'Update', 'newspack-blocks' ) }
171
- </Button>
172
- </div>
173
- </>
174
- );
175
- };
176
-
177
- const AdditionalFields = ( {
178
- attributes,
179
- setAttributes,
180
- }: Pick< EditProps, 'attributes' | 'setAttributes' > ) => {
181
- const [ editedField, setEditedField ] = useState< AdditionalField | null >( null );
182
- const moveField = ( fieldIndex: number, targetIndex: number ) => () => {
183
- const withoutMovedField = attributes.additionalFields.filter( ( _, i ) => i !== fieldIndex );
184
- setAttributes( {
185
- additionalFields: [
186
- ...withoutMovedField.slice( 0, targetIndex ),
187
- attributes.additionalFields[ fieldIndex ],
188
- ...withoutMovedField.slice( targetIndex ),
189
- ],
190
- } );
191
- };
192
- return (
193
- <>
194
- <p>
195
- { __(
196
- 'Collect additional data from donors by defining custom form fields.',
197
- 'newspack-blocks'
198
- ) }
199
- </p>
200
- <div className={ BASE_CSS_CLASSNAME }>
201
- { attributes.additionalFields.map( ( field, i ) => {
202
- const onEdit = () => setEditedField( { ...field, fieldIndex: i } );
203
- return (
204
- <div key={ i } className={ `${ BASE_CSS_CLASSNAME }__field` }>
205
- <div className={ `${ BASE_CSS_CLASSNAME }__field__left-section` }>
206
- <div>
207
- <Button
208
- onClick={ moveField( i, i - 1 ) }
209
- icon={ chevronUp }
210
- label={ __( 'Move up', 'newspack-blocks' ) }
211
- disabled={ i === 0 }
212
- />
213
- <Button
214
- onClick={ moveField( i, i + 1 ) }
215
- icon={ chevronDown }
216
- label={ __( 'Move down', 'newspack-blocks' ) }
217
- disabled={ i === attributes.additionalFields.length - 1 }
218
- />
219
- </div>
220
- <span>{ field.label }</span>
221
- </div>
222
-
223
- <FieldOptions
224
- onEdit={ onEdit }
225
- onRemove={ () =>
226
- setAttributes( {
227
- additionalFields: attributes.additionalFields.filter(
228
- ( value, index ) => index !== i
229
- ),
230
- } )
231
- }
232
- />
233
- </div>
234
- );
235
- } ) }
236
- <Button
237
- variant="secondary"
238
- onClick={ () => {
239
- const newField: AdditionalField = {
240
- type: 'text',
241
- name: `field-${ getUniqID() }`,
242
- label: `Field ${ attributes.additionalFields.length }`,
243
- isRequired: false,
244
- width: 100,
245
- isNew: true,
246
- };
247
- setEditedField( newField );
248
- } }
249
- >
250
- { __( 'Add data field', 'newspack-blocks' ) }
251
- </Button>
252
- </div>
253
-
254
- { editedField && (
255
- <Modal
256
- className={ `${ BASE_CSS_CLASSNAME }__modal` }
257
- title={
258
- editedField.isNew
259
- ? __( 'Add data field', 'newspack-blocks' )
260
- : __( 'Edit data field', 'newspack-blocks' )
261
- }
262
- onRequestClose={ () => setEditedField( null ) }
263
- >
264
- <FieldEditor
265
- field={ editedField }
266
- setAttributes={ setAttributes }
267
- attributes={ attributes }
268
- closeEditor={ () => setEditedField( null ) }
269
- updateField={ ( key: EditableKey ) => ( value: string | boolean | number ) => {
270
- setEditedField( {
271
- ...editedField,
272
- [ key ]: value,
273
- } );
274
- } }
275
- />
276
- </Modal>
277
- ) }
278
- </>
279
- );
280
- };
281
-
282
- export default AdditionalFields;
@@ -1,132 +0,0 @@
1
- import * as testingLibrary from '@testing-library/dom';
2
- import userEvent from '@testing-library/user-event';
3
- import fetchMock from 'fetch-mock-jest';
4
- import { encode } from 'html-entities';
5
-
6
- import { processStreamlinedElements } from '.';
7
-
8
- const MONTHLY_AMOUNT = 7;
9
-
10
- const createDOM = settings => {
11
- const parentElement = document.createElement( 'div' );
12
- parentElement.innerHTML = `
13
- <style>.stripe-payment--hidden {display:none;}</style>
14
- <form data-streamlined-config="${ encode( JSON.stringify( settings ) ) }">
15
- <div class='frequencies'>
16
- <div class='frequency'>
17
- <input type="radio" value="once" id="once" name="donation_frequency">
18
- <label for="once">Once</label>
19
- <input type="number" name="donation_value_once" value="${ MONTHLY_AMOUNT * 12 }" />
20
- </div>
21
- <div class='frequency'>
22
- <input type="radio" value="month" id="month" name="donation_frequency" checked>
23
- <label for="month">Monthly</label>
24
- <input type="number" name="donation_value_month" value="${ MONTHLY_AMOUNT }" />
25
- </div>
26
- </div>
27
- <div class="stripe-payment">
28
- <div class="stripe-payment__inputs stripe-payment--hidden">
29
- <input required="" placeholder="Email" type="email" name="email" value="">
30
- <input required="" placeholder="Full Name" type="text" name="full_name" value="">
31
- </div>
32
- <label>
33
- <input type="checkbox" name="agree_to_pay_fees" checked value="true">Agree to pay fees?
34
- <span id="stripe-fees-amount">($0)</span>
35
- </label>
36
- <div class="stripe-payment__messages"></div>
37
- <button type="submit">Donate</button>
38
- </div>
39
- <input name="cid" type="hidden" value="cid-123" />
40
- </form>
41
- `;
42
- document.body.appendChild( parentElement );
43
- return document.body;
44
- };
45
-
46
- fetchMock.post(
47
- '/wp-json/newspack-blocks/v1/donate',
48
- { status: 'success', client_secret: 'sec_123' },
49
- // A slight delay, necessitated by the async behavior of @testing-library/user-event.
50
- // See https://github.com/testing-library/user-event/pull/952
51
- { delay: 100 }
52
- );
53
-
54
- const frequencies = { once: 'Once', month: 'Monthly', year: 'Annually' };
55
- const feeMultiplier = '2.9';
56
- const feeStatic = '0.3';
57
- const settings = [ 'USD', '$', 'Testing Site', false, 'US', frequencies, feeMultiplier, feeStatic ];
58
-
59
- describe( 'Streamlined Donate block processing', () => {
60
- const container = createDOM( settings );
61
- processStreamlinedElements( container );
62
-
63
- const button = testingLibrary.getByText( container, 'Donate' );
64
- const emailInput = testingLibrary.getByPlaceholderText( container, 'Email' );
65
- const nameInput = testingLibrary.getByPlaceholderText( container, 'Full Name' );
66
-
67
- it( 'additional inputs are initially hidden and displayed after user clicks the button', async () => {
68
- expect( emailInput ).not.toBeVisible();
69
- await userEvent.click( button );
70
- expect( emailInput ).toBeVisible();
71
- } );
72
-
73
- it( 'form submission with invalid values triggers validation errors', async () => {
74
- await userEvent.click( button );
75
- expect(
76
- testingLibrary.getByText( container, 'Email address is invalid.' )
77
- ).toBeInTheDocument();
78
- expect(
79
- testingLibrary.getByText( container, 'Full name should be provided.' )
80
- ).toBeInTheDocument();
81
-
82
- await userEvent.type( emailInput, 'foo@bar.com' );
83
- await userEvent.click( button );
84
- expect(
85
- testingLibrary.queryByText( container, 'Email address is invalid.' )
86
- ).not.toBeInTheDocument();
87
- } );
88
-
89
- it( 'the fee amount is updated', () => {
90
- expect( testingLibrary.getByText( container, '($0.52 monthly)' ) ).toBeInTheDocument();
91
- } );
92
-
93
- it( 'form can be submitted after validation passes', async () => {
94
- await userEvent.type( nameInput, 'Bax' );
95
- await userEvent.click( button );
96
- expect(
97
- testingLibrary.queryByText( container, 'Full name should be provided.' )
98
- ).not.toBeInTheDocument();
99
- expect( testingLibrary.getByText( container, 'Processing payment…' ) ).toBeInTheDocument();
100
- } );
101
-
102
- it( 'final success message is displayed', async () => {
103
- await testingLibrary.waitFor( () => {
104
- expect(
105
- testingLibrary.getByText(
106
- container,
107
- 'Your payment has been processed. Thank you for your contribution! You will receive a confirmation email at foo@bar.com.'
108
- )
109
- ).toBeInTheDocument();
110
- } );
111
- } );
112
-
113
- it( 'correct payload was sent to the API', () => {
114
- expect( fetchMock ).toHaveLastFetched(
115
- '/wp-json/newspack-blocks/v1/donate',
116
- {
117
- body: {
118
- stripe_source_id: 'src_123',
119
- stripe_tokenization_method: 'card',
120
- amount: 7.52,
121
- email: 'foo@bar.com',
122
- full_name: 'Bax',
123
- frequency: 'month',
124
- newsletter_opt_in: false,
125
- clientId: 'cid-123',
126
- additional_fields: [],
127
- },
128
- },
129
- 'post'
130
- );
131
- } );
132
- } );