PluginProbe
HubSpot All-In-One Marketing – Forms, Popups, Live Chat / 11.3.75
HubSpot All-In-One Marketing – Forms, Popups, Live Chat v11.3.75
11.3.75 11.3.73 11.3.71 11.3.70 11.3.69 11.3.64 11.3.65 11.3.62 11.3.61 11.3.56 11.3.58 11.0.31 11.0.52 11.0.54 11.0.56 11.0.58 11.0.7 11.1.10 11.1.11 11.1.13 11.1.14 11.1.15 11.1.2 11.1.20 11.1.21 All 73 releases
← All changes | scripts/iframe/useAppEmbedder.ts +137 -12 11.0.711.3.75 View file →
@@ -1,8 +1,11 @@
1 1 import { useEffect } from 'react';
2 +import Raven from '../lib/Raven';
3 +
2 4 import {
3 5 accountName,
4 6 adminUrl,
7 + connectionStatus,
5 8 deviceId,
6 9 hubspotBaseUrl,
7 10 leadinQueryParams,
8 11 locale,
@@ -10,20 +13,83 @@
10 13 portalDomain,
11 14 portalEmail,
12 15 portalId,
13 16 reviewSkippedDate,
14 - refreshToken,
15 17 impactLink,
16 18 theme,
19 + lastAuthorizeTime,
20 + lastDeauthorizeTime,
21 + lastDisconnectTime,
17 22 leadinPluginVersion,
18 23 phpVersion,
19 24 wpVersion,
25 + contentEmbed,
26 + requiresContentEmbedScope,
27 + decryptError,
28 + LeadinConfig,
20 29 } from '../constants/leadinConfig';
30 +import { fetchAccessToken } from '../api/wordpressApiClient';
21 31 import { App, AppIframe } from './constants';
22 32 import { messageMiddleware } from './messageMiddleware';
23 33 import { resizeWindow, useIframeNotRendered } from '../utils/iframe';
24 34
25 -const getLeadinConfig = () => {
35 +type PartialLeadinConfig = Pick<
36 + LeadinConfig,
37 + | 'accountName'
38 + | 'adminUrl'
39 + | 'connectionStatus'
40 + | 'deviceId'
41 + | 'plugins'
42 + | 'portalDomain'
43 + | 'portalEmail'
44 + | 'portalId'
45 + | 'reviewSkippedDate'
46 + | 'refreshToken'
47 + | 'impactLink'
48 + | 'theme'
49 + | 'trackConsent'
50 + | 'lastAuthorizeTime'
51 + | 'lastDeauthorizeTime'
52 + | 'lastDisconnectTime'
53 + | 'leadinPluginVersion'
54 + | 'phpVersion'
55 + | 'wpVersion'
56 + | 'contentEmbed'
57 + | 'requiresContentEmbedScope'
58 + | 'decryptError'
59 +>;
60 +
61 +type AppIntegrationConfig = Pick<LeadinConfig, 'adminUrl'>;
62 +
63 +const getIntegrationConfig = (): AppIntegrationConfig => {
64 + return {
65 + adminUrl: leadinQueryParams.adminUrl,
66 + };
67 +};
68 +
69 +/**
70 + * A modified version of the original leadinConfig that is passed to some integrated apps.
71 + *
72 + * Important:
73 + * Try not to add new fields here.
74 + * This config is already too large and broad in scope.
75 + * It tightly couples the apps that use it with the WordPress plugin.
76 + * Consider instead passing new required fields as new entry to PluginAppOptions or app-specific options.
77 + */
78 +type AppLeadinConfig = {
79 + admin: string;
80 + company: string;
81 + email: string;
82 + firstName: string;
83 + irclickid: string;
84 + justConnected: string;
85 + lastName: string;
86 + mpid: string;
87 + nonce: string;
88 + websiteName: string;
89 +} & PartialLeadinConfig;
90 +
91 +const getLeadinConfig = (): AppLeadinConfig => {
26 92 const utm_query_params = Object.keys(leadinQueryParams)
27 93 .filter(x => /^utm/.test(x))
28 94 .reduce(
29 95 (p: { [key: string]: string }, c: string) => ({
@@ -36,8 +102,9 @@
36 102 accountName,
37 103 admin: leadinQueryParams.admin,
38 104 adminUrl,
39 105 company: leadinQueryParams.company,
106 + connectionStatus,
40 107 deviceId,
41 108 email: leadinQueryParams.email,
42 109 firstName: leadinQueryParams.firstName,
43 110 irclickid: leadinQueryParams.irclickid,
@@ -42,8 +109,11 @@
42 109 firstName: leadinQueryParams.firstName,
43 110 irclickid: leadinQueryParams.irclickid,
44 111 justConnected: leadinQueryParams.justConnected,
45 112 lastName: leadinQueryParams.lastName,
113 + lastAuthorizeTime,
114 + lastDeauthorizeTime,
115 + lastDisconnectTime,
46 116 leadinPluginVersion,
47 117 mpid: leadinQueryParams.mpid,
48 118 nonce: leadinQueryParams.nonce,
49 119 phpVersion,
@@ -55,8 +125,11 @@
55 125 theme,
56 126 trackConsent: leadinQueryParams.trackConsent,
57 127 websiteName: leadinQueryParams.websiteName,
58 128 wpVersion,
129 + contentEmbed,
130 + requiresContentEmbedScope,
131 + decryptError,
59 132 ...utm_query_params,
60 133 };
61 134 };
62 135
@@ -67,20 +140,19 @@
67 140 LiveChatAppOptions,
68 141 PluginAppOptions,
69 142 }: any = window;
70 143 let options;
71 -
72 144 switch (app) {
73 145 case App.Plugin:
74 - options = new PluginAppOptions().setLeadinConfig(getLeadinConfig());
146 + options = new PluginAppOptions();
75 147 break;
76 148 case App.PluginSettings:
77 - options = new PluginAppOptions()
78 - .setLeadinConfig(getLeadinConfig())
79 - .setPluginSettingsInit();
149 + options = new PluginAppOptions().setPluginSettingsInit();
80 150 break;
81 151 case App.Forms:
82 - options = new FormsAppOptions();
152 + options = new FormsAppOptions().setIntegratedAppConfig(
153 + getIntegrationConfig()
154 + );
83 155 if (createRoute) {
84 156 options = options.setCreateFormAppInit();
85 157 }
86 158 break;
@@ -101,18 +173,28 @@
101 173 app: App,
102 174 createRoute: boolean,
103 175 container: HTMLElement | null
104 176 ) {
177 + console.info(
178 + 'HubSpot plugin - starting app embedder for:',
179 + AppIframe[app],
180 + container
181 + );
105 182 const iframeNotRendered = useIframeNotRendered(AppIframe[app]);
106 183
107 184 useEffect(() => {
108 185 const { IntegratedAppEmbedder }: any = window;
109 186
110 - if (IntegratedAppEmbedder) {
187 + if (!IntegratedAppEmbedder) {
188 + return;
189 + }
190 +
191 + const createEmbedder = (accessToken = '', expiresIn = 0) => {
111 192 const options = getAppOptions(app, createRoute)
112 193 .setLocale(locale)
113 194 .setDeviceId(deviceId)
114 - .setRefreshToken(refreshToken);
195 + .setAccessToken(accessToken, expiresIn)
196 + .setLeadinConfig(getLeadinConfig());
115 197
116 198 const embedder = new IntegratedAppEmbedder(
117 199 AppIframe[app],
118 200 portalId,
@@ -117,17 +199,60 @@
117 199 AppIframe[app],
118 200 portalId,
119 201 hubspotBaseUrl,
120 202 resizeWindow,
121 - refreshToken ? '' : impactLink
203 + accessToken ? '' : impactLink
122 204 ).setOptions(options);
123 205
124 - embedder.subscribe(messageMiddleware(embedder));
206 + embedder.subscribe((message: any) => {
207 + messageMiddleware(embedder)(message);
208 + });
209 + embedder.setTokenRenewalCallback(fetchAccessToken);
210 +
125 211 embedder.attachTo(container, true);
126 212 embedder.postStartAppMessage(); // lets the app know all all data has been passed to it
127 213
128 214 (window as any).embedder = embedder;
215 + };
216 +
217 + if (connectionStatus === 'Connected') {
218 + fetchAccessToken()
219 + .then(
220 + ({
221 + accessToken,
222 + expiresIn,
223 + }: {
224 + accessToken: string;
225 + expiresIn: number;
226 + }) => {
227 + createEmbedder(accessToken, expiresIn);
228 + }
229 + )
230 + .catch(() => {});
231 + } else {
232 + createEmbedder();
129 233 }
130 234 }, []);
235 +
236 + if (iframeNotRendered) {
237 + console.error('HubSpot plugin Iframe not rendered', {
238 + portalId,
239 + container,
240 + appName: AppIframe[app],
241 + hasIntegratedAppEmbedder: !!(window as any).IntegratedAppEmbedder,
242 + });
243 + Raven.captureException(new Error('Leadin Iframe not rendered'), {
244 + fingerprint: ['USE_APP_EMBEDDER', 'IFRAME_SETUP_ERROR'],
245 + extra: {
246 + portalId,
247 + container,
248 + app,
249 + hubspotBaseUrl,
250 + impactLink,
251 + appName: AppIframe[app],
252 + isConnected: connectionStatus === 'Connected',
253 + },
254 + });
255 + }
131 256
132 257 return iframeNotRendered;
133 258 }