Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Overview page #22

Merged
merged 5 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions packages/client-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Client-Web

This package allows you to display documents and tasks and collect consents in your web apps.

## Getting Started

Please note, the `baseUrl` comes from the client that you have registered in ComplyCO's dashboard. It will look like `app-<...>.client.complyco.com`.

The `onAuthTokenRequested` callback will need to hit an endpoint on your backend which is configured to generate and sign a JWT.
The client that you have registered in ComplyCO's dashboard should be configured with the public key that corresponds with the private key used
for signing in your backend API.

```ts
import { Overview } from "@complyco/client-web/views";

const view = Overview.initialize({
baseUrl,
iframe: document.getElementById("myIframe"), // this is optional
onAuthTokenRequested,
onLoad,
onStarted,
onShutdown,
onResize,
onComplete,
onHeartbeatAge,
});
```

## Lifecycle

Note, if `iframe` isn't passed, then you can call `view.run(iframe)` in the future. This can be useful if you want to wait for `onStarted` to fire prior to opening a Dialog (where the iframe isn't mounted in the DOM until the Dialog is open).

You can call `view.unmount()` to clean up the event listeners that are managing the iframe.

## Event callbacks

- onStarted: This is called when the view starts, but before it loads. This is useful for cases such as the `Tasks.List` view where `onStarted` will only run if there are tasks for the user to see. This can help you avoid loading a dialog unnecessarily.
- onLoad: This is triggered by the iframe's onload event.
- onShutdown: This is run if the contents of the iframe shutdown, such as in the case of an unrecoverable error.
- onResize: The screens in the iframe will send their preferred size ("small" or "large") so that your UI can resize if you so choose.
- onComplete: This is run when a consent achieves a completed state.
- onHeartbeatAge: This returns the age of the last ping that the View does to the iframe. You can use this to automatically close the iframe if it becomes non-responsive.

## Views

