diff --git a/apps/web/app/api/v1/client/[environmentId]/identify/people/[userId]/lib/personState.ts b/apps/web/app/api/v1/client/[environmentId]/identify/people/[userId]/lib/personState.ts index 9ced049337..52c1aa8aa2 100644 --- a/apps/web/app/api/v1/client/[environmentId]/identify/people/[userId]/lib/personState.ts +++ b/apps/web/app/api/v1/client/[environmentId]/identify/people/[userId]/lib/personState.ts @@ -1,6 +1,5 @@ import { prisma } from "@formbricks/database"; import { attributeCache } from "@formbricks/lib/attribute/cache"; -import { getAttributesByUserId } from "@formbricks/lib/attribute/service"; import { cache } from "@formbricks/lib/cache"; import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants"; import { displayCache } from "@formbricks/lib/display/cache"; @@ -71,7 +70,6 @@ export const getPersonState = async ({ const personResponses = await getResponsesByUserId(environmentId, userId); const personDisplays = await getDisplaysByUserId(environmentId, userId); const segments = await getPersonSegmentIds(environmentId, person, device); - const attributes = await getAttributesByUserId(environmentId, userId); // If the person exists, return the persons's state const userState: TJsPersonState["data"] = { @@ -81,7 +79,6 @@ export const getPersonState = async ({ personDisplays?.map((display) => ({ surveyId: display.surveyId, createdAt: display.createdAt })) ?? [], responses: personResponses?.map((response) => response.surveyId) ?? [], - attributes, lastDisplayAt: personDisplays.length > 0 ? personDisplays.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())[0].createdAt diff --git a/packages/js-core/src/lib/attributes.ts b/packages/js-core/src/lib/attributes.ts index aef097b806..f13caffb5c 100644 --- a/packages/js-core/src/lib/attributes.ts +++ b/packages/js-core/src/lib/attributes.ts @@ -55,8 +55,7 @@ export const updateAttribute = async ( } return err({ code: "network_error", - // @ts-expect-error - status: res.error.status ?? 500, + status: 500, message: res.error.message ?? `Error updating person with userId ${userId}`, url: `${config.get().apiHost}/api/v1/client/${environmentId}/people/${userId}/attributes`, responseMessage: res.error.message, @@ -92,19 +91,6 @@ export const updateAttributes = async ( // clean attributes and remove existing attributes if config already exists const updatedAttributes = { ...attributes }; - try { - const existingAttributes = config.get().personState.data.attributes; - if (existingAttributes) { - for (const [key, value] of Object.entries(existingAttributes)) { - if (updatedAttributes[key] === value) { - delete updatedAttributes[key]; - } - } - } - } catch (e) { - logger.debug("config not set; sending all attributes to backend"); - } - // send to backend if updatedAttributes is not empty if (Object.keys(updatedAttributes).length === 0) { logger.debug("No attributes to update. Skipping update."); @@ -139,14 +125,6 @@ export const updateAttributes = async ( } }; -export const isExistingAttribute = (key: string, value: string): boolean => { - if (config.get().personState.data.attributes[key] === value) { - return true; - } - - return false; -}; - export const setAttributeInApp = async ( key: string, value: any @@ -159,11 +137,6 @@ export const setAttributeInApp = async ( const userId = config.get().personState.data.userId; logger.debug("Setting attribute: " + key + " to value: " + value); - // check if attribute already exists with this value - if (isExistingAttribute(key, value.toString())) { - logger.debug("Attribute already set to this value. Skipping update."); - return okVoid(); - } if (!userId) { logger.error( @@ -191,6 +164,10 @@ export const setAttributeInApp = async ( ...config.get(), personState, filteredSurveys, + attributes: { + ...config.get().attributes, + [key]: value.toString(), + }, }); } diff --git a/packages/js-core/src/lib/initialize.ts b/packages/js-core/src/lib/initialize.ts index 61a41de96c..bac0a1416d 100644 --- a/packages/js-core/src/lib/initialize.ts +++ b/packages/js-core/src/lib/initialize.ts @@ -162,24 +162,6 @@ export const initialize = async ( logger.debug("Adding widget container to DOM"); addWidgetContainer(); - let updatedAttributes: TAttributes | null = null; - if (configInput.attributes) { - if (configInput.userId) { - const res = await updateAttributes( - configInput.apiHost, - configInput.environmentId, - configInput.userId, - configInput.attributes - ); - if (res.ok !== true) { - return err(res.error); - } - updatedAttributes = res.value; - } else { - updatedAttributes = { ...configInput.attributes }; - } - } - if ( existingConfig && existingConfig.environmentState && @@ -195,13 +177,12 @@ export const initialize = async ( isEnvironmentStateExpired = true; } - // if the config has a userId and the person state has expired, we need to sync the person state if ( configInput.userId && - existingConfig.personState.expiresAt && - new Date(existingConfig.personState.expiresAt) < new Date() + (existingConfig.personState === null || + (existingConfig.personState.expiresAt && new Date(existingConfig.personState.expiresAt) < new Date())) ) { - logger.debug("Person state expired. Syncing."); + logger.debug("Person state needs syncing - either null or expired"); isPersonStateExpired = true; } @@ -239,6 +220,7 @@ export const initialize = async ( environmentState, personState, filteredSurveys, + attributes: configInput.attributes ?? {}, }); const surveyNames = filteredSurveys.map((s) => s.name); @@ -247,12 +229,30 @@ export const initialize = async ( putFormbricksInErrorState(config); } } else { - logger.debug( - "No valid configuration found or it has been expired. Resetting config and creating new one." - ); + logger.debug("No valid configuration found. Resetting config and creating new one."); config.resetConfig(); logger.debug("Syncing."); + let updatedAttributes: TAttributes | null = null; + if (configInput.attributes) { + if (configInput.userId) { + const res = await updateAttributes( + configInput.apiHost, + configInput.environmentId, + configInput.userId, + configInput.attributes + ); + + if (res.ok !== true) { + return err(res.error); + } + + updatedAttributes = res.value; + } else { + updatedAttributes = { ...configInput.attributes }; + } + } + try { const environmentState = await fetchEnvironmentState( { @@ -280,6 +280,7 @@ export const initialize = async ( personState, environmentState, filteredSurveys, + attributes: updatedAttributes ?? {}, }); } catch (e) { handleErrorOnFirstInit(); @@ -289,23 +290,6 @@ export const initialize = async ( await trackNoCodeAction("New Session"); } - // update attributes in config - if (updatedAttributes && Object.keys(updatedAttributes).length > 0) { - config.update({ - ...config.get(), - personState: { - ...config.get().personState, - data: { - ...config.get().personState.data, - attributes: { - ...config.get().personState.data.attributes, - ...updatedAttributes, - }, - }, - }, - }); - } - logger.debug("Adding event listeners"); addEventListeners(); addCleanupEventListeners(); diff --git a/packages/js-core/src/lib/person.ts b/packages/js-core/src/lib/person.ts index b94905e25f..3be233ae60 100644 --- a/packages/js-core/src/lib/person.ts +++ b/packages/js-core/src/lib/person.ts @@ -22,7 +22,7 @@ export const resetPerson = async (): Promise> => { environmentId: config.get().environmentId, apiHost: config.get().apiHost, ...(userId && { userId }), - attributes: config.get().personState.data.attributes, + attributes: config.get().attributes, }; await logoutPerson(); try { diff --git a/packages/js-core/src/lib/personState.ts b/packages/js-core/src/lib/personState.ts index ddfc4abe68..f3982e4e5c 100644 --- a/packages/js-core/src/lib/personState.ts +++ b/packages/js-core/src/lib/personState.ts @@ -15,7 +15,6 @@ export const DEFAULT_PERSON_STATE_NO_USER_ID: TJsPersonState = { segments: [], displays: [], responses: [], - attributes: {}, lastDisplayAt: null, }, } as const; @@ -68,7 +67,6 @@ export const fetchPersonState = async ( segments: [], displays: [], responses: [], - attributes: {}, lastDisplayAt: null, }, }; diff --git a/packages/js-core/src/lib/widget.ts b/packages/js-core/src/lib/widget.ts index 6955a0d19d..f541c8d405 100644 --- a/packages/js-core/src/lib/widget.ts +++ b/packages/js-core/src/lib/widget.ts @@ -65,7 +65,7 @@ const renderWidget = async ( } const { product } = config.get().environmentState.data ?? {}; - const { attributes } = config.get().personState.data ?? {}; + const { attributes } = config.get() ?? {}; const isMultiLanguageSurvey = survey.languages.length > 1; let languageCode = "default"; diff --git a/packages/types/js.ts b/packages/types/js.ts index 4177e8fd39..5c0194a24e 100644 --- a/packages/types/js.ts +++ b/packages/types/js.ts @@ -126,7 +126,6 @@ export const ZJsPersonState = z.object({ }) ), responses: z.array(ZId), // responded survey ids - attributes: ZAttributes, lastDisplayAt: z.date().nullable(), }), }); @@ -146,6 +145,7 @@ export const ZJsConfig = z.object({ environmentState: ZJsEnvironmentState, personState: ZJsPersonState, filteredSurveys: z.array(ZSurvey).default([]), + attributes: z.record(z.string()), status: z.object({ value: z.enum(["success", "error"]), expiresAt: z.date().nullable(),