From b6c0dbf5d38598ad5bc401d536fc30d6f7b6abaa Mon Sep 17 00:00:00 2001
From: Pradumn Kumar
Date: Mon, 7 Aug 2023 18:52:37 +0530
Subject: [PATCH] Close survey after x responses now needs to be set to a
higher number than the number of current responses (#606)
* fix: fixes close survey on x response issue
* feat: updates
* chore: don't update _count
* chore: optimizations
* fix: fixes issue with not being able to enter a lower value at all
* update toast message
* add response count to toast
* only count completed responses
---------
Co-authored-by: Johannes
Co-authored-by: Matthias Nannt
---
.../[surveyId]/edit/ResponseOptionsCard.tsx | 34 +++++++++++++++----
.../surveys/[surveyId]/edit/SurveyEditor.tsx | 2 +-
.../surveys/[surveyId]/edit/SurveyMenuBar.tsx | 11 ++++++
apps/web/lib/surveys/surveys.ts | 4 +--
.../surveys/[surveyId]/index.ts | 5 +++
packages/types/surveys.ts | 1 +
6 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/ResponseOptionsCard.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/ResponseOptionsCard.tsx
index 5d54f3142d..586e4d8b6a 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/ResponseOptionsCard.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/ResponseOptionsCard.tsx
@@ -5,6 +5,7 @@ import { DatePicker, Input, Label, Switch } from "@formbricks/ui";
import { CheckCircleIcon } from "@heroicons/react/24/solid";
import * as Collapsible from "@radix-ui/react-collapsible";
import { useEffect, useState } from "react";
+import toast from "react-hot-toast";
interface ResponseOptionsCardProps {
localSurvey: Survey;
@@ -117,13 +118,27 @@ export default function ResponseOptionsCard({ localSurvey, setLocalSurvey }: Res
}
};
- const handleInputResponse = (e: any) => {
- let value = parseInt(e.target.value);
- if (value < 1) value = 1;
- const updatedSurvey: Survey = { ...localSurvey, autoComplete: value };
+ const handleInputResponse = (e) => {
+ const updatedSurvey: Survey = { ...localSurvey, autoComplete: parseInt(e.target.value) };
setLocalSurvey(updatedSurvey);
};
+ const handleInputResponseBlur = (e) => {
+ if (parseInt(e.target.value) === 0) {
+ toast.error("Response limit can't be set to 0");
+ return;
+ }
+
+ const inputResponses = localSurvey?._count?.responses || 0;
+
+ if (parseInt(e.target.value) <= inputResponses) {
+ toast.error(
+ `Response limit needs to exceed number of received responses (${localSurvey?._count?.responses}).`
+ );
+ return;
+ }
+ };
+
return (
handleInputResponse(e)}
- className="ml-2 mr-2 inline w-16 bg-white text-center text-sm"
+ onChange={handleInputResponse}
+ onBlur={handleInputResponseBlur}
+ className="ml-2 mr-2 inline w-20 bg-white text-center text-sm"
/>
completed responses.
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyEditor.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyEditor.tsx
index cb23359749..1777c2ff04 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyEditor.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyEditor.tsx
@@ -23,7 +23,7 @@ export default function SurveyEditor({ environmentId, surveyId }: SurveyEditorPr
const [activeQuestionId, setActiveQuestionId] = useState(null);
const [localSurvey, setLocalSurvey] = useState();
const [invalidQuestions, setInvalidQuestions] = useState(null);
- const { survey, isLoadingSurvey, isErrorSurvey } = useSurvey(environmentId, surveyId);
+ const { survey, isLoadingSurvey, isErrorSurvey } = useSurvey(environmentId, surveyId, true);
const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId);
const { environment, isLoadingEnvironment, isErrorEnvironment } = useEnvironment(environmentId);
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyMenuBar.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyMenuBar.tsx
index c3d98cb065..8b924f8a32 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyMenuBar.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/edit/SurveyMenuBar.tsx
@@ -106,6 +106,17 @@ export default function SurveyMenuBar({
return false;
}
+ /*
+ Check whether the count for autocomplete responses is not less
+ than the current count of accepted response and also it is not set to 0
+ */
+ if (
+ (survey.autoComplete && survey._count?.responses && survey._count.responses >= survey.autoComplete) ||
+ survey?.autoComplete === 0
+ ) {
+ return false;
+ }
+
return true;
};
diff --git a/apps/web/lib/surveys/surveys.ts b/apps/web/lib/surveys/surveys.ts
index c6b01195e6..b04bf024b0 100644
--- a/apps/web/lib/surveys/surveys.ts
+++ b/apps/web/lib/surveys/surveys.ts
@@ -27,9 +27,9 @@ export const useSurveys = (environmentId: string) => {
};
};
-export const useSurvey = (environmentId: string, id: string) => {
+export const useSurvey = (environmentId: string, id: string, analytics?: boolean) => {
const { data, error, mutate, isLoading } = useSWR(
- `/api/v1/environments/${environmentId}/surveys/${id}`,
+ `/api/v1/environments/${environmentId}/surveys/${id}${analytics ? "?analytics=true" : ""}`,
fetcher
);
diff --git a/apps/web/pages/api/v1/environments/[environmentId]/surveys/[surveyId]/index.ts b/apps/web/pages/api/v1/environments/[environmentId]/surveys/[surveyId]/index.ts
index 3f8fc301a6..aeb36a6ae8 100644
--- a/apps/web/pages/api/v1/environments/[environmentId]/surveys/[surveyId]/index.ts
+++ b/apps/web/pages/api/v1/environments/[environmentId]/surveys/[surveyId]/index.ts
@@ -9,6 +9,8 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
const surveyId = req.query.surveyId?.toString();
+ const analytics = req.query.analytics?.toString() === "true";
+
if (environmentId === undefined) {
return res.status(400).json({ message: "Missing environmentId" });
}
@@ -31,6 +33,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
include: {
triggers: true,
attributeFilters: true,
+ _count: analytics ? { select: { responses: { where: { finished: true } } } } : false,
},
});
@@ -83,6 +86,8 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
const body = { ...req.body };
delete body.updatedAt;
+ // preventing issue with unknowingly updating analytics
+ delete body._count;
// delete unused fields for link surveys
if (body.type === "link") {
diff --git a/packages/types/surveys.ts b/packages/types/surveys.ts
index 826da7138b..7150973a52 100644
--- a/packages/types/surveys.ts
+++ b/packages/types/surveys.ts
@@ -33,6 +33,7 @@ export interface Survey {
autoComplete: number | null;
surveyClosedMessage: SurveyClosedMessage | null;
closeOnDate: Date | null;
+ _count: { responses: number | null } | null;
}
export interface AttributeFilter {