add form frontend

This commit is contained in:
Matthias Nannt
2022-06-21 20:51:18 +09:00
parent 3414516dd6
commit 75b5dc987f
8 changed files with 169 additions and 11 deletions

View File

@@ -4,12 +4,14 @@ import { v4 as uuidv4 } from "uuid";
import { persistNoCodeForm, useNoCodeForm } from "../../lib/noCodeForm";
import Loading from "../Loading";
import Page from "./Page";
import ShareModal from "./ShareModal";
import UsageIntro from "./UsageIntro";
export default function Builder({ formId }) {
const { noCodeForm, isLoadingNoCodeForm, mutateNoCodeForm } =
useNoCodeForm(formId);
const [isInitialized, setIsInitialized] = useState(false);
const [openShareModal, setOpenShareModal] = useState(false);
const addPage = useCallback(async () => {
const newNoCodeForm = JSON.parse(JSON.stringify(noCodeForm));
@@ -37,6 +39,14 @@ export default function Builder({ formId }) {
}
}, [isLoadingNoCodeForm, noCodeForm, addPage, isInitialized]);
const publishChanges = async () => {
const newNoCodeForm = JSON.parse(JSON.stringify(noCodeForm));
newNoCodeForm.pages = newNoCodeForm.pagesDraft;
await persistNoCodeForm(newNoCodeForm);
mutateNoCodeForm(newNoCodeForm);
setOpenShareModal(true);
};
useEffect(() => {
initPages();
}, [isLoadingNoCodeForm, initPages]);
@@ -61,6 +71,18 @@ export default function Builder({ formId }) {
Preview Form
</a>
</Link>
<button
onClick={() => publishChanges()}
className="px-3 py-2 text-sm font-medium text-gray-600 border border-gray-800 rounded-md hover:text-gray-600"
>
Publish
</button>
<button
onClick={() => setOpenShareModal(true)}
className="px-3 py-2 text-sm font-medium text-gray-600 border border-gray-800 rounded-md hover:text-gray-600"
>
Share
</button>
</nav>
</div>
</div>
@@ -85,6 +107,11 @@ export default function Builder({ formId }) {
</div>
</div>
</div>
<ShareModal
open={openShareModal}
setOpen={setOpenShareModal}
formId={formId}
/>
</>
);
}

View File

@@ -0,0 +1,90 @@
/* This example requires Tailwind CSS v2.0+ */
import { Dialog, Transition } from "@headlessui/react";
import { XIcon } from "@heroicons/react/outline";
import { Fragment } from "react";
export default function ShareModal({ open, setOpen, formId }) {
const getPublicFormUrl = () => {
if (process.browser) {
return `${window.location.protocol}//${window.location.host}/f/${formId}/`;
}
};
return (
<Transition.Root show={open} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={setOpen}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex items-end justify-center min-h-full p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative px-4 pt-5 pb-4 overflow-hidden text-left transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:max-w-4xl sm:w-full sm:p-6">
<div className="absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button
type="button"
className="text-gray-400 bg-white rounded-md hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-snoopred-500"
onClick={() => setOpen(false)}
>
<span className="sr-only">Close</span>
<XIcon className="w-6 h-6" aria-hidden="true" />
</button>
</div>
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg font-medium leading-6 text-gray-900">
Share your form
</h3>
<div className="max-w-xl mt-2 text-sm text-gray-500">
<p>
Let your participants fill out your form by accessing it
via the public link.
</p>
</div>
<div className="mt-5 sm:flex sm:items-center">
<div className="w-full sm:max-w-xs">
<label htmlFor="surveyLink" className="sr-only">
Public link
</label>
<input
id="surveyLink"
type="text"
placeholder="Enter your email"
className="block w-full border-gray-300 rounded-md shadow-sm focus:ring-snoopred-500 focus:border-snoopred-500 sm:text-sm"
value={getPublicFormUrl()}
disabled
/>
</div>
<button
onClick={() => {
navigator.clipboard.writeText(getPublicFormUrl());
}}
className="inline-flex items-center justify-center w-full px-4 py-2 mt-3 font-medium text-white bg-gray-800 border border-transparent rounded-md shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
Copy
</button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}

View File

@@ -31,9 +31,6 @@ export default class TextQuestion implements BlockTool {
}
save(block: HTMLDivElement) {
console.log(
(block.firstElementChild.firstElementChild as HTMLInputElement).innerHTML
);
return {
label: (block.firstElementChild.firstElementChild as HTMLInputElement)
.innerHTML,

View File

@@ -19,9 +19,10 @@ export default function App({ id = "", formId, draft = false }) {
<div className="w-full px-5 py-5">
<SnoopForm
key={id} // used to reset form
domain="localhost:3000"
protocol="http"
formId="kQ1L4BLH"
domain={window.location.host}
protocol={window.location.protocol === "http:" ? "http" : "https"}
formId={formId}
localOnly={draft}
className="w-full max-w-3xl mx-auto space-y-6"
>
{pages.map((page) => (
@@ -48,7 +49,7 @@ export default function App({ id = "", formId, draft = false }) {
label={block.data.label}
classNames={{
button:
"flex justify-center px-4 py-2 mt-5 text-sm font-medium text-white border border-transparent rounded-md shadow-sm bg-red-600 hover:bg-red-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-600",
"flex justify-center px-4 py-2 mt-5 text-sm font-medium text-white border border-transparent rounded-md shadow-sm bg-gray-700 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-700",
}}
/>
) : null

1
package-lock.json generated
View File

@@ -51,7 +51,6 @@
"../snoopforms-react": {
"name": "@snoopforms/react",
"version": "0.0.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@fingerprintjs/fingerprintjs": "^3.3.3",

View File

@@ -15,7 +15,7 @@
"@headlessui/react": "^1.6.1",
"@heroicons/react": "^1.0.6",
"@prisma/client": "^3.15.1",
"@snoopforms/react": "file:../snoopforms-react",
"@snoopforms/react": "^0.0.2",
"babel-plugin-superjson-next": "^0.4.3",
"bcryptjs": "^2.4.3",
"date-fns": "^2.28.0",

42
pages/f/[id].tsx Normal file
View File

@@ -0,0 +1,42 @@
import { GetServerSideProps } from "next";
import { getSession } from "next-auth/react";
import Head from "next/head";
import { useRouter } from "next/router";
import App from "../../components/frontend/App";
import Loading from "../../components/Loading";
import { useForm } from "../../lib/forms";
export default function Share({}) {
const router = useRouter();
const formId = router.query.id.toString();
const { form, isLoadingForm } = useForm(formId);
if (isLoadingForm) {
return <Loading />;
}
if (form.formType !== "NOCODE") {
return (
<div>
Form Frontend is only avaiblable for Forms built with No-Code-Editor
</div>
);
}
return (
<>
<Head>
<title>SnoopForms</title>
</Head>
<App formId={formId} />
</>
);
}
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const session = await getSession({ req });
if (!session) {
res.statusCode = 403;
}
return { props: {} };
};

View File

@@ -252,8 +252,10 @@
resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz"
integrity sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==
"@snoopforms/react@file:../snoopforms-react":
version "0.0.1"
"@snoopforms/react@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@snoopforms/react/-/react-0.0.2.tgz#b74eaf671309a5c07b176690fd5394384265a6cf"
integrity sha512-yXE9w7Wak1RADJjG9ajuniA/gWL283rrUsCQpjDpg8NFgb8u9SklGcuXgybkioTl2FzppN41zSTiZC5kr/GPjA==
dependencies:
"@fingerprintjs/fingerprintjs" "^3.3.3"
"@headlessui/react" "^1.6.4"