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

[Jetpack App Migration] Update App Banner Branding #67013

Merged
merged 26 commits into from Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5a9f107
Create separate banners for the WP and JP apps
SiobhyB Aug 25, 2022
b628afe
Clean up: readability spacing, delete stray return
SiobhyB Aug 25, 2022
342472b
Add lottie-web as a dependency, for animations
SiobhyB Aug 25, 2022
ad5b7f2
Update wording in banner's buttons for clarity
SiobhyB Aug 25, 2022
4de9246
Remove circles in background from Jetpack banner
SiobhyB Aug 25, 2022
5feb2d3
Add animated icon to Jetpack app banner
SiobhyB Aug 25, 2022
4972b9b
Replace 'react-lottie-player' for performance
SiobhyB Aug 27, 2022
8e94544
Use stripped back version of lottie dependency
SiobhyB Aug 27, 2022
faddc8f
Style Jerpack banner
SiobhyB Aug 27, 2022
889a31a
Rename component for clarity
SiobhyB Aug 27, 2022
02511ed
Update Android intents for Jetpack app
SiobhyB Aug 27, 2022
f11dbaf
Remove additional, unwanted padding
SiobhyB Aug 27, 2022
3110f6e
Add RTL versions of animated icons
SiobhyB Aug 27, 2022
0eb4baf
Merge branch 'trunk' into update/app-banner-branding
SiobhyB Aug 29, 2022
a0aac12
Styling tweaks to Jetpack app banner
SiobhyB Aug 30, 2022
9f44d20
Android deep links: Update intent URI for Jetpack
SiobhyB Aug 30, 2022
0242520
Merge branch 'trunk' into update/app-banner-branding
SiobhyB Aug 30, 2022
6c7a31f
Fix broken unit tests by installing canvas
SiobhyB Aug 30, 2022
0f6ba29
Make code more concise
SiobhyB Aug 31, 2022
28730f1
Replace hook with HOC, for easier usage in class
SiobhyB Aug 31, 2022
e385f51
Separate the Jetpack and WordPress banners
SiobhyB Aug 31, 2022
b86c13e
List dependency for useEffect hook
SiobhyB Sep 1, 2022
51b4302
Avoid possible memory leak by destroying animation
SiobhyB Sep 1, 2022
4b4f68a
Use 'compose' to group component wrappers
SiobhyB Sep 1, 2022
606c625
Update text width/styling for smaller screens
SiobhyB Sep 1, 2022
d9ac75e
Replace 'canvas' with 'jest-canvas-mock'
SiobhyB Sep 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 91 additions & 12 deletions client/blocks/app-banner/index.jsx
@@ -1,9 +1,12 @@
import config from '@automattic/calypso-config';
import { Button, Card } from '@automattic/components';
import { compose } from '@wordpress/compose';
import classNames from 'classnames';
import { localize } from 'i18n-calypso';
import { localize, withRtl } from 'i18n-calypso';
import { get } from 'lodash';
import lottie from 'lottie-web/build/player/lottie_light';
noahtallen marked this conversation as resolved.
Show resolved Hide resolved
import PropTypes from 'prop-types';
import { Component } from 'react';
import { Component, useEffect } from 'react';
import ReactDom from 'react-dom';
import { connect } from 'react-redux';
import TrackComponentView from 'calypso/lib/analytics/track-component-view';
Expand Down Expand Up @@ -121,16 +124,22 @@ export class AppBanner extends Component {
const { currentRoute, currentSection } = this.props;

if ( this.isAndroid() ) {
const displayJetpackAppBranding = config.isEnabled( 'jetpack/app-branding' );
const scheme = displayJetpackAppBranding ? 'jetpack' : 'wordpress';
const packageName = displayJetpackAppBranding
? 'com.jetpack.android'
: 'org.wordpress.android';

//TODO: update when section deep links are available.
switch ( currentSection ) {
case GUTENBERG:
return 'intent://post/#Intent;scheme=wordpress;package=org.wordpress.android;end';
return `intent://post/#Intent;scheme=${ scheme };package=${ packageName };end`;
case NOTES:
return 'intent://notifications/#Intent;scheme=wordpress;package=org.wordpress.android;end';
return `intent://notifications/#Intent;scheme=${ scheme };package=${ packageName };end`;
case READER:
return 'intent://read/#Intent;scheme=wordpress;package=org.wordpress.android;end';
return `intent://read/#Intent;scheme=${ scheme };package=${ packageName };end`;
case STATS:
return 'intent://stats/#Intent;scheme=wordpress;package=org.wordpress.android;end';
return `intent://stats/#Intent;scheme=${ scheme };package=${ packageName };end`;
}
}

Expand All @@ -141,12 +150,51 @@ export class AppBanner extends Component {
return null;
}

render() {
const { translate, currentSection } = this.props;
if ( ! this.props.shouldDisplayAppBanner || this.state.isDraftPostModalShown ) {
return null;
}
getJetpackAppBanner = ( { translate, currentSection, isRtl } ) => {
const { title, copy, icon } = getAppBannerData( translate, currentSection, isRtl );

return (
<div className={ classNames( 'app-banner-overlay' ) } ref={ this.preventNotificationsClose }>
<Card
className={ classNames( 'app-banner', 'is-compact', currentSection, 'jetpack' ) }
ref={ this.preventNotificationsClose }
>
<TrackComponentView
eventName="calypso_mobile_app_banner_impression"
eventProperties={ {
page: currentSection,
} }
statGroup="calypso_mobile_app_banner"
statName="impression"
/>
<BannerIcon icon={ icon } />
<div className="app-banner__text-content jetpack">
<div className="app-banner__title jetpack">
<span> { title } </span>
</div>
<div className="app-banner__copy jetpack">
<span> { copy } </span>
</div>
</div>
<div className="app-banner__buttons jetpack">
<Button
primary
className="app-banner__open-button jetpack"
onClick={ this.openApp }
href={ this.getDeepLink() }
>
{ translate( 'Open in the Jetpack app' ) }
</Button>
<Button className="app-banner__no-thanks-button jetpack" onClick={ this.dismiss }>
{ translate( 'Continue in browser' ) }
</Button>
</div>
</Card>
</div>
);
};

getWordpressAppBanner = ( { translate, currentSection } ) => {
const { title, copy } = getAppBannerData( translate, currentSection );

return (
Expand Down Expand Up @@ -190,9 +238,36 @@ export class AppBanner extends Component {
</Card>
</div>
);
};

render() {
if ( ! this.props.shouldDisplayAppBanner || this.state.isDraftPostModalShown ) {
return null;
}

const displayJetpackAppBranding = config.isEnabled( 'jetpack/app-branding' );

return displayJetpackAppBranding
? this.getJetpackAppBanner( this.props )
: this.getWordpressAppBanner( this.props );
}
}

function BannerIcon( { icon } ) {
useEffect( () => {
const animation = lottie.loadAnimation( {
Copy link
Member

Choose a reason for hiding this comment

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

Just learning about Lottie and I had a question: does the library take into account @media/prefers-reduced-motion setting out of the box or would that need extra attention here?

Copy link
Member

Choose a reason for hiding this comment

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

My understanding is that, no, Lottie does not take into account motion preferences.

You raise a good point. It's an opportunity to improve this new feature. I would imagine we should render the last frame of the animation when reduced motion is preferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this! I'll work on a PR to take reduced animation preferences into account. 🙇‍♀️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To tie up all the loose ends, I've gone ahead to create that PR here: #67826

container: document.querySelector( '.app-banner__icon' ),
renderer: 'svg',
loop: false,
autoplay: true,
path: icon,
} );
return () => animation.destroy();
}, [ icon ] );

return <div className="app-banner__icon"></div>;
}

export function getiOSDeepLink( currentRoute, currentSection ) {
const baseURI = 'https://apps.wordpress.com/get?campaign=calypso-open-in-app';
const fragment = buildDeepLinkFragment( currentRoute, currentSection );
Expand Down Expand Up @@ -274,4 +349,8 @@ const mapDispatchToProps = {
dismissAppBanner,
};

export default connect( mapStateToProps, mapDispatchToProps )( localize( AppBanner ) );
export default compose(
connect( mapStateToProps, mapDispatchToProps ),
withRtl,
localize
)( AppBanner );
50 changes: 50 additions & 0 deletions client/blocks/app-banner/style.scss
Expand Up @@ -30,6 +30,12 @@ body.app-banner-is-visible {
margin-bottom: 0;
box-shadow: 3px -2px 24px 4px rgba( 0, 0, 0, 0.29 );
overflow: hidden;

&.jetpack {
color: var( --color-neutral-100 );
padding: 30px 24px;
text-align: center;
}
}

.app-banner__circle {
Expand Down Expand Up @@ -63,21 +69,50 @@ body.app-banner-is-visible {
}
}

.app-banner__icon {
height: 50px;
width: 93px;
margin: auto;
}

.app-banner__text-content {
width: 100%;

&.jetpack {
letter-spacing: -0.4px;
margin: 30px auto 0;
}
}

.app-banner__title {
/* stylelint-disable-next-line */
font-size: rem( 22px ); //typography-exception
font-family: $brand-serif;
line-height: 30px;

&.jetpack {
/* stylelint-disable-next-line */
font-size: rem( 28px ); //typography-exception
font-weight: bold;
max-width: 18em;
margin-left: auto;
margin-right: auto;
}
}

.app-banner__copy {
margin-top: 12px;
/* stylelint-disable-next-line */
font-size: rem( 15px ); //typography-exception

&.jetpack {
/* stylelint-disable-next-line */
font-size: rem( 16px ); //typography-exception
line-height: 21px;
max-width: 18em;
margin-left: auto;
margin-right: auto;
}
}

.app-banner__buttons {
Expand All @@ -90,10 +125,25 @@ body.app-banner-is-visible {
border: 0;
border-radius: 4px; /* stylelint-disable-line */
margin-right: 10px;

&.jetpack {
background-color: var( --color-jetpack );
}
}

.button.app-banner__no-thanks-button {
background: none;
border: 0;
color: var( --color-text-subtle );

&.jetpack {
color: var( --color-text );
}
}

.button.jetpack {
width: 100%;
max-width: 366px;
margin: auto;
display: block;
}
7 changes: 6 additions & 1 deletion client/blocks/app-banner/utils.js
Expand Up @@ -13,36 +13,41 @@ export const ONE_MONTH_IN_MILLISECONDS = 2419200000; // 28 days
export const TWO_WEEKS_IN_MILLISECONDS = 1209600000;
export const ONE_DAY_IN_MILLISECONDS = 86400000;

export function getAppBannerData( translate, sectionName ) {
export function getAppBannerData( translate, sectionName, isRTL ) {
switch ( sectionName ) {
case GUTENBERG:
return {
title: translate( 'Rich mobile publishing.' ),
copy: translate(
'A streamlined editor with faster, simpler image uploading? Check and mate.'
),
icon: `/calypso/animations/app-promo/wp-to-jp${ isRTL ? '-rtl' : '' }.json`,
};
case NOTES:
return {
title: translate( 'Watch engagement happening.' ),
copy: translate(
'Is your new post a hit? With push notifications, see reactions as they roll in.'
),
icon: `/calypso/animations/app-promo/jp-notifications${ isRTL ? '-rtl' : '' }.json`,
};
case READER:
return {
title: translate( 'Read posts, even offline.' ),
copy: translate( 'Catch up with new posts on the go or save them to read offline.' ),
icon: `/calypso/animations/app-promo/jp-reader${ isRTL ? '-rtl' : '' }.json`,
};
case STATS:
return {
title: translate( 'Stats at your fingertips.' ),
copy: translate( 'See your real-time stats anytime, anywhere.' ),
icon: `/calypso/animations/app-promo/jp-stats${ isRTL ? '-rtl' : '' }.json`,
};
default:
return {
title: '',
copy: '',
icon: '',
};
}
}
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -191,6 +191,7 @@
"i18n-calypso": "workspace:^",
"i18n-calypso-cli": "workspace:^",
"lodash": "^4.17.21",
"lottie-web": "^5.9.6",
"photon": "workspace:^",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down Expand Up @@ -246,6 +247,7 @@
"gzip-size": "^6.0.0",
"husky": "^7.0.4",
"jest": "^27.3.1",
"jest-canvas-mock": "^2.4.0",
"jest-environment-jsdom": "^27.3.1",
"jest-teamcity": "^1.9.0",
"loader-utils": "^1.2.3",
Expand Down