-
Notifications
You must be signed in to change notification settings - Fork 2k
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 App Banner deep links for iOS universal links #26118
Changes from 1 commit
90a671b
b3a61e4
0bf0072
8585878
9dc9335
9660a35
5f5eb76
60af3bb
fc21712
3ed9cf0
3f7911e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ import { | |
STATS, | ||
getAppBannerData, | ||
getNewDismissTimes, | ||
getCurrentPathFragment, | ||
getCurrentSection, | ||
isDismissed, | ||
APP_BANNER_DISMISS_TIMES_PREFERENCE, | ||
|
@@ -115,7 +116,7 @@ class AppBanner extends Component { | |
}; | ||
|
||
getDeepLink() { | ||
const { currentSection } = this.props; | ||
const { currentPathFragment, currentSection } = this.props; | ||
|
||
if ( this.isAndroid() ) { | ||
//TODO: update when section deep links are available. | ||
|
@@ -131,9 +132,21 @@ class AppBanner extends Component { | |
} | ||
} | ||
|
||
//TODO: update when deferred deep links are available | ||
if ( this.isiOS() ) { | ||
return 'itms://itunes.apple.com/us/app/wordpress/id335703880?mt=8'; | ||
switch ( currentSection ) { | ||
case EDITOR: | ||
return 'https://apps.wordpress.com/get#post'; | ||
case NOTES: | ||
return 'https://apps.wordpress.com/get#notifications'; | ||
case READER: | ||
if ( currentPathFragment.length === 0 ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are we special-casing the Reader with the fragment length check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Reader doesn't have its own path when you view it on the web – so the root of the Reader just sits at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm. it's still a bit unclear how this is supposed to function. if Reader is a special exception then I think it begs for a strong explanatory comment otherwise someone will come here and trash the code at some point in the future unless it's obvious why it's there 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely adding a comment makes sense. I'll try and explain here a bit more clearly too with a couple of examples:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A one line comment should be sufficient. We basically want WordPress.com root or There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Essentially – I've added an explanatory comment to the code. |
||
return 'https://apps.wordpress.com/get#read'; | ||
} | ||
|
||
return 'https://apps.wordpress.com/get#' + currentPathFragment; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional, but temperate literals are a bit easier to read than string concat. eg: return `https://apps.wordpress.com/get#${ currentPathFragment }`; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! With my outdated JavaScript knowledge, I didn't know this was a thing :) Definitely looks nicer. |
||
case STATS: | ||
return 'https://apps.wordpress.com/get#' + currentPathFragment; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a more stable way of dealing with the fragment could be to encode the actual URL in its own transport and let the app disambiguate. I think at least we need some clarification in an explanatory comment why we're passing the fragment and path like this. for instance, imagine a fully-controlled URL… const routing = encodeURIComponent( JSON.stringify( {
section: 'post',
previousFragment: currentPathFragment,
} );
return `https://apps.wordpress.com/get?routing=${ routing }` and we can make a helper for it… const urlFor = section => `https://apps.wordpress.com/get?${ encodeURIComponent( JSON.stringify( {
section,
previousFragment: currentPathFragment,
} ) ) }`;
case EDITOR:
return urlFor( 'post' );
case NOTES:
return urlFor( 'notifications' );
case READER:
return urlFor( 'read' ); something like that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can certainly test that. The main benefit of passing the path in the way I am currently is that on the app side of things I can just pass the path directly to our routing mechanism for deep linked URLs coming from WordPress.com. It wouldn't be too much extra work to parse the necessary parts out of this type of URL though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't block on this @dmsnell :) though refactors are welcome. The simple mapping here is easy enough to read. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm mainly concerned about bugs due to encoding issues in the URL we're assuming a lot if we push out the just want to make sure that we at least recognize the places this will tend to break and determine how to or how much to mitigate them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch @dmsnell! I totally forgot about that. The spec is a bit hard to interpret https://tools.ietf.org/html/rfc3986#section-3.5, but you're right that we need to escape. https://stackoverflow.com/a/2849834
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for raising this. I've used |
||
} | ||
|
||
return null; | ||
|
@@ -201,6 +214,7 @@ const mapStateToProps = state => { | |
return { | ||
dismissedUntil: getPreference( state, APP_BANNER_DISMISS_TIMES_PREFERENCE ), | ||
currentSection: getCurrentSection( sectionName, isNotesOpen ), | ||
currentPathFragment: getCurrentPathFragment( state ), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider passing through Note that the current route may be null, so be careful with string operations. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I've removed this dependency and added some null checking. |
||
fetchingPreferences: isFetchingPreferences( state ), | ||
siteId: getSelectedSiteId( state ), | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ | |
|
||
import { get, includes, reduce } from 'lodash'; | ||
|
||
import getCurrentRoute from 'state/selectors/get-current-route'; | ||
|
||
export const APP_BANNER_DISMISS_TIMES_PREFERENCE = 'appBannerDismissTimes'; | ||
export const EDITOR = 'post-editor'; | ||
export const NOTES = 'notifications'; | ||
|
@@ -61,6 +63,13 @@ export function getCurrentSection( currentSection, isNotesOpen ) { | |
return null; | ||
} | ||
|
||
export function getCurrentPathFragment( state ) { | ||
const route = getCurrentRoute( state ); | ||
|
||
// Strip off the leading forward slash for use as a fragment | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an example of the input data could make this comment much more useful to an unfamiliar reader - what does // strip off the leading forward-slash for use as a fragment
// e.g. /settings/mysite.wordpress.com -> settings/mysite.wordpress.com also, why are we stripping the slash? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely agree with the clearer example. If I'm completely honest, there's reason for stripping the leading slash other than I thought it looked nicer. I understand that's not a great reason, and perhaps it'd be best to just leave it in there :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like a bit of overkill to add this trivial util function before we have a second instance, it's easy enough to strip a leading slash in the deep link function as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is technically a selector too, which would normally live in |
||
return route.substring( 1 ); | ||
} | ||
|
||
export function getNewDismissTimes( dismissedSection, currentDismissTimes ) { | ||
const currentTime = Date.now(); | ||
const aWeekFromNow = currentTime + ONE_WEEK_IN_MILLISECONDS; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to verify that we return the correct app links, consider adding a unit test. It's fine to pull this switch out into it's own function (makes it easier to test).
And in the test file:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks – I've pulled out a function and added some tests!