fix: make description optional for consent and CTA elements

- Made description field optional in consent-element-form.tsx
- Made description field optional in cta-element-form.tsx
- Added conditional rendering with 'Add description' button when subheader is undefined
- Removed special handling that prevented remove description button for CTA/Consent elements
- Added useAutoAnimate for smooth transitions when adding/removing description
- Ensures consistency with other question element forms where description is optional
This commit is contained in:
Dhruwang
2025-12-30 11:41:58 +05:30
parent 3434b5cf08
commit be7005b9b4
3 changed files with 85 additions and 38 deletions
@@ -153,9 +153,9 @@ export const ElementFormInput = ({
(currentElement &&
(id.includes(".")
? // Handle nested properties
(currentElement[id.split(".")[0] as keyof TSurveyElement] as any)?.[id.split(".")[1]]
(currentElement[id.split(".")[0] as keyof TSurveyElement] as any)?.[id.split(".")[1]]
: // Original behavior
(currentElement[id as keyof TSurveyElement] as TI18nString))) ||
(currentElement[id as keyof TSurveyElement] as TI18nString))) ||
createI18nString("", surveyLanguageCodes)
);
}, [
@@ -308,14 +308,6 @@ export const ElementFormInput = ({
const setFirstRender = externalSetFirstRender ?? setInternalFirstRender;
const renderRemoveDescriptionButton = () => {
if (
currentElement &&
(currentElement.type === TSurveyElementTypeEnum.CTA ||
currentElement.type === TSurveyElementTypeEnum.Consent)
) {
return false;
}
if (id === "subheader") {
return !!currentElement?.subheader || (endingCard?.type === "endScreen" && !!endingCard?.subheader);
}
@@ -591,9 +583,8 @@ export const ElementFormInput = ({
<div className="h-10 w-full"></div>
<div
ref={highlightContainerRef}
className={`no-scrollbar absolute top-0 z-0 mt-0.5 flex h-10 w-full overflow-scroll whitespace-nowrap px-3 py-2 text-center text-sm text-transparent ${
localSurvey.languages?.length > 1 ? "pr-24" : ""
}`}
className={`no-scrollbar absolute top-0 z-0 mt-0.5 flex h-10 w-full overflow-scroll whitespace-nowrap px-3 py-2 text-center text-sm text-transparent ${localSurvey.languages?.length > 1 ? "pr-24" : ""
}`}
dir="auto"
key={highlightedJSX.toString()}>
{highlightedJSX}
@@ -620,9 +611,8 @@ export const ElementFormInput = ({
maxLength={maxLength}
ref={inputRef}
onBlur={onBlur}
className={`absolute top-0 text-black caret-black ${
localSurvey.languages?.length > 1 ? "pr-24" : ""
} ${className}`}
className={`absolute top-0 text-black caret-black ${localSurvey.languages?.length > 1 ? "pr-24" : ""
} ${className}`}
isInvalid={
isInvalid &&
text[usedLanguageCode]?.trim() === "" &&
@@ -1,11 +1,15 @@
"use client";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { type JSX } from "react";
import { useTranslation } from "react-i18next";
import { TSurveyConsentElement } from "@formbricks/types/surveys/elements";
import { TSurvey } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
import { Button } from "@/modules/ui/components/button";
interface ConsentElementFormProps {
localSurvey: TSurvey;
@@ -33,6 +37,7 @@ export const ConsentElementForm = ({
isExternalUrlsAllowed,
}: ConsentElementFormProps): JSX.Element => {
const { t } = useTranslation();
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
// Common props shared across all ElementFormInput components
const commonInputProps = {
@@ -47,6 +52,8 @@ export const ConsentElementForm = ({
isExternalUrlsAllowed,
};
const [parent] = useAutoAnimate();
return (
<form>
<ElementFormInput
@@ -57,13 +64,35 @@ export const ConsentElementForm = ({
autoFocus={!element.headline?.default || element.headline.default.trim() === ""}
/>
<div className="mt-3">
<ElementFormInput
{...commonInputProps}
id="subheader"
value={element.subheader}
label={t("common.description")}
/>
<div ref={parent}>
{element.subheader !== undefined && (
<div className="inline-flex w-full items-center">
<div className="w-full">
<ElementFormInput
{...commonInputProps}
id="subheader"
value={element.subheader}
label={t("common.description")}
autoFocus={!element.subheader?.default || element.subheader.default.trim() === ""}
/>
</div>
</div>
)}
{element.subheader === undefined && (
<Button
size="sm"
variant="secondary"
className="mt-3"
type="button"
onClick={() => {
updateElement(elementIdx, {
subheader: createI18nString("", surveyLanguageCodes),
});
}}>
<PlusIcon className="mr-1 h-4 w-4" />
{t("environments.surveys.edit.add_description")}
</Button>
)}
</div>
<ElementFormInput
@@ -1,12 +1,16 @@
"use client";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { PlusIcon } from "lucide-react";
import { type JSX } from "react";
import { useTranslation } from "react-i18next";
import { TSurveyCTAElement } from "@formbricks/types/surveys/elements";
import { TSurvey } from "@formbricks/types/surveys/types";
import { TUserLocale } from "@formbricks/types/user";
import { createI18nString, extractLanguageCodes } from "@/lib/i18n/utils";
import { ElementFormInput } from "@/modules/survey/components/element-form-input";
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";
@@ -38,6 +42,8 @@ export const CTAElementForm = ({
isExternalUrlsAllowed,
}: CTAElementFormProps): JSX.Element => {
const { t } = useTranslation();
const surveyLanguageCodes = extractLanguageCodes(localSurvey.languages);
const [parent] = useAutoAnimate();
return (
<form>
@@ -57,21 +63,43 @@ export const CTAElementForm = ({
isExternalUrlsAllowed={isExternalUrlsAllowed}
/>
<div className="mt-3">
<ElementFormInput
id="subheader"
value={element.subheader}
label={t("common.description")}
localSurvey={localSurvey}
elementIdx={elementIdx}
isInvalid={isInvalid}
updateElement={updateElement}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
locale={locale}
isStorageConfigured={isStorageConfigured}
isExternalUrlsAllowed={isExternalUrlsAllowed}
/>
<div ref={parent}>
{element.subheader !== undefined && (
<div className="inline-flex w-full items-center">
<div className="w-full">
<ElementFormInput
id="subheader"
value={element.subheader}
label={t("common.description")}
localSurvey={localSurvey}
elementIdx={elementIdx}
isInvalid={isInvalid}
updateElement={updateElement}
selectedLanguageCode={selectedLanguageCode}
setSelectedLanguageCode={setSelectedLanguageCode}
locale={locale}
isStorageConfigured={isStorageConfigured}
autoFocus={!element.subheader?.default || element.subheader.default.trim() === ""}
isExternalUrlsAllowed={isExternalUrlsAllowed}
/>
</div>
</div>
)}
{element.subheader === undefined && (
<Button
size="sm"
variant="secondary"
className="mt-3"
type="button"
onClick={() => {
updateElement(elementIdx, {
subheader: createI18nString("", surveyLanguageCodes),
});
}}>
<PlusIcon className="mr-1 h-4 w-4" />
{t("environments.surveys.edit.add_description")}
</Button>
)}
</div>
<div className="mt-3 flex-1">