| @@ -1,18 +1,102 @@ | ||
| 1 | -import { useEffect, useState } from 'react'; | |
| 2 | -import { fetchRefreshToken } from '../api/wordpressApiClient'; | |
| 1 | +import React from 'react'; | |
| 2 | +import { useEffect, useRef, useState } from 'react'; | |
| 3 | +import { __ } from '@wordpress/i18n'; | |
| 4 | +import { fetchAccessToken } from '../api/wordpressApiClient'; | |
| 3 | 5 | import { getOrCreateBackgroundApp } from './backgroundAppUtils'; |
| 4 | 6 | import { isRefreshTokenAvailable } from './isRefreshTokenAvailable'; |
| 7 | +import { reportEmbedderUnavailable, whenEmbedderReady } from './embedderReady'; | |
| 8 | +import ErrorHandler from '../shared/Common/ErrorHandler'; | |
| 5 | 9 | |
| 6 | 10 | export function useGetEmbedder() { |
| 7 | 11 | const [embedder, setEmbedder] = useState<any>(null); |
| 12 | + const [errorStatus, setErrorStatus] = useState<number | null>(null); | |
| 13 | + const cancelWaitRef = useRef<(() => void) | null>(null); | |
| 14 | + const mountedRef = useRef(true); | |
| 8 | 15 | |
| 16 | + const loadEmbedder = () => { | |
| 17 | + fetchAccessToken() | |
| 18 | + .then( | |
| 19 | + ({ | |
| 20 | + accessToken, | |
| 21 | + expiresIn, | |
| 22 | + }: { | |
| 23 | + accessToken: string; | |
| 24 | + expiresIn: number; | |
| 25 | + }) => { | |
| 26 | + if (!mountedRef.current) return; | |
| 27 | + | |
| 28 | + const startedAt = Date.now(); | |
| 29 | + const { promise, cancel } = whenEmbedderReady(); | |
| 30 | + | |
| 31 | + cancelWaitRef.current = cancel; | |
| 32 | + | |
| 33 | + return promise.then(isReady => { | |
| 34 | + cancelWaitRef.current = null; | |
| 35 | + | |
| 36 | + if (!mountedRef.current) return; | |
| 37 | + | |
| 38 | + const app = isReady | |
| 39 | + ? getOrCreateBackgroundApp(accessToken, expiresIn) | |
| 40 | + : null; | |
| 41 | + | |
| 42 | + if (app) { | |
| 43 | + console.info('HubSpot plugin - embedder ready, rendering widget'); | |
| 44 | + setEmbedder(app); | |
| 45 | + } else { | |
| 46 | + reportEmbedderUnavailable(Date.now() - startedAt); | |
| 47 | + setErrorStatus(500); | |
| 48 | + } | |
| 49 | + }); | |
| 50 | + } | |
| 51 | + ) | |
| 52 | + .catch((err: any) => { | |
| 53 | + if (!mountedRef.current) return; | |
| 54 | + | |
| 55 | + console.error( | |
| 56 | + 'HubSpot plugin - access token request failed', | |
| 57 | + (err && err.status) || 'no status' | |
| 58 | + ); | |
| 59 | + setErrorStatus((err && err.status) || 500); | |
| 60 | + }); | |
| 61 | + }; | |
| 62 | + | |
| 9 | 63 | useEffect(() => { |
| 10 | 64 | if (isRefreshTokenAvailable()) { |
| 11 | - fetchRefreshToken().then(({ refreshToken }: { refreshToken: string }) => { | |
| 12 | - setEmbedder(getOrCreateBackgroundApp(refreshToken)); | |
| 13 | - }); | |
| 65 | + loadEmbedder(); | |
| 14 | 66 | } |
| 67 | + | |
| 68 | + return () => { | |
| 69 | + mountedRef.current = false; | |
| 70 | + if (cancelWaitRef.current) { | |
| 71 | + cancelWaitRef.current(); | |
| 72 | + cancelWaitRef.current = null; | |
| 73 | + } | |
| 74 | + }; | |
| 15 | 75 | }, []); |
| 16 | 76 | |
| 17 | - return embedder; | |
| 77 | + const errorElement = | |
| 78 | + errorStatus !== null | |
| 79 | + ? React.createElement(ErrorHandler, { | |
| 80 | + status: errorStatus, | |
| 81 | + resetErrorState: () => { | |
| 82 | + setErrorStatus(null); | |
| 83 | + loadEmbedder(); | |
| 84 | + }, | |
| 85 | + errorInfo: { | |
| 86 | + header: __('Unable to load HubSpot', 'leadin'), | |
| 87 | + message: __( | |
| 88 | + 'There was a problem connecting to HubSpot. Please try again.', | |
| 89 | + 'leadin' | |
| 90 | + ), | |
| 91 | + action: __('Retry', 'leadin'), | |
| 92 | + }, | |
| 93 | + }) | |
| 94 | + : null; | |
| 95 | + | |
| 96 | + return { | |
| 97 | + embedder, | |
| 98 | + errorElement, | |
| 99 | + isLoading: | |
| 100 | + isRefreshTokenAvailable() && embedder === null && errorStatus === null, | |
| 101 | + }; | |
| 18 | 102 | } |