Compare commits

...

57 Commits

Author SHA1 Message Date
pandeymangg
449b56fd40 build fix 2024-06-05 18:44:24 +05:30
pandeymangg
2b1ffa90f9 build fix 2024-06-05 18:20:34 +05:30
pandeymangg
d595794fb6 refactors 2024-06-05 14:08:08 +05:30
pandeymangg
2d3dec7834 fix: somethings 2024-06-05 10:07:33 +05:30
Piyush Gupta
bbfdba7615 feat: Add hiddenFields to app & website surveys (#2628)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
2024-06-04 11:19:47 +00:00
Anshuman Pandey
681c559c79 fix: targeting ui dir structure (#2708)
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
2024-06-04 04:56:38 +00:00
Anshuman Pandey
4e39f45446 fix: settings forms (#2700)
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
2024-06-03 15:26:30 +00:00
Hicham El Bouaaichi
62c514acf2 feat: rework loading in Settings pages (#2650)
Co-authored-by: Piyush Gupta <piyushguptaa2z123@gmail.com>
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
2024-06-03 15:10:46 +00:00
Dhruwang Jariwala
48638e8ca2 fix: added support for date, matrix, address and cal question to notion integration (#2726) 2024-06-03 15:06:50 +00:00
Dhruwang Jariwala
cb44b575c2 fix: Question card fixes (#2714) 2024-06-03 14:36:57 +00:00
Matti Nannt
1565fd33f7 docs: add tutorial for custom SSL certificates (#2724) 2024-06-03 12:02:48 +02:00
Anshuman Pandey
2bf04e9818 feat: change question type (#2646)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-06-03 08:53:12 +00:00
Piyush Gupta
a5f6ecb992 docs: adds documentation table for team roles (#2709)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-31 08:09:19 +00:00
Anshuman Pandey
a211e64f0e fix: product styling form (#2696) 2024-05-30 12:00:14 +00:00
Piyush Gupta
9d33aa034a feat: Filter Responses by hidden field values (#2662) 2024-05-30 11:00:09 +00:00
Dhruwang Jariwala
a91c9db4e0 chore: optimized survey card animation (#2707) 2024-05-30 08:43:34 +00:00
Dhruwang Jariwala
291f628415 feat: Added recall highlighting to summary header (#2672)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-29 12:51:42 +00:00
Piyush Gupta
d53ceaaaac docs: adds skipPrefilled docs (#2705) 2024-05-29 12:47:15 +00:00
Piyush Gupta
aa981fd891 chore: Increase maxDuration for cron functions to 180 seconds (#2706) 2024-05-29 12:44:07 +00:00
kiran alex ch
b50bda8488 feat: Rework the loading.tsx on PRODUCT pages (#2666)
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
2024-05-28 19:27:18 +00:00
Anshuman Pandey
0d36e11bf4 fix: tootip position single response card (#2702) 2024-05-28 18:18:36 +00:00
Matti Nannt
102cdb4589 chore: update to next 15 rc (#2690) 2024-05-28 13:23:38 +00:00
Dhruwang Jariwala
5b78487b94 feat: recall from hidden fields and attributes (#2601)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Johannes <johannes@formbricks.com>
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-27 15:28:43 +00:00
Parth Gupta
f917d2171e feat: rework the loading.tsx on Actions page (#2660)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Johannes <johannes@formbricks.com>
2024-05-27 07:27:32 +00:00
Piyush Gupta
295754480e chore: Rename Teams to Organizations (#2656)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-27 05:41:21 +00:00
Matti Nannt
db03ce70d2 fix: docker release github action not adding latest tag (#2689) 2024-05-26 08:28:27 +02:00
Johannes
a44198539d docs: update styling, add roles docs (#2686) 2024-05-24 15:30:56 +00:00
Matthias Nannt
7dbac97883 chore: increase formbricks version tag to 2.0.3 2024-05-24 17:26:25 +02:00
Matthias Nannt
df6cf5a1c5 chore: change people page title 2024-05-24 17:01:35 +02:00
Lovish Duggal
ffa774db6a feat: rework-the-loading.tsx-on-people-page (#2668)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Johannes <johannes@formbricks.com>
2024-05-24 13:26:28 +00:00
Anshuman Pandey
6d6a47a5ac fix: adds react hook form to product general settings (#2677) 2024-05-24 13:14:04 +00:00
Dhruwang Jariwala
50e373a98a fix: date picker tweaks (#2685) 2024-05-24 11:57:10 +00:00
Dhruwang Jariwala
b56b2adb54 fix: access token expiration issue in google sheet integration (#2667) 2024-05-24 09:58:42 +00:00
Johannes
af09e315c5 chore: EE license trial info on settings etc. (#2681) 2024-05-24 09:31:02 +00:00
Dhruwang Jariwala
1848e062f1 fix: highlighting for question with cyclic logic (#2669)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
2024-05-24 07:25:46 +00:00
Matti Nannt
c8f2f94361 chore: cache improvements (#2684) 2024-05-23 18:33:54 +02:00
Anshuman Pandey
be52763be4 fix: ee license check (#2661)
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
2024-05-23 14:55:02 +00:00
Dhruwang Jariwala
5dd5816c34 fix: case insensitive multi langauge check (#2682) 2024-05-23 14:45:40 +00:00
Dhruwang Jariwala
16f5ce40d9 fix: Question -> Note for ty and welcome card labels (#2644)
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
2024-05-23 14:38:29 +00:00
Anshuman Pandey
223937adcc feat: adds a POST endpoint for response creation in management apis (#2652)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-23 14:16:57 +00:00
Piyush Gupta
4544cba858 fix: File Upload currently only supports 10 files (#2642)
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
2024-05-23 12:09:21 +00:00
Piyush Gupta
1284adf91d feat: Extend Prefilling with an option to auto-skip prefilled values (#2598)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-23 11:35:42 +00:00
Piyush Gupta
4b13d19ed9 feat: adds pagination(skip and limit) support in management > response API (#2631)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
2024-05-23 10:48:16 +00:00
Dhruwang Jariwala
12a606a443 fix: modified google sheet integration and minor refactors in other integrations (#2572) 2024-05-23 10:25:48 +00:00
Dhruwang Jariwala
052f86b19f fix: recall issues (#2680) 2024-05-23 06:54:54 +00:00
Matti Nannt
27b37a5f27 fix: convert number attributes to strings automatically (#2679) 2024-05-22 17:48:02 +02:00
Dhruwang Jariwala
c37d3ae0f9 fix: ui issues (#2665) 2024-05-22 14:03:17 +00:00
Matti Nannt
e69bb3501d docs: update advanced docker update steps (#2678) 2024-05-22 15:22:30 +02:00
Matti Nannt
eda9c00548 fix: migration instructions to 2.0 (#2676) 2024-05-22 14:35:11 +02:00
Jonas Höbenreich
6a7e0d3ecb fix: set "desktop" as default device type (#2675) 2024-05-22 12:11:25 +00:00
Anshuman Pandey
48859facf4 fix: formbricks init error (#2633)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2024-05-22 12:07:17 +00:00
Matti Nannt
732b8b599f fix: docker file shouldn't check npm registry on runtime (#2663) 2024-05-21 13:39:51 +02:00
Johannes
00ad4c3895 fix: fix links to integrations on docs (#2664) 2024-05-21 11:57:24 +02:00
Dhruwang Jariwala
4858bdd838 fix: rating question and updated attribute labels on person page (#2657)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
2024-05-20 15:02:28 +00:00
Shubham Palriwala
eee78a79d9 fix: navbar on mobile docs for grouped features (#2658)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
2024-05-20 14:57:18 +00:00
Johannes
aa890affc9 fix: update links for integrations (#2659) 2024-05-20 16:45:41 +02:00
Anshuman Pandey
10aed2d9d8 fix: UI fixes (#2653)
Co-authored-by: Johannes <johannes@formbricks.com>
2024-05-20 09:11:18 +00:00
506 changed files with 12466 additions and 9245 deletions

View File

@@ -88,7 +88,7 @@ PASSWORD_RESET_DISABLED=1
# Email login. Disable the ability for users to login with email.
# EMAIL_AUTH_DISABLED=1
# Team Invite. Disable the ability for invited users to create an account.
# Organization Invite. Disable the ability for invited users to create an account.
# INVITE_DISABLED=1
##########
@@ -154,11 +154,11 @@ SLACK_CLIENT_SECRET=
# Enterprise License Key
ENTERPRISE_LICENSE_KEY=
# Automatically assign new users to a specific team and role within that team
# Insert an existing team id or generate a valid CUID for a new one at https://www.getuniqueid.com/cuid (e.g. cjld2cjxh0000qzrmn831i7rn)
# Automatically assign new users to a specific organization and role within that organization
# Insert an existing organization id or generate a valid CUID for a new one at https://www.getuniqueid.com/cuid (e.g. cjld2cjxh0000qzrmn831i7rn)
# (Role Management is an Enterprise feature)
# DEFAULT_TEAM_ID=
# DEFAULT_TEAM_ROLE=admin
# DEFAULT_ORGANIZATION_ID=
# DEFAULT_ORGANIZATION_ROLE=admin
# set to 1 to skip onboarding for new users
# ONBOARDING_DISABLED=1

View File

@@ -1,26 +0,0 @@
name: Build formbricks-com
on:
workflow_call:
jobs:
build:
name: Build Formbricks-com
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install --config.platform=linux --config.architecture=x64
- name: Build Formbricks-com
run: pnpm build --filter=formbricks-com...

View File

@@ -56,7 +56,7 @@ jobs:
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_ID }}
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}

View File

@@ -53,7 +53,7 @@ jobs:
GOOGLE_SHEETS_REDIRECT_URL: ${{ secrets.GOOGLE_SHEETS_REDIRECT_URL }}
AIRTABLE_CLIENT_ID: ${{ secrets.AIRTABLE_CLIENT_ID }}
ENTERPRISE_LICENSE_KEY: ${{ secrets.ENTERPRISE_LICENSE_KEY }}
DEFAULT_TEAM_ID: ${{ vars.DEFAULT_TEAM_ID }}
DEFAULT_ORGANIZATION_ID: ${{ vars.DEFAULT_ORGANIZATION_ID }}
ONBOARDING_DISABLED: ${{ vars.ONBOARDING_DISABLED }}
CUSTOMER_IO_API_KEY: ${{ secrets.CUSTOMER_IO_API_KEY }}
CUSTOMER_IO_SITE_ID: ${{ secrets.CUSTOMER_IO_SITE_ID }}

View File

@@ -1,4 +1,4 @@
name: Docker
name: Docker Release to Github
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by

View File

@@ -82,7 +82,7 @@ Formbricks is both a free and open source survey platform - and a privacy-first
- 🔗 Create shareable **link surveys**.
- 👨‍👩‍👦 Invite your team members to **collaborate** on your surveys.
- 👨‍👩‍👦 Invite your organization members to **collaborate** on your surveys.
- 🔌 Integrate Formbricks with **Slack, Notion, Zapier, n8n and more**.

View File

@@ -1,5 +1,3 @@
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@formbricks/ui/Select";
interface SurveySwitchProps {
value: "website" | "app";
formbricks: any;
@@ -7,23 +5,18 @@ interface SurveySwitchProps {
export const SurveySwitch = ({ value, formbricks }: SurveySwitchProps) => {
return (
<Select
<select
value={value}
onValueChange={(v) => {
onChange={(v) => {
formbricks.logout();
window.location.href = `/${v}`;
window.location.href = `/${v.target.value}`;
}}>
<SelectTrigger className="w-[180px] px-4">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="website" className="h-10 px-4 hover:bg-slate-100">
Website Surveys
</SelectItem>
<SelectItem value="app" className="hover:bg-slate-10 h-10 px-4">
App Surveys
</SelectItem>
</SelectContent>
</Select>
<option value="website" className="h-10 px-4 hover:bg-slate-100">
Website Surveys
</option>
<option value="app" className="hover:bg-slate-10 h-10 px-4">
App Surveys
</option>
</select>
);
};

View File

@@ -1,7 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
transpilePackages: ["@formbricks/ui"],
async redirects() {
return [
{
@@ -25,4 +24,4 @@ const nextConfig = {
},
};
module.exports = nextConfig;
export default nextConfig;

View File

@@ -13,7 +13,7 @@
"dependencies": {
"@formbricks/js": "workspace:*",
"@formbricks/ui": "workspace:*",
"lucide-react": "^0.378.0",
"lucide-react": "^0.379.0",
"next": "14.2.3",
"react": "18.3.1",
"react-dom": "18.3.1"

View File

@@ -6,7 +6,7 @@ import I2 from "./images/I2.webp";
export const metadata = {
title: "Using Actions in Formbricks | Fine-tuning User Moments",
description:
"Dive deep into how actions in Formbricks help products and teams to engage users at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine user targeting and generate richer, more detailed user insights.",
"Dive deep into how actions in Formbricks help products and organizations to engage users at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine user targeting and generate richer, more detailed user insights.",
};
#### App Surveys

View File

@@ -85,7 +85,7 @@ To run this survey properly, you should pre-segment your user base. As touched u
- Check the time passed since sign-up (e.g. signed up 4 weeks ago)
- User has performed a specific action a certain number of times or (e.g. created 5 reports)
- User has performed a combination of actions (e.g. created a report **and** invited a team member)
- User has performed a combination of actions (e.g. created a report **and** invited a organization member)
This way you make sure that you separate potentially misleading opinions from valuable insights.

View File

@@ -24,8 +24,7 @@ export const metadata = {
The Airtable integration allows you to automatically send responses to an Airtable of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -21,9 +21,8 @@ export const metadata = {
The Google Sheets integration allows you to automatically send responses to a Google Sheet of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks. For self-configuration, see additional setup
[below](#setup-in-self-hosted-formbricks).
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow
the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
</Note>
## Connect Google Sheets
@@ -72,7 +71,7 @@ Before the next step, make sure that you have a Formbricks Survey with at least
className="max-w-full rounded-lg sm:max-w-3xl"
/>
6. Select the Google Sheet you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in the Google Sheet. Select the questions and click on the "Link Sheet" button.
6. Enter the spreadsheet URL for the Google Sheet you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in the Google Sheet. Select the questions and click on the "Link Sheet" button.
<MdxImage
src={LinkWithQuestions}
@@ -117,7 +116,6 @@ To remove the integration with Google Account,
For the above, we ask for:
1. **User Email**: To identify you (that's it, nothing else, we're opensource, see this in our codebase [here](https://github.com/formbricks/formbricks/blob/main/apps/web/app/api/google-sheet/callback/route.ts#L47C17-L47C25))
1. **Google Drive API**: To list all your google sheets (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L13))
1. **Google Spreadsheet API**: To write to the spreadsheet you select (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L70))
<Note>We store as little personal information as possible.</Note>

View File

@@ -27,7 +27,7 @@ export const metadata = {
Make is a powerful tool to send information between Formbricks and thousands of apps. Here's how to set it up.
<Note>
### Nail down your survey first ? Any changes in the survey cause additional work in the _Scenario_. It
Nailed down your survey?? Any changes in the survey cause additional work in the _Scenario_. It
makes sense to first settle on the survey you want to run and then get to setting up Make.
</Note>

View File

@@ -29,7 +29,7 @@ export const metadata = {
n8n allows you to build flexible workflows focused on deep data integration. And with sharable templates and a user-friendly UI, the less technical people on your team can collaborate on them too. Unlike other tools, complexity is not a limitation. So you can build whatever you want — without stressing over budget. Hook up Formbricks with n8n and you can send your data to 350+ other apps. Here is how to do it.
<Note>
### Nail down your survey first Any changes in the survey cause additional work in the n8n node. It makes
Nail down your survey? Any changes in the survey cause additional work in the n8n node. It makes
sense to first settle on the survey you want to run and then get to setting up n8n.
</Note>

View File

@@ -21,8 +21,7 @@ export const metadata = {
The notion integration allows you to automatically send responses to a Notion database of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud

View File

@@ -10,7 +10,7 @@ export const metadata = {
At Formbricks, we understand the importance of integrating with third-party applications. We have step-by-step guides to configure our third-party integrations with a your Formbricks instance. We currently support the below integrations, click on them to see their individual guides:
<Note>
If you are on a self-hosted instance, you will need to configure these integrations manually. Please follow the guides [here](/self-hosting/integrations) to configure them.
If you are on a self-hosted instance, you will need to configure these integrations manually. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
</Note>
- [Airtable](/developer-docs/integrations/airtable): Automatically send responses to an Airtable of your choice.

View File

@@ -22,8 +22,7 @@ export const metadata = {
The slack integration allows you to automatically send responses to a Slack channel of your choice.
<Note>
This feature is enabled by default in Formbricks Cloud but needs to be self-configured when running a
self-hosted version of Formbricks.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,149 @@
import { MdxImage } from "@/components/MdxImage";
import AddMember from "./images/add-member.webp";
import BulkInvite from "./images/bulk-invite.webp";
import IndvInvite from "./images/individual-invite.webp";
import MenuItem from "./images/organization-settings-menu.webp";
export const metadata = {
title: "Organization Access Roles",
description:
"Assign different roles to organization members to grant them specific rights like creating surveys, viewing responses, or managing organization members.",
};
# Organization Access Roles
Assign different roles to organization members to grant them specific rights like creating surveys, viewing responses, or managing organization members.
<Note>
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free**
and **Startup** plan in the Cloud you can invite unlimited organization members as `Admins`.
</Note>
Here are the different access permissions, ranked from highest to lowest access
1. Owner
2. Admin
3. Developer
4. Editor
5. Viewer
For more information on user roles & permissions, see below:
| | Owner | Admin | Editor | Developer | Viewer |
| -------------------------------- | ----- | ----- | ------ | --------- | ------ |
| **Organization** | | | | | |
| Update organization | ✅ | ✅ | ❌ | ❌ | ❌ |
| Delete organization | ✅ | ❌ | ❌ | ❌ | ❌ |
| Add new Member | ✅ | ✅ | ❌ | ❌ | ❌ |
| Delete Member | ✅ | ✅ | ❌ | ❌ | ❌ |
| Update Member Access | ✅ | ✅ | ❌ | ❌ | ❌ |
| Update Billing | ✅ | ✅ | ❌ | ❌ | ❌ |
| **Product** | | | | | |
| Create Product | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
| Update Product Name | ✅ | ✅ | ✅ | ❌ | ❌ |
| Update Product Recontact Options | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update Look & Feel | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update Survey Languages | ✅ | ✅ | ✅ | ✅ | ❌ |
| Delete Product | ✅ | ✅ | ✅ | ✅ | ❌ |
| **Surveys** | | | | | |
| Create New Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
| Edit Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
| Delete Survey | ✅ | ✅ | ✅ | ✅ | ❌ |
| View survey results | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Response** | | | | | |
| Delete response | ✅ | ✅ | ✅ | ✅ | ❌ |
| Add tags on response | ✅ | ✅ | ✅ | ✅ | ❌ |
| Edit tags on response | ✅ | ✅ | ✅ | ✅ | ❌ |
| **Actions** | | | | | |
| Create Action | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update Action | ✅ | ✅ | ✅ | ✅ | ❌ |
| Delete Action | ✅ | ✅ | ✅ | ✅ | ❌ |
| **API Keys** | | | | | |
| Create API key | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update API key | ✅ | ✅ | ✅ | ✅ | ❌ |
| Delete API key | ✅ | ✅ | ✅ | ✅ | ❌ |
| **Tags** | | | | | |
| Create tags | ✅ | ✅ | ✅ | ✅ | ❌ |
| Update tags | ✅ | ✅ | ✅ | ✅ | ❌ |
| Delete tags | ✅ | ✅ | ✅ | ✅ | ❌ |
| **People** | | | | | |
| Delete Person | ✅ | ✅ | ✅ | ✅ | ❌ |
| **Integrations** | | | | | |
| Manage Integrations | ✅ | ✅ | ✅ | ✅ | ❌ |
## Inviting organization members
There are two ways to invite organization members: One by one or in bulk.
### Invite organization members one by one
1. Go to the `Organization Settings` page via the menu in the lower right corner:
<MdxImage
src={MenuItem}
alt="Where to find the Menu Item for Organization Settings"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Click on the `Add Member` button:
<MdxImage
src={AddMember}
alt="Add Member Button Position"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. In the modal, add the Name, Email and Role of the organization member you want to invite:
<MdxImage
src={IndvInvite}
alt="Individual Invite Modal Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
<Note>
Access Roles is a feature of the **Enterprise Edition**. In the **Community Edition** and on the **Free**
and **Startup** plan in the Cloud you can invite unlimited organization members as `Admins`.
</Note>
Formbricks sends an email to the organization member with an invitation link. The organization member can accept the invitation or create a new account by clicking on the link.
### Invite organization members in bulk
1. Go to the `Organization Settings` page via the menu in the lower right corner:
<MdxImage
src={MenuItem}
alt="Where to find the Menu Item for Organization Settings"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Click on the `Add Member` button:
<MdxImage
src={AddMember}
alt="Add Member Button Position"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. In the modal, switch to `Bulk Invite`. You can download an example .CSV file to fill in the Name, Email and Role of the organization members you want to invite:
<MdxImage
src={BulkInvite}
alt="Individual Invite Modal Tab"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
4. Upload the filled .CSV file and invite the organization members in bulk ✅
Formbricks sends an email to each organization member in the CSV. The member can accept the invitation or create a new account by clicking on the link.
---

View File

@@ -1,260 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import PreRequisiteImage from "./images/Pre-requisite.webp";
import StepEight from "./images/StepEight.webp";
import StepEleven from "./images/StepEleven.webp";
import StepFive from "./images/StepFive.webp";
import StepFour from "./images/StepFour.webp";
import StepNine from "./images/StepNine.webp";
import StepOne from "./images/StepOne.webp";
import StepSeven from "./images/StepSeven.webp";
import StepSix from "./images/StepSix.webp";
import StepTen from "./images/StepTen.webp";
import StepThree from "./images/StepThree.webp";
import StepTwo from "./images/StepTwo.webp";
import Doggo from "./images/Doggo.jpg";
import HipsterLiving from "./images/HipsterLiving.jpg";
import Mario from "./images/Mario.webp";
import WindowsXp from "./images/WindowsXp.jpg";
export const metadata = {
title: "Custom Styling in Formbricks Surveys",
description:
"Style your surveys effortlessly with Formbricks to match your brand's unique aesthetic, from Super Mario themes to the minimalist Windows XP style. Customize everything from color schemes to adding your logo, all without needing any coding skills.",
};
# Custom Styling
Style your surveys effortlessly with Formbricks to match your brand's unique aesthetic, from Super Mario themes to the minimalist Windows XP style. Customize everything from color schemes to adding your logo, all without needing any coding skills. Dont miss out some of our standout design surveys at the end!
### Product Styling
Easily apply a consistent style across all your current & future surveys:
**Pre-requisites:**
1. Navigate to the **Settings** tab on the Formbricks Dashboard.
2. Select **Look & Feel** under the **Product** section in the left navbar
<MdxImage
src={PreRequisiteImage}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
**Switch between Link Survey & App Survey** to preview different styles
### **Styling Options**
1. **Form Styling:** Customize the survey card using the following settings
<MdxImage
src={StepOne}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Brand Color**: Sets the primary color tone of the survey.
- **Text Color**: This is a single color scheme that will be used across to display all the text on your survey. Ensures all text is readable against the background.
- **Input Color:** Alters the border color of input fields.
- **Input Border Color**: This is the color of the border of the form input field.
2. **Card Styling:** Adjust the look of the survey card
<MdxImage
src={StepTwo}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Roundness**: Adjusts the corner roundness of the survey card and its components (including input boxes, buttons).
- **Card Background Color**: Sets the card's main background color.
- **Card Border Color**: Changes the border color of the card
- **Card Shadow Color**: Adds a shadow effect for depth
- **Hide Progress Bar**: Optionally remove the progress bar to simplify the survey experience
- **Add Highlight Border**: Adds a distinct border for emphasis.
3. **Background Styling**: Customize the survey background with static colors, animations, or images (upload your own or get from Unsplash)
<Note>This is only available for Link Surveys</Note>
<MdxImage
src={StepThree}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Color**: Pick any color for the background
- **Animation**: Add dynamic animations to enhance user experience..
- **Upload**: Use a custom uploaded image for a personalized touch
- Image: Choose from Unsplash's extensive gallery. Note that these images will have a link and mention of the author & Unsplash on the bottom right to give them the credit for their awesome work!
- **Background Overlay**: Adjust the background's opacity
### Add Brand Logo:
Customize your survey with your brand's logo.
<Note>only available for link survyes</Note>
1. In the Look & Feel page itself in Product settings, scroll down to see the Logo Upload box.
<MdxImage
src={StepFour}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Upload your logo
<MdxImage
src={StepFive}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. Add a background color: If youve uploaded a transparent image and want to add background to it, enable this toggle and select the color of your choice.
<MdxImage
src={StepSix}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
4. Remember to save your changes!
<MdxImage
src={StepSeven}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
<Note>The logo setting applies across all link surveys</Note>
### Overwrite Product Styling
Create surveys with specific styles that differ from your general product style.
**Pre-requisites**:
- Enable the **Custom Styling** toggle in the **Look & Feel** settings
<MdxImage
src={StepEight}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
**Steps:**
1. Open the survey editor you want to change the styling of and switch to the Styling tab.
<MdxImage
src={StepNine}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Activate the **Add Custom Styles** toggle to override the default product styling.
<MdxImage
src={StepTen}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. Customize your survey's style as needed!
<MdxImage
src={StepEleven}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
Voila! just hit the save button to apply your changes. Your survey is now ready to impress with its unique look!
## Overwrite CSS Styles for App & Website Surveys
You can overwrite the default CSS styles for the app & website surveys by adding the following CSS to your global CSS file (eg. `globals.css`):
Make sure that you do not change the CSS variable names as they are used by Formbricks to identify the CSS variables. You can change the values to your liking. We have filled in some sample values for you to change according to your desired appearance.
<Col>
<CodeGroup title="Overwrite Formbricks CSS">
```css
/* Formbricks CSS */
--fb-brand-color: red;
--fb-brand-text-color: white;
--fb-border-color: green;
--fb-border-color-highlight: rgb(13, 13, 12);
--fb-focus-color: red;
--fb-heading-color: yellow;
--fb-subheading-color: green;
--fb-info-text-color: orange;
--fb-signature-text-color: blue;
--fb-survey-background-color: black;
--fb-accent-background-color: rgb(13, 13, 12);
--fb-accent-background-color-selected: red;
--fb-placeholder-color: white;
--fb-shadow-color: var(--fb-brand-color);
--fb-rating-fill: rgb(13, 13, 12);
--fb-rating-hover: green;
--fb-back-btn-border: blue;
--fb-submit-btn-border: transparent;
--fb-rating-selected: black;
```
</CodeGroup>
</Col>
We have an example of this in our [Demo project](https://github.com/formbricks/formbricks/blob/main/apps/demo/styles/globals.css) here.
### Funky Survey Examples
- **Super Mario:** I guess he won't let himself be limited by radio buttons and do all three things
<MdxImage
src={Mario}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Hipster Living**: Does your monstera get enough water?
<MdxImage
src={HipsterLiving}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Windows XP**: Hach, nostalgia. Made us wanna play Mafia.
<MdxImage
src={WindowsXp}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Whosagooooodbooooy**: Things you've likely said to your dog.
<MdxImage
src={Doggo}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -0,0 +1,79 @@
import { MdxImage } from "@/components/MdxImage";
import FilledHiddenFields from "./filled-hidden-fields.webp";
import HiddenFieldResponses from "./hidden-field-responses.webp";
import HiddenFields from "./hidden-fields.webp";
import InputHiddenFields from "./input-hidden-fields.webp";
export const metadata = {
title: "Hidden Fields",
description: "Add hidden fields to your surveys to capture additional data without requiring user inputs!",
};
# Hidden Fields
Hidden fields are a powerful feature in Formbricks that allows you to add data to a submission without asking the user to type it in. This feature is especially useful when you already have information about a user that you want to use in the analysis of the survey results (e.g. `payment plan` or `email`)
<Note>Hidden fields are now available in the Formbricks in-app and website surveys as well</Note>
## How to Add Hidden Fields
### Enable them in the Survey Builder
1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
<MdxImage
src={HiddenFields}
alt="Enable Hidden Fields"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
<MdxImage
src={InputHiddenFields}
alt="Add Hidden Fields"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<MdxImage
src={FilledHiddenFields}
alt="Filled Hidden Fields"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
### Set Hidden Field
<Col>
<CodeGroup title="Example Screen from which the User filled it">
```sh
formbricks.track("my event", {
hiddenFields: {
screen: "landing_page",
job: "Founder"
},
});
```
</CodeGroup>
</Col>
## View Hidden Fields in Responses
These hidden fields will now be visible in the responses tab just like other fields in the Summary as well as the Response Cards, and you can use them to filter and analyze your responses.
<MdxImage
src={HiddenFieldResponses}
alt="Hidden Field Responses"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## Use Cases
- **User Metadata**: You can add hidden fields to capture user metadata such as user ID, email, or any other user-specific information.
- **Survey Metadata**: You can add hidden fields to capture other metadata, e.g. the screen from which the survey was filled, or any other app specific information.

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,131 @@
import { MdxImage } from "@/components/MdxImage";
import StepEleven from "./images/StepEleven.webp";
import StepNine from "./images/StepNine.webp";
import StepTen from "./images/StepTen.webp";
import Doggo from "./images/Doggo.jpg";
import HipsterLiving from "./images/HipsterLiving.jpg";
import Mario from "./images/Mario.webp";
import WindowsXp from "./images/WindowsXp.jpg";
export const metadata = {
title: "Overwrite Styling Theme on Individual Surveys",
description:
"Overwrite the global styling theme for individual surveys to create unique styles for each survey.",
};
# Overwrite Styling Theme on Individual Surveys
Overwrite the global styling theme for individual surveys to create unique styles for each survey.
<Note>To set a styling theme for all surveys, please see the [Styling Theme](/global/styling-theme) manual. </Note>
### Overwrite Styling Theme
1. In the Survey Editor of the survey you want to style, navigate to the **Styling** tab:
<MdxImage
src={StepNine}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Activate the **Add Custom Styles** toggle to override the default product styling:
<MdxImage
src={StepTen}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. Customize your survey's style as needed:
<MdxImage
src={StepEleven}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
Voila! just hit the save button to apply your changes. Your survey is now ready to impress with its unique look!
## Overwrite CSS Styles for App & Website Surveys
You can overwrite the default CSS styles for the app & website surveys by adding the following CSS to your global CSS file (eg. `globals.css`):
Make sure that you do not change the CSS variable names as they are used by Formbricks to identify the CSS variables. You can change the values to your liking. We have filled in some sample values for you to change according to your desired appearance.
<Col>
<CodeGroup title="Overwrite Formbricks CSS">
```css
/* Formbricks CSS */
--fb-brand-color: red;
--fb-brand-text-color: white;
--fb-border-color: green;
--fb-border-color-highlight: rgb(13, 13, 12);
--fb-focus-color: red;
--fb-heading-color: yellow;
--fb-subheading-color: green;
--fb-info-text-color: orange;
--fb-signature-text-color: blue;
--fb-survey-background-color: black;
--fb-accent-background-color: rgb(13, 13, 12);
--fb-accent-background-color-selected: red;
--fb-placeholder-color: white;
--fb-shadow-color: var(--fb-brand-color);
--fb-rating-fill: rgb(13, 13, 12);
--fb-rating-hover: green;
--fb-back-btn-border: blue;
--fb-submit-btn-border: transparent;
--fb-rating-selected: black;
```
</CodeGroup>
</Col>
We have an example of this in our [Demo project](https://github.com/formbricks/formbricks/blob/main/apps/demo/styles/globals.css) here.
## Funky Survey Examples
- **Super Mario:** I guess he won't let himself be limited by radio buttons and do all three things
<MdxImage
src={Mario}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Hipster Living**: Does your monstera get enough water?
<MdxImage
src={HipsterLiving}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Windows XP**: Hach, nostalgia. Made us wanna play Mafia.
<MdxImage
src={WindowsXp}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Whosagooooodbooooy**: Things you've likely said to your dog.
<MdxImage
src={Doggo}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -0,0 +1,149 @@
import { MdxImage } from "@/components/MdxImage";
import StepEight from "./images/StepEight.webp";
import StepEleven from "./images/StepEleven.webp";
import StepFive from "./images/StepFive.webp";
import StepFour from "./images/StepFour.webp";
import StepNine from "./images/StepNine.webp";
import StepSeven from "./images/StepSeven.webp";
import StepSix from "./images/StepSix.webp";
import StepTen from "./images/StepTen.webp";
import AllowOverwrite from "./images/allow-overwrite.webp";
import BackgroundSettings from "./images/background-settings.webp";
import CardSettings from "./images/card-settings.webp";
import FormSettings from "./images/form-settings.webp";
import LookAndFeelSettings from "./images/look-and-feel.webp";
import Doggo from "./images/Doggo.jpg";
import HipsterLiving from "./images/HipsterLiving.jpg";
import Mario from "./images/Mario.webp";
import WindowsXp from "./images/WindowsXp.jpg";
export const metadata = {
title: "Styling Theme",
description:
"Keep the survey styling consistent over all surveys with a Styling Theme. Customize the colors, fonts, and other styling options to match your brand's aesthetic.",
};
# Styling Theme
Keep the survey styling consistent over all surveys with a Styling Theme. Customize the colors, fonts, and other styling options to match your brand's aesthetic.
## Configuration
In the left side bar, you find the `Configuration` page. On this page you find the `Look & Feel` section:
<MdxImage
src={LookAndFeelSettings}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## **Styling Options**
1. **Form Styling:** Customize the survey card using the following settings
<MdxImage
src={FormSettings}
alt="Form styling options UI"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Brand Color**: Sets the primary color tone of the survey.
- **Text Color**: This is a single color scheme that will be used across to display all the text on your survey. Ensures all text is readable against the background.
- **Input Color:** Alters the border color of input fields.
- **Input Border Color**: This is the color of the border of the form input field.
2. **Card Styling:** Adjust the look of the survey card
<MdxImage
src={CardSettings}
alt="Card styling options UI"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Roundness**: Adjusts the corner roundness of the survey card and its components (including input boxes, buttons).
- **Card Background Color**: Sets the card's main background color.
- **Card Border Color**: Changes the border color of the card
- **Card Shadow Color**: Adds a shadow effect for depth
- **Hide Progress Bar**: Optionally remove the progress bar to simplify the survey experience
- **Add Highlight Border**: Adds a distinct border for emphasis.
3. **Background Styling**: Customize the survey background with static colors, animations, or images (upload your own or get from Unsplash)
<Note>This is only available for Link Surveys</Note>
<MdxImage
src={BackgroundSettings}
alt="Background styling options UI"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
- **Color**: Pick any color for the background
- **Animation**: Add dynamic animations to enhance user experience..
- **Upload**: Use a custom uploaded image for a personalized touch
- Image: Choose from Unsplash's extensive gallery. Note that these images will have a link and mention of the author & Unsplash on the bottom right to give them the credit for their awesome work!
- **Background Overlay**: Adjust the background's opacity
## Add Brand Logo
Customize your survey with your brand's logo.
<Note>Brand logos are only visible on Link Survey pages.</Note>
1. In the Look & Feel page itself in Product settings, scroll down to see the Logo Upload box.
<MdxImage
src={StepFour}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
2. Upload your logo
<MdxImage
src={StepFive}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
3. Add a background color: If youve uploaded a transparent image and want to add background to it, enable this toggle and select the color of your choice.
<MdxImage
src={StepSix}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
4. Remember to save your changes!
<MdxImage
src={StepSeven}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl "
/>
<Note>The logo settings apply across all Link Surveys pages.</Note>
## Overwrite Styling Theme
You can allow to overwrite the styling theme for individual surveys to create unique styles for each survey:
<MdxImage
src={AllowOverwrite}
alt="Choose a link survey template"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
In the survey editor, a tab called `Styling` will appear. Here you can overwrite the default styling theme.
---

View File

@@ -4,27 +4,22 @@ export const metadata = {
"Open source software beats proprietary software in every aspect - except for value capture. We're investing in growing the value creation of our open source platform because it directly translates into business with large organisations.",
};
#### Introduction
#### Introduction
# Why is Formbricks open source?
A lot has been written on why open source software beats proprietary software in all aspects - except for value capture for the company investing into its development. While this definitely poses a challenge for a profit-oriented organisation, it's also an interesting opportunity: Due to the open nature of our platform, it's usage is significantly higher. Capturing a small part of the value our platform generates translates into a decently-sized business.
| Advantage | Open Source Software | Proprietary Software |
|----------------------|----------------------------------------------------|----------------------------------------------------------|
| **Data Privacy** | Self-host for maximum control over data | Dependent on thrid party data processor. |
| **Cost** | Often free or significantly lower cost. | Typically requires a purchase or subscription. |
| **Customizability** | Code can be modified to meet specific needs. | Limited customization, restricted to developer's features.|
| **Security**| Frequent community reviews identify vulnerabilities quickly. | Security updates depend on vendor's schedule and interest.|
| **Flexibility**| Supports a wide range of applications and integrations. | Designed for specific environments and integrations. |
| **Community Support**| Large, active communities offer free support and resources. | Paid customer support with limited community help. |
| **Innovation** | Fosters rapid innovation through community contributions. | Innovations depend on vendor's vision and development team.|
| **Licensing** | Permissive licenses allow broad usage and modification. | Strict licensing with limited redistribution rights. |
| **Independence** | Not dependent on a single vendor or developer. | Vendor lock-in can limit future choices. |
| **Transparency** | Full visibility into the code base and development. | Closed-source, code is hidden from users. |
| **Interoperability**| Supports open standards, ensuring interoperability. | Often requires additional software or plugins for compatibility. |
| Advantage | Open Source Software | Proprietary Software |
| --------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------- |
| **Data Privacy** | Self-host for maximum control over data | Dependent on thrid party data processor. |
| **Cost** | Often free or significantly lower cost. | Typically requires a purchase or subscription. |
| **Customizability** | Code can be modified to meet specific needs. | Limited customization, restricted to developer's features. |
| **Security** | Frequent community reviews identify vulnerabilities quickly. | Security updates depend on vendor's schedule and interest. |
| **Flexibility** | Supports a wide range of applications and integrations. | Designed for specific environments and integrations. |
| **Community Support** | Large, active communities offer free support and resources. | Paid customer support with limited community help. |
| **Innovation** | Fosters rapid innovation through community contributions. | Innovations depend on vendor's vision and development team. |
| **Licensing** | Permissive licenses allow broad usage and modification. | Strict licensing with limited redistribution rights. |
| **Independence** | Not dependent on a single vendor or developer. | Vendor lock-in can limit future choices. |
| **Transparency** | Full visibility into the code base and development. | Closed-source, code is hidden from users. |
| **Interoperability** | Supports open standards, ensuring interoperability. | Often requires additional software or plugins for compatibility. |

View File

@@ -40,6 +40,10 @@ To prefill the questions of a survey, add query parameters to the survey URL. Th
<Note>Please make sure the answer is [URL encoded](https://www.urlencoder.org/).</Note>
## Prefilling Customisation
You can customize the prefilling behavior using the `skipPrefilled` parameter in the URL. If you want to skip the prefilled questions and show the next available question, you can add `skipPrefilled=true` to the URL. By default, the `skipPrefilled` parameter is set to `false`.
## Prefilling multiple values
Formbricks let's you prefill as many values as you want. You can combine multiple values in the URL using `&` so for example `name=Bernadette&age=18`. The order of the query parameters does not matter so you can always move around questions or add new ones without having to worry about the order of the query parameters.

View File

@@ -4,7 +4,6 @@ import FilledHiddenFields from "./filled-hidden-fields.webp";
import HiddenFieldResponses from "./hidden-field-responses.webp";
import HiddenFields from "./hidden-fields.webp";
import InputHiddenFields from "./input-hidden-fields.webp";
import SettingsPage from "./settings.webp";
export const metadata = {
title: "Hidden Fields",
@@ -21,16 +20,7 @@ Hidden fields are a powerful feature in Formbricks that allows you to add data t
### Enable them in the Survey Builder
1. Edit the survey you want to add hidden fields to & open it's settings, make sure it's selected as a **Link Survey**.
<MdxImage
src={SettingsPage}
alt="Select the Survey Type as Link Survey"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
1. Edit the survey you want to add hidden fields to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Hidden Fields**. Make sure to enable it by toggling the switch.
<MdxImage
src={HiddenFields}
@@ -39,7 +29,7 @@ Hidden fields are a powerful feature in Formbricks that allows you to add data t
className="max-w-full rounded-lg sm:max-w-3xl"
/>
3. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
2. Now click on it to add a new hidden field ID. You can add as many hidden fields as you want.
<MdxImage
src={InputHiddenFields}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -51,8 +51,8 @@ These variables are present inside your machines docker-compose file. Restart
| INSTANCE_ID | Instance ID for Formbricks Cloud to be sent to Telemetry. | optional | |
| INTERNAL_SECRET | Internal Secret (Currently we overwrite the value with a random value). | optional | |
| DEFAULT_BRAND_COLOR | Default brand color for your app (Can be overwritten from the UI as well). | optional | #64748b |
| DEFAULT_TEAM_ID | Automatically assign new users to a specific team when joining | optional | |
| DEFAULT_TEAM_ROLE | Role of the user in the default team. | optional | admin |
| DEFAULT_ORGANIZATION_ID | Automatically assign new users to a specific organization when joining | optional | |
| DEFAULT_ORGANIZATION_ROLE | Role of the user in the default organization. | optional | admin |
| ONBOARDING_DISABLED | Disables onboarding for new users if set to 1 | optional | |
| OIDC_DISPLAY_NAME | Display name for Custom OpenID Connect Provider | optional | |
| OIDC_CLIENT_ID | Client ID for Custom OpenID Connect Provider | optional (required if OIDC auth is enabled) | |

View File

@@ -0,0 +1,140 @@
export const metadata = {
title: "Add Custom SSL Certificate to Formbricks",
description: "Learn how to add a custom SSL certificate to your Formbricks self-hosted instance.",
};
# Using Formbricks One-Click Setup with a Custom SSL Certificate
<Note>
Formbricks One-Click setup already comes with a valid SSL certificate using Let's Encrypt. This guide is
only if you already have a valid SSL certificate that you need to use due to company policy or other
requirements.
</Note>
## Introduction
While Formbricks' One-Click setup can automatically create a valid SSL certificate using Let's Encrypt, there are scenarios where a custom SSL certificate is necessary. This is particularly relevant for environments like intranets or other setups with specific certificate requirements, where an internal or custom certificate authority (CA) might be used.
### Step 1: Navigate to the Formbricks Folder
Navigate into the "formbricks" folder that contains all the files from the Formbricks One-Click setup.
```sh
cd formbricks
```
### Step 2: Create a Folder for SSL Certificates
Create a new folder named "certs" within the "formbricks" folder. Place your SSL certificate files (`fullchain.crt` and `cert.key`) in this directory.
```sh
mkdir certs
# Move your SSL certificate files to the certs folder
mv /path/to/your/fullchain.crt certs/
mv /path/to/your/cert.key certs/
```
### Step 3: Understand SSL Certificate Files
For a custom SSL setup, you need the following files:
- **fullchain.crt**: This file contains your SSL certificate along with the entire certificate chain. The certificate chain includes intermediate certificates that link your SSL certificate to a trusted root certificate.
- **cert.key**: This is your private key file. It is used to encrypt and decrypt data sent between your server and clients.
### Step 4: Update File Permissions
Ensure the directory and files have appropriate permissions:
```sh
sudo chown root:root certs/*
sudo chmod 600 certs/*
```
### Step 5: Update `traefik.yaml`
Update your `traefik.yaml` file to define entry points for HTTP and HTTPS traffic and set up a provider for Traefik to use Docker and a file-based configuration.
```yaml
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
providers:
docker:
watch: true
exposedByDefault: false
file:
directory: /etc/traefik/dynamic
```
### Step 6: Create `certs-traefik.yaml`
Create a `certs-traefik.yaml` file that specifies the path to your custom SSL certificate and key.
```yaml
tls:
certificates:
- certFile: /certs/fullchain.crt
keyFile: /certs/cert.key
```
### Step 7: Update `docker-compose.yml`
Update your `docker-compose.yml` file to enforce TLS and link to your custom SSL certificate. Here's an example configuration for both the Formbricks and Traefik services. The rest of the configuration should remain the same as the One-Click setup:
```yaml
services:
formbricks:
restart: always
image: ghcr.io/formbricks/formbricks:latest
depends_on:
- postgres
labels:
- "traefik.enable=true" # Enable Traefik for this service
- "traefik.http.routers.formbricks.rule=Host(`my-domain.com`)" # Use your actual domain or IP
- "traefik.http.routers.formbricks.entrypoints=websecure" # Use the websecure entrypoint (port 443 with TLS)
- "traefik.http.routers.formbricks.tls=true" # Enable TLS
- "traefik.http.services.formbricks.loadbalancer.server.port=3000" # Forward traffic to Formbricks on port 3000
ports:
- 3000:3000
volumes:
- uploads:/home/nextjs/apps/web/uploads/
<<: *environment
traefik:
image: "traefik:v2.7"
restart: always
container_name: "traefik"
depends_on:
- formbricks
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- ./traefik.yaml:/traefik.yaml
- ./acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/certs
- ./certs-traefik.yaml:/etc/traefik/dynamic/certs-traefik.yaml
```
### Summary
1. **Navigate to the Formbricks Folder**: Move into the "formbricks" directory.
2. **Create a Folder for SSL Certificates**: Create a "certs" folder and place your `fullchain.crt` and `cert.key` files inside it.
3. **Understand SSL Certificate Files**: Ensure you have the `fullchain.crt` and `cert.key` files.
4. **Update File Permissions**: Ensure the certificate files have the correct permissions.
5. **Update `traefik.yaml`**: Define entry points and remove certificate resolvers.
6. **Create `certs-traefik.yaml`**: Specify the paths to your SSL certificate and key.
7. **Update `docker-compose.yml`**: Configure Traefik labels to enforce TLS and mount the certificate directory.
This setup ensures that Formbricks uses your custom SSL certificate for secure communications, suitable for environments with special certificate requirements.

View File

@@ -8,7 +8,7 @@ export const metadata = {
# Advanced Setup
Quickly set up and start using Formbricks with our [official Docker image](https://github.com/formbricks/formbricks/pkgs/container/formbricks) that we've already built for you.
Quickly set up and start using Formbricks with our [official Docker image](https://github.com/formbricks/formbricks/pkgs/container/formbricks) that we've already built for you.
The pre-built image is ready-to-run, and it only requires minimal configuration on your part. It's as easy as downloading the Docker image and firing up the container.
@@ -104,20 +104,12 @@ You're now ready to start the Formbricks Docker setup. The following command wil
## Update
1. Stop the Formbricks stack
<Note>
Please take a look at our [migration guide](/self-hosting/migration-guide) for version specific steps to
update Formbricks.
</Note>
<Col>
<CodeGroup title="Stop the docker instance">
```bash
docker compose down
```
</CodeGroup>
</Col>
2. Pull the latest changes
1. Pull the latest Formbricks image
<Col>
<CodeGroup title="Pull the changes into docker">
@@ -130,8 +122,20 @@ You're now ready to start the Formbricks Docker setup. The following command wil
</Col>
3. Update env vars as necessary in the docker-compose file.
4. Re-start the Formbricks stack
2. Stop the Formbricks stack
<Col>
<CodeGroup title="Stop the docker instance">
```bash
docker compose down
```
</CodeGroup>
</Col>
3. Re-start the Formbricks stack with the updated image
<Col>
<CodeGroup title="Relaunch the Docker Instance">

View File

@@ -39,10 +39,10 @@ We have step-by-step guides to configure our third-party integrations with a sel
- [Airtable](#airtable)
- [Google Sheets](#google-sheets)
- [Notion](#notion)
- Make: We do not support [Make.com](http://Make.com) for Self-hosted instances yet! Please follow our Cloud guide [here](/integrations#make)
- Make: We do not support for self-hosted instances yet.
- [n8n](#n8n)
- [Slack](#slack)
- [Wordpress]: Wordpress setup is similar to steps mentioned in Cloud [here](/integrations#wordpress), just change the API Host to your self-hosted URL.
- Wordpress: Wordpress setup is similar to the [Cloud setup](/developer-docs/integrations/wordpress), just change the API Host to your self-hosted URL.
- [Zapier](#zapier)
<Note>
@@ -116,7 +116,7 @@ Integrating Google Sheets with a self-hosted Formbricks instance requires config
1. Go to the **[Google Cloud Console](https://console.cloud.google.com/)** and **create a new project**.
2. Enable necessary APIs:
- Now select the project you just created and go to the **APIs & Services** section.
- Click on the **Enable APIs and Services** button and search for **Google Sheets API** & **Google Drive API** and enable it.
- Click on the **Enable APIs and Services** button and search for **Google Sheets API** and enable it.
3. Configure OAuth Consent Screen:
- Go to **OAuth Consent screen** and select the appropriate User Type (External or Internal). Select **Internal** if you want only the users of your Google Workspace to be able to use the integration.
- Fill the required details:
@@ -128,12 +128,11 @@ Integrating Google Sheets with a self-hosted Formbricks instance requires config
- Click on the **Add or Remove Scopes** button and add the scopes:
- `https://www.googleapis.com/auth/userinfo.email`
- `https://www.googleapis.com/auth/spreadsheets`
- `https://www.googleapis.com/auth/drive`
- Click on the **Update** button. Verify the scopes and click on the **Save and Continue** button.
- Skip the **Test Users** section and click on the **Save and Continue** button.
1. View the OAuth Consent Screen summary and click on the **Back to Dashboard** button.
2. Register OAuth Client:
5. View the OAuth Consent Screen summary and click on the **Back to Dashboard** button.
6. Register OAuth Client:
- Navigate to **Credentials** > **Create Credentials** > **OAuth Client ID**.
- Select **Web Application** and set:
@@ -142,13 +141,10 @@ Integrating Google Sheets with a self-hosted Formbricks instance requires config
- Authorized redirect URIs: `https://<your-public-facing-url>/api/google-sheet/callback`
- Save and note the Client ID and Client Secret.
1. Copy the Client ID and Client Secret and set them as environment variables in your Formbricks instance:
7. Copy the Client ID and Client Secret and set them as environment variables in your Formbricks instance:
- `GOOGLE_SHEETS_CLIENT_ID`
- `GOOGLE_SHEETS_CLIENT_SECRET`
- `GOOGLE_SHEETS_REDIRECT_URL`
2. Enable Google Drive API:
- Go to the **APIs & Services** section and click on the **Enable APIs and Services** button.
- Search for **Google Drive API** and enable it.
Now just copy **GOOGLE_SHEETS_CLIENT_ID**, **GOOGLE_SHEETS_CLIENT_SECRET** and **GOOGLE_SHEETS_REDIRECT_URL** for your integration & add it to your **Formbricks environment variables** as in the docker compose file:

View File

@@ -9,30 +9,40 @@ export const metadata = {
## Overview
Formbricks core source code is under AGPL license on GitHub. Additionally, we also have additional features for bigger teams & enterprises under the Enterprise license for Self Hosting customers. Lets understand both in depth below:
The Formbricks Core source code is licensed under AGPLv3 and available on GitHub. Additionally, we offer features for bigger organisations & enterprises for self-hostesr under a separate Enterprise License.
<Note>
Want to present a proof of concept? Request a free 30-day Enterprise Edition trial by [filling out the form
below.](#30-day-trial-license-request) No call needed or strings attached: Just give us 24h to set up the
key and send it over 🤙
</Note>
## Enterprise Edition License
Additional to the AGPL licensed Formbricks core, the Formbricks repository contains code licensed under an **[Enterprise license](https://github.com/formbricks/formbricks/blob/main/packages/ee/LICENSE)**. This additional functionality is not part of the AGPLv3 licensed Formbricks core and is designed to meet the needs of larger teams and enterprises. This advanced functionality is already included in the Docker images, but you need an **Enterprise License Key** to unlock it. For the pricing, please refer to [Formbricks Pricing](https://formbricks.com/pricing).
Additional to the AGPLv3 licensed Formbricks core, the Formbricks repository contains code licensed under our **[Enterprise License](https://github.com/formbricks/formbricks/blob/main/packages/ee/LICENSE)**. This additional functionality is not part of the AGPLv3 licensed Formbricks core and is designed to meet the needs of larger teams and enterprises. This advanced functionality is already included in the Docker images, but you need an **Enterprise License Key** to unlock it. For the pricing, please refer to [Formbricks Pricing](https://formbricks.com/pricing).
### When do I need an Enterprise License?
| | Community Edition | Enterprise License |
| -------------------------------------------------------- | ----------------- | -------------------- |
| Self-host for commercial purposes | ✅ | No EE license needed |
| To make changes to the code base (happy to publish them) | ✅ | No EE license needed |
| Unlimited responses | ✅ | No EE license needed |
| Unlimited surveys | ✅ | No EE license needed |
| Remove branding | ✅ | No EE license needed |
| SSO | ✅ | No EE license needed |
| Use any of the other 100 features | ✅ | No EE license needed |
| Team roles | ❌ | ✅ |
| Multi-language surveys | ❌ | ✅ |
| Advanced targeting / Segments | ❌ | ✅ |
| Make code changes and keep private | ❌ | ✅ |
| | Community Edition | Enterprise License |
| ----------------------------------------------------------- | ----------------- | -------------------- |
| Self-host for commercial purposes | ✅ | No EE license needed |
| Make changes to the code base (have to publish all changes) | ✅ | No EE license needed |
| Unlimited responses | ✅ | No EE license needed |
| Unlimited surveys | ✅ | No EE license needed |
| Remove branding | ✅ | No EE license needed |
| SSO | ✅ | No EE license needed |
| Use any of the other 100 features | ✅ | No EE license needed |
| Organization access roles | ❌ | ✅ |
| Multi-language surveys | ❌ | ✅ |
| Advanced targeting / Segments | ❌ | ✅ |
| Make code changes and **keep private** | ❌ | ✅ |
Ready to get started with the Enterprise Edition? Fill out our form below and we'll reach out to you.
## 30-day Trial License Request
Many organisations want to do an internal test run with the Enterprise Edition. To make that really easy, we now offer a 30-day trial license. Just fill out the form below and we'll send you a license key within 24 hours (business days):
<div
style={{
position: "relative",
@@ -50,11 +60,11 @@ Ready to get started with the Enterprise Edition? Fill out our form below and we
### The AGPL Formbricks Core
The Formbricks core application is licensed under the **[AGPLv3 Open Source License](https://github.com/formbricks/formbricks/blob/main/LICENSE)**. The core application is fully functional and includes everything you need to design & run link surveys, website surveys and in-app surveys. You can use the software for free for personal and commercial use. You're also allowed to create and distribute modified versions as long as you document the changes you make incl. date. The AGPL license requires you to publish your modified version under the AGPLv3 license as well.
The Formbricks core application is licensed under the **[AGPLv3 Open Source License](https://github.com/formbricks/formbricks/blob/main/LICENSE)**. The core application is fully functional and includes everything you need to design & run link surveys, website surveys and in-app surveys. You can use the software for free for personal and commercial use. You're also allowed to create and distribute modified versions as long as you document the changes you make incl. date and **publish your complete code under the AGPLv3 license as well.**
### The Enterprise Edition
Additional to the AGPL licensed Formbricks core, this repository contains code licensed under an Enterprise license. The **[code](https://github.com/formbricks/formbricks/tree/main/packages/ee)** and **[license](https://github.com/formbricks/formbricks/blob/main/packages/ee/LICENSE)** for the enterprise functionality can be found in the `/packages/ee` folder of this repository. This additional functionality is not part of the AGPLv3 licensed Formbricks core and is designed to meet the needs of larger teams and enterprises. This advanced functionality is already included in the Docker images, but you need an **Enterprise License Key** to unlock it.
Additional to the AGPL licensed Formbricks core, this repository contains code licensed under an Enterprise License. The **[code](https://github.com/formbricks/formbricks/tree/main/packages/ee)** and **[license](https://github.com/formbricks/formbricks/blob/main/packages/ee/LICENSE)** for the enterprise functionality can be found in the `/packages/ee` folder of this repository. This additional functionality is not part of the AGPLv3 licensed Formbricks core and is designed to meet the needs of larger teams and enterprises. This advanced functionality is already included in the Docker images, but you need an **Enterprise License Key** to unlock it.
## White-Labeling Formbricks and Other Licensing Needs
@@ -62,6 +72,6 @@ We currently do not offer Formbricks white-labeled. Any other needs? [Send us an
## Why charge for Enterprise Features?
The Enterprise Edition and White-Label Licenses allow us to fund the development of Formbricks sustainably. It guarantees that the open-source surveying infrastructure we're building will be around for decades to come.
The Enterprise Edition allows us to fund the development of Formbricks sustainably. It guarantees that the open-source surveying infrastructure we're building will be around for decades to come.
**Having more questions?**: [Join our Discord!](https://formbricks.com/discord)
**Any more questions?**: [Send us an email](mailto:johannes@formbricks.com) or [book a call with us.](https://cal.com/johannes/license)

View File

@@ -17,10 +17,16 @@ Formbricks v2.0 comes with huge features such as Multi-Language Surveys and Adva
the upgrade. Follow the below steps thoroughly to upgrade your Formbricks instance to v2.0.
</Note>
and
<Note>
If you've used the Formbricks Enterprise Edition with a free beta license key, your instance will be
downgraded to the Community Edition 2.0. You find all license details on the [license
page.](/self-hosting/license/)
</Note>
<Note>
If you've used the Formbricks Enterprise Edition with a free beta license key, your instance will be downgraded to the Community Edition 2.0. You find all license details on the [license page.](/self-hosting/license/)
We are moving from DockerHub to Github Packages for our images. If you are still pulling the images from
DockerHub please change `image: formbricks/formbricks:latest` to
`image:ghcr.io/formbricks/formbricks:latest` in your `docker-compose.yml` file.
</Note>
### Steps to Migrate
@@ -35,7 +41,7 @@ To run all these steps, please navigate to the `formbricks` folder where your `d
<CodeGroup title="Backup Postgres">
```bash
docker exec formbricks-quickstart-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbricks_pre_v2.0_$(date +%Y%m%d_%H%M%S).dump
docker exec formbricks-postgres-1 pg_dump -Fc -U postgres -d formbricks > formbricks_pre_v2.0_$(date +%Y%m%d_%H%M%S).dump
```
</CodeGroup>
@@ -51,7 +57,19 @@ docker exec formbricks-quickstart-postgres-1 pg_dump -Fc -U postgres -d formbric
restore scenario you will need to use `psql` then with an empty `formbricks` database.
</Note>
2. Stop the running Formbricks instance & remove the related containers:
2. Pull the latest version of Formbricks:
<Col>
<CodeGroup title="Stop the containers">
```bash
docker-compose pull
```
</CodeGroup>
</Col>
3. Stop the running Formbricks instance & remove the related containers:
<Col>
<CodeGroup title="Stop the containers">
@@ -63,7 +81,7 @@ docker-compose down
</CodeGroup>
</Col>
3. Restarting the containers will automatically pull the latest version of Formbricks:
4. Restarting the containers with the latest version of Formbricks:
<Col>
<CodeGroup title="Restart the containers">
@@ -75,7 +93,7 @@ docker-compose up -d
</CodeGroup>
</Col>
4. Now let's migrate the data to the latest schema:
5. Now let's migrate the data to the latest schema:
<Note>To find your Docker Network name for your Postgres Database, find it using `docker network ls`</Note>
@@ -83,6 +101,7 @@ docker-compose up -d
<CodeGroup title="Migrate the data">
```bash
docker pull ghcr.io/formbricks/data-migrations:latest && \
docker run --rm \
--network=formbricks_default \
-e DATABASE_URL="postgresql://postgres:postgres@postgres:5432/formbricks?schema=public" \
@@ -95,7 +114,7 @@ docker run --rm \
The above command will migrate your data to the latest schema. This is a crucial step to migrate your existing data to the new structure. Only if the script runs successful, changes are made to the database. The script can safely run multiple times.
5. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
6. That's it! Once the migration is complete, you can **now access your Formbricks instance** at the same URL as before.
### App Surveys with @formbricks/js

View File

@@ -6,7 +6,7 @@ import StepTwo from "./images/StepTwo.webp";
export const metadata = {
title: "Using Actions in Formbricks | Fine-tuning Session Moments",
description:
"Dive deep into how actions in Formbricks help products and teams to engage active sessions at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine public facing websites' targeting and generate richer, more detailed insights.",
"Dive deep into how actions in Formbricks help products and organizations to engage active sessions at precise moments in their journey. Discover the power of actions, from coding to no-code setups, to refine public facing websites' targeting and generate richer, more detailed insights.",
};
#### Website Surveys

View File

@@ -32,7 +32,7 @@ export const Layout = ({
</Link>
</div>
<Header />
<Navigation className="hidden lg:mt-10 lg:block" />
<Navigation className="hidden lg:mt-10 lg:block" isMobile={false} />
</div>
</motion.header>
<div className="relative flex h-full flex-col px-4 pt-14 sm:px-6 lg:px-8">

View File

@@ -90,7 +90,7 @@ const MobileNavigationDialog = ({ isOpen, close }: { isOpen: boolean; close: ()
<motion.div
layoutScroll
className="ring-zinc-900/7.5 fixed bottom-0 left-0 top-14 w-full overflow-y-auto bg-white px-4 pb-4 pt-6 shadow-lg shadow-zinc-900/10 ring-1 min-[416px]:max-w-sm sm:px-6 sm:pb-10 dark:bg-zinc-900 dark:ring-zinc-800">
<Navigation />
<Navigation isMobile={true} />
</motion.div>
</Transition.Child>
</Dialog.Panel>

View File

@@ -46,25 +46,41 @@ const NavLink = ({
active = false,
isAnchorLink = false,
}: {
href: string;
href?: string;
children: React.ReactNode;
active: boolean;
isAnchorLink?: boolean;
}) => {
return (
<Link
href={href}
aria-current={active ? "page" : undefined}
className={clsx(
"flex justify-between gap-2 py-1 pr-3 text-sm transition",
isAnchorLink ? "pl-7" : "pl-4",
active
? "rounded-r-md bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-white"
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
)}>
<span className="flex w-full truncate">{children}</span>
</Link>
const commonClasses = clsx(
"flex justify-between gap-2 py-1 pr-3 text-sm transition",
isAnchorLink ? "pl-7" : "pl-4",
active
? "rounded-r-md bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-white"
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
);
if (href) {
return (
<Link
href={href}
aria-current={active ? "page" : undefined}
className={clsx(
"flex justify-between gap-2 py-1 pr-3 text-sm transition",
isAnchorLink ? "pl-7" : "pl-4",
active
? "rounded-r-md bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-white"
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
)}>
<span className="flex w-full truncate">{children}</span>
</Link>
);
} else {
return (
<div aria-current={active ? "page" : undefined} className={commonClasses}>
<span className="flex w-full truncate">{children}</span>
</div>
);
}
};
const VisibleSectionHighlight = ({ group, pathname }: { group: NavGroup; pathname: string }) => {
@@ -131,6 +147,7 @@ const NavigationGroup = ({
setActiveGroup,
openGroups,
setOpenGroups,
isMobile,
}: {
group: NavGroup;
className?: string;
@@ -138,6 +155,7 @@ const NavigationGroup = ({
setActiveGroup: (group: NavGroup | null) => void;
openGroups: string[];
setOpenGroups: (groups: string[]) => void;
isMobile: boolean;
}) => {
const isInsideMobileNavigation = useIsInsideMobileNavigation();
const pathname = usePathname();
@@ -171,13 +189,15 @@ const NavigationGroup = ({
{group.links.map((link) => (
<motion.li key={link.title} layout="position" className="relative">
{link.href ? (
<NavLink href={link.href} active={!!pathname?.startsWith(link.href)}>
<NavLink
href={isMobile && link.children ? "" : link.href}
active={!!pathname?.startsWith(link.href)}>
{link.title}
</NavLink>
) : (
<div onClick={() => toggleParentTitle(link.title)}>
<NavLink
href={link.children?.[0]?.href || ""}
href={!isMobile ? link.children?.[0]?.href || "" : undefined}
active={
!!(
isParentOpen(link.title) &&
@@ -197,7 +217,7 @@ const NavigationGroup = ({
</div>
)}
<AnimatePresence mode="popLayout" initial={false}>
{link.children && isParentOpen(link.title) && (
{isActiveGroup && link.children && isParentOpen(link.title) && (
<motion.ul
role="list"
initial={{ opacity: 0 }}
@@ -221,7 +241,11 @@ const NavigationGroup = ({
);
};
export const Navigation = (props: React.ComponentPropsWithoutRef<"nav">) => {
interface NavigationProps extends React.ComponentPropsWithoutRef<"nav"> {
isMobile: boolean;
}
export const Navigation = ({ isMobile, ...props }: NavigationProps) => {
const [activeGroup, setActiveGroup] = useState<NavGroup | null>(navigation[0]);
const [openGroups, setOpenGroups] = useState<string[]>([]);
@@ -237,6 +261,7 @@ export const Navigation = (props: React.ComponentPropsWithoutRef<"nav">) => {
setActiveGroup={setActiveGroup}
openGroups={openGroups}
setOpenGroups={setOpenGroups}
isMobile={isMobile}
/>
))}
<li className="sticky bottom-0 z-10 mt-6 min-[416px]:hidden">

View File

@@ -35,9 +35,10 @@ export const navigation: Array<NavGroup> = [
{ title: "Advanced Targeting", href: "/app-surveys/advanced-targeting" },
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
{ title: "Recontact Options", href: "/app-surveys/recontact" },
{ title: "Hidden Fields", href: "/global/hidden-fields" }, // global
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
{ title: "User Metadata", href: "/global/metadata" }, // global
{ title: "Custom Styling", href: "/global/custom-styling" }, // global
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
{ title: "Conditional Logic", href: "/global/conditional-logic" }, // global
{ title: "Custom Start & End Conditions", href: "/global/custom-start-end-conditions" }, // global
{ title: "Recall Functionality", href: "/global/recall" }, // global
@@ -57,9 +58,10 @@ export const navigation: Array<NavGroup> = [
{ title: "Actions & Targeting", href: "/website-surveys/actions-and-targeting" },
{ title: "Show Survey to % of users", href: "/global/show-survey-to-percent-of-users" }, // app and website
{ title: "Recontact Options", href: "/app-surveys/recontact" },
{ title: "Hidden Fields", href: "/global/hidden-fields" }, // global
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" }, // global
{ title: "User Metadata", href: "/global/metadata" }, // global
{ title: "Custom Styling", href: "/global/custom-styling" }, // global
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
{ title: "Conditional Logic", href: "/global/conditional-logic" }, // global
{ title: "Custom Start & End Conditions", href: "/global/custom-start-end-conditions" }, // global
{ title: "Recall Functionality", href: "/global/recall" }, // global
@@ -84,7 +86,7 @@ export const navigation: Array<NavGroup> = [
{ title: "Embed Surveys Anywhere", href: "/link-surveys/embed-surveys" },
{ title: "Multi Language Surveys", href: "/global/multi-language-surveys" },
{ title: "User Metadata", href: "/global/metadata" },
{ title: "Custom Styling", href: "/global/custom-styling" },
{ title: "Custom Styling", href: "/global/overwrite-styling" }, // global
{ title: "Conditional Logic", href: "/global/conditional-logic" },
{ title: "Custom Start & End Conditions", href: "/global/custom-start-end-conditions" },
{ title: "Recall Functionality", href: "/global/recall" },
@@ -95,11 +97,19 @@ export const navigation: Array<NavGroup> = [
},
],
},
{
title: "Core Features",
links: [
{ title: "Access Roles", href: "/global/access-roles" },
{ title: "Styling Theme", href: "/global/styling-theme" },
],
},
{
title: "Self-Hosting",
links: [
{ title: "Overview", href: "/self-hosting/overview" },
{ title: "One-Click Setup", href: "/self-hosting/one-click" },
{ title: "Custom SSL Certificate", href: "/self-hosting/custom-ssl" },
{ title: "Docker Setup", href: "/self-hosting/docker" },
{ title: "Migration Guide", href: "/self-hosting/migration-guide" },
{ title: "Configuration", href: "/self-hosting/configuration" },

View File

@@ -111,6 +111,11 @@ const nextConfig = {
destination: "/developer-docs/integrations/:path",
permanent: true,
},
{
source: "/global/custom-styling",
destination: "/global/overwrite-styling",
permanent: true,
},
];
},
};

View File

@@ -56,7 +56,7 @@
"remark-gfm": "^4.0.0",
"remark-mdx": "^3.0.1",
"schema-dts": "^1.1.2",
"sharp": "^0.33.3",
"sharp": "^0.33.4",
"shiki": "^0.14.7",
"simple-functional-loader": "^1.2.1",
"tailwindcss": "^3.4.3",

View File

@@ -18,12 +18,11 @@ RUN turbo prune @formbricks/web --docker
FROM base AS installer
# Enable corepack and prepare pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN corepack enable
# Install necessary build tools and compilers
RUN apk update && apk add --no-cache g++ cmake make gcc python3 openssl-dev jq
# Set hardcoded environment variables
ENV DATABASE_URL="postgresql://placeholder:for@build:5432/gets_overwritten_at_runtime?schema=public"
ENV NEXTAUTH_SECRET="placeholder_for_next_auth_of_64_chars_get_overwritten_at_runtime"
@@ -59,7 +58,7 @@ RUN jq -r '.devDependencies.prisma' packages/database/package.json > /prisma_ver
## step 3: setup production runner
#
FROM base AS runner
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN corepack enable
RUN apk add --no-cache curl \
&& apk add --no-cache supercronic \
@@ -92,5 +91,5 @@ RUN mkdir -p /home/nextjs/apps/web/uploads/
VOLUME /home/nextjs/apps/web/uploads/
CMD supercronic -quiet /app/docker/cronjobs & \
(cd packages/database && pnpm db:migrate:deploy) && \
(cd packages/database && npm run db:migrate:deploy) && \
exec node apps/web/server.js

View File

@@ -7,7 +7,7 @@ import { redirect } from "next/navigation";
import { authOptions } from "@formbricks/lib/authOptions";
import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
import { AuthorizationError } from "@formbricks/types/errors";
import { DevEnvironmentBanner } from "@formbricks/ui/DevEnvironmentBanner";
import { ToasterClient } from "@formbricks/ui/ToasterClient";
@@ -22,9 +22,9 @@ const EnvLayout = async ({ children, params }) => {
throw new AuthorizationError("Not authorized");
}
const team = await getTeamByEnvironmentId(params.environmentId);
if (!team) {
throw new Error("Team not found");
const organization = await getOrganizationByEnvironmentId(params.environmentId);
if (!organization) {
throw new Error("Organization not found");
}
const environment = await getEnvironment(params.environmentId);
@@ -39,11 +39,11 @@ const EnvLayout = async ({ children, params }) => {
<PosthogIdentify
session={session}
environmentId={params.environmentId}
teamId={team.id}
teamName={team.name}
inAppSurveyBillingStatus={team.billing.features.inAppSurvey.status}
linkSurveyBillingStatus={team.billing.features.linkSurvey.status}
userTargetingBillingStatus={team.billing.features.userTargeting.status}
organizationId={organization.id}
organizationName={organization.name}
inAppSurveyBillingStatus={organization.billing.features.inAppSurvey.status}
linkSurveyBillingStatus={organization.billing.features.linkSurvey.status}
userTargetingBillingStatus={organization.billing.features.userTargeting.status}
/>
<FormbricksClient session={session} />
<ToasterClient />

View File

@@ -4,6 +4,7 @@ import { PlusIcon, TrashIcon } from "lucide-react";
import { useState } from "react";
import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/utils";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyAddressQuestion } from "@formbricks/types/surveys";
import { AdvancedOptionToggle } from "@formbricks/ui/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/Button";
@@ -18,6 +19,7 @@ interface AddressQuestionFormProps {
isInvalid: boolean;
selectedLanguageCode: string;
setSelectedLanguageCode: (language: string) => void;
attributeClasses: TAttributeClass[];
}
export const AddressQuestionForm = ({
@@ -28,6 +30,7 @@ export const AddressQuestionForm = ({
localSurvey,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: AddressQuestionFormProps): JSX.Element => {
const [showSubheader, setShowSubheader] = useState(!!question.subheader);
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages ?? []);
@@ -37,12 +40,14 @@ export const AddressQuestionForm = ({
<QuestionFormInput
id="headline"
value={question.headline}
label={"Question*"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div>
@@ -52,12 +57,14 @@ export const AddressQuestionForm = ({
<QuestionFormInput
id="subheader"
value={question.subheader}
label={"Description"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>

View File

@@ -1,3 +1,4 @@
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys";
import { LogicEditor } from "./LogicEditor";
@@ -8,6 +9,7 @@ interface AdvancedSettingsProps {
questionIdx: number;
localSurvey: TSurvey;
updateQuestion: (questionIdx: number, updatedAttributes: any) => void;
attributeClasses: TAttributeClass[];
}
export const AdvancedSettings = ({
@@ -15,6 +17,7 @@ export const AdvancedSettings = ({
questionIdx,
localSurvey,
updateQuestion,
attributeClasses,
}: AdvancedSettingsProps) => {
return (
<div>
@@ -24,6 +27,7 @@ export const AdvancedSettings = ({
updateQuestion={updateQuestion}
localSurvey={localSurvey}
questionIdx={questionIdx}
attributeClasses={attributeClasses}
/>
</div>

View File

@@ -2,11 +2,13 @@
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
import { UseFormReturn } from "react-hook-form";
import { cn } from "@formbricks/lib/cn";
import { TProductStyling } from "@formbricks/types/product";
import { TSurveyBackgroundBgType, TSurveyStyling } from "@formbricks/types/surveys";
import { TSurveyStyling } from "@formbricks/types/surveys";
import { Badge } from "@formbricks/ui/Badge";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@formbricks/ui/Form";
import { Slider } from "@formbricks/ui/Slider";
import { SurveyBgSelectorTab } from "./SurveyBgSelectorTab";
@@ -14,52 +16,24 @@ import { SurveyBgSelectorTab } from "./SurveyBgSelectorTab";
interface BackgroundStylingCardProps {
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
styling: TSurveyStyling | TProductStyling | null;
setStyling: React.Dispatch<React.SetStateAction<TSurveyStyling | TProductStyling>>;
colors: string[];
isSettingsPage?: boolean;
disabled?: boolean;
environmentId: string;
isUnsplashConfigured: boolean;
form: UseFormReturn<TProductStyling | TSurveyStyling>;
}
export const BackgroundStylingCard = ({
open,
setOpen,
styling,
setStyling,
colors,
isSettingsPage = false,
disabled,
environmentId,
isUnsplashConfigured,
form,
}: BackgroundStylingCardProps) => {
const { bgType, brightness } = styling?.background ?? {};
const handleBgChange = (color: string, type: TSurveyBackgroundBgType) => {
const { background } = styling ?? {};
setStyling({
...styling,
background: {
...background,
bg: color,
bgType: type,
brightness: 100,
},
});
};
const handleBrightnessChange = (percent: number) => {
setStyling((prev) => ({
...prev,
background: {
...prev.background,
brightness: percent,
},
}));
};
return (
<Collapsible.Root
open={open}
@@ -101,48 +75,66 @@ export const BackgroundStylingCard = ({
</div>
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent>
<hr className="py-1 text-slate-600" />
<div className="flex flex-col gap-3 p-3">
{/* Background */}
<div className="p-3">
<div className="ml-2">
<h3 className="text-sm font-semibold text-slate-700">Change background</h3>
<p className="text-xs font-normal text-slate-500">
Pick a background from our library or upload your own.
</p>
</div>
<SurveyBgSelectorTab
styling={styling}
handleBgChange={handleBgChange}
colors={colors}
bgType={bgType}
environmentId={environmentId}
isUnsplashConfigured={isUnsplashConfigured}
/>
</div>
{/* Overlay */}
<div className="flex flex-col gap-4 p-3">
<div className="ml-2">
<h3 className="text-sm font-semibold text-slate-700">Background overlay</h3>
<p className="text-xs font-normal text-slate-500">
Darken or lighten background of your choice.
</p>
</div>
<div>
<div className="ml-2 flex flex-col justify-center">
<div className="flex flex-col gap-4">
<div className="flex flex-col justify-center rounded-lg border bg-slate-50 p-6">
<Slider
value={[brightness ?? 100]}
max={200}
onValueChange={(value) => {
handleBrightnessChange(value[0]);
}}
/>
</div>
<hr className="pt-1 text-slate-600" />
<div className="flex flex-col gap-6 p-6 pt-2">
<FormField
control={form.control}
name="background"
render={({ field }) => (
<FormItem>
<div>
<FormLabel>Change background</FormLabel>
<FormDescription>Pick a background from our library or upload your own.</FormDescription>
</div>
<FormControl>
<SurveyBgSelectorTab
bg={field.value?.bg ?? ""}
handleBgChange={(bg: string, bgType: string) => {
field.onChange({
...field.value,
bg,
bgType,
brightness: 100,
});
}}
colors={colors}
bgType={field.value?.bgType ?? "color"}
environmentId={environmentId}
isUnsplashConfigured={isUnsplashConfigured}
/>
</FormControl>
</FormItem>
)}
/>
<div className="flex flex-col justify-center">
<div className="flex flex-col gap-4">
<div className="flex flex-col justify-center ">
<FormField
control={form.control}
name="background.brightness"
render={({ field }) => (
<FormItem>
<div>
<FormLabel>Brightness</FormLabel>
<FormDescription>Darken or lighten background of your choice.</FormDescription>
</div>
<FormControl>
<div className="rounded-lg border bg-slate-50 p-6">
<Slider
value={[field.value ?? 100]}
max={200}
onValueChange={(value) => {
field.onChange(value[0]);
}}
/>
</div>
</FormControl>
</FormItem>
)}
/>
</div>
</div>
</div>

View File

@@ -3,6 +3,7 @@
import { useState } from "react";
import { LocalizedEditor } from "@formbricks/ee/multiLanguage/components/LocalizedEditor";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyCTAQuestion } from "@formbricks/types/surveys";
import { Input } from "@formbricks/ui/Input";
import { Label } from "@formbricks/ui/Label";
@@ -18,6 +19,7 @@ interface CTAQuestionFormProps {
selectedLanguageCode: string;
setSelectedLanguageCode: (languageCode: string) => void;
isInvalid: boolean;
attributeClasses: TAttributeClass[];
}
export const CTAQuestionForm = ({
@@ -29,6 +31,7 @@ export const CTAQuestionForm = ({
localSurvey,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: CTAQuestionFormProps): JSX.Element => {
const [firstRender, setFirstRender] = useState(true);
@@ -37,12 +40,14 @@ export const CTAQuestionForm = ({
<QuestionFormInput
id="headline"
value={question.headline}
label={"Question*"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div className="mt-3">
@@ -87,6 +92,7 @@ export const CTAQuestionForm = ({
<QuestionFormInput
id="buttonLabel"
value={question.buttonLabel}
label={`"Next" Button Label`}
localSurvey={localSurvey}
questionIdx={questionIdx}
maxLength={48}
@@ -95,12 +101,14 @@ export const CTAQuestionForm = ({
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
{questionIdx !== 0 && (
<QuestionFormInput
id="backButtonLabel"
value={question.backButtonLabel}
label={`"Back" Button Label`}
localSurvey={localSurvey}
questionIdx={questionIdx}
maxLength={48}
@@ -109,6 +117,7 @@ export const CTAQuestionForm = ({
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
)}
</div>
@@ -130,21 +139,20 @@ export const CTAQuestionForm = ({
)}
{!question.required && (
<div className="mt-3 flex-1">
<Label htmlFor="buttonLabel">Skip Button Label</Label>
<div className="mt-2">
<QuestionFormInput
id="dismissButtonLabel"
value={question.dismissButtonLabel}
localSurvey={localSurvey}
questionIdx={questionIdx}
placeholder={"skip"}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
/>
</div>
<div className="mt-2">
<QuestionFormInput
id="dismissButtonLabel"
value={question.dismissButtonLabel}
label={"Skip Button Label"}
localSurvey={localSurvey}
questionIdx={questionIdx}
placeholder={"skip"}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>
)}
</form>

View File

@@ -2,6 +2,7 @@ import { PlusIcon, TrashIcon } from "lucide-react";
import { useState } from "react";
import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/utils";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyCalQuestion } from "@formbricks/types/surveys";
import { Button } from "@formbricks/ui/Button";
import { Input } from "@formbricks/ui/Input";
@@ -17,6 +18,7 @@ interface CalQuestionFormProps {
selectedLanguageCode: string;
setSelectedLanguageCode: (language: string) => void;
isInvalid: boolean;
attributeClasses: TAttributeClass[];
}
export const CalQuestionForm = ({
@@ -27,6 +29,7 @@ export const CalQuestionForm = ({
selectedLanguageCode,
setSelectedLanguageCode,
isInvalid,
attributeClasses,
}: CalQuestionFormProps): JSX.Element => {
const [showSubheader, setShowSubheader] = useState(!!question.subheader);
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
@@ -36,12 +39,14 @@ export const CalQuestionForm = ({
<QuestionFormInput
id="headline"
value={question.headline}
label={"Question*"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div>
{showSubheader && (
@@ -50,12 +55,14 @@ export const CalQuestionForm = ({
<QuestionFormInput
id="subheader"
value={question.subheader}
label={"Description"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>

View File

@@ -2,157 +2,47 @@
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
import React, { useMemo } from "react";
import React from "react";
import { UseFormReturn } from "react-hook-form";
import { cn } from "@formbricks/lib/cn";
import { COLOR_DEFAULTS } from "@formbricks/lib/styling/constants";
import { TProduct, TProductStyling } from "@formbricks/types/product";
import { TCardArrangementOptions } from "@formbricks/types/styling";
import { TSurveyStyling, TSurveyType } from "@formbricks/types/surveys";
import { Badge } from "@formbricks/ui/Badge";
import { CardArrangementTabs } from "@formbricks/ui/CardArrangementTabs";
import { ColorPicker } from "@formbricks/ui/ColorPicker";
import { Label } from "@formbricks/ui/Label";
import { ColorSelector } from "@formbricks/ui/ColorSelector";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@formbricks/ui/Form";
import { Slider } from "@formbricks/ui/Slider";
import { CardArrangement, ColorSelectorWithLabel } from "@formbricks/ui/Styling";
import { Switch } from "@formbricks/ui/Switch";
type CardStylingSettingsProps = {
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
styling: TSurveyStyling | TProductStyling | null;
setStyling: React.Dispatch<React.SetStateAction<TSurveyStyling | TProductStyling>>;
isSettingsPage?: boolean;
surveyType?: TSurveyType;
disabled?: boolean;
localProduct: TProduct;
product: TProduct;
form: UseFormReturn<TProductStyling | TSurveyStyling>;
};
export const CardStylingSettings = ({
setStyling,
styling,
isSettingsPage = false,
surveyType,
disabled,
open,
localProduct,
product,
setOpen,
form,
}: CardStylingSettingsProps) => {
const isAppSurvey = surveyType === "app" || surveyType === "website";
const cardBgColor = styling?.cardBackgroundColor?.light || COLOR_DEFAULTS.cardBackgroundColor;
const surveyTypeDerived = isAppSurvey ? "App / Website" : "Link";
const isLogoVisible = !!product.logo?.url;
const isLogoHidden = styling?.isLogoHidden ?? false;
const isLogoVisible = !!localProduct.logo?.url;
const linkSurveyCardArrangement = styling?.cardArrangement?.linkSurveys ?? "straight";
const inAppSurveyCardArrangement = styling?.cardArrangement?.appSurveys ?? "straight";
const setCardBgColor = (color: string) => {
setStyling((prev) => ({
...prev,
cardBackgroundColor: {
...(prev.cardBackgroundColor ?? {}),
light: color,
},
}));
};
const cardBorderColor = styling?.cardBorderColor?.light || COLOR_DEFAULTS.cardBorderColor;
const setCardBorderColor = (color: string) => {
setStyling((prev) => ({
...prev,
cardBorderColor: {
...(prev.cardBorderColor ?? {}),
light: color,
},
}));
};
const cardShadowColor = styling?.cardShadowColor?.light || COLOR_DEFAULTS.cardShadowColor;
const setCardShadowColor = (color: string) => {
setStyling((prev) => ({
...prev,
cardShadowColor: {
...(prev.cardShadowColor ?? {}),
light: color,
},
}));
};
const isHighlightBorderAllowed = !!styling?.highlightBorderColor;
const setIsHighlightBorderAllowed = (open: boolean) => {
if (!open) {
const { highlightBorderColor, ...rest } = styling ?? {};
setStyling({
...rest,
});
} else {
setStyling((prev) => ({
...prev,
highlightBorderColor: {
...(prev.highlightBorderColor ?? {}),
light: COLOR_DEFAULTS.highlightBorderColor,
},
}));
}
};
const highlightBorderColor = styling?.highlightBorderColor?.light || COLOR_DEFAULTS.highlightBorderColor;
const setHighlightBorderColor = (color: string) => {
setStyling((prev) => ({
...prev,
highlightBorderColor: {
...(prev.highlightBorderColor ?? {}),
light: color,
},
}));
};
const roundness = styling?.roundness ?? 8;
const setRoundness = (value: number) => {
setStyling((prev) => ({
...prev,
roundness: value,
}));
};
const setCardArrangement = (arrangement: TCardArrangementOptions, surveyType: TSurveyType) => {
const newCardArrangement = {
linkSurveys: linkSurveyCardArrangement,
appSurveys: inAppSurveyCardArrangement,
};
if (surveyType === "link") {
newCardArrangement.linkSurveys = arrangement;
} else if (surveyType === "app" || surveyType === "website") {
newCardArrangement.appSurveys = arrangement;
}
setStyling((prev) => ({
...prev,
cardArrangement: newCardArrangement,
}));
};
const toggleProgressBarVisibility = (hideProgressBar: boolean) => {
setStyling({
...styling,
hideProgressBar,
});
};
const toggleLogoVisibility = () => {
setStyling((prev) => ({
...prev,
isLogoHidden: !prev.isLogoHidden,
}));
};
const hideProgressBar = useMemo(() => {
return styling?.hideProgressBar;
}, [styling]);
const linkCardArrangement = form.watch("cardArrangement.linkSurveys") ?? "simple";
const appCardArrangement = form.watch("cardArrangement.appSurveys") ?? "simple";
const roundness = form.watch("roundness") ?? 8;
return (
<Collapsible.Root
@@ -194,107 +84,225 @@ export const CardStylingSettings = ({
<hr className="py-1 text-slate-600" />
<div className="flex flex-col gap-6 p-6 pt-2">
<div className="flex max-w-xs flex-col gap-4">
<div className="flex flex-col">
<h3 className="text-sm font-semibold text-slate-700">Roundness</h3>
<p className="text-xs text-slate-500">Change the border radius of the card and the inputs.</p>
</div>
<div className="flex flex-col justify-center rounded-lg border bg-slate-50 p-6">
<Slider value={[roundness]} max={22} onValueChange={(value) => setRoundness(value[0])} />
</div>
</div>
<ColorSelectorWithLabel
label="Card background color"
color={cardBgColor}
setColor={setCardBgColor}
description="Change the background color of the card."
/>
<ColorSelectorWithLabel
label="Card border color"
color={cardBorderColor}
setColor={setCardBorderColor}
description="Change the border color of the card."
/>
<ColorSelectorWithLabel
label="Card shadow color"
color={cardShadowColor}
setColor={setCardShadowColor}
description="Change the shadow color of the card."
/>
<CardArrangement
surveyType={isAppSurvey ? "app" : "link"}
activeCardArrangement={isAppSurvey ? inAppSurveyCardArrangement : linkSurveyCardArrangement}
setActiveCardArrangement={setCardArrangement}
/>
<>
<div className="flex items-center space-x-1">
<Switch
id="hideProgressBar"
checked={!!hideProgressBar}
onCheckedChange={(checked) => toggleProgressBarVisibility(checked)}
/>
<Label htmlFor="hideProgressBar" className="cursor-pointer">
<div className="ml-2">
<h3 className="text-sm font-semibold text-slate-700">Hide progress bar</h3>
<p className="text-xs font-normal text-slate-500">
Disable the visibility of survey progress.
</p>
</div>
</Label>
</div>
{isLogoVisible && (!surveyType || surveyType === "link") && !isSettingsPage && (
<div className="flex items-center space-x-1">
<Switch id="isLogoHidden" checked={isLogoHidden} onCheckedChange={toggleLogoVisibility} />
<Label htmlFor="isLogoHidden" className="cursor-pointer">
<div className="ml-2 flex flex-col">
<div className="flex items-center gap-2">
<h3 className="text-sm font-semibold text-slate-700">Hide logo</h3>
<Badge text="Link Surveys" type="gray" size="normal" />
</div>
<p className="text-xs font-normal text-slate-500">
Hides the logo in this specific survey
</p>
<div className="flex flex-col justify-center">
<FormField
control={form.control}
name="roundness"
render={() => (
<FormItem>
<div>
<FormLabel>Roundness</FormLabel>
<FormDescription>Change the border radius of the card and the inputs.</FormDescription>
</div>
</Label>
</div>
)}
{(!surveyType || isAppSurvey) && (
<div className="flex max-w-xs flex-col gap-4">
<div className="flex items-center gap-2">
<Switch checked={isHighlightBorderAllowed} onCheckedChange={setIsHighlightBorderAllowed} />
<div className="flex flex-col">
<div className="flex items-center gap-2">
<h3 className="whitespace-nowrap text-sm font-semibold text-slate-700">
Add highlight border
</h3>
<Badge
text="App & Website Surveys"
type="gray"
size="normal"
className="whitespace-nowrap"
<FormControl>
<div className="rounded-lg border bg-slate-50 p-6">
<Slider
value={[roundness]}
max={22}
onValueChange={(value) => {
form.setValue("roundness", value[0]);
}}
/>
</div>
<p className="text-xs text-slate-500">Add an outer border to your survey card.</p>
</div>
</FormControl>
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="cardBackgroundColor.light"
render={({ field }) => (
<FormItem className="space-y-4">
<div>
<FormLabel>Card background color</FormLabel>
<FormDescription>Change the background color of the card.</FormDescription>
</div>
{isHighlightBorderAllowed && (
<ColorPicker
color={highlightBorderColor}
onChange={setHighlightBorderColor}
containerClass="my-0"
<FormControl>
<ColorSelector
color={field.value || COLOR_DEFAULTS.cardBackgroundColor}
setColor={(color) => field.onChange(color)}
/>
)}
</div>
</FormControl>
</FormItem>
)}
</>
/>
<FormField
control={form.control}
name="cardBorderColor.light"
render={({ field }) => (
<FormItem className="space-y-4">
<div>
<FormLabel>Card border color</FormLabel>
<FormDescription>Change the border color of the card.</FormDescription>
</div>
<FormControl>
<ColorSelector
color={field.value || COLOR_DEFAULTS.cardBorderColor}
setColor={(color) => field.onChange(color)}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="cardShadowColor.light"
render={({ field }) => (
<FormItem className="space-y-4">
<div>
<FormLabel>Card shadow color</FormLabel>
<FormDescription>Change the shadow color of the card.</FormDescription>
</div>
<FormControl>
<ColorSelector
color={field.value || COLOR_DEFAULTS.cardShadowColor}
setColor={(color) => field.onChange(color)}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name={"cardArrangement"}
render={() => (
<FormItem>
<div>
<FormLabel>Card Arrangement for {surveyTypeDerived} Surveys</FormLabel>
<FormDescription>
How funky do you want your cards in {surveyTypeDerived} Surveys
</FormDescription>
</div>
<FormControl>
<CardArrangementTabs
key={isAppSurvey ? "app" : "link"}
surveyType={isAppSurvey ? "app" : "link"}
activeCardArrangement={isAppSurvey ? appCardArrangement : linkCardArrangement}
setActiveCardArrangement={(value, type) => {
type === "app"
? form.setValue("cardArrangement.appSurveys", value)
: form.setValue("cardArrangement.linkSurveys", value);
}}
/>
</FormControl>
</FormItem>
)}
/>
<div className="flex items-center space-x-1">
<FormField
control={form.control}
name="hideProgressBar"
render={({ field }) => (
<FormItem className="flex w-full items-center gap-2 space-y-0">
<FormControl>
<Switch
id="hideProgressBar"
checked={!!field.value}
onCheckedChange={(checked) => field.onChange(checked)}
/>
</FormControl>
<div>
<FormLabel>Hide progress bar</FormLabel>
<FormDescription>Disable the visibility of survey progress.</FormDescription>
</div>
</FormItem>
)}
/>
</div>
{isLogoVisible && (!surveyType || surveyType === "link") && !isSettingsPage && (
<div className="flex items-center space-x-1">
<FormField
control={form.control}
name="isLogoHidden"
render={({ field }) => (
<FormItem className="flex w-full items-center gap-2 space-y-0">
<FormControl>
<Switch
id="isLogoHidden"
checked={!!field.value}
onCheckedChange={(checked) => field.onChange(checked)}
/>
</FormControl>
<div>
<FormLabel>
Hide logo
<Badge text="Link Surveys" type="gray" size="normal" />
</FormLabel>
<FormDescription>Hides the logo in this specific survey</FormDescription>
</div>
</FormItem>
)}
/>
</div>
)}
{(!surveyType || isAppSurvey) && (
<div className="flex max-w-xs flex-col gap-4">
<div className="flex items-center space-x-1">
<FormField
control={form.control}
name="highlightBorderColor"
render={({ field }) => (
<FormItem className="flex w-full flex-col gap-2 space-y-0">
<div className="flex items-center gap-2">
<FormControl>
<Switch
id="highlightBorderColor"
checked={!!field.value}
onCheckedChange={(checked) => {
if (!checked) {
field.onChange(null);
return;
}
field.onChange({
light: COLOR_DEFAULTS.highlightBorderColor,
});
}}
/>
</FormControl>
<div>
<FormLabel>Add highlight border</FormLabel>
<FormDescription className="text-xs font-normal text-slate-500">
Add an outer border to your survey card.
</FormDescription>
</div>
</div>
{!!field.value && (
<FormControl>
<ColorPicker
color={field.value?.light ?? COLOR_DEFAULTS.highlightBorderColor}
onChange={(color: string) =>
field.onChange({
...field.value,
light: color,
})
}
containerClass="my-0"
/>
</FormControl>
)}
</FormItem>
)}
/>
</div>
</div>
)}
</div>
</Collapsible.CollapsibleContent>
</Collapsible.Root>

View File

@@ -3,6 +3,7 @@
import { useState } from "react";
import { LocalizedEditor } from "@formbricks/ee/multiLanguage/components/LocalizedEditor";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyConsentQuestion } from "@formbricks/types/surveys";
import { Label } from "@formbricks/ui/Label";
import { QuestionFormInput } from "@formbricks/ui/QuestionFormInput";
@@ -15,6 +16,7 @@ interface ConsentQuestionFormProps {
selectedLanguageCode: string;
setSelectedLanguageCode: (languageCode: string) => void;
isInvalid: boolean;
attributeClasses: TAttributeClass[];
}
export const ConsentQuestionForm = ({
@@ -25,6 +27,7 @@ export const ConsentQuestionForm = ({
localSurvey,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: ConsentQuestionFormProps): JSX.Element => {
const [firstRender, setFirstRender] = useState(true);
@@ -32,6 +35,7 @@ export const ConsentQuestionForm = ({
<form>
<QuestionFormInput
id="headline"
label="Question*"
value={question.headline}
localSurvey={localSurvey}
questionIdx={questionIdx}
@@ -39,6 +43,7 @@ export const ConsentQuestionForm = ({
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div className="mt-3">
@@ -61,7 +66,7 @@ export const ConsentQuestionForm = ({
<QuestionFormInput
id="label"
label="Checkbox Label"
label="Checkbox Label*"
placeholder="I agree to the terms and conditions"
value={question.label}
localSurvey={localSurvey}
@@ -70,6 +75,7 @@ export const ConsentQuestionForm = ({
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</form>
);

View File

@@ -2,6 +2,7 @@ import { PlusIcon, TrashIcon } from "lucide-react";
import { useState } from "react";
import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/utils";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey, TSurveyDateQuestion } from "@formbricks/types/surveys";
import { Button } from "@formbricks/ui/Button";
import { Label } from "@formbricks/ui/Label";
@@ -17,6 +18,7 @@ interface IDateQuestionFormProps {
selectedLanguageCode: string;
setSelectedLanguageCode: (language: string) => void;
isInvalid: boolean;
attributeClasses: TAttributeClass[];
}
const dateOptions = [
@@ -42,6 +44,7 @@ export const DateQuestionForm = ({
localSurvey,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: IDateQuestionFormProps): JSX.Element => {
const [showSubheader, setShowSubheader] = useState(!!question.subheader);
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
@@ -51,12 +54,14 @@ export const DateQuestionForm = ({
<QuestionFormInput
id="headline"
value={question.headline}
label={"Question*"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div>
{showSubheader && (
@@ -65,12 +70,14 @@ export const DateQuestionForm = ({
<QuestionFormInput
id="subheader"
value={question.subheader}
label={"Description"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>

View File

@@ -5,6 +5,7 @@ import { useState } from "react";
import { cn } from "@formbricks/lib/cn";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey } from "@formbricks/types/surveys";
import { Input } from "@formbricks/ui/Input";
import { Label } from "@formbricks/ui/Label";
@@ -19,6 +20,7 @@ interface EditThankYouCardProps {
isInvalid: boolean;
selectedLanguageCode: string;
setSelectedLanguageCode: (languageCode: string) => void;
attributeClasses: TAttributeClass[];
}
export const EditThankYouCard = ({
@@ -29,6 +31,7 @@ export const EditThankYouCard = ({
isInvalid,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: EditThankYouCardProps) => {
// const [open, setOpen] = useState(false);
let open = activeQuestionId == "end";
@@ -109,7 +112,7 @@ export const EditThankYouCard = ({
<form>
<QuestionFormInput
id="headline"
label="Headline"
label="Note*"
value={localSurvey?.thankYouCard?.headline}
localSurvey={localSurvey}
questionIdx={localSurvey.questions.length}
@@ -117,17 +120,20 @@ export const EditThankYouCard = ({
updateSurvey={updateSurvey}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<QuestionFormInput
id="subheader"
value={localSurvey.thankYouCard.subheader}
label={"Description"}
localSurvey={localSurvey}
questionIdx={localSurvey.questions.length}
isInvalid={isInvalid}
updateSurvey={updateSurvey}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div className="mt-4">
<div className="flex items-center space-x-1">
@@ -170,6 +176,7 @@ export const EditThankYouCard = ({
updateSurvey={updateSurvey}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>
<div className="space-y-2">

View File

@@ -6,6 +6,7 @@ import { useState } from "react";
import { LocalizedEditor } from "@formbricks/ee/multiLanguage/components/LocalizedEditor";
import { cn } from "@formbricks/lib/cn";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TSurvey } from "@formbricks/types/surveys";
import { FileInput } from "@formbricks/ui/FileInput";
import { Label } from "@formbricks/ui/Label";
@@ -20,6 +21,7 @@ interface EditWelcomeCardProps {
isInvalid: boolean;
selectedLanguageCode: string;
setSelectedLanguageCode: (languageCode: string) => void;
attributeClasses: TAttributeClass[];
}
export const EditWelcomeCard = ({
@@ -30,6 +32,7 @@ export const EditWelcomeCard = ({
isInvalid,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: EditWelcomeCardProps) => {
const [firstRender, setFirstRender] = useState(true);
const path = usePathname();
@@ -123,13 +126,14 @@ export const EditWelcomeCard = ({
<QuestionFormInput
id="headline"
value={localSurvey.welcomeCard.headline}
label="Headline"
label="Note*"
localSurvey={localSurvey}
questionIdx={-1}
isInvalid={isInvalid}
updateSurvey={updateSurvey}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>
<div className="mt-3">
@@ -164,6 +168,8 @@ export const EditWelcomeCard = ({
updateSurvey={updateSurvey}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
label={`"Next" Button Label`}
/>
</div>
</div>

View File

@@ -6,7 +6,8 @@ import { toast } from "react-hot-toast";
import { extractLanguageCodes } from "@formbricks/lib/i18n/utils";
import { createI18nString } from "@formbricks/lib/i18n/utils";
import { useGetBillingInfo } from "@formbricks/lib/team/hooks/useGetBillingInfo";
import { useGetBillingInfo } from "@formbricks/lib/organization/hooks/useGetBillingInfo";
import { TAttributeClass } from "@formbricks/types/attributeClasses";
import { TAllowedFileExtension, ZAllowedFileExtension } from "@formbricks/types/common";
import { TProduct } from "@formbricks/types/product";
import { TSurvey, TSurveyFileUploadQuestion } from "@formbricks/types/surveys";
@@ -25,6 +26,7 @@ interface FileUploadFormProps {
selectedLanguageCode: string;
setSelectedLanguageCode: (languageCode: string) => void;
isInvalid: boolean;
attributeClasses: TAttributeClass[];
}
export const FileUploadQuestionForm = ({
@@ -36,6 +38,7 @@ export const FileUploadQuestionForm = ({
product,
selectedLanguageCode,
setSelectedLanguageCode,
attributeClasses,
}: FileUploadFormProps): JSX.Element => {
const [showSubheader, setShowSubheader] = useState(!!question.subheader);
const [extension, setExtension] = useState("");
@@ -43,7 +46,7 @@ export const FileUploadQuestionForm = ({
billingInfo,
error: billingInfoError,
isLoading: billingInfoLoading,
} = useGetBillingInfo(product?.teamId ?? "");
} = useGetBillingInfo(product?.organizationId ?? "");
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
const handleInputChange = (event) => {
@@ -115,12 +118,14 @@ export const FileUploadQuestionForm = ({
<QuestionFormInput
id="headline"
value={question.headline}
label={"Question*"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
<div>
{showSubheader && (
@@ -129,12 +134,14 @@ export const FileUploadQuestionForm = ({
<QuestionFormInput
id="subheader"
value={question.subheader}
label={"Description"}
localSurvey={localSurvey}
questionIdx={questionIdx}
isInvalid={isInvalid}
updateQuestion={updateQuestion}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
attributeClasses={attributeClasses}
/>
</div>
@@ -171,7 +178,7 @@ export const FileUploadQuestionForm = ({
onToggle={() => updateQuestion(questionIdx, { allowMultipleFiles: !question.allowMultipleFiles })}
htmlId="allowMultipleFile"
title="Allow Multiple Files"
description="Let people upload up to 10 files at the same time."
description="Let people upload up to 25 files at the same time."
childBorder
customContainerClass="p-0"></AdvancedOptionToggle>

Some files were not shown because too many files have changed in this diff Show More