feat: survey follow ups (#4247)

Co-authored-by: Johannes <johannes@formbricks.com>
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Anshuman Pandey
2024-11-21 12:20:37 +05:30
committed by GitHub
parent f0a4fad878
commit 37ef6be4c3
56 changed files with 2260 additions and 608 deletions
+13 -12
View File
@@ -1,14 +1,12 @@
/* eslint-disable import/no-relative-packages -- required for importing types */
/* eslint-disable @typescript-eslint/no-namespace -- using namespaces is required for prisma-json-types-generator */
import { type TActionClassNoCodeConfig } from "@formbricks/types/action-classes";
import { type TIntegrationConfig } from "@formbricks/types/integration";
import { type TOrganizationBilling } from "@formbricks/types/organizations";
import { type TProductConfig, type TProductStyling } from "@formbricks/types/product";
import {
type TResponseData,
type TResponseMeta,
type TResponsePersonAttributes,
} from "@formbricks/types/responses";
import { type TBaseFilters } from "@formbricks/types/segment";
import { type TActionClassNoCodeConfig } from "../types/action-classes";
import { type TIntegrationConfig } from "../types/integration";
import { type TOrganizationBilling } from "../types/organizations";
import { type TProductConfig, type TProductStyling } from "../types/product";
import { type TResponseData, type TResponseMeta, type TResponsePersonAttributes } from "../types/responses";
import { type TBaseFilters } from "../types/segment";
import {
type TSurveyClosedMessage,
type TSurveyEnding,
@@ -19,8 +17,9 @@ import {
type TSurveyStyling,
type TSurveyVariables,
type TSurveyWelcomeCard,
} from "@formbricks/types/surveys/types";
import { type TUserLocale, type TUserNotificationSettings } from "@formbricks/types/user";
} from "../types/surveys/types";
import { type TUserLocale, type TUserNotificationSettings } from "../types/user";
import type { TSurveyFollowUpAction, TSurveyFollowUpTrigger } from "./types/survey-follow-up";
declare global {
namespace PrismaJson {
@@ -45,5 +44,7 @@ declare global {
export type SegmentFilter = TBaseFilters;
export type Styling = TProductStyling;
export type Locale = TUserLocale;
export type SurveyFollowUpTrigger = TSurveyFollowUpTrigger;
export type SurveyFollowUpAction = TSurveyFollowUpAction;
}
}
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "SurveyFollowUp" (
"id" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
"surveyId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"trigger" JSONB NOT NULL,
"action" JSONB NOT NULL,
CONSTRAINT "SurveyFollowUp_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "SurveyFollowUp" ADD CONSTRAINT "SurveyFollowUp_surveyId_fkey" FOREIGN KEY ("surveyId") REFERENCES "Survey"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "Response" ADD COLUMN "endingId" TEXT;
+1 -2
View File
@@ -65,9 +65,8 @@
},
"devDependencies": {
"@formbricks/config-typescript": "workspace:*",
"@formbricks/types": "workspace:*",
"@paralleldrive/cuid2": "2.2.2",
"@formbricks/eslint-config": "workspace:*",
"@paralleldrive/cuid2": "2.2.2",
"prisma": "5.20.0",
"prisma-dbml-generator": "0.12.0",
"prisma-json-types-generator": "3.1.1",
+17
View File
@@ -112,6 +112,7 @@ model Response {
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
finished Boolean @default(false)
endingId String?
survey Survey @relation(fields: [surveyId], references: [id], onDelete: Cascade)
surveyId String
person Person? @relation(fields: [personId], references: [id], onDelete: Cascade)
@@ -333,11 +334,27 @@ model Survey {
languages SurveyLanguage[]
showLanguageSwitch Boolean?
documents Document[]
followUps SurveyFollowUp[]
@@index([environmentId, updatedAt])
@@index([segmentId])
}
model SurveyFollowUp {
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
name String
/// [SurveyFollowUpTrigger]
/// @zod.custom(imports.ZSurveyFollowUpTrigger)
trigger Json
/// [SurveyFollowUpAction]
/// @zod.custom(imports.ZSurveyFollowUpAction)
action Json
}
enum ActionType {
code
noCode
@@ -0,0 +1,57 @@
import { z } from "zod";
export const ZSurveyFollowUpTrigger = z
.object({
type: z.enum(["response", "endings"]),
properties: z
.object({
endingIds: z.array(z.string().cuid2()),
})
.nullable(),
})
.superRefine((trigger, ctx) => {
if (trigger.type === "response") {
if (trigger.properties) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Properties should be null for response type",
});
}
}
if (trigger.type === "endings") {
if (!trigger.properties) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Properties must be defined for endings type",
});
}
}
});
export type TSurveyFollowUpTrigger = z.infer<typeof ZSurveyFollowUpTrigger>;
export const ZSurveyFollowUpAction = z.object({
type: z.literal("send-email"),
properties: z.object({
to: z.string(),
from: z.string().email(),
replyTo: z.array(z.string().email()),
subject: z.string(),
body: z.string(),
}),
});
export type TSurveyFollowUpAction = z.infer<typeof ZSurveyFollowUpAction>;
export const ZSurveyFollowUp = z.object({
id: z.string().cuid2(),
createdAt: z.date(),
updatedAt: z.date(),
name: z.string(),
trigger: ZSurveyFollowUpTrigger,
action: ZSurveyFollowUpAction,
surveyId: z.string().cuid2(),
});
export type TSurveyFollowUp = z.infer<typeof ZSurveyFollowUp>;
+10 -12
View File
@@ -1,15 +1,11 @@
/* eslint-disable import/no-relative-packages -- required for importing types */
import { z } from "zod";
export const ZActionProperties = z.record(z.string());
export { ZActionClassNoCodeConfig } from "@formbricks/types/action-classes";
export { ZIntegrationConfig } from "@formbricks/types/integration";
export { ZActionClassNoCodeConfig } from "../types/action-classes";
export { ZIntegrationConfig } from "../types/integration";
export {
ZResponseData,
ZResponsePersonAttributes,
ZResponseMeta,
ZResponseTtc,
} from "@formbricks/types/responses";
export { ZResponseData, ZResponsePersonAttributes, ZResponseMeta, ZResponseTtc } from "../types/responses";
export {
ZSurveyWelcomeCard,
@@ -22,8 +18,10 @@ export {
ZSurveySingleUse,
ZSurveyInlineTriggers,
ZSurveyEnding,
} from "@formbricks/types/surveys/types";
} from "../types/surveys/types";
export { ZSegmentFilters } from "@formbricks/types/segment";
export { ZOrganizationBilling } from "@formbricks/types/organizations";
export { ZUserNotificationSettings } from "@formbricks/types/user";
export { ZSurveyFollowUpAction, ZSurveyFollowUpTrigger } from "./types/survey-follow-up";
export { ZSegmentFilters } from "../types/segment";
export { ZOrganizationBilling } from "../types/organizations";
export { ZUserNotificationSettings } from "../types/user";