diff --git a/apps/api/src/app/controllers/user.controller.ts b/apps/api/src/app/controllers/user.controller.ts index 212c4549..f6a758f1 100644 --- a/apps/api/src/app/controllers/user.controller.ts +++ b/apps/api/src/app/controllers/user.controller.ts @@ -102,7 +102,8 @@ export const routeDefinition = { name: z.string().min(1).max(255).trim().optional(), preferences: z .object({ - skipFrontdoorLogin: z.boolean(), + skipFrontdoorLogin: z.boolean().optional(), + recordSyncEnabled: z.boolean().optional(), }) .optional(), }), diff --git a/apps/api/src/app/controllers/web-extension.controller.ts b/apps/api/src/app/controllers/web-extension.controller.ts index ec412c4e..e3a3edc3 100644 --- a/apps/api/src/app/controllers/web-extension.controller.ts +++ b/apps/api/src/app/controllers/web-extension.controller.ts @@ -113,7 +113,7 @@ const initSession = createRoute(routeDefinition.initSession.validators, async ({ name: user.name, emailVerified: user.emailVerified, picture: user.picture, - preferences: { skipFrontdoorLogin: false }, + preferences: { skipFrontdoorLogin: false, recordSyncEnabled: true }, billingAccount: user.billingAccount, entitlements: { chromeExtension: true, diff --git a/apps/api/src/app/db/user.db.ts b/apps/api/src/app/db/user.db.ts index 5385bac0..c021bdc2 100644 --- a/apps/api/src/app/db/user.db.ts +++ b/apps/api/src/app/db/user.db.ts @@ -153,22 +153,25 @@ export const checkUserEntitlement = ({ export async function updateUser( user: UserProfileSession, - data: { name?: string; preferences?: { skipFrontdoorLogin: boolean } } + data: { name?: string; preferences?: { skipFrontdoorLogin?: boolean; recordSyncEnabled?: boolean } } ): Promise { try { const existingUser = await prisma.user.findUniqueOrThrow({ where: { id: user.id }, - select: { id: true, name: true, preferences: { select: { skipFrontdoorLogin: true } } }, + select: { id: true, name: true, preferences: { select: { skipFrontdoorLogin: true, recordSyncEnabled: true } } }, }); - const skipFrontdoorLogin = data.preferences?.skipFrontdoorLogin ?? (existingUser?.preferences?.skipFrontdoorLogin || false); + // PATCH update + const skipFrontdoorLogin = data.preferences?.skipFrontdoorLogin ?? existingUser?.preferences?.skipFrontdoorLogin ?? false; + const recordSyncEnabled = data.preferences?.recordSyncEnabled ?? existingUser?.preferences?.recordSyncEnabled ?? true; + const updatedUser = await prisma.user.update({ where: { id: user.id }, data: { name: data.name ?? existingUser.name, preferences: { upsert: { - create: { skipFrontdoorLogin }, - update: { skipFrontdoorLogin }, + create: { skipFrontdoorLogin, recordSyncEnabled }, + update: { skipFrontdoorLogin, recordSyncEnabled }, }, }, }, diff --git a/apps/jetstream/src/app/components/billing/Billing.tsx b/apps/jetstream/src/app/components/billing/Billing.tsx index 467f5ccd..3c37a39b 100644 --- a/apps/jetstream/src/app/components/billing/Billing.tsx +++ b/apps/jetstream/src/app/components/billing/Billing.tsx @@ -114,7 +114,7 @@ export const Billing = () => { ) : (
-

Professional plan includes

+

Upgrading to a Jetstream Professional plan includes

  • Access to the{' '} diff --git a/apps/jetstream/src/app/components/core/AppInitializer.tsx b/apps/jetstream/src/app/components/core/AppInitializer.tsx index 9b5f2cbd..55fc6ec9 100644 --- a/apps/jetstream/src/app/components/core/AppInitializer.tsx +++ b/apps/jetstream/src/app/components/core/AppInitializer.tsx @@ -1,7 +1,7 @@ /* eslint-disable no-restricted-globals */ import { logger } from '@jetstream/shared/client-logger'; import { HTTP } from '@jetstream/shared/constants'; -import { checkHeartbeat, initSocket, registerMiddleware } from '@jetstream/shared/data'; +import { checkHeartbeat, disconnectSocket, initSocket, registerMiddleware } from '@jetstream/shared/data'; import { useObservable, useRollbar } from '@jetstream/shared/ui-utils'; import { Announcement, ApplicationCookie, SalesforceOrgUi, UserProfileUi } from '@jetstream/types'; import { initDexieDb, useAmplitude, usePageViews } from '@jetstream/ui-core'; @@ -41,7 +41,9 @@ export const AppInitializer: FunctionComponent = ({ onAnnou const appCookie = useRecoilValue(fromAppState.applicationCookieState); const [orgs, setOrgs] = useRecoilState(fromAppState.salesforceOrgsState); const invalidOrg = useObservable(orgConnectionError$); - const recordSyncEnabled = useRecoilValue(fromAppState.userProfileEntitlementState('recordSync')); + + const recordSyncEntitlementEnabled = useRecoilValue(fromAppState.userProfileEntitlementState('recordSync')); + const recordSyncEnabled = recordSyncEntitlementEnabled && userProfile.preferences.recordSyncEnabled; useEffect(() => { console.log( @@ -67,6 +69,8 @@ APP VERSION ${version} useEffect(() => { if (recordSyncEnabled) { initSocket(); + } else { + disconnectSocket(); } initDexieDb({ recordSyncEnabled }).catch((ex) => { logger.error('[DB] Error initializing db', ex); diff --git a/apps/jetstream/src/app/components/settings/Settings.tsx b/apps/jetstream/src/app/components/settings/Settings.tsx index 8bbb46db..00b1cb2d 100644 --- a/apps/jetstream/src/app/components/settings/Settings.tsx +++ b/apps/jetstream/src/app/components/settings/Settings.tsx @@ -102,6 +102,12 @@ export const Settings = () => { handleSave(_modifiedUser); } + function handleRecordSyncChange(recordSyncEnabled: boolean) { + const _modifiedUser = { ...modifiedUser, preferences: { recordSyncEnabled } } as UserProfileUiWithIdentities; + setModifiedUser(_modifiedUser); + handleSave(_modifiedUser); + } + async function handleDelete(reason: string) { /** * FUTURE: @@ -163,7 +169,7 @@ export const Settings = () => {

    General Settings

    { {recordSyncEnabled && (

    Data Sync

    - {/* FIXME: add option for user to opt-out of this behavior (e.g. user preference?) */} - {/* setRecordSyncEnabled(value)} - /> */} + onChange={handleRecordSyncChange} + />