mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-22 19:39:01 -05:00
Merge branch 'main' into surveyBg
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
<div id="top"></div>
|
||||
|
||||
[<img src="ph.png">](https://www.producthunt.com/posts/formbricks)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://formbricks.com">
|
||||
<img width="120" alt="Open Source Experience Management Solution Qualtrics Alternative Logo" src="https://github.com/formbricks/formbricks/assets/72809645/0086704f-bee7-4d38-9cc8-fa42ee59e004">
|
||||
@@ -6,7 +9,7 @@
|
||||
<h3 align="center">Formbricks</h3>
|
||||
|
||||
<p align="center">
|
||||
The Open Source Survey & Experience Management solution for fast-growing companies
|
||||
The Open Source Survey Toolbox
|
||||
<br />
|
||||
<a href="https://formbricks.com/">Website</a> | <a href="https://formbricks.com/discord">Join Discord community</a>
|
||||
</p>
|
||||
@@ -34,14 +37,6 @@
|
||||
<a href="https://trendshift.io/repositories/2570" target="_blank"><img src="https://trendshift.io/api/badge/repositories/2570" alt="Trendshift Badge for formbricks/formbricks" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
<img width="1527" alt="formtribe hackathon" src="https://github.com/formbricks/formbricks/assets/72809645/addc3a5b-421c-4c8d-8be2-eedf087100ed">
|
||||
|
||||
## 🔥 The FormTribe Hackathon is on!
|
||||
|
||||
To celebrate Hacktoberfest, we've launched our FormTribe hackathon. Write code or perform non-code side quests to collect points and increase your chances of winning the MacBook Air M2!
|
||||
|
||||
**Join the lottery with a [single tweet!](https://formtribe.com). All info on [formtribe.com](https://formtribe.com)**
|
||||
|
||||
## ✨ About Formbricks
|
||||
|
||||
<img width="1527" alt="formbricks-sneak" src="https://github-production-user-asset-6210df.s3.amazonaws.com/675065/249441967-ccb89ea3-82b4-4bf2-8d2c-528721ec313b.png">
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import HackIconGold from "@/images/formtribe/hack-icon-gold.svg";
|
||||
import PHIcon from "@/images/formtribe/ph-logo.png";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export const GitHubSponsorship: React.FC = () => {
|
||||
return (
|
||||
<div className="mx-4 my-4 mb-12 mt-12 rounded-xl bg-gradient-to-br from-slate-100 to-slate-200 px-4 py-8 dark:from-slate-800 dark:via-slate-800 dark:to-slate-700 sm:px-6 sm:pb-12 sm:pt-8 md:max-w-none lg:mt-6 lg:px-8 lg:pt-8">
|
||||
<style jsx>{`
|
||||
@media (min-width: 426px);
|
||||
`}</style>
|
||||
<div className="right-24 lg:absolute">
|
||||
<Link href="https://www.producthunt.com/posts/formbricks" target="_blank">
|
||||
<div className="my-12 grid w-full grid-cols-3 rounded-2xl border border-[#ff6154] bg-gradient-to-br from-slate-100 to-slate-200 p-12 transition-all hover:scale-105 dark:from-slate-800 dark:via-slate-800 dark:to-slate-700">
|
||||
{/* <Image
|
||||
src={GitHubMarkDark}
|
||||
alt="GitHub Sponsors Formbricks badge"
|
||||
@@ -23,20 +20,28 @@ export const GitHubSponsorship: React.FC = () => {
|
||||
height={100}
|
||||
className="mr-12 hidden dark:block md:mr-4"
|
||||
/> */}
|
||||
<Image src={HackIconGold} alt="Hacktober Icon Gold" width={100} className="mr-12 md:mr-4" />
|
||||
|
||||
<div className="col-span-2">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200 lg:text-2xl">
|
||||
We are live on ProductHunt today 🚀
|
||||
</h2>
|
||||
<p className="lg:text-md mt-2 max-w-3xl text-slate-500 dark:text-slate-400">
|
||||
Support our open source project with an upvote and comment.
|
||||
<span>
|
||||
<Link
|
||||
href="https://www.producthunt.com/posts/formbricks"
|
||||
className="ml-2 underline decoration-[#ff6154] underline-offset-4"
|
||||
target="_blank">
|
||||
View launch post.
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-end">
|
||||
<Image src={PHIcon} alt="Product Hunt Logo" width={80} className="" />
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="mt-4 text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200 lg:text-2xl">
|
||||
The FormTribe goes Hacktoberfest 🥨
|
||||
</h2>
|
||||
<p className="lg:text-md mt-4 max-w-3xl text-slate-500 dark:text-slate-400">
|
||||
Write code, win a Mac! We're running a Hacktoberfest community Hackathon:
|
||||
<span>
|
||||
<Link href="/formtribe" className="decoration-brand-dark ml-2 underline underline-offset-4">
|
||||
Find out more.
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,30 +20,26 @@ export const Hero: React.FC = ({}) => {
|
||||
<div className="relative">
|
||||
<div className="px-4 pb-20 pt-16 text-center sm:px-6 lg:px-8 lg:pb-32 lg:pt-20">
|
||||
<a
|
||||
href="https://formbricks.com/formtribe"
|
||||
href="https://www.producthunt.com/posts/formbricks"
|
||||
target="_blank"
|
||||
className="border-brand-dark xs:text-sm animate-bounce rounded-full border px-4 py-1.5 text-xs text-slate-500 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800">
|
||||
The FormTribe Hackathon is on 🔥
|
||||
Support us on Product Hunt 🚀
|
||||
<ChevronRightIcon className="inline h-5 w-5 text-slate-300" />
|
||||
</a>
|
||||
<h1 className="mt-10 text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-4xl md:text-5xl">
|
||||
<span className="xl:inline">Open-source Experience Management</span>
|
||||
<span className="xl:inline">The Open Source Survey Suite</span>
|
||||
</h1>
|
||||
|
||||
<p className="xs:max-w-none mx-auto mt-3 max-w-xs text-base text-slate-500 dark:text-slate-400 sm:text-lg md:mt-5 md:text-xl">
|
||||
Understand what customers think & feel about your product.
|
||||
<br />
|
||||
<span className="hidden md:block">
|
||||
Natively integrate user research with minimal dev attention,{" "}
|
||||
<span className="decoration-brand-dark underline underline-offset-4">privacy-first.</span>
|
||||
</span>
|
||||
Run link surveys, in-app surveys and email surveys in one app —{" "}
|
||||
<span className="decoration-brand-dark underline underline-offset-4">all privacy-first.</span>
|
||||
</p>
|
||||
|
||||
<div className="mx-auto mt-5 max-w-3xl items-center px-4 sm:flex sm:justify-center md:mt-8 md:space-x-8 md:px-0">
|
||||
<div className="mx-auto mt-5 max-w-2xl items-center px-4 sm:flex sm:justify-center md:mt-6 md:space-x-8 md:px-0">
|
||||
<p className="hidden whitespace-nowrap pt-3 text-xs text-slate-400 dark:text-slate-500 md:block">
|
||||
Trusted by
|
||||
</p>
|
||||
<div className="grid grid-cols-4 items-center gap-5 pt-2 md:gap-8">
|
||||
<div className="grid grid-cols-4 items-center gap-6 pt-2 md:gap-8">
|
||||
<Image
|
||||
src={CalLogoLight}
|
||||
alt="Cal Logo"
|
||||
@@ -68,12 +64,6 @@ export const Hero: React.FC = ({}) => {
|
||||
className="hidden rounded-lg pb-1 hover:opacity-100 dark:block md:opacity-50"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={ClovyrLogo}
|
||||
alt="Clovyr Logo"
|
||||
className="rounded-lg pb-1 hover:opacity-100 md:opacity-50"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={NILogoDark}
|
||||
alt="Neverinstall Logo"
|
||||
@@ -86,6 +76,12 @@ export const Hero: React.FC = ({}) => {
|
||||
className="hidden pb-1 hover:opacity-100 dark:block md:opacity-50"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={ClovyrLogo}
|
||||
alt="Clovyr Logo"
|
||||
className="rounded-lg pb-1 hover:opacity-100 md:opacity-50"
|
||||
width={200}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden pt-10 md:block">
|
||||
@@ -102,10 +98,10 @@ export const Hero: React.FC = ({}) => {
|
||||
variant="secondary"
|
||||
className="px-6"
|
||||
onClick={() => {
|
||||
router.push("/demo");
|
||||
plausible("Hero_CTA_LaunchDemo");
|
||||
router.push("https://www.producthunt.com/posts/formbricks");
|
||||
/* plausible("Hero_CTA_LaunchDemo"); */
|
||||
}}>
|
||||
Live demo
|
||||
Support Launch 🚀
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -120,9 +120,9 @@ export default function Header() {
|
||||
: "relative";
|
||||
return (
|
||||
<Popover className={`${stickyNavClass}`} as="header">
|
||||
<a href="https://www.producthunt.com/products/formbricks" target="_blank">
|
||||
<a href="https://www.producthunt.com/posts/formbricks" target="_blank">
|
||||
<div className="hidden bg-[#ff6154] px-4 py-2 text-center text-sm text-white md:block lg:py-0">
|
||||
We're launching soon on Product Hunt - get notified 🚀
|
||||
We're live on Product Hunt - Show your support for Open Source 🚀
|
||||
</div>
|
||||
</a>
|
||||
<div className="flex items-center justify-between px-4 py-6 sm:px-6 md:justify-start ">
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Slider } from "@/components/shared/Slider";
|
||||
import { useState } from "react";
|
||||
|
||||
const ProductItem = ({ label, usersCount, price, onSliderChange }) => (
|
||||
const LinkSurveySlider = ({ label, usersCount, price, onSliderChange }) => (
|
||||
<div className="mt-12">
|
||||
<div className="mb-2 flex items-center gap-x-2 md:gap-x-4">
|
||||
<div className="md:text-md w-3/6 text-left text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{label}
|
||||
</div>
|
||||
<div className="md:text-md w-2/6 text-center text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{Math.round(usersCount).toLocaleString()} MTU
|
||||
{Math.round(usersCount).toLocaleString()} Submissions
|
||||
</div>
|
||||
<div className="md:text-md flex w-1/6 items-center justify-end text-center text-sm font-medium text-slate-700 dark:text-slate-200 md:justify-center">
|
||||
<span>${price.toFixed(2)}</span>
|
||||
@@ -34,6 +34,72 @@ const ProductItem = ({ label, usersCount, price, onSliderChange }) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
const InAppSlider = ({ label, usersCount, price, onSliderChange }) => (
|
||||
<div className="mt-12">
|
||||
<div className="mb-2 flex items-center gap-x-2 md:gap-x-4">
|
||||
<div className="md:text-md w-3/6 text-left text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{label}
|
||||
</div>
|
||||
<div className="md:text-md w-2/6 text-center text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{Math.round(usersCount).toLocaleString()} Submissions
|
||||
</div>
|
||||
<div className="md:text-md flex w-1/6 items-center justify-end text-center text-sm font-medium text-slate-700 dark:text-slate-200 md:justify-center">
|
||||
<span>${price.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-2 w-5/6 pr-8 md:pr-20">
|
||||
<Slider
|
||||
className="slider-class"
|
||||
defaultValue={[Math.log10(250)]}
|
||||
min={3}
|
||||
max={6}
|
||||
step={0.01}
|
||||
onValueChange={onSliderChange}
|
||||
/>
|
||||
<div className="mt-2 flex items-center justify-between text-sm">
|
||||
{[3, 4, 5, 6].map((mark) => (
|
||||
<span key={mark} className="text-slate-600 dark:text-slate-300">
|
||||
{mark === 3 ? "1K" : mark === 4 ? "10K" : mark === 5 ? "100K" : "1M"}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const UserSegmentationSlider = ({ label, usersCount, price, onSliderChange }) => (
|
||||
<div className="mt-12">
|
||||
<div className="mb-2 flex items-center gap-x-2 md:gap-x-4">
|
||||
<div className="md:text-md w-3/6 text-left text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{label}
|
||||
</div>
|
||||
<div className="md:text-md w-2/6 text-center text-sm font-medium text-slate-700 dark:text-slate-200">
|
||||
{Math.round(usersCount).toLocaleString()} Submissions
|
||||
</div>
|
||||
<div className="md:text-md flex w-1/6 items-center justify-end text-center text-sm font-medium text-slate-700 dark:text-slate-200 md:justify-center">
|
||||
<span>${price.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-2 w-5/6 pr-8 md:pr-20">
|
||||
<Slider
|
||||
className="slider-class"
|
||||
defaultValue={[Math.log10(250)]}
|
||||
min={3}
|
||||
max={6}
|
||||
step={0.01}
|
||||
onValueChange={onSliderChange}
|
||||
/>
|
||||
<div className="mt-2 flex items-center justify-between text-sm">
|
||||
{[3, 4, 5, 6].map((mark) => (
|
||||
<span key={mark} className="text-slate-600 dark:text-slate-300">
|
||||
{mark === 3 ? "1K" : mark === 4 ? "10K" : mark === 5 ? "100K" : "1M"}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Headers = () => (
|
||||
<div className="mb-4 flex justify-between">
|
||||
<h3 className="text-base font-semibold text-slate-700 dark:text-slate-200 md:text-lg">Product</h3>
|
||||
@@ -89,16 +155,7 @@ export const PricingCalculator = () => {
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<ProductItem
|
||||
label="In Product Surveys"
|
||||
usersCount={usersCountForInProductSlider}
|
||||
price={productSurveysPrice}
|
||||
onSliderChange={(value) => setInProductSlider(value[0])}
|
||||
/>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<ProductItem
|
||||
<LinkSurveySlider
|
||||
label="Link Surveys"
|
||||
usersCount={transformToLog(linkSlider)}
|
||||
price={0}
|
||||
@@ -107,6 +164,22 @@ export const PricingCalculator = () => {
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<InAppSlider
|
||||
label="Website and In-App Surveys"
|
||||
usersCount={transformToLog(linkSlider)}
|
||||
price={0}
|
||||
onSliderChange={(value) => setLinkSlider(value[0])}
|
||||
/>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<UserSegmentationSlider
|
||||
label="User Segmentation"
|
||||
usersCount={usersCountForInProductSlider}
|
||||
price={productSurveysPrice}
|
||||
onSliderChange={(value) => setInProductSlider(value[0])}
|
||||
/>
|
||||
|
||||
<MonthlyEstimate price={productSurveysPrice} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,35 +1,14 @@
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui/Tooltip";
|
||||
import { CheckIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@radix-ui/react-tooltip";
|
||||
|
||||
interface SpecialRow {
|
||||
title: string | JSX.Element;
|
||||
free: string | JSX.Element;
|
||||
paid: string | JSX.Element;
|
||||
}
|
||||
|
||||
interface PricingRow {
|
||||
name: string;
|
||||
free: string | boolean;
|
||||
paid: string | boolean;
|
||||
comingSoon?: boolean;
|
||||
addOnText?: string;
|
||||
}
|
||||
|
||||
export const PricingTable = ({
|
||||
leadRow,
|
||||
pricing,
|
||||
endRow,
|
||||
}: {
|
||||
leadRow: SpecialRow;
|
||||
pricing: PricingRow[];
|
||||
endRow: SpecialRow;
|
||||
}) => {
|
||||
export const PricingTable = ({ leadRow, pricing, endRow }) => {
|
||||
return (
|
||||
<div className="grid grid-cols-1 px-4 md:gap-4 md:px-16 ">
|
||||
<div className="rounded-xl px-4 md:px-12">
|
||||
<div className="flex items-center gap-x-4">
|
||||
<div className="w-1/3 text-left font-semibold text-slate-700 dark:text-slate-200 md:text-xl">
|
||||
{leadRow.title}
|
||||
<span className="pl-2 text-sm font-normal text-slate-600">{leadRow.comparison}</span>
|
||||
</div>
|
||||
<div
|
||||
className="flex w-1/3 items-center justify-center text-center text-sm font-semibold
|
||||
@@ -49,12 +28,12 @@ export const PricingTable = ({
|
||||
<div className="w-1/3 text-left text-sm text-slate-700 dark:text-slate-200 md:text-base">
|
||||
{feature.name}
|
||||
{feature.addOnText && (
|
||||
<span className=" mx-2 bg-teal-100 p-1 text-xs text-slate-400 dark:bg-slate-700 dark:text-teal-500">
|
||||
<span className=" mx-3 rounded-full bg-emerald-200 px-2 text-xs text-slate-800 dark:bg-slate-700 dark:text-teal-500">
|
||||
Addon
|
||||
</span>
|
||||
)}
|
||||
{feature.comingSoon && (
|
||||
<span className=" mx-2 bg-blue-100 p-1 text-xs text-slate-400 dark:bg-slate-700 dark:text-teal-500">
|
||||
<span className="mx-3 rounded-full bg-slate-200 px-2 text-xs text-slate-800 dark:bg-slate-700 dark:text-teal-500">
|
||||
coming soon
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -132,7 +132,7 @@ const nextConfig = {
|
||||
},
|
||||
{
|
||||
source: "/launch",
|
||||
destination: "https://www.producthunt.com/products/formbricks",
|
||||
destination: "https://www.producthunt.com/posts/formbricks",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -663,7 +663,7 @@ export default function FormTribeHackathon() {
|
||||
|
||||
<div className="px-4 pb-16 pt-16 text-center sm:px-6 lg:px-8 lg:pb-32 lg:pt-20">
|
||||
<a
|
||||
href="https://www.producthunt.com/products/formbricks"
|
||||
href="https://www.producthunt.com/posts/formbricks"
|
||||
target="_blank"
|
||||
className=" rounded-full border bg-slate-100 px-4 py-1.5 text-sm text-slate-500 hover:scale-105">
|
||||
Don't miss the launch! Get notified 🚀
|
||||
@@ -1126,7 +1126,7 @@ const Breaker = ({ icon, title }) => {
|
||||
<div className="mt-4 flex items-center justify-center">
|
||||
<Image src={PHLogo} alt="ph-logo" className="mr-2 h-8 w-8" />
|
||||
<a
|
||||
href="https://www.producthunt.com/products/formbricks"
|
||||
href="https://www.producthunt.com/posts/formbricks"
|
||||
target="_blank"
|
||||
className="text-sm font-semibold text-[#ff6154]">
|
||||
Get notified on Product Hunt.
|
||||
|
||||
@@ -2,52 +2,77 @@ import HeroTitle from "@/components/shared/HeroTitle";
|
||||
import Layout from "@/components/shared/Layout";
|
||||
import { OpenSourceInfo } from "@/components/shared/OpenSourceInfo";
|
||||
import { GetStartedWithPricing } from "@/components/shared/PricingGetStarted";
|
||||
import { PricingCalculator } from "../components/shared/PricingCalculator";
|
||||
import { PricingTable } from "../components/shared/PricingTable";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
|
||||
const inProductSurveys = {
|
||||
leadRow: {
|
||||
title: "In-Product Surveys",
|
||||
title: "Website and In-App Surveys",
|
||||
comparison: "like HotJar",
|
||||
free: (
|
||||
<div>
|
||||
<span>5000 tracked users</span> <span className="text-slate-400">/mo</span>{" "}
|
||||
<span>250 Submissions</span> <span className="text-slate-400">/ Month</span>{" "}
|
||||
</div>
|
||||
),
|
||||
paid: "Unlimited",
|
||||
},
|
||||
features: [
|
||||
{ name: "Unlimited Surveys", free: true, paid: true },
|
||||
{ name: "Granular Targeting", free: true, paid: true },
|
||||
{ name: "30+ Templates", free: true, paid: true },
|
||||
{ name: "API Access", free: true, paid: true },
|
||||
{ name: "Third-Party Integrations", free: true, paid: true },
|
||||
{ name: "Unlimited Team Members", free: true, paid: true },
|
||||
{ name: "Unlimited Responses per Survey", free: true, paid: true },
|
||||
{ name: "Team Role Management", free: false, paid: true },
|
||||
{ name: "API Access", free: true, paid: true },
|
||||
{ name: "30+ Templates", free: true, paid: true },
|
||||
{ name: "Unlimited Responses per Survey", free: false, paid: true },
|
||||
{ name: "Team Role Management", free: false, paid: true, comingSoon: true },
|
||||
{ name: "Advanced User Targeting", free: false, paid: true, comingSoon: true },
|
||||
{ name: "Multi Language Surveys", free: false, paid: true, comingSoon: true },
|
||||
|
||||
{
|
||||
name: "Custom URL for Link Surveys",
|
||||
free: "10$/mo",
|
||||
paid: "10$/mo",
|
||||
addOnText: "Free if you self-host",
|
||||
},
|
||||
{
|
||||
name: "Remove Formbricks Branding",
|
||||
free: "10$/mo",
|
||||
paid: "10$/mo",
|
||||
addOnText: "Free if you self-host",
|
||||
},
|
||||
],
|
||||
endRow: {
|
||||
title: "In-Product Surveys Pricing",
|
||||
title: "Website and In-App Surveys",
|
||||
free: "Free",
|
||||
paid: (
|
||||
<div>
|
||||
<span>Free</span> <span className="text-slate-400">up to 5000 tracked users/mo, then </span>
|
||||
<span>$0.005</span>
|
||||
<span className="text-slate-400"> / tracked user</span>
|
||||
<span>Free</span>{" "}
|
||||
<span className="text-slate-400">
|
||||
up to 250 submissions / month <br />
|
||||
then{" "}
|
||||
</span>
|
||||
<span>$0.15</span>
|
||||
<span className="text-slate-400"> / submission</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
const userSegmentation = {
|
||||
leadRow: {
|
||||
title: "User Segmentation",
|
||||
comparison: "like Segment",
|
||||
free: (
|
||||
<div>
|
||||
<span>2500 Users</span> <span className="text-slate-400">/ Month</span>{" "}
|
||||
</div>
|
||||
),
|
||||
paid: "Unlimited",
|
||||
},
|
||||
features: [
|
||||
{ name: "Identify Users", free: true, paid: true },
|
||||
{ name: "Collect Events", free: true, paid: true },
|
||||
{ name: "Collect Attributes", free: true, paid: true },
|
||||
{ name: "Advanced User Targeting", free: false, paid: true, comingSoon: true },
|
||||
{ name: "Reusable Segments", free: false, paid: true, comingSoon: true },
|
||||
],
|
||||
endRow: {
|
||||
title: "User Segmentation like Segment",
|
||||
free: "Free",
|
||||
paid: (
|
||||
<div>
|
||||
<span>Free</span>{" "}
|
||||
<span className="text-slate-400">
|
||||
up to 2500 users / month <br />
|
||||
then{" "}
|
||||
</span>
|
||||
<span>$0.01</span>
|
||||
<span className="text-slate-400"> / user</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
@@ -56,6 +81,7 @@ const inProductSurveys = {
|
||||
const linkSurveys = {
|
||||
leadRow: {
|
||||
title: "Link Surveys",
|
||||
comparison: "like Typeform",
|
||||
free: <span>Unlimited</span>,
|
||||
paid: "Unlimited",
|
||||
},
|
||||
@@ -64,20 +90,22 @@ const linkSurveys = {
|
||||
{ name: "Unlimited Surveys", free: true, paid: true },
|
||||
{ name: "Unlimited Responses", free: true, paid: true },
|
||||
{ name: "Partial Responses", free: true, paid: true },
|
||||
{ name: "⚙️ URL Shortener", free: true, paid: true },
|
||||
{ name: "⚙️ Recall Information", free: true, paid: true },
|
||||
{ name: "⚙️ Hidden Field Questions", free: true, paid: true },
|
||||
{ name: "⚙️ Time to Complete Metadata", free: true, paid: true },
|
||||
{ name: "⚙️ File Upload", free: true, paid: true },
|
||||
{ name: "⚙️ Signature Question", free: true, paid: true },
|
||||
{ name: "⚙️ Question Grouping", free: true, paid: true },
|
||||
{ name: "⚙️ Add Media to Questions", free: true, paid: true },
|
||||
{ name: "Multi-media Backgrounds", free: true, paid: true },
|
||||
{ name: "File Upload", free: true, paid: true },
|
||||
{ name: "Hidden Fields", free: true, paid: true },
|
||||
{ name: "Single Use Survey Links", free: true, paid: true },
|
||||
{ name: "Pin-protected Surveys", free: true, paid: true },
|
||||
{ name: "Custom Styling", free: true, paid: true, comingSoon: true },
|
||||
{ name: "Recall Information", free: true, paid: true, comingSoon: true },
|
||||
{ name: "Collect Payments, Signatures and Appointments", free: true, paid: true, comingSoon: true },
|
||||
{ name: "Custom URL", free: false, paid: true },
|
||||
{ name: "Remove Formbricks Branding", free: false, paid: true },
|
||||
],
|
||||
|
||||
endRow: {
|
||||
title: "Link Surveys Pricing",
|
||||
free: "Free",
|
||||
paid: "Free",
|
||||
paid: "$30 / month",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -90,9 +118,11 @@ const integrations = {
|
||||
features: [
|
||||
{ name: "Webhooks", free: true, paid: true },
|
||||
{ name: "Zapier", free: true, paid: true },
|
||||
{ name: "Google Sheets", free: true, paid: true },
|
||||
{ name: "Notion", free: true, paid: true },
|
||||
{ name: "n8n", free: true, paid: true },
|
||||
{ name: "Make", free: true, paid: true },
|
||||
{ name: "Google Sheets", free: true, paid: true },
|
||||
{ name: "Airtable", free: true, paid: true },
|
||||
],
|
||||
endRow: {
|
||||
title: "Integrations Pricing",
|
||||
@@ -105,27 +135,73 @@ const PricingPage = () => {
|
||||
return (
|
||||
<Layout
|
||||
title="Pricing | Formbricks Open Source Experience Management"
|
||||
description="Choose what's best for you! All our plans start free.">
|
||||
description="All our plans start free - choose what's best for you!">
|
||||
<div className="relative isolate mx-5 mt-8 overflow-hidden rounded-lg bg-slate-50 px-3 pt-4 shadow-2xl dark:bg-slate-800 sm:px-8 md:pt-8 lg:gap-x-10 lg:px-12 lg:pt-0">
|
||||
<svg
|
||||
viewBox="0 0 1024 1024"
|
||||
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
|
||||
aria-hidden="true">
|
||||
<circle
|
||||
cx={512}
|
||||
cy={512}
|
||||
r={512}
|
||||
fill="url(#759c1415-0410-454c-8f7c-9a820de03641)"
|
||||
fillOpacity="0.7"
|
||||
/>
|
||||
<defs>
|
||||
<radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
|
||||
<stop stopColor="#00E6CA" />
|
||||
<stop offset={0} stopColor="#00C4B8" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div className="mx-auto w-full text-center lg:mx-0 lg:flex-auto lg:py-8 lg:text-left">
|
||||
<h2 className="text-2xl font-bold text-slate-800 dark:text-slate-50 sm:text-3xl">
|
||||
Launch Special:
|
||||
<br /> Go Unlimited! Forever!
|
||||
</h2>
|
||||
<p className="text-md mt-6 leading-8 text-slate-700 dark:text-slate-50">
|
||||
Get access to all pro features and unlimited responses + identified users for a flat fee of{" "}
|
||||
<b>only $99/month.</b>
|
||||
<br /> <br />
|
||||
<span className="text-slate-400 dark:text-slate-300">
|
||||
This deal ends on 31st of October 2023 at 11:59 PM PST.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-8 mt-2 items-center justify-center">
|
||||
<Button className="w-full justify-center py-2 shadow-sm" href="https://app.formbricks.com/">
|
||||
Get Started
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HeroTitle
|
||||
headingPt1=""
|
||||
headingTeal="Pricing"
|
||||
subheading="Choose what's best for you! All our plans start free."
|
||||
subheading="All our plans start free - choose what's best for you!"
|
||||
/>
|
||||
<div className="space-y-24">
|
||||
<div>
|
||||
<GetStartedWithPricing showDetailed={true} />
|
||||
|
||||
<PricingTable
|
||||
leadRow={inProductSurveys.leadRow}
|
||||
pricing={inProductSurveys.features}
|
||||
endRow={inProductSurveys.endRow}
|
||||
leadRow={linkSurveys.leadRow}
|
||||
pricing={linkSurveys.features}
|
||||
endRow={linkSurveys.endRow}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PricingTable
|
||||
leadRow={linkSurveys.leadRow}
|
||||
pricing={linkSurveys.features}
|
||||
endRow={linkSurveys.endRow}
|
||||
leadRow={inProductSurveys.leadRow}
|
||||
pricing={inProductSurveys.features}
|
||||
endRow={inProductSurveys.endRow}
|
||||
/>
|
||||
|
||||
<PricingTable
|
||||
leadRow={userSegmentation.leadRow}
|
||||
pricing={userSegmentation.features}
|
||||
endRow={userSegmentation.endRow}
|
||||
/>
|
||||
|
||||
<PricingTable
|
||||
@@ -134,7 +210,7 @@ const PricingPage = () => {
|
||||
endRow={integrations.endRow}
|
||||
/>
|
||||
<div>
|
||||
<PricingCalculator />
|
||||
{/* <PricingCalculator /> */}
|
||||
<OpenSourceInfo />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { transformErrorToDetails } from "@/app/lib/api/validator";
|
||||
import { createAttributeClass, getAttributeClassByName } from "@formbricks/lib/attributeClass/service";
|
||||
import { personCache } from "@formbricks/lib/person/cache";
|
||||
import { getPerson, updatePersonAttribute } from "@formbricks/lib/person/service";
|
||||
import { surveyCache } from "@formbricks/lib/survey/cache";
|
||||
import { ZJsPeopleAttributeInput } from "@formbricks/types/js";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
@@ -47,15 +48,19 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
}
|
||||
|
||||
// upsert attribute (update or create)
|
||||
updatePersonAttribute(personId, attributeClass.id, value);
|
||||
|
||||
const state = await getUpdatedState(environmentId, personId, sessionId);
|
||||
await updatePersonAttribute(personId, attributeClass.id, value);
|
||||
|
||||
personCache.revalidate({
|
||||
id: state.person.id,
|
||||
id: personId,
|
||||
environmentId,
|
||||
});
|
||||
|
||||
surveyCache.revalidate({
|
||||
environmentId,
|
||||
});
|
||||
|
||||
const state = await getUpdatedState(environmentId, personId, sessionId);
|
||||
|
||||
return responses.successResponse({ ...state }, true);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -5,6 +5,7 @@ import { prisma } from "@formbricks/database";
|
||||
import { getDisplaysByPersonId, updateDisplay } from "@formbricks/lib/display/service";
|
||||
import { personCache } from "@formbricks/lib/person/cache";
|
||||
import { deletePerson, selectPerson, transformPrismaPerson } from "@formbricks/lib/person/service";
|
||||
import { surveyCache } from "@formbricks/lib/survey/cache";
|
||||
import { ZJsPeopleUserIdInput } from "@formbricks/types/js";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
@@ -102,13 +103,17 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
|
||||
const transformedPerson = transformPrismaPerson(returnedPerson);
|
||||
|
||||
const state = await getUpdatedState(environmentId, transformedPerson.id, sessionId);
|
||||
|
||||
personCache.revalidate({
|
||||
id: transformedPerson.id,
|
||||
environmentId: environmentId,
|
||||
});
|
||||
|
||||
surveyCache.revalidate({
|
||||
environmentId,
|
||||
});
|
||||
|
||||
const state = await getUpdatedState(environmentId, transformedPerson.id, sessionId);
|
||||
|
||||
return responses.successResponse({ ...state }, true);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
Reference in New Issue
Block a user