fix: load screen on sign, block on missing counterpart #170

Merged
enes merged 7 commits from 137-sign-loading-error into staging 2024-08-29 11:02:19 +00:00
Showing only changes of commit 624afae851 - Show all commits

View File

@ -514,6 +514,9 @@ export const CreatePage = () => {
return (
file.pages?.flatMap((page, index) => {
return page.drawnFields.map((drawnField) => {
if (!drawnField.counterpart) {
throw new Error('Missing counterpart')
}
return {
type: drawnField.type,
location: {
@ -670,6 +673,7 @@ export const CreatePage = () => {
}
const generateCreateSignature = async (
markConfig: Mark[],
fileHashes: {
[key: string]: string
},
@ -677,7 +681,6 @@ export const CreatePage = () => {
) => {
const signers = users.filter((user) => user.role === UserRole.signer)
const viewers = users.filter((user) => user.role === UserRole.viewer)
const markConfig = createMarks(fileHashes)
const content: CreateSignatureEventContent = {
signers: signers.map((signer) => hexToNpub(signer.pubkey)),
@ -721,131 +724,152 @@ export const CreatePage = () => {
}
const handleCreate = async () => {
if (!validateInputs()) return
try {
if (!validateInputs()) return
setIsLoading(true)
setLoadingSpinnerDesc('Generating file hashes')
const fileHashes = await generateFileHashes()
if (!fileHashes) {
setIsLoading(true)
Review

I wonder if this flow should be refactored, given our recent conversation about error handling. I also thing that there are more efficient ways to handle loading state changes.

Having said that, perhaps it is best left to a separate PR. Worth adding as an issue?

I wonder if this flow should be refactored, given our recent conversation about error handling. I also thing that there are more efficient ways to handle loading state changes. Having said that, perhaps it is best left to a separate PR. Worth adding as an issue?
Review

I think we can for now just leave finally, to execute setIsLoading(false) once, we don't need it in each return

I think we can for now just leave `finally`, to execute `setIsLoading(false)` once, we don't need it in each return
setLoadingSpinnerDesc('Generating file hashes')
const fileHashes = await generateFileHashes()
if (!fileHashes) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating encryption key')
const encryptionKey = await generateEncryptionKey()
if (await isOnline()) {
setLoadingSpinnerDesc('generating files.zip')
const arrayBuffer = await generateFilesZip()
if (!arrayBuffer) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Encrypting files.zip')
const encryptedArrayBuffer = await encryptZipFile(
arrayBuffer,
encryptionKey
)
const markConfig = createMarks(fileHashes)
setLoadingSpinnerDesc('Uploading files.zip to file storage')
const fileUrl = await uploadFile(encryptedArrayBuffer)
if (!fileUrl) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating create signature')
const createSignature = await generateCreateSignature(
markConfig,
fileHashes,
fileUrl
)
if (!createSignature) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating keys for decryption')
// generate key pairs for decryption
const pubkeys = users.map((user) => user.pubkey)
// also add creator in the list
if (pubkeys.includes(usersPubkey!)) {
pubkeys.push(usersPubkey!)
}
const keys = await generateKeys(pubkeys, encryptionKey)
if (!keys) {
setIsLoading(false)
return
}
const meta: Meta = {
createSignature,
keys,
modifiedAt: unixNow(),
docSignatures: {}
}
setLoadingSpinnerDesc('Updating user app data')
const event = await updateUsersAppData(meta)
if (!event) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Sending notifications to counterparties')
const promises = sendNotifications(meta)
await Promise.all(promises)
Review

A promise doesn't need to be awaited if chaining is used.

A promise doesn't need to be awaited if chaining is used.
Review

We are blocking so we don't navigate away before .all is done.
Another question is if we need to block at all since even if it's rejected, we proceed to another page anyway?

We are blocking so we don't navigate away before `.all` is done. Another question is if we need to block at all since even if it's rejected, we proceed to another page anyway?
.then(() => {
toast.success('Notifications sent successfully')
})
.catch(() => {
toast.error('Failed to publish notifications')
})
navigate(appPrivateRoutes.sign, { state: { meta: meta } })
} else {
const zip = new JSZip()
selectedFiles.forEach((file) => {
zip.file(`files/${file.name}`, file)
})
const markConfig = createMarks(fileHashes)
setLoadingSpinnerDesc('Generating create signature')
const createSignature = await generateCreateSignature(
markConfig,
fileHashes,
''
)
if (!createSignature) {
setIsLoading(false)
return
}
const meta: Meta = {
createSignature,
modifiedAt: unixNow(),
docSignatures: {}
}
// add meta to zip
try {
const stringifiedMeta = JSON.stringify(meta, null, 2)
zip.file('meta.json', stringifiedMeta)
} catch (err) {
console.error(err)
toast.error('An error occurred in converting meta json to string')
return null
}
const arrayBuffer = await generateZipFile(zip)
if (!arrayBuffer) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Encrypting zip file')
const encryptedArrayBuffer = await encryptZipFile(
arrayBuffer,
encryptionKey
)
await handleOfflineFlow(encryptedArrayBuffer, encryptionKey)
}
} catch (error) {
if (error instanceof Error) {
toast.error(error.message)
}
console.error(error)
} finally {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating encryption key')
const encryptionKey = await generateEncryptionKey()
if (await isOnline()) {
setLoadingSpinnerDesc('generating files.zip')
const arrayBuffer = await generateFilesZip()
if (!arrayBuffer) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Encrypting files.zip')
const encryptedArrayBuffer = await encryptZipFile(
arrayBuffer,
encryptionKey
)
setLoadingSpinnerDesc('Uploading files.zip to file storage')
const fileUrl = await uploadFile(encryptedArrayBuffer)
if (!fileUrl) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating create signature')
const createSignature = await generateCreateSignature(fileHashes, fileUrl)
if (!createSignature) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Generating keys for decryption')
// generate key pairs for decryption
const pubkeys = users.map((user) => user.pubkey)
// also add creator in the list
if (pubkeys.includes(usersPubkey!)) {
pubkeys.push(usersPubkey!)
}
const keys = await generateKeys(pubkeys, encryptionKey)
if (!keys) {
setIsLoading(false)
return
}
const meta: Meta = {
createSignature,
keys,
modifiedAt: unixNow(),
docSignatures: {}
}
setLoadingSpinnerDesc('Updating user app data')
const event = await updateUsersAppData(meta)
if (!event) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Sending notifications to counterparties')
const promises = sendNotifications(meta)
await Promise.all(promises)
.then(() => {
toast.success('Notifications sent successfully')
})
.catch(() => {
toast.error('Failed to publish notifications')
})
navigate(appPrivateRoutes.sign, { state: { meta: meta } })
} else {
const zip = new JSZip()
selectedFiles.forEach((file) => {
zip.file(`files/${file.name}`, file)
})
setLoadingSpinnerDesc('Generating create signature')
const createSignature = await generateCreateSignature(fileHashes, '')
if (!createSignature) {
setIsLoading(false)
return
}
const meta: Meta = {
createSignature,
modifiedAt: unixNow(),
docSignatures: {}
}
// add meta to zip
try {
const stringifiedMeta = JSON.stringify(meta, null, 2)
zip.file('meta.json', stringifiedMeta)
} catch (err) {
console.error(err)
toast.error('An error occurred in converting meta json to string')
return null
}
const arrayBuffer = await generateZipFile(zip)
if (!arrayBuffer) {
setIsLoading(false)
return
}
setLoadingSpinnerDesc('Encrypting zip file')
const encryptedArrayBuffer = await encryptZipFile(
arrayBuffer,
encryptionKey
)
await handleOfflineFlow(encryptedArrayBuffer, encryptionKey)
}
}