- `Tasks.List`: Renders a list of pending tasks for the user.
- `Tasks.Details`: Renders a task by ID for the user.
- `Overview`: Renders a section of pending tasks (if any) and historical consents (if any) for the user.
- `Consents.Details`: Renders a consent by ID for the user.
5 changes: 3 additions & 2 deletions packages/client-web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@complyco/client-web",
"version": "5.1.0",
"version": "5.2.0-rc-next-1",
"description": "ComplyCo's client web widget",
"repository": "https://github.com/ComplyCo/client-widget-js",
"contributors": [
Expand Down Expand Up @@ -28,7 +28,8 @@
},
"files": [
"dist",
"views"
"views",
"README.md"
],
"preconstruct": {
"entrypoints": [
Expand Down
25 changes: 17 additions & 8 deletions packages/client-web/src/iframe/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export type ShutdownReason = ShutdownErrorReason | ShutdownUserClosedReason;
export type IframeManagerOptions = {
path: string;
apiAuth: ComplyCoAPIAuth;
iframe: HTMLIFrameElement;
events: {
onLoad: (_: { iframe: HTMLIFrameElement }) => void;
onLoad?: (_: { iframe: HTMLIFrameElement }) => void;
onStarted?: () => void;
onShutdown: (reason: ShutdownReason) => void;
onComplete: (payload: CompletePayload) => void;
onResize?: (_: { size: "small" | "large" }) => void;
Expand All @@ -38,9 +38,9 @@ export default class IframeManager {
this.#options = options;
}

#initIframe() {
#initIframe(iframe: HTMLIFrameElement) {
// NOTE: the caller should manage the iframe's visibility
const iframe = this.#options.iframe;
// const iframe = this.#options.iframe;
iframe.src = this.#options.apiAuth.clientUrl(this.#options.path);

iframe.onerror = (event, source, lineno, number, error) => {
Expand Down Expand Up @@ -116,10 +116,19 @@ export default class IframeManager {
this.#communicator = communicator;
}

run() {
this.#initIframe();
this.#initCommunicator();
}
start = (iframe?: HTMLIFrameElement | undefined | null) => {
this.run(iframe);
if (this.#options.events.onStarted) {
this.#options.events.onStarted();
}
};

run = (iframe?: HTMLIFrameElement | undefined | null) => {
if (iframe) {
this.#initIframe(iframe);
this.#initCommunicator();
}
};

#shutdown(reason: ShutdownReason) {
this.unmount();
Expand Down
5 changes: 3 additions & 2 deletions packages/client-web/src/views/consents/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function initialize(options: InitializeOptions) {
const manager = new IframeManager({
path: `/v1/consents/${options.params.id}`,
apiAuth,
iframe: options.iframe,
events: {
onLoad: options.onLoad,
onStarted: options.onStarted,
onShutdown: options.onShutdown,
onResize: options.onResize,
onComplete: options.onComplete,
Expand All @@ -26,14 +26,15 @@ export function initialize(options: InitializeOptions) {
});

try {
manager.run();
manager.start(options.iframe);
} catch (err) {
if (options.onError) {
options.onError(err);
}
}

return {
run: manager.run,
unmount: () => {
// TODO: Figure out controller + signals for cancellation
manager.unmount();
Expand Down
1 change: 1 addition & 0 deletions packages/client-web/src/views/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * as Tasks from "./tasks";
export * as Consents from "./consents";
export * as Overview from "./overview";
43 changes: 43 additions & 0 deletions packages/client-web/src/views/overview/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { type ViewOptions } from "../types";
import { ComplyCoAPIAuth } from "../../auth";
import IframeManager from "../../iframe/manager";

export type InitializeOptions = ViewOptions & {
showEmpty?: boolean;
};

export function initialize(options: InitializeOptions) {
const apiAuth = new ComplyCoAPIAuth({
baseUrl: options.baseUrl,
onGetAuthToken: options.onAuthTokenRequested,
});

const manager = new IframeManager({
path: "/v1/overview",
apiAuth,
events: {
onLoad: options.onLoad,
onStarted: options.onStarted,
onShutdown: options.onShutdown,
onResize: options.onResize,
onComplete: options.onComplete,
onHeartbeatAge: options.onHeartbeatAge,
},
});

try {
manager.start(options.iframe);
} catch (err) {
if (options.onError) {
options.onError(err);
}
}

return {
run: manager.run,
unmount: () => {
// TODO: Figure out controller + signals for cancellation
manager.unmount();
},
};
}
5 changes: 3 additions & 2 deletions packages/client-web/src/views/tasks/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function initialize(options: InitializeOptions) {
const manager = new IframeManager({
path: `/v1/tasks/${options.params.id}`,
apiAuth,
iframe: options.iframe,
events: {
onLoad: options.onLoad,
onStarted: options.onStarted,
onShutdown: options.onShutdown,
onResize: options.onResize,
onComplete: options.onComplete,
Expand All @@ -26,14 +26,15 @@ export function initialize(options: InitializeOptions) {
});

try {
manager.run();
manager.start(options.iframe);
} catch (err) {
if (options.onError) {
options.onError(err);
}
}

return {
run: manager.run,
unmount: () => {
// TODO: Figure out controller + signals for cancellation
manager.unmount();
Expand Down
7 changes: 4 additions & 3 deletions packages/client-web/src/views/tasks/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export function initialize(options: InitializeOptions) {
const manager = new IframeManager({
path: "/v1/tasks",
apiAuth,
iframe: options.iframe,
events: {
onLoad: options.onLoad,
onStarted: options.onStarted,
onShutdown: options.onShutdown,
onResize: options.onResize,
onComplete: options.onComplete,
Expand All @@ -37,7 +37,7 @@ export function initialize(options: InitializeOptions) {
})
.then((json) => {
if (json && json.data.tasks.length > 0) {
return manager.run();
return manager.start(options.iframe);
}
})
.catch((err) => {
Expand All @@ -47,7 +47,7 @@ export function initialize(options: InitializeOptions) {
});
} else {
try {
manager.run();
manager.start(options.iframe);
} catch (err) {
if (options.onError) {
options.onError(err);
Expand All @@ -56,6 +56,7 @@ export function initialize(options: InitializeOptions) {
}

return {
run: manager.run,
unmount: () => {
// TODO: Figure out controller + signals for cancellation
manager.unmount();
Expand Down
4 changes: 2 additions & 2 deletions packages/client-web/src/views/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { type ComplyCoAPIAuthOptions } from "../auth";

export type ViewOptions = Pick<
IframeManagerOptions["events"],
"onLoad" | "onShutdown" | "onComplete" | "onResize" | "onHeartbeatAge"
"onLoad" | "onStarted" | "onShutdown" | "onComplete" | "onResize" | "onHeartbeatAge"
> & {
baseUrl: string;
onAuthTokenRequested: ComplyCoAPIAuthOptions["onGetAuthToken"];
onError?: (error: any) => void;
iframe: HTMLIFrameElement;
iframe?: HTMLIFrameElement | undefined | null;
};

// TODO: Add a function to validate the view options