@automattic/newspack-blocks 1.53.0 → 1.54.0

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 (97) hide show
  1. package/.cache/babel/1783de595f21d427355e559781275222.json.gz +0 -0
  2. package/.cache/babel/2a75259638488d555bb07fb4f54ddde6.json.gz +0 -0
  3. package/.cache/babel/{64cb5afd808420a679c0d56e7bdb7949.json.gz → 2dfe70bf8fa9218857f45826e2386a32.json.gz} +0 -0
  4. package/.cache/babel/2ef414e63685642b486b71a962a5cc09.json.gz +0 -0
  5. package/.cache/babel/5a94cdb1154d1770a8b0e8cd3145825b.json.gz +0 -0
  6. package/.cache/babel/678cc0f373236434bf692c16d26ba22f.json.gz +0 -0
  7. package/.cache/babel/71371fcf9db60a3a1e024991cb3b4bf3.json.gz +0 -0
  8. package/.cache/babel/725e695c6992a4d01573b83867255ea9.json.gz +0 -0
  9. package/.cache/babel/94ee8f45c55ecf01005a435ab588333b.json.gz +0 -0
  10. package/.cache/babel/a5759fe1915229088160b7f5eb8a2e75.json.gz +0 -0
  11. package/.cache/babel/{bdebf548c146fe858685d50dd0ebd031.json.gz → be383af4530fd3521ee3db177be1bbf4.json.gz} +0 -0
  12. package/.cache/babel/d298f58c94d221b643c4c009ea0d8002.json.gz +0 -0
  13. package/.cache/babel/dc7e2d653dbbdbd1939aa281435afa5d.json.gz +0 -0
  14. package/.cache/babel/f50f27ba4b367318e30e91dbe003e5c8.json.gz +0 -0
  15. package/CHANGELOG.md +35 -0
  16. package/dist/author-profile/view.asset.php +1 -1
  17. package/dist/author-profile/view.css +1 -1
  18. package/dist/author-profile/view.rtl.css +1 -1
  19. package/dist/carousel/view.asset.php +1 -1
  20. package/dist/carousel/view.css +1 -1
  21. package/dist/carousel/view.js +1 -1
  22. package/dist/carousel/view.rtl.css +1 -1
  23. package/dist/donate/view.asset.php +1 -1
  24. package/dist/donate/view.css +1 -1
  25. package/dist/donate/view.rtl.css +1 -1
  26. package/dist/donateStreamlined.asset.php +1 -1
  27. package/dist/donateStreamlined.js +1 -1
  28. package/dist/editor.asset.php +1 -1
  29. package/dist/editor.css +1 -1
  30. package/dist/editor.js +5 -5
  31. package/dist/editor.rtl.css +1 -1
  32. package/dist/homepage-articles/view.asset.php +1 -1
  33. package/dist/homepage-articles/view.css +1 -1
  34. package/dist/homepage-articles/view.rtl.css +1 -1
  35. package/dist/placeholder_blocks.asset.php +1 -0
  36. package/dist/placeholder_blocks.js +1 -0
  37. package/includes/class-newspack-blocks-api.php +14 -12
  38. package/includes/class-newspack-blocks-patterns.php +3 -2
  39. package/includes/class-newspack-blocks.php +64 -1
  40. package/newspack-blocks.php +3 -2
  41. package/package.json +17 -16
  42. package/src/block-patterns/homepage-posts-14.php +1 -1
  43. package/src/block-patterns/homepage-posts-2.php +1 -1
  44. package/src/block-patterns/homepage-posts-26.php +1 -1
  45. package/src/block-patterns/homepage-posts-31.php +13 -0
  46. package/src/block-patterns/homepage-posts-7.php +1 -1
  47. package/src/block-styles/core/columns/editor.scss +10 -10
  48. package/src/block-styles/core/columns/view.scss +8 -8
  49. package/src/block-styles/core/group/editor.scss +3 -3
  50. package/src/block-styles/core/group/view.scss +3 -3
  51. package/src/blocks/author-list/editor.scss +1 -1
  52. package/src/blocks/author-profile/edit.js +29 -6
  53. package/src/blocks/author-profile/editor.scss +4 -3
  54. package/src/blocks/author-profile/view.scss +9 -9
  55. package/src/blocks/carousel/edit.js +31 -15
  56. package/src/blocks/carousel/editor.scss +1 -1
  57. package/src/blocks/carousel/view.php +94 -87
  58. package/src/blocks/carousel/view.scss +52 -13
  59. package/src/blocks/donate/block.json +49 -0
  60. package/src/blocks/donate/edit.tsx +569 -0
  61. package/src/blocks/donate/editor.scss +68 -8
  62. package/src/blocks/donate/index.js +8 -41
  63. package/src/blocks/donate/streamlined/style.scss +17 -17
  64. package/src/blocks/donate/view.php +226 -174
  65. package/src/blocks/donate/view.scss +97 -114
  66. package/src/blocks/homepage-articles/edit.js +28 -22
  67. package/src/blocks/homepage-articles/editor.scss +5 -5
  68. package/src/blocks/homepage-articles/templates/article.php +78 -73
  69. package/src/blocks/homepage-articles/utils.ts +1 -3
  70. package/src/blocks/homepage-articles/view.scss +68 -40
  71. package/src/blocks/iframe/edit.js +18 -14
  72. package/src/blocks/iframe/editor.scss +3 -3
  73. package/src/blocks/video-playlist/editor.scss +2 -2
  74. package/src/setup/editor.scss +46 -4
  75. package/src/setup/placeholder-blocks.js +83 -0
  76. package/src/shared/sass/_mixins.scss +7 -5
  77. package/src/types/@wordpress/block-editor.d.ts +1 -0
  78. package/src/types/@wordpress/components.d.ts +1 -0
  79. package/src/types/{index.ts → index.d.ts} +5 -1
  80. package/src/types/newspack-components.d.ts +7 -0
  81. package/vendor/autoload.php +1 -1
  82. package/vendor/composer/autoload_real.php +4 -4
  83. package/vendor/composer/autoload_static.php +2 -2
  84. package/vendor/composer/installed.php +2 -2
  85. package/webpack.config.js +4 -0
  86. package/.cache/babel/07169c73863508b392f15022920bd0b6.json.gz +0 -0
  87. package/.cache/babel/10faf7c74a89e9aa4d8b9528a654913e.json.gz +0 -0
  88. package/.cache/babel/3fc03f1e35bc1fde55a903cf25d74d3d.json.gz +0 -0
  89. package/.cache/babel/553094e2be86910f765ad110c8da1ba1.json.gz +0 -0
  90. package/.cache/babel/55dd64fbb5126117016b9edff26ca5ee.json.gz +0 -0
  91. package/.cache/babel/7cbfe1b298fdc2a21add34363b2a6046.json.gz +0 -0
  92. package/.cache/babel/95c79f7af2e88cb1c48e88f304b1a1fd.json.gz +0 -0
  93. package/.cache/babel/ac3be6086bb961d3a94ba6ba7728901c.json.gz +0 -0
  94. package/.cache/babel/c9354785521531ea2b4a9a8c2f526abf.json.gz +0 -0
  95. package/.cache/babel/ca34d0586d4fbcd06c357ff72bda9a19.json.gz +0 -0
  96. package/.cache/babel/edb4dcd474dbafd6ea1655b24469e261.json.gz +0 -0
  97. package/src/blocks/donate/edit.js +0 -587
