diff --git a/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx b/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx index 2aedc6da9486a..606823ecba2e4 100644 --- a/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx @@ -88,7 +88,7 @@ const ConnectedProductCard: FC< ConnectedProductCardProps > = ( { const cardDescription = defaultDescription.replace( /\s(?=[^\s]*$)/, '\u00A0' ); return ( - + { cardDescription } ); diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/backup-card/index.jsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/backup-card/index.jsx index a5ba14c6ab5ce..9400d74d3ed3d 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/backup-card/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/backup-card/index.jsx @@ -130,7 +130,7 @@ const BackupCard = props => { return hasBackups ? ( ) : ( - + ); }; @@ -194,6 +194,7 @@ const WithBackupsValueSection = props => { ); }; +// DEPRECATED: this output was more confusing than helpful const NoBackupsValueSection = props => { const { data: backupStats, isLoading } = useSimpleQuery( { name: QUERY_BACKUP_STATS_KEY, diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/index.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/index.tsx index f22d46a615c13..da5c17fbe9593 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/index.tsx @@ -1,22 +1,12 @@ -import { useCallback, type FC } from 'react'; +import { type FC } from 'react'; import ProductCard from '../../connected-product-card'; import ProtectValueSection from './protect-value-section'; const ProtectCard: FC< { admin: boolean; recommendation?: boolean } > = props => { const slug = 'protect'; - // This is a workaround to remove the Description from the product card. However if we end - // up needing to remove the Description from additional cards in the future, we might consider - // extending functionality to support that. - const noDescription = useCallback( () => null, [] ); - return ( - + ); diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-product-card-copy b/projects/packages/my-jetpack/changelog/update-my-jetpack-product-card-copy new file mode 100644 index 0000000000000..da33d82d48323 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-product-card-copy @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +copy updates diff --git a/projects/packages/my-jetpack/src/products/class-anti-spam.php b/projects/packages/my-jetpack/src/products/class-anti-spam.php index 3713e3dff10d2..88d212f01e324 100644 --- a/projects/packages/my-jetpack/src/products/class-anti-spam.php +++ b/projects/packages/my-jetpack/src/products/class-anti-spam.php @@ -81,7 +81,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Stop comment and form spam', 'jetpack-my-jetpack' ); + return __( 'Keep your site free from spam and bots', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-backup.php b/projects/packages/my-jetpack/src/products/class-backup.php index 32de7db90db89..396737ac17783 100644 --- a/projects/packages/my-jetpack/src/products/class-backup.php +++ b/projects/packages/my-jetpack/src/products/class-backup.php @@ -93,7 +93,7 @@ public static function get_description() { return __( 'Save every change', 'jetpack-my-jetpack' ); } - return __( 'Your site is not backed up', 'jetpack-my-jetpack' ); + return __( 'Secure your site with automatic backups and one-click restores', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-boost.php b/projects/packages/my-jetpack/src/products/class-boost.php index 25d023adcd9f5..a9f9b0f58f14b 100644 --- a/projects/packages/my-jetpack/src/products/class-boost.php +++ b/projects/packages/my-jetpack/src/products/class-boost.php @@ -89,7 +89,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Speed up your site in seconds', 'jetpack-my-jetpack' ); + return __( 'Speed up your site and improve SEO in seconds', 'jetpack-my-jetpack' ); } /** @@ -98,7 +98,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'Jetpack Boost gives your site the same performance advantages as the world’s leading websites, no developer required.', 'jetpack-my-jetpack' ); + return __( 'Fast sites get more page visits, more conversions, and better SEO rankings. Boost speeds up your site in seconds.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-creator.php b/projects/packages/my-jetpack/src/products/class-creator.php index c41557ad3c1d0..1dc5ac1d966fc 100644 --- a/projects/packages/my-jetpack/src/products/class-creator.php +++ b/projects/packages/my-jetpack/src/products/class-creator.php @@ -80,7 +80,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Create, grow, and monetize your audience', 'jetpack-my-jetpack' ); + return __( 'Get more subscribers and keep them engaged with our creator tools', 'jetpack-my-jetpack' ); } /** @@ -89,7 +89,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'Create, grow, and monetize your audience with powerful tools for creators.', 'jetpack-my-jetpack' ); + return __( 'Craft stunning content, boost your subscriber base, and monetize your audience with subscriptions.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-crm.php b/projects/packages/my-jetpack/src/products/class-crm.php index f63d90f1e7f87..27d9197c252be 100644 --- a/projects/packages/my-jetpack/src/products/class-crm.php +++ b/projects/packages/my-jetpack/src/products/class-crm.php @@ -84,7 +84,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Nurture your contacts to grow your business', 'jetpack-my-jetpack' ); + return __( 'Strengthen customer relationships and grow your business', 'jetpack-my-jetpack' ); } /** @@ -93,7 +93,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'All of your contacts in one place. Build better relationships with your customers and clients.', 'jetpack-my-jetpack' ); + return __( 'Build better relationships with your customers and grow your business.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-jetpack-ai.php b/projects/packages/my-jetpack/src/products/class-jetpack-ai.php index d576f21767a5a..a65993035db12 100644 --- a/projects/packages/my-jetpack/src/products/class-jetpack-ai.php +++ b/projects/packages/my-jetpack/src/products/class-jetpack-ai.php @@ -216,7 +216,7 @@ public static function get_next_usage_tier() { * @return string */ public static function get_description() { - return __( 'The most powerful AI tool for WordPress', 'jetpack-my-jetpack' ); + return __( 'Enhance your writing and productivity with our AI suite', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-protect.php b/projects/packages/my-jetpack/src/products/class-protect.php index bba230cca40d4..5577a34c73cab 100644 --- a/projects/packages/my-jetpack/src/products/class-protect.php +++ b/projects/packages/my-jetpack/src/products/class-protect.php @@ -92,7 +92,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Powerful, automated site security', 'jetpack-my-jetpack' ); + return __( 'Guard against malware and bad actors 24/7', 'jetpack-my-jetpack' ); } /** @@ -101,7 +101,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'Protect your site and scan for security vulnerabilities listed in our database.', 'jetpack-my-jetpack' ); + return __( 'Protect your site from bad actors and malware 24/7. Clean up security vulnerabilities with one click.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-search.php b/projects/packages/my-jetpack/src/products/class-search.php index 63b4d01771b03..df81d2e98d9a1 100644 --- a/projects/packages/my-jetpack/src/products/class-search.php +++ b/projects/packages/my-jetpack/src/products/class-search.php @@ -103,7 +103,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Custom instant site search', 'jetpack-my-jetpack' ); + return __( 'Help your visitors find what they are looking for with instant search results', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-social.php b/projects/packages/my-jetpack/src/products/class-social.php index 583741341c50b..80913a97b7d66 100644 --- a/projects/packages/my-jetpack/src/products/class-social.php +++ b/projects/packages/my-jetpack/src/products/class-social.php @@ -86,7 +86,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Auto-publish to social media', 'jetpack-my-jetpack' ); + return __( 'Effortlessly share content across social media. Right from within WordPress', 'jetpack-my-jetpack' ); } /** @@ -95,7 +95,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'Promote your content on social media by automatically publishing when you publish on your site.', 'jetpack-my-jetpack' ); + return __( 'Grow your following by sharing your content across social media automatically.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-stats.php b/projects/packages/my-jetpack/src/products/class-stats.php index a953ab4e2452a..6f1118cf6f4c2 100644 --- a/projects/packages/my-jetpack/src/products/class-stats.php +++ b/projects/packages/my-jetpack/src/products/class-stats.php @@ -91,7 +91,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'Simple, yet powerful analytics', 'jetpack-my-jetpack' ); + return __( 'The simplest way to track visitor insights and unlock your site’s growth', 'jetpack-my-jetpack' ); } /** @@ -100,7 +100,7 @@ public static function get_description() { * @return string */ public static function get_long_description() { - return __( 'With Jetpack Stats, you don’t need to be a data scientist to see how your site is performing.', 'jetpack-my-jetpack' ); + return __( 'With Jetpack Stats, you don’t need to be a data scientist to see how your site is performing, understand your visitors, and grow your site.', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/my-jetpack/src/products/class-videopress.php b/projects/packages/my-jetpack/src/products/class-videopress.php index c5c61fac47cc2..307228664fd57 100644 --- a/projects/packages/my-jetpack/src/products/class-videopress.php +++ b/projects/packages/my-jetpack/src/products/class-videopress.php @@ -92,7 +92,7 @@ public static function get_title() { * @return string */ public static function get_description() { - return __( 'High quality, ad-free video', 'jetpack-my-jetpack' ); + return __( 'High-quality, ad-free video built specifically for WordPress', 'jetpack-my-jetpack' ); } /** diff --git a/projects/packages/sync/changelog/fix-sync-hpos-checksums b/projects/packages/sync/changelog/fix-sync-hpos-checksums new file mode 100644 index 0000000000000..9c9b77c8d4e96 --- /dev/null +++ b/projects/packages/sync/changelog/fix-sync-hpos-checksums @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Jetpack Sync: Take order type into account when performing HPOS Checksums diff --git a/projects/packages/sync/src/class-package-version.php b/projects/packages/sync/src/class-package-version.php index ceaa8233b467c..8237ced0e7ee8 100644 --- a/projects/packages/sync/src/class-package-version.php +++ b/projects/packages/sync/src/class-package-version.php @@ -12,7 +12,7 @@ */ class Package_Version { - const PACKAGE_VERSION = '3.5.0-alpha'; + const PACKAGE_VERSION = '3.4.1-alpha'; const PACKAGE_SLUG = 'sync'; diff --git a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php index 610e216ec9cf0..d3abc38330079 100644 --- a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php +++ b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php @@ -60,13 +60,11 @@ public function __construct() { /** * Get order types that we want to sync. Adding a new type here is not enough, we would also need to add its prop in filter_order_data method. * - * @access private - * * @param bool $prefixed Whether to return prefixed types with shop_ or not. * * @return array Order types to sync. */ - private function get_order_types_to_sync( $prefixed = false ) { + public static function get_order_types_to_sync( $prefixed = false ) { $types = array( 'order', 'order_refund' ); if ( $prefixed ) { $types = array_map( @@ -87,7 +85,7 @@ function ( $type ) { * @param callable $callable Action handler callable. */ public function init_listeners( $callable ) { - foreach ( $this->get_order_types_to_sync() as $type ) { + foreach ( self::get_order_types_to_sync() as $type ) { add_action( "woocommerce_after_{$type}_object_save", $callable ); add_filter( "jetpack_sync_before_enqueue_woocommerce_after_{$type}_object_save", array( $this, 'expand_order_object' ) ); } @@ -167,7 +165,7 @@ public function get_objects_by_id( $object_type, $ids ) { $orders = wc_get_orders( array( 'post__in' => $ids, - 'type' => $this->get_order_types_to_sync( true ), + 'type' => self::get_order_types_to_sync( true ), 'post_status' => $this->get_all_possible_order_status_keys(), 'limit' => -1, ) @@ -420,7 +418,7 @@ public function enqueue_full_sync_actions( $config, $max_items_to_enqueue, $stat public function get_where_sql( $config ) { global $wpdb; $parent_where = parent::get_where_sql( $config ); - $order_types = $this->get_order_types_to_sync( true ); + $order_types = self::get_order_types_to_sync( true ); $order_type_placeholder = implode( ', ', array_fill( 0, count( $order_types ), '%s' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Query is prepared. $where_sql = $wpdb->prepare( "type IN ( $order_type_placeholder )", $order_types ); diff --git a/projects/packages/sync/src/replicastore/class-table-checksum.php b/projects/packages/sync/src/replicastore/class-table-checksum.php index d1cd99dbc690b..2413a5e9f8014 100644 --- a/projects/packages/sync/src/replicastore/class-table-checksum.php +++ b/projects/packages/sync/src/replicastore/class-table-checksum.php @@ -8,6 +8,7 @@ namespace Automattic\Jetpack\Sync\Replicastore; use Automattic\Jetpack\Sync; +use Automattic\Jetpack\Sync\Modules\WooCommerce_HPOS_Orders; use Exception; use WP_Error; @@ -313,7 +314,12 @@ protected function get_default_tables() { 'key_fields' => array( 'id' ), 'checksum_fields' => array( 'date_updated_gmt', 'total_amount' ), 'checksum_text_fields' => array( 'type', 'status' ), - 'filter_values' => array(), + 'filter_values' => array( + 'type' => array( + 'operator' => 'IN', + 'values' => WooCommerce_HPOS_Orders::get_order_types_to_sync( true ), + ), + ), 'is_table_enabled_callback' => 'Automattic\Jetpack\Sync\Replicastore\Table_Checksum::enable_woocommerce_hpos_tables', ), 'wc_order_addresses' => array( @@ -321,6 +327,9 @@ protected function get_default_tables() { 'range_field' => 'order_id', 'key_fields' => array( 'order_id', 'address_type' ), 'checksum_text_fields' => array( 'address_type' ), + 'parent_table' => 'wc_orders', + 'parent_join_field' => 'id', + 'table_join_field' => 'order_id', 'filter_values' => array(), 'is_table_enabled_callback' => 'Automattic\Jetpack\Sync\Replicastore\Table_Checksum::enable_woocommerce_hpos_tables', ), @@ -330,6 +339,9 @@ protected function get_default_tables() { 'key_fields' => array( 'order_id' ), 'checksum_fields' => array( 'date_paid_gmt', 'date_completed_gmt' ), 'checksum_text_fields' => array( 'order_key' ), + 'parent_table' => 'wc_orders', + 'parent_join_field' => 'id', + 'table_join_field' => 'order_id', 'filter_values' => array(), 'is_table_enabled_callback' => 'Automattic\Jetpack\Sync\Replicastore\Table_Checksum::enable_woocommerce_hpos_tables', ), diff --git a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-email-preview.php b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-email-preview.php new file mode 100644 index 0000000000000..99af3d5b1ca63 --- /dev/null +++ b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-email-preview.php @@ -0,0 +1,123 @@ +base_api_path = 'wpcom'; + $this->version = 'v2'; + $this->namespace = $this->base_api_path . '/' . $this->version; + $this->rest_base = '/email-preview'; + $this->wpcom_is_wpcom_only_endpoint = true; + $this->wpcom_is_site_specific_endpoint = true; + + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + } + + /** + * Registers the routes for email preview. + * + * @see register_rest_route() + */ + public function register_routes() { + $options = array( + 'show_in_index' => true, + 'methods' => 'GET', + // if this is not a wpcom site, we need to proxy the request to wpcom + 'callback' => ( ( new Host() )->is_wpcom_simple() ) ? array( + $this, + 'email_preview', + ) : array( $this, 'proxy_request_to_wpcom_as_user' ), + 'permission_callback' => array( $this, 'permissions_check' ), + 'args' => array( + 'id' => array( + 'description' => __( 'Unique identifier for the post.', 'jetpack' ), + 'type' => 'integer', + ), + ), + ); + + register_rest_route( + $this->namespace, + $this->rest_base, + $options + ); + } + + /** + * Checks if the user is connected and has access to edit the post + * + * @param WP_REST_Request $request Full data about the request. + * + * @return true|WP_Error True if the request has edit access, WP_Error object otherwise. + */ + public function permissions_check( $request ) { + if ( ! ( new Host() )->is_wpcom_simple() ) { + if ( ! ( new Manager() )->is_user_connected() ) { + return new WP_Error( + 'rest_cannot_send_email_preview', + __( 'Please connect your user account to WordPress.com', 'jetpack' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + } + + $post = get_post( $request->get_param( 'post_id' ) ); + + if ( ! $post ) { + return new \WP_Error( + 'post_not_found', + __( 'Post not found.', 'jetpack' ), + array( 'status' => 404 ) + ); + } + + if ( ! current_user_can( 'edit_post', $post->ID ) ) { + return new WP_Error( + 'rest_forbidden_context', + __( 'Please connect your user account to WordPress.com', 'jetpack' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; + } + + /** + * Returns an email preview of a post. + * + * @param WP_REST_Request $request Full data about the request. + * + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function email_preview( $request ) { + $post_id = $request['post_id']; + $post = get_post( $post_id ); + return rest_ensure_response( + array( + 'html' => apply_filters( 'jetpack_generate_email_preview_html', '', $post ), + ) + ); + } +} + +wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Email_Preview' ); diff --git a/projects/plugins/jetpack/changelog/add-email-preview-endpoint b/projects/plugins/jetpack/changelog/add-email-preview-endpoint new file mode 100644 index 0000000000000..f14da362d760e --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-email-preview-endpoint @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Jetpack Newsletter: Adds Jetpack Newsletter menu with preview option. diff --git a/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-complex-word-slash b/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-complex-word-slash new file mode 100644 index 0000000000000..13bccddec026a --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-complex-word-slash @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +AI Assistant: Remove slash highlights on Breve diff --git a/projects/plugins/jetpack/changelog/update-ai-proofread-disabled b/projects/plugins/jetpack/changelog/update-ai-proofread-disabled new file mode 100644 index 0000000000000..d2cc8ce3620de --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-ai-proofread-disabled @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Disable AI Proofread by default diff --git a/projects/plugins/jetpack/extensions/blocks/subscriptions/editor.js b/projects/plugins/jetpack/extensions/blocks/subscriptions/editor.js index 8fc4401732fdd..ee4a6a6ffd14c 100644 --- a/projects/plugins/jetpack/extensions/blocks/subscriptions/editor.js +++ b/projects/plugins/jetpack/extensions/blocks/subscriptions/editor.js @@ -1,11 +1,14 @@ import { registerJetpackPlugin } from '@automattic/jetpack-shared-extension-utils'; import { createBlock } from '@wordpress/blocks'; +import { select } from '@wordpress/data'; import { addFilter } from '@wordpress/hooks'; +import { atSymbol } from '@wordpress/icons'; import { registerJetpackBlockFromMetadata } from '../../shared/register-jetpack-block'; import metadata from './block.json'; import CommandPalette from './command-palette'; import deprecated from './deprecated'; import edit from './edit'; +import NewsletterMenu from './menu'; import SubscribePanels from './panel'; const blockName = metadata.name.replace( 'jetpack/', '' ); @@ -62,14 +65,25 @@ registerJetpackBlockFromMetadata( metadata, { deprecated, } ); +const shouldShowNewsletterMenu = () => { + const postType = select( 'core/editor' ).getCurrentPostType(); + const isPost = postType === 'post'; + // TODO: Remove the query param check once the feature is stable. + return isPost && new URLSearchParams( window.location.search ).has( 'showNewsletterMenu' ); +}; + // Registers slot/fill panels defined via settings.render and command palette commands registerJetpackPlugin( blockName, { - render: () => ( - <> - , - - - ), + render: () => { + return ( + <> + + { shouldShowNewsletterMenu() && } + + + ); + }, + icon: shouldShowNewsletterMenu() ? atSymbol : undefined, } ); // Allows block to be inserted inside core navigation block diff --git a/projects/plugins/jetpack/extensions/blocks/subscriptions/menu.js b/projects/plugins/jetpack/extensions/blocks/subscriptions/menu.js new file mode 100644 index 0000000000000..40d0c3a3dc395 --- /dev/null +++ b/projects/plugins/jetpack/extensions/blocks/subscriptions/menu.js @@ -0,0 +1,122 @@ +import apiFetch from '@wordpress/api-fetch'; +import { Button, Modal, PanelBody, Path, SVG } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { PluginSidebar } from '@wordpress/edit-post'; +import { __ } from '@wordpress/i18n'; +import { useState, useCallback, useEffect } from 'react'; + +// Fallback SVG for the send icon that will be released with Gutenberg 19.0 +// Replace with import { send } from '@wordpress/icons' when available; +const sendIconSvg = ( + + + +); + +const NewsletterMenu = () => { + const [ isModalOpen, setIsModalOpen ] = useState( false ); + const [ isLoading, setIsLoading ] = useState( true ); + const [ previewHtml, setPreviewHtml ] = useState( '' ); + + const { postId } = useSelect( select => { + return { + postId: select( 'core/editor' ).getCurrentPostId(), + }; + }, [] ); + + const fetchPreview = useCallback( async () => { + if ( ! postId ) { + return; + } + + setIsLoading( true ); + try { + const response = await apiFetch( { + path: `/wpcom/v2/email-preview/?post_id=${ postId }`, + method: 'GET', + } ); + + if ( response && response.html ) { + setPreviewHtml( response.html ); + } else { + throw new Error( 'Invalid response format' ); + } + } catch ( error ) { + setPreviewHtml( `${ __( 'Error loading preview', 'jetpack' ) }` ); + } finally { + setIsLoading( false ); + } + }, [ postId ] ); + + const openModal = () => { + setIsModalOpen( true ); + }; + + const closeModal = () => setIsModalOpen( false ); + + useEffect( () => { + if ( isModalOpen ) { + fetchPreview(); + } + }, [ isModalOpen, fetchPreview ] ); + + const modalContent = ( + <> + { isLoading &&

{ __( 'Loading preview…', 'jetpack' ) }

} + { ! isLoading && ( +