Skip to content

Commit

Permalink
Social: Create a social service connect button
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pablinos committed May 8, 2024
1 parent 507cf65 commit b8d5b9b
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 4 deletions.
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions projects/js-packages/publicize-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import './src/social-store';

export { default as Connection } from './src/components/connection';
export { default as ConnectionVerify } from './src/components/connection-verify';
export { default as ConnectButton } from './src/components/connect-button';
export { default as Form } from './src/components/form';
export { default as SocialPreviewsModal } from './src/components/social-previews/modal';
export { default as SocialPreviewsPanel } from './src/components/social-previews/panel';
Expand Down
1 change: 1 addition & 0 deletions projects/js-packages/publicize-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface Connection {
description: string;
name: string;
examples?: Array< React.ComponentType >;
connectUrl?: string;
}

export const getSupportedConnections = (): Connection[] => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,34 @@ import { __, sprintf } from '@wordpress/i18n';
import { Icon, chevronDown } from '@wordpress/icons';
import classNames from 'classnames';
import { useCallback, useState } from 'react';
import { store } from '../../social-store';
import ConnectButton from '../connect-button';
import { ConnectPage } from './connect-page/connect-page';
import { getSupportedConnections } from './constants';
import styles from './style.module.scss';

const AddConnectionModal = ( { onCloseModal } ) => {
const supportedServices = useSelect( select => {
const supportedConnections = getSupportedConnections();
const services = select( store )
.getServices()
.filter( service => service.type === 'publicize' )
.reduce(
( serviceData, service ) => ( {
...serviceData,
[ service.ID ]: service.connect_Url,
} ),
{}
);

return supportedConnections
.filter( connection => Object.hasOwn( services, connection.name ) )
.map( connection => {
connection.connectUrl = services[ connection.name ];
return connection;
} );
}, [] );

const [ currentService, setCurrentService ] = useState( null );

const [ isSmall ] = useBreakpointMatch( 'sm' );
Expand Down Expand Up @@ -53,7 +76,7 @@ const AddConnectionModal = ( { onCloseModal } ) => {
</tr>
</thead>
<tbody>
{ getSupportedConnections().map( service => (
{ supportedServices.map( service => (
<tr key={ service.name }>
<td>
<service.icon iconSize={ isSmall ? 36 : 48 } />
Expand All @@ -70,9 +93,12 @@ const AddConnectionModal = ( { onCloseModal } ) => {
</td>
<td>
<div className={ styles[ 'column-actions' ] }>
<Button type="submit" variant="primary" size={ isSmall ? 'small' : 'normal' }>
{ __( 'Connect', 'jetpack' ) }
</Button>
<ConnectButton
connectUrl={ service.connectUrl }
onClose={ res => console.log( res ) }
key={ service.name }
size={ isSmall ? 'small' : 'normal' }
/>
<Button
size={ isSmall ? 'small' : 'normal' }
className={ styles[ 'chevron-button' ] }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Button } from '@automattic/jetpack-components';
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { requestExternalAccess } from '../../utils/request-external-access.js';

const ConnectButton = ( { connectUrl, onClose, className = null, size = 'normal' } ) => {
const requestConnection = useCallback(
() => requestExternalAccess( connectUrl, onClose ),
[ connectUrl, onClose ]
);
return (
<Button className={ className } variant="primary" onClick={ requestConnection } size={ size }>
{ __( 'Connect', 'jetpack' ) }
</Button>
);
};

export default ConnectButton;
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,14 @@ export function getConnectionProfileDetails( state, service, { forceDefaults = f

return { displayName, profileImage, username };
}

/**
* Returns the services list from the store.
*
* @param {import("../types").SocialStoreState} state - State object.
*
* @returns {Array} The services list
*/
export function getServices( state ) {
return state.connectionData?.services ?? [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type JetpackSettingsSelectors = {

type ConnectionDataSelectors = {
getConnections: () => Array< object >;
getServices: () => Array< object >;
getConnectionsAdminUrl: () => string;
hasConnections: () => boolean;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './get-share-message-max-length';
export * from './get-supported-additional-connections';
export * from './request-external-access';
export * from './types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import PopupMonitor from '@automattic/popup-monitor';

/**
* The callback function of the requestExternalAccess utility.
* @callback requestCallback
* @param {object} result - Received authentication data.
* @param {number} result.keyring_id
* @param {string} result.id_token
* @param {object} result.user
*/

/**
* Utility for requesting authorization of sharing services.
* @param {string} url - The URL to be loaded in the newly opened window.
* @param {requestCallback} cb - The callback that handles the response.
*/
export const requestExternalAccess = ( url, cb ) => {
const popupMonitor = new PopupMonitor();
let lastMessage;

popupMonitor.open(
url,
null,
'toolbar=0,location=0,status=0,menubar=0,' + popupMonitor.getScreenCenterSpecs( 780, 700 )
);

popupMonitor.once( 'close', () => {
cb( lastMessage?.ID ? lastMessage : {} );
} );

popupMonitor.on( 'message', message => {
lastMessage = message?.data;
} );
};
16 changes: 16 additions & 0 deletions projects/plugins/social/src/class-jetpack-social.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Automattic\Jetpack\Admin_UI\Admin_Menu;
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Connection\Rest_Authentication as Connection_Rest_Authentication;
Expand Down Expand Up @@ -256,6 +257,7 @@ public function initial_state() {
'connectionData' => array(
'connections' => $publicize->get_all_connections_for_user(), // TODO: Sanitize the array
'adminUrl' => esc_url_raw( $publicize->publicize_connections_url( 'jetpack-social-connections-admin-page' ) ),
'services' => $this->get_services(),
),
'sharesData' => $publicize->get_publicize_shares_info( Jetpack_Options::get_option( 'id' ) ),
),
Expand All @@ -266,6 +268,20 @@ public function initial_state() {
return $state;
}

public function get_services() {

Check failure on line 271 in projects/plugins/social/src/class-jetpack-social.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Missing doc comment for function get_services() (Squiz.Commenting.FunctionComment.Missing)
$site_id = Connection_Manager::get_site_id();
if ( is_wp_error( $site_id ) ) {
return [];

Check failure on line 274 in projects/plugins/social/src/class-jetpack-social.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Short array syntax is not allowed (Universal.Arrays.DisallowShortArraySyntax.Found)
}
$path = sprintf( '/sites/%d/external-services', $site_id );
$response = Client::wpcom_json_api_request_as_user( $path );
if ( is_wp_error( $response ) ) {
return [];

Check failure on line 279 in projects/plugins/social/src/class-jetpack-social.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Short array syntax is not allowed (Universal.Arrays.DisallowShortArraySyntax.Found)
}
$body = json_decode( wp_remote_retrieve_body( $response ) );
return array_values( (array) $body->services ) ?? [];

Check failure on line 282 in projects/plugins/social/src/class-jetpack-social.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Short array syntax is not allowed (Universal.Arrays.DisallowShortArraySyntax.Found)
}

/**
* Returns a boolean as to whether we have a plan that supports
* sharing beyond the free limit.
Expand Down

0 comments on commit b8d5b9b

Please sign in to comment.