mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-30 10:49:55 -06:00
[RM] getSurveysWithResponseCount
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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" && (
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user