Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update/my jetpack status handling #37217

Merged
merged 24 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
99461b2
improve the active/ inactive status handling in My Jetpack with bette…
jboland88 May 3, 2024
b36a9e1
changelog
jboland88 May 3, 2024
1b38ee4
Merge branch 'trunk' into update/my-jetpack-status-handling
jboland88 May 3, 2024
b70404d
Don't yet remove extra product classes
jboland88 May 3, 2024
cd441bd
Add better handling for connection error states
jboland88 May 3, 2024
2ebf1ed
Add one more caveat to first site conneciton status
jboland88 May 3, 2024
6ea7237
Merge branch 'trunk' into update/my-jetpack-status-handling
jboland88 May 14, 2024
d7e5da1
Change condition for first site connection stauts
jboland88 May 14, 2024
7fe0ee5
Fix boost unit test in My Jetpack
jboland88 May 14, 2024
621424e
Version madness
jboland88 May 14, 2024
5a3fe56
Add some additional checks for products that have overrides of is_active
jboland88 May 15, 2024
9430da2
Adjustment to hybrid module activation
jboland88 May 15, 2024
e6bd972
Add more handling for when a product has a disabled module and no plan
jboland88 May 16, 2024
c467372
more updates for hybrid products
jboland88 May 16, 2024
5dfe8a9
Switch to explicit check for inactive module
jboland88 May 16, 2024
9ce0ff4
Additional check for module name
jboland88 May 17, 2024
d2b3169
Merge branch 'trunk' into update/my-jetpack-status-handling
jboland88 May 17, 2024
0ac7f9c
Merge branch 'trunk' into update/my-jetpack-status-handling
jboland88 May 21, 2024
33b7157
Version bump
jboland88 May 21, 2024
4b10c36
A few bugfixes
jboland88 May 21, 2024
c6a6d0e
update language on cards for missing user connection
jboland88 May 21, 2024
0b28264
Add a required plan check for disabled modules
jboland88 May 22, 2024
931d34e
Merge branch 'trunk' into update/my-jetpack-status-handling
jboland88 May 22, 2024
d3e7e7d
version management
jboland88 May 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ export const PRODUCT_STATUSES = {
ACTIVE: 'active',
INACTIVE: 'inactive',
MODULE_DISABLED: 'module_disabled',
ERROR: 'error',
SITE_CONNECTION_ERROR: 'site_connection_error',
ABSENT: 'plugin_absent',
ABSENT_WITH_PLAN: 'plugin_absent_with_plan',
NEEDS_PURCHASE: 'needs_purchase',
NEEDS_PURCHASE_OR_FREE: 'needs_purchase_or_free',
NEEDS_FIRST_SITE_CONNECTION: 'needs_first_site_connection',
USER_CONNECTION_ERROR: 'user_connection_error',
CAN_UPGRADE: 'can_upgrade',
};

Expand Down Expand Up @@ -90,6 +92,20 @@ const ActionButton = ( {
primaryActionOverride[ PRODUCT_STATUSES.ABSENT_WITH_PLAN ] ),
};
}
// The site or user have never been connected before and the connection is required
case PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION:
return {
...buttonState,
href: purchaseUrl || `#/add-${ slug }`,
size: 'small',
variant: 'primary',
weight: 'regular',
label: __( 'Learn more', 'jetpack-my-jetpack' ),
onClick: onAdd,
...( primaryActionOverride &&
PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION in primaryActionOverride &&
primaryActionOverride[ PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION ] ),
};
case PRODUCT_STATUSES.NEEDS_PURCHASE: {
return {
...buttonState,
Expand Down Expand Up @@ -152,7 +168,7 @@ const ActionButton = ( {
primaryActionOverride[ PRODUCT_STATUSES.ACTIVE ] ),
};
}
case PRODUCT_STATUSES.ERROR:
case PRODUCT_STATUSES.SITE_CONNECTION_ERROR:
return {
...buttonState,
href: '#/connection',
Expand All @@ -165,6 +181,18 @@ const ActionButton = ( {
PRODUCT_STATUSES.ERROR in primaryActionOverride &&
primaryActionOverride[ PRODUCT_STATUSES.ERROR ] ),
};
case PRODUCT_STATUSES.USER_CONNECTION_ERROR:
return {
href: '#/connection',
size: 'small',
variant: 'primary',
weight: 'regular',
label: __( 'Sign In', 'jetpack-my-jetpack' ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the wording of "Sign In" much more, but I noticed we've never really called in a sign-in anywhere else

In the connection footer we just call it "Connect"
image

and on the connection screen we say "Connect your user account"
image

on the auth screen if we are already logged in we just say "Approve"
image

and on the login screen we call it "log in" not "sign in"
image

and when connected, in the connection footer we say "Connected as" not "signed in as"
image

Overall it seems like we lack consistency in what we call a user connection on the frontend, and I don't think we'll fix that here, but we might want to go with one of the existing names for it rather than introducing yet another name for it, even though I do like "Sign in" much more than a lot of the others as far as clarity. Maybe we could just have it as "Connect" (since that's most of our messaging around it in My Jetpack) or "Log In" (since we use that on the actual auth screen when logging in)

I may be putting too much thought into this, let me know what you think!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the wording of "Sign In" much more, but I noticed we've never really called in a sign-in anywhere else

Good call - this is probably not the diff to change that in :) I'll update that to use the "connect" and "needs user connection" language.

onClick: onFixConnection,
...( primaryActionOverride &&
PRODUCT_STATUSES.USER_CONNECTION_ERROR in primaryActionOverride &&
primaryActionOverride[ PRODUCT_STATUSES.USER_CONNECTION_ERROR ] ),
};
case PRODUCT_STATUSES.INACTIVE:
case PRODUCT_STATUSES.MODULE_DISABLED:
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import styles from './style.module.scss';
export const PRODUCT_STATUSES_LABELS = {
[ PRODUCT_STATUSES.ACTIVE ]: __( 'Active', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.INACTIVE ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.MODULE_DISABLED ]: __( 'Module disabled', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.MODULE_DISABLED ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.NEEDS_PURCHASE ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.NEEDS_PURCHASE_OR_FREE ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.ABSENT ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.ABSENT_WITH_PLAN ]: __( 'Needs Plugin', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.ERROR ]: __( 'Needs connection', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION ]: __( 'Inactive', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.USER_CONNECTION_ERROR ]: __( 'Needs sign-in', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.SITE_CONNECTION_ERROR ]: __( 'Needs connection', 'jetpack-my-jetpack' ),
[ PRODUCT_STATUSES.CAN_UPGRADE ]: __( 'Active', 'jetpack-my-jetpack' ),
};

Expand Down Expand Up @@ -252,11 +254,13 @@ ProductCard.propTypes = {
status: PropTypes.oneOf( [
PRODUCT_STATUSES.ACTIVE,
PRODUCT_STATUSES.INACTIVE,
PRODUCT_STATUSES.ERROR,
PRODUCT_STATUSES.SITE_CONNECTION_ERROR,
PRODUCT_STATUSES.ABSENT,
PRODUCT_STATUSES.ABSENT_WITH_PLAN,
PRODUCT_STATUSES.NEEDS_PURCHASE,
PRODUCT_STATUSES.NEEDS_PURCHASE_OR_FREE,
PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION,
PRODUCT_STATUSES.USER_CONNECTION_ERROR,
PRODUCT_STATUSES.CAN_UPGRADE,
PRODUCT_STATUSES.MODULE_DISABLED,
] ).isRequired,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ const getStatusClassName = status => {
case PRODUCT_STATUSES.CAN_UPGRADE:
return styles.active;
case PRODUCT_STATUSES.ABSENT_WITH_PLAN:
case PRODUCT_STATUSES.SITE_CONNECTION_ERROR:
case PRODUCT_STATUSES.USER_CONNECTION_ERROR:
return styles.warning;
case PRODUCT_STATUSES.INACTIVE:
case PRODUCT_STATUSES.NEEDS_PURCHASE:
case PRODUCT_STATUSES.NEEDS_PURCHASE_OR_FREE:
return styles.inactive;
case PRODUCT_STATUSES.ERROR:
case PRODUCT_STATUSES.NEEDS_FIRST_SITE_CONNECTION:
return styles.inactive;
default:
return styles.inactive;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: changed

Improving the active/ inactive statuses on My Jetpack
2 changes: 1 addition & 1 deletion projects/packages/my-jetpack/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}"
},
"branch-alias": {
"dev-trunk": "4.23.x-dev"
"dev-trunk": "4.24.x-dev"
},
"version-constants": {
"::PACKAGE_VERSION": "src/class-initializer.php"
Expand Down
2 changes: 0 additions & 2 deletions projects/packages/my-jetpack/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ interface Window {
features: string[];
has_paid_plan_for_product: boolean;
features_by_tier: Array< string >;
has_required_plan: boolean;
has_required_tier: Array< string >;
is_bundle: boolean;
is_plugin_active: boolean;
is_upgradable_by_bundle: string[];
Expand Down
2 changes: 1 addition & 1 deletion projects/packages/my-jetpack/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@automattic/jetpack-my-jetpack",
"version": "4.23.3-alpha",
"version": "4.24.0-alpha",
"description": "WP Admin page with information and configuration shared among all Jetpack stand-alone plugins",
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/my-jetpack/#readme",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion projects/packages/my-jetpack/src/class-initializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Initializer {
*
* @var string
*/
const PACKAGE_VERSION = '4.23.3-alpha';
const PACKAGE_VERSION = '4.24.0-alpha';

/**
* HTML container ID for the IDC screen on My Jetpack page.
Expand Down
2 changes: 1 addition & 1 deletion projects/packages/my-jetpack/src/class-products.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public static function get_product_data_schema() {
'status' => array(
'title' => 'The product status',
'type' => 'string',
'enum' => array( 'active', 'inactive', 'plugin_absent', 'needs_purchase', 'needs_purchase_or_free', 'error' ),
'enum' => array( 'active', 'inactive', 'plugin_absent', 'needs_purchase', 'needs_purchase_or_free', 'needs_first_site_connection', 'user_connection_error', 'site_connection_error' ),
),
'class' => array(
'title' => 'The product class handler',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ public static function get_features() {

/**
* Determine if the site has an Akismet plan by checking for an API key
* Note that some Akismet Plans are free - we're just checking for an API key and don't have the perspective of the plan attached to it here
*
* @return bool - whether an API key was found
*/
public static function has_required_plan() {
public static function has_paid_plan_for_product() {
// Check if the site has an API key for Akismet
$akismet_api_key = apply_filters( 'akismet_get_api_key', defined( 'WPCOM_API_KEY' ) ? constant( 'WPCOM_API_KEY' ) : get_option( 'wordpress_api_key' ) );
$fallback = ! empty( $akismet_api_key );
Expand Down
18 changes: 8 additions & 10 deletions projects/packages/my-jetpack/src/products/class-backup.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ class Backup extends Hybrid_Product {
*/
public static $has_free_offering = false;

/**
* Whether this product requires a plan to work at all
*
* @var bool
*/
public static $requires_plan = true;

/**
* Get the product name
*
Expand Down Expand Up @@ -190,7 +197,7 @@ private static function get_state_from_wpcom() {
*
* @return boolean
*/
public static function has_required_plan() {
public static function has_paid_plan_for_product() {
$rewind_data = static::get_state_from_wpcom();
if ( is_wp_error( $rewind_data ) ) {
return false;
Expand Down Expand Up @@ -231,13 +238,4 @@ public static function get_manage_url() {
return Redirect::get_url( 'my-jetpack-manage-backup' );
}
}

/**
* Checks whether the Product is active
*
* @return boolean
*/
public static function is_active() {
return parent::is_active() && static::has_required_plan();
}
}
5 changes: 2 additions & 3 deletions projects/packages/my-jetpack/src/products/class-creator.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ public static function get_wpcom_monthly_product_slug() {
*
* @return boolean
*/
public static function has_required_plan() {
public static function has_paid_plan_for_product() {
$purchases_data = Wpcom_Products::get_site_current_purchases();
if ( is_wp_error( $purchases_data ) ) {
return false;
Expand All @@ -345,7 +345,6 @@ public static function has_required_plan() {
* @return boolean
*/
public static function is_upgradable() {
$has_required_plan = self::has_required_plan();
return ! $has_required_plan;
return ! self::has_paid_plan_for_product();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,13 @@ public static function do_product_specific_activation( $product_activation ) {
}
}

// Only activate the module if the plan supports it
// We don't want to throw an error for a missing plan here since we try activation before purchase
if ( static::has_required_plan() && static::$module_name ) {
if ( ! empty( static::$module_name ) ) {
// Only activate the module if the plan supports it
// We don't want to throw an error for a missing plan here since we try activation before purchase
if ( static::$requires_plan && ! static::has_any_plan_for_product() ) {
return true;
}

$module_activation = ( new Modules() )->activate( static::$module_name, false, false );

if ( ! $module_activation ) {
Expand Down Expand Up @@ -156,7 +160,7 @@ public static function install_and_activate_standalone() {
* Activate the module as well, if the user has a plan
* or the product does not require a plan to work
*/
if ( static::has_required_plan() && static::$module_name ) {
if ( static::has_any_plan_for_product() && isset( static::$module_name ) ) {
$module_activation = ( new Modules() )->activate( static::$module_name, false, false );

if ( ! $module_activation ) {
Expand Down
29 changes: 20 additions & 9 deletions projects/packages/my-jetpack/src/products/class-jetpack-ai.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static function get_tiers() {
*/
public static function get_features_by_tier() {
$current_tier = self::get_current_usage_tier();
$current_description = $current_tier === 0
$current_description = 0 === $current_tier
? __( 'Up to 20 requests', 'jetpack-my-jetpack' )
/* translators: number of requests */
: sprintf( __( 'Up to %d requests per month', 'jetpack-my-jetpack' ), $current_tier );
Expand Down Expand Up @@ -179,7 +179,7 @@ public static function get_current_usage_tier() {

// Bail early if it's not possible to fetch the feature data.
if ( is_wp_error( $info ) ) {
return null;
return 0;
}

$current_tier = isset( $info['current-tier']['value'] ) ? $info['current-tier']['value'] : null;
Expand All @@ -193,7 +193,7 @@ public static function get_current_usage_tier() {
* @return int
*/
public static function get_next_usage_tier() {
if ( ! self::is_site_connected() || ! self::has_required_plan() ) {
if ( ! self::is_site_connected() || ! self::has_paid_plan_for_product() ) {
return 100;
}

Expand Down Expand Up @@ -419,12 +419,23 @@ public static function get_wpcom_bi_yearly_product_slug() {
}

/**
* Checks whether the current plan (or purchases) of the site already supports the product
* Checks whether the site has a paid plan for this product
*
* @return boolean
*/
public static function has_required_plan() {
return static::does_site_have_feature( 'ai-assistant' );
public static function has_paid_plan_for_product() {
$purchases_data = Wpcom_Products::get_site_current_purchases();
if ( is_wp_error( $purchases_data ) ) {
return false;
}
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
foreach ( $purchases_data as $purchase ) {
if ( str_contains( $purchase->product_slug, 'jetpack_ai' ) ) {
return true;
}
}
}
return false;
}

/**
Expand All @@ -433,11 +444,11 @@ public static function has_required_plan() {
* @return boolean
*/
public static function is_upgradable() {
$has_required_plan = self::has_required_plan();
$current_tier = self::get_current_usage_tier();
$has_ai_feature = static::does_site_have_feature( 'ai-assistant' );
$current_tier = self::get_current_usage_tier();

// Mark as not upgradable if user is on unlimited tier or does not have any plan.
if ( ! $has_required_plan || null === $current_tier || 1 === $current_tier ) {
if ( ! $has_ai_feature || null === $current_tier || 1 === $current_tier ) {
return false;
}

Expand Down
Loading
Loading