From 0c53ee84605299186f08d35fd8a1ccc9daa30700 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Thu, 5 Sep 2024 10:33:01 +0000 Subject: [PATCH] feat(AddAppConnection): show pop-up reminder hint --- .../src/components/AddAppConnection/index.jsx | 16 ++++- .../web/src/helpers/authenticationSteps.js | 67 +++++++++++-------- .../web/src/hooks/useAuthenticateApp.ee.js | 26 ++++++- packages/web/src/locales/en.json | 1 + 4 files changed, 76 insertions(+), 34 deletions(-) diff --git a/packages/web/src/components/AddAppConnection/index.jsx b/packages/web/src/components/AddAppConnection/index.jsx index f253831b..c1c47743 100644 --- a/packages/web/src/components/AddAppConnection/index.jsx +++ b/packages/web/src/components/AddAppConnection/index.jsx @@ -31,7 +31,7 @@ function AddAppConnection(props) { const hasConnection = Boolean(connectionId); const useShared = searchParams.get('shared') === 'true'; const appAuthClientId = searchParams.get('appAuthClientId') || undefined; - const { authenticate } = useAuthenticateApp({ + const { authenticate, isPopupBlocked } = useAuthenticateApp({ appKey: key, connectionId, appAuthClientId, @@ -76,6 +76,7 @@ function AddAppConnection(props) { async (data) => { if (!authenticate) return; setInProgress(true); + setError(null); try { const response = await authenticate({ fields: data, @@ -88,7 +89,12 @@ function AddAppConnection(props) { } catch (err) { const error = err; console.log(error); - setError(error.graphQLErrors?.[0]); + + if (error.message) { + setError(error); + } else { + setError(error.graphQLErrors?.[0]); + } } finally { setInProgress(false); } @@ -128,6 +134,12 @@ function AddAppConnection(props) { )} + {isPopupBlocked && ( + + {formatMessage('addAppConnection.popupReminder')} + + )} + {error && ( { - const mutation = MUTATIONS[step.name]; +export const processMutation = async (mutationName, variables) => { + const mutation = MUTATIONS[mutationName]; const mutationResponse = await apolloClient.mutate({ mutation, variables: { input: variables }, @@ -15,56 +10,70 @@ const processMutation = async (step, variables) => { autoSnackbar: false, }, }); - const responseData = mutationResponse.data[step.name]; + const responseData = mutationResponse.data[mutationName]; + return responseData; }; + const parseUrlSearchParams = (event) => { const searchParams = new URLSearchParams(event.data.payload.search); const hashParams = new URLSearchParams(event.data.payload.hash.substring(1)); const searchParamsObject = getObjectOfEntries(searchParams.entries()); const hashParamsObject = getObjectOfEntries(hashParams.entries()); + return { ...hashParamsObject, ...searchParamsObject, }; }; + function getObjectOfEntries(iterator) { const result = {}; for (const [key, value] of iterator) { result[key] = value; } + return result; } -const processOpenWithPopup = (step, variables) => { + +export const processOpenWithPopup = (url) => { + const windowFeatures = + 'toolbar=no, titlebar=no, menubar=no, width=500, height=700, top=100, left=100'; + const popup = window.open(url, '_blank', windowFeatures); + popup?.focus(); + + return popup; +}; + +export const processPopupMessage = (popup) => { return new Promise((resolve, reject) => { - const windowFeatures = - 'toolbar=no, titlebar=no, menubar=no, width=500, height=700, top=100, left=100'; - const url = variables.url; - const popup = window.open(url, '_blank', windowFeatures); - popup?.focus(); - const closeCheckIntervalId = setInterval(() => { - if (!popup) return; - if (popup?.closed) { - clearInterval(closeCheckIntervalId); - reject({ message: 'Error occured while verifying credentials!' }); - } - }, 1000); + let closeCheckIntervalId; + + if (popup) { + closeCheckIntervalId = setInterval(() => { + if (popup.closed) { + clearInterval(closeCheckIntervalId); + + reject({ message: 'Error occured while verifying credentials!' }); + } + }, 1000); + } + const messageHandler = async (event) => { if (event.data.source !== 'automatisch') { return; } + const data = parseUrlSearchParams(event); window.removeEventListener('message', messageHandler); - clearInterval(closeCheckIntervalId); + + if (closeCheckIntervalId) { + clearInterval(closeCheckIntervalId); + } + resolve(data); }; + window.addEventListener('message', messageHandler, false); }); }; -export const processStep = async (step, variables) => { - if (step.type === AuthenticationSteps.Mutation) { - return processMutation(step, variables); - } else if (step.type === AuthenticationSteps.OpenWithPopup) { - return processOpenWithPopup(step, variables); - } -}; diff --git a/packages/web/src/hooks/useAuthenticateApp.ee.js b/packages/web/src/hooks/useAuthenticateApp.ee.js index 68c8af8a..e38d592b 100644 --- a/packages/web/src/hooks/useAuthenticateApp.ee.js +++ b/packages/web/src/hooks/useAuthenticateApp.ee.js @@ -1,6 +1,10 @@ import * as React from 'react'; -import { processStep } from 'helpers/authenticationSteps'; +import { + processMutation, + processOpenWithPopup, + processPopupMessage, +} from 'helpers/authenticationSteps'; import computeAuthStepVariables from 'helpers/computeAuthStepVariables'; import useAppAuth from './useAppAuth'; @@ -24,6 +28,7 @@ export default function useAuthenticateApp(payload) { const { data: auth } = useAppAuth(appKey); const [authenticationInProgress, setAuthenticationInProgress] = React.useState(false); + const [isPopupBlocked, setPopupBlocked] = React.useState(false); const steps = getSteps(auth?.data, !!connectionId, useShared); const authenticate = React.useMemo(() => { @@ -45,10 +50,24 @@ export default function useAuthenticateApp(payload) { while (stepIndex < steps?.length) { const step = steps[stepIndex]; const variables = computeAuthStepVariables(step.arguments, response); + let popup; + + if (step.type === 'openWithPopup') { + popup = processOpenWithPopup(variables.url); + + if (!popup) { + setPopupBlocked(true); + } + } try { - const stepResponse = await processStep(step, variables); - response[step.name] = stepResponse; + if (step.type === 'mutation') { + const stepResponse = await processMutation(step.name, variables); + response[step.name] = stepResponse; + } else if (step.type === 'openWithPopup') { + const stepResponse = await processPopupMessage(popup); + response[step.name] = stepResponse; + } } catch (err) { console.log(err); setAuthenticationInProgress(false); @@ -66,6 +85,7 @@ export default function useAuthenticateApp(payload) { return { authenticate, + isPopupBlocked, inProgress: authenticationInProgress, }; } diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index e65d0ecd..d4f9592a 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -37,6 +37,7 @@ "apps.noConnections": "You don't have any connections yet.", "addAppConnection.submit": "Submit", "addAppConnection.callToDocs": "Visit our documentation to see how to add connection for {appName}.", + "addAppConnection.popupReminder": "Make sure pop-ups are enabled in your browser.", "connection.flowCount": "{count} flows", "connection.viewFlows": "View flows", "connection.testConnection": "Test connection",