mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-24 06:28:49 -05:00
chore: added date transform for cached services (#1753)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
d8b6b95ed5
commit
3103760611
@@ -98,7 +98,6 @@ export const leaveTeamAction = async (teamId: string) => {
|
||||
|
||||
export const createInviteTokenAction = async (inviteId: string) => {
|
||||
const { email } = await getInvite(inviteId);
|
||||
|
||||
const inviteToken = createInviteToken(inviteId, email, {
|
||||
expiresIn: "7d",
|
||||
});
|
||||
|
||||
-1
@@ -74,7 +74,6 @@ export default function MemberActions({ team, member, invite, showDeleteButton }
|
||||
const handleShareInvite = async () => {
|
||||
try {
|
||||
if (!invite) return;
|
||||
|
||||
const { inviteToken } = await createInviteTokenAction(invite.id);
|
||||
setShareInviteToken(inviteToken);
|
||||
setShowShareInviteModal(true);
|
||||
|
||||
@@ -2,7 +2,7 @@ import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TActionClassType } from "@formbricks/types/actionClasses";
|
||||
import { TAction, TActionInput, ZActionInput } from "@formbricks/types/actions";
|
||||
import { TAction, TActionInput, ZAction, ZActionInput } from "@formbricks/types/actions";
|
||||
import { ZOptionalNumber } from "@formbricks/types/common";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
@@ -14,6 +14,7 @@ import { createActionClass, getActionClassByEnvironmentIdAndName } from "../acti
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { actionCache } from "./cache";
|
||||
import { createPerson, getPersonByUserId } from "../person/service";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const getLatestActionByEnvironmentId = async (environmentId: string): Promise<TAction | null> => {
|
||||
const action = await unstable_cache(
|
||||
@@ -62,12 +63,7 @@ export const getLatestActionByEnvironmentId = async (environmentId: string): Pro
|
||||
|
||||
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
|
||||
// https://github.com/vercel/next.js/issues/51613
|
||||
return action
|
||||
? {
|
||||
...action,
|
||||
createdAt: new Date(action.createdAt),
|
||||
}
|
||||
: action;
|
||||
return action ? formatDateFields(action, ZAction) : null;
|
||||
};
|
||||
|
||||
export const getLatestActionByPersonId = async (personId: string): Promise<TAction | null> => {
|
||||
@@ -116,12 +112,7 @@ export const getLatestActionByPersonId = async (personId: string): Promise<TActi
|
||||
|
||||
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
|
||||
// https://github.com/vercel/next.js/issues/51613
|
||||
return action
|
||||
? {
|
||||
...action,
|
||||
createdAt: new Date(action.createdAt),
|
||||
}
|
||||
: action;
|
||||
return action ? formatDateFields(action, ZAction) : null;
|
||||
};
|
||||
|
||||
export const getActionsByPersonId = async (personId: string, page?: number): Promise<TAction[]> => {
|
||||
@@ -167,10 +158,7 @@ export const getActionsByPersonId = async (personId: string, page?: number): Pro
|
||||
)();
|
||||
|
||||
// Deserialize dates if caching does not support deserialization
|
||||
return actions.map((action) => ({
|
||||
...action,
|
||||
createdAt: new Date(action.createdAt),
|
||||
}));
|
||||
return actions.map((action) => formatDateFields(action, ZAction));
|
||||
};
|
||||
|
||||
export const getActionsByEnvironmentId = async (environmentId: string, page?: number): Promise<TAction[]> => {
|
||||
@@ -224,10 +212,8 @@ export const getActionsByEnvironmentId = async (environmentId: string, page?: nu
|
||||
|
||||
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
|
||||
// https://github.com/vercel/next.js/issues/51613
|
||||
return actions.map((action) => ({
|
||||
...action,
|
||||
createdAt: new Date(action.createdAt),
|
||||
}));
|
||||
|
||||
return actions.map((action) => formatDateFields(action, ZAction));
|
||||
};
|
||||
|
||||
export const createAction = async (data: TActionInput): Promise<TAction> => {
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TActionClass, TActionClassInput, ZActionClassInput } from "@formbricks/types/actionClasses";
|
||||
import {
|
||||
TActionClass,
|
||||
TActionClassInput,
|
||||
ZActionClass,
|
||||
ZActionClassInput,
|
||||
} from "@formbricks/types/actionClasses";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
@@ -11,6 +16,7 @@ import { unstable_cache } from "next/cache";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { actionClassCache } from "./cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
const select = {
|
||||
id: true,
|
||||
@@ -23,8 +29,8 @@ const select = {
|
||||
environmentId: true,
|
||||
};
|
||||
|
||||
export const getActionClasses = (environmentId: string, page?: number): Promise<TActionClass[]> =>
|
||||
unstable_cache(
|
||||
export const getActionClasses = async (environmentId: string, page?: number): Promise<TActionClass[]> => {
|
||||
const actionClasses = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [page, ZOptionalNumber]);
|
||||
|
||||
@@ -40,8 +46,7 @@ export const getActionClasses = (environmentId: string, page?: number): Promise<
|
||||
createdAt: "asc",
|
||||
},
|
||||
});
|
||||
|
||||
return actionClasses;
|
||||
return actionClasses.map((actionClass) => formatDateFields(actionClass, ZActionClass));
|
||||
} catch (error) {
|
||||
throw new DatabaseError(`Database error when fetching actions for environment ${environmentId}`);
|
||||
}
|
||||
@@ -52,12 +57,14 @@ export const getActionClasses = (environmentId: string, page?: number): Promise<
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return actionClasses.map((actionClass) => formatDateFields(actionClass, ZActionClass));
|
||||
};
|
||||
|
||||
export const getActionClassByEnvironmentIdAndName = async (
|
||||
environmentId: string,
|
||||
name: string
|
||||
): Promise<TActionClass | null> =>
|
||||
unstable_cache(
|
||||
): Promise<TActionClass | null> => {
|
||||
const actionClass = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [name, ZString]);
|
||||
|
||||
@@ -81,9 +88,11 @@ export const getActionClassByEnvironmentIdAndName = async (
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return actionClass ? formatDateFields(actionClass, ZActionClass) : null;
|
||||
};
|
||||
|
||||
export const getActionClass = async (actionClassId: string): Promise<TActionClass | null> =>
|
||||
unstable_cache(
|
||||
export const getActionClass = async (actionClassId: string): Promise<TActionClass | null> => {
|
||||
const actionClass = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([actionClassId, ZId]);
|
||||
|
||||
@@ -106,6 +115,8 @@ export const getActionClass = async (actionClassId: string): Promise<TActionClas
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return actionClass ? formatDateFields(actionClass, ZActionClass) : null;
|
||||
};
|
||||
|
||||
export const deleteActionClass = async (
|
||||
environmentId: string,
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TApiKey, TApiKeyCreateInput, ZApiKeyCreateInput } from "@formbricks/types/apiKeys";
|
||||
import { TApiKey, TApiKeyCreateInput, ZApiKey, ZApiKeyCreateInput } from "@formbricks/types/apiKeys";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { getHash } from "../crypto";
|
||||
import { createHash, randomBytes } from "crypto";
|
||||
import { DatabaseError, InvalidInputError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { DatabaseError, InvalidInputError } from "@formbricks/types/errors";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { ZString, ZOptionalNumber } from "@formbricks/types/common";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { apiKeyCache } from "./cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const getApiKey = async (apiKeyId: string): Promise<TApiKey | null> =>
|
||||
unstable_cache(
|
||||
export const getApiKey = async (apiKeyId: string): Promise<TApiKey | null> => {
|
||||
const apiKey = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([apiKeyId, ZString]);
|
||||
|
||||
@@ -29,10 +30,6 @@ export const getApiKey = async (apiKeyId: string): Promise<TApiKey | null> =>
|
||||
},
|
||||
});
|
||||
|
||||
if (!apiKeyData) {
|
||||
throw new ResourceNotFoundError("API Key from ID", apiKeyId);
|
||||
}
|
||||
|
||||
return apiKeyData;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -48,9 +45,11 @@ export const getApiKey = async (apiKeyId: string): Promise<TApiKey | null> =>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return apiKey ? formatDateFields(apiKey, ZApiKey) : null;
|
||||
};
|
||||
|
||||
export const getApiKeys = async (environmentId: string, page?: number): Promise<TApiKey[]> =>
|
||||
unstable_cache(
|
||||
export const getApiKeys = async (environmentId: string, page?: number): Promise<TApiKey[]> => {
|
||||
const apiKeys = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [page, ZOptionalNumber]);
|
||||
|
||||
@@ -77,6 +76,8 @@ export const getApiKeys = async (environmentId: string, page?: number): Promise<
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return apiKeys.map((apiKey) => formatDateFields(apiKey, ZApiKey));
|
||||
};
|
||||
|
||||
export const hashApiKey = (key: string): string => createHash("sha256").update(key).digest("hex");
|
||||
|
||||
@@ -112,7 +113,7 @@ export async function createApiKey(environmentId: string, apiKeyData: TApiKeyCre
|
||||
export const getApiKeyFromKey = async (apiKey: string): Promise<TApiKey | null> => {
|
||||
const hashedKey = getHash(apiKey);
|
||||
|
||||
return unstable_cache(
|
||||
const apiKeyData = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([apiKey, ZString]);
|
||||
|
||||
@@ -142,6 +143,7 @@ export const getApiKeyFromKey = async (apiKey: string): Promise<TApiKey | null>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return apiKeyData ? formatDateFields(apiKeyData, ZApiKey) : null;
|
||||
};
|
||||
|
||||
export const deleteApiKey = async (id: string): Promise<TApiKey | null> => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ZAttributeClassUpdateInput,
|
||||
TAttributeClassType,
|
||||
ZAttributeClassType,
|
||||
ZAttributeClass,
|
||||
} from "@formbricks/types/attributeClasses";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
@@ -16,7 +17,7 @@ import { unstable_cache } from "next/cache";
|
||||
import { SERVICES_REVALIDATION_INTERVAL, ITEMS_PER_PAGE } from "../constants";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { attributeClassCache } from "./cache";
|
||||
import { formatAttributeClassDateFields } from "./util";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const getAttributeClass = async (attributeClassId: string): Promise<TAttributeClass | null> => {
|
||||
const attributeClass = await unstable_cache(
|
||||
@@ -40,11 +41,7 @@ export const getAttributeClass = async (attributeClassId: string): Promise<TAttr
|
||||
}
|
||||
)();
|
||||
|
||||
if (!attributeClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatAttributeClassDateFields(attributeClass);
|
||||
return attributeClass ? formatDateFields(attributeClass, ZAttributeClass) : null;
|
||||
};
|
||||
|
||||
export const getAttributeClasses = async (
|
||||
@@ -80,8 +77,7 @@ export const getAttributeClasses = async (
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return attributeClasses.map(formatAttributeClassDateFields);
|
||||
return attributeClasses.map((attributeClass) => formatDateFields(attributeClass, ZAttributeClass));
|
||||
};
|
||||
|
||||
export const updateAttributeClass = async (
|
||||
@@ -113,17 +109,19 @@ export const updateAttributeClass = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const getAttributeClassByName = async (environmentId: string, name: string) =>
|
||||
await unstable_cache(
|
||||
export const getAttributeClassByName = async (environmentId: string, name: string) => {
|
||||
const attributeClass = await unstable_cache(
|
||||
async (): Promise<TAttributeClass | null> => {
|
||||
validateInputs([environmentId, ZId], [name, ZString]);
|
||||
|
||||
return await prisma.attributeClass.findFirst({
|
||||
const attributeClass = await prisma.attributeClass.findFirst({
|
||||
where: {
|
||||
environmentId,
|
||||
name,
|
||||
},
|
||||
});
|
||||
|
||||
return attributeClass;
|
||||
},
|
||||
[`getAttributeClassByName-${environmentId}-${name}`],
|
||||
{
|
||||
@@ -131,6 +129,8 @@ export const getAttributeClassByName = async (environmentId: string, name: strin
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return attributeClass ? formatDateFields(attributeClass, ZAttributeClass) : null;
|
||||
};
|
||||
|
||||
export const createAttributeClass = async (
|
||||
environmentId: string,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TDisplayLegacyCreateInput,
|
||||
TDisplayLegacyUpdateInput,
|
||||
TDisplayUpdateInput,
|
||||
ZDisplay,
|
||||
ZDisplayCreateInput,
|
||||
ZDisplayLegacyCreateInput,
|
||||
ZDisplayLegacyUpdateInput,
|
||||
@@ -21,8 +22,8 @@ import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { createPerson, getPersonByUserId } from "../person/service";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { displayCache } from "./cache";
|
||||
import { formatDisplaysDateFields } from "./util";
|
||||
import { TPerson } from "@formbricks/types/people";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
const selectDisplay = {
|
||||
id: true,
|
||||
@@ -33,20 +34,20 @@ const selectDisplay = {
|
||||
personId: true,
|
||||
};
|
||||
|
||||
export const getDisplay = async (displayId: string): Promise<TDisplay | null> =>
|
||||
await unstable_cache(
|
||||
export const getDisplay = async (displayId: string): Promise<TDisplay | null> => {
|
||||
const display = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([displayId, ZId]);
|
||||
|
||||
try {
|
||||
const responsePrisma = await prisma.response.findUnique({
|
||||
const display = await prisma.response.findUnique({
|
||||
where: {
|
||||
id: displayId,
|
||||
},
|
||||
select: selectDisplay,
|
||||
});
|
||||
|
||||
return responsePrisma;
|
||||
return display;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -61,6 +62,8 @@ export const getDisplay = async (displayId: string): Promise<TDisplay | null> =>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return display ? formatDateFields(display, ZDisplay) : null;
|
||||
};
|
||||
|
||||
export const updateDisplay = async (
|
||||
displayId: string,
|
||||
@@ -295,10 +298,6 @@ export const getDisplaysByPersonId = async (personId: string, page?: number): Pr
|
||||
},
|
||||
});
|
||||
|
||||
if (!displays) {
|
||||
throw new ResourceNotFoundError("Display from PersonId", personId);
|
||||
}
|
||||
|
||||
return displays;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -314,8 +313,7 @@ export const getDisplaysByPersonId = async (personId: string, page?: number): Pr
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return formatDisplaysDateFields(displays);
|
||||
return displays.map((display) => formatDateFields(display, ZDisplay));
|
||||
};
|
||||
|
||||
export const deleteDisplayByResponseId = async (responseId: string, surveyId: string): Promise<TDisplay> => {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { TDisplay } from "@formbricks/types/displays";
|
||||
|
||||
export const formatDisplaysDateFields = (displays: TDisplay[]): TDisplay[] => {
|
||||
return displays.map((display) => ({
|
||||
...display,
|
||||
createdAt: new Date(display.createdAt),
|
||||
updatedAt: new Date(display.updatedAt),
|
||||
}));
|
||||
};
|
||||
@@ -20,19 +20,20 @@ import { z } from "zod";
|
||||
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { environmentCache } from "./cache";
|
||||
import { formatEnvironmentDateFields } from "./util";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const getEnvironment = (environmentId: string): Promise<TEnvironment | null> =>
|
||||
unstable_cache(
|
||||
export const getEnvironment = async (environmentId: string): Promise<TEnvironment | null> => {
|
||||
const environment = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
|
||||
try {
|
||||
return await prisma.environment.findUnique({
|
||||
const environment = await prisma.environment.findUnique({
|
||||
where: {
|
||||
id: environmentId,
|
||||
},
|
||||
});
|
||||
return environment;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
console.error(error);
|
||||
@@ -48,9 +49,11 @@ export const getEnvironment = (environmentId: string): Promise<TEnvironment | nu
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return environment ? formatDateFields(environment, ZEnvironment) : null;
|
||||
};
|
||||
|
||||
export const getEnvironments = async (productId: string): Promise<TEnvironment[]> =>
|
||||
unstable_cache(
|
||||
export const getEnvironments = async (productId: string): Promise<TEnvironment[]> => {
|
||||
const environments = await unstable_cache(
|
||||
async (): Promise<TEnvironment[]> => {
|
||||
validateInputs([productId, ZId]);
|
||||
let productPrisma;
|
||||
@@ -95,6 +98,8 @@ export const getEnvironments = async (productId: string): Promise<TEnvironment[]
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return environments.map((environment) => formatDateFields(environment, ZEnvironment));
|
||||
};
|
||||
|
||||
export const updateEnvironment = async (
|
||||
environmentId: string,
|
||||
@@ -130,7 +135,7 @@ export const getFirstEnvironmentByUserId = async (userId: string): Promise<TEnvi
|
||||
async () => {
|
||||
validateInputs([userId, ZId]);
|
||||
try {
|
||||
return await prisma.environment.findFirst({
|
||||
const environment = await prisma.environment.findFirst({
|
||||
where: {
|
||||
type: "production",
|
||||
product: {
|
||||
@@ -144,6 +149,7 @@ export const getFirstEnvironmentByUserId = async (userId: string): Promise<TEnvi
|
||||
},
|
||||
},
|
||||
});
|
||||
return environment;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -159,7 +165,7 @@ export const getFirstEnvironmentByUserId = async (userId: string): Promise<TEnvi
|
||||
}
|
||||
)();
|
||||
|
||||
return environment ? formatEnvironmentDateFields(environment) : environment;
|
||||
return environment ? formatDateFields(environment, ZEnvironment) : null;
|
||||
};
|
||||
|
||||
export const createEnvironment = async (
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import "server-only";
|
||||
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
|
||||
export const formatEnvironmentDateFields = (environemt: TEnvironment): TEnvironment => {
|
||||
if (typeof environemt.createdAt === "string") {
|
||||
environemt.createdAt = new Date(environemt.createdAt);
|
||||
}
|
||||
if (typeof environemt.updatedAt === "string") {
|
||||
environemt.updatedAt = new Date(environemt.updatedAt);
|
||||
}
|
||||
|
||||
return environemt;
|
||||
};
|
||||
@@ -1,15 +1,21 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { TIntegration, TIntegrationInput, ZIntegrationType } from "@formbricks/types/integration";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZString, ZOptionalNumber } from "@formbricks/types/common";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { integrationCache } from "./cache";
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
import {
|
||||
TIntegration,
|
||||
TIntegrationInput,
|
||||
ZIntegration,
|
||||
ZIntegrationType,
|
||||
} from "@formbricks/types/integration";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { integrationCache } from "./cache";
|
||||
|
||||
export async function createOrUpdateIntegration(
|
||||
environmentId: string,
|
||||
@@ -48,20 +54,20 @@ export async function createOrUpdateIntegration(
|
||||
}
|
||||
}
|
||||
|
||||
export const getIntegrations = async (environmentId: string, page?: number): Promise<TIntegration[]> =>
|
||||
unstable_cache(
|
||||
export const getIntegrations = async (environmentId: string, page?: number): Promise<TIntegration[]> => {
|
||||
const integrations = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [page, ZOptionalNumber]);
|
||||
|
||||
try {
|
||||
const result = await prisma.integration.findMany({
|
||||
const integrations = await prisma.integration.findMany({
|
||||
where: {
|
||||
environmentId,
|
||||
},
|
||||
take: page ? ITEMS_PER_PAGE : undefined,
|
||||
skip: page ? ITEMS_PER_PAGE * (page - 1) : undefined,
|
||||
});
|
||||
return result;
|
||||
return integrations;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -75,17 +81,19 @@ export const getIntegrations = async (environmentId: string, page?: number): Pro
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return integrations.map((integration) => formatDateFields(integration, ZIntegration));
|
||||
};
|
||||
|
||||
export const getIntegration = async (integrationId: string): Promise<TIntegration | null> =>
|
||||
unstable_cache(
|
||||
export const getIntegration = async (integrationId: string): Promise<TIntegration | null> => {
|
||||
const integration = await unstable_cache(
|
||||
async () => {
|
||||
try {
|
||||
const result = await prisma.integration.findUnique({
|
||||
const integration = await prisma.integration.findUnique({
|
||||
where: {
|
||||
id: integrationId,
|
||||
},
|
||||
});
|
||||
return result;
|
||||
return integration;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -96,17 +104,19 @@ export const getIntegration = async (integrationId: string): Promise<TIntegratio
|
||||
[`getIntegration-${integrationId}`],
|
||||
{ tags: [integrationCache.tag.byId(integrationId)], revalidate: SERVICES_REVALIDATION_INTERVAL }
|
||||
)();
|
||||
return integration ? formatDateFields(integration, ZIntegration) : null;
|
||||
};
|
||||
|
||||
export const getIntegrationByType = async (
|
||||
environmentId: string,
|
||||
type: TIntegrationInput["type"]
|
||||
): Promise<TIntegration | null> =>
|
||||
unstable_cache(
|
||||
): Promise<TIntegration | null> => {
|
||||
const integration = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [type, ZIntegrationType]);
|
||||
|
||||
try {
|
||||
const result = await prisma.integration.findUnique({
|
||||
const integration = await prisma.integration.findUnique({
|
||||
where: {
|
||||
type_environmentId: {
|
||||
environmentId,
|
||||
@@ -114,8 +124,7 @@ export const getIntegrationByType = async (
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return result;
|
||||
return integration;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new DatabaseError(error.message);
|
||||
@@ -129,6 +138,8 @@ export const getIntegrationByType = async (
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return integration ? formatDateFields(integration, ZIntegration) : null;
|
||||
};
|
||||
|
||||
export const deleteIntegration = async (integrationId: string): Promise<TIntegration> => {
|
||||
validateInputs([integrationId, ZString]);
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ZInviteUpdateInput,
|
||||
ZCurrentUser,
|
||||
TCurrentUser,
|
||||
ZInvite,
|
||||
} from "@formbricks/types/invites";
|
||||
import { ResourceNotFoundError, ValidationError, DatabaseError } from "@formbricks/types/errors";
|
||||
import { ZString, ZOptionalNumber } from "@formbricks/types/common";
|
||||
@@ -18,8 +19,8 @@ import { validateInputs } from "../utils/validate";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { inviteCache } from "./cache";
|
||||
import { formatInviteDateFields } from "./util";
|
||||
import { getMembershipByUserIdTeamId } from "../membership/service";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
const inviteSelect = {
|
||||
id: true,
|
||||
@@ -33,8 +34,13 @@ const inviteSelect = {
|
||||
expiresAt: true,
|
||||
role: true,
|
||||
};
|
||||
|
||||
export const getInvitesByTeamId = async (teamId: string, page?: number): Promise<TInvite[] | null> => {
|
||||
interface InviteWithCreator extends TInvite {
|
||||
creator: {
|
||||
name: string | null;
|
||||
email: string;
|
||||
};
|
||||
}
|
||||
export const getInvitesByTeamId = async (teamId: string, page?: number): Promise<TInvite[]> => {
|
||||
const invites = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([teamId, ZString], [page, ZOptionalNumber]);
|
||||
@@ -52,8 +58,7 @@ export const getInvitesByTeamId = async (teamId: string, page?: number): Promise
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return invites.map(formatInviteDateFields);
|
||||
return invites.map((invite: TInvite) => formatDateFields(invite, ZInvite));
|
||||
};
|
||||
|
||||
export const updateInvite = async (inviteId: string, data: TInviteUpdateInput): Promise<TInvite | null> => {
|
||||
@@ -114,10 +119,8 @@ export const deleteInvite = async (inviteId: string): Promise<TInvite> => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getInvite = async (
|
||||
inviteId: string
|
||||
): Promise<TInvite & { creator: { name: string | null; email: string } }> =>
|
||||
unstable_cache(
|
||||
export const getInvite = async (inviteId: string): Promise<InviteWithCreator> => {
|
||||
const invite = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([inviteId, ZString]);
|
||||
|
||||
@@ -138,12 +141,16 @@ export const getInvite = async (
|
||||
if (!invite) {
|
||||
throw new ResourceNotFoundError("Invite", inviteId);
|
||||
}
|
||||
|
||||
return invite;
|
||||
},
|
||||
[`getInvite-${inviteId}`],
|
||||
{ tags: [inviteCache.tag.byId(inviteId)], revalidate: SERVICES_REVALIDATION_INTERVAL }
|
||||
)();
|
||||
return {
|
||||
...formatDateFields(invite, ZInvite),
|
||||
creator: invite.creator,
|
||||
};
|
||||
};
|
||||
|
||||
export const resendInvite = async (inviteId: string): Promise<TInvite> => {
|
||||
validateInputs([inviteId, ZString]);
|
||||
|
||||
@@ -4,13 +4,14 @@ import { prisma } from "@formbricks/database";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { TPerson, TPersonUpdateInput, ZPersonUpdateInput } from "@formbricks/types/people";
|
||||
import { TPerson, TPersonUpdateInput, ZPerson, ZPersonUpdateInput } from "@formbricks/types/people";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { personCache } from "./cache";
|
||||
import { createAttributeClass, getAttributeClassByName } from "../attributeClass/service";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const selectPerson = {
|
||||
id: true,
|
||||
@@ -90,11 +91,7 @@ export const getPerson = async (personId: string): Promise<TPerson | null> => {
|
||||
{ tags: [personCache.tag.byId(personId)], revalidate: SERVICES_REVALIDATION_INTERVAL }
|
||||
)();
|
||||
|
||||
if (!prismaPerson) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return transformPrismaPerson(prismaPerson);
|
||||
return prismaPerson ? formatDateFields(transformPrismaPerson(prismaPerson), ZPerson) : null;
|
||||
};
|
||||
|
||||
export const getPeople = async (environmentId: string, page?: number): Promise<TPerson[]> => {
|
||||
@@ -126,12 +123,8 @@ export const getPeople = async (environmentId: string, page?: number): Promise<T
|
||||
}
|
||||
)();
|
||||
|
||||
if (!peoplePrisma || peoplePrisma.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return peoplePrisma
|
||||
.map(transformPrismaPerson)
|
||||
.map((prismaPerson) => formatDateFields(transformPrismaPerson(prismaPerson), ZPerson))
|
||||
.filter((person: TPerson | null): person is TPerson => person !== null);
|
||||
};
|
||||
|
||||
@@ -309,8 +302,8 @@ export const updatePerson = async (personId: string, personInput: TPersonUpdateI
|
||||
}
|
||||
};
|
||||
|
||||
export const getPersonByUserId = async (environmentId: string, userId: string): Promise<TPerson | null> =>
|
||||
await unstable_cache(
|
||||
export const getPersonByUserId = async (environmentId: string, userId: string): Promise<TPerson | null> => {
|
||||
const person = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [userId, ZString]);
|
||||
|
||||
@@ -378,6 +371,8 @@ export const getPersonByUserId = async (environmentId: string, userId: string):
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return person ? formatDateFields(person, ZPerson) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated This function is deprecated and only used in legacy endpoints. Use updatePerson instead.
|
||||
|
||||
@@ -15,6 +15,7 @@ import { environmentCache } from "../environment/cache";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { deleteLocalFilesByEnvironmentId, deleteS3FilesByEnvironmentId } from "../storage/service";
|
||||
import { productCache } from "./cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
const selectProduct = {
|
||||
id: true,
|
||||
@@ -33,8 +34,8 @@ const selectProduct = {
|
||||
environments: true,
|
||||
};
|
||||
|
||||
export const getProducts = async (teamId: string, page?: number): Promise<TProduct[]> =>
|
||||
unstable_cache(
|
||||
export const getProducts = async (teamId: string, page?: number): Promise<TProduct[]> => {
|
||||
const products = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([teamId, ZId], [page, ZOptionalNumber]);
|
||||
|
||||
@@ -47,7 +48,6 @@ export const getProducts = async (teamId: string, page?: number): Promise<TProdu
|
||||
take: page ? ITEMS_PER_PAGE : undefined,
|
||||
skip: page ? ITEMS_PER_PAGE * (page - 1) : undefined,
|
||||
});
|
||||
|
||||
return products;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -63,9 +63,11 @@ export const getProducts = async (teamId: string, page?: number): Promise<TProdu
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return products.map((product) => formatDateFields(product, ZProduct));
|
||||
};
|
||||
|
||||
export const getProductByEnvironmentId = async (environmentId: string): Promise<TProduct | null> =>
|
||||
unstable_cache(
|
||||
export const getProductByEnvironmentId = async (environmentId: string): Promise<TProduct | null> => {
|
||||
const product = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
|
||||
@@ -83,10 +85,6 @@ export const getProductByEnvironmentId = async (environmentId: string): Promise<
|
||||
select: selectProduct,
|
||||
});
|
||||
|
||||
if (!productPrisma) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return productPrisma;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -102,6 +100,8 @@ export const getProductByEnvironmentId = async (environmentId: string): Promise<
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return product ? formatDateFields(product, ZProduct) : null;
|
||||
};
|
||||
|
||||
export const updateProduct = async (
|
||||
productId: string,
|
||||
@@ -154,8 +154,8 @@ export const updateProduct = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const getProduct = async (productId: string): Promise<TProduct | null> =>
|
||||
unstable_cache(
|
||||
export const getProduct = async (productId: string): Promise<TProduct | null> => {
|
||||
const product = await unstable_cache(
|
||||
async () => {
|
||||
let productPrisma;
|
||||
try {
|
||||
@@ -180,6 +180,8 @@ export const getProduct = async (productId: string): Promise<TProduct | null> =>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return product ? formatDateFields(product, ZProduct) : null;
|
||||
};
|
||||
|
||||
export const deleteProduct = async (productId: string): Promise<TProduct> => {
|
||||
const product = await prisma.product.delete({
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TProfile,
|
||||
TProfileCreateInput,
|
||||
TProfileUpdateInput,
|
||||
ZProfile,
|
||||
ZProfileUpdateInput,
|
||||
} from "@formbricks/types/profile";
|
||||
import { Prisma } from "@prisma/client";
|
||||
@@ -16,6 +17,7 @@ import { z } from "zod";
|
||||
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { updateMembership } from "../membership/service";
|
||||
import { deleteTeam } from "../team/service";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { profileCache } from "./cache";
|
||||
import { formatProfileDateFields } from "./util";
|
||||
@@ -51,7 +53,6 @@ export const getProfile = async (id: string): Promise<TProfile | null> => {
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return profile;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -68,14 +69,12 @@ export const getProfile = async (id: string): Promise<TProfile | null> => {
|
||||
}
|
||||
)();
|
||||
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...profile,
|
||||
...formatProfileDateFields(profile),
|
||||
} as TProfile;
|
||||
return profile
|
||||
? {
|
||||
...profile,
|
||||
...formatDateFields(profile, ZProfile),
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
export const getProfileByEmail = async (email: string): Promise<TProfile | null> => {
|
||||
@@ -91,10 +90,6 @@ export const getProfileByEmail = async (email: string): Promise<TProfile | null>
|
||||
select: responseSelection,
|
||||
});
|
||||
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return profile;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -111,14 +106,12 @@ export const getProfileByEmail = async (email: string): Promise<TProfile | null>
|
||||
}
|
||||
)();
|
||||
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...profile,
|
||||
...formatProfileDateFields(profile),
|
||||
} as TProfile;
|
||||
return profile
|
||||
? {
|
||||
...profile,
|
||||
...formatProfileDateFields(profile),
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
const getAdminMemberships = (memberships: TMembership[]): TMembership[] =>
|
||||
|
||||
@@ -10,8 +10,10 @@ import {
|
||||
TResponseInput,
|
||||
TResponseLegacyInput,
|
||||
TResponseUpdateInput,
|
||||
ZResponse,
|
||||
ZResponseInput,
|
||||
ZResponseLegacyInput,
|
||||
ZResponseNote,
|
||||
ZResponseUpdateInput,
|
||||
} from "@formbricks/types/responses";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
@@ -20,10 +22,11 @@ import { unstable_cache } from "next/cache";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { deleteDisplayByResponseId } from "../display/service";
|
||||
import { createPerson, getPerson, getPersonByUserId, transformPrismaPerson } from "../person/service";
|
||||
import { calculateTtcTotal, formatResponseDateFields } from "../response/util";
|
||||
import { calculateTtcTotal } from "../response/util";
|
||||
import { responseNoteCache } from "../responseNote/cache";
|
||||
import { getResponseNotes } from "../responseNote/service";
|
||||
import { captureTelemetry } from "../telemetry";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { responseCache } from "./cache";
|
||||
|
||||
@@ -137,8 +140,8 @@ export const getResponsesByPersonId = async (
|
||||
)();
|
||||
|
||||
return responses.map((response) => ({
|
||||
...response,
|
||||
...formatResponseDateFields(response),
|
||||
...formatDateFields(response, ZResponse),
|
||||
notes: response.notes.map((note) => formatDateFields(note, ZResponseNote)),
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -184,14 +187,12 @@ export const getResponseBySingleUseId = async (
|
||||
}
|
||||
)();
|
||||
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...response,
|
||||
...formatResponseDateFields(response),
|
||||
};
|
||||
return response
|
||||
? {
|
||||
...formatDateFields(response, ZResponse),
|
||||
notes: response.notes.map((note) => formatDateFields(note, ZResponseNote)),
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
export const createResponse = async (responseInput: TResponseInput): Promise<TResponse> => {
|
||||
@@ -369,13 +370,9 @@ export const getResponse = async (responseId: string): Promise<TResponse | null>
|
||||
}
|
||||
)();
|
||||
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...response,
|
||||
...formatResponseDateFields(response),
|
||||
...formatDateFields(response, ZResponse),
|
||||
notes: response.notes.map((note) => formatDateFields(note, ZResponseNote)),
|
||||
} as TResponse;
|
||||
};
|
||||
|
||||
@@ -426,8 +423,8 @@ export const getResponses = async (surveyId: string, page?: number): Promise<TRe
|
||||
)();
|
||||
|
||||
return responses.map((response) => ({
|
||||
...response,
|
||||
...formatResponseDateFields(response),
|
||||
...formatDateFields(response, ZResponse),
|
||||
notes: response.notes.map((note) => formatDateFields(note, ZResponseNote)),
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -483,8 +480,8 @@ export const getResponsesByEnvironmentId = async (
|
||||
)();
|
||||
|
||||
return responses.map((response) => ({
|
||||
...response,
|
||||
...formatResponseDateFields(response),
|
||||
...formatDateFields(response, ZResponse),
|
||||
notes: response.notes.map((note) => formatDateFields(note, ZResponseNote)),
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
|
||||
import { DatabaseError } from "@formbricks/types/errors";
|
||||
import { TResponseNote } from "@formbricks/types/responses";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { TResponseNote, ZResponseNote } from "@formbricks/types/responses";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { responseCache } from "../response/cache";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
@@ -12,6 +12,7 @@ import { ZString } from "@formbricks/types/common";
|
||||
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { responseNoteCache } from "./cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
const select = {
|
||||
id: true,
|
||||
@@ -60,7 +61,6 @@ export const createResponseNote = async (
|
||||
id: responseNote.id,
|
||||
responseId: responseNote.response.id,
|
||||
});
|
||||
|
||||
return responseNote;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -72,8 +72,8 @@ export const createResponseNote = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const getResponseNote = async (responseNoteId: string): Promise<TResponseNote | null> =>
|
||||
unstable_cache(
|
||||
export const getResponseNote = async (responseNoteId: string): Promise<TResponseNote | null> => {
|
||||
const responseNote = await unstable_cache(
|
||||
async () => {
|
||||
try {
|
||||
const responseNote = await prisma.responseNote.findUnique({
|
||||
@@ -95,9 +95,11 @@ export const getResponseNote = async (responseNoteId: string): Promise<TResponse
|
||||
[`getResponseNote-${responseNoteId}`],
|
||||
{ tags: [responseNoteCache.tag.byId(responseNoteId)], revalidate: SERVICES_REVALIDATION_INTERVAL }
|
||||
)();
|
||||
return responseNote ? formatDateFields(responseNote, ZResponseNote) : null;
|
||||
};
|
||||
|
||||
export const getResponseNotes = async (responseId: string): Promise<TResponseNote[]> =>
|
||||
unstable_cache(
|
||||
export const getResponseNotes = async (responseId: string): Promise<TResponseNote[]> => {
|
||||
const responseNotes = await unstable_cache(
|
||||
async () => {
|
||||
try {
|
||||
validateInputs([responseId, ZId]);
|
||||
@@ -108,6 +110,9 @@ export const getResponseNotes = async (responseId: string): Promise<TResponseNot
|
||||
},
|
||||
select,
|
||||
});
|
||||
if (!responseNotes) {
|
||||
throw new ResourceNotFoundError("Response Notes by ResponseId", responseId);
|
||||
}
|
||||
return responseNotes;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -121,6 +126,8 @@ export const getResponseNotes = async (responseId: string): Promise<TResponseNot
|
||||
[`getResponseNotes-${responseId}`],
|
||||
{ tags: [responseNoteCache.tag.byResponseId(responseId)], revalidate: SERVICES_REVALIDATION_INTERVAL }
|
||||
)();
|
||||
return responseNotes.map((responseNote) => formatDateFields(responseNote, ZResponseNote));
|
||||
};
|
||||
|
||||
export const updateResponseNote = async (responseNoteId: string, text: string): Promise<TResponseNote> => {
|
||||
validateInputs([responseNoteId, ZString], [text, ZString]);
|
||||
|
||||
@@ -19,10 +19,9 @@ import { productCache } from "../product/cache";
|
||||
import { getProductByEnvironmentId } from "../product/service";
|
||||
import { responseCache } from "../response/cache";
|
||||
import { captureTelemetry } from "../telemetry";
|
||||
import { diffInDays } from "../utils/datetime";
|
||||
import { diffInDays, formatDateFields } from "../utils/datetime";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { surveyCache } from "./cache";
|
||||
import { formatSurveyDateFields } from "./util";
|
||||
|
||||
export const selectSurvey = {
|
||||
id: true,
|
||||
@@ -126,7 +125,6 @@ export const getSurvey = async (surveyId: string): Promise<TSurvey | null> => {
|
||||
...surveyPrisma,
|
||||
triggers: surveyPrisma.triggers.map((trigger) => trigger.actionClass.name),
|
||||
};
|
||||
|
||||
return transformedSurvey;
|
||||
},
|
||||
[`getSurvey-${surveyId}`],
|
||||
@@ -136,16 +134,9 @@ export const getSurvey = async (surveyId: string): Promise<TSurvey | null> => {
|
||||
}
|
||||
)();
|
||||
|
||||
if (!survey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
|
||||
// https://github.com/vercel/next.js/issues/51613
|
||||
return {
|
||||
...survey,
|
||||
...formatSurveyDateFields(survey),
|
||||
};
|
||||
return survey ? formatDateFields(survey, ZSurvey) : null;
|
||||
};
|
||||
|
||||
export const getSurveysByAttributeClassId = async (
|
||||
@@ -187,11 +178,7 @@ export const getSurveysByAttributeClassId = async (
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return surveys.map((survey) => ({
|
||||
...survey,
|
||||
...formatSurveyDateFields(survey),
|
||||
}));
|
||||
return surveys.map((survey) => formatDateFields(survey, ZSurvey));
|
||||
};
|
||||
|
||||
export const getSurveysByActionClassId = async (actionClassId: string, page?: number): Promise<TSurvey[]> => {
|
||||
@@ -232,11 +219,7 @@ export const getSurveysByActionClassId = async (actionClassId: string, page?: nu
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
|
||||
return surveys.map((survey) => ({
|
||||
...survey,
|
||||
...formatSurveyDateFields(survey),
|
||||
}));
|
||||
return surveys.map((survey) => formatDateFields(survey, ZSurvey));
|
||||
};
|
||||
|
||||
export const getSurveys = async (environmentId: string, page?: number): Promise<TSurvey[]> => {
|
||||
@@ -282,10 +265,7 @@ export const getSurveys = async (environmentId: string, page?: number): Promise<
|
||||
|
||||
// since the unstable_cache function does not support deserialization of dates, we need to manually deserialize them
|
||||
// https://github.com/vercel/next.js/issues/51613
|
||||
return surveys.map((survey) => ({
|
||||
...survey,
|
||||
...formatSurveyDateFields(survey),
|
||||
}));
|
||||
return surveys.map((survey) => formatDateFields(survey, ZSurvey));
|
||||
};
|
||||
|
||||
export const updateSurvey = async (updatedSurvey: TSurvey): Promise<TSurvey> => {
|
||||
@@ -609,10 +589,10 @@ export const duplicateSurvey = async (environmentId: string, surveyId: string) =
|
||||
return newSurvey;
|
||||
};
|
||||
|
||||
export const getSyncSurveys = (environmentId: string, person: TPerson): Promise<TSurvey[]> => {
|
||||
export const getSyncSurveys = async (environmentId: string, person: TPerson): Promise<TSurvey[]> => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
|
||||
return unstable_cache(
|
||||
const surveys = await unstable_cache(
|
||||
async () => {
|
||||
const product = await getProductByEnvironmentId(environmentId);
|
||||
|
||||
@@ -689,6 +669,9 @@ export const getSyncSurveys = (environmentId: string, person: TPerson): Promise<
|
||||
}
|
||||
});
|
||||
|
||||
if (!surveys) {
|
||||
throw new ResourceNotFoundError("Survey", environmentId);
|
||||
}
|
||||
return surveys;
|
||||
},
|
||||
[`getSyncSurveys-${environmentId}-${person.userId}`],
|
||||
@@ -702,4 +685,5 @@ export const getSyncSurveys = (environmentId: string, person: TPerson): Promise<
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return surveys.map((survey) => formatDateFields(survey, ZSurvey));
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import { prisma } from "@formbricks/database";
|
||||
import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
||||
import { ZId } from "@formbricks/types/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/errors";
|
||||
import { TTeam, TTeamBilling, TTeamUpdateInput, ZTeamUpdateInput } from "@formbricks/types/teams";
|
||||
import { TTeam, TTeamBilling, TTeamUpdateInput, ZTeam, ZTeamUpdateInput } from "@formbricks/types/teams";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
@@ -12,6 +12,7 @@ import { environmentCache } from "../environment/cache";
|
||||
import { getProducts } from "../product/service";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { teamCache } from "./cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const select = {
|
||||
id: true,
|
||||
@@ -25,8 +26,8 @@ export const getTeamsTag = (teamId: string) => `teams-${teamId}`;
|
||||
export const getTeamsByUserIdCacheTag = (userId: string) => `users-${userId}-teams`;
|
||||
export const getTeamByEnvironmentIdCacheTag = (environmentId: string) => `environments-${environmentId}-team`;
|
||||
|
||||
export const getTeamsByUserId = async (userId: string, page?: number): Promise<TTeam[]> =>
|
||||
unstable_cache(
|
||||
export const getTeamsByUserId = async (userId: string, page?: number): Promise<TTeam[]> => {
|
||||
const teams = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([userId, ZString], [page, ZOptionalNumber]);
|
||||
|
||||
@@ -43,7 +44,9 @@ export const getTeamsByUserId = async (userId: string, page?: number): Promise<T
|
||||
take: page ? ITEMS_PER_PAGE : undefined,
|
||||
skip: page ? ITEMS_PER_PAGE * (page - 1) : undefined,
|
||||
});
|
||||
|
||||
if (!teams) {
|
||||
throw new ResourceNotFoundError("Teams by UserId", userId);
|
||||
}
|
||||
return teams;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -59,9 +62,11 @@ export const getTeamsByUserId = async (userId: string, page?: number): Promise<T
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return teams.map((team) => formatDateFields(team, ZTeam));
|
||||
};
|
||||
|
||||
export const getTeamByEnvironmentId = async (environmentId: string): Promise<TTeam | null> =>
|
||||
unstable_cache(
|
||||
export const getTeamByEnvironmentId = async (environmentId: string): Promise<TTeam | null> => {
|
||||
const team = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
|
||||
@@ -97,9 +102,11 @@ export const getTeamByEnvironmentId = async (environmentId: string): Promise<TTe
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return team ? formatDateFields(team, ZTeam) : null;
|
||||
};
|
||||
|
||||
export const getTeam = async (teamId: string): Promise<TTeam | null> =>
|
||||
unstable_cache(
|
||||
export const getTeam = async (teamId: string): Promise<TTeam | null> => {
|
||||
const team = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([teamId, ZString]);
|
||||
|
||||
@@ -110,7 +117,6 @@ export const getTeam = async (teamId: string): Promise<TTeam | null> =>
|
||||
},
|
||||
select,
|
||||
});
|
||||
|
||||
return team;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
@@ -126,6 +132,8 @@ export const getTeam = async (teamId: string): Promise<TTeam | null> =>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return team ? formatDateFields(team, ZTeam) : null;
|
||||
};
|
||||
|
||||
export const createTeam = async (teamInput: TTeamUpdateInput): Promise<TTeam> => {
|
||||
try {
|
||||
@@ -281,7 +289,7 @@ export const getTeamsWithPaidPlan = async (): Promise<TTeam[]> => {
|
||||
}
|
||||
)();
|
||||
|
||||
return teams;
|
||||
return teams.map((team) => formatDateFields(team, ZTeam));
|
||||
};
|
||||
|
||||
export const getMonthlyActiveTeamPeopleCount = async (teamId: string): Promise<number> =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// utility functions for date and time
|
||||
import z from "zod";
|
||||
|
||||
// Helper function to calculate difference in days between two dates
|
||||
export const diffInDays = (date1: Date, date2: Date) => {
|
||||
@@ -6,6 +6,42 @@ export const diffInDays = (date1: Date, date2: Date) => {
|
||||
return Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||
};
|
||||
|
||||
function isZodDate(schema: z.ZodTypeAny): boolean {
|
||||
// Check if the field is a ZodDate
|
||||
if (schema instanceof z.ZodDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the field is a nullable type and the inner type is ZodDate
|
||||
if (schema instanceof z.ZodNullable && schema._def.innerType instanceof z.ZodDate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function formatDateFields<T extends z.ZodRawShape>(
|
||||
object: z.infer<z.ZodObject<T>>,
|
||||
zodSchema: z.ZodObject<T>
|
||||
): z.infer<typeof zodSchema> {
|
||||
const schemaFields = zodSchema.shape;
|
||||
const formattedObject = { ...object };
|
||||
|
||||
for (const key in schemaFields) {
|
||||
if (Object.prototype.hasOwnProperty.call(schemaFields, key) && isZodDate(schemaFields[key])) {
|
||||
const dateStr = (formattedObject as any)[key];
|
||||
try {
|
||||
if (typeof dateStr === "string") {
|
||||
(formattedObject as any)[key] = new Date(dateStr);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error parsing date for key ${key}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formattedObject as z.infer<typeof zodSchema>;
|
||||
}
|
||||
export const formatDateWithOrdinal = (date: Date): string => {
|
||||
const getOrdinalSuffix = (day: number) => {
|
||||
const suffixes = ["th", "st", "nd", "rd"];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "server-only";
|
||||
|
||||
import { TWebhook, TWebhookInput, ZWebhookInput } from "@formbricks/types/webhooks";
|
||||
import { TWebhook, TWebhookInput, ZWebhook, ZWebhookInput } from "@formbricks/types/webhooks";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
@@ -10,9 +10,10 @@ import { ZOptionalNumber } from "@formbricks/types/common";
|
||||
import { ITEMS_PER_PAGE, SERVICES_REVALIDATION_INTERVAL } from "../constants";
|
||||
import { webhookCache } from "./cache";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { formatDateFields } from "../utils/datetime";
|
||||
|
||||
export const getWebhooks = async (environmentId: string, page?: number): Promise<TWebhook[]> =>
|
||||
unstable_cache(
|
||||
export const getWebhooks = async (environmentId: string, page?: number): Promise<TWebhook[]> => {
|
||||
const webhooks = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([environmentId, ZId], [page, ZOptionalNumber]);
|
||||
|
||||
@@ -35,6 +36,8 @@ export const getWebhooks = async (environmentId: string, page?: number): Promise
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return webhooks.map((webhook) => formatDateFields(webhook, ZWebhook));
|
||||
};
|
||||
|
||||
export const getWebhookCountBySource = async (
|
||||
environmentId: string,
|
||||
@@ -63,8 +66,8 @@ export const getWebhookCountBySource = async (
|
||||
}
|
||||
)();
|
||||
|
||||
export const getWebhook = async (id: string): Promise<TWebhook | null> =>
|
||||
unstable_cache(
|
||||
export const getWebhook = async (id: string): Promise<TWebhook | null> => {
|
||||
const webhook = await unstable_cache(
|
||||
async () => {
|
||||
validateInputs([id, ZId]);
|
||||
|
||||
@@ -81,6 +84,8 @@ export const getWebhook = async (id: string): Promise<TWebhook | null> =>
|
||||
revalidate: SERVICES_REVALIDATION_INTERVAL,
|
||||
}
|
||||
)();
|
||||
return webhook ? formatDateFields(webhook, ZWebhook) : null;
|
||||
};
|
||||
|
||||
export const createWebhook = async (
|
||||
environmentId: string,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import z from "zod";
|
||||
import { ZMembershipRole } from "./memberships";
|
||||
|
||||
const ZInvite = z.object({
|
||||
export const ZInvite = z.object({
|
||||
id: z.string(),
|
||||
email: z.string(),
|
||||
name: z.string().nullish(),
|
||||
|
||||
@@ -22,7 +22,7 @@ export const ZResponseNoteUser = z.object({
|
||||
|
||||
export type TResponseNoteUser = z.infer<typeof ZResponseNoteUser>;
|
||||
|
||||
const ZResponseNote = z.object({
|
||||
export const ZResponseNote = z.object({
|
||||
updatedAt: z.date(),
|
||||
createdAt: z.date(),
|
||||
id: z.string(),
|
||||
|
||||
Reference in New Issue
Block a user