feat: optional payment for frontend (#5056)

This commit is contained in:
DarkSky
2023-11-25 23:15:44 +08:00
committed by GitHub
parent 13e712158c
commit f04ec50d12
14 changed files with 146 additions and 38 deletions
@@ -28,6 +28,11 @@ const UserPlanButtonWithData = () => {
const t = useAFFiNEI18N();
if (plan === SubscriptionPlan.SelfHosted) {
// Self hosted version doesn't have a payment apis.
return <div className={styles.userPlanButton}>{plan}</div>;
}
return (
<Tooltip content={t['com.affine.payment.tag-tooltips']()} side="top">
<div className={styles.userPlanButton} onClick={handleClick}>
@@ -7,6 +7,7 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import { useMemo } from 'react';
import { useSelfHosted } from '../../../hooks/affine/use-server-flavor';
import { useWorkspace } from '../../../hooks/use-workspace';
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
import { ExportPanel } from './export';
@@ -20,6 +21,7 @@ import type { WorkspaceSettingDetailProps } from './types';
export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
const { workspaceId } = props;
const t = useAFFiNEI18N();
const isSelfHosted = useSelfHosted();
const workspace = useWorkspace(workspaceId);
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
@@ -56,7 +58,11 @@ export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
</SettingWrapper>
<SettingWrapper title={t['com.affine.brand.affineCloud']()}>
<PublishPanel workspace={workspace} {...props} />
<MembersPanel workspace={workspace} {...props} />
<MembersPanel
workspace={workspace}
upgradable={!isSelfHosted}
{...props}
/>
</SettingWrapper>
{storageAndExportSetting}
<SettingWrapper>
@@ -51,6 +51,7 @@ enum MemberLimitCount {
const COUNT_PER_PAGE = 8;
export interface MembersPanelProps extends WorkspaceSettingDetailProps {
upgradable: boolean;
workspace: AffineOfficialWorkspace;
}
type OnRevoke = (memberId: string) => void;
@@ -70,6 +71,7 @@ const MembersPanelLocal = () => {
export const CloudWorkspaceMembersPanel = ({
workspace,
isOwner,
upgradable,
}: MembersPanelProps) => {
const workspaceId = workspace.id;
const memberCount = useMemberCount(workspaceId);
@@ -165,16 +167,20 @@ export const CloudWorkspaceMembersPanel = ({
planName: plan,
memberLimit,
})}
,
<div className={style.goUpgradeWrapper} onClick={handleUpgrade}>
<span className={style.goUpgrade}>
{t['com.affine.payment.member.description.go-upgrade']()}
</span>
<ArrowRightBigIcon className={style.arrowRight} />
</div>
{upgradable ? (
<>
,
<div className={style.goUpgradeWrapper} onClick={handleUpgrade}>
<span className={style.goUpgrade}>
{t['com.affine.payment.member.description.go-upgrade']()}
</span>
<ArrowRightBigIcon className={style.arrowRight} />
</div>
</>
) : null}
</span>
);
}, [handleUpgrade, memberLimit, plan, t]);
}, [handleUpgrade, memberLimit, plan, t, upgradable]);
return (
<>
@@ -35,6 +35,7 @@ import {
openSignOutModalAtom,
} from '../../../../atoms';
import { useCurrentUser } from '../../../../hooks/affine/use-current-user';
import { useSelfHosted } from '../../../../hooks/affine/use-server-flavor';
import { useUserSubscription } from '../../../../hooks/use-subscription';
import { Upload } from '../../../pure/file-upload';
import * as style from './style.css';
@@ -167,6 +168,7 @@ export const AvatarAndName = () => {
const StoragePanel = () => {
const t = useAFFiNEI18N();
const isSelfHosted = useSelfHosted();
const { data } = useQuery({
query: allBlobSizesQuery,
@@ -175,6 +177,7 @@ const StoragePanel = () => {
const [subscription] = useUserSubscription();
const plan = subscription?.plan ?? SubscriptionPlan.Free;
// TODO(@JimmFly): get limit from user usage query directly after #4720 is merged
const maxLimit = useMemo(() => {
return bytes.parse(plan === SubscriptionPlan.Free ? '10GB' : '100GB');
}, [plan]);
@@ -199,6 +202,7 @@ const StoragePanel = () => {
plan={plan}
value={data.collectAllBlobSizes.size}
onUpgrade={onUpgrade}
upgradable={!isSelfHosted}
/>
</SettingRow>
);
@@ -8,6 +8,7 @@ import {
import type { ReactElement, SVGProps } from 'react';
import { useCurrentLoginStatus } from '../../../../hooks/affine/use-current-login-status';
import { useSelfHosted } from '../../../../hooks/affine/use-server-flavor';
import { AboutAffine } from './about';
import { AppearanceSettings } from './appearance';
import { BillingSettings } from './billing';
@@ -36,6 +37,7 @@ export type GeneralSettingList = GeneralSettingListItem[];
export const useGeneralSettingList = (): GeneralSettingList => {
const t = useAFFiNEI18N();
const status = useCurrentLoginStatus();
const isSelfHosted = useSelfHosted();
const settings: GeneralSettingListItem[] = [
{
@@ -50,13 +52,6 @@ export const useGeneralSettingList = (): GeneralSettingList => {
icon: KeyboardIcon,
testId: 'shortcuts-panel-trigger',
},
{
key: 'plans',
title: t['com.affine.payment.title'](),
icon: UpgradeIcon,
testId: 'plans-panel-trigger',
},
{
key: 'plugins',
title: 'Plugins',
@@ -71,13 +66,21 @@ export const useGeneralSettingList = (): GeneralSettingList => {
},
];
if (status === 'authenticated') {
if (!isSelfHosted) {
settings.splice(3, 0, {
key: 'billing',
title: t['com.affine.payment.billing-setting.title'](),
icon: PaymentIcon,
testId: 'billing-panel-trigger',
key: 'plans',
title: t['com.affine.payment.title'](),
icon: UpgradeIcon,
testId: 'plans-panel-trigger',
});
if (status === 'authenticated') {
settings.splice(3, 0, {
key: 'billing',
title: t['com.affine.payment.billing-setting.title'](),
icon: PaymentIcon,
testId: 'billing-panel-trigger',
});
}
}
return settings;