fields ui

This commit is contained in:
Timur Ercan
2023-02-09 15:48:26 +01:00
parent 4cb9a3a65a
commit c4eb1b27d9
5 changed files with 106 additions and 52 deletions

View File

@ -1,38 +1,60 @@
import { ResizableBox, ResizeCallbackData } from "react-resizable";
import React, { SyntheticEvent, useState } from "react";
import React, { SyntheticEvent, useEffect, useState } from "react";
import Draggable from "react-draggable";
import { CircleStackIcon } from "@heroicons/react/24/outline";
import Logo from "../logo";
const stc = require("string-to-color");
type FieldPropsType = {
color: string;
type: string;
field: {
color: string;
type: string;
position: any;
id: string;
recipient: string;
};
onPositionChangedHandler: any;
};
export default function Field(props: FieldPropsType) {
const [field, setField]: any = useState(props.field);
const [position, setPosition]: any = useState(
props.field.position || { x: 0, y: -842 }
);
const nodeRef = React.createRef<HTMLDivElement>();
console.log(props.field);
const onControlledDrag = (e: any, position: any) => {
const { x, y } = position;
setPosition({ x, y });
};
const onDragStop = (e: any, position: any) => {
if (!position) return;
const { x, y } = position;
props.onPositionChangedHandler({ x, y }, props.field.id);
};
return (
<Draggable bounds="parent" defaultPosition={{ x: 0, y: -595 }}>
<ResizableBox
width={150}
height={75}
minConstraints={[170, 75]}
maxConstraints={[260, 125]}
className="bg-neon opacity-90 w-auto h-auto flex align-middle"
lockAspectRatio={true}
onResizeStart={(e: SyntheticEvent, data: ResizeCallbackData) => {
e.preventDefault();
e.stopPropagation();
}}
<Draggable
nodeRef={nodeRef}
bounds="parent"
position={position}
onDrag={onControlledDrag}
onStop={onDragStop}
>
<div
ref={nodeRef}
style={{ background: stc(props.field.recipient) }}
className="cursor-move opacity-90 p-2 m-auto w-auto flex-row-reverse text-lg font-bold text-center absolute"
>
<div className="m-auto w-auto flex-row-reverse text-lg font-bold text-center">
{/* todo icons */}
Signature
<div className="text-xs text-center">
Timur Ercan <br></br>
{"<timur.ercan31@gmail.com>"}
</div>
<div className="text-xs text-center">{props.field.recipient}</div>
</div>
</ResizableBox>
</div>
</Draggable>
);
}

View File

@ -2,11 +2,22 @@ import { Fragment, useState } from "react";
import { Document, Page } from "react-pdf/dist/esm/entry.webpack5";
import Field from "./editor/field";
import short from "short-uuid";
import { Button } from "@documenso/ui";
const stc = require("string-to-color");
export default function PDFViewer(props) {
const [file, setFile] = useState("");
const [selectedValue, setSelectedValue] = useState("");
const [numPages, setNumPages] = useState(null);
const [loading, setLoading] = useState(true);
const [fields, setFields] = useState([]);
function onPositionChangedHandler(position, id) {
if (!position) return;
const newFields = [...fields];
fields.find((e) => e.id == id).position = position;
// setFields(newFields);
}
function onFileChange(event) {
setFile(event.target.files[0]);
@ -25,6 +36,50 @@ export default function PDFViewer(props) {
return (
<>
<div hidden={loading}>
<div className="max-w-xs mt-6">
<select
className="mb-3 inline mt-1 w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
style={{ background: stc(selectedValue) }}
defaultValue={props?.document?.Recipient[0]}
value={selectedValue}
selectedIndex={0}
onChange={(e) => setSelectedValue(e.target.value)}
>
{props?.document?.Recipient?.map((item) => (
<option
key={item.email + short.generate().toString()}
style={{
background: stc(
item.name ? `${item.name} <${item.email}>` : item.email
),
}}
>
{item.name ? `${item.name} <${item.email}>` : item.email}
</option>
))}
</select>
</div>
<Button
className="inline ml-1"
onClick={() => {
setFields(
fields.concat({
id: short.generate().toString(),
type: "signature",
position: { x: 0, y: -842 },
recipient: selectedValue,
})
);
}}
>
Add Signature Field
</Button>
<Button color="secondary" className="inline ml-1">
Add Date Field
</Button>
<Button color="secondary" className="inline ml-1">
Add Text Field
</Button>
<Document
file={props.pdfUrl}
onLoadSuccess={onDocumentLoadSuccess}
@ -54,11 +109,12 @@ export default function PDFViewer(props) {
onLoadSuccess={() => setLoading(false)}
onRenderError={() => setLoading(false)}
></Page>
{props.fields.map((item) => (
{fields.map((item) => (
<Field
key={short.generate().toString()}
position={{ x: 0, y: -500 }}
key={item.id}
field={item}
className="absolute"
onPositionChangedHandler={onPositionChangedHandler}
></Field>
))}
</div>

View File

@ -43,6 +43,7 @@
"sass": "^1.57.1",
"short-uuid": "^4.2.2",
"signature_pad": "^4.1.4",
"string-to-color": "^2.2.2",
"typescript": "4.8.4"
},
"devDependencies": {

View File

@ -23,7 +23,6 @@ const PDFViewer = dynamic(() => import("../../../components/pdf-viewer"), {
const DocumentsDetailPage: NextPageWithLayout = (props: any) => {
const router = useRouter();
const [fields, setFields]: any[] = useState([]);
return (
<div className="mt-4">
@ -95,34 +94,8 @@ const DocumentsDetailPage: NextPageWithLayout = (props: any) => {
</div>
</div>
<div className="mx-auto w-fit">
<div className="max-w-xs mt-6">
<select
className="mb-3 inline mt-1 w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
defaultValue={props?.document?.Recipient[0]}
>
{props?.document?.Recipient?.map((item: any) => (
<option key={item.email + short.generate().toString()}>
{item.name ? `${item.name} <${item.email}>` : item.email}
</option>
))}
</select>
<Button
className="inline ml-1"
onClick={() => {
setFields(fields.concat({ type: "signature" }));
}}
>
Add Signature
</Button>
<Button color="secondary" className="inline ml-1">
Add Date
</Button>
<Button color="secondary" className="inline ml-1">
Add Text
</Button>
</div>
<PDFViewer
fields={fields}
document={props.document}
pdfUrl={`${NEXT_PUBLIC_WEBAPP_URL}/api/documents/${router.query.id}`}
/>
</div>

4
package-lock.json generated
View File

@ -76,6 +76,7 @@
"sass": "^1.57.1",
"short-uuid": "^4.2.2",
"signature_pad": "^4.1.4",
"string-to-color": "^2.2.2",
"typescript": "4.8.4"
},
"devDependencies": {
@ -8538,7 +8539,7 @@
"@types/nodemailer-sendgrid": "^1.0.0",
"@types/react-dom": "18.0.9",
"@types/react-pdf": "^6.2.0",
"@types/react-resizable": "*",
"@types/react-resizable": "^3.0.3",
"autoprefixer": "^10.4.13",
"avatar-from-initials": "^1.0.3",
"bcryptjs": "^2.4.3",
@ -8566,6 +8567,7 @@
"sass": "^1.57.1",
"short-uuid": "^4.2.2",
"signature_pad": "^4.1.4",
"string-to-color": "*",
"tailwindcss": "^3.2.4",
"typescript": "4.8.4"
},