diff --git a/apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx b/apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx
index 7c682c496..1536c1a1b 100644
--- a/apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx
+++ b/apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx
@@ -1,4 +1,5 @@
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
+import { IS_DOCUMENSO_CLOUD } from '@documenso/lib/constants/app';
import { ORGANISATION_MEMBER_ROLE_HIERARCHY } from '@documenso/lib/constants/organisations';
import { ORGANISATION_MEMBER_ROLE_MAP } from '@documenso/lib/constants/organisations-translations';
import {
@@ -28,6 +29,7 @@ import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { SettingsHeader } from '~/components/general/settings-header';
+import { SsoPortalUpsell } from '~/components/general/settings-upsell/sso-portal-upsell';
import { appMetaTags } from '~/utils/meta';
const ZProviderFormSchema = ZUpdateOrganisationAuthenticationPortalRequestSchema.shape.data
@@ -63,10 +65,33 @@ export default function OrganisationSettingSSOLoginPage() {
const { t } = useLingui();
const organisation = useCurrentOrganisation();
+ const isAuthenticationPortalEnabled = organisation.organisationClaim.flags.authenticationPortal === true;
+
const { data: authenticationPortal, isLoading: isLoadingAuthenticationPortal } =
- trpc.enterprise.organisation.authenticationPortal.get.useQuery({
- organisationId: organisation.id,
- });
+ trpc.enterprise.organisation.authenticationPortal.get.useQuery(
+ {
+ organisationId: organisation.id,
+ },
+ {
+ // The endpoint rejects orgs without the claim flag, so don't fire
+ // requests that are guaranteed to error.
+ enabled: isAuthenticationPortalEnabled,
+ },
+ );
+
+ if (!isAuthenticationPortalEnabled && IS_DOCUMENSO_CLOUD()) {
+ return (
+
+ );
+ }
if (isLoadingAuthenticationPortal || !authenticationPortal) {
return
;
diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx
index 7e0366d6f..a46b07056 100644
--- a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx
+++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx
@@ -1,5 +1,5 @@
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
-import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
+import { IS_BILLING_ENABLED, IS_DOCUMENSO_CLOUD } from '@documenso/lib/constants/app';
import { canExecuteOrganisationAction } from '@documenso/lib/utils/organisations';
import type { SanitizeBrandingCssWarning } from '@documenso/lib/utils/sanitize-branding-css';
import { trpc } from '@documenso/trpc/react';
@@ -17,6 +17,7 @@ import {
type TBrandingPreferencesFormSchema,
} from '~/components/forms/branding-preferences-form';
import { SettingsHeader } from '~/components/general/settings-header';
+import { BrandingUpsell } from '~/components/general/settings-upsell/branding-upsell';
import { useCurrentTeam } from '~/providers/team';
export default function TeamsSettingsPage() {
@@ -155,6 +156,8 @@ export default function TeamsSettingsPage() {
)}
+ ) : IS_DOCUMENSO_CLOUD() ? (
+
diff --git a/apps/remix/package.json b/apps/remix/package.json
index 0a889ccef..daa376df3 100644
--- a/apps/remix/package.json
+++ b/apps/remix/package.json
@@ -44,7 +44,7 @@
"autoprefixer": "^10.4.22",
"colord": "^2.9.3",
"content-disposition": "^1.0.1",
- "framer-motion": "^12.23.24",
+ "framer-motion": "^12.43.0",
"hono": "^4.12.14",
"hono-react-router-adapter": "^0.6.5",
"input-otp": "^1.4.2",
diff --git a/package-lock.json b/package-lock.json
index 3510fd7a7..a10151db2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -399,7 +399,7 @@
"autoprefixer": "^10.4.22",
"colord": "^2.9.3",
"content-disposition": "^1.0.1",
- "framer-motion": "^12.23.24",
+ "framer-motion": "^12.43.0",
"hono": "^4.12.14",
"hono-react-router-adapter": "^0.6.5",
"input-otp": "^1.4.2",
@@ -20310,13 +20310,13 @@
}
},
"node_modules/framer-motion": {
- "version": "12.23.24",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
- "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
+ "version": "12.43.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.43.0.tgz",
+ "integrity": "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g==",
"license": "MIT",
"dependencies": {
- "motion-dom": "^12.23.23",
- "motion-utils": "^12.23.6",
+ "motion-dom": "^12.43.0",
+ "motion-utils": "^12.39.0",
"tslib": "^2.4.0"
},
"peerDependencies": {
@@ -24677,18 +24677,18 @@
"license": "MIT"
},
"node_modules/motion-dom": {
- "version": "12.23.23",
- "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
- "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
+ "version": "12.43.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.43.0.tgz",
+ "integrity": "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==",
"license": "MIT",
"dependencies": {
- "motion-utils": "^12.23.6"
+ "motion-utils": "^12.39.0"
}
},
"node_modules/motion-utils": {
- "version": "12.23.6",
- "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
- "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "version": "12.39.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz",
+ "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==",
"license": "MIT"
},
"node_modules/mqtt": {
@@ -33933,7 +33933,7 @@
"clsx": "^1.2.1",
"cmdk": "^0.2.1",
"colord": "^2.9.3",
- "framer-motion": "^12.23.24",
+ "framer-motion": "^12.43.0",
"lucide-react": "^0.554.0",
"luxon": "^3.7.2",
"pdfjs-dist": "5.4.296",
diff --git a/packages/lib/constants/app.ts b/packages/lib/constants/app.ts
index 67931b4c5..9740fae22 100644
--- a/packages/lib/constants/app.ts
+++ b/packages/lib/constants/app.ts
@@ -53,6 +53,14 @@ export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL = () =>
export const IS_BILLING_ENABLED = () => env('NEXT_PUBLIC_FEATURE_BILLING_ENABLED') === 'true';
+/**
+ * Whether this instance is Documenso Cloud (managed SaaS).
+ *
+ * Used so we can show a different UI for Documenso Cloud and self-hosted instances since
+ * there are things like billing, upsells, documenso links, etc that don't make sense for self-hosted instances.
+ */
+export const IS_DOCUMENSO_CLOUD = () => env('NEXT_PUBLIC_IS_DOCUMENSO_CLOUD') === 'true';
+
export const API_V2_BETA_URL = '/api/v2-beta';
export const API_V2_URL = '/api/v2';
@@ -135,3 +143,5 @@ export const CSC_INSTANCE_SIGNATURE_LEVEL = (): TSignatureLevel => {
return value;
};
+
+export const DOCUMENSO_CLOUD_ENTERPRISE_CTA_URL = 'https://documen.so/enterprise-cta';
diff --git a/packages/lib/utils/settings-nav.ts b/packages/lib/utils/settings-nav.ts
index 7f5f51330..c503c9b53 100644
--- a/packages/lib/utils/settings-nav.ts
+++ b/packages/lib/utils/settings-nav.ts
@@ -18,7 +18,7 @@ import {
} from 'lucide-react';
import type { ComponentType } from 'react';
import { FaUsers } from 'react-icons/fa6';
-import { IS_BILLING_ENABLED } from '../constants/app';
+import { IS_BILLING_ENABLED, IS_DOCUMENSO_CLOUD } from '../constants/app';
import { canExecuteOrganisationAction } from './organisations';
import { canExecuteTeamAction } from './teams';
@@ -73,6 +73,7 @@ export const getSettingsNavGroups = ({
hasManageableBillingOrgs,
}: GetSettingsNavGroupsArgs): SettingsNavGroups => {
const isBillingEnabled = IS_BILLING_ENABLED();
+ const isDocumensoCloud = IS_DOCUMENSO_CLOUD();
const canManageOrg =
organisation !== null && canExecuteOrganisationAction('MANAGE_ORGANISATION', organisation.currentOrganisationRole);
@@ -126,7 +127,7 @@ export const getSettingsNavGroups = ({
label: msg`Certificates`,
isSubNav: true,
},
- ...(isBillingEnabled && organisation.organisationClaim.flags.emailDomains
+ ...((isBillingEnabled && organisation.organisationClaim.flags.emailDomains) || isDocumensoCloud
? [
{
key: 'email-domains',
@@ -154,7 +155,7 @@ export const getSettingsNavGroups = ({
label: msg`Groups`,
icon: GroupIcon,
},
- ...(isBillingEnabled && organisation.organisationClaim.flags.authenticationPortal
+ ...((isBillingEnabled && organisation.organisationClaim.flags.authenticationPortal) || isDocumensoCloud
? [
{
key: 'sso',
diff --git a/packages/ui/package.json b/packages/ui/package.json
index d39030cbc..85472a456 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -62,7 +62,7 @@
"clsx": "^1.2.1",
"cmdk": "^0.2.1",
"colord": "^2.9.3",
- "framer-motion": "^12.23.24",
+ "framer-motion": "^12.43.0",
"lucide-react": "^0.554.0",
"luxon": "^3.7.2",
"pdfjs-dist": "5.4.296",