-
Notifications
You must be signed in to change notification settings - Fork 798
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Social: Create a social service connect button (#37196)
* Social: Create a social service connect button This is currently a proof of concept where we get the available external services and render a connect button, which in turn triggers the authentication flow for each service. To test it, the site must be sandboxed with D146389-code applied. * Integrate the button with the add connection modal * Fix naming * Filter services from the backend * Clean up * More cleanup * Move constants logic to hook * Create a shared ConnectForm component * Use the updated hook and form component * Add mastodon validation * Add changelog * OK Phan, here you go * No phan, not OK * Fix notices z-index when a modal is open * Fix up versions * Return only the ones that are present in the available services. * Always return an empty array for connections --------- Co-authored-by: Manzoor Wani <[email protected]>
- Loading branch information
1 parent
2d24fc4
commit 839954e
Showing
22 changed files
with
336 additions
and
71 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
4 changes: 4 additions & 0 deletions
4
projects/js-packages/components/changelog/add-social-connect-button
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: patch | ||
Type: fixed | ||
|
||
Fixed notices z-index for global notices when modal is open |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
projects/js-packages/publicize-components/changelog/add-social-connect-button
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: patch | ||
Type: added | ||
|
||
Add connect form/button for connection management |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...cts/js-packages/publicize-components/src/components/add-connection-modal/connect-form.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<form | ||
className={ classNames( styles[ 'connect-form' ], { [ styles.small ]: isSmall } ) } | ||
onSubmit={ onSubmitForm } | ||
> | ||
{ displayInputs ? ( | ||
<> | ||
{ 'mastodon' === service.ID ? ( | ||
<input | ||
required | ||
type="text" | ||
name="instance" | ||
aria-label={ __( 'Mastodon username', 'jetpack' ) } | ||
placeholder={ '@[email protected]' } | ||
/> | ||
) : null } | ||
</> | ||
) : null } | ||
<Button variant="primary" type="submit" size={ isSmall ? 'small' : 'normal' }> | ||
{ __( 'Connect', 'jetpack' ) } | ||
</Button> | ||
</form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,39 @@ | ||
import { Button, useBreakpointMatch } from '@automattic/jetpack-components'; | ||
import { useSelect } from '@wordpress/data'; | ||
import { __ } from '@wordpress/i18n'; | ||
import classNames from 'classnames'; | ||
import { SupportedService } from '../constants'; | ||
import { useCallback } from 'react'; | ||
import { store as socialStore } from '../../../social-store'; | ||
import { ConnectForm } from '../connect-form'; | ||
import styles from './style.module.scss'; | ||
import type { SupportedService } from '../use-supported-services'; | ||
|
||
type ConnectPageProps = { | ||
service: SupportedService; | ||
onBackClicked: VoidFunction; | ||
onConfirm: ( data: unknown ) => void; | ||
}; | ||
|
||
export const ConnectPage: React.FC< ConnectPageProps > = ( { service, onBackClicked } ) => { | ||
export const ConnectPage: React.FC< ConnectPageProps > = ( { | ||
service, | ||
onBackClicked, | ||
onConfirm, | ||
} ) => { | ||
const [ isSmall ] = useBreakpointMatch( 'sm' ); | ||
|
||
const connections = useSelect( select => { | ||
return select( socialStore ).getConnections(); | ||
}, [] ); | ||
|
||
const isMastodonAlreadyConnected = useCallback( | ||
( username: string ) => { | ||
return connections.some( connection => { | ||
return connection.service_name === 'mastodon' && connection.external_display === username; | ||
} ); | ||
}, | ||
[ connections ] | ||
); | ||
|
||
return ( | ||
<> | ||
<div | ||
|
@@ -20,7 +42,7 @@ export const ConnectPage: React.FC< ConnectPageProps > = ( { service, onBackClic | |
} ) } | ||
> | ||
{ service.examples.map( ( Example, idx ) => ( | ||
<div key={ service.name + idx } className={ styles.example }> | ||
<div key={ service.ID + idx } className={ styles.example }> | ||
<Example /> | ||
</div> | ||
) ) } | ||
|
@@ -33,19 +55,13 @@ export const ConnectPage: React.FC< ConnectPageProps > = ( { service, onBackClic | |
> | ||
{ __( 'Back', 'jetpack' ) } | ||
</Button> | ||
<form className={ classNames( styles[ 'connect-form' ], { [ styles.small ]: isSmall } ) }> | ||
{ 'mastodon' === service.name ? ( | ||
<input | ||
required | ||
type="text" | ||
aria-label={ __( 'Mastodon username', 'jetpack' ) } | ||
placeholder={ '@[email protected]' } | ||
/> | ||
) : null } | ||
<Button type="submit" variant="primary"> | ||
{ __( 'Connect', 'jetpack' ) } | ||
</Button> | ||
</form> | ||
<ConnectForm | ||
service={ service } | ||
isSmall={ isSmall } | ||
onConfirm={ onConfirm } | ||
displayInputs | ||
isMastodonAlreadyConnected={ isMastodonAlreadyConnected } | ||
/> | ||
</div> | ||
</> | ||
); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.