mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-08 02:43:06 -05:00
chore: replacing intercom with chatwoot (#6980)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
This commit is contained in:
+3
-2
@@ -189,8 +189,9 @@ REDIS_URL=redis://localhost:6379
|
|||||||
# The below is used for Rate Limiting (uses In-Memory LRU Cache if not provided) (You can use a service like Webdis for this)
|
# The below is used for Rate Limiting (uses In-Memory LRU Cache if not provided) (You can use a service like Webdis for this)
|
||||||
# REDIS_HTTP_URL:
|
# REDIS_HTTP_URL:
|
||||||
|
|
||||||
# INTERCOM_APP_ID=
|
# Chatwoot
|
||||||
# INTERCOM_SECRET_KEY=
|
# CHATWOOT_BASE_URL=
|
||||||
|
# CHATWOOT_WEBSITE_TOKEN=
|
||||||
|
|
||||||
# Enable Prometheus metrics
|
# Enable Prometheus metrics
|
||||||
# PROMETHEUS_ENABLED=
|
# PROMETHEUS_ENABLED=
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { IntercomClientWrapper } from "@/app/intercom/IntercomClientWrapper";
|
import { ChatwootWidget } from "@/app/chatwoot/ChatwootWidget";
|
||||||
|
import { CHATWOOT_BASE_URL, CHATWOOT_WEBSITE_TOKEN, IS_CHATWOOT_CONFIGURED } from "@/lib/constants";
|
||||||
import { getUser } from "@/lib/user/service";
|
import { getUser } from "@/lib/user/service";
|
||||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||||
import { ClientLogout } from "@/modules/ui/components/client-logout";
|
import { ClientLogout } from "@/modules/ui/components/client-logout";
|
||||||
@@ -18,7 +19,15 @@ const AppLayout = async ({ children }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NoMobileOverlay />
|
<NoMobileOverlay />
|
||||||
<IntercomClientWrapper user={user} />
|
{IS_CHATWOOT_CONFIGURED && (
|
||||||
|
<ChatwootWidget
|
||||||
|
userEmail={user?.email}
|
||||||
|
userName={user?.name}
|
||||||
|
userId={user?.id}
|
||||||
|
chatwootWebsiteToken={CHATWOOT_WEBSITE_TOKEN}
|
||||||
|
chatwootBaseUrl={CHATWOOT_BASE_URL}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<ToasterClient />
|
<ToasterClient />
|
||||||
{children}
|
{children}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { IntercomClientWrapper } from "@/app/intercom/IntercomClientWrapper";
|
|
||||||
import { NoMobileOverlay } from "@/modules/ui/components/no-mobile-overlay";
|
import { NoMobileOverlay } from "@/modules/ui/components/no-mobile-overlay";
|
||||||
|
|
||||||
const AppLayout = async ({ children }) => {
|
const AppLayout = async ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NoMobileOverlay />
|
<NoMobileOverlay />
|
||||||
<IntercomClientWrapper />
|
|
||||||
{children}
|
{children}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
interface ChatwootWidgetProps {
|
||||||
|
chatwootBaseUrl: string;
|
||||||
|
chatwootWebsiteToken?: string;
|
||||||
|
userEmail?: string | null;
|
||||||
|
userName?: string | null;
|
||||||
|
userId?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHATWOOT_SCRIPT_ID = "chatwoot-script";
|
||||||
|
|
||||||
|
export const ChatwootWidget = ({
|
||||||
|
userEmail,
|
||||||
|
userName,
|
||||||
|
userId,
|
||||||
|
chatwootWebsiteToken,
|
||||||
|
chatwootBaseUrl,
|
||||||
|
}: ChatwootWidgetProps) => {
|
||||||
|
const userSetRef = useRef(false);
|
||||||
|
|
||||||
|
const setUserInfo = useCallback(() => {
|
||||||
|
const $chatwoot = (
|
||||||
|
globalThis as unknown as {
|
||||||
|
$chatwoot: {
|
||||||
|
setUser: (userId: string, userInfo: { email?: string | null; name?: string | null }) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
).$chatwoot;
|
||||||
|
if (userId && $chatwoot && !userSetRef.current) {
|
||||||
|
$chatwoot.setUser(userId, {
|
||||||
|
email: userEmail,
|
||||||
|
name: userName,
|
||||||
|
});
|
||||||
|
userSetRef.current = true;
|
||||||
|
}
|
||||||
|
}, [userId, userEmail, userName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chatwootWebsiteToken) return;
|
||||||
|
|
||||||
|
const existingScript = document.getElementById(CHATWOOT_SCRIPT_ID);
|
||||||
|
if (existingScript) return;
|
||||||
|
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = `${chatwootBaseUrl}/packs/js/sdk.js`;
|
||||||
|
script.id = CHATWOOT_SCRIPT_ID;
|
||||||
|
script.async = true;
|
||||||
|
|
||||||
|
script.onload = () => {
|
||||||
|
(
|
||||||
|
globalThis as unknown as {
|
||||||
|
chatwootSDK: { run: (options: { websiteToken: string; baseUrl: string }) => void };
|
||||||
|
}
|
||||||
|
).chatwootSDK?.run({
|
||||||
|
websiteToken: chatwootWebsiteToken,
|
||||||
|
baseUrl: chatwootBaseUrl,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
const handleChatwootReady = () => setUserInfo();
|
||||||
|
globalThis.addEventListener("chatwoot:ready", handleChatwootReady);
|
||||||
|
|
||||||
|
// Check if Chatwoot is already ready
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
globalThis as unknown as {
|
||||||
|
$chatwoot: {
|
||||||
|
setUser: (userId: string, userInfo: { email?: string | null; name?: string | null }) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
).$chatwoot
|
||||||
|
) {
|
||||||
|
setUserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
globalThis.removeEventListener("chatwoot:ready", handleChatwootReady);
|
||||||
|
|
||||||
|
const $chatwoot = (globalThis as unknown as { $chatwoot: { reset: () => void } }).$chatwoot;
|
||||||
|
if ($chatwoot) {
|
||||||
|
$chatwoot.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
const scriptElement = document.getElementById(CHATWOOT_SCRIPT_ID);
|
||||||
|
scriptElement?.remove();
|
||||||
|
|
||||||
|
userSetRef.current = false;
|
||||||
|
};
|
||||||
|
}, [chatwootBaseUrl, chatwootWebsiteToken, userId, userEmail, userName, setUserInfo]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Intercom from "@intercom/messenger-js-sdk";
|
|
||||||
import { useCallback, useEffect } from "react";
|
|
||||||
import { TUser } from "@formbricks/types/user";
|
|
||||||
|
|
||||||
interface IntercomClientProps {
|
|
||||||
isIntercomConfigured: boolean;
|
|
||||||
intercomUserHash?: string;
|
|
||||||
user?: TUser | null;
|
|
||||||
intercomAppId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IntercomClient = ({
|
|
||||||
user,
|
|
||||||
intercomUserHash,
|
|
||||||
isIntercomConfigured,
|
|
||||||
intercomAppId,
|
|
||||||
}: IntercomClientProps) => {
|
|
||||||
const initializeIntercom = useCallback(() => {
|
|
||||||
let initParams = {};
|
|
||||||
|
|
||||||
if (user && intercomUserHash) {
|
|
||||||
const { id, name, email, createdAt } = user;
|
|
||||||
|
|
||||||
initParams = {
|
|
||||||
user_id: id,
|
|
||||||
user_hash: intercomUserHash,
|
|
||||||
name,
|
|
||||||
email,
|
|
||||||
created_at: createdAt ? Math.floor(createdAt.getTime() / 1000) : undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Intercom({
|
|
||||||
app_id: intercomAppId!,
|
|
||||||
...initParams,
|
|
||||||
});
|
|
||||||
}, [user, intercomUserHash, intercomAppId]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
try {
|
|
||||||
if (isIntercomConfigured) {
|
|
||||||
if (!intercomAppId) {
|
|
||||||
throw new Error("Intercom app ID is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user && !intercomUserHash) {
|
|
||||||
throw new Error("Intercom user hash is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeIntercom();
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// Shutdown Intercom when component unmounts
|
|
||||||
if (typeof window !== "undefined" && window.Intercom) {
|
|
||||||
window.Intercom("shutdown");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to initialize Intercom:", error);
|
|
||||||
}
|
|
||||||
}, [isIntercomConfigured, initializeIntercom, intercomAppId, intercomUserHash, user]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { createHmac } from "crypto";
|
|
||||||
import type { TUser } from "@formbricks/types/user";
|
|
||||||
import { INTERCOM_APP_ID, INTERCOM_SECRET_KEY, IS_INTERCOM_CONFIGURED } from "@/lib/constants";
|
|
||||||
import { IntercomClient } from "./IntercomClient";
|
|
||||||
|
|
||||||
interface IntercomClientWrapperProps {
|
|
||||||
user?: TUser | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IntercomClientWrapper = ({ user }: IntercomClientWrapperProps) => {
|
|
||||||
let intercomUserHash: string | undefined;
|
|
||||||
if (user) {
|
|
||||||
const secretKey = INTERCOM_SECRET_KEY;
|
|
||||||
if (secretKey) {
|
|
||||||
intercomUserHash = createHmac("sha256", secretKey).update(user.id).digest("hex");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<IntercomClient
|
|
||||||
isIntercomConfigured={IS_INTERCOM_CONFIGURED}
|
|
||||||
user={user}
|
|
||||||
intercomAppId={INTERCOM_APP_ID}
|
|
||||||
intercomUserHash={intercomUserHash}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -215,9 +215,9 @@ export const BILLING_LIMITS = {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const INTERCOM_SECRET_KEY = env.INTERCOM_SECRET_KEY;
|
export const CHATWOOT_WEBSITE_TOKEN = env.CHATWOOT_WEBSITE_TOKEN;
|
||||||
export const INTERCOM_APP_ID = env.INTERCOM_APP_ID;
|
export const CHATWOOT_BASE_URL = env.CHATWOOT_BASE_URL || "https://app.chatwoot.com";
|
||||||
export const IS_INTERCOM_CONFIGURED = Boolean(env.INTERCOM_APP_ID && INTERCOM_SECRET_KEY);
|
export const IS_CHATWOOT_CONFIGURED = Boolean(env.CHATWOOT_WEBSITE_TOKEN);
|
||||||
|
|
||||||
export const TURNSTILE_SECRET_KEY = env.TURNSTILE_SECRET_KEY;
|
export const TURNSTILE_SECRET_KEY = env.TURNSTILE_SECRET_KEY;
|
||||||
export const TURNSTILE_SITE_KEY = env.TURNSTILE_SITE_KEY;
|
export const TURNSTILE_SITE_KEY = env.TURNSTILE_SITE_KEY;
|
||||||
|
|||||||
+4
-4
@@ -39,8 +39,8 @@ export const env = createEnv({
|
|||||||
.or(z.string().refine((str) => str === "")),
|
.or(z.string().refine((str) => str === "")),
|
||||||
IMPRINT_ADDRESS: z.string().optional(),
|
IMPRINT_ADDRESS: z.string().optional(),
|
||||||
INVITE_DISABLED: z.enum(["1", "0"]).optional(),
|
INVITE_DISABLED: z.enum(["1", "0"]).optional(),
|
||||||
INTERCOM_SECRET_KEY: z.string().optional(),
|
CHATWOOT_WEBSITE_TOKEN: z.string().optional(),
|
||||||
INTERCOM_APP_ID: z.string().optional(),
|
CHATWOOT_BASE_URL: z.string().url().optional(),
|
||||||
IS_FORMBRICKS_CLOUD: z.enum(["1", "0"]).optional(),
|
IS_FORMBRICKS_CLOUD: z.enum(["1", "0"]).optional(),
|
||||||
LOG_LEVEL: z.enum(["debug", "info", "warn", "error", "fatal"]).optional(),
|
LOG_LEVEL: z.enum(["debug", "info", "warn", "error", "fatal"]).optional(),
|
||||||
MAIL_FROM: z.string().email().optional(),
|
MAIL_FROM: z.string().email().optional(),
|
||||||
@@ -162,7 +162,8 @@ export const env = createEnv({
|
|||||||
IMPRINT_URL: process.env.IMPRINT_URL,
|
IMPRINT_URL: process.env.IMPRINT_URL,
|
||||||
IMPRINT_ADDRESS: process.env.IMPRINT_ADDRESS,
|
IMPRINT_ADDRESS: process.env.IMPRINT_ADDRESS,
|
||||||
INVITE_DISABLED: process.env.INVITE_DISABLED,
|
INVITE_DISABLED: process.env.INVITE_DISABLED,
|
||||||
INTERCOM_SECRET_KEY: process.env.INTERCOM_SECRET_KEY,
|
CHATWOOT_WEBSITE_TOKEN: process.env.CHATWOOT_WEBSITE_TOKEN,
|
||||||
|
CHATWOOT_BASE_URL: process.env.CHATWOOT_BASE_URL,
|
||||||
IS_FORMBRICKS_CLOUD: process.env.IS_FORMBRICKS_CLOUD,
|
IS_FORMBRICKS_CLOUD: process.env.IS_FORMBRICKS_CLOUD,
|
||||||
LOG_LEVEL: process.env.LOG_LEVEL,
|
LOG_LEVEL: process.env.LOG_LEVEL,
|
||||||
MAIL_FROM: process.env.MAIL_FROM,
|
MAIL_FROM: process.env.MAIL_FROM,
|
||||||
@@ -170,7 +171,6 @@ export const env = createEnv({
|
|||||||
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||||
SENTRY_DSN: process.env.SENTRY_DSN,
|
SENTRY_DSN: process.env.SENTRY_DSN,
|
||||||
OPENTELEMETRY_LISTENER_URL: process.env.OPENTELEMETRY_LISTENER_URL,
|
OPENTELEMETRY_LISTENER_URL: process.env.OPENTELEMETRY_LISTENER_URL,
|
||||||
INTERCOM_APP_ID: process.env.INTERCOM_APP_ID,
|
|
||||||
NOTION_OAUTH_CLIENT_ID: process.env.NOTION_OAUTH_CLIENT_ID,
|
NOTION_OAUTH_CLIENT_ID: process.env.NOTION_OAUTH_CLIENT_ID,
|
||||||
NOTION_OAUTH_CLIENT_SECRET: process.env.NOTION_OAUTH_CLIENT_SECRET,
|
NOTION_OAUTH_CLIENT_SECRET: process.env.NOTION_OAUTH_CLIENT_SECRET,
|
||||||
OIDC_CLIENT_ID: process.env.OIDC_CLIENT_ID,
|
OIDC_CLIENT_ID: process.env.OIDC_CLIENT_ID,
|
||||||
|
|||||||
@@ -61,10 +61,6 @@ const nextConfig = {
|
|||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "images.unsplash.com",
|
hostname: "images.unsplash.com",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
protocol: "https",
|
|
||||||
hostname: "api-iam.eu.intercom.io",
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
async redirects() {
|
async redirects() {
|
||||||
@@ -168,7 +164,7 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Content-Security-Policy",
|
key: "Content-Security-Policy",
|
||||||
value: `default-src 'self'; script-src 'self' 'unsafe-inline'${scriptSrcUnsafeEval} https://*.intercom.io https://*.intercomcdn.com https:; style-src 'self' 'unsafe-inline' https://*.intercomcdn.com https:; img-src 'self' blob: data: http://localhost:9000 https://*.intercom.io https://*.intercomcdn.com https:; font-src 'self' data: https://*.intercomcdn.com https:; connect-src 'self' http://localhost:9000 https://*.intercom.io wss://*.intercom.io https://*.intercomcdn.com https:; frame-src 'self' https://*.intercom.io https://app.cal.com https:; media-src 'self' https:; object-src 'self' data: https:; base-uri 'self'; form-action 'self'`,
|
value: `default-src 'self'; script-src 'self' 'unsafe-inline'${scriptSrcUnsafeEval} https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' blob: data: http://localhost:9000 https:; font-src 'self' data: https:; connect-src 'self' http://localhost:9000 https: wss:; frame-src 'self' https://app.cal.com https:; media-src 'self' https:; object-src 'self' data: https:; base-uri 'self'; form-action 'self'`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "Strict-Transport-Security",
|
key: "Strict-Transport-Security",
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
"@formbricks/surveys": "workspace:*",
|
"@formbricks/surveys": "workspace:*",
|
||||||
"@formbricks/types": "workspace:*",
|
"@formbricks/types": "workspace:*",
|
||||||
"@hookform/resolvers": "5.0.1",
|
"@hookform/resolvers": "5.0.1",
|
||||||
"@intercom/messenger-js-sdk": "0.0.14",
|
|
||||||
"@json2csv/node": "7.0.6",
|
"@json2csv/node": "7.0.6",
|
||||||
"@lexical/code": "0.36.2",
|
"@lexical/code": "0.36.2",
|
||||||
"@lexical/link": "0.36.2",
|
"@lexical/link": "0.36.2",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ checksums:
|
|||||||
common/ranking_items: 463f2eb500f1b42fbce6cec17612fb9a
|
common/ranking_items: 463f2eb500f1b42fbce6cec17612fb9a
|
||||||
common/respondents_will_not_see_this_card: 18c3dd44d6ff6ca2310ad196b84f30d3
|
common/respondents_will_not_see_this_card: 18c3dd44d6ff6ca2310ad196b84f30d3
|
||||||
common/retry: 6e44d18639560596569a1278f9c83676
|
common/retry: 6e44d18639560596569a1278f9c83676
|
||||||
|
common/retrying: 0cb623dbdcbf16d3680f0180ceac734c
|
||||||
common/select_a_date: 521e4a705800da06d091fde3e801ce02
|
common/select_a_date: 521e4a705800da06d091fde3e801ce02
|
||||||
common/select_for_ranking: e5f4e20752d1c2d852cd02dc3a0e9dd0
|
common/select_for_ranking: e5f4e20752d1c2d852cd02dc3a0e9dd0
|
||||||
common/sending_responses: 184772f70cca69424eaf34f73520789f
|
common/sending_responses: 184772f70cca69424eaf34f73520789f
|
||||||
|
|||||||
Generated
-8
@@ -162,9 +162,6 @@ importers:
|
|||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: 5.0.1
|
specifier: 5.0.1
|
||||||
version: 5.0.1(react-hook-form@7.56.2(react@19.1.2))
|
version: 5.0.1(react-hook-form@7.56.2(react@19.1.2))
|
||||||
'@intercom/messenger-js-sdk':
|
|
||||||
specifier: 0.0.14
|
|
||||||
version: 0.0.14
|
|
||||||
'@json2csv/node':
|
'@json2csv/node':
|
||||||
specifier: 7.0.6
|
specifier: 7.0.6
|
||||||
version: 7.0.6
|
version: 7.0.6
|
||||||
@@ -2252,9 +2249,6 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@intercom/messenger-js-sdk@0.0.14':
|
|
||||||
resolution: {integrity: sha512-2dH4BDAh9EI90K7hUkAdZ76W79LM45Sd1OBX7t6Vzy8twpNiQ5X+7sH9G5hlJlkSGnf+vFWlFcy9TOYAyEs1hA==}
|
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1':
|
'@isaacs/balanced-match@4.0.1':
|
||||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
@@ -12235,8 +12229,6 @@ snapshots:
|
|||||||
'@img/sharp-win32-x64@0.34.5':
|
'@img/sharp-win32-x64@0.34.5':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@intercom/messenger-js-sdk@0.0.14': {}
|
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1': {}
|
'@isaacs/balanced-match@4.0.1': {}
|
||||||
|
|
||||||
'@isaacs/brace-expansion@5.0.0':
|
'@isaacs/brace-expansion@5.0.0':
|
||||||
|
|||||||
+2
-2
@@ -146,8 +146,8 @@
|
|||||||
"IMPRINT_ADDRESS",
|
"IMPRINT_ADDRESS",
|
||||||
"INVITE_DISABLED",
|
"INVITE_DISABLED",
|
||||||
"IS_FORMBRICKS_CLOUD",
|
"IS_FORMBRICKS_CLOUD",
|
||||||
"INTERCOM_APP_ID",
|
"CHATWOOT_WEBSITE_TOKEN",
|
||||||
"INTERCOM_SECRET_KEY",
|
"CHATWOOT_BASE_URL",
|
||||||
"LOG_LEVEL",
|
"LOG_LEVEL",
|
||||||
"MAIL_FROM",
|
"MAIL_FROM",
|
||||||
"MAIL_FROM_NAME",
|
"MAIL_FROM_NAME",
|
||||||
|
|||||||
Reference in New Issue
Block a user