Compare commits

..

1 Commits

Author SHA1 Message Date
Piyush Gupta
9833ba6b26 fix: license restores 2024-11-18 18:22:20 +05:30
727 changed files with 3191 additions and 5184 deletions

View File

@@ -1,6 +1,7 @@
name: Bug report
description: "Found a bug? Please fill out the sections below. \U0001F44D"
type: bug
labels:
- bug
body:
- type: textarea
id: issue-summary

View File

@@ -1,6 +1,7 @@
name: Feature request
description: "Suggest an idea for this project \U0001F680"
type: feature
labels:
- enhancement
body:
- type: textarea
id: problem-description

View File

@@ -1,11 +0,0 @@
name: Task (internal)
description: "Template for creating a task. Used by the Formbricks Team only \U0001f4e5"
type: task
body:
- type: textarea
id: task-summary
attributes:
label: Task description
description: A clear detailed-rich description of the task.
validations:
required: true

View File

@@ -2,7 +2,7 @@ Copyright (c) 2024 Formbricks GmbH
Portions of this software are licensed as follows:
- All content that resides under the "apps/web/modules/ee" directory of this repository, if these directories exist, is licensed under the license defined in "apps/web/modules/ee/LICENSE".
- All content that resides under the "packages/ee/", "apps/web/modules/ee" & "apps/web/app/(ee)" directories of this repository, if these directories exist, is licensed under the license defined in "packages/ee/LICENSE".
- All content that resides under the "packages/js/", "packages/react-native/" and "packages/api/" directories of this repository, if that directories exist, is licensed under the "MIT" license as defined in the "LICENSE" files of these packages.
- All third party components incorporated into the Formbricks Software are licensed under the original license provided by the owner of the applicable component.
- Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.

View File

