mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-01 19:30:29 -06:00
* add placement enum and prop to db scheme * enable placement toggle in setttings * enable in-app survey placement demo * add position helper function * add placement to in-app-modal preview * add placement prop to api endpoint * add placement to widget * remove coming soon * add styling * add apply tailwind styles instead of a ts function * add clickoutside and darkoverlay prop * add darkOverlay and clickOutside form * update js package tailwind apply classes * add background to widget and close on click outside * only show backdrop and clickOutside if is center * only display background when modal is centered * responsive changes in js widget * add updated migration, move styles from global.css to function --------- Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
234 lines
6.0 KiB
TypeScript
234 lines
6.0 KiB
TypeScript
import { prisma } from "@formbricks/database";
|
|
import { Settings } from "@formbricks/types/js";
|
|
|
|
export const getSettings = async (environmentId: string, personId: string): Promise<Settings> => {
|
|
// get recontactDays from product
|
|
const product = await prisma.product.findFirst({
|
|
where: {
|
|
environments: {
|
|
some: {
|
|
id: environmentId,
|
|
},
|
|
},
|
|
},
|
|
select: {
|
|
recontactDays: true,
|
|
},
|
|
});
|
|
|
|
if (!product) {
|
|
throw new Error("Product not found");
|
|
}
|
|
|
|
const person = await prisma.person.findUnique({
|
|
where: {
|
|
id: personId,
|
|
},
|
|
select: {
|
|
attributes: {
|
|
select: {
|
|
id: true,
|
|
value: true,
|
|
attributeClassId: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!person) {
|
|
throw new Error("Person not found");
|
|
}
|
|
|
|
// get all surveys that meet the displayOption criteria
|
|
const potentialSurveys = await prisma.survey.findMany({
|
|
where: {
|
|
OR: [
|
|
{
|
|
environmentId,
|
|
type: "web",
|
|
status: "inProgress",
|
|
displayOption: "respondMultiple",
|
|
},
|
|
{
|
|
environmentId,
|
|
type: "web",
|
|
status: "inProgress",
|
|
displayOption: "displayOnce",
|
|
displays: { none: { personId } },
|
|
},
|
|
{
|
|
environmentId,
|
|
type: "web",
|
|
status: "inProgress",
|
|
displayOption: "displayMultiple",
|
|
displays: { none: { personId, status: "responded" } },
|
|
},
|
|
],
|
|
},
|
|
select: {
|
|
id: true,
|
|
questions: true,
|
|
recontactDays: true,
|
|
triggers: {
|
|
select: {
|
|
id: true,
|
|
eventClass: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
},
|
|
},
|
|
},
|
|
// last display
|
|
},
|
|
attributeFilters: {
|
|
select: {
|
|
id: true,
|
|
condition: true,
|
|
value: true,
|
|
attributeClass: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
displays: {
|
|
where: {
|
|
personId,
|
|
},
|
|
orderBy: {
|
|
createdAt: "desc",
|
|
},
|
|
take: 1,
|
|
select: {
|
|
createdAt: true,
|
|
},
|
|
},
|
|
thankYouCard: true,
|
|
autoClose: true,
|
|
delay: true,
|
|
},
|
|
});
|
|
|
|
// get last display for this person
|
|
const lastDisplayPerson = await prisma.display.findFirst({
|
|
where: {
|
|
personId,
|
|
},
|
|
orderBy: {
|
|
createdAt: "desc",
|
|
},
|
|
select: {
|
|
createdAt: true,
|
|
},
|
|
});
|
|
|
|
// filter surveys that meet the attributeFilters criteria
|
|
const potentialSurveysWithAttributes = potentialSurveys.filter((survey) => {
|
|
const attributeFilters = survey.attributeFilters;
|
|
if (attributeFilters.length === 0) {
|
|
return true;
|
|
}
|
|
// check if meets all attribute filters criterias
|
|
return attributeFilters.every((attributeFilter) => {
|
|
const attribute = person.attributes.find(
|
|
(attribute) => attribute.attributeClassId === attributeFilter.attributeClass.id
|
|
);
|
|
if (attributeFilter.condition === "equals") {
|
|
return attribute?.value === attributeFilter.value;
|
|
} else if (attributeFilter.condition === "notEquals") {
|
|
return attribute?.value !== attributeFilter.value;
|
|
} else {
|
|
throw Error("Invalid attribute filter condition");
|
|
}
|
|
});
|
|
});
|
|
|
|
// filter surveys that meet the recontactDays criteria
|
|
const surveys = potentialSurveysWithAttributes
|
|
.filter((survey) => {
|
|
if (!lastDisplayPerson) {
|
|
// no display yet - always display
|
|
return true;
|
|
} else if (survey.recontactDays !== null) {
|
|
// if recontactDays is set on survey, use that
|
|
const lastDisplaySurvey = survey.displays[0];
|
|
if (!lastDisplaySurvey) {
|
|
// no display yet - always display
|
|
return true;
|
|
}
|
|
const lastDisplayDate = new Date(lastDisplaySurvey.createdAt);
|
|
const currentDate = new Date();
|
|
const diffTime = Math.abs(currentDate.getTime() - lastDisplayDate.getTime());
|
|
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
return diffDays >= survey.recontactDays;
|
|
} else if (product.recontactDays !== null) {
|
|
// if recontactDays is not set in survey, use product recontactDays
|
|
const lastDisplayDate = new Date(lastDisplayPerson.createdAt);
|
|
const currentDate = new Date();
|
|
const diffTime = Math.abs(currentDate.getTime() - lastDisplayDate.getTime());
|
|
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
|
return diffDays >= product.recontactDays;
|
|
} else {
|
|
// if recontactDays is not set in survey or product, always display
|
|
return true;
|
|
}
|
|
})
|
|
.map((survey) => {
|
|
return {
|
|
id: survey.id,
|
|
questions: JSON.parse(JSON.stringify(survey.questions)),
|
|
triggers: survey.triggers,
|
|
thankYouCard: JSON.parse(JSON.stringify(survey.thankYouCard)),
|
|
autoClose: survey.autoClose,
|
|
delay: survey.delay,
|
|
};
|
|
});
|
|
|
|
const noCodeEvents = await prisma.eventClass.findMany({
|
|
where: {
|
|
environmentId,
|
|
type: "noCode",
|
|
},
|
|
select: {
|
|
name: true,
|
|
noCodeConfig: true,
|
|
},
|
|
});
|
|
|
|
const environmentProdut = await prisma.environment.findUnique({
|
|
where: {
|
|
id: environmentId,
|
|
},
|
|
select: {
|
|
product: {
|
|
select: {
|
|
brandColor: true,
|
|
formbricksSignature: true,
|
|
placement: true,
|
|
darkOverlay: true,
|
|
clickOutsideClose: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
const formbricksSignature = environmentProdut?.product.formbricksSignature;
|
|
const brandColor = environmentProdut?.product.brandColor;
|
|
const placement = environmentProdut?.product.placement;
|
|
const darkOverlay = environmentProdut?.product.darkOverlay;
|
|
const clickOutsideClose = environmentProdut?.product.clickOutsideClose;
|
|
|
|
return {
|
|
surveys,
|
|
noCodeEvents,
|
|
brandColor,
|
|
formbricksSignature,
|
|
placement,
|
|
darkOverlay,
|
|
clickOutsideClose,
|
|
};
|
|
};
|