feat(design): home page new design and functionality #135
@ -1,6 +1,6 @@
|
||||
import { Dispatch, SetStateAction, useEffect } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Meta, ProfileMetadata } from '../../types'
|
||||
import { SigitInfo, SignedStatus } from '../../hooks/useSigitMeta'
|
||||
import { SigitCardDisplayInfo, SigitStatus } from '../../utils'
|
||||
import { Event, kinds } from 'nostr-tools'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { MetadataController } from '../../controllers'
|
||||
@ -25,17 +25,10 @@ import { getExtensionIconLabel } from '../getExtensionIconLabel'
|
||||
|
||||
type SigitProps = {
|
||||
meta: Meta
|
||||
parsedMeta: SigitInfo
|
||||
profiles: { [key: string]: ProfileMetadata }
|
||||
setProfiles: Dispatch<SetStateAction<{ [key: string]: ProfileMetadata }>>
|
||||
parsedMeta: SigitCardDisplayInfo
|
||||
}
|
||||
|
||||
export const DisplaySigit = ({
|
||||
meta,
|
||||
parsedMeta,
|
||||
profiles,
|
||||
setProfiles
|
||||
}: SigitProps) => {
|
||||
export const DisplaySigit = ({ meta, parsedMeta }: SigitProps) => {
|
||||
const {
|
||||
title,
|
||||
createdAt,
|
||||
@ -45,51 +38,67 @@ export const DisplaySigit = ({
|
||||
fileExtensions
|
||||
} = parsedMeta
|
||||
|
||||
const [profiles, setProfiles] = useState<{ [key: string]: ProfileMetadata }>(
|
||||
{}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const hexKeys: string[] = []
|
||||
const hexKeys = new Set<string>([
|
||||
...signers.map((signer) => npubToHex(signer)!)
|
||||
])
|
||||
|
||||
if (submittedBy) {
|
||||
hexKeys.push(npubToHex(submittedBy)!)
|
||||
hexKeys.add(npubToHex(submittedBy)!)
|
||||
}
|
||||
hexKeys.push(...signers.map((signer) => npubToHex(signer)!))
|
||||
|
||||
const metadataController = new MetadataController()
|
||||
|
||||
const handleMetadataEvent = (key: string) => (event: Event) => {
|
||||
const metadataContent =
|
||||
metadataController.extractProfileMetadataContent(event)
|
||||
|
||||
if (metadataContent) {
|
||||
setProfiles((prev) => ({
|
||||
...prev,
|
||||
[key]: metadataContent
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const handleEventListener =
|
||||
(key: string) => (kind: number, event: Event) => {
|
||||
if (kind === kinds.Metadata) {
|
||||
handleMetadataEvent(key)(event)
|
||||
}
|
||||
}
|
||||
|
||||
hexKeys.forEach((key) => {
|
||||
if (!(key in profiles)) {
|
||||
const handleMetadataEvent = (event: Event) => {
|
||||
const metadataContent =
|
||||
metadataController.extractProfileMetadataContent(event)
|
||||
|
||||
if (metadataContent)
|
||||
setProfiles((prev) => ({
|
||||
...prev,
|
||||
[key]: metadataContent
|
||||
}))
|
||||
}
|
||||
|
||||
metadataController.on(key, (kind: number, event: Event) => {
|
||||
if (kind === kinds.Metadata) {
|
||||
handleMetadataEvent(event)
|
||||
}
|
||||
})
|
||||
metadataController.on(key, handleEventListener(key))
|
||||
|
||||
metadataController
|
||||
.findMetadata(key)
|
||||
.then((metadataEvent) => {
|
||||
if (metadataEvent) handleMetadataEvent(metadataEvent)
|
||||
if (metadataEvent) handleMetadataEvent(key)(metadataEvent)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`error occurred in finding metadata for: ${key}`, err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [submittedBy, signers, profiles, setProfiles])
|
||||
|
||||
return () => {
|
||||
hexKeys.forEach((key) => {
|
||||
metadataController.off(key, handleEventListener(key))
|
||||
})
|
||||
}
|
||||
}, [submittedBy, signers, profiles])
|
||||
|
||||
return (
|
||||
<div className={styles.itemWrapper}>
|
||||
<Link
|
||||
to={
|
||||
signedStatus === SignedStatus.Complete
|
||||
signedStatus === SigitStatus.Complete
|
||||
? appPublicRoutes.verify
|
||||
: appPrivateRoutes.sign
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ export const DisplaySigner = ({
|
||||
const [signStatus, setSignedStatus] = useState<SignStatus>()
|
||||
|
||||
useEffect(() => {
|
||||
if (!meta) return
|
||||
|
||||
const updateSignStatus = async () => {
|
||||
const npub = hexToNpub(pubkey)
|
||||
if (npub in meta.docSignatures) {
|
||||
|
@ -1,117 +1,147 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { CreateSignatureEventContent, Meta } from '../types'
|
||||
import { parseJson } from '../utils'
|
||||
import { Mark } from '../types/mark'
|
||||
import {
|
||||
parseCreateSignatureEvent,
|
||||
parseCreateSignatureEventContent,
|
||||
SigitMetaParseError,
|
||||
SigitStatus,
|
||||
SignStatus
|
||||
} from '../utils'
|
||||
import { toast } from 'react-toastify'
|
||||
import { verifyEvent } from 'nostr-tools'
|
||||
import { Event } from 'nostr-tools'
|
||||
|
||||
type npub = `npub1${string}`
|
||||
interface FlatMeta extends Meta, CreateSignatureEventContent, Partial<Event> {
|
||||
// Validated create signature event
|
||||
isValid: boolean
|
||||
|
||||
export enum SignedStatus {
|
||||
Partial = 'In-Progress',
|
||||
Complete = 'Completed'
|
||||
}
|
||||
|
||||
export interface SigitInfo {
|
||||
createdAt?: number
|
||||
title?: string
|
||||
submittedBy?: string
|
||||
signers: npub[]
|
||||
fileExtensions: string[]
|
||||
signedStatus: SignedStatus
|
||||
}
|
||||
|
||||
export const extractSigitInfo = async (meta: Meta) => {
|
||||
if (!meta?.createSignature) return
|
||||
|
||||
const sigitInfo: SigitInfo = {
|
||||
signers: [],
|
||||
fileExtensions: [],
|
||||
signedStatus: SignedStatus.Partial
|
||||
// Calculated status fields
|
||||
signedStatus: SigitStatus
|
||||
signersStatus: {
|
||||
[signer: `npub1${string}`]: SignStatus
|
||||
}
|
||||
|
||||
const createSignatureEvent = await parseJson<Event>(
|
||||
meta.createSignature
|
||||
).catch((err) => {
|
||||
console.log('err in parsing the createSignature event:>> ', err)
|
||||
toast.error(
|
||||
err.message || 'error occurred in parsing the create signature event'
|
||||
)
|
||||
return
|
||||
})
|
||||
|
||||
if (!createSignatureEvent) return
|
||||
|
||||
// created_at in nostr events are stored in seconds
|
||||
sigitInfo.createdAt = createSignatureEvent.created_at * 1000
|
||||
|
||||
const createSignatureContent = await parseJson<CreateSignatureEventContent>(
|
||||
createSignatureEvent.content
|
||||
).catch((err) => {
|
||||
console.log(`err in parsing the createSignature event's content :>> `, err)
|
||||
return
|
||||
})
|
||||
|
||||
if (!createSignatureContent) return
|
||||
|
||||
const files = Object.keys(createSignatureContent.fileHashes)
|
||||
const extensions = files.reduce((result: string[], file: string) => {
|
||||
const extension = file.split('.').pop()
|
||||
if (extension) {
|
||||
result.push(extension)
|
||||
}
|
||||
return result
|
||||
}, [])
|
||||
|
||||
const signedBy = Object.keys(meta.docSignatures) as npub[]
|
||||
const isCompletelySigned = createSignatureContent.signers.every((signer) =>
|
||||
signedBy.includes(signer)
|
||||
)
|
||||
|
||||
sigitInfo.title = createSignatureContent.title
|
||||
sigitInfo.submittedBy = createSignatureEvent.pubkey
|
||||
sigitInfo.signers = createSignatureContent.signers
|
||||
sigitInfo.fileExtensions = extensions
|
||||
|
||||
if (isCompletelySigned) {
|
||||
sigitInfo.signedStatus = SignedStatus.Complete
|
||||
}
|
||||
|
||||
return sigitInfo
|
||||
}
|
||||
|
||||
export const useSigitMeta = (meta: Meta) => {
|
||||
const [title, setTitle] = useState<string>()
|
||||
const [createdAt, setCreatedAt] = useState<number>()
|
||||
const [submittedBy, setSubmittedBy] = useState<string>()
|
||||
const [signers, setSigners] = useState<npub[]>([])
|
||||
const [signedStatus, setSignedStatus] = useState<SignedStatus>(
|
||||
SignedStatus.Partial
|
||||
/**
|
||||
* Custom use hook for parsing the Sigit Meta
|
||||
* @param meta Sigit Meta
|
||||
* @returns flattened Meta object with calculated signed status
|
||||
*/
|
||||
export const useSigitMeta = (meta: Meta): FlatMeta => {
|
||||
const [isValid, setIsValid] = useState(false)
|
||||
const [kind, setKind] = useState<number>()
|
||||
const [tags, setTags] = useState<string[][]>()
|
||||
const [created_at, setCreatedAt] = useState<number>()
|
||||
const [pubkey, setPubkey] = useState<string>() // submittedBy, pubkey from nostr event
|
||||
const [id, setId] = useState<string>()
|
||||
const [sig, setSig] = useState<string>()
|
||||
|
||||
const [signers, setSigners] = useState<`npub1${string}`[]>([])
|
||||
const [viewers, setViewers] = useState<`npub1${string}`[]>([])
|
||||
const [fileHashes, setFileHashes] = useState<{
|
||||
[user: `npub1${string}`]: string
|
||||
}>({})
|
||||
const [markConfig, setMarkConfig] = useState<Mark[]>([])
|
||||
const [title, setTitle] = useState<string>('')
|
||||
const [zipUrl, setZipUrl] = useState<string>('')
|
||||
|
||||
const [signedStatus, setSignedStatus] = useState<SigitStatus>(
|
||||
SigitStatus.Partial
|
||||
)
|
||||
const [fileExtensions, setFileExtensions] = useState<string[]>([])
|
||||
const [signersStatus, setSignersStatus] = useState<{
|
||||
[signer: `npub1${string}`]: SignStatus
|
||||
}>({})
|
||||
|
||||
useEffect(() => {
|
||||
const getSigitInfo = async () => {
|
||||
const sigitInfo = await extractSigitInfo(meta)
|
||||
if (!meta) return
|
||||
;(async function () {
|
||||
try {
|
||||
const createSignatureEvent = await parseCreateSignatureEvent(
|
||||
meta.createSignature
|
||||
)
|
||||
|
||||
if (!sigitInfo) return
|
||||
const { kind, tags, created_at, pubkey, id, sig, content } =
|
||||
createSignatureEvent
|
||||
|
||||
setTitle(sigitInfo.title)
|
||||
setCreatedAt(sigitInfo.createdAt)
|
||||
setSubmittedBy(sigitInfo.submittedBy)
|
||||
setSigners(sigitInfo.signers)
|
||||
setSignedStatus(sigitInfo.signedStatus)
|
||||
setFileExtensions(sigitInfo.fileExtensions)
|
||||
}
|
||||
setIsValid(verifyEvent(createSignatureEvent))
|
||||
setKind(kind)
|
||||
setTags(tags)
|
||||
// created_at in nostr events are stored in seconds
|
||||
setCreatedAt(created_at * 1000)
|
||||
|
||||
setPubkey(pubkey)
|
||||
setId(id)
|
||||
setSig(sig)
|
||||
|
||||
getSigitInfo()
|
||||
const { title, signers, viewers, fileHashes, markConfig, zipUrl } =
|
||||
await parseCreateSignatureEventContent(content)
|
||||
|
||||
setTitle(title)
|
||||
setSigners(signers)
|
||||
setViewers(viewers)
|
||||
setFileHashes(fileHashes)
|
||||
setMarkConfig(markConfig)
|
||||
setZipUrl(zipUrl)
|
||||
|
||||
// Parse each signature event and set signer status
|
||||
for (const npub in meta.docSignatures) {
|
||||
try {
|
||||
const event = await parseCreateSignatureEvent(
|
||||
meta.docSignatures[npub as `npub1${string}`]
|
||||
)
|
||||
const isValidSignature = verifyEvent(event)
|
||||
setSignersStatus((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[npub]: isValidSignature
|
||||
? SignStatus.Signed
|
||||
: SignStatus.Invalid
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
setSignersStatus((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[npub]: SignStatus.Invalid
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const signedBy = Object.keys(meta.docSignatures) as `npub1${string}`[]
|
||||
const isCompletelySigned = signers.every((signer) =>
|
||||
signedBy.includes(signer)
|
||||
)
|
||||
setSignedStatus(
|
||||
isCompletelySigned ? SigitStatus.Complete : SigitStatus.Partial
|
||||
)
|
||||
} catch (error) {
|
||||
if (error instanceof SigitMetaParseError) {
|
||||
toast.error(error.message)
|
||||
}
|
||||
console.error(error)
|
||||
}
|
||||
})()
|
||||
}, [meta])
|
||||
|
||||
return {
|
||||
title,
|
||||
createdAt,
|
||||
submittedBy,
|
||||
modifiedAt: meta.modifiedAt,
|
||||
createSignature: meta.createSignature,
|
||||
docSignatures: meta.docSignatures,
|
||||
keys: meta.keys,
|
||||
isValid,
|
||||
kind,
|
||||
tags,
|
||||
created_at,
|
||||
pubkey,
|
||||
id,
|
||||
sig,
|
||||
signers,
|
||||
viewers,
|
||||
fileHashes,
|
||||
markConfig,
|
||||
title,
|
||||
zipUrl,
|
||||
signedStatus,
|
||||
fileExtensions
|
||||
signersStatus
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAppSelector } from '../../hooks'
|
||||
import { appPrivateRoutes, appPublicRoutes } from '../../routes'
|
||||
import { Meta, ProfileMetadata } from '../../types'
|
||||
import { Meta } from '../../types'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Select } from '../../components/Select'
|
||||
@ -14,10 +14,10 @@ import { useDropzone } from 'react-dropzone'
|
||||
import { Container } from '../../components/Container'
|
||||
import styles from './style.module.scss'
|
||||
import {
|
||||
extractSigitInfo,
|
||||
SigitInfo,
|
||||
SignedStatus
|
||||
} from '../../hooks/useSigitMeta'
|
||||
extractSigitCardDisplayInfo,
|
||||
SigitCardDisplayInfo,
|
||||
SigitStatus
|
||||
} from '../../utils'
|
||||
|
||||
// Unsupported Filter options are commented
|
||||
const FILTERS = [
|
||||
@ -52,29 +52,28 @@ export const HomePage = () => {
|
||||
|
||||
const [sigits, setSigits] = useState<{ [key: string]: Meta }>({})
|
||||
const [parsedSigits, setParsedSigits] = useState<{
|
||||
[key: string]: SigitInfo
|
||||
[key: string]: SigitCardDisplayInfo
|
||||
}>({})
|
||||
const [profiles, setProfiles] = useState<{ [key: string]: ProfileMetadata }>(
|
||||
{}
|
||||
)
|
||||
const usersAppData = useAppSelector((state) => state.userAppData)
|
||||
|
||||
useEffect(() => {
|
||||
if (usersAppData) {
|
||||
const getSigitInfo = async () => {
|
||||
const parsedSigits: { [key: string]: SigitCardDisplayInfo } = {}
|
||||
for (const key in usersAppData.sigits) {
|
||||
if (Object.prototype.hasOwnProperty.call(usersAppData.sigits, key)) {
|
||||
const sigitInfo = await extractSigitInfo(usersAppData.sigits[key])
|
||||
const sigitInfo = await extractSigitCardDisplayInfo(
|
||||
usersAppData.sigits[key]
|
||||
)
|
||||
if (sigitInfo) {
|
||||
setParsedSigits((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[key]: sigitInfo
|
||||
}
|
||||
})
|
||||
parsedSigits[key] = sigitInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setParsedSigits({
|
||||
...parsedSigits
|
||||
})
|
||||
}
|
||||
|
||||
setSigits(usersAppData.sigits)
|
||||
@ -240,9 +239,9 @@ export const HomePage = () => {
|
||||
const isMatch = title?.toLowerCase().includes(q.toLowerCase())
|
||||
switch (filter) {
|
||||
case 'Completed':
|
||||
return signedStatus === SignedStatus.Complete && isMatch
|
||||
return signedStatus === SigitStatus.Complete && isMatch
|
||||
case 'In-progress':
|
||||
return signedStatus === SignedStatus.Partial && isMatch
|
||||
return signedStatus === SigitStatus.Partial && isMatch
|
||||
case 'Show all':
|
||||
return isMatch
|
||||
default:
|
||||
@ -259,8 +258,6 @@ export const HomePage = () => {
|
||||
key={`sigit-${key}`}
|
||||
parsedMeta={parsedSigits[key]}
|
||||
meta={sigits[key]}
|
||||
profiles={profiles}
|
||||
setProfiles={setProfiles}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -7,3 +7,4 @@ export * from './string'
|
||||
export * from './zip'
|
||||
export * from './utils'
|
||||
export * from './mark'
|
||||
export * from './meta'
|
||||
|
181
src/utils/meta.ts
Normal file
181
src/utils/meta.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import { CreateSignatureEventContent, Meta } from '../types'
|
||||
import { parseJson } from '.'
|
||||
import { Event } from 'nostr-tools'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
export enum SignStatus {
|
||||
Signed = 'Signed',
|
||||
Pending = 'Pending',
|
||||
Invalid = 'Invalid Sign'
|
||||
}
|
||||
|
||||
export enum SigitStatus {
|
||||
Partial = 'In-Progress',
|
||||
Complete = 'Completed'
|
||||
}
|
||||
|
||||
type Jsonable =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| undefined
|
||||
| readonly Jsonable[]
|
||||
| { readonly [key: string]: Jsonable }
|
||||
| { toJSON(): Jsonable }
|
||||
|
||||
export class SigitMetaParseError extends Error {
|
||||
public readonly context?: Jsonable
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
options: { cause?: Error; context?: Jsonable } = {}
|
||||
) {
|
||||
const { cause, context } = options
|
||||
|
||||
super(message, { cause })
|
||||
this.name = this.constructor.name
|
||||
|
||||
this.context = context
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle meta errors
|
||||
* Wraps the errors without message property and stringify to a message so we can use it later
|
||||
* @param error
|
||||
* @returns
|
||||
*/
|
||||
function handleError(error: unknown): Error {
|
||||
if (error instanceof Error) return error
|
||||
|
||||
// No message error, wrap it and stringify
|
||||
let stringified = 'Unable to stringify the thrown value'
|
||||
try {
|
||||
stringified = JSON.stringify(error)
|
||||
} catch (error) {
|
||||
console.error(stringified, error)
|
||||
}
|
||||
|
||||
return new Error(`[SiGit Error]: ${stringified}`)
|
||||
}
|
||||
|
||||
// Reuse common error messages for meta parsing
|
||||
export enum SigitMetaParseErrorType {
|
||||
'PARSE_ERROR_SIGNATURE_EVENT' = 'error occurred in parsing the create signature event',
|
||||
'PARSE_ERROR_SIGNATURE_EVENT_CONTENT' = "err in parsing the createSignature event's content"
|
||||
}
|
||||
|
||||
export interface SigitCardDisplayInfo {
|
||||
createdAt?: number
|
||||
title?: string
|
||||
submittedBy?: string
|
||||
signers: `npub1${string}`[]
|
||||
fileExtensions: string[]
|
||||
signedStatus: SigitStatus
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for createSignatureEvent parse that throws custom SigitMetaParseError with cause and context
|
||||
* @param raw Raw string for parsing
|
||||
* @returns parsed Event
|
||||
*/
|
||||
export const parseCreateSignatureEvent = async (
|
||||
raw: string
|
||||
): Promise<Event> => {
|
||||
try {
|
||||
const createSignatureEvent = await parseJson<Event>(raw)
|
||||
return createSignatureEvent
|
||||
} catch (error) {
|
||||
throw new SigitMetaParseError(
|
||||
SigitMetaParseErrorType.PARSE_ERROR_SIGNATURE_EVENT,
|
||||
{
|
||||
cause: handleError(error),
|
||||
context: raw
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for event content parser that throws custom SigitMetaParseError with cause and context
|
||||
* @param raw Raw string for parsing
|
||||
* @returns parsed CreateSignatureEventContent
|
||||
*/
|
||||
export const parseCreateSignatureEventContent = async (
|
||||
raw: string
|
||||
): Promise<CreateSignatureEventContent> => {
|
||||
try {
|
||||
const createSignatureEventContent =
|
||||
await parseJson<CreateSignatureEventContent>(raw)
|
||||
return createSignatureEventContent
|
||||
} catch (error) {
|
||||
throw new SigitMetaParseError(
|
||||
SigitMetaParseErrorType.PARSE_ERROR_SIGNATURE_EVENT_CONTENT,
|
||||
{
|
||||
cause: handleError(error),
|
||||
context: raw
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts only necessary metadata for the card display
|
||||
* @param meta Sigit metadata
|
||||
* @returns SigitCardDisplayInfo
|
||||
*/
|
||||
export const extractSigitCardDisplayInfo = async (meta: Meta) => {
|
||||
if (!meta?.createSignature) return
|
||||
|
||||
const sigitInfo: SigitCardDisplayInfo = {
|
||||
signers: [],
|
||||
fileExtensions: [],
|
||||
signedStatus: SigitStatus.Partial
|
||||
}
|
||||
|
||||
try {
|
||||
const createSignatureEvent = await parseCreateSignatureEvent(
|
||||
meta.createSignature
|
||||
)
|
||||
|
||||
// created_at in nostr events are stored in seconds
|
||||
sigitInfo.createdAt = createSignatureEvent.created_at * 1000
|
||||
|
||||
const createSignatureContent = await parseCreateSignatureEventContent(
|
||||
createSignatureEvent.content
|
||||
)
|
||||
|
||||
const files = Object.keys(createSignatureContent.fileHashes)
|
||||
const extensions = files.reduce((result: string[], file: string) => {
|
||||
const extension = file.split('.').pop()
|
||||
if (extension) {
|
||||
result.push(extension)
|
||||
}
|
||||
return result
|
||||
}, [])
|
||||
|
||||
const signedBy = Object.keys(meta.docSignatures) as `npub1${string}`[]
|
||||
const isCompletelySigned = createSignatureContent.signers.every((signer) =>
|
||||
signedBy.includes(signer)
|
||||
)
|
||||
|
||||
sigitInfo.title = createSignatureContent.title
|
||||
sigitInfo.submittedBy = createSignatureEvent.pubkey
|
||||
sigitInfo.signers = createSignatureContent.signers
|
||||
sigitInfo.fileExtensions = extensions
|
||||
|
||||
if (isCompletelySigned) {
|
||||
sigitInfo.signedStatus = SigitStatus.Complete
|
||||
}
|
||||
|
||||
return sigitInfo
|
||||
} catch (error) {
|
||||
if (error instanceof SigitMetaParseError) {
|
||||
toast.error(error.message)
|
||||
console.error(error.name, error.message, error.cause, error.context)
|
||||
} else {
|
||||
console.error('Unexpected error', error)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user
created_at * 1000
should be made into a utility function and used in other similar places (there is at least one that I could find).Similarly, there is a reverse action,
created_at / 1000
, which should also be a utility.