mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-09 00:40:18 -06:00
made status optional and edited display update functionality
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
31
apps/web/app/api/v1/client/displays/[displayId]/route.ts
Normal file
31
apps/web/app/api/v1/client/displays/[displayId]/route.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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)}
|
||||
|
||||
@@ -59,7 +59,6 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
id: true,
|
||||
},
|
||||
data: {
|
||||
status: "seen",
|
||||
survey: {
|
||||
connect: {
|
||||
id: surveyId,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Display" ALTER COLUMN "status" DROP NOT NULL,
|
||||
ALTER COLUMN "status" DROP DEFAULT;
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user