diff --git a/apps/docs/app/developer-docs/api-sdk/page.mdx b/apps/docs/app/developer-docs/api-sdk/page.mdx
index 5811a2c894..292423075e 100644
--- a/apps/docs/app/developer-docs/api-sdk/page.mdx
+++ b/apps/docs/app/developer-docs/api-sdk/page.mdx
@@ -79,27 +79,6 @@ Promise<{ id: string }, NetworkError | Error>
-- Update Display
-
-
-
-
-```javascript {{ title: 'Update Display Method Call'}}
-await api.client.display.update(
- displayId: "",
- {
- userId: "", // optional
- responseId: "", // optional
- },
-);
-```
-
-```javascript {{ title: 'Update Display Method Return Type' }}
-Promise<{ }, NetworkError | Error]>
-```
-
-
-
## Responses
diff --git a/apps/web/app/api/v1/client/[environmentId]/displays/[displayId]/route.ts b/apps/web/app/api/v1/client/[environmentId]/displays/[displayId]/route.ts
deleted file mode 100644
index e9fcdcfcf2..0000000000
--- a/apps/web/app/api/v1/client/[environmentId]/displays/[displayId]/route.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { responses } from "@/app/lib/api/response";
-import { transformErrorToDetails } from "@/app/lib/api/validator";
-import { updateDisplay } from "@formbricks/lib/display/service";
-import { ZDisplayUpdateInput } from "@formbricks/types/displays";
-
-interface Context {
- params: {
- displayId: string;
- environmentId: string;
- };
-}
-
-export const OPTIONS = async (): Promise => {
- return responses.successResponse({}, true);
-};
-
-export const PUT = async (request: Request, context: Context): Promise => {
- const { displayId, environmentId } = context.params;
- const jsonInput = await request.json();
- const inputValidation = ZDisplayUpdateInput.safeParse({
- ...jsonInput,
- environmentId,
- });
-
- if (!inputValidation.success) {
- return responses.badRequestResponse(
- "Fields are missing or incorrectly formatted",
- transformErrorToDetails(inputValidation.error),
- true
- );
- }
-
- try {
- await updateDisplay(displayId, inputValidation.data);
- return responses.successResponse({}, true);
- } catch (error) {
- console.error(error);
- return responses.internalServerErrorResponse(error.message, true);
- }
-};
diff --git a/apps/web/app/s/[surveyId]/components/LinkSurvey.tsx b/apps/web/app/s/[surveyId]/components/LinkSurvey.tsx
index e7c4017786..117b59fe62 100644
--- a/apps/web/app/s/[surveyId]/components/LinkSurvey.tsx
+++ b/apps/web/app/s/[surveyId]/components/LinkSurvey.tsx
@@ -278,6 +278,7 @@ export const LinkSurvey = ({
url: window.location.href,
source: sourceParam || "",
},
+ displayId: surveyState.displayId,
...(Object.keys(hiddenFieldsRecord).length > 0 && { hiddenFields: hiddenFieldsRecord }),
});
}}
diff --git a/packages/api/README.md b/packages/api/README.md
index c546b4e968..a283d79e25 100644
--- a/packages/api/README.md
+++ b/packages/api/README.md
@@ -37,18 +37,6 @@ The API client is now ready to be used across your project. It can be used to in
});
```
-- Update a Display
-
- ```ts
- await api.client.display.update(
- displayId: "",
- {
- userId: "", // optional
- responseId: "", // optional
- },
- );
- ```
-
### Response
- Create a Response
diff --git a/packages/api/src/api/client/display.ts b/packages/api/src/api/client/display.ts
index 1b06a95524..a01da13d37 100644
--- a/packages/api/src/api/client/display.ts
+++ b/packages/api/src/api/client/display.ts
@@ -1,4 +1,4 @@
-import { type TDisplayCreateInput, type TDisplayUpdateInput } from "@formbricks/types/displays";
+import { type TDisplayCreateInput } from "@formbricks/types/displays";
import { type Result } from "@formbricks/types/error-handlers";
import { type NetworkError } from "@formbricks/types/errors";
import { makeRequest } from "../../utils/make-request";
@@ -17,16 +17,4 @@ export class DisplayAPI {
): Promise> {
return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/displays`, "POST", displayInput);
}
-
- async update(
- displayId: string,
- displayInput: Omit
- ): Promise> {
- return makeRequest(
- this.apiHost,
- `/api/v1/client/${this.environmentId}/displays/${displayId}`,
- "PUT",
- displayInput
- );
- }
}
diff --git a/packages/database/data-migrations/20240905120500_refactor_display_response_relationship/data-migration.ts b/packages/database/data-migrations/20240905120500_refactor_display_response_relationship/data-migration.ts
new file mode 100644
index 0000000000..315025402f
--- /dev/null
+++ b/packages/database/data-migrations/20240905120500_refactor_display_response_relationship/data-migration.ts
@@ -0,0 +1,96 @@
+/* eslint-disable no-console -- logging is allowed in migration scripts */
+import { PrismaClient } from "@prisma/client";
+
+const prisma = new PrismaClient();
+
+async function runMigration(): Promise {
+ await prisma.$transaction(
+ async (tx) => {
+ const startTime = Date.now();
+ console.log("Starting data migration...");
+
+ // Fetch all displays
+ const displays = await tx.display.findMany({
+ where: {
+ responseId: {
+ not: null,
+ },
+ },
+ select: {
+ id: true,
+ responseId: true,
+ },
+ });
+
+ if (displays.length === 0) {
+ // Stop the migration if there are no Displays
+ console.log("No Displays found");
+ return;
+ }
+
+ console.log(`Total displays with responseId: ${displays.length.toString()}`);
+
+ let totalResponseTransformed = 0;
+ let totalDisplaysDeleted = 0;
+ await Promise.all(
+ displays.map(async (display) => {
+ if (!display.responseId) {
+ return Promise.resolve();
+ }
+
+ const response = await tx.response.findUnique({
+ where: { id: display.responseId },
+ select: { id: true },
+ });
+
+ if (response) {
+ totalResponseTransformed++;
+ return Promise.all([
+ tx.response.update({
+ where: { id: response.id },
+ data: { display: { connect: { id: display.id } } },
+ }),
+ tx.display.update({
+ where: { id: display.id },
+ data: { responseId: null },
+ }),
+ ]);
+ }
+
+ totalDisplaysDeleted++;
+ return tx.display.delete({
+ where: { id: display.id },
+ });
+ })
+ );
+
+ console.log(`${totalResponseTransformed.toString()} responses transformed`);
+ console.log(`${totalDisplaysDeleted.toString()} displays deleted`);
+ const endTime = Date.now();
+ console.log(`Data migration completed. Total time: ${((endTime - startTime) / 1000).toString()}s`);
+ },
+ {
+ timeout: 300000, // 5 minutes
+ }
+ );
+}
+
+function handleError(error: unknown): void {
+ console.error("An error occurred during migration:", error);
+ process.exit(1);
+}
+
+function handleDisconnectError(): void {
+ console.error("Failed to disconnect Prisma client");
+ process.exit(1);
+}
+
+function main(): void {
+ runMigration()
+ .catch(handleError)
+ .finally(() => {
+ prisma.$disconnect().catch(handleDisconnectError);
+ });
+}
+
+main();
diff --git a/packages/database/migrations/20240917112456_add_display_id_to_response/migration.sql b/packages/database/migrations/20240917112456_add_display_id_to_response/migration.sql
new file mode 100644
index 0000000000..d5d4decd5b
--- /dev/null
+++ b/packages/database/migrations/20240917112456_add_display_id_to_response/migration.sql
@@ -0,0 +1,14 @@
+/*
+ Warnings:
+
+ - A unique constraint covering the columns `[displayId]` on the table `Response` will be added. If there are existing duplicate values, this will fail.
+
+*/
+-- AlterTable
+ALTER TABLE "Response" ADD COLUMN "displayId" TEXT;
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Response_displayId_key" ON "Response"("displayId");
+
+-- AddForeignKey
+ALTER TABLE "Response" ADD CONSTRAINT "Response_displayId_fkey" FOREIGN KEY ("displayId") REFERENCES "Display"("id") ON DELETE SET NULL ON UPDATE CASCADE;
diff --git a/packages/database/package.json b/packages/database/package.json
index fac4e4898e..5e9917e268 100644
--- a/packages/database/package.json
+++ b/packages/database/package.json
@@ -47,7 +47,8 @@
"data-migration:fix-logic-end-destination": "ts-node ./data-migrations/20240806120500_fix-logic-end-destination/data-migration.ts",
"data-migration:v2.4": "pnpm data-migration:segments-cleanup && pnpm data-migration:multiple-endings && pnpm data-migration:simplified-email-verification && pnpm data-migration:fix-logic-end-destination",
"data-migration:remove-dismissed-value-inconsistency": "ts-node ./data-migrations/20240807120500_cta_consent_dismissed_inconsistency/data-migration.ts",
- "data-migration:v2.5": "pnpm data-migration:remove-dismissed-value-inconsistency"
+ "data-migration:v2.5": "pnpm data-migration:remove-dismissed-value-inconsistency",
+ "data-migration:add-display-id-to-response": "ts-node ./data-migrations/20240905120500_refactor_display_response_relationship/data-migration.ts"
},
"dependencies": {
"@prisma/client": "^5.18.0",
diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma
index fd3860c52e..268cb3371b 100644
--- a/packages/database/schema.prisma
+++ b/packages/database/schema.prisma
@@ -132,6 +132,8 @@ model Response {
// singleUseId, used to prevent multiple responses
singleUseId String?
language String?
+ displayId String? @unique
+ display Display? @relation(fields: [displayId], references: [id])
@@unique([surveyId, singleUseId])
@@index([surveyId, createdAt]) // to determine monthly response count
@@ -198,8 +200,9 @@ model Display {
surveyId String
person Person? @relation(fields: [personId], references: [id], onDelete: Cascade)
personId String?
- responseId String? @unique
+ responseId String? @unique //deprecated
status DisplayStatus?
+ response Response?
@@index([surveyId])
@@index([personId, createdAt])
diff --git a/packages/js-core/src/app/lib/widget.ts b/packages/js-core/src/app/lib/widget.ts
index b7557ebcaf..79a0395959 100644
--- a/packages/js-core/src/app/lib/widget.ts
+++ b/packages/js-core/src/app/lib/widget.ts
@@ -193,6 +193,7 @@ const renderWidget = async (
action,
},
hiddenFields,
+ displayId: surveyState.displayId,
});
if (isNewResponse) {
diff --git a/packages/js-core/src/website/lib/widget.ts b/packages/js-core/src/website/lib/widget.ts
index e233004868..85b91be500 100644
--- a/packages/js-core/src/website/lib/widget.ts
+++ b/packages/js-core/src/website/lib/widget.ts
@@ -188,6 +188,7 @@ const renderWidget = async (
action,
},
hiddenFields,
+ displayId: surveyState.displayId,
});
if (isNewResponse) {
diff --git a/packages/lib/display/service.ts b/packages/lib/display/service.ts
index 3abbd8b265..66cccded77 100644
--- a/packages/lib/display/service.ts
+++ b/packages/lib/display/service.ts
@@ -8,12 +8,9 @@ import {
TDisplay,
TDisplayCreateInput,
TDisplayFilters,
- TDisplayUpdateInput,
ZDisplayCreateInput,
- ZDisplayUpdateInput,
} from "@formbricks/types/displays";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
-import { TPerson } from "@formbricks/types/people";
import { cache } from "../cache";
import { ITEMS_PER_PAGE } from "../constants";
import { createPerson, getPersonByUserId } from "../person/service";
@@ -25,7 +22,6 @@ export const selectDisplay = {
createdAt: true,
updatedAt: true,
surveyId: true,
- responseId: true,
personId: true,
status: true,
};
@@ -60,57 +56,6 @@ export const getDisplay = reactCache(
)()
);
-export const updateDisplay = async (
- displayId: string,
- displayInput: TDisplayUpdateInput
-): Promise => {
- validateInputs([displayInput, ZDisplayUpdateInput.partial()]);
-
- let person: TPerson | null = null;
- if (displayInput.userId) {
- person = await getPersonByUserId(displayInput.environmentId, displayInput.userId);
- if (!person) {
- throw new ResourceNotFoundError("Person", displayInput.userId);
- }
- }
-
- try {
- const data = {
- ...(person?.id && {
- person: {
- connect: {
- id: person.id,
- },
- },
- }),
- ...(displayInput.responseId && {
- responseId: displayInput.responseId,
- }),
- };
- const display = await prisma.display.update({
- where: {
- id: displayId,
- },
- data,
- select: selectDisplay,
- });
-
- displayCache.revalidate({
- id: display.id,
- surveyId: display.surveyId,
- });
-
- return display;
- } catch (error) {
- console.error(error);
- if (error instanceof Prisma.PrismaClientKnownRequestError) {
- throw new DatabaseError(error.message);
- }
-
- throw error;
- }
-};
-
export const createDisplay = async (displayInput: TDisplayCreateInput): Promise => {
validateInputs([displayInput, ZDisplayCreateInput]);
@@ -234,34 +179,6 @@ export const getDisplaysByUserId = reactCache(
)()
);
-export const deleteDisplayByResponseId = async (
- responseId: string,
- surveyId: string
-): Promise => {
- validateInputs([responseId, ZId], [surveyId, ZId]);
-
- try {
- const display = await prisma.display.delete({
- where: {
- responseId,
- },
- select: selectDisplay,
- });
-
- displayCache.revalidate({
- id: display.id,
- personId: display.personId,
- surveyId,
- });
- return display;
- } catch (error) {
- if (error instanceof Prisma.PrismaClientKnownRequestError) {
- throw new DatabaseError(error.message);
- }
- throw error;
- }
-};
-
export const getDisplayCountBySurveyId = reactCache(
(surveyId: string, filters?: TDisplayFilters): Promise =>
cache(
@@ -301,3 +218,29 @@ export const getDisplayCountBySurveyId = reactCache(
}
)()
);
+
+export const deleteDisplay = async (displayId: string): Promise => {
+ validateInputs([displayId, ZId]);
+ try {
+ const display = await prisma.display.delete({
+ where: {
+ id: displayId,
+ },
+ select: selectDisplay,
+ });
+
+ displayCache.revalidate({
+ id: display.id,
+ personId: display.personId,
+ surveyId: display.surveyId,
+ });
+
+ return display;
+ } catch (error) {
+ if (error instanceof Prisma.PrismaClientKnownRequestError) {
+ throw new DatabaseError(error.message);
+ }
+
+ throw error;
+ }
+};
diff --git a/packages/lib/display/tests/display.test.ts b/packages/lib/display/tests/display.test.ts
index 8a334117d5..0aed38ac48 100644
--- a/packages/lib/display/tests/display.test.ts
+++ b/packages/lib/display/tests/display.test.ts
@@ -4,24 +4,20 @@ import {
mockDisplay,
mockDisplayInput,
mockDisplayInputWithUserId,
- mockDisplayUpdate,
mockDisplayWithPersonId,
- mockDisplayWithResponseId,
mockEnvironment,
- mockResponseId,
mockSurveyId,
} from "./__mocks__/data.mock";
import { Prisma } from "@prisma/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { testInputValidation } from "vitestSetup";
-import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
+import { DatabaseError } from "@formbricks/types/errors";
import {
createDisplay,
- deleteDisplayByResponseId,
+ deleteDisplay,
getDisplay,
getDisplayCountBySurveyId,
getDisplaysByPersonId,
- updateDisplay,
} from "../service";
beforeEach(() => {
@@ -135,49 +131,13 @@ describe("Tests for createDisplay service", () => {
});
});
-describe("Tests for updateDisplay Service", () => {
+describe("Tests for delete display service", () => {
describe("Happy Path", () => {
- it("Updates a display (responded)", async () => {
- prisma.display.update.mockResolvedValue(mockDisplayWithResponseId);
- prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
+ it("Deletes a display", async () => {
+ prisma.display.delete.mockResolvedValue(mockDisplay);
- const display = await updateDisplay(mockDisplay.id, mockDisplayUpdate);
- expect(display).toEqual(mockDisplayWithResponseId);
- });
- });
-
- describe("Sad Path", () => {
- testInputValidation(updateDisplay, "123", "123");
-
- it("Throws DatabaseError on PrismaClientKnownRequestError", async () => {
- prisma.environment.findUnique.mockResolvedValue(mockEnvironment);
- const mockErrorMessage = "Mock error message";
- const errToThrow = new Prisma.PrismaClientKnownRequestError(mockErrorMessage, {
- code: "P2002",
- clientVersion: "0.0.1",
- });
-
- prisma.display.update.mockRejectedValue(errToThrow);
-
- await expect(updateDisplay(mockDisplay.id, mockDisplayUpdate)).rejects.toThrow(DatabaseError);
- });
-
- it("Throws a generic Error for other unexpected issues", async () => {
- const mockErrorMessage = "Mock error message";
- prisma.display.update.mockRejectedValue(new Error(mockErrorMessage));
-
- await expect(updateDisplay(mockDisplay.id, mockDisplayUpdate)).rejects.toThrow(Error);
- });
- });
-});
-
-describe("Tests for deleteDisplayByResponseId service", () => {
- describe("Happy Path", () => {
- it("Deletes a display when a response associated to it is deleted", async () => {
- prisma.display.delete.mockResolvedValue(mockDisplayWithResponseId);
-
- const display = await deleteDisplayByResponseId(mockResponseId, mockSurveyId);
- expect(display).toEqual(mockDisplayWithResponseId);
+ const display = await deleteDisplay(mockDisplay.id);
+ expect(display).toEqual(mockDisplay);
});
});
describe("Sad Path", () => {
@@ -190,14 +150,14 @@ describe("Tests for deleteDisplayByResponseId service", () => {
prisma.display.delete.mockRejectedValue(errToThrow);
- await expect(deleteDisplayByResponseId(mockResponseId, mockSurveyId)).rejects.toThrow(DatabaseError);
+ await expect(deleteDisplay(mockDisplay.id)).rejects.toThrow(DatabaseError);
});
it("Throws a generic Error for other exceptions", async () => {
const mockErrorMessage = "Mock error message";
prisma.display.delete.mockRejectedValue(new Error(mockErrorMessage));
- await expect(deleteDisplayByResponseId(mockResponseId, mockSurveyId)).rejects.toThrow(Error);
+ await expect(deleteDisplay(mockDisplay.id)).rejects.toThrow(Error);
});
});
});
diff --git a/packages/lib/response/service.ts b/packages/lib/response/service.ts
index 7d7253e588..e2e800668a 100644
--- a/packages/lib/response/service.ts
+++ b/packages/lib/response/service.ts
@@ -22,7 +22,7 @@ import { getAttributes } from "../attribute/service";
import { cache } from "../cache";
import { IS_FORMBRICKS_CLOUD, ITEMS_PER_PAGE, WEBAPP_URL } from "../constants";
import { displayCache } from "../display/cache";
-import { deleteDisplayByResponseId, getDisplayCountBySurveyId } from "../display/service";
+import { deleteDisplay, getDisplayCountBySurveyId } from "../display/service";
import { getMonthlyOrganizationResponseCount, getOrganizationByEnvironmentId } from "../organization/service";
import { createPerson, getPersonByUserId } from "../person/service";
import { sendPlanLimitsReachedEventToPosthogWeekly } from "../posthogServer";
@@ -62,6 +62,7 @@ export const responseSelection = {
personAttributes: true,
singleUseId: true,
language: true,
+ displayId: true,
person: {
select: {
id: true,
@@ -254,6 +255,7 @@ export const createResponse = async (responseInput: TResponseInput): Promise =>
tags: responsePrisma.tags.map((tagPrisma: { tag: TTag }) => tagPrisma.tag),
};
- deleteDisplayByResponseId(responseId, response.surveyId);
-
+ if (response.displayId) {
+ deleteDisplay(response.displayId);
+ }
const survey = await getSurvey(response.surveyId);
if (survey) {
diff --git a/packages/lib/responseQueue.ts b/packages/lib/responseQueue.ts
index 21c2df8465..bcb4f8f834 100644
--- a/packages/lib/responseQueue.ts
+++ b/packages/lib/responseQueue.ts
@@ -87,19 +87,11 @@ export class ResponseQueue {
userId: this.surveyState.userId || null,
singleUseId: this.surveyState.singleUseId || null,
data: { ...responseUpdate.data, ...responseUpdate.hiddenFields },
+ displayId: this.surveyState.displayId,
});
if (!response.ok) {
throw new Error("Could not create response");
}
- if (this.surveyState.displayId) {
- try {
- await this.api.client.display.update(this.surveyState.displayId, {
- responseId: response.data.id,
- });
- } catch (error) {
- console.error(`Failed to update display, proceeding with the response. ${error}`);
- }
- }
this.surveyState.updateResponseId(response.data.id);
if (this.config.setSurveyState) {
this.config.setSurveyState(this.surveyState);
diff --git a/packages/lib/survey/service.ts b/packages/lib/survey/service.ts
index 4811142683..e6b9045fc2 100644
--- a/packages/lib/survey/service.ts
+++ b/packages/lib/survey/service.ts
@@ -36,6 +36,7 @@ import { capturePosthogEnvironmentEvent } from "../posthogServer";
import { productCache } from "../product/cache";
import { getProductByEnvironmentId } from "../product/service";
import { responseCache } from "../response/cache";
+import { getResponsesByPersonId } from "../response/service";
import { segmentCache } from "../segment/cache";
import { createSegment, deleteSegment, evaluateSegment, getSegment, updateSegment } from "../segment/service";
import { diffInDays } from "../utils/datetime";
@@ -1124,6 +1125,7 @@ export const getSyncSurveys = reactCache(
}
const displays = await getDisplaysByPersonId(person.id);
+ const responses = await getResponsesByPersonId(person.id);
// filter surveys that meet the displayOption criteria
surveys = surveys.filter((survey) => {
@@ -1133,20 +1135,18 @@ export const getSyncSurveys = reactCache(
case "displayOnce":
return displays.filter((display) => display.surveyId === survey.id).length === 0;
case "displayMultiple":
- return (
- displays
- .filter((display) => display.surveyId === survey.id)
- .filter((display) => display.responseId).length === 0
- );
+ if (!responses) return true;
+ else {
+ return responses.filter((response) => response.surveyId === survey.id).length === 0;
+ }
case "displaySome":
if (survey.displayLimit === null) {
return true;
}
if (
- displays
- .filter((display) => display.surveyId === survey.id)
- .some((display) => display.responseId)
+ responses &&
+ responses.filter((response) => response.surveyId === survey.id).length !== 0
) {
return false;
}
diff --git a/packages/lib/survey/tests/survey.test.ts b/packages/lib/survey/tests/survey.test.ts
index 216af08b99..06da286338 100644
--- a/packages/lib/survey/tests/survey.test.ts
+++ b/packages/lib/survey/tests/survey.test.ts
@@ -1,4 +1,5 @@
import { prisma } from "../../__mocks__/database";
+import { mockResponseNote, mockResponseWithMockPerson } from "../../response/tests/__mocks__/data.mock";
import { Prisma } from "@prisma/client";
import { beforeEach, describe, expect, it } from "vitest";
import { testInputValidation } from "vitestSetup";
@@ -303,6 +304,9 @@ describe("Tests for getSyncSurveys", () => {
it("Returns synced surveys", async () => {
prisma.survey.findMany.mockResolvedValueOnce([mockSyncSurveyOutput]);
prisma.person.findUnique.mockResolvedValueOnce(mockPrismaPerson);
+ prisma.response.findMany.mockResolvedValue([mockResponseWithMockPerson]);
+ prisma.responseNote.findMany.mockResolvedValue([mockResponseNote]);
+
const surveys = await getSyncSurveys(mockId, mockPrismaPerson.id, "desktop", {
version: "1.7.0",
});
diff --git a/packages/lib/surveyState.ts b/packages/lib/surveyState.ts
index cb0e9fcce8..16443882bc 100644
--- a/packages/lib/surveyState.ts
+++ b/packages/lib/surveyState.ts
@@ -76,6 +76,7 @@ export class SurveyState {
finished: responseUpdate.finished,
ttc: responseUpdate.ttc,
data: { ...this.responseAcc.data, ...responseUpdate.data },
+ displayId: responseUpdate.displayId,
};
}
diff --git a/packages/react-native/src/survey-web-view.tsx b/packages/react-native/src/survey-web-view.tsx
index bb77a53beb..3028080bc7 100644
--- a/packages/react-native/src/survey-web-view.tsx
+++ b/packages/react-native/src/survey-web-view.tsx
@@ -96,6 +96,7 @@ export function SurveyWebView({ survey }: SurveyWebViewProps): JSX.Element | und
finished: responseUpdate.finished,
language:
responseUpdate.language === "default" ? getDefaultLanguageCode(survey) : responseUpdate.language,
+ displayId: surveyState.displayId,
});
};
diff --git a/packages/types/displays.ts b/packages/types/displays.ts
index 9943e99ff5..d9157b8e21 100644
--- a/packages/types/displays.ts
+++ b/packages/types/displays.ts
@@ -4,9 +4,8 @@ export const ZDisplay = z.object({
id: z.string().cuid2(),
createdAt: z.date(),
updatedAt: z.date(),
- personId: z.string().cuid2().nullable(),
- surveyId: z.string().cuid2(),
- responseId: z.string().cuid2().nullable(),
+ personId: z.string().cuid().nullable(),
+ surveyId: z.string().cuid(),
status: z.enum(["seen", "responded"]).nullable(),
});
@@ -21,14 +20,6 @@ export const ZDisplayCreateInput = z.object({
export type TDisplayCreateInput = z.infer;
-export const ZDisplayUpdateInput = z.object({
- environmentId: z.string().cuid2(),
- userId: z.string().optional(),
- responseId: z.string().cuid2().optional(),
-});
-
-export type TDisplayUpdateInput = z.infer;
-
export const ZDisplaysWithSurveyName = ZDisplay.extend({
surveyName: z.string(),
});
diff --git a/packages/types/responses.ts b/packages/types/responses.ts
index 5586053b1b..df81229770 100644
--- a/packages/types/responses.ts
+++ b/packages/types/responses.ts
@@ -226,6 +226,7 @@ export const ZResponse = z.object({
createdAt: z.date(),
updatedAt: z.date(),
surveyId: z.string().cuid2(),
+ displayId: z.string().nullish(),
person: ZResponsePerson.nullable(),
personAttributes: ZResponsePersonAttributes,
finished: z.boolean(),
@@ -246,6 +247,7 @@ export const ZResponseInput = z.object({
environmentId: z.string().cuid2(),
surveyId: z.string().cuid2(),
userId: z.string().nullish(),
+ displayId: z.string().nullish(),
singleUseId: z.string().nullable().optional(),
finished: z.boolean(),
language: z.string().optional(),
@@ -301,6 +303,7 @@ export const ZResponseUpdate = z.object({
})
.optional(),
hiddenFields: ZResponseHiddenFieldValue.optional(),
+ displayId: z.string().nullish(),
});
export type TResponseUpdate = z.infer;