mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 16:23:06 +10:00
editor component, viewer component
This commit is contained in:
@ -13,7 +13,7 @@ type FieldPropsType = {
|
|||||||
id: string;
|
id: string;
|
||||||
recipient: string;
|
recipient: string;
|
||||||
};
|
};
|
||||||
onPositionChangedHandler: any;
|
onPositionChanged: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Field(props: FieldPropsType) {
|
export default function Field(props: FieldPropsType) {
|
||||||
@ -31,7 +31,7 @@ export default function Field(props: FieldPropsType) {
|
|||||||
if (!position) return;
|
if (!position) return;
|
||||||
const { x, y } = position;
|
const { x, y } = position;
|
||||||
|
|
||||||
props.onPositionChangedHandler({ x, y }, props.field.id);
|
props.onPositionChanged({ x, y }, props.field.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,19 +1,78 @@
|
|||||||
import { NEXT_PUBLIC_WEBAPP_URL } from "@documenso/lib/constants";
|
import { NEXT_PUBLIC_WEBAPP_URL } from "@documenso/lib/constants";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
import { Button } from "@documenso/ui";
|
||||||
|
import short from "short-uuid";
|
||||||
|
const stc = require("string-to-color");
|
||||||
|
|
||||||
const PDFViewer = dynamic(() => import("./pdf-viewer"), {
|
const PDFViewer = dynamic(() => import("./pdf-viewer"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function PDFEditor(props: any) {
|
export default function PDFEditor(props: any) {
|
||||||
|
const [selectedValue, setSelectedValue] = useState("");
|
||||||
|
const [fields, setFields] = useState<any[]>([]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
function onPositionChangedHandler(position: any, id: any) {
|
||||||
|
if (!position) return;
|
||||||
|
const newFields = [...fields];
|
||||||
|
fields.find((e) => e.id == id).position = position;
|
||||||
|
|
||||||
|
// no instant redraw neccessary, postion information for saving or later rerender is enough
|
||||||
|
// setFields(newFields);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<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) }}
|
||||||
|
value={selectedValue}
|
||||||
|
onChange={(e) => setSelectedValue(e.target.value)}
|
||||||
|
>
|
||||||
|
{props?.document?.Recipient?.map((item: any) => (
|
||||||
|
<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>
|
||||||
|
<Button
|
||||||
|
className="inline ml-1"
|
||||||
|
onClick={() => {
|
||||||
|
setFields(
|
||||||
|
fields.concat({
|
||||||
|
id: short.generate().toString(),
|
||||||
|
page: 0,
|
||||||
|
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>
|
||||||
<PDFViewer
|
<PDFViewer
|
||||||
document={props.document}
|
document={props.document}
|
||||||
|
fields={fields}
|
||||||
|
onPositionChanged={onPositionChangedHandler}
|
||||||
pdfUrl={`${NEXT_PUBLIC_WEBAPP_URL}/api/documents/${router.query.id}`}
|
pdfUrl={`${NEXT_PUBLIC_WEBAPP_URL}/api/documents/${router.query.id}`}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,21 +2,14 @@ import { Fragment, useState } from "react";
|
|||||||
import { Document, Page } from "react-pdf/dist/esm/entry.webpack5";
|
import { Document, Page } from "react-pdf/dist/esm/entry.webpack5";
|
||||||
import Field from "./field";
|
import Field from "./field";
|
||||||
import short from "short-uuid";
|
import short from "short-uuid";
|
||||||
import { Button } from "@documenso/ui";
|
|
||||||
const stc = require("string-to-color");
|
|
||||||
|
|
||||||
export default function PDFViewer(props) {
|
export default function PDFViewer(props) {
|
||||||
const [file, setFile] = useState("");
|
const [file, setFile] = useState("");
|
||||||
const [selectedValue, setSelectedValue] = useState("");
|
|
||||||
const [numPages, setNumPages] = useState(null);
|
const [numPages, setNumPages] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [fields, setFields] = useState([]);
|
|
||||||
|
|
||||||
function onPositionChangedHandler(position, id) {
|
function onPositionChangedHandler(position, id) {
|
||||||
if (!position) return;
|
props.onPositionChanged(position, id);
|
||||||
const newFields = [...fields];
|
|
||||||
fields.find((e) => e.id == id).position = position;
|
|
||||||
// setFields(newFields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onFileChange(event) {
|
function onFileChange(event) {
|
||||||
@ -36,50 +29,7 @@ export default function PDFViewer(props) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div hidden={loading}>
|
<div hidden={loading}>
|
||||||
<div className="max-w-xs mt-6">
|
<div className="max-w-xs mt-6"></div>
|
||||||
<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
|
<Document
|
||||||
file={props.pdfUrl}
|
file={props.pdfUrl}
|
||||||
onLoadSuccess={onDocumentLoadSuccess}
|
onLoadSuccess={onDocumentLoadSuccess}
|
||||||
@ -109,12 +59,14 @@ export default function PDFViewer(props) {
|
|||||||
onLoadSuccess={() => setLoading(false)}
|
onLoadSuccess={() => setLoading(false)}
|
||||||
onRenderError={() => setLoading(false)}
|
onRenderError={() => setLoading(false)}
|
||||||
></Page>
|
></Page>
|
||||||
{fields.map((item) => (
|
{props?.fields
|
||||||
|
.filter((item) => item.page === index)
|
||||||
|
.map((item) => (
|
||||||
<Field
|
<Field
|
||||||
key={item.id}
|
key={item.id}
|
||||||
field={item}
|
field={item}
|
||||||
className="absolute"
|
className="absolute"
|
||||||
onPositionChangedHandler={onPositionChangedHandler}
|
onPositionChanged={onPositionChangedHandler}
|
||||||
></Field>
|
></Field>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user