22 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44
5- import React , { useRef , FormEventHandler , useEffect } from 'react' ;
5+ import React , { useRef , FormEventHandler , useEffect , useCallback } from 'react' ;
66import { FtlMsg } from 'fxa-react/lib/utils' ;
77
88import { ReactComponent as GoogleLogo } from './google-logo.svg' ;
@@ -18,6 +18,7 @@ export type ThirdPartyAuthProps = {
1818 onContinueWithApple ?: FormEventHandler < HTMLFormElement > ;
1919 showSeparator ?: boolean ;
2020 viewName ?: string ;
21+ deeplink ?: string ;
2122} ;
2223
2324/**
@@ -30,6 +31,7 @@ const ThirdPartyAuth = ({
3031 onContinueWithApple,
3132 showSeparator = true ,
3233 viewName = 'unknown' ,
34+ deeplink,
3335} : ThirdPartyAuthProps ) => {
3436 const config = useConfig ( ) ;
3537
@@ -76,6 +78,7 @@ const ThirdPartyAuth = ({
7678 </ FtlMsg >
7779 </ >
7880 ) ,
81+ deeplink
7982 } }
8083 />
8184 < ThirdPartySignInForm
@@ -98,6 +101,7 @@ const ThirdPartyAuth = ({
98101 </ FtlMsg >
99102 </ >
100103 ) ,
104+ deeplink
101105 } }
102106 />
103107 </ div >
@@ -125,6 +129,7 @@ const ThirdPartySignInForm = ({
125129 buttonText,
126130 onSubmit,
127131 viewName,
132+ deeplink
128133} : {
129134 party : 'google' | 'apple' ;
130135 authorizationEndpoint : string ;
@@ -139,11 +144,14 @@ const ThirdPartySignInForm = ({
139144 buttonText : ReactElement ;
140145 onSubmit ?: FormEventHandler < HTMLFormElement > ;
141146 viewName ?: string ;
147+ deeplink ?: string ;
142148} ) => {
143149 const { logViewEventOnce } = useMetrics ( ) ;
144150 const stateRef = useRef < HTMLInputElement > ( null ) ;
151+ const formRef = useRef < HTMLFormElement > ( null ) ;
152+ const isDeeplinking = deeplink !== undefined ;
145153
146- async function onClick ( ) {
154+ const onClick = useCallback ( async ( ) => {
147155 logViewEventOnce ( `flow.${ party } ` , 'oauth-start' ) ;
148156
149157 switch ( `${ party } -${ viewName } ` ) {
@@ -165,20 +173,40 @@ const ThirdPartySignInForm = ({
165173 case 'apple-signup' :
166174 GleanMetrics . thirdPartyAuth . startAppleAuthFromReg ( ) ;
167175 break ;
176+ case 'google-deeplink' :
177+ GleanMetrics . thirdPartyAuth . googleDeeplink ( ) ;
178+ break ;
179+ case 'apple-deeplink' :
180+ GleanMetrics . thirdPartyAuth . appleDeeplink ( ) ;
181+ break ;
168182 }
169183
170184 // wait for all the Glean events to be sent before the page unloads
171185 await GleanMetrics . isDone ( ) ;
172186
173- stateRef . current ! . value = getState ( ) ;
174- }
187+ if ( stateRef . current ) {
188+ stateRef . current . value = getState ( ) ;
189+ }
190+ } , [ party , viewName , logViewEventOnce ] ) ;
191+
175192
176193 if ( onSubmit === undefined ) {
177194 onSubmit = ( ) => true ;
178195 }
179196
197+ useEffect ( ( ) => {
198+ if ( deeplink && formRef . current ) {
199+ // Only deeplink if this is the correct button
200+ if ( ( deeplink === "googleLogin" && party === "google" ) || ( deeplink === "appleLogin" && party === "apple" ) ) {
201+ onClick ( ) ;
202+ formRef . current . submit ( ) ;
203+ }
204+ }
205+
206+ } , [ deeplink , onClick , party ] ) ;
207+
180208 return (
181- < form action = { authorizationEndpoint } method = "GET" onSubmit = { onSubmit } >
209+ < form action = { authorizationEndpoint } method = "GET" onSubmit = { onSubmit } ref = { formRef } >
182210 < input
183211 data-testid = { `${ party } -signin-form-state` }
184212 ref = { stateRef }
@@ -196,13 +224,15 @@ const ThirdPartySignInForm = ({
196224 < input type = "hidden" name = "response_mode" value = { responseMode } />
197225 ) }
198226
199- < button
200- type = "submit"
201- className = "w-full px-2 mt-2 justify-center text-black bg-transparent border-grey-300 border hover:border-black rounded-lg text-md text-center inline-flex items-center focus-visible-default outline-offset-2"
202- onClick = { onClick }
203- >
204- { buttonText }
205- </ button >
227+ { ! isDeeplinking ? (
228+ < button
229+ type = "submit"
230+ className = "w-full px-2 mt-2 justify-center text-black bg-transparent border-grey-300 border hover:border-black rounded-lg text-md text-center inline-flex items-center focus-visible-default outline-offset-2"
231+ onClick = { onClick }
232+ >
233+ { buttonText }
234+ </ button >
235+ ) : null }
206236 </ form >
207237 ) ;
208238} ;
@@ -213,7 +243,7 @@ function deleteParams(searchParams: URLSearchParams, paramsToDelete: string[]) {
213243}
214244
215245function getState ( ) {
216- // We stash originating location in the state oauth param
246+ // We stash the originating location in the state oauth param
217247 // because we will need it to use it to reconstruct the redirect URL for RP
218248 const params = new URLSearchParams ( window . location . search ) ;
219249 // we won't need these params that are used for internal backbone/react navigation
@@ -225,12 +255,11 @@ function getState() {
225255 'forceExperimentGroup' ,
226256 'showReactApp' ,
227257 ] ) ;
228- const state = encodeURIComponent (
258+ return encodeURIComponent (
229259 `${ window . location . origin } ${
230260 window . location . pathname
231261 } ?${ modifiedParams . toString ( ) } `
232262 ) ;
233- return state ;
234263}
235264
236265export default ThirdPartyAuth ;
0 commit comments