diff --git a/apps/remix/app/components/embed/embed-direct-template-client-page.tsx b/apps/remix/app/components/embed/embed-direct-template-client-page.tsx index 47832c7af..6927d9b58 100644 --- a/apps/remix/app/components/embed/embed-direct-template-client-page.tsx +++ b/apps/remix/app/components/embed/embed-direct-template-client-page.tsx @@ -47,7 +47,7 @@ export type EmbedDirectTemplateClientPageProps = { fields: Field[]; metadata?: DocumentMeta | TemplateMeta | null; hidePoweredBy?: boolean; - isPlatformOrEnterprise?: boolean; + allowWhiteLabelling?: boolean; }; export const EmbedDirectTemplateClientPage = ({ @@ -58,7 +58,7 @@ export const EmbedDirectTemplateClientPage = ({ fields, metadata, hidePoweredBy = false, - isPlatformOrEnterprise = false, + allowWhiteLabelling = false, }: EmbedDirectTemplateClientPageProps) => { const { _ } = useLingui(); const { toast } = useToast(); @@ -286,7 +286,7 @@ export const EmbedDirectTemplateClientPage = ({ document.documentElement.classList.add('dark-mode-disabled'); } - if (isPlatformOrEnterprise) { + if (allowWhiteLabelling) { injectCss({ css: data.css, cssVars: data.cssVars, diff --git a/apps/remix/app/components/embed/embed-document-signing-page.tsx b/apps/remix/app/components/embed/embed-document-signing-page.tsx index 9f501e592..f158cd4a8 100644 --- a/apps/remix/app/components/embed/embed-document-signing-page.tsx +++ b/apps/remix/app/components/embed/embed-document-signing-page.tsx @@ -50,7 +50,7 @@ export type EmbedSignDocumentClientPageProps = { metadata?: DocumentMeta | TemplateMeta | null; isCompleted?: boolean; hidePoweredBy?: boolean; - isPlatformOrEnterprise?: boolean; + allowWhitelabelling?: boolean; allRecipients?: RecipientWithFields[]; }; @@ -63,7 +63,7 @@ export const EmbedSignDocumentClientPage = ({ metadata, isCompleted, hidePoweredBy = false, - isPlatformOrEnterprise = false, + allowWhitelabelling = false, allRecipients = [], }: EmbedSignDocumentClientPageProps) => { const { _ } = useLingui(); @@ -211,7 +211,7 @@ export const EmbedSignDocumentClientPage = ({ document.documentElement.classList.add('dark-mode-disabled'); } - if (isPlatformOrEnterprise) { + if (allowWhitelabelling) { injectCss({ css: data.css, cssVars: data.cssVars, diff --git a/apps/remix/app/routes/embed+/direct.$url.tsx b/apps/remix/app/routes/embed+/direct.$url.tsx index ee75ce16a..f5ac53f8f 100644 --- a/apps/remix/app/routes/embed+/direct.$url.tsx +++ b/apps/remix/app/routes/embed+/direct.$url.tsx @@ -2,6 +2,7 @@ import { data } from 'react-router'; import { match } from 'ts-pattern'; import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session'; +import { isCommunityPlan as isUserCommunityPlan } from '@documenso/ee/server-only/util/is-community-plan'; import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise'; import { isDocumentPlatform } from '@documenso/ee/server-only/util/is-document-platform'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; @@ -55,12 +56,16 @@ export async function loader({ params, request }: Route.LoaderArgs) { documentAuth: template.authOptions, }); - const [isPlatformDocument, isEnterpriseDocument] = await Promise.all([ + const [isPlatformDocument, isEnterpriseDocument, isCommunityPlan] = await Promise.all([ isDocumentPlatform(template), isUserEnterprise({ userId: template.userId, teamId: template.teamId ?? undefined, }), + isUserCommunityPlan({ + userId: template.userId, + teamId: template.teamId ?? undefined, + }), ]); const isAccessAuthValid = match(derivedRecipientAccessAuth) @@ -108,6 +113,7 @@ export async function loader({ params, request }: Route.LoaderArgs) { hidePoweredBy, isPlatformDocument, isEnterpriseDocument, + isCommunityPlan, }); } @@ -121,6 +127,7 @@ export default function EmbedDirectTemplatePage() { hidePoweredBy, isPlatformDocument, isEnterpriseDocument, + isCommunityPlan, } = useSuperLoaderData(); return ( @@ -139,7 +146,7 @@ export default function EmbedDirectTemplatePage() { fields={fields} metadata={template.templateMeta} hidePoweredBy={isPlatformDocument || isEnterpriseDocument || hidePoweredBy} - isPlatformOrEnterprise={isPlatformDocument || isEnterpriseDocument} + allowWhiteLabelling={isCommunityPlan || isPlatformDocument || isEnterpriseDocument} /> diff --git a/apps/remix/app/routes/embed+/sign.$url.tsx b/apps/remix/app/routes/embed+/sign.$url.tsx index 63680a27b..ed242bf5a 100644 --- a/apps/remix/app/routes/embed+/sign.$url.tsx +++ b/apps/remix/app/routes/embed+/sign.$url.tsx @@ -3,6 +3,7 @@ import { data } from 'react-router'; import { match } from 'ts-pattern'; import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session'; +import { isCommunityPlan as isUserCommunityPlan } from '@documenso/ee/server-only/util/is-community-plan'; import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise'; import { isDocumentPlatform } from '@documenso/ee/server-only/util/is-document-platform'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; @@ -61,12 +62,16 @@ export async function loader({ params, request }: Route.LoaderArgs) { ); } - const [isPlatformDocument, isEnterpriseDocument] = await Promise.all([ + const [isPlatformDocument, isEnterpriseDocument, isCommunityPlan] = await Promise.all([ isDocumentPlatform(document), isUserEnterprise({ userId: document.userId, teamId: document.teamId ?? undefined, }), + isUserCommunityPlan({ + userId: document.userId, + teamId: document.teamId ?? undefined, + }), ]); const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({ @@ -127,6 +132,7 @@ export async function loader({ params, request }: Route.LoaderArgs) { hidePoweredBy, isPlatformDocument, isEnterpriseDocument, + isCommunityPlan, }); } @@ -141,6 +147,7 @@ export default function EmbedSignDocumentPage() { hidePoweredBy, isPlatformDocument, isEnterpriseDocument, + isCommunityPlan, } = useSuperLoaderData(); return ( @@ -163,7 +170,7 @@ export default function EmbedSignDocumentPage() { metadata={document.documentMeta} isCompleted={document.status === DocumentStatus.COMPLETED} hidePoweredBy={isPlatformDocument || isEnterpriseDocument || hidePoweredBy} - isPlatformOrEnterprise={isPlatformDocument || isEnterpriseDocument} + allowWhitelabelling={isCommunityPlan || isPlatformDocument || isEnterpriseDocument} allRecipients={allRecipients} /> diff --git a/packages/ee/server-only/util/is-community-plan.ts b/packages/ee/server-only/util/is-community-plan.ts new file mode 100644 index 000000000..b32769d41 --- /dev/null +++ b/packages/ee/server-only/util/is-community-plan.ts @@ -0,0 +1,56 @@ +import { subscriptionsContainsActivePlan } from '@documenso/lib/utils/billing'; +import { prisma } from '@documenso/prisma'; +import type { Subscription } from '@documenso/prisma/client'; + +import { getCommunityPlanPriceIds } from '../stripe/get-community-plan-prices'; + +export type IsCommunityPlanOptions = { + userId: number; + teamId?: number; +}; + +/** + * Whether the user or team is on the community plan. + */ +export const isCommunityPlan = async ({ + userId, + teamId, +}: IsCommunityPlanOptions): Promise => { + let subscriptions: Subscription[] = []; + + if (teamId) { + subscriptions = await prisma.team + .findFirstOrThrow({ + where: { + id: teamId, + }, + select: { + owner: { + include: { + subscriptions: true, + }, + }, + }, + }) + .then((team) => team.owner.subscriptions); + } else { + subscriptions = await prisma.user + .findFirstOrThrow({ + where: { + id: userId, + }, + select: { + subscriptions: true, + }, + }) + .then((user) => user.subscriptions); + } + + if (subscriptions.length === 0) { + return false; + } + + const communityPlanPriceIds = await getCommunityPlanPriceIds(); + + return subscriptionsContainsActivePlan(subscriptions, communityPlanPriceIds); +};