[RM] getSurveysWithResponseCount

This commit is contained in:
Ankur Datta
2023-07-19 09:41:06 +00:00
parent 186a4269a3
commit 5612fbfa22
4 changed files with 81 additions and 78 deletions

View File

@@ -14,6 +14,7 @@ import {
DropdownMenuTrigger,
} from "@/components/shared/DropdownMenu";
import LoadingSpinner from "@/components/shared/LoadingSpinner";
import type { TSurveyWithAnalytics } from "@formbricks/types/v1/surveys";
import {
DocumentDuplicateIcon,
EllipsisHorizontalIcon,
@@ -26,21 +27,28 @@ import {
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import toast from "react-hot-toast";
import type { TEnvironment } from "@formbricks/types/v1/environment";
interface SurveyDropDownMenuProps{
environmentId:string,
survey:TSurveyWithAnalytics,
environment:TEnvironment,
otherEnvironment:TEnvironment
}
export default function SurveyDropDownMenu({
environmentId,
survey,
environment,
otherEnvironment,
}: any) {
}: SurveyDropDownMenuProps) {
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [loading, setLoading] = useState(false);
const router = useRouter();
const handleDeleteSurvey = async (survey) => {
setLoading(true);
try {
await deleteSurveyAction(survey.id);
router.refresh();

View File

@@ -6,12 +6,13 @@ import SurveyDropDownMenu from "@/app/environments/[environmentId]/surveys/Surve
import SurveyStarter from "@/app/environments/[environmentId]/surveys/SurveyStarter";
import { getProductByEnvironmentId, getProductWithEnvironments } from "@formbricks/lib/services/product";
import { getEnvironment } from "@formbricks/lib/services/environment";
import { getSurveysWithResponseCount } from "@formbricks/lib/services/survey";
import { getSurveysWithAnalytics } from "@formbricks/lib/services/survey";
import type { TSurveyWithAnalytics } from "@formbricks/types/v1/surveys";
export default async function SurveysList({ environmentId }: { environmentId: string }) {
const product = await getProductByEnvironmentId(environmentId);
const environment = await getEnvironment(environmentId);
const surveys = await getSurveysWithResponseCount(environmentId);
const surveys:TSurveyWithAnalytics[] = await getSurveysWithAnalytics(environmentId);
const productWithEnvironments = await getProductWithEnvironments(product.id);
const otherEnvironment = productWithEnvironments.environments.find((e) => e.type !== environment.type);
@@ -70,7 +71,7 @@ export default async function SurveysList({ environmentId }: { environmentId: st
tooltip
environmentId={environmentId}
/>
<p className="ml-2 text-xs text-slate-400 ">{survey.responses} responses</p>
<p className="ml-2 text-xs text-slate-400 ">{survey.analytics.numResponses} responses</p>
</>
)}
{survey.status === "draft" && (

View File

@@ -6,9 +6,7 @@ import {
TSurvey,
TSurveyWithAnalytics,
ZSurvey,
ZSurveyWithAnalytics,
TSurveyWithResponseCount,
ZSurveyWithResponseCount,
ZSurveyWithAnalytics
} from "@formbricks/types/v1/surveys";
import { Prisma } from "@prisma/client";
import "server-only";
@@ -55,7 +53,18 @@ export const select = {
value: true,
},
},
};
displays:{
select:{
status:true,
id:true
}
},
_count:{
select:{
responses:true
}
}
}
export const preloadSurvey = (surveyId: string) => {
void getSurvey(surveyId);
@@ -68,7 +77,7 @@ export const getSurvey = cache(async (surveyId: string): Promise<TSurveyWithAnal
where: {
id: surveyId,
},
select,
select
});
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
@@ -82,28 +91,21 @@ export const getSurvey = cache(async (surveyId: string): Promise<TSurveyWithAnal
throw new ResourceNotFoundError("Survey", surveyId);
}
const numDisplays = await prisma.display.count({
where: {
surveyId,
},
});
const numDisplaysResponded = await prisma.display.count({
where: {
surveyId,
status: "responded",
},
});
let {_count,displays, ...surveyPrismaFields}=surveyPrisma;
const numDisplays=displays.length
const numDisplaysResponded=displays.filter((item)=>item.status==='responded').length
const numResponses=_count.responses
// responseRate, rounded to 2 decimal places
const responseRate = numDisplays ? Math.round((numDisplaysResponded / numDisplays) * 100) / 100 : 0;
const transformedSurvey = {
...surveyPrisma,
triggers: surveyPrisma.triggers.map((trigger) => trigger.eventClass),
...surveyPrismaFields,
triggers: surveyPrismaFields.triggers.map((trigger) => trigger.eventClass),
analytics: {
numDisplays,
responseRate,
numResponses
},
};
@@ -136,7 +138,7 @@ export const getSurveys = cache(async (environmentId: string): Promise<TSurvey[]
}
const surveys: TSurvey[] = [];
for (const surveyPrisma of surveysPrisma) {
for (const {_count,displays, ...surveyPrisma} of surveysPrisma) {
const transformedSurvey = {
...surveyPrisma,
triggers: surveyPrisma.triggers.map((trigger) => trigger.eventClass),
@@ -155,52 +157,48 @@ export const getSurveys = cache(async (environmentId: string): Promise<TSurvey[]
}
});
export const getSurveysWithResponseCount = cache(
async (environmentId: string): Promise<TSurveyWithResponseCount[]> => {
let surveysPrisma;
try {
surveysPrisma = await prisma.survey.findMany({
where: {
environment: {
id: environmentId,
},
},
include: {
_count: {
select: {
responses: true,
},
},
},
});
} catch (error) {
console.log(error);
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
throw error;
export const getSurveysWithAnalytics = cache(async (environmentId: string): Promise<TSurveyWithAnalytics[]> => {
let surveysPrisma;
try {
surveysPrisma = await prisma.survey.findMany({
where: {
environmentId,
},
select
});
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
const surveys: TSurveyWithResponseCount[] = [];
for (const surveyPrisma of surveysPrisma) {
const transformedSurvey = {
...surveyPrisma,
attributeFilters: [],
triggers: [],
responses: surveyPrisma._count.responses,
};
const survey = ZSurveyWithResponseCount.parse(transformedSurvey);
surveys.push(survey);
}
try {
return surveys;
} catch (error) {
if (error instanceof z.ZodError) {
console.error(JSON.stringify(error.errors, null, 2)); // log the detailed error information
}
throw new ValidationError("Data validation of survey failed");
}
throw error;
}
);
const surveys: TSurveyWithAnalytics[] = [];
for (const {_count,displays, ...surveyPrisma} of surveysPrisma) {
const numDisplays=displays.length
const numDisplaysResponded=displays.filter((item)=>item.status==='responded').length
const responseRate = numDisplays ? Math.round((numDisplaysResponded / numDisplays) * 100) / 100 : 0;
const transformedSurvey = {
...surveyPrisma,
triggers: surveyPrisma.triggers.map((trigger) => trigger.eventClass),
analytics:{
numDisplays,
responseRate,
numResponses:_count.responses
}
};
const survey = ZSurveyWithAnalytics.parse(transformedSurvey);
surveys.push(survey);
}
try {
return surveys;
} catch (error) {
if (error instanceof z.ZodError) {
console.error(JSON.stringify(error.errors, null, 2)); // log the detailed error information
}
throw new ValidationError("Data validation of survey failed");
}
});

View File

@@ -246,13 +246,9 @@ export const ZSurveyWithAnalytics = ZSurvey.extend({
analytics: z.object({
numDisplays: z.number(),
responseRate: z.number(),
numResponses: z.number(),
}),
surveyClosedMessage: ZSurveyClosedMessage,
});
export const ZSurveyWithResponseCount = ZSurvey.extend({
responses: z.number(),
});
export type TSurveyWithAnalytics = z.infer<typeof ZSurveyWithAnalytics>;
export type TSurveyWithResponseCount = z.infer<typeof ZSurveyWithResponseCount>;