@foreverrbum/ethsign
Version:
This package will allow you to electronically sign documents within your application
336 lines (331 loc) • 21.9 kB
JavaScript
import React, { useState } from 'react';
import ViewIcon from '../../assets/contracts_actions/view.svg';
import SignIcon from '../../assets/contracts_actions/sign.svg';
import ArchiveIcon from '../../assets/contracts_actions/archive.svg';
import DownloadIcon from '../../assets/contracts_actions/download.svg';
import HistoryIcon from '../../assets/contracts_actions/history.svg';
import InfoIcon from '../../assets/contracts_actions/info.svg';
import {withRouter} from 'react-router-dom';
import { getFileArray } from '../../helpers/download';
import { archiveDocuments, storeNotif } from '../../helpers/dashboard';
import ReactTooltip from 'react-tooltip';
import Alert from '../Alert';
import { FormattedMessage, useIntl } from 'react-intl';
import DownloadPDF from '../PDF/DownloadPDF';
import CopyToClipboard from 'react-copy-to-clipboard';
import moment from 'moment';
const ContractActions = (props) => {
const {doc, signers, initiator, contract, provider, idx, handleArchiveData, filter, error, reloadContractDetails} = props;
// onClick={()=>{handleData(doc.documentKey, 3)}} for deleting
// onClick={()=>{handleData(doc.documentKey, 1)}} for updating data
const [loading, handleLoading] = useState(false)
const [archivedWaiting, handleArchivedWaiting] = useState(false);
const [showPasswordPopup, handleShowPasswordPopup] = useState(false);
const [showArchivePopup, handleShowArchivePopup] = useState(false);
const [showDownloadPopup, handleShowDownloadPopup] = useState(false);
const [showDetailsPopup, handleShowDetailsPopup] = useState(false);
const [showWebviewer, handleShowWebviewer] = useState(null);
const [creationUseDate, handleCreationUseDate] = useState(true);
const [expirationUseDate, handleExpirationUseDate] = useState(true);
const { formatMessage } = useIntl();
const handleSignSubmission = async () => {
handleLoading(true);
let password = doc.withPassword == true ? (document.getElementById('password_input') ? document.getElementById('password_input').value : ''): '';
let fileArr = await getFileArray(password, doc.ipfsHash, doc.storageProvider, false, formatMessage)
let sigArr = null;
if (fileArr!=false){
if (doc.metaHash != null && doc.metaHash != undefined){
sigArr = await getFileArray(password, doc.metaHash, doc.storageProvider, false, formatMessage)
}
props.history.push({
pathname: '/sign',
state: {
doc: doc,
idx: idx,
fileArr: fileArr,
sigArr: sigArr,
commentData: doc.commentData,
password: password
},
})
}
handleLoading(false);
}
const handleDownloadSubmission = async () => {
// console.log(data)
handleLoading(true);
let password = doc.withPassword == true ? (document.getElementById('password_input') ? document.getElementById('password_input').value : ''): '';
handleShowWebviewer({
password:password,
doc: doc
})
// await downloadFile(password, doc.ipfsHash, doc.name, () => handleShowDownloadPopup(false), doc.storageProvider, formatMessage);
handleLoading(false)
}
const handleArchiveSubmission = async () => {
handleLoading(true);
let tx = await archiveDocuments(provider, contract, [doc.documentKey], handleArchivedWaiting, formatMessage);
// console.log(tx)
if (tx == true){
handleArchiveData(doc.documentKey, 3);
handleShowArchivePopup(false);
storeNotif('', formatMessage({id: 'SUCCESSFULLY_ARCHIVED_CONTRACT'}), 'success');
}
handleLoading(false);
handleArchivedWaiting(false);
}
const handleHistorySubmission = async () => {
handleLoading(true);
props.history.push({
pathname: '/history',
state: {
doc: doc,
signers: signers,
initiator: initiator,
idx: idx,
},
})
handleLoading(false);
}
const handleReuploadDocument = async () => {
handleLoading(true);
props.history.push({
pathname: '/upload',
state: {
doc: doc,
filter: filter,
idx: idx,
},
})
handleLoading(false);
}
if(!doc) {
return null;
}
return doc.status == 0 || error ? (
<>
<button className={`select-none bg-red-100 text-red-500 hover:bg-red-150 active:bg-red-200 outline-none py-1 px-2 rounded`} onClick={(event) => { event.stopPropagation(); if(doc.status == 0) {handleReuploadDocument();} else {reloadContractDetails(doc.documentKey, idx)} }}>{doc.status == 0 ? 'Upload PDF' : formatMessage({id: 'RETRY'})}</button>
</>
) : (
<>
<ReactTooltip className={`rounded-lg text-xs text-white px-2 py-0 bg-gray-300`} delayShow={500} delayHide={100} offset={{'top': -10}} arrowColor="rgba(0,0,0,0)" place="top" type="dark" effect="solid" />
<img onClick={(event) => {
event.stopPropagation();
if(doc.status === 0 || doc.status === '') {
return;
}
if(doc.withPassword == false) {
handleLoading(true);
handleSignSubmission();
}else{
handleShowPasswordPopup(true);
}
}} data-tip={doc.status==2 ? formatMessage({id: "SIGN"}):formatMessage({id: "VIEW"})} style={{opacity: doc.status ===0 || doc.status === '' ? '.5' : '1'}} src={doc.status==2 ? SignIcon:ViewIcon} className={`select-none mr-2 cursor-pointer`}/>
{filter !== 'archived' &&
<img onClick={(event) => {
event.stopPropagation();
if(filter == 'archived') {
return;
}
handleShowArchivePopup(true);
}} data-tip={formatMessage({id: "ARCHIVE"})} style={{opacity: filter == 'archived' ? '.5' : '1'}} src={ArchiveIcon} className={`select-none mr-2 cursor-pointer`}/>
}
<img onClick={(event) => {
event.stopPropagation();
if(doc.status === 0 || doc.status === '') {
return;
}
if(doc.withPassword == false) {
handleLoading(true);
handleDownloadSubmission();
}else{
handleShowDownloadPopup(true);
}
}} data-tip={formatMessage({id: 'DOWNLOAD'})} style={{opacity: doc.status === 0 || doc.status === '' ? '.5' : '1'}} src={DownloadIcon} className={`select-none mr-2 cursor-pointer`}/>
<img data-tip={formatMessage({id: 'HISTORY'})} onClick={handleHistorySubmission} src={HistoryIcon} className={`select-none mr-2 cursor-pointer`}/>
<img onClick={(event) => {
event.stopPropagation();
let date = `${moment.unix(doc?.creation.date).format('lll')}
${doc?.expiration.date? `- ${moment.unix(doc?.expiration.date).format('lll')}`:''}`;
handleCreationUseDate(true);
handleExpirationUseDate(true);
handleShowDetailsPopup(true);
}} data-tip={formatMessage({id: 'DETAILS'})} src={InfoIcon} className={`select-none mr-2 cursor-pointer`}/>
{/* Popups are below */}
{showPasswordPopup &&
<Alert
title={formatMessage({id: 'DOCUMENT_PASSWORD'})}
message={formatMessage({id: 'THIS_CONTRACT_IS_PROTECTED'})}
loading={loading}
displayLoader={doc.withPassword ? false : true}
loadingText={doc.withPassword ? formatMessage({id: 'DECRYPTING_YOUR_FILE_WITH_POINT'}) : formatMessage({id: 'LOADING'})}
closeCallback={() => handleShowPasswordPopup(false)}
closeButtonText={formatMessage({id:'CANCEL'})}
okCallback={() => handleSignSubmission()}
okButtonText={formatMessage({id:"OK"})}
closeOnOutsideClick={true}
customComponent={
<div className="flex flex-wrap sm:flex-nowrap justify-start">
<div className="mb-2 sm:my-auto mr-4 hidden sm:block"><FormattedMessage id='PASSWORD' />:</div>
<form onSubmit={(e) => {e.preventDefault(); handleSignSubmission();}}>
<input
placeholder={formatMessage({id: 'ENTER_YOUR_PASSWORD'})}
required={false}
name="password"
type="password"
autoComplete="new-password"
autoFocus
maxLength={32}
id="password_input"
className={`flex-grow-1 rounded-sm focus:outline-none rounded-sm px-4 py-1 border mr-0 border-gray-200`}
>
</input>
</form>
</div>
}
/>
}
{showArchivePopup &&
<Alert
title={formatMessage({id: 'ARCHIVE_CONTRACT'})}
message={formatMessage({id: 'ARE_YOU_WANT_TO_ARCHIVE_THE_DOC'},{name: doc.name})}
closeButtonText={formatMessage({id:'CANCEL'})}
loading={loading}
loadingText={archivedWaiting ? formatMessage({id: 'WAITING_FOR_CONFIRMATIONS_FROM_NEWWORK'}) : formatMessage({id: 'ARCHIVING_CONTRACT'})}
closeCallback={() => handleShowArchivePopup(false)}
closeOnOutsideClick={true}
okButtonText={formatMessage({id:'ARCHIVE'})}
okCallback={() => {handleArchiveSubmission();}}
/>
}
{showDownloadPopup &&
<Alert
title={formatMessage({id: 'DOCUMENT_PASSWORD'})}
message={formatMessage({id: 'THIS_CONTRACT_IS_PROTECTED'})}
loading={loading}
displayLoader={doc.withPassword ? false : true}
loadingText={doc.withPassword ? formatMessage({id: 'DECRYPTING_YOUR_FILE_WITH_POINT'}) : formatMessage({id: 'LOADING'})}
closeCallback={() => handleShowDownloadPopup(false)}
closeOnOutsideClick={true}
closeButtonText={formatMessage({id: "CANCEL"})}
okCallback={() => handleDownloadSubmission()}
okButtonText={formatMessage({id: "OK"})}
customComponent={
<div className="flex flex-wrap sm:flex-nowrap justify-start">
<div className="mb-2 sm:my-auto mr-4 hidden sm:block"><FormattedMessage id='PASSWORD'/>:</div>
<form onSubmit={(e) => {e.preventDefault(); handleDownloadSubmission()}}>
<input
placeholder={formatMessage({id: 'ENTER_YOUR_PASSWORD'})}
required={false}
name="password"
type="password"
autoComplete="new-password"
autoFocus
maxLength={32}
id="password_input"
className={`flex-grow-1 rounded-sm focus:outline-none rounded-sm px-4 py-1 border mr-0 border-gray-200`}
>
</input>
</form>
</div>
}
/>
}
{showDetailsPopup &&
<Alert
title={formatMessage({id: 'DOCUMENT_DETAILS'})}
type={2}
closeCallback={() => handleShowDetailsPopup(false)}
closeOnOutsideClick={true}
customComponent={
<div className="flex flex-wrap sm:flex-nowrap justify-start flex-col w-full text-gray">
<div className="flex flex-row justify-between pt-4 pb-6">
<div>{formatMessage({id: 'UPLOADED_DOCUMENT'}) + ":"}</div>
<div className="text-right">{doc.name}</div>
</div>
<div className="flex flex-row justify-between pb-2">
<div className="flex flex-col">
<div>{(creationUseDate ? formatMessage({id: "CREATED_DATE"}) : formatMessage({id: "CREATION_BLOCK"})) + ":"}</div>
<div onClick={() => handleCreationUseDate(!creationUseDate)} className="cursor-pointer select-none text-10 underline text-blue-200">{creationUseDate ? formatMessage({id: "CREATION_BLOCK"}) : formatMessage({id: "CREATED_DATE"})}</div>
</div>
<div className="text-right">{creationUseDate ?
`${moment.unix(doc?.creation.date).format('lll')}
${doc?.expiration.date? `- ${moment.unix(doc?.expiration.date).format('lll')}`:''}`
:
doc.creation?.block}</div>
</div>
<div className="flex flex-row justify-between pb-2">
<div className="flex flex-col">
<div>{(expirationUseDate ? formatMessage({id: "EXPIRATION_DATE"}) : formatMessage({id: "EXPIRATION_BLOCK"})) + ":"}</div>
<div onClick={() => handleExpirationUseDate(!expirationUseDate)} className="cursor-pointer select-none text-10 underline text-blue-200">{expirationUseDate ? formatMessage({id: "EXPIRATION_BLOCK"}) : formatMessage({id: "EXPIRATION_DATE"})}</div>
</div>
<div className="text-right">{expirationUseDate ? (doc.expiration?.date ? doc.expiration.date : formatMessage({id: 'NEVER'}))
:
doc.expiration?.block !== 'Never' ? doc.expiration.block : formatMessage({id: 'NEVER'})}</div>
</div>
<div className="flex flex-row justify-between pb-6">
<div>{formatMessage({id: "DOCUMENT_KEY"}) + ":"}</div>
<div className="flex">
<div className="pr-1 text-right">
{doc.documentKey && doc.documentKey.slice(0, 6) + '...' + doc.documentKey.slice(doc.documentKey.length - 6)}
</div>
<CopyToClipboard text={doc.documentKey}>
<div className="inline mb-1 cursor-pointer">
<svg width="15" height="17" viewBox="0 0 15 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4375 0.1875H3.49219C3.41055 0.1875 3.34375 0.254297 3.34375 0.335938V1.375C3.34375 1.45664 3.41055 1.52344 3.49219 1.52344H12.6953V14.2891C12.6953 14.3707 12.7621 14.4375 12.8438 14.4375H13.8828C13.9645 14.4375 14.0312 14.3707 14.0312 14.2891V0.78125C14.0312 0.452832 13.7659 0.1875 13.4375 0.1875ZM11.0625 2.5625H1.5625C1.23408 2.5625 0.96875 2.82783 0.96875 3.15625V13.0032C0.96875 13.1609 1.03184 13.3112 1.14316 13.4226L4.35869 16.6381C4.39951 16.6789 4.4459 16.7123 4.496 16.7401V16.7754H4.57393C4.63887 16.7995 4.70752 16.8125 4.77803 16.8125H11.0625C11.3909 16.8125 11.6562 16.5472 11.6562 16.2188V3.15625C11.6562 2.82783 11.3909 2.5625 11.0625 2.5625ZM4.49414 14.8865L2.89658 13.2871H4.49414V14.8865ZM10.3203 15.4766H5.68164V12.8418C5.68164 12.4317 5.34951 12.0996 4.93945 12.0996H2.30469V3.89844H10.3203V15.4766Z" fill="currentColor" />
</svg>
</div>
</CopyToClipboard>
</div>
</div>
<div className="flex flex-row justify-between pb-6">
<div>{formatMessage({id: "DOCUMENT_STORAGE_CID"}) + ":"}</div>
<div className="flex">
<div className="pr-1 text-right">
{doc.ipfsHash && doc.ipfsHash.slice(0, 6) + '...' + doc.ipfsHash.slice(doc.ipfsHash.length - 6)}
{!doc.ipfsHash && '--'}
</div>
<CopyToClipboard text={doc.ipfsHash}>
<div className="inline mb-1 cursor-pointer">
<svg width="15" height="17" viewBox="0 0 15 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4375 0.1875H3.49219C3.41055 0.1875 3.34375 0.254297 3.34375 0.335938V1.375C3.34375 1.45664 3.41055 1.52344 3.49219 1.52344H12.6953V14.2891C12.6953 14.3707 12.7621 14.4375 12.8438 14.4375H13.8828C13.9645 14.4375 14.0312 14.3707 14.0312 14.2891V0.78125C14.0312 0.452832 13.7659 0.1875 13.4375 0.1875ZM11.0625 2.5625H1.5625C1.23408 2.5625 0.96875 2.82783 0.96875 3.15625V13.0032C0.96875 13.1609 1.03184 13.3112 1.14316 13.4226L4.35869 16.6381C4.39951 16.6789 4.4459 16.7123 4.496 16.7401V16.7754H4.57393C4.63887 16.7995 4.70752 16.8125 4.77803 16.8125H11.0625C11.3909 16.8125 11.6562 16.5472 11.6562 16.2188V3.15625C11.6562 2.82783 11.3909 2.5625 11.0625 2.5625ZM4.49414 14.8865L2.89658 13.2871H4.49414V14.8865ZM10.3203 15.4766H5.68164V12.8418C5.68164 12.4317 5.34951 12.0996 4.93945 12.0996H2.30469V3.89844H10.3203V15.4766Z" fill="currentColor" />
</svg>
</div>
</CopyToClipboard>
</div>
</div>
<div className="flex flex-row justify-between pb-6">
<div>{formatMessage({id: "DOCUMENT_META_STORAGE_CID"}) + ":"}</div>
<div className="flex">
<div className="pr-1 text-right">
{doc.metaHash && doc.metaHash.slice(0, 6) + '...' + doc.metaHash.slice(doc.metaHash.length - 6)}
{!doc.metaHash && '--'}
</div>
<CopyToClipboard text={doc.metaHash}>
<div className="inline mb-1 cursor-pointer">
<svg width="15" height="17" viewBox="0 0 15 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4375 0.1875H3.49219C3.41055 0.1875 3.34375 0.254297 3.34375 0.335938V1.375C3.34375 1.45664 3.41055 1.52344 3.49219 1.52344H12.6953V14.2891C12.6953 14.3707 12.7621 14.4375 12.8438 14.4375H13.8828C13.9645 14.4375 14.0312 14.3707 14.0312 14.2891V0.78125C14.0312 0.452832 13.7659 0.1875 13.4375 0.1875ZM11.0625 2.5625H1.5625C1.23408 2.5625 0.96875 2.82783 0.96875 3.15625V13.0032C0.96875 13.1609 1.03184 13.3112 1.14316 13.4226L4.35869 16.6381C4.39951 16.6789 4.4459 16.7123 4.496 16.7401V16.7754H4.57393C4.63887 16.7995 4.70752 16.8125 4.77803 16.8125H11.0625C11.3909 16.8125 11.6562 16.5472 11.6562 16.2188V3.15625C11.6562 2.82783 11.3909 2.5625 11.0625 2.5625ZM4.49414 14.8865L2.89658 13.2871H4.49414V14.8865ZM10.3203 15.4766H5.68164V12.8418C5.68164 12.4317 5.34951 12.0996 4.93945 12.0996H2.30469V3.89844H10.3203V15.4766Z" fill="currentColor" />
</svg>
</div>
</CopyToClipboard>
</div>
</div>
<div className="flex flex-row justify-between pb-2">
<div>{formatMessage({id: "STORAGE_PROVIDER"}) + ":"}</div>
<div className="text-right">{doc.storageProvider == "IP" ? 'IPFS (Arweave)' : (doc.storageProvider == "FL" ? 'IPFS (Fleek)' : (doc.storageProvider == "AR" ? "Arweave" : "Unknown"))}</div>
</div>
</div>
}
/>
}
{
showWebviewer &&
<DownloadPDF data={showWebviewer}
handleShowWebviewer={handleShowWebviewer}
handleShowDownloadPopup={handleShowDownloadPopup}
/>
}
</>
);
}
export default withRouter(ContractActions);