fix: Check for complete submission before displaying CTA on Thank You… (#1979)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Dhruwang Jariwala
2024-02-27 17:05:52 +05:30
committed by GitHub
parent 21787f2af5
commit 8064e1ecf6
8 changed files with 44 additions and 37 deletions

View File

@@ -18,6 +18,7 @@ import ContentWrapper from "@formbricks/ui/ContentWrapper";
import { SurveyInline } from "@formbricks/ui/Survey";
let setIsError = (_: boolean) => {};
let setIsResponseSendingFinished = (_: boolean) => {};
interface LinkSurveyProps {
survey: TSurvey;
@@ -72,6 +73,10 @@ export default function LinkSurvey({
onResponseSendingFailed: () => {
setIsError(true);
},
onResponseSendingFinished: () => {
// when response of current question is processed successfully
setIsResponseSendingFinished(true);
},
setSurveyState: setSurveyState,
},
surveyState
@@ -157,6 +162,9 @@ export default function LinkSurvey({
getSetIsError={(f: (value: boolean) => void) => {
setIsError = f;
}}
getSetIsResponseSendingFinished={(f: (value: boolean) => void) => {
setIsResponseSendingFinished = f;
}}
onRetry={() => {
setIsError(false);
responseQueue.processQueue();

View File

@@ -16,6 +16,7 @@ const logger = Logger.getInstance();
const errorHandler = ErrorHandler.getInstance();
let surveyRunning = false;
let setIsError = (_: boolean) => {};
let setIsResponseSendingFinished = (_: boolean) => {};
export const renderWidget = async (survey: TSurvey) => {
if (surveyRunning) {
@@ -40,6 +41,9 @@ export const renderWidget = async (survey: TSurvey) => {
onResponseSendingFailed: () => {
setIsError(true);
},
onResponseSendingFinished: () => {
setIsResponseSendingFinished(true);
},
},
surveyState
);
@@ -51,7 +55,6 @@ export const renderWidget = async (survey: TSurvey) => {
const darkOverlay = productOverwrites.darkOverlay ?? product.darkOverlay;
const placement = productOverwrites.placement ?? product.placement;
const isBrandingEnabled = product.inAppSurveyBranding;
const formbricksSurveys = await loadFormbricksSurveysExternally();
setTimeout(() => {
@@ -66,6 +69,9 @@ export const renderWidget = async (survey: TSurvey) => {
getSetIsError: (f: (value: boolean) => void) => {
setIsError = f;
},
getSetIsResponseSendingFinished: (f: (value: boolean) => void) => {
setIsResponseSendingFinished = f;
},
onDisplay: async () => {
const { userId } = config.get();
// if config does not have a person, we store the displays in local storage

View File

@@ -9,6 +9,7 @@ interface QueueConfig {
environmentId: string;
retryAttempts: number;
onResponseSendingFailed?: (responseUpdate: TResponseUpdate) => void;
onResponseSendingFinished?: () => void;
setSurveyState?: (state: SurveyState) => void;
}
@@ -68,6 +69,9 @@ export class ResponseQueue {
}
this.isRequestInProgress = false;
} else {
if (responseUpdate.finished && this.config.onResponseSendingFinished) {
this.config.onResponseSendingFinished();
}
this.isRequestInProgress = false;
this.processQueue(); // process the next item in the queue if any
}

View File

@@ -29,6 +29,7 @@ export function Survey({
isRedirectDisabled = false,
prefillResponseData,
getSetIsError,
getSetIsResponseSendingFinished,
onFileUpload,
responseCount,
}: SurveyBaseProps) {
@@ -36,6 +37,9 @@ export function Survey({
activeQuestionId || (survey.welcomeCard.enabled ? "start" : survey?.questions[0]?.id)
);
const [showError, setShowError] = useState(false);
// flag state to store whether response processing has been completed or not
const [isResponseSendingFinished, setIsResponseSendingFinished] = useState(false);
const [loadingElement, setLoadingElement] = useState(false);
const [history, setHistory] = useState<string[]>([]);
const [responseData, setResponseData] = useState<TResponseData>({});
@@ -85,7 +89,15 @@ export function Survey({
setShowError(value);
});
}
});
}, [getSetIsError]);
useEffect(() => {
if (getSetIsResponseSendingFinished) {
getSetIsResponseSendingFinished((value: boolean) => {
setIsResponseSendingFinished(value);
});
}
}, [getSetIsResponseSendingFinished]);
let currIdxTemp = currentQuestionIndex;
let currQuesTemp = currentQuestion;
@@ -216,6 +228,7 @@ export function Survey({
} else if (questionId === "end" && survey.thankYouCard.enabled) {
return (
<ThankYouCard
isResponseSendingFinished={isResponseSendingFinished}
headline={
typeof survey.thankYouCard.headline === "string"
? replaceRecallInfo(survey.thankYouCard.headline)

View File

@@ -15,6 +15,7 @@ export function SurveyModal({
darkOverlay,
highlightBorderColor,
onDisplay,
getSetIsResponseSendingFinished,
onActiveQuestionChange,
onResponse,
onClose,
@@ -49,6 +50,7 @@ export function SurveyModal({
isBrandingEnabled={isBrandingEnabled}
activeQuestionId={activeQuestionId}
onDisplay={onDisplay}
getSetIsResponseSendingFinished={getSetIsResponseSendingFinished}
onActiveQuestionChange={onActiveQuestionChange}
onResponse={onResponse}
onClose={close}

View File

@@ -13,6 +13,7 @@ interface ThankYouCardProps {
buttonLabel?: string;
buttonLink?: string;
imageUrl?: string;
isResponseSendingFinished: boolean;
}
export default function ThankYouCard({
@@ -23,9 +24,10 @@ export default function ThankYouCard({
buttonLabel,
buttonLink,
imageUrl,
isResponseSendingFinished,
}: ThankYouCardProps) {
useEffect(() => {
if (!buttonLink) return;
if (!buttonLink || !isResponseSendingFinished) return;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Enter") {
window.top?.location.replace(buttonLink);
@@ -35,7 +37,7 @@ export default function ThankYouCard({
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [buttonLink]);
}, [buttonLink, isResponseSendingFinished]);
return (
<div className="text-center">
@@ -66,7 +68,7 @@ export default function ThankYouCard({
<Headline alignTextCenter={true} headline={headline} questionId="thankYouCard" />
<Subheader subheader={subheader} questionId="thankYouCard" />
<RedirectCountDown redirectUrl={redirectUrl} isRedirectDisabled={isRedirectDisabled} />
{buttonLabel && (
{buttonLabel && isResponseSendingFinished && (
<div className="mt-6 flex w-full flex-col items-center justify-center space-y-4">
<Button
buttonLabel={buttonLabel}

View File

@@ -7,6 +7,7 @@ export interface SurveyBaseProps {
isBrandingEnabled: boolean;
activeQuestionId?: string;
getSetIsError?: (getSetError: (value: boolean) => void) => void;
getSetIsResponseSendingFinished?: (getSetIsResponseSendingFinished: (value: boolean) => void) => void;
onDisplay?: () => void;
onResponse?: (response: TResponseUpdate) => void;
onFinished?: () => void;

View File

@@ -1,40 +1,11 @@
import { useEffect, useMemo } from "react";
import { renderSurveyInline, renderSurveyModal } from "@formbricks/surveys";
import { TResponseData, TResponseUpdate } from "@formbricks/types/responses";
import { TUploadFileConfig } from "@formbricks/types/storage";
import { TSurvey } from "@formbricks/types/surveys";
import { SurveyInlineProps, SurveyModalProps } from "@formbricks/types/formbricksSurveys";
const createContainerId = () => `formbricks-survey-container`;
interface SurveyProps {
survey: TSurvey;
brandColor: string;
isBrandingEnabled: boolean;
activeQuestionId?: string;
getSetIsError?: (getSetError: (value: boolean) => void) => void;
onRetry?: () => void;
onDisplay?: () => void;
onResponse?: (response: TResponseUpdate) => void;
onFinished?: () => void;
onActiveQuestionChange?: (questionId: string) => void;
onClose?: () => void;
onFileUpload: (file: File, config?: TUploadFileConfig) => Promise<string>;
autoFocus?: boolean;
prefillResponseData?: TResponseData;
isRedirectDisabled?: boolean;
responseCount?: number;
supportEmail?: string | null;
}
interface SurveyModalProps extends SurveyProps {
placement: "topRight" | "bottomRight" | "bottomLeft" | "topLeft" | "center";
clickOutside: boolean;
darkOverlay: boolean;
highlightBorderColor: string | null;
}
export const SurveyInline = (props: SurveyProps) => {
export const SurveyInline = (props: Omit<SurveyInlineProps & { brandColor: string }, "containerId">) => {
const containerId = useMemo(() => createContainerId(), []);
useEffect(() => {
renderSurveyInline({
@@ -45,7 +16,7 @@ export const SurveyInline = (props: SurveyProps) => {
return <div id={containerId} className="h-full w-full" />;
};
export const SurveyModal = (props: SurveyModalProps) => {
export const SurveyModal = (props: SurveyModalProps & { brandColor: string }) => {
useEffect(() => {
renderSurveyModal(props);
}, [props]);