@@ -228,7 +228,7 @@ The Formbricks core application is licensed under the [AGPLv3 Open Source Licens
### 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/apps/web/modules/ee) and [license](https://github.com/formbricks/formbricks/blob/main/apps/web/modules/ee/LICENSE) for the enterprise functionality can be found in the `/apps/web/modules/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](https://formbricks.com/docs/self-hosting/enterprise) 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](https://formbricks.com/docs/self-hosting/enterprise) to unlock it.
### White-Labeling Formbricks and Other Licensing Needs

View File

@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -12,6 +12,7 @@
},
"dependencies": {
"@formbricks/js": "workspace:*",
"@formbricks/ui": "workspace:*",
"lucide-react": "0.452.0",
"next": "15.0.3",
"react": "19.0.0-rc-ed15d500-20241110",

View File

@@ -1,6 +1,6 @@
import type { AppProps } from "next/app";
import Head from "next/head";
import "../globals.css";
import "@formbricks/ui/globals.css";
const App = ({ Component, pageProps }: AppProps) => {
return (

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -127,10 +127,10 @@ Locate that file. We are using the [Tailwind Template “Syntax”](https://tail
<CodeGroup title="Entire Widget">
```tsx
import { Button } from "@/modules/ui/components/Button";
import { Popover, PopoverContent, PopoverTrigger } from "@/modules/ui/popover";
import { useRouter } from "next/router";
import { useState } from "react";
import { Button } from "@formbricks/ui/components/Button";
import { Popover, PopoverContent, PopoverTrigger } from "@formbricks/ui/components/Popover";
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
export const DocsFeedback = () => {

View File

@@ -0,0 +1,83 @@
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@formbricks/ui/components/Accordion";
import { FaqJsonLdComponent } from "./FAQPageJsonLd";
const FAQ_DATA = [
{
question: "What is an environment ID?",
answer: () => (
<>
The environment ID is a unique identifier associated with each Environment in Formbricks,
distinguishing between different setups like production, development, etc.
</>
),
},
{
question: "How can I implement authentication for the Formbricks API?",
answer: () => (
<>
Formbricks provides 2 types of API keys for each environment ie development and production. You can
generate, view, and manage these keys in the Settings section on the Admin dashboard. Include the API
key in your requests to authenticate and gain access to Formbricks functionalities.
</>
),
},
{
question: "Can I run the deployment shell script on any server?",
answer: () => (
<>
You can run it on any machine you own as long as its running a <b> Linux Ubuntu </b> distribution. And
to forward the requests, make sure you have an <b>A record</b> setup for your domain pointing to the
server.
</>
),
},
{
question: "Can I self-host Formbricks?",
answer: () => (
<>
Absolutely! We provide an option for users to host Formbricks on their own server, ensuring even more
control over data and compliance. And the best part? Self-hosting is available for free, always. For
documentation on self hosting, click{" "}
<a href="/self-hosting/deployment" className="text-brand-dark dark:text-brand-light">
here
</a>
.
</>
),
},
{
question: "How can I change Button texts in my survey?",
answer: () => (
<>
For the question that you want to change the button text, click on the <b>Show Advanced Settings</b>{" "}
toggle and change the button label in the <b>Button Text</b> field.
</>
),
},
];
export const faqJsonLdData = FAQ_DATA.map((faq) => ({
questionName: faq.question,
acceptedAnswerText: faq.answer(),
}));
export const FAQ = () => {
return (
<>
<FaqJsonLdComponent data={faqJsonLdData} />
<Accordion type="single" collapsible>
{FAQ_DATA.map((faq, index) => (
<AccordionItem key={`item-${index}`} value={`item-${index + 1}`} className="not-prose mb-0 mt-0">
<AccordionTrigger>{faq.question}</AccordionTrigger>
<AccordionContent>{faq.answer()}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</>
);
};

View File

@@ -0,0 +1,12 @@
"use client";
import { FAQPageJsonLd } from "next-seo";
export const FaqJsonLdComponent = ({ data }) => {
const faqEntities = data.map(({ question, answer }) => ({
questionName: question,
acceptedAnswerText: answer,
}));
return <FAQPageJsonLd mainEntity={faqEntities} />;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,89 +0,0 @@
import { MdxImage } from "@/components/MdxImage";
import CreatedVariables from "./images/created-variables.webp";
import InputVariables from "./images/input-variables.webp";
import LogicWithVariables from "./images/logic-with-variables.webp";
import VariablesCard from "./images/variables-card.webp";
import VariablesUsage from "./images/variables-usage.webp";
export const metadata = {
title: "Variables",
description: "Add variabeles to your surveys to transform your survey into a quiz",
};
# Variables
Variables are a powerful feature in Formbricks that allows you to keep track of data variables when user fills a form. This feature is especially useful when you want to use your survey as a quiz.
## Types of Variables
There are two types of variables you can add to your survey:
1. **Text**: You can add text variables to your survey to capture text data.
2. **Number**: You can add number variables to your survey to capture number data.
## How to Add Variables
1. Edit the survey you want to add variables to & switch to the Questions tab and scroll down to the bottom of the page. You will see a section called **Variables**.
<MdxImage
src={VariablesCard}
alt="Variables card"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. Now click on it to add a new variable ID. You can add as many variables as you want. You can also choose the type of variable you want to add along with the default value.
<MdxImage
src={InputVariables}
alt="add variables"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<MdxImage
src={CreatedVariables}
alt="created variables"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
## Use case:
- **Quiz**: You can use variables to create a quiz. For example, you can add a variable `score` and update it every time a user answers a question. You can also use the variable for recall to show the final score to the user.
- **Personalisation**: You can use variables to store user data and personalise the survey experience. For example, you can add a variable `full_name` and update it every time a user fills in their first name and last name. You can use the variable to personalise the survey experience by addressing the user with their full name.
## How is it different from Hidden Fields?
Variables are different from hidden fields in the following ways:
1. **Setting**: Hidden fields can be set through query parameters or `formbricks.init`, but the variables can only be set either during creation or dynamically by using logic actions.
2. **Updating**: Hidden fields cannot be set again, but the value of variables can be updated while the user fills the survey.
3. **Type**: Hidden fields can only store text data, but variables can store both text and number data.
## How to use Variables
1. Once you have added the variables to your survey, you'll be able to access them in the logic editor. You can use the variables to create logic actions and conditions.
<MdxImage
src={VariablesUsage}
alt="Variables usage"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
2. You can create logic based on the variables and questions in your survey and can update the variables based on the user's response.
<MdxImage
src={LogicWithVariables}
alt="Logic with variables"
quality="100"
className="max-w-full rounded-lg sm:max-w-3xl"
/>
<Note>
To know more about how to use logic in Formbricks, check out the [Conditional
Logic](/global/conditional-logic).
</Note>

View File

@@ -1,54 +0,0 @@
export const metadata = {
title: "Cluster Setup for Formbricks",
description: "Learn how to set up Formbricks in a multi-instance cluster configuration for high availability and scalability.",
};
#### Self-Hosting
# Cluster Setup
<Note>
Running Formbricks in a multi-instance cluster configuration is an Enterprise Edition feature and requires an enterprise license key.
</Note>
## Overview
Running Formbricks as a cluster of multiple instances offers several key advantages:
- **High Availability**: Ensure your surveys remain accessible even if some instances fail
- **Load Distribution**: Handle higher traffic by distributing requests across multiple instances
- **Scalability**: Easily scale horizontally by adding more instances as your needs grow
- **Zero-Downtime Updates**: Rolling updates without service interruption
## Requirements
To run Formbricks in a cluster setup, you'll need:
- Enterprise Edition license key
- Shared PostgreSQL database
- Shared Redis cache for session management and caching
- Load balancer to distribute traffic
## Redis Configuration
<Note>
Redis integration is an Enterprise Edition feature and requires an enterprise license key.
</Note>
Configure Redis by adding the following environment variables to your instances:
```sh {{ title: 'env file' }}
REDIS_URL=redis://your-redis-host:6379
REDIS_HTTP_URL=http://your-redis-host:8000
```
## Coming Soon
We're working on comprehensive Kubernetes deployment instructions to make cluster setup even easier. This will include:
- Kubernetes manifests
- Helm charts
- Detailed scaling configurations
- Production-ready deployment examples
Stay tuned for updates.

View File

@@ -19,7 +19,7 @@ The Formbricks Core source code is licensed under AGPLv3 and available on GitHub
## Enterprise Edition License
Additional to the AGPLv3 licensed Formbricks core, the Formbricks repository contains code licensed under our **[Enterprise License](https://github.com/formbricks/formbricks/blob/main/apps/web/modules/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?
@@ -64,7 +64,7 @@ The Formbricks core application is licensed under the **[AGPLv3 Open Source Lice
### 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/apps/web/modules/ee)** and **[license](https://github.com/formbricks/formbricks/blob/main/apps/web/modules/ee/LICENSE)** for the enterprise functionality can be found in the `/apps/web/modules/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](https://formbricks.com/docs/self-hosting/enterprise)** 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

View File

@@ -54,7 +54,6 @@ export const navigation: Array<NavGroup> = [
title: "Add Image/Video to Question",
href: "/global/add-image-or-video-question",
},
{ title: "Variables", href: "/global/variables" },
],
},
],
@@ -86,7 +85,6 @@ export const navigation: Array<NavGroup> = [
title: "Add Image/Video to Question",
href: "/global/add-image-or-video-question",
},
{ title: "Variables", href: "/global/variables" },
],
},
],
@@ -143,7 +141,6 @@ export const navigation: Array<NavGroup> = [
{ title: "Configuration", href: "/self-hosting/configuration" },
{ title: "Integrations", href: "/self-hosting/integrations" },
{ title: "License", href: "/self-hosting/license" },
{ title: "Cluster Setup", href: "/self-hosting/cluster-setup" },
],
},
{

View File

@@ -16,7 +16,7 @@ const withMDX = nextMDX({
const nextConfig = {
basePath: "/docs",
pageExtensions: ["js", "jsx", "ts", "tsx", "mdx"],
transpilePackages: ["@formbricks/lib"],
transpilePackages: ["@formbricks/ui", "@formbricks/lib"],
images: {
remotePatterns: [
{

View File

@@ -18,6 +18,7 @@
"@docsearch/react": "3.6.2",
"@formbricks/lib": "workspace:*",
"@formbricks/types": "workspace:*",
"@formbricks/ui": "workspace:*",
"@headlessui/react": "2.1.9",
"@headlessui/tailwindcss": "0.2.1",
"@mapbox/rehype-prism": "0.9.0",

View File

@@ -1,4 +1,5 @@
import headlessuiPlugin from "@headlessui/tailwindcss";
import forms from "@tailwindcss/forms";
import typographyPlugin from "@tailwindcss/typography";
import { type Config } from "tailwindcss";
import defaultTheme from "tailwindcss/defaultTheme";
@@ -81,5 +82,5 @@ export default {
},
},
},
plugins: [typographyPlugin, headlessuiPlugin],
plugins: [typographyPlugin, headlessuiPlugin, forms],
} satisfies Config;

View File

@@ -10,7 +10,11 @@ const getAbsolutePath = (value: string) => {
};
const config: StorybookConfig = {
stories: ["../src/**/*.mdx", "../../web/modules/ui/**/stories.@(js|jsx|mjs|ts|tsx)"],
stories: [
"../src/**/*.mdx",
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
"../../../packages/ui/**/stories.@(js|jsx|mjs|ts|tsx)",
],
addons: [
getAbsolutePath("@storybook/addon-onboarding"),
getAbsolutePath("@storybook/addon-links"),

View File

@@ -1,5 +1,5 @@
import type { Preview } from "@storybook/react";
import "@formbricks/web/modules/ui/globals.css";
import "../../../packages/ui/globals.css";
const preview: Preview = {
parameters: {

View File

@@ -11,6 +11,7 @@
"clean": "rimraf .turbo node_modules dist storybook-static"
},
"dependencies": {
"@formbricks/ui": "workspace:*",
"eslint-plugin-react-refresh": "0.4.12",
"react": "19.0.0-rc-ed15d500-20241110",
"react-dom": "19.0.0-rc-ed15d500-20241110"

View File

@@ -1,7 +1,7 @@
/** @type {import('tailwindcss').Config} */
import base from "../web/tailwind.config";
import base from "../../packages/ui/tailwind.config";
export default {
...base,
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}", "../web/modules/ui/**/*.{js,ts,jsx,tsx}"],
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}", "../../packages/ui/**/*.{js,ts,jsx,tsx}"],
};

View File

@@ -1,5 +1,4 @@
import react from "@vitejs/plugin-react";
import path from "path";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
@@ -8,9 +7,4 @@ export default defineConfig({
define: {
"process.env": {},
},
resolve: {
alias: {
"@": path.resolve(__dirname, "../web"),
},
},
});

View File

@@ -1,6 +1,5 @@
"use client";
import { Button } from "@/modules/ui/components/button";
import { ArrowRight } from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
@@ -8,6 +7,7 @@ import { useEffect } from "react";
import { cn } from "@formbricks/lib/cn";
import { TEnvironment } from "@formbricks/types/environment";
import { TProductConfigChannel } from "@formbricks/types/product";
import { Button } from "@formbricks/ui/components/Button";
import { OnboardingSetupInstructions } from "./OnboardingSetupInstructions";
interface ConnectWithFormbricksProps {

View File

@@ -1,9 +1,6 @@
"use client";
import { inviteOrganizationMemberAction } from "@/app/(app)/(onboarding)/organizations/actions";
import { Button } from "@/modules/ui/components/button";
import { FormControl, FormError, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
import { Input } from "@/modules/ui/components/input";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
@@ -11,6 +8,9 @@ import { FormProvider, useForm } from "react-hook-form";
import { toast } from "react-hot-toast";
import { z } from "zod";
import { TOrganization } from "@formbricks/types/organizations";
import { Button } from "@formbricks/ui/components/Button";
import { FormControl, FormError, FormField, FormItem, FormLabel } from "@formbricks/ui/components/Form";
import { Input } from "@formbricks/ui/components/Input";
interface InviteOrganizationMemberProps {
organization: TOrganization;

View File

@@ -1,14 +1,14 @@
"use client";
import { Button } from "@/modules/ui/components/button";
import { CodeBlock } from "@/modules/ui/components/code-block";
import { Html5Icon, NpmIcon } from "@/modules/ui/components/icons";
import { TabBar } from "@/modules/ui/components/tab-bar";
import { useTranslations } from "next-intl";
import "prismjs/themes/prism.css";
import { useState } from "react";
import toast from "react-hot-toast";
import { TProductConfigChannel } from "@formbricks/types/product";
import { Button } from "@formbricks/ui/components/Button";
import { CodeBlock } from "@formbricks/ui/components/CodeBlock";
import { TabBar } from "@formbricks/ui/components/TabBar";
import { Html5Icon, NpmIcon } from "@formbricks/ui/components/icons";
const tabs = [
{ id: "html", label: "HTML", icon: <Html5Icon /> },

View File

@@ -1,6 +1,4 @@
import { InviteOrganizationMember } from "@/app/(app)/(onboarding)/environments/[environmentId]/connect/components/InviteOrganizationMember";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { XIcon } from "lucide-react";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
@@ -8,6 +6,8 @@ import { notFound, redirect } from "next/navigation";
import { authOptions } from "@formbricks/lib/authOptions";
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface InvitePageProps {
params: Promise<{

View File

@@ -1,11 +1,11 @@
import { ConnectWithFormbricks } from "@/app/(app)/(onboarding)/environments/[environmentId]/connect/components/ConnectWithFormbricks";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { XIcon } from "lucide-react";
import { getTranslations } from "next-intl/server";
import { WEBAPP_URL } from "@formbricks/lib/constants";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getProductByEnvironmentId } from "@formbricks/lib/product/service";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface ConnectPageProps {
params: Promise<{

View File

@@ -1,7 +1,5 @@
import { XMTemplateList } from "@/app/(app)/(onboarding)/environments/[environmentId]/xm-templates/components/XMTemplateList";
import { getOrganizationIdFromEnvironmentId } from "@/lib/utils/helper";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { XIcon } from "lucide-react";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
@@ -9,6 +7,8 @@ import { authOptions } from "@formbricks/lib/authOptions";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getProductByEnvironmentId, getUserProducts } from "@formbricks/lib/product/service";
import { getUser } from "@formbricks/lib/user/service";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface XMTemplatePageProps {
params: Promise<{

View File

@@ -3,20 +3,6 @@
import { formbricksLogout } from "@/app/lib/formbricks";
import FBLogo from "@/images/formbricks-wordmark.svg";
import { CreateOrganizationModal } from "@/modules/organization/components/CreateOrganizationModal";
import { ProfileAvatar } from "@/modules/ui/components/avatars";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { ArrowUpRightIcon, ChevronRightIcon, LogOutIcon, PlusIcon } from "lucide-react";
import { signOut } from "next-auth/react";
import { useTranslations } from "next-intl";
@@ -29,6 +15,20 @@ import { cn } from "@formbricks/lib/cn";
import { capitalizeFirstLetter } from "@formbricks/lib/utils/strings";
import { TOrganization } from "@formbricks/types/organizations";
import { TUser } from "@formbricks/types/user";
import { ProfileAvatar } from "@formbricks/ui/components/Avatars";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@formbricks/ui/components/DropdownMenu";
interface LandingSidebarProps {
isMultiOrgEnabled: boolean;

View File

@@ -1,12 +1,12 @@
import { LandingSidebar } from "@/app/(app)/(onboarding)/organizations/[organizationId]/landing/components/landing-sidebar";
import { getEnterpriseLicense } from "@/modules/ee/license-check/lib/utils";
import { Header } from "@/modules/ui/components/header";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { notFound, redirect } from "next/navigation";
import { getEnterpriseLicense } from "@formbricks/ee/lib/service";
import { authOptions } from "@formbricks/lib/authOptions";
import { getOrganization, getOrganizationsByUserId } from "@formbricks/lib/organization/service";
import { getUser } from "@formbricks/lib/user/service";
import { Header } from "@formbricks/ui/components/Header";
const Page = async (props) => {
const params = await props.params;

View File

@@ -1,5 +1,4 @@
import { PosthogIdentify } from "@/app/(app)/environments/[environmentId]/components/PosthogIdentify";
import { ToasterClient } from "@/modules/ui/components/toaster-client";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
@@ -8,6 +7,7 @@ import { canUserAccessOrganization } from "@formbricks/lib/organization/auth";
import { getOrganization } from "@formbricks/lib/organization/service";
import { getUser } from "@formbricks/lib/user/service";
import { AuthorizationError } from "@formbricks/types/errors";
import { ToasterClient } from "@formbricks/ui/components/ToasterClient";
const ProductOnboardingLayout = async (props) => {
const params = await props.params;

View File

@@ -1,12 +1,12 @@
import { OnboardingOptionsContainer } from "@/app/(app)/(onboarding)/organizations/components/OnboardingOptionsContainer";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { GlobeIcon, GlobeLockIcon, LinkIcon, XIcon } from "lucide-react";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
import { authOptions } from "@formbricks/lib/authOptions";
import { getUserProducts } from "@formbricks/lib/product/service";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface ChannelPageProps {
params: Promise<{

View File

@@ -1,12 +1,12 @@
import { OnboardingOptionsContainer } from "@/app/(app)/(onboarding)/organizations/components/OnboardingOptionsContainer";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { HeartIcon, ListTodoIcon, XIcon } from "lucide-react";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
import { authOptions } from "@formbricks/lib/authOptions";
import { getUserProducts } from "@formbricks/lib/product/service";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface ModePageProps {
params: Promise<{

View File

@@ -4,20 +4,6 @@ import { createProductAction } from "@/app/(app)/environments/[environmentId]/ac
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { TOrganizationTeam } from "@/modules/ee/teams/product-teams/types/teams";
import { CreateTeamModal } from "@/modules/ee/teams/team-list/components/create-team-modal";
import { Button } from "@/modules/ui/components/button";
import { ColorPicker } from "@/modules/ui/components/color-picker";
import {
FormControl,
FormDescription,
FormError,
FormField,
FormItem,
FormLabel,
FormProvider,
} from "@/modules/ui/components/form";
import { Input } from "@/modules/ui/components/input";
import { MultiSelect } from "@/modules/ui/components/multi-select";
import { SurveyInline } from "@/modules/ui/components/survey";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslations } from "next-intl";
import Image from "next/image";
@@ -34,6 +20,20 @@ import {
TProductUpdateInput,
ZProductUpdateInput,
} from "@formbricks/types/product";
import { Button } from "@formbricks/ui/components/Button";
import { ColorPicker } from "@formbricks/ui/components/ColorPicker";
import {
FormControl,
FormDescription,
FormError,
FormField,
FormItem,
FormLabel,
FormProvider,
} from "@formbricks/ui/components/Form";
import { Input } from "@formbricks/ui/components/Input";
import { MultiSelect } from "@formbricks/ui/components/MultiSelect";
import { SurveyInline } from "@formbricks/ui/components/Survey";
interface ProductSettingsProps {
organizationId: string;

View File

@@ -1,19 +1,19 @@
import { getTeamsByOrganizationId } from "@/app/(app)/(onboarding)/lib/onboarding";
import { getCustomHeadline } from "@/app/(app)/(onboarding)/lib/utils";
import { ProductSettings } from "@/app/(app)/(onboarding)/organizations/[organizationId]/products/new/settings/components/ProductSettings";
import { getRoleManagementPermission } from "@/modules/ee/license-check/lib/utils";
import { Button } from "@/modules/ui/components/button";
import { Header } from "@/modules/ui/components/header";
import { XIcon } from "lucide-react";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
import { getRoleManagementPermission } from "@formbricks/ee/lib/service";
import { authOptions } from "@formbricks/lib/authOptions";
import { DEFAULT_BRAND_COLOR, DEFAULT_LOCALE } from "@formbricks/lib/constants";
import { getOrganization } from "@formbricks/lib/organization/service";
import { getUserProducts } from "@formbricks/lib/product/service";
import { getUserLocale } from "@formbricks/lib/user/service";
import { TProductConfigChannel, TProductConfigIndustry, TProductMode } from "@formbricks/types/product";
import { Button } from "@formbricks/ui/components/Button";
import { Header } from "@formbricks/ui/components/Header";
interface ProductSettingsPageProps {
params: Promise<{

View File

@@ -1,7 +1,7 @@
import { OptionCard } from "@/modules/ui/components/option-card";
import { LucideProps } from "lucide-react";
import Link from "next/link";
import { ForwardRefExoticComponent, RefAttributes } from "react";
import { OptionCard } from "@formbricks/ui/components/OptionCard";
interface OnboardingOptionsContainerProps {
options: {

View File

@@ -1,8 +1,6 @@
import { FormbricksClient } from "@/app/(app)/components/FormbricksClient";
import { PosthogIdentify } from "@/app/(app)/environments/[environmentId]/components/PosthogIdentify";
import { ResponseFilterProvider } from "@/app/(app)/environments/[environmentId]/components/ResponseFilterContext";
import { DevEnvironmentBanner } from "@/modules/ui/components/dev-environment-banner";
import { ToasterClient } from "@/modules/ui/components/toaster-client";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
@@ -12,6 +10,8 @@ import { getEnvironment } from "@formbricks/lib/environment/service";
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
import { getUser } from "@formbricks/lib/user/service";
import { AuthorizationError } from "@formbricks/types/errors";
import { DevEnvironmentBanner } from "@formbricks/ui/components/DevEnvironmentBanner";
import { ToasterClient } from "@formbricks/ui/components/ToasterClient";
const SurveyEditorEnvironmentLayout = async (props) => {
const params = await props.params;

View File

@@ -12,12 +12,9 @@ import {
getProductIdFromSurveyId,
} from "@/lib/utils/helper";
import { getSegment, getSurvey } from "@/lib/utils/services";
import { getSurveyFollowUpsPermission } from "@/modules/ee/license-check/lib/utils";
import { checkMultiLanguagePermission } from "@/modules/ee/multi-language-surveys/lib/actions";
import { z } from "zod";
import { createActionClass } from "@formbricks/lib/actionClass/service";
import { UNSPLASH_ACCESS_KEY, UNSPLASH_ALLOWED_DOMAINS } from "@formbricks/lib/constants";
import { getOrganization } from "@formbricks/lib/organization/service";
import { getProduct } from "@formbricks/lib/product/service";
import {
cloneSegment,
@@ -29,37 +26,15 @@ import { surveyCache } from "@formbricks/lib/survey/cache";
import { loadNewSegmentInSurvey, updateSurvey } from "@formbricks/lib/survey/service";
import { ZActionClassInput } from "@formbricks/types/action-classes";
import { ZId } from "@formbricks/types/common";
import { OperationNotAllowedError, ResourceNotFoundError } from "@formbricks/types/errors";
import { ZBaseFilters, ZSegmentFilters, ZSegmentUpdateInput } from "@formbricks/types/segment";
import { ZSurvey } from "@formbricks/types/surveys/types";
/**
* Checks if survey follow-ups are enabled for the given organization.
*
* @param { string } organizationId The ID of the organization to check.
* @returns { Promise<void> } A promise that resolves if the permission is granted.
* @throws { ResourceNotFoundError } If the organization is not found.
* @throws { OperationNotAllowedError } If survey follow-ups are not enabled for the organization.
*/
const checkSurveyFollowUpsPermission = async (organizationId: string): Promise<void> => {
const organization = await getOrganization(organizationId);
if (!organization) {
throw new ResourceNotFoundError("Organization", organizationId);
}
const isSurveyFollowUpsEnabled = await getSurveyFollowUpsPermission(organization);
if (!isSurveyFollowUpsEnabled) {
throw new OperationNotAllowedError("Survey follow ups are not enabled for this organization");
}
};
export const updateSurveyAction = authenticatedActionClient
.schema(ZSurvey)
.action(async ({ ctx, parsedInput }) => {
const organizationId = await getOrganizationIdFromSurveyId(parsedInput.id);
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId,
organizationId: await getOrganizationIdFromSurveyId(parsedInput.id),
access: [
{
type: "organization",
@@ -73,14 +48,6 @@ export const updateSurveyAction = authenticatedActionClient
],
});
if (parsedInput.followUps?.length) {
await checkSurveyFollowUpsPermission(organizationId);
}
if (parsedInput.languages?.length) {
await checkMultiLanguagePermission(organizationId);
}
return await updateSurvey(parsedInput);
});

View File

@@ -1,9 +1,9 @@
"use client";
import { ModalWithTabs } from "@/modules/ui/components/modal-with-tabs";
import { useTranslations } from "next-intl";
import { TActionClass } from "@formbricks/types/action-classes";
import { TSurvey } from "@formbricks/types/surveys/types";
import { ModalWithTabs } from "@formbricks/ui/components/ModalWithTabs";
import { CreateNewActionTab } from "./CreateNewActionTab";
import { SavedActionsTab } from "./SavedActionsTab";

View File

@@ -1,8 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { QuestionToggleTable } from "@/modules/ui/components/question-toggle-table";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -11,6 +9,8 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyAddressQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { QuestionToggleTable } from "@formbricks/ui/components/QuestionToggleTable";
interface AddressQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -1,8 +1,5 @@
"use client";
import { Badge } from "@/modules/ui/components/badge";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
import { Slider } from "@/modules/ui/components/slider";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
@@ -11,6 +8,9 @@ import { UseFormReturn } from "react-hook-form";
import { cn } from "@formbricks/lib/cn";
import { TProductStyling } from "@formbricks/types/product";
import { TSurveyStyling } from "@formbricks/types/surveys/types";
import { Badge } from "@formbricks/ui/components/Badge";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@formbricks/ui/components/Form";
import { Slider } from "@formbricks/ui/components/Slider";
import { SurveyBgSelectorTab } from "./SurveyBgSelectorTab";
interface BackgroundStylingCardProps {

View File

@@ -2,15 +2,15 @@
import { LocalizedEditor } from "@/modules/ee/multi-language-surveys/components/localized-editor";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { OptionsSwitch } from "@/modules/ui/components/options-switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useTranslations } from "next-intl";
import { type JSX, useState } from "react";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyCTAQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { OptionsSwitch } from "@formbricks/ui/components/OptionsSwitch";
const options = [
{

View File

@@ -1,8 +1,4 @@
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { type JSX, useEffect, useState } from "react";
@@ -10,6 +6,10 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyCalQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
interface CalQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -1,11 +1,5 @@
"use client";
import { Badge } from "@/modules/ui/components/badge";
import { CardArrangementTabs } from "@/modules/ui/components/card-arrangement-tabs";
import { ColorPicker } from "@/modules/ui/components/color-picker";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
import { Slider } from "@/modules/ui/components/slider";
import { Switch } from "@/modules/ui/components/switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
@@ -16,6 +10,12 @@ import { cn } from "@formbricks/lib/cn";
import { COLOR_DEFAULTS } from "@formbricks/lib/styling/constants";
import { TProduct, TProductStyling } from "@formbricks/types/product";
import { TSurveyStyling, TSurveyType } from "@formbricks/types/surveys/types";
import { Badge } from "@formbricks/ui/components/Badge";
import { CardArrangementTabs } from "@formbricks/ui/components/CardArrangementTabs";
import { ColorPicker } from "@formbricks/ui/components/ColorPicker";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@formbricks/ui/components/Form";
import { Slider } from "@formbricks/ui/components/Slider";
import { Switch } from "@formbricks/ui/components/Switch";
type CardStylingSettingsProps = {
open: boolean;

View File

@@ -1,5 +1,5 @@
import { ColorPicker } from "@/modules/ui/components/color-picker";
import { useState } from "react";
import { ColorPicker } from "@formbricks/ui/components/ColorPicker";
interface ColorSurveyBgProps {
handleBgChange: (bg: string, bgType: string) => void;

View File

@@ -3,14 +3,6 @@ import {
getDefaultOperatorForQuestion,
replaceEndingCardHeadlineRecall,
} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { Button } from "@/modules/ui/components/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { Label } from "@/modules/ui/components/label";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { createId } from "@paralleldrive/cuid2";
import {
@@ -28,6 +20,14 @@ import { duplicateLogicItem } from "@formbricks/lib/surveyLogic/utils";
import { replaceHeadlineRecall } from "@formbricks/lib/utils/recall";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyLogic, TSurveyQuestion } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/components/Button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@formbricks/ui/components/DropdownMenu";
import { Label } from "@formbricks/ui/components/Label";
interface ConditionalLogicProps {
localSurvey: TSurvey;

View File

@@ -2,12 +2,12 @@
import { LocalizedEditor } from "@/modules/ee/multi-language-surveys/components/localized-editor";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Label } from "@/modules/ui/components/label";
import { useTranslations } from "next-intl";
import { type JSX, useState } from "react";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyConsentQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Label } from "@formbricks/ui/components/Label";
interface ConsentQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -1,8 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { QuestionToggleTable } from "@/modules/ui/components/question-toggle-table";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -11,6 +9,8 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyContactInfoQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { QuestionToggleTable } from "@formbricks/ui/components/QuestionToggleTable";
interface ContactInfoQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -1,11 +1,4 @@
import { isValidCssSelector } from "@/app/lib/actionClass/actionClass";
import { Button } from "@/modules/ui/components/button";
import { CodeActionForm } from "@/modules/ui/components/code-action-form";
import { FormControl, FormError, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { NoCodeActionForm } from "@/modules/ui/components/no-code-action-form";
import { TabToggle } from "@/modules/ui/components/tab-toggle";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslations } from "next-intl";
import { useMemo } from "react";
@@ -19,6 +12,13 @@ import {
ZActionClassInput,
} from "@formbricks/types/action-classes";
import { TSurvey } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/components/Button";
import { FormControl, FormError, FormField, FormItem, FormLabel } from "@formbricks/ui/components/Form";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { TabToggle } from "@formbricks/ui/components/TabToggle";
import { CodeActionForm } from "@formbricks/ui/components/organisms/CodeActionForm";
import { NoCodeActionForm } from "@formbricks/ui/components/organisms/NoCodeActionForm";
import { createActionClassAction } from "../actions";
interface CreateNewActionTabProps {

View File

@@ -1,7 +1,4 @@
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { OptionsSwitch } from "@/modules/ui/components/options-switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -10,6 +7,9 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyDateQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { OptionsSwitch } from "@formbricks/ui/components/OptionsSwitch";
interface IDateQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -7,16 +7,12 @@ import {
findEndingCardUsedInLogic,
formatTextWithSlashes,
} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { ConfirmationModal } from "@/modules/ui/components/confirmation-modal";
import { OptionsSwitch } from "@/modules/ui/components/options-switch";
import { TooltipRenderer } from "@/modules/ui/components/tooltip";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { createId } from "@paralleldrive/cuid2";
import * as Collapsible from "@radix-ui/react-collapsible";
import { GripIcon, Handshake, Undo2 } from "lucide-react";
import { useTranslations } from "next-intl";
import { useState } from "react";
import toast from "react-hot-toast";
import { cn } from "@formbricks/lib/cn";
import { recallToHeadline } from "@formbricks/lib/utils/recall";
@@ -29,6 +25,8 @@ import {
TSurveyRedirectUrlCard,
} from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { OptionsSwitch } from "@formbricks/ui/components/OptionsSwitch";
import { TooltipRenderer } from "@formbricks/ui/components/Tooltip";
interface EditEndingCardProps {
localSurvey: TSurvey;
@@ -67,8 +65,6 @@ export const EditEndingCard = ({
? plan === "free" && endingCard.type !== "redirectToUrl"
: false;
const [openDeleteConfirmationModal, setOpenDeleteConfirmationModal] = useState(false);
const endingCardTypes = [
{ value: "endScreen", label: t("environments.surveys.edit.ending_card") },
{
@@ -81,7 +77,6 @@ export const EditEndingCard = ({
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: endingCard.id,
});
let open = activeQuestionId === endingCard.id;
const setOpen = (e) => {
@@ -102,16 +97,6 @@ export const EditEndingCard = ({
};
const deleteEndingCard = () => {
const isEndingCardUsedInFollowUps = localSurvey.followUps.some((followUp) => {
if (followUp.trigger.type === "endings") {
if (followUp.trigger.properties?.endingIds?.includes(endingCard.id)) {
return true;
}
}
return false;
});
// checking if this ending card is used in logic
const quesIdx = findEndingCardUsedInLogic(localSurvey, endingCard.id);
@@ -120,11 +105,6 @@ export const EditEndingCard = ({
return;
}
if (isEndingCardUsedInFollowUps) {
setOpenDeleteConfirmationModal(true);
return;
}
setLocalSurvey((prevSurvey) => {
const updatedEndings = prevSurvey.endings.filter((_, index) => index !== endingCardIndex);
return { ...prevSurvey, endings: updatedEndings };
@@ -285,37 +265,6 @@ export const EditEndingCard = ({
)}
</Collapsible.CollapsibleContent>
</Collapsible.Root>
<ConfirmationModal
buttonText={t("common.delete")}
onConfirm={() => {
setLocalSurvey((prevSurvey) => {
const updatedEndings = prevSurvey.endings.filter((_, index) => index !== endingCardIndex);
const surveyFollowUps = prevSurvey.followUps.map((f) => {
if (f.trigger.properties?.endingIds?.includes(endingCard.id)) {
return {
...f,
trigger: {
...f.trigger,
properties: {
...f.trigger.properties,
endingIds: f.trigger.properties.endingIds.filter((id) => id !== endingCard.id),
},
},
};
}
return f;
});
return { ...prevSurvey, endings: updatedEndings, followUps: surveyFollowUps };
});
}}
open={openDeleteConfirmationModal}
setOpen={setOpenDeleteConfirmationModal}
text={t("environments.surveys.edit.follow_ups_ending_card_delete_modal_text")}
title={t("environments.surveys.edit.follow_ups_ending_card_delete_modal_title")}
/>
</div>
);
};

View File

@@ -2,9 +2,6 @@
import { LocalizedEditor } from "@/modules/ee/multi-language-surveys/components/localized-editor";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { FileInput } from "@/modules/ui/components/file-input";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import * as Collapsible from "@radix-ui/react-collapsible";
import { Hand } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -14,6 +11,9 @@ import { cn } from "@formbricks/lib/cn";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyQuestionId, TSurveyWelcomeCard } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { FileInput } from "@formbricks/ui/components/FileInput";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
interface EditWelcomeCardProps {
localSurvey: TSurvey;

View File

@@ -1,15 +1,5 @@
"use client";
import { ConfirmationModal } from "@/modules/ui/components/confirmation-modal";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { createId } from "@paralleldrive/cuid2";
import { ArrowDownIcon, ArrowUpIcon, CopyIcon, EllipsisIcon, TrashIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -29,6 +19,16 @@ import {
TSurveyQuestionTypeEnum,
TSurveyRedirectUrlCard,
} from "@formbricks/types/surveys/types";
import { ConfirmationModal } from "@formbricks/ui/components/ConfirmationModal";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@formbricks/ui/components/DropdownMenu";
interface EditorCardMenuProps {
survey: TSurvey;
@@ -184,6 +184,7 @@ export const EditorCardMenu = ({
deleteCard(cardIdx);
}}
/>
<DropdownMenu>
<DropdownMenuTrigger>
<EllipsisIcon className="h-4 w-4 text-slate-500 hover:text-slate-600" />
@@ -285,6 +286,7 @@ export const EditorCardMenu = ({
</div>
</DropdownMenuContent>
</DropdownMenu>
<ConfirmationModal
open={logicWarningModal}
setOpen={setLogicWarningModal}

View File

@@ -1,15 +1,15 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyEndScreenCard } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
interface EndScreenFormProps {
localSurvey: TSurvey;

View File

@@ -1,9 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { useGetBillingInfo } from "@/modules/utils/hooks/useGetBillingInfo";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon, XCircleIcon } from "lucide-react";
@@ -18,6 +15,9 @@ import { TAllowedFileExtension, ZAllowedFileExtension } from "@formbricks/types/
import { TProduct } from "@formbricks/types/product";
import { TSurvey, TSurveyFileUploadQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
interface FileUploadFormProps {
localSurvey: TSurvey;

View File

@@ -1,8 +1,5 @@
"use client";
import { Button } from "@/modules/ui/components/button";
import { ColorPicker } from "@/modules/ui/components/color-picker";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon, SparklesIcon } from "lucide-react";
@@ -14,6 +11,9 @@ import { COLOR_DEFAULTS } from "@formbricks/lib/styling/constants";
import { mixColor } from "@formbricks/lib/utils/colors";
import { TProductStyling } from "@formbricks/types/product";
import { TSurveyStyling } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/components/Button";
import { ColorPicker } from "@formbricks/ui/components/ColorPicker";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@formbricks/ui/components/Form";
type FormStylingSettingsProps = {
open: boolean;

View File

@@ -1,11 +1,6 @@
"use client";
import { findHiddenFieldUsedInLogic } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { Tag } from "@/modules/ui/components/tag";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { EyeOff } from "lucide-react";
@@ -16,6 +11,11 @@ import { cn } from "@formbricks/lib/cn";
import { extractRecallInfo } from "@formbricks/lib/utils/recall";
import { TSurvey, TSurveyHiddenFields, TSurveyQuestionId } from "@formbricks/types/surveys/types";
import { validateId } from "@formbricks/types/surveys/validation";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
import { Tag } from "@formbricks/ui/components/Tag";
interface HiddenFieldsCardProps {
localSurvey: TSurvey;
@@ -84,17 +84,6 @@ export const HiddenFieldsCard = ({
return;
}
const isHiddenFieldUsedInFollowUp = localSurvey.followUps
.filter((f) => !f.deleted)
.some((followUp) => {
return followUp.action.properties.to === fieldId;
});
if (isHiddenFieldUsedInFollowUp) {
toast.error(t("environments.surveys.edit.follow_ups_hidden_field_error"));
return;
}
updateSurvey(
{
enabled: true,

View File

@@ -1,8 +1,5 @@
"use client";
import { Badge } from "@/modules/ui/components/badge";
import { Label } from "@/modules/ui/components/label";
import { RadioGroup, RadioGroupItem } from "@/modules/ui/components/radio-group";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { AlertCircleIcon, CheckIcon, LinkIcon, MonitorIcon } from "lucide-react";
@@ -14,6 +11,9 @@ import { getDefaultEndingCard } from "@formbricks/lib/templates";
import { TEnvironment } from "@formbricks/types/environment";
import { TSegment } from "@formbricks/types/segment";
import { TSurvey, TSurveyType } from "@formbricks/types/surveys/types";
import { Badge } from "@formbricks/ui/components/Badge";
import { Label } from "@formbricks/ui/components/Label";
import { RadioGroup, RadioGroupItem } from "@formbricks/ui/components/RadioGroup";
interface HowToSendCardProps {
localSurvey: TSurvey;

View File

@@ -1,4 +1,4 @@
import { FileInput } from "@/modules/ui/components/file-input";
import { FileInput } from "@formbricks/ui/components/FileInput";
interface UploadImageSurveyBgProps {
environmentId: string;

View File

@@ -1,18 +1,18 @@
import { LogicEditorActions } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorActions";
import { LogicEditorConditions } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditorConditions";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/modules/ui/components/select";
import { ArrowRightIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { ReactElement, useMemo } from "react";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { QUESTIONS_ICON_MAP } from "@formbricks/lib/utils/questions";
import { TSurvey, TSurveyLogic, TSurveyQuestion } from "@formbricks/types/surveys/types";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@formbricks/ui/components/Select";
interface LogicEditorProps {
localSurvey: TSurvey;

View File

@@ -4,15 +4,7 @@ import {
getActionTargetOptions,
getActionValueOptions,
getActionVariableOptions,
hasJumpToQuestionAction,
} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { InputCombobox } from "@/modules/ui/components/input-combo-box";
import { createId } from "@paralleldrive/cuid2";
import { CopyIcon, CornerDownRightIcon, EllipsisVerticalIcon, PlusIcon, TrashIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -27,6 +19,13 @@ import {
TSurveyLogicAction,
TSurveyQuestion,
} from "@formbricks/types/surveys/types";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@formbricks/ui/components/DropdownMenu";
import { InputCombobox } from "@formbricks/ui/components/InputCombobox";
interface LogicEditorActions {
localSurvey: TSurvey;
@@ -61,11 +60,7 @@ export function LogicEditorActions({
actionsClone.splice(actionIdx, 1);
break;
case "addBelow":
actionsClone.splice(actionIdx + 1, 0, {
id: createId(),
objective: hasJumpToQuestionAction(logicItem.actions) ? "requireAnswer" : "jumpToQuestion",
target: "",
});
actionsClone.splice(actionIdx + 1, 0, { id: createId(), objective: "jumpToQuestion", target: "" });
break;
case "duplicate":
actionsClone.splice(actionIdx + 1, 0, { ...actionsClone[actionIdx], id: createId() });
@@ -93,11 +88,6 @@ export function LogicEditorActions({
handleActionsChange("update", actionIdx, actionBody);
};
const filteredObjectiveOptions = actionObjectiveOptions.filter(
(option) => option.value !== "jumpToQuestion"
);
const jumpToQuestionActionIdx = actions.findIndex((action) => action.objective === "jumpToQuestion");
return (
<div className="flex grow gap-2">
<CornerDownRightIcon className="mt-3 h-4 w-4 shrink-0" />
@@ -112,11 +102,7 @@ export function LogicEditorActions({
id={`action-${idx}-objective`}
key={`objective-${action.id}`}
showSearch={false}
options={
jumpToQuestionActionIdx === -1 || idx === jumpToQuestionActionIdx
? actionObjectiveOptions
: filteredObjectiveOptions
}
options={actionObjectiveOptions}
value={action.objective}
onChangeValue={(val: TActionObjective) => {
handleObjectiveChange(idx, val);

View File

@@ -4,13 +4,6 @@ import {
getDefaultOperatorForQuestion,
getMatchValueProps,
} from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { InputCombobox, TComboboxOption } from "@/modules/ui/components/input-combo-box";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { createId } from "@paralleldrive/cuid2";
import { CopyIcon, EllipsisVerticalIcon, PlusIcon, TrashIcon, WorkflowIcon } from "lucide-react";
@@ -34,6 +27,13 @@ import {
TSurveyLogicConditionsOperator,
TSurveyQuestion,
} from "@formbricks/types/surveys/types";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@formbricks/ui/components/DropdownMenu";
import { InputCombobox, TComboboxOption } from "@formbricks/ui/components/InputCombobox";
interface LogicEditorConditionsProps {
conditions: TConditionGroup;

View File

@@ -1,9 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { ShuffleOptionSelect } from "@/modules/ui/components/shuffle-option-select";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon, TrashIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -12,6 +9,9 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TI18nString, TSurvey, TSurveyMatrixQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { ShuffleOptionSelect } from "@formbricks/ui/components/ShuffleOptionSelect";
import { isLabelValidForAllLanguages } from "../lib/validation";
interface MatrixQuestionFormProps {

View File

@@ -2,9 +2,6 @@
import { findOptionUsedInLogic } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { ShuffleOptionSelect } from "@/modules/ui/components/shuffle-option-select";
import { DndContext } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { useAutoAnimate } from "@formkit/auto-animate/react";
@@ -23,6 +20,9 @@ import {
TSurveyQuestionTypeEnum,
} from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { ShuffleOptionSelect } from "@formbricks/ui/components/ShuffleOptionSelect";
import { QuestionOptionChoice } from "./QuestionOptionChoice";
interface MultipleChoiceQuestionFormProps {

View File

@@ -1,8 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Button } from "@/modules/ui/components/button";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -11,6 +9,8 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyNPSQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/components/Button";
interface NPSQuestionFormProps {
localSurvey: TSurvey;

View File

@@ -1,9 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { OptionsSwitch } from "@/modules/ui/components/options-switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { HashIcon, LinkIcon, MailIcon, MessageSquareTextIcon, PhoneIcon, PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -16,6 +13,9 @@ import {
TSurveyOpenTextQuestionInputType,
} from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { OptionsSwitch } from "@formbricks/ui/components/OptionsSwitch";
const questionTypes = [
{ value: "text", label: "common.text", icon: <MessageSquareTextIcon className="h-4 w-4" /> },

View File

@@ -1,8 +1,4 @@
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { FileInput } from "@/modules/ui/components/file-input";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { createId } from "@paralleldrive/cuid2";
import { PlusIcon } from "lucide-react";
@@ -13,6 +9,10 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyPictureSelectionQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { FileInput } from "@formbricks/ui/components/FileInput";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
interface PictureSelectionFormProps {
localSurvey: TSurvey;

View File

@@ -1,11 +1,11 @@
"use client";
import { Label } from "@/modules/ui/components/label";
import { getPlacementStyle } from "@/modules/ui/components/preview-survey/lib/utils";
import { RadioGroup, RadioGroupItem } from "@/modules/ui/components/radio-group";
import { useTranslations } from "next-intl";
import { cn } from "@formbricks/lib/cn";
import { TPlacement } from "@formbricks/types/common";
import { Label } from "@formbricks/ui/components/Label";
import { getPlacementStyle } from "@formbricks/ui/components/PreviewSurvey/lib/utils";
import { RadioGroup, RadioGroupItem } from "@formbricks/ui/components/RadioGroup";
const placements = [
{ name: "common.bottom_right", value: "bottomRight", disabled: false },

View File

@@ -4,8 +4,6 @@ import { ContactInfoQuestionForm } from "@/app/(app)/(survey-editor)/environment
import { RankingQuestionForm } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/RankingQuestionForm";
import { formatTextWithSlashes } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { useAutoAnimate } from "@formkit/auto-animate/react";
@@ -26,6 +24,8 @@ import {
TSurveyQuestionTypeEnum,
} from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
import { AddressQuestionForm } from "./AddressQuestionForm";
import { AdvancedSettings } from "./AdvancedSettings";
import { CTAQuestionForm } from "./CTAQuestionForm";

View File

@@ -1,5 +1,4 @@
import { ProBadge } from "@/modules/ui/components/pro-badge";
import { MailIcon, PaintbrushIcon, Rows3Icon, SettingsIcon } from "lucide-react";
import { PaintbrushIcon, Rows3Icon, SettingsIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { type JSX, useMemo } from "react";
import { cn } from "@formbricks/lib/cn";
@@ -9,15 +8,31 @@ interface Tab {
id: TSurveyEditorTabs;
label: string;
icon: JSX.Element;
isPro?: boolean;
}
const tabs: Tab[] = [
{
id: "questions",
label: "common.questions",
icon: <Rows3Icon className="h-5 w-5" />,
},
{
id: "styling",
label: "common.styling",
icon: <PaintbrushIcon className="h-5 w-5" />,
},
{
id: "settings",
label: "common.settings",
icon: <SettingsIcon className="h-5 w-5" />,
},
];
interface QuestionsAudienceTabsProps {
activeId: TSurveyEditorTabs;
setActiveId: React.Dispatch<React.SetStateAction<TSurveyEditorTabs>>;
isStylingTabVisible?: boolean;
isCxMode: boolean;
isSurveyFollowUpsAllowed: boolean;
}
export const QuestionsAudienceTabs = ({
@@ -25,35 +40,7 @@ export const QuestionsAudienceTabs = ({
setActiveId,
isStylingTabVisible,
isCxMode,
isSurveyFollowUpsAllowed = false,
}: QuestionsAudienceTabsProps) => {
const tabs: Tab[] = useMemo(
() => [
{
id: "questions",
label: "common.questions",
icon: <Rows3Icon className="h-5 w-5" />,
},
{
id: "styling",
label: "common.styling",
icon: <PaintbrushIcon className="h-5 w-5" />,
},
{
id: "settings",
label: "common.settings",
icon: <SettingsIcon className="h-5 w-5" />,
},
{
id: "followUps",
label: "environments.surveys.edit.follow_ups",
icon: <MailIcon className="h-5 w-5" />,
isPro: !isSurveyFollowUpsAllowed,
},
],
[isSurveyFollowUpsAllowed]
);
const t = useTranslations();
const tabsComputed = useMemo(() => {
if (isStylingTabVisible) {
@@ -82,7 +69,6 @@ export const QuestionsAudienceTabs = ({
aria-current={tab.id === activeId ? "page" : undefined}>
{tab.icon && <div className="mr-2 h-5 w-5">{tab.icon}</div>}
{t(tab.label)}
{tab.isPro && <ProBadge />}
</button>
))}
</nav>

View File

@@ -282,13 +282,11 @@ export const QuestionsView = ({
}
}
});
updatedSurvey.questions.splice(questionIdx, 1);
const firstEndingCard = localSurvey.endings[0];
setLocalSurvey(updatedSurvey);
delete internalQuestionIdMap[questionId];
if (questionId === activeQuestionIdTemp) {
if (questionIdx <= localSurvey.questions.length && localSurvey.questions.length > 0) {
setActiveQuestionId(localSurvey.questions[questionIdx % localSurvey.questions.length].id);
@@ -296,7 +294,6 @@ export const QuestionsView = ({
setActiveQuestionId(firstEndingCard.id);
}
}
toast.success(t("environments.surveys.edit.question_deleted"));
};

View File

@@ -1,9 +1,6 @@
"use client";
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { ShuffleOptionSelect } from "@/modules/ui/components/shuffle-option-select";
import { DndContext } from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { useAutoAnimate } from "@formkit/auto-animate/react";
@@ -15,6 +12,9 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TI18nString, TSurvey, TSurveyRankingQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { ShuffleOptionSelect } from "@formbricks/ui/components/ShuffleOptionSelect";
import { QuestionOptionChoice } from "./QuestionOptionChoice";
interface RankingQuestionFormProps {

View File

@@ -1,7 +1,4 @@
import { QuestionFormInput } from "@/modules/surveys/components/QuestionFormInput";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Button } from "@/modules/ui/components/button";
import { Label } from "@/modules/ui/components/label";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { HashIcon, PlusIcon, SmileIcon, StarIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -9,6 +6,9 @@ import { createI18nString, extractLanguageCodes } from "@formbricks/lib/i18n/uti
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TSurvey, TSurveyRatingQuestion } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/components/Button";
import { Label } from "@formbricks/ui/components/Label";
import { Dropdown } from "./RatingTypeDropdown";
interface RatingQuestionFormProps {

View File

@@ -1,9 +1,5 @@
"use client";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { RadioGroup, RadioGroupItem } from "@/modules/ui/components/radio-group";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
@@ -11,6 +7,10 @@ import { useTranslations } from "next-intl";
import Link from "next/link";
import { useEffect, useState } from "react";
import { TSurvey } from "@formbricks/types/surveys/types";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { RadioGroup, RadioGroupItem } from "@formbricks/ui/components/RadioGroup";
interface DisplayOption {
id: "displayOnce" | "displayMultiple" | "respondMultiple" | "displaySome";

View File

@@ -1,7 +1,7 @@
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { useTranslations } from "next-intl";
import { TSurveyRedirectUrlCard } from "@formbricks/types/surveys/types";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
interface RedirectUrlFormProps {
endingCard: TSurveyRedirectUrlCard;

View File

@@ -1,10 +1,5 @@
"use client";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { DatePicker } from "@/modules/ui/components/date-picker";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { ArrowUpRight, CheckIcon } from "lucide-react";
@@ -14,6 +9,11 @@ import { KeyboardEventHandler, useEffect, useState } from "react";
import toast from "react-hot-toast";
import { cn } from "@formbricks/lib/cn";
import { TSurvey } from "@formbricks/types/surveys/types";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { DatePicker } from "@formbricks/ui/components/DatePicker";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
interface ResponseOptionsCardProps {
localSurvey: TSurvey;

View File

@@ -1,9 +1,9 @@
import { Input } from "@/modules/ui/components/input";
import { Code2Icon, MousePointerClickIcon, SparklesIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { TActionClass } from "@formbricks/types/action-classes";
import { TSurvey } from "@formbricks/types/surveys/types";
import { Input } from "@formbricks/ui/components/Input";
interface SavedActionsTabProps {
actionClasses: TActionClass[];

View File

@@ -1,14 +1,3 @@
import { AlertDialog } from "@/modules/ui/components/alert-dialog";
import { Button } from "@/modules/ui/components/button";
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormProvider,
} from "@/modules/ui/components/form";
import { Switch } from "@/modules/ui/components/switch";
import { RotateCcwIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
@@ -18,6 +7,17 @@ import toast from "react-hot-toast";
import { TEnvironment } from "@formbricks/types/environment";
import { TProduct, TProductStyling } from "@formbricks/types/product";
import { TSurvey, TSurveyStyling } from "@formbricks/types/surveys/types";
import { AlertDialog } from "@formbricks/ui/components/AlertDialog";
import { Button } from "@formbricks/ui/components/Button";
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormProvider,
} from "@formbricks/ui/components/Form";
import { Switch } from "@formbricks/ui/components/Switch";
import { BackgroundStylingCard } from "./BackgroundStylingCard";
import { CardStylingSettings } from "./CardStylingSettings";
import { FormStylingSettings } from "./FormStylingSettings";

View File

@@ -1,7 +1,7 @@
import { TabBar } from "@/modules/ui/components/tab-bar";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";
import { TabBar } from "@formbricks/ui/components/TabBar";
import { AnimatedSurveyBg } from "./AnimatedSurveyBg";
import { ColorSurveyBg } from "./ColorSurveyBg";
import { UploadImageSurveyBg } from "./ImageSurveyBg";

View File

@@ -1,8 +1,6 @@
"use client";
import { FollowUpsView } from "@/modules/ee/survey-follow-ups/components/follow-ups-view";
import { TTeamPermission } from "@/modules/ee/teams/product-teams/types/teams";
import { PreviewSurvey } from "@/modules/ui/components/preview-survey";
import { useCallback, useEffect, useRef, useState } from "react";
import { extractLanguageCodes, getEnabledLanguages } from "@formbricks/lib/i18n/utils";
import { structuredClone } from "@formbricks/lib/pollyfills/structuredClone";
@@ -16,6 +14,7 @@ import { TProduct } from "@formbricks/types/product";
import { TSegment } from "@formbricks/types/segment";
import { TSurvey, TSurveyEditorTabs, TSurveyStyling } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { PreviewSurvey } from "@formbricks/ui/components/PreviewSurvey";
import { refetchProductAction } from "../actions";
import { LoadingSkeleton } from "./LoadingSkeleton";
import { QuestionsAudienceTabs } from "./QuestionsStylingSettingsTabs";
@@ -41,10 +40,7 @@ interface SurveyEditorProps {
plan: TOrganizationBillingPlan;
isCxMode: boolean;
locale: TUserLocale;
mailFrom: string;
isSurveyFollowUpsAllowed: boolean;
productPermission: TTeamPermission | null;
userEmail: string;
}
export const SurveyEditor = ({
@@ -64,10 +60,7 @@ export const SurveyEditor = ({
plan,
isCxMode = false,
locale,
mailFrom,
isSurveyFollowUpsAllowed = false,
productPermission,
userEmail,
}: SurveyEditorProps) => {
const [activeView, setActiveView] = useState<TSurveyEditorTabs>("questions");
const [activeQuestionId, setActiveQuestionId] = useState<string | null>(null);
@@ -168,7 +161,6 @@ export const SurveyEditor = ({
setActiveId={setActiveView}
isCxMode={isCxMode}
isStylingTabVisible={!!product.styling.allowStyleOverwrite}
isSurveyFollowUpsAllowed={isSurveyFollowUpsAllowed}
/>
{activeView === "questions" && (
@@ -223,18 +215,6 @@ export const SurveyEditor = ({
productPermission={productPermission}
/>
)}
{activeView === "followUps" && (
<FollowUpsView
localSurvey={localSurvey}
setLocalSurvey={setLocalSurvey}
selectedLanguageCode={selectedLanguageCode}
mailFrom={mailFrom}
isSurveyFollowUpsAllowed={isSurveyFollowUpsAllowed}
userEmail={userEmail}
locale={locale}
/>
)}
</main>
<aside className="group hidden flex-1 flex-shrink-0 items-center justify-center overflow-hidden border-l border-slate-200 bg-slate-100 shadow-inner md:flex md:flex-col">

View File

@@ -3,10 +3,6 @@
import { SurveyStatusDropdown } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/SurveyStatusDropdown";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { createSegmentAction } from "@/modules/ee/advanced-targeting/lib/actions";
import { AlertDialog } from "@/modules/ui/components/alert-dialog";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
import { isEqual } from "lodash";
import { AlertTriangleIcon, ArrowLeftIcon, SettingsIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -25,6 +21,10 @@ import {
ZSurveyEndScreenCard,
ZSurveyRedirectUrlCard,
} from "@formbricks/types/surveys/types";
import { AlertDialog } from "@formbricks/ui/components/AlertDialog";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui/components/Tooltip";
import { updateSurveyAction } from "../actions";
import { isSurveyValid } from "../lib/validation";

View File

@@ -1,7 +1,5 @@
"use client";
import { Label } from "@/modules/ui/components/label";
import { Switch } from "@/modules/ui/components/switch";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { CheckIcon } from "lucide-react";
@@ -10,6 +8,8 @@ import Link from "next/link";
import { useState } from "react";
import { TPlacement } from "@formbricks/types/common";
import { TSurvey, TSurveyProductOverwrites } from "@formbricks/types/surveys/types";
import { Label } from "@formbricks/ui/components/Label";
import { Switch } from "@formbricks/ui/components/Switch";
import { Placement } from "./Placement";
interface SurveyPlacementCardProps {

View File

@@ -1,17 +1,6 @@
"use client";
import { findVariableUsedInLogic } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils";
import { Button } from "@/modules/ui/components/button";
import { FormControl, FormField, FormItem, FormProvider } from "@/modules/ui/components/form";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/modules/ui/components/select";
import { createId } from "@paralleldrive/cuid2";
import { TrashIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -20,6 +9,17 @@ import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { extractRecallInfo } from "@formbricks/lib/utils/recall";
import { TSurvey, TSurveyVariable } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/components/Button";
import { FormControl, FormField, FormItem, FormProvider } from "@formbricks/ui/components/Form";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@formbricks/ui/components/Select";
interface SurveyVariablesCardItemProps {
variable?: TSurveyVariable;

View File

@@ -1,16 +1,6 @@
"use client";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { Alert, AlertDescription } from "@/modules/ui/components/alert";
import { AlertDialog } from "@/modules/ui/components/alert-dialog";
import { BasicAddFilterModal } from "@/modules/ui/components/basic-add-filter-modal";
import { BasicSegmentEditor } from "@/modules/ui/components/basic-segment-editor";
import { Button } from "@/modules/ui/components/button";
import { LoadSegmentModal } from "@/modules/ui/components/load-segment-modal";
import { SaveAsNewSegmentModal } from "@/modules/ui/components/save-as-new-segment-modal";
import { SegmentTitle } from "@/modules/ui/components/segment-title";
import { TargetingIndicator } from "@/modules/ui/components/targeting-indicator";
import { UpgradePlanNotice } from "@/modules/ui/components/upgrade-plan-notice";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import { AlertCircle, CheckIcon, ChevronDownIcon, ChevronUpIcon, PencilIcon } from "lucide-react";
@@ -25,6 +15,16 @@ import { isAdvancedSegment } from "@formbricks/lib/segment/utils";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
import { TBaseFilter, TSegment, TSegmentCreateInput, TSegmentUpdateInput } from "@formbricks/types/segment";
import { TSurvey } from "@formbricks/types/surveys/types";
import { Alert, AlertDescription } from "@formbricks/ui/components/Alert";
import { AlertDialog } from "@formbricks/ui/components/AlertDialog";
import { BasicAddFilterModal } from "@formbricks/ui/components/BasicAddFilterModal";
import { BasicSegmentEditor } from "@formbricks/ui/components/BasicSegmentEditor";
import { Button } from "@formbricks/ui/components/Button";
import { LoadSegmentModal } from "@formbricks/ui/components/LoadSegmentModal";
import { SaveAsNewSegmentModal } from "@formbricks/ui/components/SaveAsNewSegmentModal";
import { SegmentTitle } from "@formbricks/ui/components/SegmentTitle";
import { TargetingIndicator } from "@formbricks/ui/components/TargetingIndicator";
import { UpgradePlanNotice } from "@formbricks/ui/components/UpgradePlanNotice";
import {
cloneBasicSegmentAction,
createBasicSegmentAction,

View File

@@ -1,8 +1,5 @@
"use client";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { LoadingSpinner } from "@/modules/ui/components/loading-spinner";
import { debounce } from "lodash";
import { SearchIcon } from "lucide-react";
import { useTranslations } from "next-intl";
@@ -10,6 +7,9 @@ import UnsplashImage from "next/image";
import { useEffect, useRef, useState } from "react";
import toast from "react-hot-toast";
import { TSurveyBackgroundBgType } from "@formbricks/types/surveys/types";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { LoadingSpinner } from "@formbricks/ui/components/LoadingSpinner";
import { getImagesFromUnsplashAction, triggerDownloadUnsplashImageAction } from "../actions";
interface ImageFromUnsplashSurveyBgProps {

View File

@@ -1,13 +1,13 @@
"use client";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { Label } from "@/modules/ui/components/label";
import { useTranslations } from "next-intl";
import { useState } from "react";
import toast from "react-hot-toast";
import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys/types";
import { validateId } from "@formbricks/types/surveys/validation";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { Label } from "@formbricks/ui/components/Label";
interface UpdateQuestionIdProps {
localSurvey: TSurvey;

View File

@@ -2,9 +2,6 @@
import { TTeamPermission } from "@/modules/ee/teams/product-teams/types/teams";
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
import { AdvancedOptionToggle } from "@/modules/ui/components/advanced-option-toggle";
import { Button } from "@/modules/ui/components/button";
import { Input } from "@/modules/ui/components/input";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as Collapsible from "@radix-ui/react-collapsible";
import {
@@ -21,6 +18,9 @@ import { getAccessFlags } from "@formbricks/lib/membership/utils";
import { TActionClass } from "@formbricks/types/action-classes";
import { TOrganizationRole } from "@formbricks/types/memberships";
import { TSurvey } from "@formbricks/types/surveys/types";
import { AdvancedOptionToggle } from "@formbricks/ui/components/AdvancedOptionToggle";
import { Button } from "@formbricks/ui/components/Button";
import { Input } from "@formbricks/ui/components/Input";
import { AddActionModal } from "./AddActionModal";
interface WhenToSendCardProps {

View File

@@ -366,18 +366,6 @@ export const logicRules = {
},
],
},
[TSurveyQuestionTypeEnum.ContactInfo]: {
options: [
{
label: "environments.surveys.edit.is_submitted",
value: ZSurveyLogicConditionsOperator.Enum.isSubmitted,
},
{
label: "environments.surveys.edit.is_skipped",
value: ZSurveyLogicConditionsOperator.Enum.isSkipped,
},
],
},
},
["variable.text"]: {
options: [

View File

@@ -1,33 +0,0 @@
import { Prisma } from "@prisma/client";
import { cache as reactCache } from "react";
import { prisma } from "@formbricks/database";
import { cache } from "@formbricks/lib/cache";
import { userCache } from "@formbricks/lib/user/cache";
import { DatabaseError } from "@formbricks/types/errors";
export const getUserEmail = reactCache(
(userId: string): Promise<string | null> =>
cache(
async () => {
try {
const user = await prisma.user.findUnique({ where: { id: userId }, select: { email: true } });
if (!user) {
return null;
}
return user.email;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError(error.message);
}
throw error;
}
},
[`getUserEmail-${userId}`],
{
tags: [userCache.tag.byId(userId)],
}
)()
);

View File

@@ -1,9 +1,7 @@
import { TComboboxGroupedOption, TComboboxOption } from "@/modules/ui/components/input-combo-box";
import { EyeOffIcon, FileDigitIcon, FileType2Icon } from "lucide-react";
import { HTMLInputTypeAttribute } from "react";
import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { isConditionGroup } from "@formbricks/lib/surveyLogic/utils";
import { translate } from "@formbricks/lib/templates";
import { getQuestionTypes } from "@formbricks/lib/utils/questions";
import { recallToHeadline } from "@formbricks/lib/utils/recall";
import { TAttributeClass } from "@formbricks/types/attribute-classes";
@@ -15,14 +13,13 @@ import {
TSurvey,
TSurveyLogic,
TSurveyLogicAction,
TSurveyLogicActions,
TSurveyLogicConditionsOperator,
TSurveyQuestion,
TSurveyQuestionId,
TSurveyQuestionTypeEnum,
TSurveyVariable,
} from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { TComboboxGroupedOption, TComboboxOption } from "@formbricks/ui/components/InputCombobox";
import { TLogicRuleOption, logicRules } from "./logicRuleEngine";
// formats the text to highlight specific parts of the text with slashes
@@ -150,10 +147,6 @@ export const actionObjectiveOptions: TComboboxOption[] = [
{ label: "environments.surveys.edit.jump_to_question", value: "jumpToQuestion" },
];
export const hasJumpToQuestionAction = (actions: TSurveyLogicActions): boolean => {
return actions.some((action) => action.objective === "jumpToQuestion");
};
const getQuestionOperatorOptions = (question: TSurveyQuestion): TComboboxOption[] => {
let options: TLogicRuleOption;
@@ -610,10 +603,8 @@ export const getMatchValueProps = (
options: groupedOptions,
};
} else if (selectedVariable?.type === "number") {
const allowedQuestions = questions.filter(
(question) =>
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type) ||
(question.type === TSurveyQuestionTypeEnum.OpenText && question.inputType === "number")
const allowedQuestions = questions.filter((question) =>
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
);
const questionOptions = allowedQuestions.map((question) => {
@@ -949,10 +940,8 @@ export const getActionValueOptions = (
return groupedOptions;
} else if (selectedVariable.type === "number") {
const allowedQuestions = questions.filter(
(question) =>
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type) ||
(question.type === TSurveyQuestionTypeEnum.OpenText && question.inputType === "number")
const allowedQuestions = questions.filter((question) =>
[TSurveyQuestionTypeEnum.Rating, TSurveyQuestionTypeEnum.NPS].includes(question.type)
);
const questionOptions = allowedQuestions.map((question) => {
@@ -1159,10 +1148,6 @@ export const findHiddenFieldUsedInLogic = (survey: TSurvey, hiddenFieldId: strin
return survey.questions.findIndex((question) => question.logic?.some(isUsedInLogicRule));
};
export const getSurveyFollowUpActionDefaultBody = (locale: TUserLocale) => {
return translate("follow_ups_modal_action_body", locale) as string;
};
export const findEndingCardUsedInLogic = (survey: TSurvey, endingCardId: string): number => {
const isUsedInAction = (action: TSurveyLogicAction): boolean => {
return action.objective === "jumpToQuestion" && action.target === endingCardId;

View File

@@ -1,21 +1,14 @@
import { getUserEmail } from "@/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/user";
import {
getAdvancedTargetingPermission,
getMultiLanguagePermission,
getSurveyFollowUpsPermission,
} from "@/modules/ee/license-check/lib/utils";
import { getProductPermissionByUserId } from "@/modules/ee/teams/lib/roles";
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
import { ErrorComponent } from "@/modules/ui/components/error-component";
import { getServerSession } from "next-auth";
import { getTranslations } from "next-intl/server";
import { getAdvancedTargetingPermission, getMultiLanguagePermission } from "@formbricks/ee/lib/service";
import { getActionClasses } from "@formbricks/lib/actionClass/service";
import { getAttributeClasses } from "@formbricks/lib/attributeClass/service";
import { authOptions } from "@formbricks/lib/authOptions";
import {
DEFAULT_LOCALE,
IS_FORMBRICKS_CLOUD,
MAIL_FROM,
SURVEY_BG_COLORS,
UNSPLASH_ACCESS_KEY,
} from "@formbricks/lib/constants";
@@ -28,6 +21,7 @@ import { getResponseCountBySurveyId } from "@formbricks/lib/response/service";
import { getSegments } from "@formbricks/lib/segment/service";
import { getSurvey } from "@formbricks/lib/survey/service";
import { getUserLocale } from "@formbricks/lib/user/service";
import { ErrorComponent } from "@formbricks/ui/components/ErrorComponent";
import { SurveyEditor } from "./components/SurveyEditor";
export const generateMetadata = async (props) => {
@@ -63,7 +57,6 @@ const Page = async (props) => {
getServerSession(authOptions),
getSegments(params.environmentId),
]);
if (!session) {
throw new Error(t("common.session_not_found"));
}
@@ -88,9 +81,6 @@ const Page = async (props) => {
const isUserTargetingAllowed = await getAdvancedTargetingPermission(organization);
const isMultiLanguageAllowed = await getMultiLanguagePermission(organization);
const isSurveyFollowUpsAllowed = await getSurveyFollowUpsPermission(organization);
const userEmail = await getUserEmail(session.user.id);
if (
!survey ||
@@ -98,7 +88,6 @@ const Page = async (props) => {
!actionClasses ||
!attributeClasses ||
!product ||
!userEmail ||
isSurveyCreationDeletionDisabled
) {
return <ErrorComponent />;
@@ -125,9 +114,6 @@ const Page = async (props) => {
isUnsplashConfigured={UNSPLASH_ACCESS_KEY ? true : false}
isCxMode={isCxMode}
locale={locale ?? DEFAULT_LOCALE}
mailFrom={MAIL_FROM ?? "hola@formbricks.com"}
isSurveyFollowUpsAllowed={isSurveyFollowUpsAllowed}
userEmail={userEmail}
/>
);
};

View File

@@ -1,13 +0,0 @@
import { z } from "zod";
export const ZCreateSurveyFollowUpFormSchema = z.object({
followUpName: z.string().trim().min(1, "Name is required"),
triggerType: z.enum(["response", "endings"]),
endingIds: z.array(z.string().cuid2()).nullable(),
emailTo: z.string().trim().min(1, "To is required"),
replyTo: z.array(z.string().email()).min(1, "Replies must have at least one email"),
subject: z.string().trim().min(1, "Subject is required"),
body: z.string().trim().min(1, "Body is required"),
});
export type TCreateSurveyFollowUpForm = z.infer<typeof ZCreateSurveyFollowUpFormSchema>;

View File

@@ -39,5 +39,4 @@ export const getMinimalSurvey = (locale: string): TSurvey => ({
isVerifyEmailEnabled: false,
isSingleResponsePerEmailEnabled: false,
variables: [],
followUps: [],
});

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