import { useEffect, useState } from 'react' import { CreateSignatureEventContent, Meta } from '../types' 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' interface FlatMeta extends Meta, CreateSignatureEventContent, Partial { // Validated create signature event isValid: boolean // Calculated status fields signedStatus: SigitStatus signersStatus: { [signer: `npub1${string}`]: SignStatus } } /** * 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() const [tags, setTags] = useState() const [created_at, setCreatedAt] = useState() const [pubkey, setPubkey] = useState() // submittedBy, pubkey from nostr event const [id, setId] = useState() const [sig, setSig] = useState() const [signers, setSigners] = useState<`npub1${string}`[]>([]) const [viewers, setViewers] = useState<`npub1${string}`[]>([]) const [fileHashes, setFileHashes] = useState<{ [user: `npub1${string}`]: string }>({}) const [markConfig, setMarkConfig] = useState([]) const [title, setTitle] = useState('') const [zipUrl, setZipUrl] = useState('') const [signedStatus, setSignedStatus] = useState( SigitStatus.Partial ) const [signersStatus, setSignersStatus] = useState<{ [signer: `npub1${string}`]: SignStatus }>({}) useEffect(() => { if (!meta) return ;(async function () { try { const createSignatureEvent = await parseCreateSignatureEvent( meta.createSignature ) const { kind, tags, created_at, pubkey, id, sig, content } = createSignatureEvent 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) 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 { 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, signersStatus } }