diff --git a/src/components/DrawPDFFields/style.module.scss b/src/components/DrawPDFFields/style.module.scss
index 4793f44..8f14fd1 100644
--- a/src/components/DrawPDFFields/style.module.scss
+++ b/src/components/DrawPDFFields/style.module.scss
@@ -59,14 +59,18 @@
.drawingRectangle {
position: absolute;
border: 1px solid #01aaad;
- width: 40px;
- height: 40px;
+ //width: 40px;
+ //height: 40px;
z-index: 50;
background-color: #01aaad4b;
cursor: pointer;
display: flex;
justify-content: center;
+ &.nonEditable {
+ cursor: default;
+ }
+
.resizeHandle {
position: absolute;
right: -5px;
diff --git a/src/components/PDFView/PdfItem.tsx b/src/components/PDFView/PdfItem.tsx
index 7ffd000..d463ea5 100644
--- a/src/components/PDFView/PdfItem.tsx
+++ b/src/components/PDFView/PdfItem.tsx
@@ -1,25 +1,25 @@
import { PdfFile } from '../../types/drawing.ts'
-import { MarkConfigDetails} from '../../types/mark.ts'
+import { Mark, MarkConfigDetails } from '../../types/mark.ts'
import PdfPageItem from './PdfPageItem.tsx';
interface PdfItemProps {
pdfFile: PdfFile
- markConfigDetails: MarkConfigDetails[]
+ marks: Mark[]
+ handleMarkClick: (id: number) => void
}
-const PdfItem = ({ pdfFile, markConfigDetails }: PdfItemProps) => {
- const filterMarkConfigDetails = (i: number) => {
- return markConfigDetails.filter(
- (details) => details.markLocation.page === i);
+const PdfItem = ({ pdfFile, marks, handleMarkClick }: PdfItemProps) => {
+ const filterByPage = (marks: Mark[], page: number): Mark[] => {
+ return marks.filter((mark) => mark.location.page === page);
}
return (
pdfFile.pages.map((page, i) => {
- console.log('page: ', page);
return (
)
}))
diff --git a/src/components/PDFView/PdfMarkItem.tsx b/src/components/PDFView/PdfMarkItem.tsx
index a170c45..60774e0 100644
--- a/src/components/PDFView/PdfMarkItem.tsx
+++ b/src/components/PDFView/PdfMarkItem.tsx
@@ -1,20 +1,24 @@
-import { MarkLocation } from '../../types/mark.ts'
+import { Mark, MarkLocation } from '../../types/mark.ts'
import styles from '../DrawPDFFields/style.module.scss'
import { inPx } from '../../utils/pdf.ts'
interface PdfMarkItemProps {
- markLocation: MarkLocation
+ mark: Mark
+ handleMarkClick: (id: number) => void
+ isEditable: boolean
}
-const PdfMarkItem = ({ markLocation }: PdfMarkItemProps) => {
+const PdfMarkItem = ({ mark, handleMarkClick, isEditable }: PdfMarkItemProps) => {
+ const handleClick = () => isEditable && handleMarkClick(mark.id);
return (
)
diff --git a/src/components/PDFView/PdfPageItem.tsx b/src/components/PDFView/PdfPageItem.tsx
index 5176fe9..051ac44 100644
--- a/src/components/PDFView/PdfPageItem.tsx
+++ b/src/components/PDFView/PdfPageItem.tsx
@@ -1,27 +1,45 @@
import styles from '../DrawPDFFields/style.module.scss'
import { PdfPage } from '../../types/drawing.ts'
-import { MarkConfigDetails, MarkLocation } from '../../types/mark.ts'
+import { Mark, MarkConfigDetails } from '../../types/mark.ts'
import PdfMarkItem from './PdfMarkItem.tsx'
-import { useState } from 'react';
+import { useSelector } from 'react-redux'
+import { State } from '../../store/rootReducer.ts'
+import { hexToNpub } from '../../utils'
interface PdfPageProps {
page: PdfPage
- markConfigDetails: MarkConfigDetails[]
+ marks: Mark[]
+ handleMarkClick: (id: number) => void
}
-const PdfPageItem = ({ page, markConfigDetails }: PdfPageProps) => {
- const [currentMark, setCurrentMark] = useState(null);
-
+const PdfPageItem = ({ page, marks, handleMarkClick }: PdfPageProps) => {
+ const usersPubkey = useSelector((state: State) => state.auth.usersPubkey)
+ const isEditable = (mark: Mark): boolean => {
+ if (!usersPubkey) return false;
+ return mark.npub === hexToNpub(usersPubkey);
+ }
return (
-
- {markConfigDetails.map((detail, i) => (
-
+
+ {
+ marks.map((mark, i) => (
+
))}
)
diff --git a/src/components/PDFView/index.tsx b/src/components/PDFView/index.tsx
index 6c6113c..1f72275 100644
--- a/src/components/PDFView/index.tsx
+++ b/src/components/PDFView/index.tsx
@@ -1,41 +1,29 @@
import { PdfFile } from '../../types/drawing.ts'
import { Box } from '@mui/material'
import PdfItem from './PdfItem.tsx'
-import { MarkConfig, MarkConfigDetails } from '../../types/mark.ts'
-import { State } from '../../store/rootReducer'
-import { useSelector } from 'react-redux';
-import { hexToNpub, npubToHex } from '../../utils'
+import { Mark, MarkConfigDetails } from '../../types/mark.ts'
interface PdfViewProps {
files: { [filename: string]: PdfFile },
fileHashes: { [key: string]: string | null },
- markConfig: MarkConfig,
+ marks: Mark[],
+ handleMarkClick: (id: number) => void
}
-const PdfView = (props: PdfViewProps) => {
- console.log('current file hashes: ', props.fileHashes)
- const usersPubkey = useSelector((state: State) => state.auth.usersPubkey);
- if (!usersPubkey) return;
- console.log(props.markConfig[hexToNpub(usersPubkey)]);
-
- console.log('users pubkey: ', usersPubkey);
- console.log('mark config: ', props.markConfig);
-
- const getMarkConfigDetails = (fileName: string): MarkConfigDetails[] | undefined => {
- const fileHash = props.fileHashes[fileName];
- if (!fileHash) return;
- return props.markConfig[hexToNpub(usersPubkey)][fileHash];
+const PdfView = ({ files, fileHashes, marks, handleMarkClick }: PdfViewProps) => {
+ const filterByFile = (marks: Mark[], fileHash: string): Mark[] => {
+ return marks.filter((mark) => mark.pdfFileHash === fileHash);
}
- const { files } = props;
return (
-
+
{Object.entries(files)
- .filter(([name]) => !!getMarkConfigDetails(name))
.map(([name, file], i) => (
+ marks={filterByFile(marks, fileHashes[name] ?? "")}
+ handleMarkClick={handleMarkClick}
+ />
))}
)
diff --git a/src/components/PDFView/style.module.scss b/src/components/PDFView/style.module.scss
new file mode 100644
index 0000000..2e6e519
--- /dev/null
+++ b/src/components/PDFView/style.module.scss
@@ -0,0 +1,16 @@
+.imageWrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%; /* Adjust as needed */
+ height: 100%; /* Adjust as needed */
+ overflow: hidden; /* Ensure no overflow */
+ border: 1px solid #ccc; /* Optional: for visual debugging */
+ background-color: #e0f7fa; /* Optional: for visual debugging */
+}
+
+.image {
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain; /* Ensure the image fits within the container */
+}
\ No newline at end of file
diff --git a/src/pages/create/index.tsx b/src/pages/create/index.tsx
index 215ca83..f509fa6 100644
--- a/src/pages/create/index.tsx
+++ b/src/pages/create/index.tsx
@@ -62,6 +62,8 @@ import {
import styles from './style.module.scss'
import { PdfFile } from '../../types/drawing'
import { DrawPDFFields } from '../../components/DrawPDFFields'
+import { Mark } from '../../types/mark.ts'
+import { v4 as uuidv4 } from 'uuid';
export const CreatePage = () => {
const navigate = useNavigate()
@@ -339,34 +341,29 @@ export const CreatePage = () => {
return fileHashes
}
- const createMarkConfig = (fileHashes: { [key: string]: string }) => {
- const markConfig: any = {}
-
- drawnPdfs.forEach(drawnPdf => {
- const fileHash = fileHashes[drawnPdf.file.name]
-
- drawnPdf.pages.forEach((page, pageIndex) => {
- page.drawnFields.forEach(drawnField => {
- if (!markConfig[drawnField.counterpart]) markConfig[drawnField.counterpart] = {}
- if (!markConfig[drawnField.counterpart][fileHash]) markConfig[drawnField.counterpart][fileHash] = []
-
- console.log('drawn field: ', drawnField);
-
- markConfig[drawnField.counterpart][fileHash].push({
- markType: drawnField.type,
- markLocation: {
- page: pageIndex,
+ const createMarkConfig = (fileHashes: { [key: string]: string }) : Mark[] => {
+ return drawnPdfs.flatMap((drawnPdf) => {
+ const fileHash = fileHashes[drawnPdf.file.name];
+ return drawnPdf.pages.flatMap((page, index) => {
+ return page.drawnFields.map((drawnField) => {
+ return {
+ type: drawnField.type,
+ location: {
+ page: index,
top: drawnField.top,
left: drawnField.left,
height: drawnField.height,
width: drawnField.width,
- }
- })
+ },
+ npub: drawnField.counterpart,
+ pdfFileHash: fileHash
+ }
})
})
})
-
- return markConfig
+ .map((mark, index) => {
+ return {...mark, id: index }
+ });
}
// Handle errors during zip file generation
diff --git a/src/pages/sign/MarkFormField.tsx b/src/pages/sign/MarkFormField.tsx
new file mode 100644
index 0000000..2e63f38
--- /dev/null
+++ b/src/pages/sign/MarkFormField.tsx
@@ -0,0 +1,32 @@
+import { CurrentUserMark, Mark } from '../../types/mark.ts'
+import styles from './style.module.scss'
+import { Box, Button, TextField } from '@mui/material'
+
+interface MarkFormFieldProps {
+ handleSubmit: (event: any) => void
+ handleChange: (event: any) => void
+ currentMark: CurrentUserMark
+ currentMarkValue: string
+}
+
+const MarkFormField = (props: MarkFormFieldProps) => {
+ const { handleSubmit, handleChange, currentMark, currentMarkValue } = props;
+ const getSubmitButton = () => currentMark.isLast ? 'Complete' : 'Next';
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default MarkFormField;
\ No newline at end of file
diff --git a/src/pages/sign/index.tsx b/src/pages/sign/index.tsx
index c7f2866..e8caa7c 100644
--- a/src/pages/sign/index.tsx
+++ b/src/pages/sign/index.tsx
@@ -1,8 +1,8 @@
-import { Box, Button, Typography } from '@mui/material'
+import { Box, Button, FormControl, InputLabel, TextField, Typography } from '@mui/material'
import axios from 'axios'
import saveAs from 'file-saver'
import JSZip from 'jszip'
-import _ from 'lodash'
+import _, { set } from 'lodash'
import { MuiFileInput } from 'mui-file-input'
import { Event, verifyEvent } from 'nostr-tools'
import { useEffect, useState } from 'react'
@@ -36,7 +36,8 @@ import styles from './style.module.scss'
import { PdfFile } from '../../types/drawing.ts'
import { toFile, toPdfFile } from '../../utils/pdf.ts'
import PdfView from '../../components/PDFView'
-import { MarkConfig } from '../../types/mark.ts'
+import { CurrentUserMark, Mark, MarkConfig, MarkConfigDetails, User } from '../../types/mark.ts'
+import MarkFormField from './MarkFormField.tsx'
enum SignedStatus {
Fully_Signed,
User_Is_Next_Signer,
@@ -74,7 +75,7 @@ export const SignPage = () => {
const [signers, setSigners] = useState<`npub1${string}`[]>([])
const [viewers, setViewers] = useState<`npub1${string}`[]>([])
- const [markConfig, setMarkConfig] = useState(null)
+ const [marks, setMarks] = useState([])
const [creatorFileHashes, setCreatorFileHashes] = useState<{
[key: string]: string
}>({})
@@ -93,6 +94,11 @@ export const SignPage = () => {
const [authUrl, setAuthUrl] = useState()
const nostrController = NostrController.getInstance()
+ const [currentUserMark, setCurrentUserMark] = useState(null);
+ const [currentUserMarks, setCurrentUserMarks] = useState([]);
+ const [currentMarkValue, setCurrentMarkValue] = useState('');
+ const [isMarksCompleted, setIsMarksCompleted] = useState(false);
+ const [isLastUserMark, setIsLastUserMark] = useState(false);
useEffect(() => {
if (signers.length > 0) {
@@ -183,9 +189,25 @@ export const SignPage = () => {
setViewers(createSignatureContent.viewers)
setCreatorFileHashes(createSignatureContent.fileHashes)
setSubmittedBy(createSignatureEvent.pubkey)
- setMarkConfig(createSignatureContent.markConfig);
+ setMarks(createSignatureContent.markConfig);
- console.log('createSignatureContent', createSignatureContent)
+ console.log('createSignatureContent markConfig', createSignatureContent);
+ if (usersPubkey) {
+ console.log('this runs behind users pubkey');
+ const curMarks = getCurrentUserMarks(createSignatureContent.markConfig, usersPubkey)
+ if (curMarks.length === 0) {
+ setIsMarksCompleted(true)
+ } else {
+ const nextMark = findNextIncompleteMark(curMarks)
+ if (!nextMark) {
+ setIsMarksCompleted(true)
+ } else {
+ setCurrentUserMark(nextMark)
+ setIsMarksCompleted(false)
+ }
+ setCurrentUserMarks(curMarks)
+ }
+ }
setSignedBy(Object.keys(meta.docSignatures) as `npub1${string}`[])
}
@@ -514,6 +536,57 @@ export const SignPage = () => {
)
}
+ const handleMarkClick = (id: number) => {
+ const nextMark = currentUserMarks.find(mark => mark.mark.id === id)
+ setCurrentUserMark(nextMark!)
+ setCurrentMarkValue(nextMark?.mark.value || "")
+ }
+
+ const getMarkConfigPerUser = (markConfig: MarkConfig) => {
+ if (!usersPubkey) return;
+ return markConfig[hexToNpub(usersPubkey)];
+ }
+
+ const handleChange = (event: any) => setCurrentMarkValue(event.target.value);
+
+ const handleSubmit = (event: any) => {
+ event.preventDefault();
+ if (!currentMarkValue || !currentUserMark) return;
+
+ const curMark = {
+ ...currentUserMark.mark,
+ value: currentMarkValue
+ };
+
+ const indexToUpdate = marks.findIndex(mark => mark.id === curMark.id);
+
+ const updatedMarks: Mark[] = [
+ ...marks.slice(0, indexToUpdate),
+ curMark,
+ ...marks.slice(indexToUpdate + 1)
+ ];
+
+ setMarks(updatedMarks)
+ setCurrentMarkValue("")
+
+ const updatedCurUserMarks = getCurrentUserMarks(updatedMarks, usersPubkey!)
+ console.log('updatedCurUserMarks: ', updatedCurUserMarks)
+ setCurrentUserMarks(updatedCurUserMarks)
+ const nextMark = findNextIncompleteMark(updatedCurUserMarks)
+ console.log('next mark: ', nextMark)
+ if (!nextMark) {
+ setCurrentUserMark(null)
+ setIsMarksCompleted(true)
+ } else {
+ setCurrentUserMark(nextMark)
+ setIsMarksCompleted(false)
+ }
+ }
+
+ const findNextIncompleteMark = (usersMarks: CurrentUserMark[]): CurrentUserMark | undefined => {
+ return usersMarks.find(mark => !mark.isCompleted);
+ }
+
// Update the meta signatures
const updateMetaSignatures = (meta: Meta, signedEvent: SignedEvent): Meta => {
const metaCopy = _.cloneDeep(meta)
@@ -735,6 +808,25 @@ export const SignPage = () => {
navigate(appPublicRoutes.verify)
}
+ const getCurrentUserMarks = (marks: Mark[], pubkey: string): CurrentUserMark[] => {
+ console.log('marks: ', marks);
+
+ const filteredMarks = marks
+ .filter(mark => mark.npub === hexToNpub(pubkey))
+ const currentMarks = filteredMarks
+ .map((mark, index, arr) => {
+ return {
+ mark,
+ isLast: isLast(index, arr),
+ isCompleted: !!mark.value
+ }
+ })
+ console.log('current marks: ', currentMarks)
+ return currentMarks;
+ }
+
+ const isLast = (index: number, arr: any[]) => (index === (arr.length -1))
+
const handleExportSigit = async () => {
if (Object.entries(files).length === 0 || !meta) return
@@ -852,9 +944,12 @@ export const SignPage = () => {
)
}
+ if (isLoading) {
+ return
+ }
+
return (
<>
- {isLoading && }
{displayInput && (
<>
@@ -881,56 +976,68 @@ export const SignPage = () => {
>
)}
- {submittedBy && Object.entries(files).length > 0 && meta && (
- <>
-
+ {/*{submittedBy && Object.entries(files).length > 0 && meta && (*/}
+ {/* <>*/}
+ {/* */}
- {signedStatus === SignedStatus.Fully_Signed && (
-
-
-
- )}
+ {/* {signedStatus === SignedStatus.Fully_Signed && (*/}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* )}*/}
- {signedStatus === SignedStatus.User_Is_Next_Signer && (
-
-
-
- )}
+ {/* {signedStatus === SignedStatus.User_Is_Next_Signer && (*/}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* )}*/}
- {isSignerOrCreator && (
-
-
-
- )}
- >
- )}
- {markConfig && (*/}
+ {/* */}
+ {/* */}
+ {/* )}*/}
+ {/* >*/}
+ {/*)}*/}
+ {
+ !isMarksCompleted && marks.length > 0 && (
+ )}
+ marks={marks}
+ fileHashes={currentFileHashes}
+ handleMarkClick={handleMarkClick}
+ />
+ )
+ }
+
+ {
+ !isMarksCompleted && currentUserMark !== null &&
+ }
+
+ { isMarksCompleted && Ready to Sign!
}
-
-
-
-
>
diff --git a/src/pages/sign/style.module.scss b/src/pages/sign/style.module.scss
index d3b1086..aa3377b 100644
--- a/src/pages/sign/style.module.scss
+++ b/src/pages/sign/style.module.scss
@@ -51,7 +51,10 @@
.fixedBottomForm {
position: fixed;
bottom: 0;
- width: 50%;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 100%;
+ max-width: 500px;
border-top: 1px solid #ccc;
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
diff --git a/src/types/core.ts b/src/types/core.ts
index f4fb8b4..99a8cfa 100644
--- a/src/types/core.ts
+++ b/src/types/core.ts
@@ -1,4 +1,4 @@
-import { MarkConfig } from "./mark"
+import { Mark } from './mark'
import { Keys } from '../store/auth/types'
export enum UserRole {
@@ -23,7 +23,7 @@ export interface CreateSignatureEventContent {
signers: `npub1${string}`[]
viewers: `npub1${string}`[]
fileHashes: { [key: string]: string }
- markConfig: MarkConfig
+ markConfig: Mark[]
title: string
zipUrl: string
}
diff --git a/src/types/mark.ts b/src/types/mark.ts
index 57e1512..3bc38f8 100644
--- a/src/types/mark.ts
+++ b/src/types/mark.ts
@@ -1,10 +1,25 @@
import { MarkType } from "./drawing";
+// export interface Mark {
+// /**
+// * @key png (pdf page) file hash
+// */
+// [key: string]: MarkConfigDetails[]
+// }
+
+export interface CurrentUserMark {
+ mark: Mark
+ isLast: boolean
+ isCompleted: boolean
+}
+
export interface Mark {
- /**
- * @key png (pdf page) file hash
- */
- [key: string]: MarkConfigDetails[]
+ id: number;
+ npub: string;
+ pdfFileHash: string;
+ type: MarkType;
+ location: MarkLocation;
+ value?: string;
}
export interface MarkConfig {
@@ -33,11 +48,12 @@ export interface MarkValue {
}
export interface MarkConfigDetails {
- markType: MarkType;
+ type: MarkType;
/**
* Coordinates in format: X:10;Y:50
*/
- markLocation: MarkLocation;
+ location: MarkLocation;
+ value?: MarkValue
}
export interface MarkLocation {