import { CurrentUserMark, Mark } from '../types/mark.ts' import { hexToNpub } from './nostr.ts' import { Meta, SignedEventContent } from '../types' import { Event } from 'nostr-tools' import { EMPTY } from './const.ts' /** * Takes in an array of Marks already filtered by User. * Returns an array of CurrentUserMarks with correct values mix-and-matched. * @param marks - default Marks extracted from Meta * @param signedMetaMarks - signed user Marks extracted from DocSignatures */ const getCurrentUserMarks = ( marks: Mark[], signedMetaMarks: Mark[] ): CurrentUserMark[] => { return marks.map((mark, index, arr) => { const signedMark = signedMetaMarks.find((m) => m.id === mark.id) return { mark, currentValue: signedMark?.value ?? EMPTY, id: index + 1, isLast: isLast(index, arr), isCompleted: !!signedMark?.value } }) } /** * Returns next incomplete CurrentUserMark if there is one * @param usersMarks */ const findNextIncompleteCurrentUserMark = ( usersMarks: CurrentUserMark[] ): CurrentUserMark | undefined => { return usersMarks.find((mark) => !mark.isCompleted) } /** * Returns Marks that are assigned to a specific user * @param marks * @param pubkey */ const filterMarksByPubkey = (marks: Mark[], pubkey: string): Mark[] => { return marks.filter((mark) => mark.npub === hexToNpub(pubkey)) } /** * Takes Signed Doc Signatures part of Meta and extracts * all Marks into one flar array, regardless of the user. * @param meta */ const extractMarksFromSignedMeta = (meta: Meta): Mark[] => { return Object.values(meta.docSignatures) .map((val: string) => JSON.parse(val as string)) .map((val: Event) => JSON.parse(val.content)) .flatMap((val: SignedEventContent) => val.marks) } /** * Checks the CurrentUserMarks array that every element in that array has been * marked as complete. * @param currentUserMarks */ const isCurrentUserMarksComplete = ( currentUserMarks: CurrentUserMark[] ): boolean => { return currentUserMarks.every((mark) => mark.isCompleted) } /** * Inserts an updated mark into an existing array of marks. Returns a copy of the * existing array with a new value inserted * @param marks * @param markToUpdate */ const updateMarks = (marks: Mark[], markToUpdate: Mark): Mark[] => { const indexToUpdate = marks.findIndex((mark) => mark.id === markToUpdate.id) return [ ...marks.slice(0, indexToUpdate), markToUpdate, ...marks.slice(indexToUpdate + 1) ] } const updateCurrentUserMarks = ( currentUserMarks: CurrentUserMark[], markToUpdate: CurrentUserMark ): CurrentUserMark[] => { const indexToUpdate = currentUserMarks.findIndex( (m) => m.mark.id === markToUpdate.mark.id ) return [ ...currentUserMarks.slice(0, indexToUpdate), markToUpdate, ...currentUserMarks.slice(indexToUpdate + 1) ] } const isLast = (index: number, arr: T[]) => index === arr.length - 1 const isCurrentValueLast = ( currentUserMarks: CurrentUserMark[], selectedMark: CurrentUserMark, selectedMarkValue: string ) => { const filteredMarks = currentUserMarks.filter( (mark) => mark.id !== selectedMark.id ) return ( isCurrentUserMarksComplete(filteredMarks) && selectedMarkValue.length > 0 ) } const getUpdatedMark = ( selectedMark: CurrentUserMark, selectedMarkValue: string ): CurrentUserMark => { return { ...selectedMark, currentValue: selectedMarkValue, isCompleted: !!selectedMarkValue, mark: { ...selectedMark.mark, value: selectedMarkValue } } } const findOtherUserMarks = (marks: Mark[], pubkey: string): Mark[] => { return marks.filter((mark) => mark.npub !== hexToNpub(pubkey)) } export { getCurrentUserMarks, filterMarksByPubkey, extractMarksFromSignedMeta, isCurrentUserMarksComplete, findNextIncompleteCurrentUserMark, updateMarks, updateCurrentUserMarks, isCurrentValueLast, getUpdatedMark, findOtherUserMarks }