@@ -0,0 +1,569 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classNames from 'classnames';
5
+ import { hooks } from 'newspack-components';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { __ } from '@wordpress/i18n';
11
+ import apiFetch from '@wordpress/api-fetch';
12
+ import { useState, useEffect, useMemo, useRef, Fragment } from '@wordpress/element';
13
+ import {
14
+ CheckboxControl,
15
+ PanelBody,
16
+ ExternalLink,
17
+ Placeholder,
18
+ Spinner,
19
+ SelectControl,
20
+ ToggleControl,
21
+ TextControl,
22
+ } from '@wordpress/components';
23
+ import { InspectorControls, RichText } from '@wordpress/block-editor';
24
+ import { isEmpty } from 'lodash';
25
+
26
+ type FrequencySlug = 'once' | 'month' | 'year';
27
+
28
+ const FREQUENCIES: { [ Key in FrequencySlug as string ]: string } = {
29
+ once: __( 'One-time', 'newspack-blocks' ),
30
+ month: __( 'Monthly', 'newspack-blocks' ),
31
+ year: __( 'Annually', 'newspack-blocks' ),
32
+ };
33
+ const FREQUENCY_SLUGS: FrequencySlug[] = Object.keys( FREQUENCIES ) as FrequencySlug[];
34
+
35
+ type DonationAmounts = {
36
+ [ Key in FrequencySlug as string ]: [ number, number, number, number ];
37
+ };
38
+
39
+ type OverridableConfiguration = {
40
+ amounts: DonationAmounts;
41
+ tiered: boolean;
42
+ disabledFrequencies: {
43
+ [ Key in FrequencySlug as string ]: boolean;
44
+ };
45
+ };
46
+
47
+ type DonateBlockAttributes = OverridableConfiguration & {
48
+ buttonText: string;
49
+ thanksText: string;
50
+ defaultFrequency: FrequencySlug;
51
+ campaign: string;
52
+ className: string;
53
+ // Manual mode enables block-level overrides of the global Donate settings.
54
+ manual: boolean;
55
+ // Legacy attributes.
56
+ suggestedAmounts?: [ number, number, number ];
57
+ suggestedAmountUntiered?: number;
58
+ };
59
+ type EditProps = {
60
+ attributes: DonateBlockAttributes;
61
+ setAttributes: ( attributes: Partial< DonateBlockAttributes > ) => void;
62
+ className: string;
63
+ };
64
+ type DonationSettings = OverridableConfiguration & {
65
+ currencySymbol: string;
66
+ };
67
+
68
+ type EditState = DonationSettings;
69
+
70
+ const TIER_LABELS = [
71
+ __( 'Low-tier', 'newspack' ),
72
+ __( 'Mid-tier', 'newspack' ),
73
+ __( 'High-tier', 'newspack' ),
74
+ __( 'Other', 'newspack' ),
75
+ ];
76
+
77
+ const getMigratedAmount = (
78
+ frequency: FrequencySlug,
79
+ amounts: [ number, number, number ],
80
+ untieredAmount: number
81
+ ): [ number, number, number, number ] => {
82
+ const multiplier = frequency === 'month' ? 1 : 12;
83
+ return [
84
+ amounts[ 0 ] * multiplier,
85
+ amounts[ 1 ] * multiplier,
86
+ amounts[ 2 ] * multiplier,
87
+ untieredAmount * multiplier,
88
+ ];
89
+ };
90
+
91
+ const Edit = ( { attributes, setAttributes, className }: EditProps ) => {
92
+ const [ isLoading, setIsLoading ] = useState( true );
93
+ const [ error, setError ] = useState( '' );
94
+
95
+ // Unique identifier to prevent collisions with other Donate blocks' labels.
96
+ const uid = useMemo( () => Math.random().toString( 16 ).slice( 2 ), [] );
97
+
98
+ const [ settings, setSettings ] = hooks.useObjectState< EditState >( {
99
+ amounts: {},
100
+ currencySymbol: '$',
101
+ tiered: false,
102
+ disabledFrequencies: {},
103
+ } );
104
+
105
+ useEffect( () => {
106
+ apiFetch< DonationSettings >( {
107
+ path: '/newspack/v1/wizard/newspack-reader-revenue-wizard/donations',
108
+ } )
109
+ .then( ( donationSettings: DonationSettings ) => {
110
+ setSettings( {
111
+ amounts: donationSettings.amounts,
112
+ currencySymbol: donationSettings.currencySymbol,
113
+ tiered: donationSettings.tiered,
114
+ disabledFrequencies: donationSettings.disabledFrequencies,
115
+ } );
116
+
117
+ if ( isEmpty( attributes.disabledFrequencies ) ) {
118
+ setAttributes( { disabledFrequencies: donationSettings.disabledFrequencies } );
119
+ }
120
+
121
+ // Migrate old attributes.
122
+ if (
123
+ isEmpty( attributes.amounts ) &&
124
+ attributes.suggestedAmounts &&
125
+ attributes.suggestedAmounts.length
126
+ ) {
127
+ const untieredAmount =
128
+ attributes.suggestedAmountUntiered || donationSettings.amounts.month[ 3 ];
129
+ setAttributes( {
130
+ suggestedAmounts: undefined,
131
+ suggestedAmountUntiered: undefined,
132
+ amounts: {
133
+ once: getMigratedAmount( 'once', attributes.suggestedAmounts, untieredAmount ),
134
+ month: getMigratedAmount( 'month', attributes.suggestedAmounts, untieredAmount ),
135
+ year: getMigratedAmount( 'year', attributes.suggestedAmounts, untieredAmount ),
136
+ },
137
+ } );
138
+ } else {
139
+ setAttributes( { amounts: { ...donationSettings.amounts, ...attributes.amounts } } );
140
+ }
141
+ } )
142
+ .catch( setError )
143
+ .finally( () => setIsLoading( false ) );
144
+ }, [] );
145
+
146
+ const isRenderingStreamlinedBlock = () =>
147
+ window.newspack_blocks_data?.is_rendering_streamlined_block;
148
+
149
+ const amounts = attributes.manual ? attributes.amounts : settings.amounts;
150
+ const availableFrequencies = FREQUENCY_SLUGS.filter( slug =>
151
+ attributes.manual
152
+ ? ! attributes.disabledFrequencies[ slug ]
153
+ : ! settings.disabledFrequencies[ slug ]
154
+ );
155
+
156
+ const formRef = useRef< HTMLFormElement >( null );
157
+
158
+ // Update selected frequency when available frequencies change.
159
+ useEffect( () => {
160
+ if ( formRef.current ) {
161
+ const formValues = Object.fromEntries( new FormData( formRef.current ) );
162
+ if ( ! formValues.donation_frequency && formRef.current.elements ) {
163
+ const frequencyRadioInput = formRef.current.elements[ 0 ];
164
+ if ( frequencyRadioInput instanceof HTMLInputElement ) {
165
+ frequencyRadioInput.click();
166
+ }
167
+ }
168
+ }
169
+ if ( availableFrequencies.indexOf( attributes.defaultFrequency ) === -1 ) {
170
+ setAttributes( { defaultFrequency: availableFrequencies[ 0 ] } );
171
+ }
172
+ }, [ attributes.disabledFrequencies ] );
173
+
174
+ // Update selected frequency when the default frequency attribute is updated.
175
+ useEffect( () => {
176
+ if ( formRef.current ) {
177
+ const defaultFrequencyInput = formRef.current.querySelector(
178
+ `[name="donation_frequency"][value="${ attributes.defaultFrequency }"]`
179
+ );
180
+ if ( defaultFrequencyInput instanceof HTMLInputElement ) {
181
+ defaultFrequencyInput.click();
182
+ }
183
+ }
184
+ }, [ attributes.defaultFrequency ] );
185
+
186
+ const handleCustomDonationChange = ( {
187
+ value,
188
+ frequency,
189
+ tierIndex,
190
+ }: {
191
+ value: string;
192
+ frequency: FrequencySlug;
193
+ tierIndex: number;
194
+ } ) => {
195
+ const subject = attributes.manual ? attributes : settings;
196
+ subject.amounts[ frequency ][ tierIndex ] = parseFloat( value );
197
+ const update: Partial< DonateBlockAttributes > = {
198
+ amounts: {
199
+ [ frequency ]: subject.amounts[ frequency ],
200
+ ...subject.amounts,
201
+ },
202
+ };
203
+
204
+ if ( attributes.manual ) {
205
+ setAttributes( update );
206
+ } else {
207
+ setSettings( update );
208
+ }
209
+ };
210
+
211
+ const renderFrequencySelect = ( frequencySlug: FrequencySlug ) => (
212
+ <>
213
+ <input
214
+ type="radio"
215
+ value={ frequencySlug }
216
+ id={ `newspack-donate-${ frequencySlug }-${ uid }` }
217
+ name="donation_frequency"
218
+ defaultChecked={ frequencySlug === attributes.defaultFrequency }
219
+ />
220
+ <label
221
+ htmlFor={ 'newspack-donate-' + frequencySlug + '-' + uid }
222
+ className="donation-frequency-label freq-label"
223
+ >
224
+ { FREQUENCIES[ frequencySlug ] }
225
+ </label>
226
+ </>
227
+ );
228
+
229
+ const displayAmount = ( amount: number ) => amount.toFixed( 2 ).replace( /\.?0*$/, '' );
230
+ const getClassNames = ( classes: string ) =>
231
+ classNames(
232
+ classes,
233
+ className,
234
+ 'wpbnbd',
235
+ `wpbnbd-frequencies--${ availableFrequencies.length }`
236
+ );
237
+
238
+ const getFrequenciesContainerStyle = () => {
239
+ let padding = '(0.76rem + 1.6em + 1px)';
240
+ switch ( attributes.className ) {
241
+ case 'is-style-alternate':
242
+ padding = '( 1.14rem + 1.6em ) + 8px';
243
+ break;
244
+ case 'is-style-minimal':
245
+ padding = '( 0.76rem + 1.6em + 4px )';
246
+ break;
247
+ }
248
+ return { paddingTop: `calc(${ availableFrequencies.length }*${ padding })` };
249
+ };
250
+
251
+ const renderAmountValueInput = ( {
252
+ frequencySlug,
253
+ tierIndex,
254
+ id,
255
+ label,
256
+ }: {
257
+ frequencySlug: FrequencySlug;
258
+ tierIndex: number;
259
+ id: string;
260
+ label?: string;
261
+ } ) => (
262
+ <span key={ `${ frequencySlug }-${ tierIndex }` }>
263
+ { label && <label htmlFor={ id }>{ label }</label> }
264
+ <input
265
+ type="number"
266
+ min="0"
267
+ onChange={ evt =>
268
+ handleCustomDonationChange( {
269
+ value: evt.target.value,
270
+ frequency: frequencySlug,
271
+ tierIndex,
272
+ } )
273
+ }
274
+ value={ amounts[ frequencySlug ][ tierIndex ] }
275
+ id={ id }
276
+ />
277
+ </span>
278
+ );
279
+
280
+ const renderUntieredForm = () => (
281
+ <div className="wp-block-newspack-blocks-donate__options">
282
+ <div
283
+ className="wp-block-newspack-blocks-donate__frequencies frequencies"
284
+ style={ getFrequenciesContainerStyle() }
285
+ >
286
+ { availableFrequencies.map( frequencySlug => (
287
+ <div
288
+ className="wp-block-newspack-blocks-donate__frequency frequency"
289
+ key={ frequencySlug }
290
+ >
291
+ { renderFrequencySelect( frequencySlug ) }
292
+ <div className="input-container">
293
+ <label
294
+ className="donate-label"
295
+ htmlFor={ 'newspack-' + frequencySlug + '-' + uid + '-untiered-input' }
296
+ >
297
+ { __( 'Donation amount', 'newspack-blocks' ) }
298
+ </label>
299
+ <div className="wp-block-newspack-blocks-donate__money-input money-input">
300
+ <span className="currency">{ settings.currencySymbol }</span>
301
+ { renderAmountValueInput( {
302
+ frequencySlug,
303
+ tierIndex: 3,
304
+ id: `newspack-${ frequencySlug }-${ uid }-untiered-input`,
305
+ } ) }
306
+ </div>
307
+ </div>
308
+ </div>
309
+ ) ) }
310
+ </div>
311
+ </div>
312
+ );
313
+
314
+ const renderTieredForm = () => (
315
+ <div className="wp-block-newspack-blocks-donate__options">
316
+ <div
317
+ className="wp-block-newspack-blocks-donate__frequencies frequencies"
318
+ style={ getFrequenciesContainerStyle() }
319
+ >
320
+ { availableFrequencies.map( frequencySlug => (
321
+ <div
322
+ className="wp-block-newspack-blocks-donate__frequency frequency"
323
+ key={ frequencySlug }
324
+ >
325
+ { renderFrequencySelect( frequencySlug ) }
326
+
327
+ <div className="wp-block-newspack-blocks-donate__tiers tiers">
328
+ { amounts[ frequencySlug ].map( ( suggestedAmount, index ) => {
329
+ const isOtherTier = index === 3;
330
+ const id = `newspack-tier-${ frequencySlug }-${ uid }-${
331
+ isOtherTier ? 'other' : index
332
+ }`;
333
+ return (
334
+ <div
335
+ className={ classNames(
336
+ 'wp-block-newspack-blocks-donate__tier',
337
+ `wp-block-newspack-blocks-donate__tier--${
338
+ isOtherTier ? 'other' : 'frequency'
339
+ }`
340
+ ) }
341
+ key={ index }
342
+ >
343
+ <input
344
+ type="radio"
345
+ value={ isOtherTier ? 'other' : suggestedAmount }
346
+ className={ isOtherTier ? 'other-input' : 'frequency-input' }
347
+ id={ id }
348
+ name={ `donation_value_${ frequencySlug }` }
349
+ defaultChecked={ index === 1 }
350
+ />
351
+ <label className="tier-select-label tier-label" htmlFor={ id }>
352
+ { isOtherTier
353
+ ? __( 'Other', 'newspack-blocks' )
354
+ : settings.currencySymbol + displayAmount( suggestedAmount ) }
355
+ </label>
356
+ { isOtherTier ? (
357
+ <>
358
+ <label className="odl" htmlFor={ id + '-other-input' }>
359
+ { __( 'Donation amount', 'newspack-blocks' ) }
360
+ </label>
361
+ <div className="wp-block-newspack-blocks-donate__money-input money-input">
362
+ <span className="currency">{ settings.currencySymbol }</span>
363
+ { renderAmountValueInput( {
364
+ frequencySlug,
365
+ tierIndex: index,
366
+ id: `${ id }-other-input`,
367
+ } ) }
368
+ </div>
369
+ </>
370
+ ) : null }
371
+ </div>
372
+ );
373
+ } ) }
374
+ </div>
375
+ </div>
376
+ ) ) }
377
+ </div>
378
+ </div>
379
+ );
380
+
381
+ const renderButton = () => (
382
+ <button type="submit" onClick={ evt => evt.preventDefault() }>
383
+ { isRenderingStreamlinedBlock() ? (
384
+ __( 'Donate with card', 'newspack-blocks' )
385
+ ) : (
386
+ <RichText
387
+ onChange={ ( value: string ) => setAttributes( { buttonText: value } ) }
388
+ placeholder={ __( 'Button text…', 'newspack-blocks' ) }
389
+ value={ attributes.buttonText }
390
+ tagName="span"
391
+ />
392
+ ) }
393
+ </button>
394
+ );
395
+
396
+ const renderFooter = () => (
397
+ <>
398
+ <p className="wp-block-newspack-blocks-donate__thanks thanks">
399
+ <RichText
400
+ onChange={ ( value: string ) => setAttributes( { thanksText: value } ) }
401
+ placeholder={ __( 'Thank you text…', 'newspack-blocks' ) }
402
+ value={ attributes.thanksText }
403
+ tagName="span"
404
+ />
405
+ </p>
406
+ { isRenderingStreamlinedBlock() ? (
407
+ <div className="wp-block-newspack-blocks-donate__stripe stripe-payment">
408
+ <div className="stripe-payment__row stripe-payment__row--flex stripe-payment__footer">
409
+ <div className="stripe-payment__methods">
410
+ <div className="stripe-payment__request-button">
411
+ { __( 'Apple/Google Pay Button', 'newspack-blocks' ) }
412
+ </div>
413
+ { renderButton() }
414
+ </div>
415
+ <a
416
+ target="_blank"
417
+ rel="noreferrer"
418
+ className="stripe-payment__branding"
419
+ href="https://stripe.com"
420
+ >
421
+ <img
422
+ width="111"
423
+ height="26"
424
+ src={ window.newspack_blocks_data?.streamlined_block_stripe_badge }
425
+ alt="Stripe"
426
+ />
427
+ </a>
428
+ </div>
429
+ </div>
430
+ ) : (
431
+ renderButton()
432
+ ) }
433
+ </>
434
+ );
435
+
436
+ if ( error.length ) {
437
+ return (
438
+ <Placeholder icon="warning" label={ __( 'Error', 'newspack-blocks' ) } instructions={ error }>
439
+ <ExternalLink href="/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/donations">
440
+ { __( 'Go to donation settings to troubleshoot.', 'newspack-blocks' ) }
441
+ </ExternalLink>
442
+ </Placeholder>
443
+ );
444
+ }
445
+
446
+ if ( isLoading ) {
447
+ return <Placeholder icon={ <Spinner /> } className="component-placeholder__align-center" />;
448
+ }
449
+
450
+ const isTiered = attributes.manual ? attributes.tiered : settings.tiered;
451
+
452
+ return (
453
+ <>
454
+ <div className={ getClassNames( isTiered ? 'tiered' : 'untiered' ) }>
455
+ <form ref={ formRef }>
456
+ { isTiered ? renderTieredForm() : renderUntieredForm() }
457
+ { renderFooter() }
458
+ </form>
459
+ </div>
460
+
461
+ <InspectorControls>
462
+ <PanelBody title={ __( 'Suggested Donations', 'newspack-blocks' ) }>
463
+ <SelectControl
464
+ label={ __( 'Default Tab', 'newspack' ) }
465
+ value={ attributes.defaultFrequency }
466
+ options={ availableFrequencies.map( key => ( {
467
+ label: FREQUENCIES[ key ],
468
+ value: key,
469
+ } ) ) }
470
+ onChange={ ( defaultFrequency: FrequencySlug ) =>
471
+ setAttributes( { defaultFrequency } )
472
+ }
473
+ />
474
+ <ToggleControl
475
+ checked={ Boolean( attributes.manual ) }
476
+ onChange={ () => setAttributes( { manual: ! attributes.manual } ) }
477
+ label={ __( 'Configure manually', 'newspack-blocks' ) }
478
+ />
479
+ { attributes.manual ? (
480
+ <>
481
+ <ToggleControl
482
+ checked={ Boolean( attributes.tiered ) }
483
+ onChange={ () => setAttributes( { tiered: ! attributes.tiered } ) }
484
+ label={ __( 'Tiered', 'newspack-blocks' ) }
485
+ />
486
+ { attributes.tiered ? (
487
+ <div className="components-frequency-donations">
488
+ { FREQUENCY_SLUGS.map( ( frequency: FrequencySlug ) => {
489
+ const isFrequencyDisabled = attributes.disabledFrequencies[ frequency ];
490
+ const isOneFrequencyActive =
491
+ Object.values( attributes.disabledFrequencies ).filter( Boolean ).length ===
492
+ FREQUENCY_SLUGS.length - 1;
493
+ return (
494
+ <Fragment key={ frequency }>
495
+ <CheckboxControl
496
+ label={ FREQUENCIES[ frequency ] }
497
+ checked={ ! isFrequencyDisabled }
498
+ disabled={ ! isFrequencyDisabled && isOneFrequencyActive }
499
+ onChange={ () => {
500
+ setAttributes( {
501
+ disabledFrequencies: {
502
+ ...attributes.disabledFrequencies,
503
+ [ frequency ]: ! isFrequencyDisabled,
504
+ },
505
+ } );
506
+ } }
507
+ />
508
+ { ! isFrequencyDisabled && (
509
+ <div className="wp-block-newspack-blocks-donate__panel-inputs">
510
+ { amounts[ frequency ].map( ( suggestedAmount, tierIndex ) =>
511
+ renderAmountValueInput( {
512
+ frequencySlug: frequency,
513
+ tierIndex,
514
+ label: TIER_LABELS[ tierIndex ],
515
+ id: `${ frequency }-${ tierIndex }-amount`,
516
+ } )
517
+ ) }
518
+ </div>
519
+ ) }
520
+ </Fragment>
521
+ );
522
+ } ) }
523
+ </div>
524
+ ) : (
525
+ <div className="components-frequency-donations">
526
+ <div className="wp-block-newspack-blocks-donate__panel-inputs">
527
+ { FREQUENCY_SLUGS.map( ( frequencySlug: FrequencySlug ) =>
528
+ renderAmountValueInput( {
529
+ frequencySlug,
530
+ tierIndex: 3,
531
+ label: FREQUENCIES[ frequencySlug ],
532
+ id: `${ frequencySlug }-${ 3 }-amount`,
533
+ } )
534
+ ) }
535
+ </div>
536
+ </div>
537
+ ) }
538
+ </>
539
+ ) : (
540
+ <p>
541
+ { __(
542
+ 'The Donate Block allows you to collect donations from readers. The fields are automatically defined based on your donation settings.',
543
+ 'newspack-blocks'
544
+ ) }
545
+ <br />
546
+ <br />
547
+ <ExternalLink href="/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/donations">
548
+ { __( 'Edit donation settings', 'newspack-blocks' ) }
549
+ </ExternalLink>
550
+ </p>
551
+ ) }
552
+ </PanelBody>
553
+ <PanelBody title={ __( 'Campaign', 'newspack-blocks' ) } initialOpen={ false }>
554
+ <TextControl
555
+ label={ __( 'Campaign ID', 'newspack-blocks' ) }
556
+ value={ attributes.campaign || '' }
557
+ onChange={ ( value: string ) =>
558
+ setAttributes( {
559
+ campaign: value,
560
+ } )
561
+ }
562
+ />
563
+ </PanelBody>
564
+ </InspectorControls>
565
+ </>
566
+ );
567
+ };
568
+
569
+ export default Edit;
@@ -1,15 +1,38 @@
1
- @import '../../shared/sass/colors';
2
- @import '../../shared/sass/variables';
1
+ @use '../../shared/sass/colors';
2
+ @use '../../shared/sass/variables';
3
3
 
