2024-07-11 16:16:36 +02:00
|
|
|
import { AccessTime, CalendarMonth, ExpandMore, Gesture, PictureAsPdf, Badge, Work, Close } from '@mui/icons-material'
|
|
|
|
import { Box, Typography, Accordion, AccordionDetails, AccordionSummary, CircularProgress, FormControl, InputLabel, MenuItem, Select } from '@mui/material'
|
2024-06-29 00:43:08 +02:00
|
|
|
import styles from './style.module.scss'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
|
|
|
|
|
|
import * as PDFJS from "pdfjs-dist";
|
2024-07-11 16:16:36 +02:00
|
|
|
import { ProfileMetadata, User } from '../../types';
|
|
|
|
import { PdfFile, DrawTool, MouseState, PdfPage, DrawnField, MarkType } from '../../types/drawing';
|
|
|
|
import { truncate } from 'lodash';
|
|
|
|
import { hexToNpub } from '../../utils';
|
2024-06-29 00:43:08 +02:00
|
|
|
PDFJS.GlobalWorkerOptions.workerSrc = 'node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
selectedFiles: any[]
|
2024-07-11 16:16:36 +02:00
|
|
|
users: User[]
|
|
|
|
metadata: { [key: string]: ProfileMetadata }
|
|
|
|
onDrawFieldsChange: (pdfFiles: PdfFile[]) => void
|
2024-06-29 00:43:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const DrawPDFFields = (props: Props) => {
|
|
|
|
const { selectedFiles } = props
|
|
|
|
|
|
|
|
const [pdfFiles, setPdfFiles] = useState<PdfFile[]>([])
|
|
|
|
const [parsingPdf, setParsingPdf] = useState<boolean>(false)
|
|
|
|
const [showDrawToolBox, setShowDrawToolBox] = useState<boolean>(false)
|
|
|
|
|
|
|
|
const [selectedTool, setSelectedTool] = useState<DrawTool | null>()
|
|
|
|
const [toolbox] = useState<DrawTool[]>([
|
|
|
|
{
|
2024-07-11 16:16:36 +02:00
|
|
|
identifier: MarkType.SIGNATURE,
|
2024-06-29 00:43:08 +02:00
|
|
|
icon: <Gesture/>,
|
2024-07-11 16:16:36 +02:00
|
|
|
label: 'Signature',
|
|
|
|
active: false
|
2024-06-29 00:43:08 +02:00
|
|
|
|
|
|
|
},
|
|
|
|
{
|
2024-07-11 16:16:36 +02:00
|
|
|
identifier: MarkType.FULLNAME,
|
2024-06-29 00:43:08 +02:00
|
|
|
icon: <Badge/>,
|
2024-07-11 16:16:36 +02:00
|
|
|
label: 'Full Name',
|
|
|
|
active: true
|
2024-06-29 00:43:08 +02:00
|
|
|
},
|
|
|
|
{
|
2024-07-11 16:16:36 +02:00
|
|
|
identifier: MarkType.JOBTITLE,
|
2024-06-29 00:43:08 +02:00
|
|
|
icon: <Work/>,
|
2024-07-11 16:16:36 +02:00
|
|
|
label: 'Job Title',
|
|
|
|
active: false
|
2024-06-29 00:43:08 +02:00
|
|
|
},
|
|
|
|
{
|
2024-07-11 16:16:36 +02:00
|
|
|
identifier: MarkType.DATE,
|
2024-06-29 00:43:08 +02:00
|
|
|
icon: <CalendarMonth/>,
|
2024-07-11 16:16:36 +02:00
|
|
|
label: 'Date',
|
|
|
|
active: false
|
2024-06-29 00:43:08 +02:00
|
|
|
},
|
|
|
|
{
|
2024-07-11 16:16:36 +02:00
|
|
|
identifier: MarkType.DATETIME,
|
2024-06-29 00:43:08 +02:00
|
|
|
icon: <AccessTime/>,
|
2024-07-11 16:16:36 +02:00
|
|
|
label: 'Datetime',
|
|
|
|
active: false
|
2024-06-29 00:43:08 +02:00
|
|
|
},
|
|
|
|
])
|
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
const [mouseState, setMouseState] = useState<MouseState>({
|
|
|
|
clicked: false
|
|
|
|
})
|
|
|
|
|
2024-06-29 00:43:08 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (selectedFiles) {
|
|
|
|
setParsingPdf(true)
|
|
|
|
|
|
|
|
parsePdfPages().finally(() => {
|
|
|
|
setParsingPdf(false)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}, [selectedFiles])
|
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (pdfFiles) props.onDrawFieldsChange(pdfFiles)
|
|
|
|
}, [pdfFiles])
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Drawing events
|
|
|
|
*/
|
|
|
|
useEffect(() => {
|
|
|
|
// window.addEventListener('mousedown', onMouseDown);
|
|
|
|
window.addEventListener('mouseup', onMouseUp);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
// window.removeEventListener('mousedown', onMouseDown);
|
|
|
|
window.removeEventListener('mouseup', onMouseUp);
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
const refreshPdfFiles = () => {
|
|
|
|
setPdfFiles([...pdfFiles])
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Fired only when left click and mouse over pdf page
|
|
|
|
* Creates new drawnElement and pushes in the array
|
|
|
|
* It is re rendered and visible right away
|
|
|
|
*
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param page PdfPage where press happened
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onMouseDown = (event: any, page: PdfPage) => {
|
|
|
|
// Proceed only if left click
|
|
|
|
if (event.button !== 0) return
|
|
|
|
|
|
|
|
// Only allow drawing if mouse is not over other drawn element
|
|
|
|
const isOverPdfImageWrapper = event.target.tagName === 'IMG'
|
|
|
|
|
|
|
|
if (!selectedTool || !isOverPdfImageWrapper) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-07-26 15:24:23 +02:00
|
|
|
const { mouseX, mouseY, rect } = getMouseCoordinates(event)
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
const newField: DrawnField = {
|
|
|
|
left: mouseX,
|
|
|
|
top: mouseY,
|
2024-07-26 15:24:23 +02:00
|
|
|
bottom: rect.height - mouseY,
|
2024-07-11 16:16:36 +02:00
|
|
|
width: 0,
|
|
|
|
height: 0,
|
|
|
|
counterpart: '',
|
|
|
|
type: selectedTool.identifier
|
|
|
|
}
|
|
|
|
|
|
|
|
page.drawnFields.push(newField)
|
|
|
|
|
|
|
|
setMouseState((prev) => {
|
|
|
|
return {
|
|
|
|
...prev,
|
|
|
|
clicked: true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Drawing is finished, resets all the variables used to draw
|
|
|
|
* @param event Mouse event
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onMouseUp = (event: MouseEvent) => {
|
|
|
|
setMouseState((prev) => {
|
|
|
|
return {
|
|
|
|
...prev,
|
|
|
|
clicked: false,
|
|
|
|
dragging: false,
|
|
|
|
resizing: false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* After {@link onMouseDown} create an drawing element, this function gets called on every pixel moved
|
|
|
|
* which alters the newly created drawing element, resizing it while mouse move
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param page PdfPage where moving is happening
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onMouseMove = (event: any, page: PdfPage) => {
|
|
|
|
if (mouseState.clicked && selectedTool) {
|
|
|
|
const lastElementIndex = page.drawnFields.length -1
|
|
|
|
const lastDrawnField = page.drawnFields[lastElementIndex]
|
|
|
|
|
2024-07-26 15:24:23 +02:00
|
|
|
const { mouseX, mouseY, rect } = getMouseCoordinates(event)
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
const width = mouseX - lastDrawnField.left
|
|
|
|
const height = mouseY - lastDrawnField.top
|
2024-07-26 15:24:23 +02:00
|
|
|
const bottom = rect.height - height - lastDrawnField.top - 3
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
lastDrawnField.width = width
|
|
|
|
lastDrawnField.height = height
|
2024-07-26 15:24:23 +02:00
|
|
|
lastDrawnField.bottom = bottom
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
const currentDrawnFields = page.drawnFields
|
|
|
|
|
|
|
|
currentDrawnFields[lastElementIndex] = lastDrawnField
|
|
|
|
|
|
|
|
refreshPdfFiles()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Fired when event happens on the drawn element which will be moved
|
|
|
|
* mouse coordinates relative to drawn element will be stored
|
|
|
|
* so when we start moving, offset can be calculated
|
|
|
|
* mouseX - offsetX
|
|
|
|
* mouseY - offsetY
|
|
|
|
*
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param drawnField Which we are moving
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onDrawnFieldMouseDown = (event: any, drawnField: DrawnField) => {
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
// Proceed only if left click
|
|
|
|
if (event.button !== 0) return
|
|
|
|
|
|
|
|
const drawingRectangleCoords = getMouseCoordinates(event)
|
|
|
|
|
|
|
|
setMouseState({
|
|
|
|
dragging: true,
|
|
|
|
clicked: false,
|
|
|
|
coordsInWrapper: {
|
|
|
|
mouseX: drawingRectangleCoords.mouseX,
|
|
|
|
mouseY: drawingRectangleCoords.mouseY
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Moves the drawnElement by the mouse position (mouse can grab anywhere on the drawn element)
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param drawnField which we are moving
|
|
|
|
*/
|
2024-07-26 15:24:23 +02:00
|
|
|
const onDrawnFieldMouseMove = (event: any, drawnField: DrawnField) => {
|
2024-07-11 16:16:36 +02:00
|
|
|
if (mouseState.dragging) {
|
|
|
|
const { mouseX, mouseY, rect } = getMouseCoordinates(event, event.target.parentNode)
|
|
|
|
const coordsOffset = mouseState.coordsInWrapper
|
|
|
|
|
|
|
|
if (coordsOffset) {
|
|
|
|
let left = mouseX - coordsOffset.mouseX
|
|
|
|
let top = mouseY - coordsOffset.mouseY
|
|
|
|
|
|
|
|
const rightLimit = rect.width - drawnField.width - 3
|
|
|
|
const bottomLimit = rect.height - drawnField.height - 3
|
|
|
|
|
|
|
|
if (left < 0) left = 0
|
|
|
|
if (top < 0) top = 0
|
|
|
|
if (left > rightLimit) left = rightLimit
|
|
|
|
if (top > bottomLimit) top = bottomLimit
|
2024-07-26 15:24:23 +02:00
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
drawnField.left = left
|
|
|
|
drawnField.top = top
|
2024-07-26 15:24:23 +02:00
|
|
|
drawnField.bottom = rect.height - drawnField.height - top - 3
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
refreshPdfFiles()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
2024-07-26 15:24:23 +02:00
|
|
|
* Fired when clicked
|
|
|
|
drawnField.top = top
|
|
|
|
on the resize handle, sets the state for a resize action
|
2024-07-12 15:07:36 +02:00
|
|
|
* @param event Mouse event
|
|
|
|
* @param drawnField which we are resizing
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onResizeHandleMouseDown = (event: any, drawnField: DrawnField) => {
|
|
|
|
// Proceed only if left click
|
|
|
|
if (event.button !== 0) return
|
|
|
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
setMouseState({
|
|
|
|
resizing: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Resizes the drawn element by the mouse position
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param drawnField which we are resizing
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onResizeHandleMouseMove = (event: any, drawnField: DrawnField) => {
|
|
|
|
if (mouseState.resizing) {
|
2024-07-26 15:24:23 +02:00
|
|
|
const { mouseX, mouseY, rect } = getMouseCoordinates(event, event.target.parentNode.parentNode)
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
const width = mouseX - drawnField.left
|
|
|
|
const height = mouseY - drawnField.top
|
|
|
|
|
|
|
|
drawnField.width = width
|
|
|
|
drawnField.height = height
|
2024-07-26 15:24:23 +02:00
|
|
|
drawnField.bottom = rect.height - height - drawnField.top - 3
|
2024-07-11 16:16:36 +02:00
|
|
|
|
|
|
|
refreshPdfFiles()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Removes the drawn element using the indexes in the params
|
|
|
|
* @param event Mouse event
|
|
|
|
* @param pdfFileIndex pdf file index
|
|
|
|
* @param pdfPageIndex pdf page index
|
|
|
|
* @param drawnFileIndex drawn file index
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onRemoveHandleMouseDown = (event: any, pdfFileIndex: number, pdfPageIndex: number, drawnFileIndex: number) => {
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
pdfFiles[pdfFileIndex].pages[pdfPageIndex].drawnFields.splice(drawnFileIndex, 1)
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Used to stop mouse click propagating to the parent elements
|
|
|
|
* so select can work properly
|
|
|
|
* @param event Mouse event
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const onUserSelectHandleMouseDown = (event: any) => {
|
|
|
|
event.stopPropagation()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the mouse coordinates relative to a element in the `event` param
|
|
|
|
* @param event MouseEvent
|
|
|
|
* @param customTarget mouse coordinates relative to this element, if not provided
|
|
|
|
* event.target will be used
|
|
|
|
*/
|
|
|
|
const getMouseCoordinates = (event: any, customTarget?: any) => {
|
|
|
|
const target = customTarget ? customTarget : event.target
|
|
|
|
const rect = target.getBoundingClientRect();
|
|
|
|
const mouseX = event.clientX - rect.left; //x position within the element.
|
|
|
|
const mouseY = event.clientY - rect.top; //y position within the element.
|
|
|
|
|
|
|
|
return {
|
|
|
|
mouseX,
|
|
|
|
mouseY,
|
|
|
|
rect
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Reads the pdf binary files and converts it's pages to images
|
|
|
|
* creates the pdfFiles object and sets to a state
|
|
|
|
*/
|
2024-06-29 00:43:08 +02:00
|
|
|
const parsePdfPages = async () => {
|
|
|
|
const pdfFiles: PdfFile[] = []
|
|
|
|
|
2024-06-29 00:44:06 +02:00
|
|
|
for (const file of selectedFiles) {
|
2024-06-29 00:43:08 +02:00
|
|
|
if (file.type.toLowerCase().includes('pdf')) {
|
|
|
|
const data = await readPdf(file)
|
|
|
|
const pages = await pdfToImages(data)
|
|
|
|
|
|
|
|
pdfFiles.push({
|
|
|
|
file: file,
|
2024-07-11 16:16:36 +02:00
|
|
|
pages: pages,
|
|
|
|
expanded: false
|
2024-06-29 00:43:08 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setPdfFiles(pdfFiles)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts pdf to the images
|
|
|
|
* @param data pdf file bytes
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const pdfToImages = async (data: any): Promise<PdfPage[]> => {
|
2024-06-29 00:43:08 +02:00
|
|
|
const images: string[] = [];
|
|
|
|
const pdf = await PDFJS.getDocument(data).promise;
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
|
|
|
|
for (let i = 0; i < pdf.numPages; i++) {
|
|
|
|
const page = await pdf.getPage(i + 1);
|
2024-07-26 15:24:23 +02:00
|
|
|
const viewport = page.getViewport({ scale: 1 });
|
2024-06-29 00:43:08 +02:00
|
|
|
const context = canvas.getContext("2d");
|
|
|
|
canvas.height = viewport.height;
|
|
|
|
canvas.width = viewport.width;
|
|
|
|
await page.render({ canvasContext: context!, viewport: viewport }).promise;
|
|
|
|
images.push(canvas.toDataURL());
|
|
|
|
}
|
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
return Promise.resolve(images.map((image) => {
|
|
|
|
return {
|
|
|
|
image,
|
|
|
|
drawnFields: []
|
|
|
|
}
|
|
|
|
}))
|
2024-06-29 00:43:08 +02:00
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Reads the pdf file binaries
|
|
|
|
*/
|
2024-06-29 00:43:08 +02:00
|
|
|
const readPdf = (file: File) => {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
|
|
reader.onload = (e: any) => {
|
|
|
|
const data = e.target.result
|
|
|
|
|
|
|
|
resolve(data)
|
|
|
|
};
|
|
|
|
|
|
|
|
reader.onerror = (err) => {
|
|
|
|
console.error('err', err)
|
|
|
|
reject(err)
|
|
|
|
};
|
|
|
|
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @returns if expanded pdf accordion is present
|
|
|
|
*/
|
2024-06-29 00:43:08 +02:00
|
|
|
const hasExpandedPdf = () => {
|
|
|
|
return !!pdfFiles.filter(pdfFile => !!pdfFile.expanded).length
|
|
|
|
}
|
|
|
|
|
2024-06-29 00:46:35 +02:00
|
|
|
const handleAccordionExpandChange = (expanded: boolean, pdfFile: PdfFile) => {
|
2024-06-29 00:43:08 +02:00
|
|
|
pdfFile.expanded = expanded
|
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
refreshPdfFiles()
|
2024-06-29 00:43:08 +02:00
|
|
|
setShowDrawToolBox(hasExpandedPdf())
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Changes the drawing tool
|
|
|
|
* @param drawTool to draw with
|
|
|
|
*/
|
2024-06-29 00:43:08 +02:00
|
|
|
const handleToolSelect = (drawTool: DrawTool) => {
|
|
|
|
// If clicked on the same tool, unselect
|
|
|
|
if (drawTool.identifier === selectedTool?.identifier) {
|
|
|
|
setSelectedTool(null)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
setSelectedTool(drawTool)
|
|
|
|
}
|
|
|
|
|
2024-07-12 15:07:36 +02:00
|
|
|
/**
|
|
|
|
* Renders the pdf pages and drawing elements
|
|
|
|
*/
|
2024-07-11 16:16:36 +02:00
|
|
|
const getPdfPages = (pdfFile: PdfFile, pdfFileIndex: number) => {
|
|
|
|
return (
|
|
|
|
<Box sx={{
|
|
|
|
width: '100%'
|
|
|
|
}}>
|
|
|
|
{pdfFile.pages.map((page, pdfPageIndex: number) => {
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={pdfPageIndex}
|
|
|
|
style={{
|
|
|
|
border: '1px solid #c4c4c4',
|
|
|
|
marginBottom: '10px'
|
|
|
|
}}
|
|
|
|
className={`${styles.pdfImageWrapper} ${selectedTool ? styles.drawing : ''}`}
|
|
|
|
onMouseMove={(event) => {onMouseMove(event, page)}}
|
|
|
|
onMouseDown={(event) => {onMouseDown(event, page)}}
|
|
|
|
>
|
|
|
|
<img draggable="false" style={{ width: '100%' }} src={page.image}/>
|
|
|
|
|
|
|
|
{page.drawnFields.map((drawnField, drawnFieldIndex: number) => {
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={drawnFieldIndex}
|
|
|
|
onMouseDown={(event) => { onDrawnFieldMouseDown(event, drawnField) }}
|
2024-07-26 15:24:23 +02:00
|
|
|
onMouseMove={(event) => { onDrawnFieldMouseMove(event, drawnField)}}
|
2024-07-11 16:16:36 +02:00
|
|
|
className={styles.drawingRectangle}
|
|
|
|
style={{
|
|
|
|
left: `${drawnField.left}px`,
|
|
|
|
top: `${drawnField.top}px`,
|
|
|
|
width: `${drawnField.width}px`,
|
|
|
|
height: `${drawnField.height}px`,
|
|
|
|
pointerEvents: mouseState.clicked ? 'none' : 'all'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<span
|
|
|
|
onMouseDown={(event) => {onResizeHandleMouseDown(event, drawnField)}}
|
|
|
|
onMouseMove={(event) => {onResizeHandleMouseMove(event, drawnField)}}
|
|
|
|
className={styles.resizeHandle}
|
|
|
|
></span>
|
|
|
|
<span
|
|
|
|
onMouseDown={(event) => {onRemoveHandleMouseDown(event, pdfFileIndex, pdfPageIndex, drawnFieldIndex)}}
|
|
|
|
className={styles.removeHandle}
|
|
|
|
>
|
|
|
|
<Close fontSize='small'/>
|
|
|
|
</span>
|
|
|
|
<div
|
|
|
|
onMouseDown={(event) => {onUserSelectHandleMouseDown(event)}}
|
|
|
|
className={styles.userSelect}
|
|
|
|
>
|
|
|
|
<FormControl fullWidth size='small'>
|
|
|
|
<InputLabel id="counterparts">Counterpart</InputLabel>
|
|
|
|
<Select
|
|
|
|
value={drawnField.counterpart}
|
|
|
|
onChange={(event) => { drawnField.counterpart = event.target.value; refreshPdfFiles() }}
|
|
|
|
labelId="counterparts"
|
|
|
|
label="Counterparts"
|
|
|
|
>
|
|
|
|
{props.users.map((user, index) => {
|
|
|
|
let displayValue = truncate(hexToNpub(user.pubkey), {
|
|
|
|
length: 16
|
|
|
|
})
|
|
|
|
|
|
|
|
const metadata = props.metadata[user.pubkey]
|
|
|
|
|
|
|
|
if (metadata) {
|
|
|
|
displayValue = truncate(metadata.name || metadata.display_name || metadata.username, {
|
|
|
|
length: 16
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return <MenuItem key={index} value={hexToNpub(user.pubkey)}>{displayValue}</MenuItem>
|
|
|
|
})}
|
|
|
|
</Select>
|
|
|
|
</FormControl>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
})}
|
|
|
|
</Box>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-06-29 00:43:08 +02:00
|
|
|
if (parsingPdf) {
|
|
|
|
return (
|
|
|
|
<Box sx={{ width: '100%', textAlign: 'center' }}>
|
|
|
|
<CircularProgress/>
|
|
|
|
</Box>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pdfFiles.length) {
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Box>
|
|
|
|
<Box sx={{ mt: 1 }}>
|
|
|
|
<Typography sx={{ mb: 1 }}>Draw fields on the PDFs:</Typography>
|
|
|
|
|
2024-07-11 16:16:36 +02:00
|
|
|
{pdfFiles.map((pdfFile, pdfFileIndex: number) => {
|
2024-06-29 00:43:08 +02:00
|
|
|
return (
|
2024-07-11 16:16:36 +02:00
|
|
|
<Accordion key={pdfFileIndex} expanded={pdfFile.expanded} onChange={(_event, expanded) => {handleAccordionExpandChange(expanded, pdfFile)}}>
|
2024-06-29 00:43:08 +02:00
|
|
|
<AccordionSummary
|
|
|
|
expandIcon={<ExpandMore />}
|
2024-07-11 16:16:36 +02:00
|
|
|
aria-controls={`panel${pdfFileIndex}-content`}
|
|
|
|
id={`panel${pdfFileIndex}header`}
|
2024-06-29 00:43:08 +02:00
|
|
|
>
|
|
|
|
<PictureAsPdf sx={{ mr: 1 }}/>
|
|
|
|
{pdfFile.file.name}
|
|
|
|
</AccordionSummary>
|
|
|
|
<AccordionDetails>
|
2024-07-11 16:16:36 +02:00
|
|
|
{getPdfPages(pdfFile, pdfFileIndex)}
|
2024-06-29 00:43:08 +02:00
|
|
|
</AccordionDetails>
|
|
|
|
</Accordion>
|
|
|
|
)
|
|
|
|
})}
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
{showDrawToolBox && (
|
|
|
|
<Box className={styles.drawToolBoxContainer}>
|
|
|
|
<Box className={styles.drawToolBox}>
|
2024-07-11 16:16:36 +02:00
|
|
|
{toolbox.filter(drawTool => drawTool.active).map((drawTool: DrawTool, index: number) => {
|
2024-06-29 00:43:08 +02:00
|
|
|
return (
|
2024-07-11 16:16:36 +02:00
|
|
|
<Box
|
|
|
|
key={index}
|
|
|
|
onClick={() => {handleToolSelect(drawTool)}} className={`${styles.toolItem} ${selectedTool?.identifier === drawTool.identifier ? styles.selected : ''}`}>
|
2024-06-29 00:43:08 +02:00
|
|
|
{ drawTool.icon }
|
|
|
|
{ drawTool.label }
|
|
|
|
</Box>
|
|
|
|
)
|
|
|
|
})}
|
|
|
|
</Box>
|
|
|
|
</Box>
|
|
|
|
)}
|
|
|
|
</Box>
|
|
|
|
)
|
|
|
|
}
|