frontend pt 3

This commit is contained in:
knugget
2022-06-23 16:37:31 -05:00
parent 24a1e29af2
commit 29bd1973f2
9 changed files with 359 additions and 75 deletions

View File

@@ -6,6 +6,9 @@ interface Props {
onClick?: () => void;
disabled?: boolean;
fullwidth?: boolean;
small?: boolean;
icon?: boolean;
secondary?: boolean;
[key: string]: any;
}
@@ -15,14 +18,20 @@ const StandardButton: React.FC<Props> = ({
onClick = () => {},
disabled = false,
fullwidth = false,
small = false,
icon = false,
secondary = false,
...rest
}) => {
return (
<button
className={classNames(
`inline-flex items-center px-5 py-3 text-sm text-white rounded shadow-sm bg-snoopfade focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500`,
`inline-flex items-center rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500`,
disabled ? "disabled:opacity-50" : "",
fullwidth ? " w-full justify-center " : ""
fullwidth ? " w-full justify-center " : "",
small ? "px-2.5 py-1.5 text-xs" : "px-5 py-3 text-sm",
icon ? "px-1.5 py-1.5 text-xs" : "px-5 py-3 text-sm",
secondary ? "bg-ui-gray-light text-red" : "bg-snoopfade text-white"
)}
onClick={onClick}
disabled={disabled}

View File

@@ -1,5 +1,4 @@
import { NoCodeForm } from "@prisma/client";
import Link from "next/link";
import { useCallback, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { v4 as uuidv4 } from "uuid";
@@ -8,6 +7,15 @@ import { persistNoCodeForm, useNoCodeForm } from "../../lib/noCodeForm";
import Loading from "../Loading";
import Page from "./Page";
import ShareModal from "./ShareModal";
import SecondNavBar from "../layout/SecondNavBar";
import SecondNavBarItem from "../layout/SecondNavBarItem";
import {
DocumentAddIcon,
PlusIcon,
EyeIcon,
ShareIcon,
PaperAirplaneIcon,
} from "@heroicons/react/outline";
export default function Builder({ formId }) {
const { form, isLoadingForm } = useForm(formId);
@@ -117,35 +125,28 @@ export default function Builder({ formId }) {
return (
<>
<div className="relative z-10 flex flex-shrink-0 h-16 shadow-inner bg-ui-gray-lighter">
<div className="flex items-center justify-center flex-1 px-4">
<nav className="flex space-x-4" aria-label="resultModes">
<button
onClick={() => addPage()}
className="px-3 py-2 text-sm font-medium text-gray-600 border border-gray-800 rounded-md hover:text-gray-600"
>
Add Page
</button>
<Link href={`/forms/${formId}/preview`}>
<a className="px-3 py-2 text-sm font-medium text-gray-600 border border-gray-800 rounded-md hover:text-gray-600">
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>
<SecondNavBar>
<SecondNavBarItem>
<PlusIcon className="w-8 h-8 mx-auto stroke-1" />
Element
</SecondNavBarItem>
<SecondNavBarItem onClick={() => addPage()}>
<DocumentAddIcon className="w-8 h-8 mx-auto stroke-1" />
Page
</SecondNavBarItem>
<SecondNavBarItem link href={`/forms/${formId}/preview`}>
<EyeIcon className="w-8 h-8 mx-auto stroke-1" />
Preview
</SecondNavBarItem>
<SecondNavBarItem onClick={() => publishChanges()}>
<PaperAirplaneIcon className="w-8 h-8 mx-auto stroke-1" />
Publish
</SecondNavBarItem>
<SecondNavBarItem onClick={() => setOpenShareModal(true)}>
<ShareIcon className="w-8 h-8 mx-auto stroke-1" />
Share
</SecondNavBarItem>
</SecondNavBar>
<div className="w-full bg-ui-gray-lighter">
<div className="flex justify-center w-full">

View File

@@ -2,44 +2,65 @@ import { FaReact, FaVuejs } from "react-icons/fa";
import { DocumentSearchIcon } from "@heroicons/react/outline";
import { classNames } from "../../lib/utils";
import StandardButton from "../StandardButton";
const libs = [
{
id: "react",
name: "React",
href: "#",
bgColor: "bg-snoopfade",
version: "v0.1",
icon: FaReact,
},
{
id: "reactNative",
name: "React Native",
comingSoon: true,
href: "#",
bgColor: "bg-ui-gray-light",
icon: FaReact,
},
{
id: "vue",
name: "Vue.js",
comingSoon: true,
href: "#",
bgColor: "bg-ui-gray-light",
icon: FaVuejs,
},
{
id: "docs",
name: "Docs",
href: "#",
bgColor: "bg-snoopfade",
icon: DocumentSearchIcon,
},
];
import Link from "next/link";
import SecondNavBar from "../layout/SecondNavBar";
import SecondNavBarItem from "../layout/SecondNavBarItem";
export default function FormCode({ formId }) {
const libs = [
{
id: "react",
name: "React",
href: `forms/${formId}/react`,
bgColor: "bg-blue",
version: "v0.1",
icon: FaReact,
},
{
id: "reactNative",
name: "React Native",
comingSoon: true,
href: "#",
bgColor: "bg-ui-gray-light",
icon: FaReact,
},
{
id: "vue",
name: "Vue.js",
comingSoon: true,
href: "#",
bgColor: "bg-ui-gray-light",
icon: FaVuejs,
},
{
id: "docs",
name: "Docs",
href: "https://docs.snoopforms.com",
bgColor: "bg-ui-gray-dark",
icon: DocumentSearchIcon,
},
];
return (
<>
<SecondNavBar>
<SecondNavBarItem link href={`/forms/${formId}/react`}>
<FaReact className="w-8 h-8 mx-auto stroke-1" />
React
</SecondNavBarItem>
<SecondNavBarItem disabled>
<FaReact className="w-8 h-8 mx-auto stroke-1" />
React Native
</SecondNavBarItem>
<SecondNavBarItem disabled>
<FaVuejs className="w-8 h-8 mx-auto stroke-1" />
Vue
</SecondNavBarItem>
<SecondNavBarItem link outbound href="https://docs.snoopforms.com">
<DocumentSearchIcon className="w-8 h-8 mx-auto stroke-1" />
Docs
</SecondNavBarItem>
</SecondNavBar>
<header>
<div className="max-w-5xl">
<div className="mx-auto mt-8">
@@ -53,7 +74,7 @@ export default function FormCode({ formId }) {
<div className="mt-4 mb-12">
<p className="text-ui-gray-dark">
To send all form submissions to this dashboard, update the form ID
in the <strong>{"<snoopForm>"}</strong> component.
in the <code>{"<snoopForm>"}</code> component.
</p>
</div>
<div className="grid grid-cols-2 gap-10">
@@ -87,7 +108,7 @@ export default function FormCode({ formId }) {
<p>
<code>
{"<"}
<span className="text-yellow-200">SnoopForm</span>
<span className="text-yellow-200">snoopForm</span>
{""}
</code>
</p>
@@ -120,7 +141,11 @@ export default function FormCode({ formId }) {
className="grid grid-cols-1 gap-5 mt-3 sm:gap-6 sm:grid-cols-2"
>
{libs.map((lib) => (
<a className="flex col-span-1 rounded-md shadow-sm" key={lib.id}>
<a
className="flex col-span-1 rounded-md shadow-sm"
key={lib.id}
href={lib.href}
>
<li
className={classNames(
lib.comingSoon
@@ -163,12 +188,13 @@ export default function FormCode({ formId }) {
</a>
))}
</ul>
<div className="my-12 font-light text-center text-ui-gray-medium">
<p>
Your form is running? Go to{" "}
<a href="#" className="underline text-red">
Pipelines
</a>
<Link href={`/forms/${formId}/preview`}>
<a className="underline text-red">Pipelines</a>
</Link>
</p>
</div>
</div>

View File

@@ -1,8 +1,16 @@
import { HomeIcon } from "@heroicons/react/outline";
import { HomeIcon, PlusIcon } from "@heroicons/react/outline";
import Link from "next/link";
import { useForm } from "../../lib/forms";
import Router from "next/router";
import StandardButton from "../StandardButton";
import { createForm } from "../../lib/forms";
export default function MenuBreadcrumbs({ formId }) {
const newForm = async () => {
const form = await createForm();
await Router.push(`/forms/${form.id}/welcome`);
};
const { form, isLoadingForm } = useForm(formId);
const pages = [
@@ -18,6 +26,13 @@ export default function MenuBreadcrumbs({ formId }) {
<div className="hidden sm:flex sm:flex-1">
<nav className="hidden lg:flex" aria-label="Breadcrumb">
<ol className="flex items-center space-x-4">
<li>
<div>
<StandardButton icon secondary onClick={() => newForm()}>
<PlusIcon className="w-6 h-6" />
</StandardButton>
</div>
</li>
<li>
<div>
<Link href="/forms/">

View File

@@ -8,8 +8,8 @@ export default function MenuProfile({}) {
<Menu as="div" className="relative flex-shrink-0">
{({ open }) => (
<>
<div>
<Menu.Button className="flex text-sm bg-white rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
<div className="inline-flex items-center ">
<Menu.Button className="flex ml-3 text-sm bg-white rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
<span className="sr-only">Open user menu</span>
<img
className="w-8 h-8 rounded-full"

View File

@@ -0,0 +1,27 @@
import React from "react";
import { classNames } from "../../lib/utils";
interface Props {
children: React.ReactNode;
onClick?: () => void;
[key: string]: any;
}
// button component, consuming props
const SecondNavBar: React.FC<Props> = ({
children,
onClick = () => {},
...rest
}) => {
return (
<div className="relative z-10 flex flex-shrink-0 h-16 py-2 bg-ui-gray-lighter">
<div className="flex items-center justify-center flex-1 px-4 py-2">
<nav className="flex space-x-4" aria-label="resultModes">
{children}
</nav>
</div>
</div>
);
};
export default SecondNavBar;

View File

@@ -0,0 +1,58 @@
import React from "react";
import { classNames } from "../../lib/utils";
import Link from "next/link";
interface Props {
children: React.ReactNode;
onClick?: () => void;
itemLabel: string;
disabled?: boolean;
link?: boolean;
outbound?: boolean;
href: string;
}
// button component, consuming props
const SecondNavBarItem: React.FC<Props> = ({
children,
onClick = () => {},
itemLabel,
disabled = false,
link = false,
outbound = false,
href,
...rest
}) => {
return (
<div>
{link ? (
<Link href={href}>
<a
target={outbound ? "_blank" : "_self"}
className="inline-flex p-2 text-xs bg-transparent rounded-sm hover:bg-ui-gray-light hover:cursor-pointer text-ui-gray-dark hover:text-red"
>
<span>{children}</span>
{itemLabel}
</a>
</Link>
) : (
<button
className={classNames(
`p-2 text-xs rounded-sm`,
disabled
? "text-ui-gray-medium"
: "bg-transparent hover:bg-ui-gray-light text-ui-gray-dark hover:text-red"
)}
onClick={onClick}
disabled={disabled}
{...rest}
>
<span>{children}</span>
{itemLabel}
</button>
)}
</div>
);
};
export default SecondNavBarItem;

148
pages/forms/[id]/react.tsx Normal file
View File

@@ -0,0 +1,148 @@
import { GetServerSideProps } from "next";
import { getSession } from "next-auth/react";
import { useRouter } from "next/router";
import LayoutFormBasics from "../../../components/layout/LayoutFormBasic";
import Loading from "../../../components/Loading";
import StandardButton from "../../../components/StandardButton";
import { useForm } from "../../../lib/forms";
import { DocumentSearchIcon } from "@heroicons/react/outline";
import Link from "next/link";
import SecondNavBar from "../../../components/layout/SecondNavBar";
import SecondNavBarItem from "../../../components/layout/SecondNavBarItem";
import { FaReact, FaVuejs } from "react-icons/fa";
import { FaDiscord } from "react-icons/fa";
export default function ReactPage() {
const router = useRouter();
const formId = router.query.id.toString();
const { form, isLoadingForm } = useForm(router.query.id);
if (isLoadingForm) {
return <Loading />;
}
return (
<>
<LayoutFormBasics
title={form.title}
formId={formId}
currentStep="pipelines"
>
<SecondNavBar>
<SecondNavBarItem link href={`/forms/${formId}/react`}>
<FaReact className="w-8 h-8 mx-auto stroke-1" />
React
</SecondNavBarItem>
<SecondNavBarItem disabled>
<FaReact className="w-8 h-8 mx-auto stroke-1" />
React Native
</SecondNavBarItem>
<SecondNavBarItem disabled>
<FaVuejs className="w-8 h-8 mx-auto stroke-1" />
Vue
</SecondNavBarItem>
<SecondNavBarItem link outbound href="https://docs.snoopforms.com">
<DocumentSearchIcon className="w-8 h-8 mx-auto stroke-1" />
Docs
</SecondNavBarItem>
</SecondNavBar>
<header>
<div className="mx-auto mt-8 max-w-7xl">
<h1 className="text-3xl font-bold leading-tight text-ui-gray-dark">
Build your form with React
</h1>
</div>
</header>
<div className="my-4">
<p className="text-ui-gray-dark">
Use our pre-built components to build your form. Manage data in this
dashboard.
</p>
</div>
<div className="grid grid-cols-2 gap-10 mt-16">
<div>
<h2 className="text-xl font-bold text-ui-gray-dark">
1. Get started
</h2>
<p className="text-ui-gray-dark">
Install the snoopReact Library with Node Package Manager via
snoopforms/react.
</p>
</div>
<div className="p-8 font-light text-gray-200 bg-black rounded-md">
<code>{"npm install --save @snoopforms/react"}</code>
</div>
</div>
<div className="grid grid-cols-2 gap-10 mt-16">
<div>
<h2 className="text-xl font-bold text-ui-gray-dark">
2. Build the form
</h2>
<p className="text-ui-gray-dark">
Use the pre-built components snoopForm, snoopPage and snoopElement
to build exactly the form you want.
</p>
</div>
<div className="p-8 font-light text-gray-200 bg-black rounded-md">
<code>{`<SnoopForm
domain="localhost:3000"
protocol="http"
className="w-full space-y-6"
onSubmit={({ submission, schema })=>{}}>
<SnoopPage name="first">
<SnoopElement
type="text"
name={"name"}
label="Your name"
classNames={{
label: "your-label-class",
element: "your-input-class",}}
required/>
</SnoopPage>
<SnoopPage thankyou>
<h1>Thank you!</h1>
</SnoopPage>
</SnoopForm>`}</code>
</div>
</div>
<div className="grid grid-cols-2 gap-10 my-16">
<div>
<h2 className="text-xl font-bold text-ui-gray-dark">Questions?</h2>
<p className="pb-4 text-ui-gray-dark">
Find a more detailed explanation on how to go about build the form
and piping your data{" "}
<a
href="https://docs.snoopforms.com"
target="_blank"
rel="noreferrer"
className="underline text-red hover:no-underline"
>
in the docs.
</a>{" "}
Or join our Discord and ask us :)
</p>
</div>
<div className="flex items-center justify-center p-8 rounded-md bg-purple">
<a
className="inline-flex items-center justify-center px-4 py-2 bg-white rounded-sm hover:motion-safe:animate-bounce text-purple text-bold text-md"
href="https://discord.gg/kT4Aq7Kq"
target="_blank"
rel="noreferrer"
>
Join Discord <FaDiscord className="w-8 h-8 ml-2" />
</a>
</div>
</div>
</LayoutFormBasics>
</>
);
}
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const session = await getSession({ req });
if (!session) {
res.statusCode = 403;
}
return { props: {} };
};