4
- @import './streamlined/style.scss';
4
+ @use 'streamlined/style.scss';
5
5
 
6
6
  .wp-block-newspack-blocks-donate {
7
+ &__tier--frequency {
8
+ position: relative;
9
+ }
10
+
11
+ &__panel-inputs {
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ justify-content: space-between;
15
+ margin-bottom: 21px;
16
+ input,
17
+ span {
18
+ min-width: 0;
19
+ }
20
+ span {
21
+ margin-bottom: 7px;
22
+ display: inline-block;
23
+ width: 48%;
24
+ }
25
+ input {
26
+ max-width: 100%;
27
+ }
28
+ }
29
+
7
30
  button[type='submit'] {
8
31
  border: none;
9
32
  border-radius: 5px;
10
33
  box-sizing: border-box;
11
- color: $color__background-body;
12
- font-size: $font__size-sm;
34
+ color: colors.$color__background-body;
35
+ font-size: variables.$font__size-sm;
13
36
  font-weight: bold;
14
37
  outline: none;
15
38
  line-height: 3;
@@ -25,14 +48,33 @@
25
48
  &__request-button {
26
49
  font-size: 0.8em;
27
50
  border-radius: 5px;
28
- color: $color__secondary;
29
- border: $color__secondary 1px dashed;
51
+ color: colors.$color__secondary;
52
+ border: colors.$color__secondary 1px dashed;
30
53
  padding: 0 20px;
31
54
  opacity: 0.5;
32
55
  }
33
56
  }
34
57
  }
