Skip to content

Commit

Permalink
feat: improve RedirectFromAuth.jsx
Browse files Browse the repository at this point in the history
  • Loading branch information
d-klotz committed Aug 9, 2024
1 parent 8808fd2 commit 4abc0f0
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 143 deletions.
47 changes: 47 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 1 addition & 10 deletions packages/ui/lib/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,6 @@ export default class API {
return this._get(url);
}

// authorize callback for scrive with the following params as an example:
// {
// "originalUrl":"https://redirecturl/",
// "entityType":"Freshbooks",
// "data": data
// }
//
// 'authData' should be the qString parsed dictionary of all the
// query params from the auth redirect once the user signs into the third party
async authorize(entityType, authData) {
const url = `${this.endpointAuthorize}`;
const params = {
Expand All @@ -156,7 +147,7 @@ export default class API {
entities: [entity1, entity2],
config,
};
return this._post(url, params); // todo: to improve dev experience, return a clear response, with this current implementation one does not now what returns from this request.
return this._post(url, params);
}

async updateIntegration(integrationId, config) {
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IntegrationHorizontal,
IntegrationVertical,
IntegrationList,
RedirectFromAuth,
} from "./integration";

export {
Expand All @@ -16,4 +17,5 @@ export {
IntegrationHorizontal,
IntegrationVertical,
IntegrationList,
RedirectFromAuth,
};
55 changes: 26 additions & 29 deletions packages/ui/lib/integration/IntegrationList.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import React, { useEffect, useState } from "react";
import IntegrationSkeleton from "./IntegrationSkeleton";
import IntegrationUtils from "../utils/IntegrationUtils";
import { getActiveAndPossibleIntegrationsCombined } from "../utils/IntegrationUtils";
import API from "../api/api";
import { IntegrationHorizontal, IntegrationVertical } from "../integration";

Expand All @@ -10,38 +10,38 @@ import { IntegrationHorizontal, IntegrationVertical } from "../integration";
* @param props.friggBaseUrl - Base URL for Frigg backend
* @param props.componentLayout - Layout for displaying integrations - either 'default-horizontal' or 'default-vertical'
* @param props.authToken - JWT token for authenticated user in Frigg
* @returns {Element}
* @returns {JSX.Element} The rendered component
* @constructor
*/
const IntegrationList = (props) => {
const [installedIntegrations, setInstalledIntegrations] = useState([]);
const [integrations, setIntegrations] = useState({});
const integrationUtils = useRef(null);
const [integrations, setIntegrations] = useState([]);
const [isloading, setIsLoading] = useState(true);

const loadIntegrations = async () => {
if (!props.authToken) {
console.log("Authentication token is required to fetch integrations.");
}

const refreshIntegrations = useCallback(async () => {
const api = new API(props.friggBaseUrl, props.authToken);
const integrationsData = await api.listIntegrations();

if (integrationsData.error) {
// dispatch(logoutUser());
//todo: if integration has an error, we should display an error message + a way to solve it
console.log(
"Something went wrong while fetching integrations, please try again later."
);
}

setIntegrations(integrationsData);
if (integrationsData.integrations) {
integrationUtils.current = new IntegrationUtils(integrationsData);
const activeAndPossibleIntegrations =
getActiveAndPossibleIntegrationsCombined(integrationsData);
setIntegrations(activeAndPossibleIntegrations);
}
}, [props.authToken, props.friggBaseUrl]);
};

useEffect(() => {
const init = async () => {
if (props.authToken) {
await refreshIntegrations();
}
};

init();
}, [props.authToken, refreshIntegrations]);
loadIntegrations().then(() => setIsLoading(false));
}, []);

const setInstalled = (data) => {
const items = [data, ...installedIntegrations];
Expand All @@ -55,7 +55,7 @@ const IntegrationList = (props) => {
data={integration}
key={`combined-integration-${integration.type}`}
handleInstall={setInstalled}
refreshIntegrations={refreshIntegrations}
refreshIntegrations={loadIntegrations}
friggBaseUrl={props.friggBaseUrl}
authToken={props.authToken}
/>
Expand All @@ -67,7 +67,7 @@ const IntegrationList = (props) => {
data={integration}
key={`combined-integration-${integration.type}`}
handleInstall={setInstalled}
refreshIntegrations={refreshIntegrations}
refreshIntegrations={loadIntegrations}
friggBaseUrl={props.friggBaseUrl}
/>
);
Expand Down Expand Up @@ -95,7 +95,7 @@ const IntegrationList = (props) => {

return (
<>
{integrationUtils.current === null ? (
{isloading && (
<div className="grid gap-6 lg:col-span-1 lg:grid-cols-1 xl:col-span-2 xl:grid-cols-2 2xl:col-span-3 2xl:grid-cols-3">
<IntegrationSkeleton layout={props.componentLayout} />
<IntegrationSkeleton layout={props.componentLayout} />
Expand All @@ -107,15 +107,12 @@ const IntegrationList = (props) => {
<IntegrationSkeleton layout={props.componentLayout} />
<IntegrationSkeleton layout={props.componentLayout} />
</div>
)}
{renderCombinedIntegrations(integrations).length === 0 ? (
<p>No {props.integrationType} integrations found.</p>
) : (
renderCombinedIntegrations(
integrationUtils.current.getActiveAndPossibleIntegrationsCombined()
)
renderCombinedIntegrations(integrations)
)}
{integrationUtils.current !== null &&
renderCombinedIntegrations(
integrationUtils.current.getActiveAndPossibleIntegrationsCombined()
).length === 0 && <p>No {props.integrationType} integrations found.</p>}
</>
);
};
Expand Down
72 changes: 72 additions & 0 deletions packages/ui/lib/integration/RedirectFromAuth.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { useEffect } from "react";
import qString from "query-string";
import API from "../api/api";
import { LoadingSpinner } from "../components/LoadingSpinner.jsx";

/**
* @param {string} props.app - The name of the app being authorized
* @param {string} props.friggBaseUrl - The base URL for the Frigg service
* @param {string} props.authToken - JWT token for authenticated user in Frigg
* @param {string} props.primaryEntityName - The name of the primary entity in the app
* @returns {JSX.Element} The rendered component
* @constructor
*/
const RedirectFromAuth = (props) => {
useEffect(() => {
const handleAuth = async () => {
const api = new API(props.friggBaseUrl, props.authToken);
const params = qString.parse(window.location.search);

if (params.code) {
const integrations = await api.listIntegrations();
const targetEntity = await api.authorize(props.app, {
code: params.code,
});

if (targetEntity?.error) {
alert(targetEntity.error);
window.location.href = "/integrations";
return;
}

const config = {
type: props.app,
category: "CRM",
};

const primaryEntity = integrations.entities.authorized.find(
(entity) => entity.type === props.primaryEntityName
);

//todo: shouldn't the integration be created only if primary and target entities exist and are different?
//todo2: move the createIntegration function to the integrationList component
const integration = await api.createIntegration(
primaryEntity.id ?? targetEntity.entity_id,
targetEntity.entity_id,
config
);

if (integration.error) {
alert(integration.error);
return;
}

window.location.href = "/integrations";
}
};

handleAuth();
}, [props.app]);

return (
<div className="container">
<div id="card-wrap" className="card">
<div className="card-body">
<LoadingSpinner />
</div>
</div>
</div>
);
};

export default RedirectFromAuth;
2 changes: 2 additions & 0 deletions packages/ui/lib/integration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import IntegrationList from "./IntegrationList.jsx";
import IntegrationSkeleton from "./IntegrationSkeleton.jsx";
import IntegrationVertical from "./IntegrationVertical";
import QuickActionsMenu from "./QuickActionsMenu";
import RedirectFromAuth from "./RedirectFromAuth.jsx";

export {
IntegrationDropdown,
Expand All @@ -12,4 +13,5 @@ export {
IntegrationSkeleton,
IntegrationVertical,
QuickActionsMenu,
RedirectFromAuth,
};
Loading

0 comments on commit 4abc0f0

Please sign in to comment.