made status optional and edited display update functionality

This commit is contained in:
Dhruwang
2023-10-08 19:36:42 +05:30
parent 93150b88b7
commit 9614208fb9
13 changed files with 54 additions and 47 deletions

View File

@@ -1,5 +1,5 @@
import { responses } from "@/lib/api/response";
import { markDisplayResponded, updateDisplay } from "@formbricks/lib/display/service";
import { markDisplayResponded } from "@formbricks/lib/display/service";
import { NextResponse } from "next/server";
export async function OPTIONS(): Promise<NextResponse> {
@@ -27,21 +27,3 @@ export async function POST(_: Request, { params }: { params: { displayId: string
return responses.internalServerErrorResponse(error.message);
}
}
export async function PUT(
request: Request,
{ params }: { params: { displayId: string } }
): Promise<NextResponse> {
const { displayId } = params;
if (!displayId) {
return responses.badRequestResponse("Missing displayId");
}
const displayUpdate = await request.json();
try {
const display = await updateDisplay(displayId, displayUpdate);
return responses.successResponse(display);
} catch (error) {
return responses.internalServerErrorResponse(error.message);
}
}

View File

@@ -0,0 +1,31 @@
import { responses } from "@/lib/api/response";
import { updateDisplay } from "@formbricks/lib/display/service";
import { TDisplayInput, ZDisplayInput } from "@formbricks/types/v1/displays";
import { NextResponse } from "next/server";
import { transformErrorToDetails } from "@/lib/api/validator";
export async function PUT(
request: Request,
{ params }: { params: { displayId: string } }
): Promise<NextResponse> {
const { displayId } = params;
if (!displayId) {
return responses.badRequestResponse("Missing displayId");
}
const displayInput: TDisplayInput = await request.json();
const inputValidation = ZDisplayInput.safeParse(displayInput);
if (!inputValidation.success) {
return responses.badRequestResponse(
"Fields are missing or incorrectly formatted",
transformErrorToDetails(inputValidation.error),
true
);
}
try {
const display = await updateDisplay(displayId, inputValidation.data);
return responses.successResponse(display);
} catch (error) {
return responses.internalServerErrorResponse(error.message);
}
}

View File

@@ -42,7 +42,6 @@ export default function LinkSurvey({
// pass in the responseId if the survey is a single use survey, ensures survey state is updated with the responseId
const [surveyState, setSurveyState] = useState(new SurveyState(survey.id, singleUseId, responseId));
const [activeQuestionId, setActiveQuestionId] = useState<string>(survey.questions[0].id);
const [displayId, setDisplayId] = useState<string>();
const prefillResponseData: TResponseData | undefined = prefillAnswer
? getPrefillResponseData(survey.questions[0], survey, prefillAnswer)
: undefined;
@@ -118,14 +117,12 @@ export default function LinkSurvey({
onDisplay={async () => {
if (!isPreview) {
const { id } = await createDisplay({ surveyId: survey.id }, webAppUrl);
setDisplayId(id);
const newSurveyState = surveyState.copy();
newSurveyState.updateDisplayId(id);
setSurveyState(newSurveyState);
}
}}
onResponse={(responseUpdate: TResponseUpdate) => {
responseUpdate.displayId = displayId!;
!isPreview && responseQueue.add(responseUpdate);
}}
onActiveQuestionChange={(questionId) => setActiveQuestionId(questionId)}

View File

@@ -59,7 +59,6 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
id: true,
},
data: {
status: "seen",
survey: {
connect: {
id: surveyId,

View File

@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "Display" ALTER COLUMN "status" DROP NOT NULL,
ALTER COLUMN "status" DROP DEFAULT;

View File

@@ -166,15 +166,15 @@ enum DisplayStatus {
}
model Display {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
surveyId String
person Person? @relation(fields: [personId], references: [id], onDelete: Cascade)
person Person? @relation(fields: [personId], references: [id], onDelete: Cascade)
personId String?
responseId String? @unique
status DisplayStatus @default(seen)
responseId String? @unique
status DisplayStatus?
}
model SurveyTrigger {

View File

@@ -13,7 +13,6 @@ const containerId = "formbricks-web-container";
const config = Config.getInstance();
const logger = Logger.getInstance();
const errorHandler = ErrorHandler.getInstance();
let displayId: string | null = null;
let surveyRunning = false;
export const renderWidget = (survey: TSurvey) => {
@@ -67,12 +66,10 @@ export const renderWidget = (survey: TSurvey) => {
},
config.get().apiHost
);
displayId = id;
surveyState.updateDisplayId(id);
responseQueue.updateSurveyState(surveyState);
},
onResponse: (responseUpdate: TResponseUpdate) => {
responseUpdate.displayId = displayId!;
responseQueue.add(responseUpdate);
},
onClose: closeSurvey,

View File

@@ -18,7 +18,7 @@ export const createDisplay = async (
};
export const updateDisplay = async (displayId: string, displayInput: any, apiHost: string): Promise<void> => {
const res = await fetch(`${apiHost}/api/v1/client/displays/${displayId}/responded`, {
const res = await fetch(`${apiHost}/api/v1/client/displays/${displayId}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(displayInput),

View File

@@ -39,7 +39,6 @@ const selectDisplay = {
},
},
},
status: true,
};
export const updateDisplay = async (
@@ -82,7 +81,6 @@ export const createDisplay = async (displayInput: TDisplayInput): Promise<TDispl
id: displayInput.surveyId,
},
},
status: "seen",
...(displayInput.personId && {
person: {
@@ -187,7 +185,6 @@ export const getDisplaysOfPerson = cache(
createdAt: displayPrisma.createdAt,
updatedAt: displayPrisma.updatedAt,
person: null,
status: displayPrisma.status,
surveyId: displayPrisma.surveyId,
surveyName: displayPrisma.survey.name,
responseId: displayPrisma.responseId,

View File

@@ -2,7 +2,6 @@ import { TResponseUpdate } from "@formbricks/types/v1/responses";
import { createResponse, updateResponse } from "./client/response";
import { updateDisplay } from "./client/display";
import SurveyState from "./surveyState";
import { markDisplayResponded } from "./client/display";
interface QueueConfig {
apiHost: string;
@@ -81,11 +80,8 @@ export class ResponseQueue {
},
this.config.apiHost
);
if (responseUpdate.displayId) {
await updateDisplay(responseUpdate.displayId, { responseId: response.id }, this.config.apiHost);
}
if (this.surveyState.displayId) {
markDisplayResponded(this.surveyState.displayId, this.config.apiHost);
await updateDisplay(this.surveyState.displayId, { responseId: response.id }, this.config.apiHost);
}
this.surveyState.updateResponseId(response.id);
if (this.config.setSurveyState) {

View File

@@ -76,6 +76,7 @@ export const selectSurveyWithAnalytics = {
displays: {
select: {
status: true,
responseId: true,
id: true,
},
},
@@ -116,7 +117,9 @@ export const getSurveyWithAnalytics = async (surveyId: string): Promise<TSurveyW
let { _count, displays, ...surveyPrismaFields } = surveyPrisma;
const numDisplays = displays.length;
const numDisplaysResponded = displays.filter((item) => item.status === "responded").length;
const numDisplaysResponded = displays.filter((item) => {
return item.status === "responded" || item.responseId;
}).length;
const numResponses = _count.responses;
// responseRate, rounded to 2 decimal places
const responseRate = numDisplays ? Math.round((numDisplaysResponded / numDisplays) * 100) / 100 : 0;
@@ -390,7 +393,9 @@ export const getSurveysWithAnalytics = async (environmentId: string): Promise<TS
const surveys: TSurveyWithAnalytics[] = [];
for (const { _count, displays, ...surveyPrisma } of surveysPrisma) {
const numDisplays = displays.length;
const numDisplaysResponded = displays.filter((item) => item.status === "responded").length;
const numDisplaysResponded = displays.filter((item) => {
return item.status === "responded" || item.responseId;
}).length;
const responseRate = numDisplays ? Math.round((numDisplaysResponded / numDisplays) * 100) / 100 : 0;
const transformedSurvey = {

View File

@@ -8,14 +8,15 @@ export const ZDisplay = z.object({
surveyId: z.string().cuid2(),
person: ZPerson.nullable(),
responseId: z.string().cuid2().nullable(),
status: z.enum(["seen", "responded"]),
status: z.enum(["seen", "responded"]).optional(),
});
export type TDisplay = z.infer<typeof ZDisplay>;
export const ZDisplayInput = z.object({
surveyId: z.string().cuid2(),
surveyId: z.string().cuid2().optional(),
personId: z.string().cuid2().optional(),
responseId: z.string().cuid2().optional(),
});
export type TDisplayInput = z.infer<typeof ZDisplayInput>;

View File

@@ -96,7 +96,6 @@ export type TResponseWithSurvey = z.infer<typeof ZResponseWithSurvey>;
export const ZResponseUpdate = z.object({
finished: z.boolean(),
data: ZResponseData,
displayId: z.string().cuid2(),
});
export type TResponseUpdate = z.infer<typeof ZResponseUpdate>;