-
+ New Form
+ {forms &&
+ (forms.length === 0 ? (
+
+
+
+
+ Welcome to snoopForms{" "}
+
+
+ Spin up forms in minutes. Pipe your data exactly where you need
+ it. Maximize your results with juicy analytics.
+
+ {/*
*/}
+
+
+
+ You don't have any forms yet.
+
+
+ It's time to create your first!
+
+
+
-
-
- {forms
- .sort((a, b) => b.updatedAt - a.updatedAt)
- .map((form, formIdx) => (
-
-
-
-
- {form.name}
-
-
-
-
-
+
+
+ ) : (
+
+
- )}
+
+ {forms
+ .sort((a, b) => b.updatedAt - a.updatedAt)
+ .map((form, formIdx) => (
+
+
+
+
+ {form.name}
+
+
+
+
+
+
+
+ ))}
+
+ ))}
);
}
diff --git a/components/builder/Builder.tsx b/components/builder/Builder.tsx
new file mode 100644
index 0000000000..452ac2036f
--- /dev/null
+++ b/components/builder/Builder.tsx
@@ -0,0 +1,49 @@
+import { useCallback, useEffect } from "react";
+import { v4 as uuidv4 } from "uuid";
+import { useNoCodeForm } from "../../lib/noCodeForm";
+import Loading from "../Loading";
+import Page from "./Page";
+
+export default function Builder({ formId }) {
+ const { noCodeForm, mutateNoCodeForm, isLoadingNoCodeForm } =
+ useNoCodeForm(formId);
+
+ const addPage = useCallback(() => {
+ if (noCodeForm) {
+ const updatedNCF = JSON.parse(JSON.stringify(noCodeForm));
+ updatedNCF.pages.push({
+ id: uuidv4(),
+ elements: [],
+ });
+ mutateNoCodeForm(updatedNCF, false);
+ }
+ }, [mutateNoCodeForm, noCodeForm]);
+
+ useEffect(() => {
+ if (noCodeForm && noCodeForm.pages.length === 0) addPage();
+ }, [noCodeForm]);
+
+ if (isLoadingNoCodeForm) {
+ return
;
+ }
+
+ return (
+
+
+
+
+ {noCodeForm.pages.map((page) => (
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/components/builder/Editor.tsx b/components/builder/Editor.tsx
new file mode 100644
index 0000000000..3f5b408b13
--- /dev/null
+++ b/components/builder/Editor.tsx
@@ -0,0 +1,38 @@
+import { useCallback, useRef } from "react";
+import { createReactEditorJS } from "react-editor-js";
+
+const ReactEditorJS = createReactEditorJS();
+
+const Editor = ({}) => {
+ const editorCore = useRef(null);
+
+ const handleInitialize = useCallback((instance) => {
+ editorCore.current = instance;
+ }, []);
+
+ /* const handleSave = useCallback(async () => {
+ const savedData = await editorCore.current.save();
+ console.log(savedData);
+ }, []);
+
+ setTimeout(() => {
+ // save every ten seconds
+ handleSave();
+ }, 10000); */
+
+ const EDITOR_JS_TOOLS = {};
+
+ // Editor.js This will show block editor in component
+ // pass EDITOR_JS_TOOLS in tools props to configure tools with editor.js
+ return (
+
+ );
+};
+
+// Return the CustomEditor to use by other components.
+
+export default Editor;
diff --git a/components/builder/Page.tsx b/components/builder/Page.tsx
new file mode 100644
index 0000000000..45dcdbbc1f
--- /dev/null
+++ b/components/builder/Page.tsx
@@ -0,0 +1,12 @@
+import dynamic from "next/dynamic";
+let Editor = dynamic(() => import("./Editor"), {
+ ssr: false,
+});
+
+export default function Page({}) {
+ return (
+
+ {Editor && }
+
+ );
+}
diff --git a/components/form/FormOnboardingModal.tsx b/components/form/FormOnboardingModal.tsx
index ccea7a0012..041c0678e6 100644
--- a/components/form/FormOnboardingModal.tsx
+++ b/components/form/FormOnboardingModal.tsx
@@ -1,8 +1,10 @@
/* This example requires Tailwind CSS v2.0+ */
import { Dialog, RadioGroup, Transition } from "@headlessui/react";
import { CheckCircleIcon, LightBulbIcon } from "@heroicons/react/solid";
+import { useRouter } from "next/router";
import { Fragment, useState } from "react";
import { persistForm, useForm } from "../../lib/forms";
+import { createNoCodeForm } from "../../lib/noCodeForm";
import { classNames } from "../../lib/utils";
import Loading from "../Loading";
@@ -23,15 +25,14 @@ const formTypes = [
type FormOnboardingModalProps = {
open: boolean;
- setOpen: (o: boolean) => void;
formId: string;
};
export default function FormOnboardingModal({
open,
- setOpen,
formId,
}: FormOnboardingModalProps) {
+ const router = useRouter();
const { form, mutateForm, isLoadingForm } = useForm(formId);
const [name, setName] = useState(form.name);
const [formType, setFormType] = useState(formTypes[0]);
@@ -46,7 +47,10 @@ export default function FormOnboardingModal({
};
await persistForm(updatedForm);
mutateForm(updatedForm);
- setOpen(false);
+ if (updatedForm.formType === "NOCODE") {
+ await createNoCodeForm(formId);
+ }
+ router.push(`/forms/${formId}/form`);
};
if (isLoadingForm) {
diff --git a/components/layout/LayoutBasic.tsx b/components/layout/LayoutBasic.tsx
index 73f8f5f05c..b7530b2b08 100644
--- a/components/layout/LayoutBasic.tsx
+++ b/components/layout/LayoutBasic.tsx
@@ -30,8 +30,13 @@ export default function Layout({ children }) {
-
-

+
+
@@ -86,7 +91,7 @@ export default function Layout({ children }) {
{/* Mobile menu button */}
-
+
Open main menu
{open ? (
diff --git a/components/layout/LayoutFormBuilder.tsx b/components/layout/LayoutFormBuilder.tsx
new file mode 100644
index 0000000000..71475544cb
--- /dev/null
+++ b/components/layout/LayoutFormBuilder.tsx
@@ -0,0 +1,63 @@
+import { signIn, useSession } from "next-auth/react";
+import Head from "next/head";
+import Loading from "../Loading";
+import MenuBreadcrumbs from "./MenuBreadcrumbs";
+import MenuProfile from "./MenuProfile";
+import MenuSteps from "./MenuSteps";
+
+export default function LayoutFormResults({
+ title,
+ formId,
+ currentStep,
+ children,
+}) {
+ const { data: session, status } = useSession();
+
+ if (status === "loading") {
+ return ;
+ }
+
+ if (!session) {
+ signIn();
+ return You need to be authenticated to view this page.
;
+ }
+
+ return (
+ <>
+
+ {title}
+
+
+
+
+
+ {/* Main content */}
+ {children}
+
+
+ >
+ );
+}
diff --git a/lib/noCodeForm.ts b/lib/noCodeForm.ts
new file mode 100644
index 0000000000..ab1cb6e919
--- /dev/null
+++ b/lib/noCodeForm.ts
@@ -0,0 +1,32 @@
+import useSWR from "swr";
+import { fetcher } from "./utils";
+
+export const useNoCodeForm = (formId) => {
+ const { data, error, mutate } = useSWR(
+ `/api/forms/${formId}/nocodeform`,
+ fetcher
+ );
+
+ return {
+ noCodeForm: data,
+ isLoadingNoCodeForm: !error && !data,
+ isErrorNoCodeForm: error,
+ mutateNoCodeForm: mutate,
+ };
+};
+
+export const createNoCodeForm = async (formId) => {
+ try {
+ const res = await fetch(`/api/forms/${formId}/nocodeform`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({}),
+ });
+ return await res.json();
+ } catch (error) {
+ console.error(error);
+ throw Error(
+ `createNoCodeForm: unable to create noCodeForm: ${error.message}`
+ );
+ }
+};
diff --git a/package.json b/package.json
index 09673c2943..825af2970f 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,8 @@
"lint": "next lint"
},
"dependencies": {
+ "@editorjs/editorjs": "^2.24.3",
+ "@editorjs/paragraph": "^2.8.0",
"@headlessui/react": "^1.6.1",
"@heroicons/react": "^1.0.6",
"@prisma/client": "^3.15.1",
@@ -22,7 +24,7 @@
"nodemailer": "^6.7.5",
"react": "18.1.0",
"react-dom": "18.1.0",
- "react-feather": "^2.0.9",
+ "react-editor-js": "^2.0.6",
"react-icons": "^4.4.0",
"superjson": "^1.9.1",
"swr": "^1.3.0"
diff --git a/pages/api/forms/[id]/nocodeform/index.ts b/pages/api/forms/[id]/nocodeform/index.ts
new file mode 100644
index 0000000000..00839c096a
--- /dev/null
+++ b/pages/api/forms/[id]/nocodeform/index.ts
@@ -0,0 +1,54 @@
+import type { NextApiResponse, NextApiRequest } from "next";
+import { getSession } from "next-auth/react";
+import { formHasOwnership } from "../../../../../lib/api";
+import { prisma } from "../../../../../lib/prisma";
+
+export default async function handle(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ // Check Authentication
+ const session = await getSession({ req: req });
+ if (!session) {
+ return res.status(401).json({ message: "Not authenticated" });
+ }
+
+ const formId = req.query.id.toString();
+
+ // GET /api/forms/:id/nocodeform
+ // Get noCodeForm for a form with specific id
+ if (req.method === "GET") {
+ const data = await prisma.noCodeForm.findUnique({
+ where: {
+ formId: formId,
+ },
+ });
+ return res.json(data);
+ }
+ // POST /api/forms/:id/nocodeform
+ // Updates an existing nocodeform
+ // Required fields in body: -
+ // Optional fields in body: title, published, finishedOnboarding, elements, elementsDraft
+ else if (req.method === "POST") {
+ const ownership = await formHasOwnership(session, formId);
+ if (!ownership) {
+ return res
+ .status(401)
+ .json({ message: "You are not authorized to change this noCodeForm" });
+ }
+ const data = { ...req.body, updatedAt: new Date() };
+ // create or update record
+ const prismaRes = await prisma.noCodeForm.upsert({
+ where: { formId },
+ update: data,
+ create: { form: { connect: { id: formId } } },
+ });
+ return res.json(prismaRes);
+ }
+ // Unknown HTTP Method
+ else {
+ throw new Error(
+ `The HTTP ${req.method} method is not supported by this route.`
+ );
+ }
+}
diff --git a/pages/auth/signin.tsx b/pages/auth/signin.tsx
index dac5fce205..ef10181366 100644
--- a/pages/auth/signin.tsx
+++ b/pages/auth/signin.tsx
@@ -2,6 +2,7 @@ import { getCsrfToken } from "next-auth/react";
import { useRouter } from "next/router";
import { XCircleIcon } from "@heroicons/react/solid";
import { GetServerSideProps } from "next";
+import Image from "next/image";
interface props {
csrfToken: string;
@@ -34,9 +35,14 @@ export default function SignIn({ csrfToken }: props) {
)}
-
+
-

+
@@ -65,7 +71,7 @@ export default function SignIn({ csrfToken }: props) {
type="email"
autoComplete="email"
required
- className="block w-full px-3 py-2 placeholder-lightgray-400 border border-lightgray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-snoopred-500 focus:border-snoopred-500 sm:text-sm"
+ className="block w-full px-3 py-2 border rounded-md shadow-sm appearance-none placeholder-lightgray-400 border-lightgray-300 focus:outline-none focus:ring-snoopred-500 focus:border-snoopred-500 sm:text-sm"
/>
@@ -83,7 +89,7 @@ export default function SignIn({ csrfToken }: props) {
type="password"
autoComplete="current-password"
required
- className="block w-full px-3 py-2 placeholder-lightgray-400 border border-lightgray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-snoopred-500 focus:border-snoopred-500 sm:text-sm"
+ className="block w-full px-3 py-2 border rounded-md shadow-sm appearance-none placeholder-lightgray-400 border-lightgray-300 focus:outline-none focus:ring-snoopred-500 focus:border-snoopred-500 sm:text-sm"
/>
@@ -91,12 +97,18 @@ export default function SignIn({ csrfToken }: props) {
diff --git a/pages/forms/[id]/form.tsx b/pages/forms/[id]/form.tsx
index 64b9afba57..b966ed9071 100644
--- a/pages/forms/[id]/form.tsx
+++ b/pages/forms/[id]/form.tsx
@@ -1,10 +1,10 @@
import { GetServerSideProps } from "next";
import { getSession } from "next-auth/react";
import { useRouter } from "next/router";
-import { useEffect, useState } from "react";
+import Builder from "../../../components/builder/Builder";
import FormCode from "../../../components/form/FormCode";
-import FormOnboardingModal from "../../../components/form/FormOnboardingModal";
import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
+import LayoutFormBuilder from "../../../components/layout/LayoutFormBuilder";
import Loading from "../../../components/Loading";
import { useForm } from "../../../lib/forms";
@@ -12,28 +12,26 @@ export default function FormPage() {
const router = useRouter();
const formId = router.query.id.toString();
const { form, isLoadingForm } = useForm(router.query.id);
- const [openOnboardingModal, setOpenOnboardingModal] = useState(false);
-
- useEffect(() => {
- if (form && !form.finishedOnboarding) {
- setOpenOnboardingModal(true);
- }
- }, [isLoadingForm]);
if (isLoadingForm) {
return
;
}
+ if (!form.finishedOnboarding) {
+ router.push(`/forms/${formId}/welcome`);
+ return
;
+ }
+
if (form.formType === "NOCODE") {
return (
<>
-
-
-
+
+
+
>
);
} else {
@@ -41,11 +39,6 @@ export default function FormPage() {
<>
-
>
);
diff --git a/pages/forms/[id]/welcome.tsx b/pages/forms/[id]/welcome.tsx
new file mode 100644
index 0000000000..1ec31b658b
--- /dev/null
+++ b/pages/forms/[id]/welcome.tsx
@@ -0,0 +1,43 @@
+import { GetServerSideProps } from "next";
+import { getSession } from "next-auth/react";
+import { useRouter } from "next/router";
+import { useEffect, useState } from "react";
+import FormOnboardingModal from "../../../components/form/FormOnboardingModal";
+import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
+import Loading from "../../../components/Loading";
+import { useForm } from "../../../lib/forms";
+
+export default function WelcomePage() {
+ const router = useRouter();
+ const formId = router.query.id.toString();
+ const { form, isLoadingForm } = useForm(router.query.id);
+ const [openOnboardingModal, setOpenOnboardingModal] = useState(false);
+
+ useEffect(() => {
+ if (form && !form.finishedOnboarding) {
+ setOpenOnboardingModal(true);
+ }
+ }, [isLoadingForm]);
+
+ if (isLoadingForm) {
+ return
;
+ }
+
+ if (!form.finishedOnboarding) {
+ return (
+
+
+
+ );
+ } else {
+ router.push(`/forms/${formId}`);
+ }
+}
+
+export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
+ const session = await getSession({ req });
+ if (!session) {
+ res.statusCode = 403;
+ }
+ return { props: {} };
+};
diff --git a/prisma/migrations/20220614082103_init/migration.sql b/prisma/migrations/20220615062843_init/migration.sql
similarity index 85%
rename from prisma/migrations/20220614082103_init/migration.sql
rename to prisma/migrations/20220615062843_init/migration.sql
index 4881278485..ebe1fadfab 100644
--- a/prisma/migrations/20220614082103_init/migration.sql
+++ b/prisma/migrations/20220615062843_init/migration.sql
@@ -19,6 +19,17 @@ CREATE TABLE "Form" (
CONSTRAINT "Form_pkey" PRIMARY KEY ("id")
);
+-- CreateTable
+CREATE TABLE "NoCodeForm" (
+ "id" TEXT NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+ "formId" TEXT NOT NULL,
+ "pages" JSONB NOT NULL DEFAULT '[]',
+
+ CONSTRAINT "NoCodeForm_pkey" PRIMARY KEY ("id")
+);
+
-- CreateTable
CREATE TABLE "Pipeline" (
"id" TEXT NOT NULL,
@@ -79,6 +90,9 @@ CREATE TABLE "verification_requests" (
CONSTRAINT "verification_requests_pkey" PRIMARY KEY ("id")
);
+-- CreateIndex
+CREATE UNIQUE INDEX "NoCodeForm_formId_key" ON "NoCodeForm"("formId");
+
-- CreateIndex
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
@@ -88,6 +102,9 @@ CREATE UNIQUE INDEX "verification_requests_token_key" ON "verification_requests"
-- AddForeignKey
ALTER TABLE "Form" ADD CONSTRAINT "Form_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+-- AddForeignKey
+ALTER TABLE "NoCodeForm" ADD CONSTRAINT "NoCodeForm_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
-- AddForeignKey
ALTER TABLE "Pipeline" ADD CONSTRAINT "Pipeline_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index ccb23c17c4..bfaedb1cb8 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -29,6 +29,16 @@ model Form {
schema Json
submissionSessions SubmissionSession[]
pipelines Pipeline[]
+ noCodeForm NoCodeForm?
+}
+
+model NoCodeForm {
+ id String @id @default(uuid())
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ form Form @relation(fields: [formId], references: [id], onDelete: Cascade)
+ formId String @unique
+ pages Json @default("[]")
}
model Pipeline {
diff --git a/public/img/mascot-face-small.png b/public/img/mascot-face-small.png
new file mode 100644
index 0000000000..650acb06a5
Binary files /dev/null and b/public/img/mascot-face-small.png differ
diff --git a/public/snoopForms_Logo_v4.svg b/public/img/snoopforms-logo.svg
similarity index 100%
rename from public/snoopForms_Logo_v4.svg
rename to public/img/snoopforms-logo.svg
diff --git a/yarn.lock b/yarn.lock
index 94139d6898..e795e6f70f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -44,6 +44,20 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
+"@editorjs/editorjs@^2.24.3":
+ version "2.24.3"
+ resolved "https://registry.yarnpkg.com/@editorjs/editorjs/-/editorjs-2.24.3.tgz#60ee6dd37d57b870ef29754355d77f9c61f30e79"
+ integrity sha512-VzrWaQ7mggNUAPTDGcqXJNIlBZH3S2IqsIUGA43UM2Q9VFaeS5KuVFVOTrFJvAzF7G+vZTO52ocm+hrDhTwvyw==
+ dependencies:
+ codex-notifier "^1.1.2"
+ codex-tooltip "^1.0.5"
+ nanoid "^3.1.22"
+
+"@editorjs/paragraph@^2.8.0":
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/@editorjs/paragraph/-/paragraph-2.8.0.tgz#11cc381fcafaf8b9160517ce65d59eee93fc4af9"
+ integrity sha512-z6w5ZR0ru3p/IjxJW/tb7OcSnVttkZukQMIsnBMX1FIKc1BNdr7NwM1YoCyTl4OnC90YfL0xgES6/20/W267pw==
+
"@eslint/eslintrc@^1.2.3":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
@@ -216,6 +230,25 @@
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz#f691893df506b93e3cb1ccc15ec6e5ac64e8e570"
integrity sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==
+"@react-editor-js/client@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@react-editor-js/client/-/client-2.0.6.tgz#be9a2704b58322bc37dc6d2acb014f0ff28fe43c"
+ integrity sha512-LMMJLAXAwk1kVMy7fxTRFK6OdouvoseqJbmVUygJb2EcfuT84nC9OAtvGEL4vsVLUcnzEV400+F9t5OKa77FGQ==
+ dependencies:
+ "@react-editor-js/core" "2.0.6"
+
+"@react-editor-js/core@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@react-editor-js/core/-/core-2.0.6.tgz#3f20c0668d1f8502489ed7e354ff26461b270dce"
+ integrity sha512-mvHM2I+gT3AnvFpFhTZI0EFLKD9pRpgXDf286uwv6n6tngwLfnCCmtCbgiGI9ICph2GJvRZfaQubE+MHQ6YV8g==
+
+"@react-editor-js/server@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@react-editor-js/server/-/server-2.0.6.tgz#237f11002b4db9fe754fd9a89ff76f131f8a21fb"
+ integrity sha512-soW/bV5auciYr8gEYISWK4fuIblAcc4bcwPuCKnDBj9W9r/nAxMmNgCG+z9rs9Gnroa0Ko3Hzwzs9d5MdOShzg==
+ dependencies:
+ "@react-editor-js/core" "2.0.6"
+
"@rushstack/eslint-patch@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz#6801033be7ff87a6b7cadaf5b337c9f366a3c4b0"
@@ -581,6 +614,16 @@ chokidar@^3.5.3:
optionalDependencies:
fsevents "~2.3.2"
+codex-notifier@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/codex-notifier/-/codex-notifier-1.1.2.tgz#a733079185f4c927fa296f1d71eb8753fe080895"
+ integrity sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg==
+
+codex-tooltip@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/codex-tooltip/-/codex-tooltip-1.0.5.tgz#ba25fd5b3a58ba2f73fd667c2b46987ffd1edef2"
+ integrity sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag==
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@@ -1567,7 +1610,7 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-nanoid@^3.1.30, nanoid@^3.3.4:
+nanoid@^3.1.22, nanoid@^3.1.30, nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
@@ -1908,7 +1951,7 @@ prisma@^3.15.1:
dependencies:
"@prisma/engines" "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
-prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -1940,12 +1983,13 @@ react-dom@18.1.0:
loose-envify "^1.1.0"
scheduler "^0.22.0"
-react-feather@^2.0.9:
- version "2.0.10"
- resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-2.0.10.tgz#0e9abf05a66754f7b7bb71757ac4da7fb6be3b68"
- integrity sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==
+react-editor-js@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/react-editor-js/-/react-editor-js-2.0.6.tgz#34771596986d79513e12e5f4990da46b9e0f2430"
+ integrity sha512-8u47IbhExiFB2kGNdJYlsX5iVlSzac38A3oJ7bmnTz3Lp7Slys1xreoYdG71+KiOcfX0dEgOIavV4e6TJeB5eg==
dependencies:
- prop-types "^15.7.2"
+ "@react-editor-js/client" "2.0.6"
+ "@react-editor-js/server" "2.0.6"
react-icons@^4.4.0:
version "4.4.0"