Files
formbricks-formbricks/packages/js/src/lib/initialize.ts
Anshuman Pandey 1fa12d473c feat: attributes on initialising formbricks (#1736)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2023-12-06 12:39:46 +00:00

174 lines
4.5 KiB
TypeScript

import type { TJsConfig, TJsConfigInput } from "@formbricks/types/js";
import { Config } from "./config";
import {
ErrorHandler,
MissingFieldError,
MissingPersonError,
NetworkError,
NotInitializedError,
Result,
err,
okVoid,
} from "./errors";
import { addCleanupEventListeners, addEventListeners, removeAllEventListeners } from "./eventListeners";
import { Logger } from "./logger";
import { checkPageUrl } from "./noCodeActions";
import { sync } from "./sync";
import { addWidgetContainer, closeSurvey } from "./widget";
import { trackAction } from "./actions";
import { updatePersonAttributes } from "./person";
import { TPersonAttributes } from "@formbricks/types/people";
const config = Config.getInstance();
const logger = Logger.getInstance();
let isInitialized = false;
const setDebugLevel = (c: TJsConfigInput): void => {
if (c.debug) {
logger.debug(`Setting log level to debug`);
logger.configure({ logLevel: "debug" });
}
};
export const initialize = async (
c: TJsConfigInput
): Promise<Result<void, MissingFieldError | NetworkError | MissingPersonError>> => {
if (isInitialized) {
logger.debug("Already initialized, skipping initialization.");
return okVoid();
}
setDebugLevel(c);
ErrorHandler.getInstance().printStatus();
logger.debug("Start initialize");
if (!c.environmentId) {
logger.debug("No environmentId provided");
return err({
code: "missing_field",
field: "environmentId",
});
}
if (!c.apiHost) {
logger.debug("No apiHost provided");
return err({
code: "missing_field",
field: "apiHost",
});
}
logger.debug("Adding widget container to DOM");
addWidgetContainer();
if (!c.userId && c.attributes) {
logger.error("No userId provided but attributes. Cannot update attributes without userId.");
return err({
code: "missing_field",
field: "userId",
});
}
// if userId and attributes are available, set them in backend
let updatedAttributes: TPersonAttributes | null = null;
if (c.userId && c.attributes) {
const res = await updatePersonAttributes(c.apiHost, c.environmentId, c.userId, c.attributes);
if (res.ok !== true) {
return err(res.error);
}
updatedAttributes = res.value;
}
let existingConfig: TJsConfig | undefined;
try {
existingConfig = config.get();
} catch (e) {
logger.debug("No existing configuration found.");
}
if (
existingConfig &&
existingConfig.state &&
existingConfig.environmentId === c.environmentId &&
existingConfig.apiHost === c.apiHost &&
existingConfig.userId === c.userId &&
existingConfig.expiresAt // only accept config when they follow new config version with expiresAt
) {
logger.debug("Found existing configuration.");
if (existingConfig.expiresAt < new Date()) {
logger.debug("Configuration expired.");
await sync({
apiHost: c.apiHost,
environmentId: c.environmentId,
userId: c.userId,
});
} else {
logger.debug("Configuration not expired. Extending expiration.");
config.update(existingConfig);
}
} else {
logger.debug("No valid configuration found or it has been expired. Creating new config.");
logger.debug("Syncing.");
await sync({
apiHost: c.apiHost,
environmentId: c.environmentId,
userId: c.userId,
});
// and track the new session event
await trackAction("New Session");
}
// update attributes in config
if (updatedAttributes && Object.keys(updatedAttributes).length > 0) {
config.update({
environmentId: config.get().environmentId,
apiHost: config.get().apiHost,
userId: config.get().userId,
state: {
...config.get().state,
attributes: { ...config.get().state.attributes, ...c.attributes },
},
});
}
logger.debug("Adding event listeners");
addEventListeners();
addCleanupEventListeners();
isInitialized = true;
logger.debug("Initialized");
// check page url if initialized after page load
checkPageUrl();
return okVoid();
};
export const checkInitialized = (): Result<void, NotInitializedError> => {
logger.debug("Check if initialized");
if (!isInitialized || !ErrorHandler.initialized) {
return err({
code: "not_initialized",
message: "Formbricks not initialized. Call initialize() first.",
});
}
return okVoid();
};
export const deinitalize = (): void => {
logger.debug("Deinitializing");
closeSurvey();
removeAllEventListeners();
config.resetConfig();
isInitialized = false;
};