diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/components/WhenToSendCard.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/components/WhenToSendCard.tsx index aab2b5d0d5..c0baf76dbf 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/components/WhenToSendCard.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/components/WhenToSendCard.tsx @@ -40,9 +40,11 @@ export default function WhenToSendCard({ const [isAddEventModalOpen, setAddEventModalOpen] = useState(false); const [activeIndex, setActiveIndex] = useState(null); const [actionClasses, setActionClasses] = useState(propActionClasses); + const [randomizerToggle, setRandomizerToggle] = useState(localSurvey.displayPercentage ? true : false); const { isViewer } = getAccessFlags(membershipRole); const autoClose = localSurvey.autoClose !== null; + const delay = localSurvey.delay !== 0; const addTriggerEvent = useCallback(() => { const updatedSurvey = { ...localSurvey }; @@ -71,7 +73,7 @@ export default function WhenToSendCard({ setLocalSurvey(updatedSurvey); }; - const handleCheckMark = () => { + const handleAutoCloseToggle = () => { if (autoClose) { const updatedSurvey = { ...localSurvey, autoClose: null }; setLocalSurvey(updatedSurvey); @@ -81,6 +83,27 @@ export default function WhenToSendCard({ } }; + const handleDelayToggle = () => { + if (delay) { + const updatedSurvey = { ...localSurvey, delay: 0 }; + setLocalSurvey(updatedSurvey); + } else { + const updatedSurvey = { ...localSurvey, delay: 5 }; + setLocalSurvey(updatedSurvey); + } + }; + + const handleDisplayPercentageToggle = () => { + if (localSurvey.displayPercentage) { + const updatedSurvey = { ...localSurvey, displayPercentage: null }; + setLocalSurvey(updatedSurvey); + } else { + const updatedSurvey = { ...localSurvey, displayPercentage: 50 }; + setLocalSurvey(updatedSurvey); + } + setRandomizerToggle(!randomizerToggle); + }; + const handleInputSeconds = (e: any) => { let value = parseInt(e.target.value); @@ -96,6 +119,11 @@ export default function WhenToSendCard({ setLocalSurvey(updatedSurvey); }; + const handleRandomizerInput = (e) => { + const updatedSurvey = { ...localSurvey, displayPercentage: parseInt(e.target.value) }; + setLocalSurvey(updatedSurvey); + }; + useEffect(() => { if (isAddEventModalOpen) return; if (activeIndex !== null) { @@ -155,8 +183,9 @@ export default function WhenToSendCard({ - -
+
+ + {!isAddEventModalOpen && localSurvey.triggers?.map((triggerEventClass, idx) => (
@@ -209,7 +238,14 @@ export default function WhenToSendCard({
-
+
+
- - + @@ -252,6 +287,30 @@ export default function WhenToSendCard({

+ +
+
+

+ Show to {localSurvey.displayPercentage}% of targeted users +

+ +
+
+
{ + const randomNum = Math.floor(Math.random() * 100) + 1; + return randomNum <= displayPercentage; +}; + export const trackAction = async ( name: string, properties: TJsActionInput["properties"] = {} @@ -64,6 +69,14 @@ export const trackAction = async ( export const triggerSurvey = async (actionName: string, activeSurveys: TSurvey[]): Promise => { for (const survey of activeSurveys) { + // Check if the survey should be displayed based on displayPercentage + if (survey.displayPercentage) { + const shouldDisplaySurvey = shouldDisplayBasedOnPercentage(survey.displayPercentage); + if (!shouldDisplaySurvey) { + logger.debug("Survey display skipped based on displayPercentage."); + continue; + } + } for (const trigger of survey.triggers) { if (trigger === actionName) { logger.debug(`Formbricks: survey ${survey.id} triggered by action "${actionName}"`); diff --git a/packages/lib/survey/service.ts b/packages/lib/survey/service.ts index dbee579647..caeb778040 100644 --- a/packages/lib/survey/service.ts +++ b/packages/lib/survey/service.ts @@ -41,6 +41,7 @@ export const selectSurvey = { autoClose: true, closeOnDate: true, delay: true, + displayPercentage: true, autoComplete: true, verifyEmail: true, redirectUrl: true, diff --git a/packages/lib/survey/tests/survey.mock.ts b/packages/lib/survey/tests/survey.mock.ts index d0ed5caedc..07f034440b 100644 --- a/packages/lib/survey/tests/survey.mock.ts +++ b/packages/lib/survey/tests/survey.mock.ts @@ -135,6 +135,7 @@ export const mockSurveyOutput: SurveyMock = { productOverwrites: null, singleUse: null, styling: null, + displayPercentage: null, pin: null, resultShareKey: null, ...baseSurveyProperties, @@ -157,6 +158,7 @@ export const updateSurveyInput: TSurvey = { productOverwrites: null, styling: null, singleUse: null, + displayPercentage: null, pin: null, resultShareKey: null, ...commonMockProperties, diff --git a/packages/types/surveys.ts b/packages/types/surveys.ts index 8785a4a9e4..32f56c8c60 100644 --- a/packages/types/surveys.ts +++ b/packages/types/surveys.ts @@ -435,6 +435,7 @@ export const ZSurvey = z.object({ verifyEmail: ZSurveyVerifyEmail.nullable(), pin: z.string().nullable().optional(), resultShareKey: z.string().nullable(), + displayPercentage: z.number().min(1).max(100).nullable(), }); export const ZSurveyInput = z.object({