Signing Page - New Design #152
@ -71,6 +71,10 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.edited {
|
||||
border: 1px dotted #01aaad
|
||||
}
|
||||
|
||||
.resizeHandle {
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
|
102
src/components/MarkFormField/index.tsx
Normal file
102
src/components/MarkFormField/index.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
import { CurrentUserMark } from '../../types/mark.ts'
|
||||
import styles from './style.module.scss'
|
||||
|
||||
import { MARK_TYPE_TRANSLATION, NEXT, SIGN } from '../../utils/const.ts'
|
||||
import {
|
||||
findNextIncompleteCurrentUserMark,
|
||||
isCurrentUserMarksComplete,
|
||||
isCurrentValueLast
|
||||
} from '../../utils'
|
||||
|
||||
interface MarkFormFieldProps {
|
||||
handleSubmit: (event: any) => void
|
||||
handleSelectedMarkValueChange: (event: any) => void
|
||||
selectedMark: CurrentUserMark
|
||||
selectedMarkValue: string
|
||||
currentUserMarks: CurrentUserMark[]
|
||||
handleCurrentUserMarkChange: (mark: CurrentUserMark) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for rendering a form field connected to a mark and keeping track of its value.
|
||||
*/
|
||||
const MarkFormField = ({
|
||||
handleSubmit,
|
||||
handleSelectedMarkValueChange,
|
||||
selectedMark,
|
||||
selectedMarkValue,
|
||||
currentUserMarks,
|
||||
handleCurrentUserMarkChange
|
||||
}: MarkFormFieldProps) => {
|
||||
const getSubmitButtonText = () => (isReadyToSign() ? SIGN : NEXT)
|
||||
const isReadyToSign = () =>
|
||||
isCurrentUserMarksComplete(currentUserMarks) ||
|
||||
isCurrentValueLast(currentUserMarks, selectedMark, selectedMarkValue)
|
||||
const isCurrent = (currentMark: CurrentUserMark) =>
|
||||
currentMark.id === selectedMark.id
|
||||
const isDone = (currentMark: CurrentUserMark) => currentMark.isCompleted
|
||||
const findNext = () => {
|
||||
return (
|
||||
currentUserMarks[selectedMark.id] ||
|
||||
findNextIncompleteCurrentUserMark(currentUserMarks)
|
||||
)
|
||||
}
|
||||
const handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault()
|
||||
console.log('handle form submit runs...')
|
||||
return isReadyToSign()
|
||||
? handleSubmit(event)
|
||||
: handleCurrentUserMarkChange(findNext()!)
|
||||
}
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.actions}>
|
||||
<div className={styles.actionsWrapper}>
|
||||
<div className={styles.actionsTop}>
|
||||
<div className={styles.actionsTopInfo}>
|
||||
<p className={styles.actionsTopInfoText}>Add your signature</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.inputWrapper}>
|
||||
<form onSubmit={(e) => handleFormSubmit(e)}>
|
||||
<input
|
||||
className={styles.input}
|
||||
placeholder={
|
||||
MARK_TYPE_TRANSLATION[selectedMark.mark.type.valueOf()]
|
||||
}
|
||||
onChange={handleSelectedMarkValueChange}
|
||||
value={selectedMarkValue}
|
||||
/>
|
||||
<div className={styles.actionsBottom}>
|
||||
<button type="submit" className={styles.submitButton}>
|
||||
{getSubmitButtonText()}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className={styles.footerContainer}>
|
||||
<div className={styles.footer}>
|
||||
{currentUserMarks.map((mark, index) => {
|
||||
return (
|
||||
<div className={styles.pagination} key={index}>
|
||||
<button
|
||||
className={`${styles.paginationButton} ${isDone(mark) && styles.paginationButtonDone}`}
|
||||
onClick={() => handleCurrentUserMarkChange(mark)}
|
||||
>
|
||||
{mark.id}
|
||||
</button>
|
||||
{isCurrent(mark) && (
|
||||
<div className={styles.paginationButtonCurrent}></div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarkFormField
|
187
src/components/MarkFormField/style.module.scss
Normal file
187
src/components/MarkFormField/style.module.scss
Normal file
@ -0,0 +1,187 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actions {
|
||||
background: white;
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
grid-gap: 15px;
|
||||
box-shadow: 0 -2px 4px 0 rgb(0,0,0,0.1);
|
||||
max-width: 750px;
|
||||
}
|
||||
|
||||
.actionsWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-gap: 20px;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.actionsTop {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actionsTopInfo {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.actionsTopInfoText {
|
||||
font-size: 16px;
|
||||
color: #434343;
|
||||
}
|
||||
|
||||
.actionsTrigger {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.actionButtons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-gap: 5px;
|
||||
}
|
||||
|
||||
.inputWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.textInput {
|
||||
height: 100px;
|
||||
background: rgba(0,0,0,0.1);
|
||||
border-radius: 4px;
|
||||
border: solid 2px #4c82a3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
border-radius: 4px;
|
||||
border: solid 1px rgba(0,0,0,0.15);
|
||||
padding: 5px 10px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
background: linear-gradient(rgba(0,0,0,0.00), rgba(0,0,0,0.00) 100%), linear-gradient(white, white);
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
border: solid 1px rgba(0,0,0,0.15);
|
||||
outline: none;
|
||||
background: linear-gradient(rgba(0,0,0,0.05), rgba(0,0,0,0.05) 100%), linear-gradient(white, white);
|
||||
}
|
||||
|
||||
.actionsBottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-gap: 5px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button {
|
||||
transition: ease 0.2s;
|
||||
width: auto;
|
||||
border-radius: 4px;
|
||||
outline: unset;
|
||||
border: unset;
|
||||
background: unset;
|
||||
color: #ffffff;
|
||||
background: #4c82a3;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
padding: 8px 15px;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-gap: 12px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-decoration: unset;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transition: ease 0.2s;
|
||||
background: #5e8eab;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button:active {
|
||||
transition: ease 0.2s;
|
||||
background: #447592;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.footerContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-gap: 5px;
|
||||
align-items: start;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-gap: 5px;
|
||||
}
|
||||
|
||||
.paginationButton {
|
||||
font-size: 12px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
background: rgba(0,0,0,0.1);
|
||||
color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.paginationButton:hover {
|
||||
background: #447592;
|
||||
color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
.paginationButtonDone {
|
||||
background: #5e8eab;
|
||||
color: rgb(255,255,255);
|
||||
}
|
||||
|
||||
.paginationButtonCurrent {
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
background: #4c82a3;
|
||||
}
|
@ -12,26 +12,31 @@ interface PdfMarkItemProps {
|
||||
/**
|
||||
* Responsible for display an individual Pdf Mark.
|
||||
*/
|
||||
const PdfMarkItem = ({ selectedMark, handleMarkClick, selectedMarkValue, userMark }: PdfMarkItemProps) => {
|
||||
const { location } = userMark.mark;
|
||||
const handleClick = () => handleMarkClick(userMark.mark.id);
|
||||
const getMarkValue = () => (
|
||||
selectedMark?.mark.id === userMark.mark.id
|
||||
? selectedMarkValue
|
||||
: userMark.mark.value
|
||||
)
|
||||
const PdfMarkItem = ({
|
||||
selectedMark,
|
||||
handleMarkClick,
|
||||
selectedMarkValue,
|
||||
userMark
|
||||
}: PdfMarkItemProps) => {
|
||||
const { location } = userMark.mark
|
||||
const handleClick = () => handleMarkClick(userMark.mark.id)
|
||||
const isEdited = () => selectedMark?.mark.id === userMark.mark.id
|
||||
const getMarkValue = () =>
|
||||
isEdited() ? selectedMarkValue : userMark.currentValue
|
||||
return (
|
||||
<div
|
||||
onClick={handleClick}
|
||||
className={styles.drawingRectangle}
|
||||
className={`${styles.drawingRectangle} ${isEdited() && styles.edited}`}
|
||||
style={{
|
||||
left: inPx(location.left),
|
||||
top: inPx(location.top),
|
||||
width: inPx(location.width),
|
||||
height: inPx(location.height)
|
||||
}}
|
||||
>{getMarkValue()}</div>
|
||||
>
|
||||
{getMarkValue()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PdfMarkItem
|
||||
export default PdfMarkItem
|
||||
|
@ -1,22 +1,23 @@
|
||||
import PdfView from './index.tsx'
|
||||
import MarkFormField from '../../pages/sign/MarkFormField.tsx'
|
||||
import MarkFormField from '../MarkFormField'
|
||||
import { PdfFile } from '../../types/drawing.ts'
|
||||
import { CurrentUserMark, Mark } from '../../types/mark.ts'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import {
|
||||
findNextCurrentUserMark,
|
||||
findNextIncompleteCurrentUserMark,
|
||||
getUpdatedMark,
|
||||
isCurrentUserMarksComplete,
|
||||
updateCurrentUserMarks,
|
||||
updateCurrentUserMarks
|
||||
} from '../../utils'
|
||||
import { EMPTY } from '../../utils/const.ts'
|
||||
import { Container } from '../Container'
|
||||
import styles from '../../pages/sign/style.module.scss'
|
||||
|
||||
interface PdfMarkingProps {
|
||||
files: { pdfFile: PdfFile, filename: string, hash: string | null }[],
|
||||
currentUserMarks: CurrentUserMark[],
|
||||
setIsReadyToSign: (isReadyToSign: boolean) => void,
|
||||
setCurrentUserMarks: (currentUserMarks: CurrentUserMark[]) => void,
|
||||
files: { pdfFile: PdfFile; filename: string; hash: string | null }[]
|
||||
currentUserMarks: CurrentUserMark[]
|
||||
setIsReadyToSign: (isReadyToSign: boolean) => void
|
||||
setCurrentUserMarks: (currentUserMarks: CurrentUserMark[]) => void
|
||||
setUpdatedMarks: (markToUpdate: Mark) => void
|
||||
}
|
||||
|
||||
@ -35,66 +36,89 @@ const PdfMarking = (props: PdfMarkingProps) => {
|
||||
setUpdatedMarks
|
||||
} = props
|
||||
const [selectedMark, setSelectedMark] = useState<CurrentUserMark | null>(null)
|
||||
const [selectedMarkValue, setSelectedMarkValue] = useState<string>("")
|
||||
const [selectedMarkValue, setSelectedMarkValue] = useState<string>('')
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedMark(findNextCurrentUserMark(currentUserMarks) || null)
|
||||
}, [currentUserMarks])
|
||||
setSelectedMark(findNextIncompleteCurrentUserMark(currentUserMarks) || null)
|
||||
}, [])
|
||||
|
||||
const handleMarkClick = (id: number) => {
|
||||
const nextMark = currentUserMarks.find((mark) => mark.mark.id === id);
|
||||
setSelectedMark(nextMark!);
|
||||
setSelectedMarkValue(nextMark?.mark.value ?? EMPTY);
|
||||
const nextMark = currentUserMarks.find((mark) => mark.mark.id === id)
|
||||
setSelectedMark(nextMark!)
|
||||
setSelectedMarkValue(nextMark?.mark.value ?? EMPTY)
|
||||
}
|
||||
|
||||
const handleCurrentUserMarkChange = (mark: CurrentUserMark) => {
|
||||
if (!selectedMark) return
|
||||
const updatedSelectedMark: CurrentUserMark = getUpdatedMark(
|
||||
selectedMark,
|
||||
selectedMarkValue
|
||||
)
|
||||
|
||||
const updatedCurrentUserMarks = updateCurrentUserMarks(
|
||||
currentUserMarks,
|
||||
updatedSelectedMark
|
||||
)
|
||||
setCurrentUserMarks(updatedCurrentUserMarks)
|
||||
setSelectedMark(mark)
|
||||
setSelectedMarkValue(mark.currentValue ?? EMPTY)
|
||||
}
|
||||
|
||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
if (!selectedMarkValue || !selectedMark) return;
|
||||
event.preventDefault()
|
||||
if (!selectedMarkValue || !selectedMark) return
|
||||
|
||||
const updatedMark: CurrentUserMark = {
|
||||
...selectedMark,
|
||||
mark: {
|
||||
...selectedMark.mark,
|
||||
value: selectedMarkValue
|
||||
},
|
||||
isCompleted: true
|
||||
}
|
||||
const updatedMark: CurrentUserMark = getUpdatedMark(
|
||||
selectedMark,
|
||||
selectedMarkValue
|
||||
)
|
||||
|
||||
setSelectedMarkValue(EMPTY)
|
||||
const updatedCurrentUserMarks = updateCurrentUserMarks(currentUserMarks, updatedMark);
|
||||
const updatedCurrentUserMarks = updateCurrentUserMarks(
|
||||
currentUserMarks,
|
||||
updatedMark
|
||||
)
|
||||
setCurrentUserMarks(updatedCurrentUserMarks)
|
||||
setSelectedMark(findNextCurrentUserMark(updatedCurrentUserMarks) || null)
|
||||
console.log(isCurrentUserMarksComplete(updatedCurrentUserMarks))
|
||||
setIsReadyToSign(isCurrentUserMarksComplete(updatedCurrentUserMarks))
|
||||
setSelectedMark(null)
|
||||
setIsReadyToSign(true)
|
||||
setUpdatedMarks(updatedMark.mark)
|
||||
}
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setSelectedMarkValue(event.target.value)
|
||||
// const updateCurrentUserMarkValues = () => {
|
||||
// const updatedMark: CurrentUserMark = getUpdatedMark(selectedMark!, selectedMarkValue)
|
||||
// const updatedCurrentUserMarks = updateCurrentUserMarks(currentUserMarks, updatedMark)
|
||||
// setSelectedMarkValue(EMPTY)
|
||||
// setCurrentUserMarks(updatedCurrentUserMarks)
|
||||
// }
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setSelectedMarkValue(event.target.value)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container className={styles.container}>
|
||||
{
|
||||
currentUserMarks?.length > 0 && (
|
||||
<PdfView
|
||||
files={files}
|
||||
handleMarkClick={handleMarkClick}
|
||||
selectedMarkValue={selectedMarkValue}
|
||||
selectedMark={selectedMark}
|
||||
currentUserMarks={currentUserMarks}
|
||||
/>)}
|
||||
{
|
||||
selectedMark !== null && (
|
||||
<MarkFormField
|
||||
handleSubmit={handleSubmit}
|
||||
handleChange={handleChange}
|
||||
selectedMark={selectedMark}
|
||||
selectedMarkValue={selectedMarkValue}
|
||||
/>
|
||||
)}
|
||||
{currentUserMarks?.length > 0 && (
|
||||
<PdfView
|
||||
files={files}
|
||||
handleMarkClick={handleMarkClick}
|
||||
selectedMarkValue={selectedMarkValue}
|
||||
selectedMark={selectedMark}
|
||||
currentUserMarks={currentUserMarks}
|
||||
/>
|
||||
)}
|
||||
{selectedMark !== null && (
|
||||
<MarkFormField
|
||||
handleSubmit={handleSubmit}
|
||||
handleSelectedMarkValueChange={handleChange}
|
||||
selectedMark={selectedMark}
|
||||
selectedMarkValue={selectedMarkValue}
|
||||
currentUserMarks={currentUserMarks}
|
||||
handleCurrentUserMarkChange={handleCurrentUserMarkChange}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PdfMarking
|
||||
export default PdfMarking
|
||||
|
@ -1,37 +0,0 @@
|
||||
import { CurrentUserMark } from '../../types/mark.ts'
|
||||
import styles from './style.module.scss'
|
||||
import { Box, Button, TextField } from '@mui/material'
|
||||
|
||||
import { MARK_TYPE_TRANSLATION } from '../../utils/const.ts'
|
||||
|
||||
interface MarkFormFieldProps {
|
||||
handleSubmit: (event: any) => void
|
||||
handleChange: (event: any) => void
|
||||
selectedMark: CurrentUserMark
|
||||
selectedMarkValue: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for rendering a form field connected to a mark and keeping track of its value.
|
||||
*/
|
||||
const MarkFormField = (props: MarkFormFieldProps) => {
|
||||
const { handleSubmit, handleChange, selectedMark, selectedMarkValue } = props;
|
||||
const getSubmitButton = () => selectedMark.isLast ? 'Complete' : 'Next';
|
||||
return (
|
||||
<div className={styles.fixedBottomForm}>
|
||||
<Box component="form" onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="mark-value"
|
||||
label={MARK_TYPE_TRANSLATION[selectedMark.mark.type.valueOf()]}
|
||||
value={selectedMarkValue}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Button type="submit" variant="contained">
|
||||
{getSubmitButton()}
|
||||
</Button>
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarkFormField;
|
@ -1,24 +1,26 @@
|
||||
import { MarkType } from "./drawing";
|
||||
import { MarkType } from './drawing'
|
||||
|
||||
export interface CurrentUserMark {
|
||||
id: number
|
||||
mark: Mark
|
||||
isLast: boolean
|
||||
isCompleted: boolean
|
||||
currentValue?: string
|
||||
}
|
||||
|
||||
export interface Mark {
|
||||
id: number;
|
||||
npub: string;
|
||||
pdfFileHash: string;
|
||||
type: MarkType;
|
||||
location: MarkLocation;
|
||||
value?: string;
|
||||
id: number
|
||||
npub: string
|
||||
pdfFileHash: string
|
||||
type: MarkType
|
||||
location: MarkLocation
|
||||
value?: string
|
||||
}
|
||||
|
||||
export interface MarkLocation {
|
||||
top: number;
|
||||
left: number;
|
||||
height: number;
|
||||
width: number;
|
||||
page: number;
|
||||
top: number
|
||||
left: number
|
||||
height: number
|
||||
width: number
|
||||
page: number
|
||||
}
|
||||
|
@ -3,4 +3,6 @@ import { MarkType } from '../types/drawing.ts'
|
||||
export const EMPTY: string = ''
|
||||
export const MARK_TYPE_TRANSLATION: { [key: string]: string } = {
|
||||
[MarkType.FULLNAME.valueOf()]: 'Full Name'
|
||||
}
|
||||
}
|
||||
export const SIGN: string = 'Sign'
|
||||
export const NEXT: string = 'Next'
|
||||
|
@ -2,6 +2,7 @@ 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.
|
||||
@ -9,16 +10,18 @@ import { Event } from 'nostr-tools'
|
||||
* @param marks - default Marks extracted from Meta
|
||||
* @param signedMetaMarks - signed user Marks extracted from DocSignatures
|
||||
*/
|
||||
const getCurrentUserMarks = (marks: Mark[], signedMetaMarks: Mark[]): CurrentUserMark[] => {
|
||||
const getCurrentUserMarks = (
|
||||
marks: Mark[],
|
||||
signedMetaMarks: Mark[]
|
||||
): CurrentUserMark[] => {
|
||||
return marks.map((mark, index, arr) => {
|
||||
const signedMark = signedMetaMarks.find((m) => m.id === mark.id);
|
||||
if (signedMark && !!signedMark.value) {
|
||||
mark.value = signedMark.value
|
||||
}
|
||||
const signedMark = signedMetaMarks.find((m) => m.id === mark.id)
|
||||
return {
|
||||
mark,
|
||||
currentValue: signedMark?.value ?? EMPTY,
|
||||
id: index + 1,
|
||||
isLast: isLast(index, arr),
|
||||
isCompleted: !!mark.value
|
||||
isCompleted: !!signedMark?.value
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -27,8 +30,10 @@ const getCurrentUserMarks = (marks: Mark[], signedMetaMarks: Mark[]): CurrentUse
|
||||
* Returns next incomplete CurrentUserMark if there is one
|
||||
* @param usersMarks
|
||||
*/
|
||||
const findNextCurrentUserMark = (usersMarks: CurrentUserMark[]): CurrentUserMark | undefined => {
|
||||
return usersMarks.find((mark) => !mark.isCompleted);
|
||||
const findNextIncompleteCurrentUserMark = (
|
||||
usersMarks: CurrentUserMark[]
|
||||
): CurrentUserMark | undefined => {
|
||||
return usersMarks.find((mark) => !mark.isCompleted)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,7 +42,7 @@ const findNextCurrentUserMark = (usersMarks: CurrentUserMark[]): CurrentUserMark
|
||||
* @param pubkey
|
||||
*/
|
||||
const filterMarksByPubkey = (marks: Mark[], pubkey: string): Mark[] => {
|
||||
return marks.filter(mark => mark.npub === hexToNpub(pubkey))
|
||||
return marks.filter((mark) => mark.npub === hexToNpub(pubkey))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +62,9 @@ const extractMarksFromSignedMeta = (meta: Meta): Mark[] => {
|
||||
* marked as complete.
|
||||
* @param currentUserMarks
|
||||
*/
|
||||
const isCurrentUserMarksComplete = (currentUserMarks: CurrentUserMark[]): boolean => {
|
||||
const isCurrentUserMarksComplete = (
|
||||
currentUserMarks: CurrentUserMark[]
|
||||
): boolean => {
|
||||
return currentUserMarks.every((mark) => mark.isCompleted)
|
||||
}
|
||||
|
||||
@ -68,7 +75,7 @@ const isCurrentUserMarksComplete = (currentUserMarks: CurrentUserMark[]): boolea
|
||||
* @param markToUpdate
|
||||
*/
|
||||
const updateMarks = (marks: Mark[], markToUpdate: Mark): Mark[] => {
|
||||
const indexToUpdate = marks.findIndex(mark => mark.id === markToUpdate.id);
|
||||
const indexToUpdate = marks.findIndex((mark) => mark.id === markToUpdate.id)
|
||||
return [
|
||||
...marks.slice(0, indexToUpdate),
|
||||
markToUpdate,
|
||||
@ -76,8 +83,13 @@ const updateMarks = (marks: Mark[], markToUpdate: Mark): Mark[] => {
|
||||
]
|
||||
}
|
||||
|
||||
const updateCurrentUserMarks = (currentUserMarks: CurrentUserMark[], markToUpdate: CurrentUserMark): CurrentUserMark[] => {
|
||||
const indexToUpdate = currentUserMarks.findIndex((m) => m.mark.id === markToUpdate.mark.id)
|
||||
const updateCurrentUserMarks = (
|
||||
currentUserMarks: CurrentUserMark[],
|
||||
markToUpdate: CurrentUserMark
|
||||
): CurrentUserMark[] => {
|
||||
const indexToUpdate = currentUserMarks.findIndex(
|
||||
(m) => m.mark.id === markToUpdate.mark.id
|
||||
)
|
||||
return [
|
||||
...currentUserMarks.slice(0, indexToUpdate),
|
||||
markToUpdate,
|
||||
@ -85,14 +97,40 @@ const updateCurrentUserMarks = (currentUserMarks: CurrentUserMark[], markToUpdat
|
||||
]
|
||||
}
|
||||
|
||||
const isLast = <T>(index: number, arr: T[]) => (index === (arr.length -1))
|
||||
const isLast = <T>(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
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getCurrentUserMarks,
|
||||
filterMarksByPubkey,
|
||||
extractMarksFromSignedMeta,
|
||||
isCurrentUserMarksComplete,
|
||||
findNextCurrentUserMark,
|
||||
findNextIncompleteCurrentUserMark,
|
||||
updateMarks,
|
||||
updateCurrentUserMarks,
|
||||
isCurrentValueLast,
|
||||
getUpdatedMark
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user