diff --git a/apps/formbricks-com/components/shared/Header.tsx b/apps/formbricks-com/components/shared/Header.tsx index 76b57ee726..65ef9c71c9 100644 --- a/apps/formbricks-com/components/shared/Header.tsx +++ b/apps/formbricks-com/components/shared/Header.tsx @@ -250,7 +250,7 @@ export default function Header() { */} Pricing diff --git a/apps/formbricks-com/components/shared/OpenSourceInfo.tsx b/apps/formbricks-com/components/shared/OpenSourceInfo.tsx new file mode 100644 index 0000000000..11df9246c1 --- /dev/null +++ b/apps/formbricks-com/components/shared/OpenSourceInfo.tsx @@ -0,0 +1,35 @@ +import { Button } from "@formbricks/ui"; + +export const OpenSourceInfo = () => { + return ( +
+
+
+

+ Open Source +

+ +

+ Formbricks is an open source project. You can self-host it for free. We provide multiple easy + deployment options as per your customisation needs. We have documented the process of self-hosting + Formbricks on your own server using Docker, Bash Scripting, and Building from Source. +

+
+ + +
+
+
+
+ ); +}; diff --git a/apps/formbricks-com/components/shared/PricingCalculator.tsx b/apps/formbricks-com/components/shared/PricingCalculator.tsx new file mode 100644 index 0000000000..03972ac30f --- /dev/null +++ b/apps/formbricks-com/components/shared/PricingCalculator.tsx @@ -0,0 +1,115 @@ +import { Slider } from "@/components/shared/Slider"; +import { useState } from "react"; + +const ProductItem = ({ label, usersCount, price, onSliderChange }) => ( +
+
+
+ {label} +
+
+ {Math.round(usersCount).toLocaleString()} MTU +
+
+ ${price.toFixed(2)} +
+
+
+ +
+ {[3, 4, 5, 6].map((mark) => ( + + {mark === 3 ? "1K" : mark === 4 ? "10K" : mark === 5 ? "100K" : "1M"} + + ))} +
+
+
+); + +const Headers = () => ( +
+

Product

+

+ Subtotal +

+
+); + +const MonthlyEstimate = ({ price }) => ( +
+ + Monthly estimate: + +
+ + ${price.toFixed(2)} + + + {" "} + / month + +
+
+); + +export const PricingCalculator = () => { + const [inProductSlider, setInProductSlider] = useState(Math.log10(1000)); + const [linkSlider, setLinkSlider] = useState(Math.log10(1000)); + + const transformToLog = (value) => Math.pow(10, value); + + const calculatePrice = (users) => { + if (users <= 5000) { + return 0; + } else { + return users * 0.005; + } + }; + + const usersCountForInProductSlider = transformToLog(inProductSlider); + const productSurveysPrice = calculatePrice(usersCountForInProductSlider); + + return ( +
+

+ Pricing Calculator +

+ +
+
+ + +
+ + setInProductSlider(value[0])} + /> + +
+ + setLinkSlider(value[0])} + /> + +
+ + +
+
+
+ ); +}; diff --git a/apps/formbricks-com/components/shared/PricingGetStarted.tsx b/apps/formbricks-com/components/shared/PricingGetStarted.tsx new file mode 100644 index 0000000000..d7774475d1 --- /dev/null +++ b/apps/formbricks-com/components/shared/PricingGetStarted.tsx @@ -0,0 +1,47 @@ +import { Button } from "@formbricks/ui"; + +export const GetStartedWithPricing = ({ showDetailed }: { showDetailed: boolean }) => { + return ( + <> +
+
+
+

Free

+ + {showDetailed && ( +

+ General free usage on every product. Best for early stage startups and hobbyists +

+ )} + + +
+
+

Paid

+ {showDetailed && ( +

+ Formbricks with the next-generation features, Pay only for the tracked users. +

+ )} + + +
+
+
+ + ); +}; diff --git a/apps/formbricks-com/components/shared/PricingTable.tsx b/apps/formbricks-com/components/shared/PricingTable.tsx new file mode 100644 index 0000000000..54311b1c3a --- /dev/null +++ b/apps/formbricks-com/components/shared/PricingTable.tsx @@ -0,0 +1,103 @@ +import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@formbricks/ui"; +import { CheckIcon, XMarkIcon } from "@heroicons/react/24/outline"; + +export const PricingTable = ({ leadRow, pricing, endRow }) => { + return ( +
+
+
+
+ {leadRow.title} +
+
+ {leadRow.free} +
+ +
+ {leadRow.paid} +
+
+
+ +
+ {pricing.map((feature) => ( +
+
+ {feature.name} + {feature.addOnText && ( + + Addon + + )} +
+
+ {feature.addOnText ? ( + + + + {feature.free} + + +

+ {feature.addOnText} +

+
+
+
+ ) : feature.free ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+
+ {feature.addOnText ? ( + + + + {feature.paid} + + +

+ {feature.addOnText} +

+
+
+
+ ) : feature.paid ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+
+ ))} +
+ +
+
+
+ {endRow.title} +
+
+ {endRow.free} +
+ +
+ {endRow.paid} +
+
+
+
+ ); +}; diff --git a/apps/formbricks-com/components/shared/Slider.tsx b/apps/formbricks-com/components/shared/Slider.tsx new file mode 100644 index 0000000000..07bce61744 --- /dev/null +++ b/apps/formbricks-com/components/shared/Slider.tsx @@ -0,0 +1,24 @@ +"use client"; + +import * as React from "react"; +import * as SliderPrimitive from "@radix-ui/react-slider"; + +import { cn } from "@formbricks/lib/cn"; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export { Slider }; diff --git a/apps/formbricks-com/components/shared/icons/XCircleIcon.jsx b/apps/formbricks-com/components/shared/icons/XCircleIcon.jsx new file mode 100644 index 0000000000..d1573c7733 --- /dev/null +++ b/apps/formbricks-com/components/shared/icons/XCircleIcon.jsx @@ -0,0 +1,13 @@ + + +; diff --git a/apps/formbricks-com/package.json b/apps/formbricks-com/package.json index 1101313dfd..36de8e409a 100644 --- a/apps/formbricks-com/package.json +++ b/apps/formbricks-com/package.json @@ -47,6 +47,8 @@ "node-fetch": "^3.3.2", "prism-react-renderer": "^2.1.0", "prismjs": "^1.29.0", + "@radix-ui/react-slider": "^1.1.2", + "@radix-ui/react-tooltip": "^1.0.6", "react": "18.2.0", "react-dom": "18.2.0", "react-highlight-words": "^0.20.0", diff --git a/apps/formbricks-com/pages/index.tsx b/apps/formbricks-com/pages/index.tsx index c21f7950a1..c4b8bc18dd 100644 --- a/apps/formbricks-com/pages/index.tsx +++ b/apps/formbricks-com/pages/index.tsx @@ -4,7 +4,6 @@ import Features from "@/components/home/Features"; import Highlights from "@/components/home/Highlights"; import BreakerCTA from "@/components/shared/BreakerCTA"; import Steps from "@/components/home/Steps"; -import Pricing from "@/components/shared/Pricing"; import GitHubSponsorship from "@/components/home/GitHubSponsorship"; import BestPractices from "@/components/shared/BestPractices"; @@ -42,7 +41,6 @@ const IndexPage = () => ( href="https://app.formbricks.com/auth/signup" inverted /> - ); diff --git a/apps/formbricks-com/pages/pricing.tsx b/apps/formbricks-com/pages/pricing.tsx new file mode 100644 index 0000000000..b4969a6d6d --- /dev/null +++ b/apps/formbricks-com/pages/pricing.tsx @@ -0,0 +1,147 @@ +import HeroTitle from "@/components/shared/HeroTitle"; +import Layout from "@/components/shared/Layout"; +import { PricingTable } from "../components/shared/PricingTable"; +import { PricingCalculator } from "../components/shared/PricingCalculator"; +import { GetStartedWithPricing } from "@/components/shared/PricingGetStarted"; +import { OpenSourceInfo } from "@/components/shared/OpenSourceInfo"; + +const inProductSurveys = { + leadRow: { + title: "In-Product Surveys", + free: ( +
+ 5000 tracked users /mo{" "} +
+ ), + 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: "Advanced User Targeting", free: false, paid: true }, + { name: "Multi Language", free: false, paid: 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", + free: "Free", + paid: ( +
+ Free up to 5000 tracked users/mo, then + $0.005 + / tracked user +
+ ), + }, +}; + +const linkSurveys = { + leadRow: { + title: "Link Surveys", + free: Unlimited, + paid: "Unlimited", + }, + + features: [ + { name: "Unlimited Surveys", free: true, paid: true }, + { name: "Unlimited Responses", free: true, paid: true }, + { name: "Partial Submissions", 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 }, + ], + + endRow: { + title: "Link Surveys Pricing", + free: "Free", + paid: "Free", + }, +}; + +const integrations = { + leadRow: { + title: "Integrations", + free: Unlimited, + paid: "Unlimited", + }, + features: [ + { name: "Webhooks", free: true, paid: true }, + { name: "Zapier", free: true, paid: true }, + { name: "Google Sheets", free: true, paid: true }, + { name: "n8n", free: true, paid: true }, + { name: "Make", free: true, paid: true }, + ], + endRow: { + title: "Integrations Pricing", + free: "Free", + paid: "Free", + }, +}; + +const PricingPage = () => { + return ( + + + + + + +
+ + +
+ + + +
+ + + + + + +
+ ); +}; + +export default PricingPage; diff --git a/packages/ui/components/icons/CrossMarkIcon.tsx b/packages/ui/components/icons/CrossMarkIcon.tsx index 62b9606985..570eb4190c 100644 --- a/packages/ui/components/icons/CrossMarkIcon.tsx +++ b/packages/ui/components/icons/CrossMarkIcon.tsx @@ -2,7 +2,6 @@ export const CrossMarkIcon: React.FC> = (props) => return ( - 6.6.0' dependencies: eslint: 8.50.0 - eslint-plugin-turbo: 1.8.8(eslint@8.50.0) + eslint-plugin-turbo: 1.10.3(eslint@8.50.0) dev: true /eslint-import-resolver-node@0.3.9: @@ -10740,8 +10797,8 @@ packages: semver: 6.3.1 string.prototype.matchall: 4.0.8 - /eslint-plugin-turbo@1.8.8(eslint@8.50.0): - resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==} + /eslint-plugin-turbo@1.10.3(eslint@8.50.0): + resolution: {integrity: sha512-g3Mnnk7el1FqxHfqbE/MayLvCsYjA/vKmAnUj66kV4AlM7p/EZqdt42NMcMSKtDVEm0w+utQkkzWG2Xsa0Pd/g==} peerDependencies: eslint: '>6.6.0' dependencies: @@ -21866,64 +21923,65 @@ packages: dependencies: safe-buffer: 5.2.1 - /turbo-darwin-64@1.10.13: - resolution: {integrity: sha512-vmngGfa2dlYvX7UFVncsNDMuT4X2KPyPJ2Jj+xvf5nvQnZR/3IeDEGleGVuMi/hRzdinoxwXqgk9flEmAYp0Xw==} + /turbo-darwin-64@1.10.3: + resolution: {integrity: sha512-IIB9IomJGyD3EdpSscm7Ip1xVWtYb7D0x7oH3vad3gjFcjHJzDz9xZ/iw/qItFEW+wGFcLSRPd+1BNnuLM8AsA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.13: - resolution: {integrity: sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw==} + /turbo-darwin-arm64@1.10.3: + resolution: {integrity: sha512-SBNmOZU9YEB0eyNIxeeQ+Wi0Ufd+nprEVp41rgUSRXEIpXjsDjyBnKnF+sQQj3+FLb4yyi/yZQckB+55qXWEsw==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.13: - resolution: {integrity: sha512-0CyYmnKTs6kcx7+JRH3nPEqCnzWduM0hj8GP/aodhaIkLNSAGAa+RiYZz6C7IXN+xUVh5rrWTnU2f1SkIy7Gdg==} + /turbo-linux-64@1.10.3: + resolution: {integrity: sha512-kvAisGKE7xHJdyMxZLvg53zvHxjqPK1UVj4757PQqtx9dnjYHSc8epmivE6niPgDHon5YqImzArCjVZJYpIGHQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.13: - resolution: {integrity: sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q==} + /turbo-linux-arm64@1.10.3: + resolution: {integrity: sha512-Qgaqln0IYRgyL0SowJOi+PNxejv1I2xhzXOI+D+z4YHbgSx87ox1IsALYBlK8VRVYY8VCXl+PN12r1ioV09j7A==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.13: - resolution: {integrity: sha512-S5XySRfW2AmnTeY1IT+Jdr6Goq7mxWganVFfrmqU+qqq3Om/nr0GkcUX+KTIo9mPrN0D3p5QViBRzulwB5iuUQ==} + /turbo-windows-64@1.10.3: + resolution: {integrity: sha512-rbH9wManURNN8mBnN/ZdkpUuTvyVVEMiUwFUX4GVE5qmV15iHtZfDLUSGGCP2UFBazHcpNHG1OJzgc55GFFrUw==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.13: - resolution: {integrity: sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ==} + /turbo-windows-arm64@1.10.3: + resolution: {integrity: sha512-ThlkqxhcGZX39CaTjsHqJnqVe+WImjX13pmjnpChz6q5HHbeRxaJSFzgrHIOt0sUUVx90W/WrNRyoIt/aafniw==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.13: - resolution: {integrity: sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ==} + /turbo@1.10.3: + resolution: {integrity: sha512-U4gKCWcKgLcCjQd4Pl8KJdfEKumpyWbzRu75A6FCj6Ctea1PIm58W6Ltw1QXKqHrl2pF9e1raAskf/h6dlrPCA==} hasBin: true + requiresBuild: true optionalDependencies: - turbo-darwin-64: 1.10.13 - turbo-darwin-arm64: 1.10.13 - turbo-linux-64: 1.10.13 - turbo-linux-arm64: 1.10.13 - turbo-windows-64: 1.10.13 - turbo-windows-arm64: 1.10.13 + turbo-darwin-64: 1.10.3 + turbo-darwin-arm64: 1.10.3 + turbo-linux-64: 1.10.3 + turbo-linux-arm64: 1.10.3 + turbo-windows-64: 1.10.3 + turbo-windows-arm64: 1.10.3 dev: true /tween-functions@1.2.0: