mirror of
https://github.com/formbricks/formbricks.git
synced 2026-03-18 09:41:32 -05:00
Merge branch 'main' of github.com:formbricks/formbricks
This commit is contained in:
@@ -140,7 +140,6 @@ export default function FeedbackModal({ show, setShow, formId, customer }: Feedb
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
console.log("submission sent!");
|
||||
e.target.reset();
|
||||
setFeedbackSent(true);
|
||||
}}>
|
||||
|
||||
@@ -45,6 +45,15 @@ const nextConfig = {
|
||||
},
|
||||
];
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: "/demo",
|
||||
destination: "/demo/organisations/demo-organisation/forms/demo-pmf",
|
||||
permanent: false,
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.NEXT_PUBLIC_SENTRY_DSN) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import { convertDateTimeString, onlyUnique, parseUserAgent } from "@/lib/utils";
|
||||
import { BackIcon } from "@formbricks/ui";
|
||||
import { InboxIcon } from "@heroicons/react/24/outline";
|
||||
import clsx from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useMemo } from "react";
|
||||
import EmptyPageFiller from "../EmptyPageFiller";
|
||||
@@ -39,12 +38,10 @@ export default function SingleCustomerPage() {
|
||||
return (
|
||||
<div>
|
||||
<main className="mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<Link
|
||||
className="inline-flex pt-5 text-sm text-gray-500"
|
||||
href={`/organisations/${router.query.organisationId}/customers/`}>
|
||||
<button className="inline-flex pt-5 text-sm text-gray-500" onClick={() => router.back()}>
|
||||
<BackIcon className="mr-2 h-5 w-5" />
|
||||
Back to customers overview
|
||||
</Link>
|
||||
Back
|
||||
</button>
|
||||
<div className="flex items-baseline justify-between border-b border-gray-200 pt-4 pb-6">
|
||||
<h1 className="text-4xl font-bold tracking-tight text-gray-900">{customer.email}</h1>
|
||||
</div>
|
||||
|
||||
@@ -136,7 +136,9 @@ export default function PMFTimeline({ submissions }) {
|
||||
{submission.customerEmail ? (
|
||||
<Link
|
||||
className="text-sm font-medium text-gray-700"
|
||||
href={`/organisations/${router.query.organisationId}/customers/${submission.customerEmail}`}>
|
||||
href={`${form.id.startsWith("demo") ? "/demo" : ""}/organisations/${
|
||||
router.query.organisationId
|
||||
}/customers/${submission.customerEmail}`}>
|
||||
{submission.customerEmail}
|
||||
</Link>
|
||||
) : (
|
||||
|
||||
@@ -7,13 +7,14 @@ import { useForm } from "@/lib/forms";
|
||||
import { getOptionLabelMap, useSubmissions } from "@/lib/submissions";
|
||||
import { Pie } from "@formbricks/charts";
|
||||
import { NotDisappointedIcon, SomewhatDisappointedIcon, VeryDisappointedIcon } from "@formbricks/ui";
|
||||
import { InformationCircleIcon } from "@heroicons/react/20/solid";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useMemo, useState } from "react";
|
||||
import FilterNavigation from "../shared/FilterNavigation";
|
||||
|
||||
const limitFields = ["userSegment"];
|
||||
|
||||
export default function SegmentResults() {
|
||||
const router = useRouter();
|
||||
const [filteredSubmissions, setFilteredSubmissions] = useState([]);
|
||||
@@ -61,7 +62,7 @@ export default function SegmentResults() {
|
||||
<FilterNavigation
|
||||
submissions={submissions}
|
||||
setFilteredSubmissions={setFilteredSubmissions}
|
||||
limitFields={["userSegment"]}
|
||||
limitFields={limitFields}
|
||||
/>
|
||||
<div className="mb-2 flex py-2 text-sm font-bold">
|
||||
<h4 className="text-slate-600">Tutorials</h4>
|
||||
@@ -113,7 +114,9 @@ export default function SegmentResults() {
|
||||
<div className="rounded-md bg-teal-50 p-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<InformationCircleIcon className="h-5 w-5 text-teal-400" aria-hidden="true" />
|
||||
<span className="inline-flex items-center rounded-full bg-teal-100 px-2.5 py-0.5 text-xs font-medium text-teal-800">
|
||||
How it works
|
||||
</span>
|
||||
</div>
|
||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
||||
<p className="text-sm text-teal-700">
|
||||
@@ -171,7 +174,9 @@ export default function SegmentResults() {
|
||||
<div className="rounded-md bg-teal-50 p-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<InformationCircleIcon className="h-5 w-5 text-teal-400" aria-hidden="true" />
|
||||
<span className="inline-flex items-center rounded-full bg-teal-100 px-2.5 py-0.5 text-xs font-medium text-teal-800">
|
||||
How it works
|
||||
</span>
|
||||
</div>
|
||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
||||
<p className="text-sm text-teal-700">
|
||||
|
||||
@@ -29,9 +29,6 @@ export const DataInSurvey = () => {
|
||||
process.env.NODE_ENV === "production" ? "cldvn1r6x0002s00gnw01lj40" : "cldvkpx11000019a0aoucngcb"
|
||||
}
|
||||
customer={{ email: session.user.email }}
|
||||
onFinished={({ submission }) => {
|
||||
console.log(submission);
|
||||
}}
|
||||
schema={{
|
||||
config: {
|
||||
progressBar: false,
|
||||
|
||||
118
apps/web/src/components/layout/LayoutDemo.tsx
Normal file
118
apps/web/src/components/layout/LayoutDemo.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
"use client";
|
||||
|
||||
import AvatarPlaceholder from "@/images/avatar-placeholder.png";
|
||||
import { Disclosure, Menu, Transition } from "@headlessui/react";
|
||||
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Fragment } from "react";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import { Logo } from "../Logo";
|
||||
|
||||
export default function LayoutDemo({ children }) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Formbricks</title>
|
||||
<meta name="description" content="Build user research into your product" />
|
||||
</Head>
|
||||
<div className="min-h-screen">
|
||||
<Disclosure as="nav" className="border-b border-gray-200 bg-white">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<div className="mx-auto w-full px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex h-16 justify-between">
|
||||
<div className="flex">
|
||||
<div className="flex flex-shrink-0 items-center">
|
||||
<Link href="/">
|
||||
<Logo className="block h-8 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden sm:ml-6 sm:flex sm:items-center">
|
||||
{/* <button
|
||||
type="button"
|
||||
className="rounded-full bg-white p-1 text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
|
||||
<span className="sr-only">View notifications</span>
|
||||
<BellIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button> */}
|
||||
|
||||
{/* Profile dropdown */}
|
||||
<Menu as="div" className="relative ml-3">
|
||||
<div>
|
||||
<Menu.Button className="focus:ring-brand flex max-w-xs items-center rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-offset-2">
|
||||
<span className="sr-only">Open user menu</span>
|
||||
<Image
|
||||
src={AvatarPlaceholder}
|
||||
width="100"
|
||||
height="100"
|
||||
className="h-8 w-8 rounded-full"
|
||||
alt="Avatar placeholder"
|
||||
/>
|
||||
</Menu.Button>
|
||||
</div>
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95">
|
||||
<Menu.Items className="absolute right-0 z-10 mt-2 w-48 origin-top-right divide-y divide-gray-100 rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
<div className="px-4 py-3">
|
||||
<p className="text-sm">Signed in as</p>
|
||||
<p className="truncate text-sm font-medium text-gray-900">Demo</p>
|
||||
</div>
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
</div>
|
||||
<div className="-mr-2 flex items-center sm:hidden">
|
||||
{/* Mobile menu button */}
|
||||
<Disclosure.Button className="inline-flex items-center justify-center rounded-md bg-white p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
|
||||
<span className="sr-only">Open main menu</span>
|
||||
{open ? (
|
||||
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
|
||||
) : (
|
||||
<Bars3Icon className="block h-6 w-6" aria-hidden="true" />
|
||||
)}
|
||||
</Disclosure.Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Disclosure.Panel className="sm:hidden">
|
||||
<div className="border-t border-gray-200 pt-4 pb-3">
|
||||
<div className="flex items-center px-4">
|
||||
<div className="flex-shrink-0">
|
||||
<Image
|
||||
className="h-10 w-10 rounded-full"
|
||||
src={AvatarPlaceholder}
|
||||
alt="profile picture"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<div className="text-base font-medium text-gray-800">Demo User</div>
|
||||
<div className="text-sm font-medium text-gray-500">demo@formbricks.com</div>
|
||||
</div>
|
||||
{/* <button
|
||||
type="button"
|
||||
className="ml-auto flex-shrink-0 rounded-full bg-white p-1 text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
|
||||
<span className="sr-only">View notifications</span>
|
||||
<BellIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button> */}
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
|
||||
<main className="h-full bg-gray-50">{children}</main>
|
||||
<ToastContainer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
387
apps/web/src/demo-data/customers-demo-customer.ts
Normal file
387
apps/web/src/demo-data/customers-demo-customer.ts
Normal file
@@ -0,0 +1,387 @@
|
||||
const output = {
|
||||
email: "user@example.com",
|
||||
createdAt: "2023-02-03T12:20:58.516Z",
|
||||
updatedAt: "2023-02-03T12:20:58.516Z",
|
||||
organisationId: "cldoc9md4000119204dn8i5td",
|
||||
data: {
|
||||
name: "John",
|
||||
},
|
||||
submissions: [
|
||||
{
|
||||
id: "cldoi02dh000619vitjyq89n0",
|
||||
createdAt: "2023-02-03T12:24:00.774Z",
|
||||
updatedAt: "2023-02-03T12:24:35.356Z",
|
||||
finished: true,
|
||||
archived: false,
|
||||
formId: "cldohxjrl000519viwe8i9d39",
|
||||
customerEmail: "test@crowd.dev",
|
||||
customerOrganisationId: "cldoc9md4000119204dn8i5td",
|
||||
data: {
|
||||
improvement: "Make it possible to add a note to a transaction",
|
||||
mainBenefit: "The best is that I can get a quick overview of all my transactions",
|
||||
userSegment: "founder",
|
||||
disappointment: "veryDisappointed",
|
||||
selfSegmentation: "other founders",
|
||||
},
|
||||
meta: {
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
},
|
||||
form: {
|
||||
id: "cldohxjrl000519viwe8i9d39",
|
||||
createdAt: "2023-02-03T12:22:03.346Z",
|
||||
updatedAt: "2023-02-03T12:22:03.346Z",
|
||||
type: "pmf",
|
||||
label: "PMF Demo",
|
||||
organisationId: "cldoc9md4000119204dn8i5td",
|
||||
schema: {
|
||||
pages: [
|
||||
{
|
||||
id: "disappointmentPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "disappointment",
|
||||
name: "disappointment",
|
||||
type: "radio",
|
||||
label: "How disappointed would you be if you could no longer use our service?",
|
||||
options: [
|
||||
{
|
||||
label: "Very disappointed",
|
||||
value: "veryDisappointed",
|
||||
},
|
||||
{
|
||||
label: "Somewhat disappointed",
|
||||
value: "somewhatDisappointed",
|
||||
},
|
||||
{
|
||||
label: "Not disappointed",
|
||||
value: "notDisappointed",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "mainBenefitPage",
|
||||
elements: [
|
||||
{
|
||||
id: "mainBenefit",
|
||||
name: "mainBenefit",
|
||||
type: "text",
|
||||
label: "What is the main benefit you receive from our service?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "userSegmentPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "userSegment",
|
||||
name: "userSegment",
|
||||
type: "radio",
|
||||
label: "What is your job title?",
|
||||
options: [
|
||||
{
|
||||
label: "Founder",
|
||||
value: "founder",
|
||||
},
|
||||
{
|
||||
label: "Executive",
|
||||
value: "executive",
|
||||
},
|
||||
{
|
||||
label: "Product Manager",
|
||||
value: "productManager",
|
||||
},
|
||||
{
|
||||
label: "Product Owner",
|
||||
value: "productOwner",
|
||||
},
|
||||
{
|
||||
label: "Software Engineer",
|
||||
value: "softwareEngineer",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "improvementPage",
|
||||
elements: [
|
||||
{
|
||||
id: "improvement",
|
||||
name: "improvement",
|
||||
type: "text",
|
||||
label: "How can we improve our service for you?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "selfSegmentationPage",
|
||||
elements: [
|
||||
{
|
||||
id: "selfSegmentation",
|
||||
name: "selfSegmentation",
|
||||
type: "text",
|
||||
label: "What type of people would benefit most from using our service?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPage",
|
||||
elements: [
|
||||
{
|
||||
id: "thankYou",
|
||||
name: "thankYou",
|
||||
type: "html",
|
||||
},
|
||||
],
|
||||
endScreen: true,
|
||||
},
|
||||
],
|
||||
config: {},
|
||||
schemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cldohw5qs000119vi6sv59odw",
|
||||
createdAt: "2023-02-03T12:20:58.516Z",
|
||||
updatedAt: "2023-02-03T12:20:58.516Z",
|
||||
finished: true,
|
||||
archived: false,
|
||||
formId: "cldohpx4t000019vijzlf8mgn",
|
||||
customerEmail: "user@example.com",
|
||||
customerOrganisationId: "cldoc9md4000119204dn8i5td",
|
||||
data: {
|
||||
message: "Really love your new design. Great job guys!",
|
||||
pageUrl: "http://localhost:3002/feedback-widget",
|
||||
feedbackType: "compliment",
|
||||
},
|
||||
meta: {
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
},
|
||||
form: {
|
||||
id: "cldohpx4t000019vijzlf8mgn",
|
||||
createdAt: "2023-02-03T12:16:07.422Z",
|
||||
updatedAt: "2023-02-03T12:16:07.422Z",
|
||||
type: "feedback",
|
||||
label: "Feedback Form Demo",
|
||||
organisationId: "cldoc9md4000119204dn8i5td",
|
||||
schema: {
|
||||
pages: [
|
||||
{
|
||||
id: "feedbackTypePage",
|
||||
elements: [
|
||||
{
|
||||
name: "feedbackType",
|
||||
type: "radio",
|
||||
label: "What's on your mind?",
|
||||
options: [
|
||||
{
|
||||
label: "Idea",
|
||||
value: "idea",
|
||||
},
|
||||
{
|
||||
label: "Compliment",
|
||||
value: "compliment",
|
||||
},
|
||||
{
|
||||
label: "Bug",
|
||||
value: "bug",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "messagePage",
|
||||
elements: [
|
||||
{
|
||||
name: "message",
|
||||
type: "textarea",
|
||||
label: "What's your feedback?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPage",
|
||||
elements: [
|
||||
{
|
||||
name: "thankYou",
|
||||
type: "html",
|
||||
},
|
||||
],
|
||||
endScreen: true,
|
||||
},
|
||||
],
|
||||
config: {},
|
||||
schemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cldohwtyr000319viwrymradt",
|
||||
createdAt: "2023-02-03T12:21:29.908Z",
|
||||
updatedAt: "2023-02-03T12:21:29.908Z",
|
||||
finished: true,
|
||||
archived: false,
|
||||
formId: "cldohpx4t000019vijzlf8mgn",
|
||||
customerEmail: "user@example.com",
|
||||
customerOrganisationId: "cldoc9md4000119204dn8i5td",
|
||||
data: {
|
||||
message: "Maybe you can add a mobile app so I can check my account balance on the go 😊",
|
||||
pageUrl: "http://localhost:3002/feedback-widget",
|
||||
feedbackType: "idea",
|
||||
},
|
||||
meta: {
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
},
|
||||
form: {
|
||||
id: "cldohpx4t000019vijzlf8mgn",
|
||||
createdAt: "2023-02-03T12:16:07.422Z",
|
||||
updatedAt: "2023-02-03T12:16:07.422Z",
|
||||
type: "feedback",
|
||||
label: "Feedback Form Demo",
|
||||
organisationId: "cldoc9md4000119204dn8i5td",
|
||||
schema: {
|
||||
pages: [
|
||||
{
|
||||
id: "feedbackTypePage",
|
||||
elements: [
|
||||
{
|
||||
name: "feedbackType",
|
||||
type: "radio",
|
||||
label: "What's on your mind?",
|
||||
options: [
|
||||
{
|
||||
label: "Idea",
|
||||
value: "idea",
|
||||
},
|
||||
{
|
||||
label: "Compliment",
|
||||
value: "compliment",
|
||||
},
|
||||
{
|
||||
label: "Bug",
|
||||
value: "bug",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "messagePage",
|
||||
elements: [
|
||||
{
|
||||
name: "message",
|
||||
type: "textarea",
|
||||
label: "What's your feedback?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPage",
|
||||
elements: [
|
||||
{
|
||||
name: "thankYou",
|
||||
type: "html",
|
||||
},
|
||||
],
|
||||
endScreen: true,
|
||||
},
|
||||
],
|
||||
config: {},
|
||||
schemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cldohx4lk000419vilwqzfcnk",
|
||||
createdAt: "2023-02-03T12:21:43.688Z",
|
||||
updatedAt: "2023-02-03T12:21:43.688Z",
|
||||
finished: true,
|
||||
archived: false,
|
||||
formId: "cldohpx4t000019vijzlf8mgn",
|
||||
customerEmail: "user@example.com",
|
||||
customerOrganisationId: "cldoc9md4000119204dn8i5td",
|
||||
data: {
|
||||
message: 'I get a blank page after clicking on "my profile"',
|
||||
pageUrl: "http://localhost:3002/feedback-widget",
|
||||
feedbackType: "bug",
|
||||
},
|
||||
meta: {
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
},
|
||||
form: {
|
||||
id: "cldohpx4t000019vijzlf8mgn",
|
||||
createdAt: "2023-02-03T12:16:07.422Z",
|
||||
updatedAt: "2023-02-03T12:16:07.422Z",
|
||||
type: "feedback",
|
||||
label: "Feedback Form Demo",
|
||||
organisationId: "cldoc9md4000119204dn8i5td",
|
||||
schema: {
|
||||
pages: [
|
||||
{
|
||||
id: "feedbackTypePage",
|
||||
elements: [
|
||||
{
|
||||
name: "feedbackType",
|
||||
type: "radio",
|
||||
label: "What's on your mind?",
|
||||
options: [
|
||||
{
|
||||
label: "Idea",
|
||||
value: "idea",
|
||||
},
|
||||
{
|
||||
label: "Compliment",
|
||||
value: "compliment",
|
||||
},
|
||||
{
|
||||
label: "Bug",
|
||||
value: "bug",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "messagePage",
|
||||
elements: [
|
||||
{
|
||||
name: "message",
|
||||
type: "textarea",
|
||||
label: "What's your feedback?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPage",
|
||||
elements: [
|
||||
{
|
||||
name: "thankYou",
|
||||
type: "html",
|
||||
},
|
||||
],
|
||||
endScreen: true,
|
||||
},
|
||||
],
|
||||
config: {},
|
||||
schemaVersion: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default output;
|
||||
16
apps/web/src/demo-data/customers.ts
Normal file
16
apps/web/src/demo-data/customers.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
const output = [
|
||||
{
|
||||
email: "user@example.com",
|
||||
createdAt: "2023-02-03T12:20:58.516Z",
|
||||
updatedAt: "2023-02-03T12:20:58.516Z",
|
||||
organisationId: "demo-organisation",
|
||||
data: {
|
||||
name: "Matti",
|
||||
},
|
||||
_count: {
|
||||
submissions: 5,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default output;
|
||||
5
apps/web/src/demo-data/forms-demo-pmf-submissions.ts
Normal file
5
apps/web/src/demo-data/forms-demo-pmf-submissions.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { getPmfSubmissions } from "./pmf-submissions";
|
||||
|
||||
const output = getPmfSubmissions();
|
||||
|
||||
export default output;
|
||||
124
apps/web/src/demo-data/forms-demo-pmf.ts
Normal file
124
apps/web/src/demo-data/forms-demo-pmf.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
const output = {
|
||||
id: "demo-pmf",
|
||||
createdAt: "2023-02-03T12:22:03.346Z",
|
||||
updatedAt: "2023-02-03T12:22:03.346Z",
|
||||
type: "pmf",
|
||||
label: "PMF Demo",
|
||||
organisationId: "demo-organisation",
|
||||
schema: {
|
||||
pages: [
|
||||
{
|
||||
id: "disappointmentPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "disappointment",
|
||||
name: "disappointment",
|
||||
type: "radio",
|
||||
label: "How disappointed would you be if you could no longer use our service?",
|
||||
options: [
|
||||
{
|
||||
label: "Very disappointed",
|
||||
value: "veryDisappointed",
|
||||
},
|
||||
{
|
||||
label: "Somewhat disappointed",
|
||||
value: "somewhatDisappointed",
|
||||
},
|
||||
{
|
||||
label: "Not disappointed",
|
||||
value: "notDisappointed",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "mainBenefitPage",
|
||||
elements: [
|
||||
{
|
||||
id: "mainBenefit",
|
||||
name: "mainBenefit",
|
||||
type: "text",
|
||||
label: "What is the main benefit you receive from our service?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "userSegmentPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "userSegment",
|
||||
name: "userSegment",
|
||||
type: "radio",
|
||||
label: "What is your job title?",
|
||||
options: [
|
||||
{
|
||||
label: "Founder",
|
||||
value: "founder",
|
||||
},
|
||||
{
|
||||
label: "Executive",
|
||||
value: "executive",
|
||||
},
|
||||
{
|
||||
label: "Product Manager",
|
||||
value: "productManager",
|
||||
},
|
||||
{
|
||||
label: "Product Owner",
|
||||
value: "productOwner",
|
||||
},
|
||||
{
|
||||
label: "Software Engineer",
|
||||
value: "softwareEngineer",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "improvementPage",
|
||||
elements: [
|
||||
{
|
||||
id: "improvement",
|
||||
name: "improvement",
|
||||
type: "text",
|
||||
label: "How can we improve our service for you?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "selfSegmentationPage",
|
||||
elements: [
|
||||
{
|
||||
id: "selfSegmentation",
|
||||
name: "selfSegmentation",
|
||||
type: "text",
|
||||
label: "What type of people would benefit most from using our service?",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPage",
|
||||
elements: [
|
||||
{
|
||||
id: "thankYou",
|
||||
name: "thankYou",
|
||||
type: "html",
|
||||
},
|
||||
],
|
||||
endScreen: true,
|
||||
},
|
||||
],
|
||||
config: {},
|
||||
schemaVersion: 1,
|
||||
},
|
||||
};
|
||||
|
||||
export default output;
|
||||
15
apps/web/src/demo-data/pipelines-demo-pipeline.ts
Normal file
15
apps/web/src/demo-data/pipelines-demo-pipeline.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
const output = {
|
||||
id: "pmf-demo-pipeline-1",
|
||||
createdAt: "2023-02-08T10:52:47.877Z",
|
||||
updatedAt: "2023-02-08T10:52:47.877Z",
|
||||
label: "email",
|
||||
type: "emailNotification",
|
||||
events: ["submissionFinished"],
|
||||
formId: "demo-pmf",
|
||||
enabled: true,
|
||||
config: {
|
||||
email: "mail@example.com",
|
||||
},
|
||||
};
|
||||
|
||||
export default output;
|
||||
17
apps/web/src/demo-data/pipelines.ts
Normal file
17
apps/web/src/demo-data/pipelines.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const output = [
|
||||
{
|
||||
id: "demo-pipeline",
|
||||
createdAt: "2023-02-08T10:52:47.877Z",
|
||||
updatedAt: "2023-02-08T10:52:47.877Z",
|
||||
label: "email",
|
||||
type: "emailNotification",
|
||||
events: ["submissionFinished"],
|
||||
formId: "demo-pmf",
|
||||
enabled: true,
|
||||
config: {
|
||||
email: "mail@example.com",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default output;
|
||||
83
apps/web/src/demo-data/pmf-submissions.ts
Normal file
83
apps/web/src/demo-data/pmf-submissions.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
const improvements = [
|
||||
"Please provide a mobile app so I can check my account balance on the go",
|
||||
"Make it possible to archive old transactions",
|
||||
"Make it possible to add a note to a transaction",
|
||||
"A mobile app would be awesome",
|
||||
"I would like to be able to add a note to a transaction",
|
||||
"I would like to be able to archive old transactions",
|
||||
"I think a cool feature would be if I could organize my transactions into categories",
|
||||
];
|
||||
|
||||
const mainBenefits = [
|
||||
"I like that I can see my account balance",
|
||||
"I like that I can see my transactions at a glance",
|
||||
"getting a notification when I receive money",
|
||||
"Seeing all my transactions in one place",
|
||||
"I like that I can see my account balance",
|
||||
"Totally love the notifications when I receive money",
|
||||
"The best is that I can get an overview of all my transactions",
|
||||
"Love the notifications when I receive money",
|
||||
"The notifications when I receive money are great",
|
||||
];
|
||||
|
||||
const userSegments = ["founder", "executive", "productManager", "productOwner", "softwareEngineer"];
|
||||
|
||||
const disappointments = [
|
||||
"veryDisappointed",
|
||||
"veryDisappointed",
|
||||
"veryDisappointed",
|
||||
"somewhatDisappointed",
|
||||
"somewhatDisappointed",
|
||||
"notDisappointed",
|
||||
];
|
||||
|
||||
const selfSegmentations = [
|
||||
"Founders",
|
||||
"Executives",
|
||||
"Product Managers",
|
||||
"Product Owners",
|
||||
"Software Engineers",
|
||||
"Designers",
|
||||
"Other founders",
|
||||
"Other executives",
|
||||
"Other product managers",
|
||||
"Other product owners",
|
||||
"My befriended software engineers",
|
||||
"My befriended designers",
|
||||
"My befriended founders",
|
||||
"I think other founders would like this",
|
||||
"I think other executives would like this",
|
||||
"I think other product managers would like this",
|
||||
];
|
||||
|
||||
export const getPmfSubmissions = () => {
|
||||
const submissions = [];
|
||||
for (let i = 0; i < 28; i++) {
|
||||
submissions.push({
|
||||
id: `demo-pmf-submission-${i}`,
|
||||
createdAt: "2023-02-08T11:04:04.084Z",
|
||||
updatedAt: "2023-02-08T11:04:09.752Z",
|
||||
finished: true,
|
||||
archived: false,
|
||||
formId: "demo-pmf",
|
||||
customerEmail: "user@example.com",
|
||||
customerOrganisationId: "demo-organisation",
|
||||
data: {
|
||||
improvement: getRandomItem(improvements),
|
||||
mainBenefit: getRandomItem(mainBenefits),
|
||||
userSegment: getRandomItem(userSegments),
|
||||
disappointment: getRandomItem(disappointments),
|
||||
selfSegmentation: getRandomItem(selfSegmentations),
|
||||
},
|
||||
meta: {
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
||||
},
|
||||
});
|
||||
}
|
||||
return submissions;
|
||||
};
|
||||
|
||||
function getRandomItem(items) {
|
||||
return items[Math.floor(Math.random() * items.length)];
|
||||
}
|
||||
20
apps/web/src/lib/demo.ts
Normal file
20
apps/web/src/lib/demo.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const demoEndpoints = {
|
||||
"/api/organisations/demo-organisation/forms/demo-pmf": {
|
||||
file: "forms-demo-pmf.ts",
|
||||
},
|
||||
"/api/organisations/demo-organisation/forms/demo-pmf/submissions": {
|
||||
file: "forms-demo-pmf-submissions.ts",
|
||||
},
|
||||
"/api/organisations/demo-organisation/forms/demo-pmf/pipelines": {
|
||||
file: "pipelines.ts",
|
||||
},
|
||||
"/api/organisations/demo-organisation/forms/demo-pmf/pipelines/demo-pipeline": {
|
||||
file: "pipelines-demo-pipeline.ts",
|
||||
},
|
||||
"/api/organisations/demo-organisation/customers": {
|
||||
file: "customers.ts",
|
||||
},
|
||||
"/api/organisations/demo-organisation/customers/user@example.com": {
|
||||
file: "customers-demo-customer.ts",
|
||||
},
|
||||
};
|
||||
@@ -2,8 +2,14 @@ import crypto from "crypto";
|
||||
import intlFormat from "date-fns/intlFormat";
|
||||
import { formatDistance } from "date-fns";
|
||||
import platform from "platform";
|
||||
import { demoEndpoints } from "./demo";
|
||||
|
||||
export const fetcher = async (url) => {
|
||||
if (url in demoEndpoints) {
|
||||
const { file } = demoEndpoints[url];
|
||||
const { default: data } = await import(`../demo-data/${file}`);
|
||||
return data;
|
||||
}
|
||||
const res = await fetch(url);
|
||||
|
||||
// If the status code is not in the range 200-299,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import SingleCustomerPage from "@/components/customers/SingleCustomerPage";
|
||||
import LayoutDemo from "@/components/layout/LayoutDemo";
|
||||
|
||||
export default function Demo() {
|
||||
return (
|
||||
<LayoutDemo>
|
||||
<SingleCustomerPage />
|
||||
</LayoutDemo>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import PMFPage from "@/components/forms/pmf/PMFPage";
|
||||
import LayoutDemo from "@/components/layout/LayoutDemo";
|
||||
|
||||
export default function Demo() {
|
||||
return (
|
||||
<LayoutDemo>
|
||||
<PMFPage />
|
||||
</LayoutDemo>
|
||||
);
|
||||
}
|
||||
@@ -70,7 +70,7 @@ function FbPie({ color, submissions, schema, fieldName }: Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PieChart width={400} height={250}>
|
||||
<PieChart width={500} height={250}>
|
||||
{/* <Pie dataKey="value" fill={color || "#00C4B8"} /> */}
|
||||
<Pie
|
||||
data={data}
|
||||
@@ -92,9 +92,14 @@ function FbPie({ color, submissions, schema, fieldName }: Props) {
|
||||
fontSize={12}
|
||||
textAnchor={x > cx ? "start" : "end"}
|
||||
dominantBaseline="central">
|
||||
{/*
|
||||
<tspan>
|
||||
{/*
|
||||
// @ts-ignore */}
|
||||
{data[index].name} ({Math.round((value / data.length) * 100)}%)
|
||||
{data[index].name}
|
||||
</tspan>
|
||||
<tspan dy="20" dx="-38">
|
||||
({Math.round((value / submissions.length) * 100)}%)
|
||||
</tspan>
|
||||
</text>
|
||||
);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user