-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement UI for DocuSign extension Uses iframe to provide seamless experience for users See videos: - https://htdhealth.slack.com/files/UHBBGDBU2/F05K4UTK5RT/docusign_-_28.07.2023.mov - https://htdhealth.slack.com/files/UHBBGDBU2/F05KLG9J3U1/docusign_-_settings_explanation.mov
- Loading branch information
1 parent
863d3c6
commit d7c92ff
Showing
15 changed files
with
467 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/components/Extension/DocuSignExtension/DocuSignExtension.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React, { FC } from 'react' | ||
import { useTranslation } from 'next-i18next' | ||
import { ErrorPage } from '../../ErrorPage' | ||
import { EmbeddedSigningAction } from './actions' | ||
import { ActionKey } from './types' | ||
import type { Activity, ExtensionActivityRecord } from '../types' | ||
|
||
interface DocuSignExtensionProps { | ||
activity: Activity | ||
activityDetails: ExtensionActivityRecord | ||
} | ||
|
||
export const DocuSignExtension: FC<DocuSignExtensionProps> = ({ | ||
activityDetails, | ||
}) => { | ||
const { t } = useTranslation() | ||
|
||
switch (activityDetails.plugin_action_key) { | ||
case ActionKey.EMBEDDED_SIGNING: | ||
return <EmbeddedSigningAction activityDetails={activityDetails} /> | ||
default: | ||
return <ErrorPage title={t('activities.activity_not_supported')} /> | ||
} | ||
} | ||
|
||
DocuSignExtension.displayName = 'DropboxSignExtension' |
94 changes: 94 additions & 0 deletions
94
...nents/Extension/DocuSignExtension/actions/EmbeddedSigningAction/EmbeddedSigningAction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react' | ||
import { parse } from 'query-string' | ||
import he from 'he' | ||
import { mapActionFieldsToObject } from '../../../utils' | ||
import { DocuSignEvent, type EmbeddedSigningFields } from '../../types' | ||
import type { ExtensionActivityRecord } from '../../../types' | ||
import { useCompleteEmbeddedSigningAction } from './hooks/useCompleteEmbeddedSigningAction' | ||
import { IFrameMessager } from './IFrameMessager' | ||
import { SigningProcess } from './SigningProcess' | ||
import { FinishedMessage } from './FinishedMessage' | ||
import classes from './embeddedSigning.module.css' | ||
|
||
interface EmbeddedSigningActionActionProps { | ||
activityDetails: ExtensionActivityRecord | ||
} | ||
|
||
export const EmbeddedSigningAction: FC<EmbeddedSigningActionActionProps> = ({ | ||
activityDetails, | ||
}) => { | ||
const { activity_id, fields } = activityDetails | ||
const { onSubmit } = useCompleteEmbeddedSigningAction() | ||
// visible in IFrame only | ||
const { event: iframeEvent } = | ||
(parse(location.search) as { event?: DocuSignEvent }) ?? {} | ||
const [isIframeLoaded, setIsIframeLoaded] = useState(false) | ||
const [event, setEvent] = useState<DocuSignEvent | undefined>(undefined) | ||
const isFinished = !!event | ||
const isIframe = !!iframeEvent | ||
|
||
const { signUrl } = useMemo( | ||
() => mapActionFieldsToObject<EmbeddedSigningFields>(fields), | ||
[fields] | ||
) | ||
|
||
/** | ||
* This is needed because Orchestration seems to encode string action field values | ||
* - Data point value: https://url.com/?signature_id=ABC&token=DEF | ||
* - Action field value https://url.com/?signature_id=ABC&token=DEF | ||
* | ||
* We need the decoded action field value and he library helps us to force decode | ||
* the url to a valid one. | ||
*/ | ||
const decodedSignUrl = he.decode(signUrl) | ||
|
||
const finishSigning = useCallback( | ||
({ signed }: { signed: boolean }) => { | ||
onSubmit(activity_id, { signed }) | ||
}, | ||
[activity_id, onSubmit] | ||
) | ||
|
||
useEffect(() => { | ||
if (isFinished) { | ||
setIsIframeLoaded(false) | ||
|
||
if (event === DocuSignEvent.SIGNING_COMPLETE) { | ||
finishSigning({ signed: true }) | ||
} | ||
} | ||
}, [event, finishSigning, isFinished]) | ||
|
||
// this window is iframe content -> render only messager | ||
if (isIframe) { | ||
return <IFrameMessager iframeEvent={iframeEvent} setEvent={setEvent} /> | ||
} | ||
|
||
// this window is extension content -> render messager and extension | ||
return ( | ||
<> | ||
<IFrameMessager iframeEvent={iframeEvent} setEvent={setEvent} /> | ||
|
||
<div | ||
// if iframe is loaded -> fill screen | ||
className={`${classes.wrapper} ${ | ||
isIframeLoaded ? classes['flex-full'] : '' | ||
}`} | ||
> | ||
{isFinished ? ( | ||
// signing process is finished -> display messsage | ||
<FinishedMessage event={event} finishSigning={finishSigning} /> | ||
) : ( | ||
// signing process incomplete (or user refreshed page) -> display signing process | ||
<SigningProcess | ||
signUrl={decodedSignUrl} | ||
isIframeLoaded={isIframeLoaded} | ||
setIsIframeLoaded={setIsIframeLoaded} | ||
/> | ||
)} | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
EmbeddedSigningAction.displayName = 'EmbeddedSigningAction' |
52 changes: 52 additions & 0 deletions
52
src/components/Extension/DocuSignExtension/actions/EmbeddedSigningAction/FinishedMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React, { FC } from 'react' | ||
import { useTranslation } from 'next-i18next' | ||
import { Button } from '@awell_health/ui-library' | ||
import { DocuSignEvent } from '../../types' | ||
import { LoadingPage } from '../../../../LoadingPage' | ||
|
||
interface FinishedMessage { | ||
event: DocuSignEvent | ||
finishSigning: (args: { signed: boolean }) => void | ||
} | ||
|
||
export const FinishedMessage: FC<FinishedMessage> = ({ | ||
event, | ||
finishSigning, | ||
}) => { | ||
const { t } = useTranslation() | ||
|
||
const finishAndFailSigning = () => { | ||
finishSigning({ signed: false }) | ||
} | ||
|
||
switch (event) { | ||
case DocuSignEvent.SIGNING_COMPLETE: | ||
return ( | ||
<LoadingPage title={t('activities.docu_sign.finished_sign_document')} /> | ||
) | ||
case DocuSignEvent.TTL_EXPIRED: | ||
return ( | ||
<> | ||
<span> | ||
<h2>{t('activities.docu_sign.expired_sign_document')}</h2> | ||
<Button onClick={finishAndFailSigning}> | ||
{t('activities.cta_done')} | ||
</Button> | ||
</span> | ||
</> | ||
) | ||
default: | ||
return ( | ||
<> | ||
<span> | ||
<h2>{t('activities.docu_sign.failed_sign_document')}</h2> | ||
<Button onClick={finishAndFailSigning}> | ||
{t('activities.cta_done')} | ||
</Button> | ||
</span> | ||
</> | ||
) | ||
} | ||
} | ||
|
||
FinishedMessage.displayName = 'FinishedMessage' |
51 changes: 51 additions & 0 deletions
51
src/components/Extension/DocuSignExtension/actions/EmbeddedSigningAction/IFrameMessager.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React, { FC, useCallback, useEffect } from 'react' | ||
import { DocuSignEvent, DocuSignMessage, WindowEventType } from '../../types' | ||
|
||
interface IFrameMessager { | ||
iframeEvent?: DocuSignEvent | ||
setEvent: (event: DocuSignEvent | undefined) => void | ||
} | ||
|
||
export const IFrameMessager: FC<IFrameMessager> = ({ | ||
iframeEvent, | ||
setEvent, | ||
}) => { | ||
const isIframe = !!iframeEvent | ||
|
||
const handleDocuSignEvent = useCallback( | ||
(event: MessageEvent<DocuSignMessage>) => { | ||
// validate domain | ||
if (event.origin !== location.origin) { | ||
return | ||
} | ||
|
||
switch (event.data?.type) { | ||
case WindowEventType.DOCU_SIGN_SET_EVENT: | ||
setEvent(event.data.event) | ||
break | ||
default: | ||
break | ||
} | ||
}, | ||
[setEvent] | ||
) | ||
|
||
useEffect(() => { | ||
if (isIframe) { | ||
window.top?.postMessage( | ||
{ event: iframeEvent, type: WindowEventType.DOCU_SIGN_SET_EVENT }, | ||
location.origin | ||
) | ||
} else { | ||
window.addEventListener('message', handleDocuSignEvent, false) | ||
|
||
return () => { | ||
window.removeEventListener('message', handleDocuSignEvent, false) | ||
} | ||
} | ||
}, [handleDocuSignEvent, iframeEvent, isIframe]) | ||
|
||
return <></> | ||
} | ||
|
||
IFrameMessager.displayName = 'IFrameMessager' |
58 changes: 58 additions & 0 deletions
58
src/components/Extension/DocuSignExtension/actions/EmbeddedSigningAction/SigningProcess.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { FC, useState } from 'react' | ||
import { useTranslation } from 'next-i18next' | ||
import { Button } from '@awell_health/ui-library' | ||
import classes from './embeddedSigning.module.css' | ||
import { LoadingPage } from '../../../../LoadingPage' | ||
|
||
interface SigningProcess { | ||
signUrl: string | ||
isIframeLoaded: boolean | ||
setIsIframeLoaded: (isLoaded: boolean) => void | ||
} | ||
|
||
export const SigningProcess: FC<SigningProcess> = ({ | ||
signUrl, | ||
isIframeLoaded, | ||
setIsIframeLoaded, | ||
}) => { | ||
const { t } = useTranslation() | ||
|
||
const [isSignProcess, setIsSignProcess] = useState(false) | ||
|
||
const beginSigning = () => { | ||
setIsSignProcess(true) | ||
} | ||
|
||
if (isSignProcess) { | ||
return ( | ||
<> | ||
{!isIframeLoaded && ( | ||
<LoadingPage | ||
title={t('activities.docu_sign.loading_sign_document')} | ||
/> | ||
)} | ||
<iframe | ||
className={ | ||
isIframeLoaded | ||
? classes['iframe-loaded'] | ||
: classes['iframe-loading'] | ||
} | ||
src={signUrl} | ||
onLoad={() => { | ||
setIsIframeLoaded(true) | ||
}} | ||
/> | ||
</> | ||
) | ||
} | ||
|
||
return ( | ||
<span> | ||
<Button onClick={beginSigning}> | ||
{t('activities.docu_sign.cta_sign_document')} | ||
</Button> | ||
</span> | ||
) | ||
} | ||
|
||
SigningProcess.displayName = 'SigningProcess' |
25 changes: 25 additions & 0 deletions
25
...ents/Extension/DocuSignExtension/actions/EmbeddedSigningAction/embeddedSigning.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
.wrapper { | ||
display: flex; | ||
justify-content: center; | ||
text-align: center; | ||
padding: 12px 0 0 0; | ||
} | ||
|
||
.flex-full { | ||
flex: 1 0; | ||
} | ||
|
||
.wrapper > iframe { | ||
border: 0; | ||
} | ||
|
||
.iframe-loaded { | ||
width: 80%; | ||
height: 80%; | ||
} | ||
|
||
.iframe-loading { | ||
width: 0; | ||
height: 0; | ||
visibility: hidden; | ||
} |
20 changes: 20 additions & 0 deletions
20
...ocuSignExtension/actions/EmbeddedSigningAction/hooks/useCompleteEmbeddedSigningAction.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useCallback } from 'react' | ||
import { DataPoints, useCompleteExtensionActivity } from '../../../types' | ||
|
||
export const useCompleteEmbeddedSigningAction = () => { | ||
const { isSubmitting, onSubmit: _onSubmit } = useCompleteExtensionActivity() | ||
|
||
const onSubmit = useCallback( | ||
async (activityId: string, { signed }: { signed: boolean }) => { | ||
const dataPoints: DataPoints = [{ key: 'signed', value: String(signed) }] | ||
|
||
return _onSubmit(activityId, dataPoints) | ||
}, | ||
[_onSubmit] | ||
) | ||
|
||
return { | ||
isSubmitting, | ||
onSubmit, | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
src/components/Extension/DocuSignExtension/actions/EmbeddedSigningAction/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { EmbeddedSigningAction } from './EmbeddedSigningAction' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { EmbeddedSigningAction } from './EmbeddedSigningAction' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { DocuSignExtension } from './DocuSignExtension' |
Oops, something went wrong.