35
58
 
59
+ .wp-block-newspack-blocks-donate.wpbnbd.tiered {
60
+ .tiers {
61
+ input.frequency-input {
62
+ ~ input[type='number'] {
63
+ position: absolute;
64
+ max-width: 81px;
65
+ top: -31px;
66
+ z-index: 9;
67
+ left: 5px;
68
+ display: none;
69
+ }
70
+
71
+ &:checked ~ input[type='number'] {
72
+ display: flex;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
36
78
  .block-editor-block-list__layout
37
79
  .block-editor-block-list__block
38
80
  .wp-block-newspack-blocks-donate.tiered.is-style-minimal
@@ -40,5 +82,23 @@
40
82
  input[type='radio']:checked
41
83
  + .tier-select-label {
42
84
  background: transparent;
43
- color: $color__text-main;
85
+ color: colors.$color__text-main;
86
+ }
87
+
88
+ .components-frequency-donations {
89
+ p {
90
+ margin-bottom: 8px;
91
+ }
92
+
93
+ .components-base-control {
94
+ margin-bottom: 0;
95
+
96
+ &:last-child {
97
+ margin-bottom: 0;
98
+
99
+ .components-base-control__field {
100
+ margin-bottom: 0;
101
+ }
102
+ }
103
+ }
44
104
  }