diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c83f75a32869c..8552b9506d76c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -888,6 +888,9 @@ importers: '@automattic/jetpack-shared-extension-utils': specifier: workspace:* version: link:../shared-extension-utils + '@automattic/popup-monitor': + specifier: 1.0.2 + version: 1.0.2 '@automattic/social-previews': specifier: 2.0.1-beta.13 version: 2.0.1-beta.13(@babel/runtime@7.24.0)(@types/react@18.3.1)(react-dom@18.2.0)(react@18.2.0) diff --git a/projects/js-packages/components/changelog/add-social-connect-button b/projects/js-packages/components/changelog/add-social-connect-button new file mode 100644 index 0000000000000..979138de2705f --- /dev/null +++ b/projects/js-packages/components/changelog/add-social-connect-button @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fixed notices z-index for global notices when modal is open diff --git a/projects/js-packages/components/components/global-notices/styles.module.scss b/projects/js-packages/components/components/global-notices/styles.module.scss index 730d1391d3229..98c297670d5d8 100644 --- a/projects/js-packages/components/components/global-notices/styles.module.scss +++ b/projects/js-packages/components/components/global-notices/styles.module.scss @@ -6,6 +6,8 @@ inset-block-start: auto; // top inset-block-end: 0; // bottom inset-inline: 0; // left and right + // Modals have 100000, so this needs to be above them + z-index: 100001; @include break-small { width: auto; diff --git a/projects/js-packages/publicize-components/changelog/add-social-connect-button b/projects/js-packages/publicize-components/changelog/add-social-connect-button new file mode 100644 index 0000000000000..766e0ff8c9e9d --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/add-social-connect-button @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Add connect form/button for connection management diff --git a/projects/js-packages/publicize-components/package.json b/projects/js-packages/publicize-components/package.json index ba5e622ec4be4..3f876c970245d 100644 --- a/projects/js-packages/publicize-components/package.json +++ b/projects/js-packages/publicize-components/package.json @@ -22,6 +22,7 @@ "@automattic/jetpack-components": "workspace:*", "@automattic/jetpack-connection": "workspace:*", "@automattic/jetpack-shared-extension-utils": "workspace:*", + "@automattic/popup-monitor": "1.0.2", "@automattic/social-previews": "2.0.1-beta.13", "@wordpress/annotations": "2.56.0", "@wordpress/api-fetch": "6.53.0", diff --git a/projects/js-packages/publicize-components/src/components/add-connection-modal/connect-form.tsx b/projects/js-packages/publicize-components/src/components/add-connection-modal/connect-form.tsx new file mode 100644 index 0000000000000..51f699a14d396 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/add-connection-modal/connect-form.tsx @@ -0,0 +1,109 @@ +import { Button, useGlobalNotices } from '@automattic/jetpack-components'; +import { __ } from '@wordpress/i18n'; +import classNames from 'classnames'; +import { useCallback } from 'react'; +import { requestExternalAccess } from '../../utils'; +import styles from './style.module.scss'; +import type { SupportedService } from './use-supported-services'; + +type ConnectFormProps = { + service: SupportedService; + isSmall?: boolean; + onConfirm: ( data: unknown ) => void; + onSubmit?: VoidFunction; + displayInputs?: boolean; + isMastodonAlreadyConnected?: ( username: string ) => boolean; +}; + +const isValidMastodonUsername = ( username: string ) => + /^@?\b([A-Z0-9_]+)@([A-Z0-9.-]+\.[A-Z]{2,})$/gi.test( username ); + +/** + * Connect form component + * + * @param {ConnectFormProps} props - Component props + * + * @returns {import('react').ReactNode} Connect form component + */ +export function ConnectForm( { + service, + isSmall, + onConfirm, + onSubmit, + displayInputs, + isMastodonAlreadyConnected, +}: ConnectFormProps ) { + const { createErrorNotice } = useGlobalNotices(); + + const onSubmitForm = useCallback( + ( event: React.FormEvent ) => { + event.preventDefault(); + // Prevent Jetpack settings from being submitted + event.stopPropagation(); + + if ( onSubmit ) { + return onSubmit(); + } + const formData = new FormData( event.target as HTMLFormElement ); + const url = new URL( service.connect_URL ); + + switch ( service.ID ) { + case 'mastodon': { + const instance = formData.get( 'instance' ).toString().trim(); + + if ( ! isValidMastodonUsername( instance ) ) { + createErrorNotice( __( 'Invalid Mastodon username', 'jetpack' ) ); + + return; + } + + if ( isMastodonAlreadyConnected?.( instance ) ) { + createErrorNotice( __( 'This Mastodon account is already connected', 'jetpack' ) ); + + return; + } + + url.searchParams.set( 'instance', formData.get( 'instance' ) as string ); + break; + } + + default: + break; + } + + requestExternalAccess( url.toString(), onConfirm ); + }, + [ + createErrorNotice, + isMastodonAlreadyConnected, + onConfirm, + onSubmit, + service.ID, + service.connect_URL, + ] + ); + + return ( +
{ service.description }