From 803722110b863a47a66f6d705096e7ae29236592 Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Sat, 7 Dec 2024 20:11:07 -0500 Subject: [PATCH] More progress on saving status in RSVP V2 block. --- build/blocks/rsvp-status/index.asset.php | 2 +- build/blocks/rsvp-status/index.js | 2 +- build/blocks/rsvp-v2/block.json | 16 +--- build/blocks/rsvp-v2/index.asset.php | 2 +- build/blocks/rsvp-v2/index.js | 2 +- includes/core/classes/class-assets.php | 2 + src/blocks/rsvp-status/index.js | 3 +- src/blocks/rsvp-v2/block.json | 16 +--- src/blocks/rsvp-v2/edit.js | 109 ++++++++++------------- src/blocks/rsvp-v2/index.js | 10 ++- 10 files changed, 67 insertions(+), 97 deletions(-) diff --git a/build/blocks/rsvp-status/index.asset.php b/build/blocks/rsvp-status/index.asset.php index bf374f8b7..9ca840789 100644 --- a/build/blocks/rsvp-status/index.asset.php +++ b/build/blocks/rsvp-status/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => '980c9982f495280b9cf9'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => '647c9e73475f1342072f'); diff --git a/build/blocks/rsvp-status/index.js b/build/blocks/rsvp-status/index.js index b3356ac2c..30d30c971 100644 --- a/build/blocks/rsvp-status/index.js +++ b/build/blocks/rsvp-status/index.js @@ -1 +1 @@ -(()=>{"use strict";const e=window.wp.blocks,t=window.wp.blockEditor,s=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"gatherpress/rsvp-status","version":"1.0.0","title":"RSVP Status","category":"gatherpress","icon":"megaphone","example":{},"description":"Displays the RSVP status of a user.","attributes":{"content":{"type":"string","default":""}},"supports":{"html":false,"color":{"text":true,"background":true},"spacing":{"padding":true,"margin":true},"typography":{"fontSize":true,"lineHeight":true}},"textdomain":"gatherpress","editorScript":"file:./index.js","style":"file:./style-index.css","viewScriptModule":"file:./view.js"}'),r=window.wp.i18n,i=window.ReactJSXRuntime;(0,e.registerBlockType)(s.name,{...s,edit:({attributes:e,setAttributes:s})=>{const{content:n}=e,o=(0,t.useBlockProps)();return(0,i.jsx)("div",{...o,children:(0,i.jsx)(t.RichText,{tagName:"div",value:n,onChange:e=>s({content:e}),placeholder:(0,r.__)("Write RSVP status…","gatherpress")})})},save:()=>{const e=t.useBlockProps.save();return(0,i.jsx)("div",{...e})}})})(); \ No newline at end of file +(()=>{"use strict";const e=window.wp.blocks,t=window.wp.blockEditor,s=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"gatherpress/rsvp-status","version":"1.0.0","title":"RSVP Status","category":"gatherpress","icon":"megaphone","example":{},"description":"Displays the RSVP status of a user.","attributes":{"content":{"type":"string","default":""}},"supports":{"html":false,"color":{"text":true,"background":true},"spacing":{"padding":true,"margin":true},"typography":{"fontSize":true,"lineHeight":true}},"textdomain":"gatherpress","editorScript":"file:./index.js","style":"file:./style-index.css","viewScriptModule":"file:./view.js"}'),r=window.wp.i18n,i=window.ReactJSXRuntime;(0,e.registerBlockType)(s,{edit:({attributes:e,setAttributes:s})=>{const{content:o}=e,n=(0,t.useBlockProps)();return(0,i.jsx)("div",{...n,children:(0,i.jsx)(t.RichText,{tagName:"div",value:o,onChange:e=>s({content:e}),placeholder:(0,r.__)("Write RSVP status…","gatherpress")})})},save:()=>{const e=t.useBlockProps.save();return(0,i.jsx)("div",{...e})}})})(); \ No newline at end of file diff --git a/build/blocks/rsvp-v2/block.json b/build/blocks/rsvp-v2/block.json index 69006e66f..90f635802 100644 --- a/build/blocks/rsvp-v2/block.json +++ b/build/blocks/rsvp-v2/block.json @@ -9,21 +9,9 @@ "example": {}, "description": "Enables members to easily confirm their attendance for an event.", "attributes": { - "noStatusLabel": { + "serializedInnerBlocks": { "type": "string", - "default": "RSVP" - }, - "attendingLabel": { - "type": "string", - "default": "Edit RSVP" - }, - "waitingListLabel": { - "type": "string", - "default": "Edit RSVP" - }, - "notAttendingLabel": { - "type": "string", - "default": "Edit RSVP" + "default": "[]" } }, "supports": { diff --git a/build/blocks/rsvp-v2/index.asset.php b/build/blocks/rsvp-v2/index.asset.php index 2f6d7721b..8ebffea58 100644 --- a/build/blocks/rsvp-v2/index.asset.php +++ b/build/blocks/rsvp-v2/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'e342b20ef97f7ae4fc71'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '9da56d3f11ea2a058a0c'); diff --git a/build/blocks/rsvp-v2/index.js b/build/blocks/rsvp-v2/index.js index cd62a6f71..49dfae18f 100644 --- a/build/blocks/rsvp-v2/index.js +++ b/build/blocks/rsvp-v2/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={5212:()=>{const e=window.wp.blocks,t=window.wp.blockEditor,s=window.wp.components,r=window.wp.i18n,n=window.wp.element,a=window.wp.data,o=[["core/buttons",{align:"center",layout:{type:"flex",justifyContent:"center"}},[["core/button",{text:(0,r.__)("RSVP","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-open-modal"}]]],["core/paragraph",{content:(0,r.__)("Attending","gatherpress")}],["gatherpress/modal",{className:"gatherpress-rsvp-modal"},[["gatherpress/modal-content",{className:"gatherpress-rsvp-modal-content"},[["core/heading",{level:3,content:(0,r.__)("Update your RSVP","gatherpress")}],["core/paragraph",{content:(0,r.__)("To set or change your attending status, simply click the Not Attending button below.","gatherpress")}],["core/buttons",{align:"left",layout:{type:"flex",justifyContent:"flex-start"}},[["core/button",{text:(0,r.__)("Attend","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-status-attending"}],["core/button",{text:(0,r.__)("Close","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-close-modal"}]]]]]]]],i=window.ReactJSXRuntime,l=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"gatherpress/rsvp-v2","version":"2.0.0","title":"RSVP V2","category":"gatherpress","icon":"insert","example":{},"description":"Enables members to easily confirm their attendance for an event.","attributes":{"noStatusLabel":{"type":"string","default":"RSVP"},"attendingLabel":{"type":"string","default":"Edit RSVP"},"waitingListLabel":{"type":"string","default":"Edit RSVP"},"notAttendingLabel":{"type":"string","default":"Edit RSVP"}},"supports":{"align":["wide","full"],"layout":{"allowSwitching":false,"allowInheriting":false,"default":{"justifyContent":"center","type":"flex"}},"html":false,"interactivity":true},"textdomain":"gatherpress","editorScript":"file:./index.js","style":"file:./style-index.css","viewScriptModule":"file:./view.js"}');(0,e.registerBlockType)(l,{edit:({setAttributes:e})=>{const l=(0,t.useBlockProps)(),c=(0,a.useDispatch)(),{setStatus:p}=c("gatherpress/rsvp-status"),{status:g}=(0,a.useSelect)((e=>({status:e("gatherpress/rsvp-status").getStatus()})),[]),u=(0,a.useSelect)((e=>e("core/block-editor").getSelectedBlock()?.clientId),[]),d=(0,a.useSelect)((e=>u?e("core/block-editor").getBlocks(u):[]),[u]),h=e=>{for(const t of e){if("core/button"===t.name)return t;if(t.innerBlocks.length>0){const e=h(t.innerBlocks);if(e)return e}}return null},f=h(d);return(0,n.useEffect)((()=>{if(f){const t=f.attributes.text;switch(g){case"no_status":e({noStatusLabel:t});break;case"attending":e({attendingLabel:t});break;case"waiting_list":e({waitingListLabel:t});break;case"not_attending":e({notAttendingLabel:t})}}}),[f,e,g]),(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.InspectorControls,{children:(0,i.jsx)(s.PanelBody,{children:(0,i.jsx)(s.SelectControl,{label:(0,r.__)("RSVP Status","gatherpress"),value:g,options:[{label:(0,r.__)("No Status (User has not responded)","gatherpress"),value:"no_status"},{label:(0,r.__)("Attending (User is confirmed)","gatherpress"),value:"attending"},{label:(0,r.__)("Waiting List (Pending confirmation)","gatherpress"),value:"waiting_list"},{label:(0,r.__)("Not Attending (User declined)","gatherpress"),value:"not_attending"}],onChange:e=>p(e)})})}),(0,i.jsx)("div",{...l,children:(0,i.jsx)(t.InnerBlocks,{template:o})})]})},save:()=>(0,i.jsx)("div",{...t.useBlockProps.save(),children:(0,i.jsx)(t.InnerBlocks.Content,{})})})}},s={};function r(e){var n=s[e];if(void 0!==n)return n.exports;var a=s[e]={exports:{}};return t[e](a,a.exports,r),a.exports}r.m=t,e=[],r.O=(t,s,n,a)=>{if(!s){var o=1/0;for(p=0;p=a)&&Object.keys(r.O).every((e=>r.O[e](s[l])))?s.splice(l--,1):(i=!1,a0&&e[p-1][2]>a;p--)e[p]=e[p-1];e[p]=[s,n,a]},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={345:0,525:0};r.O.j=t=>0===e[t];var t=(t,s)=>{var n,a,o=s[0],i=s[1],l=s[2],c=0;if(o.some((t=>0!==e[t]))){for(n in i)r.o(i,n)&&(r.m[n]=i[n]);if(l)var p=l(r)}for(t&&t(s);cr(5212)));n=r.O(n)})(); \ No newline at end of file +(()=>{"use strict";var e,t={5212:()=>{const e=window.wp.blocks,t=window.wp.blockEditor,s=window.wp.components,r=window.wp.i18n,n=window.wp.element,a=window.wp.data,o=[["core/buttons",{align:"center",layout:{type:"flex",justifyContent:"center"}},[["core/button",{text:(0,r.__)("RSVP","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-open-modal"}]]],["core/paragraph",{content:(0,r.__)("Attending","gatherpress")}],["gatherpress/modal",{className:"gatherpress-rsvp-modal"},[["gatherpress/modal-content",{className:"gatherpress-rsvp-modal-content"},[["core/heading",{level:3,content:(0,r.__)("Update your RSVP","gatherpress")}],["core/paragraph",{content:(0,r.__)("To set or change your attending status, simply click the Not Attending button below.","gatherpress")}],["core/buttons",{align:"left",layout:{type:"flex",justifyContent:"flex-start"}},[["core/button",{text:(0,r.__)("Attend","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-status-attending"}],["core/button",{text:(0,r.__)("Close","gatherpress"),tagName:"button",className:"gatherpress-rsvp--js-close-modal"}]]]]]]]],l=window.ReactJSXRuntime,i=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"gatherpress/rsvp-v2","version":"2.0.0","title":"RSVP V2","category":"gatherpress","icon":"insert","example":{},"description":"Enables members to easily confirm their attendance for an event.","attributes":{"serializedInnerBlocks":{"type":"string","default":"[]"}},"supports":{"align":["wide","full"],"layout":{"allowSwitching":false,"allowInheriting":false,"default":{"justifyContent":"center","type":"flex"}},"html":false,"interactivity":true},"textdomain":"gatherpress","editorScript":"file:./index.js","style":"file:./style-index.css","viewScriptModule":"file:./view.js"}');(0,e.registerBlockType)(i,{edit:({attributes:e,setAttributes:i,clientId:c})=>{const{serializedInnerBlocks:p="{}"}=e,[d,g]=(0,n.useState)("no_status"),u=(0,t.useBlockProps)(),{replaceInnerBlocks:h}=(0,a.useDispatch)(t.store),f=(0,a.useSelect)((e=>e(t.store).getBlocks(c)),[c]),v=(0,n.useCallback)((e=>{const t=JSON.parse(p||"{}")[e];t&&t.length>0&&h(c,t)}),[c,h,p]);return(0,n.useEffect)((()=>{v(d)}),[d,v]),(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(t.InspectorControls,{children:(0,l.jsx)(s.PanelBody,{children:(0,l.jsx)(s.SelectControl,{label:(0,r.__)("RSVP Status","gatherpress"),value:d,options:[{label:(0,r.__)("No Status (User has not responded)","gatherpress"),value:"no_status"},{label:(0,r.__)("Attending (User is confirmed)","gatherpress"),value:"attending"},{label:(0,r.__)("Waiting List (Pending confirmation)","gatherpress"),value:"waiting_list"},{label:(0,r.__)("Not Attending (User declined)","gatherpress"),value:"not_attending"}],onChange:e=>{((e,t)=>{const s={...JSON.parse(p||"{}"),[e]:t};i({serializedInnerBlocks:JSON.stringify(s)})})(d,f),g(e),v(e)}})})}),(0,l.jsx)("div",{...u,children:(0,l.jsx)(t.InnerBlocks,{template:o})})]})},save:({attributes:e})=>{const s=t.useBlockProps.save(),{serializedInnerBlocks:r}=e;return(0,l.jsx)("div",{...s,"data-serialized-inner-blocks":r,children:(0,l.jsx)(t.InnerBlocks.Content,{})})}})}},s={};function r(e){var n=s[e];if(void 0!==n)return n.exports;var a=s[e]={exports:{}};return t[e](a,a.exports,r),a.exports}r.m=t,e=[],r.O=(t,s,n,a)=>{if(!s){var o=1/0;for(p=0;p=a)&&Object.keys(r.O).every((e=>r.O[e](s[i])))?s.splice(i--,1):(l=!1,a0&&e[p-1][2]>a;p--)e[p]=e[p-1];e[p]=[s,n,a]},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={345:0,525:0};r.O.j=t=>0===e[t];var t=(t,s)=>{var n,a,o=s[0],l=s[1],i=s[2],c=0;if(o.some((t=>0!==e[t]))){for(n in l)r.o(l,n)&&(r.m[n]=l[n]);if(i)var p=i(r)}for(t&&t(s);cr(5212)));n=r.O(n)})(); \ No newline at end of file diff --git a/includes/core/classes/class-assets.php b/includes/core/classes/class-assets.php index a1b05af89..268942105 100644 --- a/includes/core/classes/class-assets.php +++ b/includes/core/classes/class-assets.php @@ -396,7 +396,9 @@ protected function unregister_blocks(): array { 'gatherpress/event-date', 'gatherpress/online-event', 'gatherpress/rsvp', + 'gatherpress/rsvp-v2', 'gatherpress/rsvp-response', + 'gatherpress/rsvp-response-v2', 'gatherpress/rsvp-status', ); break; diff --git a/src/blocks/rsvp-status/index.js b/src/blocks/rsvp-status/index.js index 5f83ed717..a816e5a3a 100644 --- a/src/blocks/rsvp-status/index.js +++ b/src/blocks/rsvp-status/index.js @@ -10,8 +10,7 @@ import { useBlockProps } from '@wordpress/block-editor'; import metadata from './block.json'; import Edit from './edit'; -registerBlockType(metadata.name, { - ...metadata, +registerBlockType(metadata, { edit: Edit, save: () => { // Use blockProps to ensure proper WordPress class handling diff --git a/src/blocks/rsvp-v2/block.json b/src/blocks/rsvp-v2/block.json index cdabe8de5..1fae058ff 100644 --- a/src/blocks/rsvp-v2/block.json +++ b/src/blocks/rsvp-v2/block.json @@ -9,21 +9,9 @@ "example": {}, "description": "Enables members to easily confirm their attendance for an event.", "attributes": { - "noStatusLabel": { + "serializedInnerBlocks": { "type": "string", - "default": "RSVP" - }, - "attendingLabel": { - "type": "string", - "default": "Edit RSVP" - }, - "waitingListLabel": { - "type": "string", - "default": "Edit RSVP" - }, - "notAttendingLabel": { - "type": "string", - "default": "Edit RSVP" + "default": "[]" } }, "supports": { diff --git a/src/blocks/rsvp-v2/edit.js b/src/blocks/rsvp-v2/edit.js index 4a62bb1fe..d79be1009 100644 --- a/src/blocks/rsvp-v2/edit.js +++ b/src/blocks/rsvp-v2/edit.js @@ -5,95 +5,81 @@ import { InnerBlocks, InspectorControls, useBlockProps, + store as blockEditorStore, } from '@wordpress/block-editor'; import { PanelBody, SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useState, useCallback } from '@wordpress/element'; +import { useDispatch, useSelect } from '@wordpress/data'; /** * Internal dependencies. */ -import { useDispatch, useSelect } from '@wordpress/data'; import TEMPLATE from './template'; /** * Edit component for the GatherPress RSVP block. * - * This component defines the edit interface for the GatherPress RSVP block in the block editor. - * It dynamically manages and updates block attributes based on user input and the status of - * nested blocks. The component includes: - * - `InspectorControls` for managing RSVP statuses via a dropdown. - * - Logic to locate and update text labels of nested `core/button` blocks based on the current RSVP status. - * - `InnerBlocks` to allow nested content within the RSVP block. - * - * The `useEffect` hook ensures that changes to the RSVP status or inner blocks dynamically update - * the block attributes, ensuring consistent behavior and text labels. - * * @param {Object} props The props passed to the component. + * @param {Object} props.attributes Block attributes. * @param {Function} props.setAttributes Function to update block attributes. + * @param {string} props.clientId The unique ID of the block instance. * * @since 1.0.0 * * @return {JSX.Element} The rendered edit interface for the RSVP block. */ -const Edit = ({ setAttributes }) => { +const Edit = ({ attributes, setAttributes, clientId }) => { + const { serializedInnerBlocks = '{}' } = attributes; + const [status, setStatus] = useState('no_status'); const blockProps = useBlockProps(); - const dispatch = useDispatch(); - const { setStatus } = dispatch('gatherpress/rsvp-status'); - const { status } = useSelect( - (select) => ({ - status: select('gatherpress/rsvp-status').getStatus(), - }), - [] - ); - - const clientId = useSelect( - (select) => select('core/block-editor').getSelectedBlock()?.clientId, - [] - ); + const { replaceInnerBlocks } = useDispatch(blockEditorStore); + // Get the current inner blocks const innerBlocks = useSelect( - (select) => - clientId ? select('core/block-editor').getBlocks(clientId) : [], + (select) => select(blockEditorStore).getBlocks(clientId), [clientId] ); - const locateButtonBlock = (blocks) => { - for (const block of blocks) { - if (block.name === 'core/button') { - return block; - } - if (block.innerBlocks.length > 0) { - const found = locateButtonBlock(block.innerBlocks); - if (found) { - return found; - } + // Save the provided inner blocks to the serializedInnerBlocks attribute + const saveInnerBlocks = (state, blocks) => { + const currentSerializedBlocks = JSON.parse( + serializedInnerBlocks || '{}' + ); + const updatedBlocks = { + ...currentSerializedBlocks, + [state]: blocks, + }; + + setAttributes({ + serializedInnerBlocks: JSON.stringify(updatedBlocks), + }); + }; + + // Load inner blocks for a given state + const loadInnerBlocksForState = useCallback( + (state) => { + const savedBlocks = JSON.parse(serializedInnerBlocks || '{}')[ + state + ]; + if (savedBlocks && savedBlocks.length > 0) { + replaceInnerBlocks(clientId, savedBlocks); } - } - return null; + }, + [clientId, replaceInnerBlocks, serializedInnerBlocks] + ); + + // Handle status change: save current inner blocks and load new ones + const handleStatusChange = (newStatus) => { + saveInnerBlocks(status, innerBlocks); // Save current inner blocks before switching state + setStatus(newStatus); // Update the state + loadInnerBlocksForState(newStatus); // Load blocks for the new state }; - const buttonBlock = locateButtonBlock(innerBlocks); + // On initial render, ensure correct blocks are loaded useEffect(() => { - if (buttonBlock) { - const buttonText = buttonBlock.attributes.text; - - switch (status) { - case 'no_status': - setAttributes({ noStatusLabel: buttonText }); - break; - case 'attending': - setAttributes({ attendingLabel: buttonText }); - break; - case 'waiting_list': - setAttributes({ waitingListLabel: buttonText }); - break; - case 'not_attending': - setAttributes({ notAttendingLabel: buttonText }); - break; - } - } - }, [buttonBlock, setAttributes, status]); + loadInnerBlocksForState(status); + }, [status, loadInnerBlocksForState]); return ( <> @@ -132,7 +118,7 @@ const Edit = ({ setAttributes }) => { value: 'not_attending', }, ]} - onChange={(newStatus) => setStatus(newStatus)} + onChange={handleStatusChange} /> @@ -142,4 +128,5 @@ const Edit = ({ setAttributes }) => { ); }; + export default Edit; diff --git a/src/blocks/rsvp-v2/index.js b/src/blocks/rsvp-v2/index.js index ca4d9c5b3..f958a7cf6 100644 --- a/src/blocks/rsvp-v2/index.js +++ b/src/blocks/rsvp-v2/index.js @@ -22,9 +22,15 @@ import './style.scss'; */ registerBlockType(metadata, { edit, - save: () => { + save: ({ attributes }) => { + const blockProps = useBlockProps.save(); + const { serializedInnerBlocks } = attributes; + return ( -
+
);