mirror of
https://github.com/toeverything/AFFiNE.git
synced 2025-01-03 14:53:35 +03:00
fix(core): revalidate quota and subscription when subscribing (#9220)
This commit is contained in:
parent
bdbefd3e28
commit
f788fdd0a4
@ -7,10 +7,10 @@ import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
|||||||
import { type I18nString, useI18n } from '@affine/i18n';
|
import { type I18nString, useI18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||||
import bytes from 'bytes';
|
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { useAsyncCallback } from '../../hooks/affine-async-hooks';
|
||||||
import * as styles from './cloud-quota-modal.css';
|
import * as styles from './cloud-quota-modal.css';
|
||||||
|
|
||||||
export const CloudQuotaModal = () => {
|
export const CloudQuotaModal = () => {
|
||||||
@ -66,22 +66,32 @@ export const CloudQuotaModal = () => {
|
|||||||
}
|
}
|
||||||
}, [userQuota, isOwner, workspaceQuota, t]);
|
}, [userQuota, isOwner, workspaceQuota, t]);
|
||||||
|
|
||||||
|
const onAbortLargeBlob = useAsyncCallback(
|
||||||
|
async (blob: Blob) => {
|
||||||
|
// wait for quota revalidation
|
||||||
|
await workspaceQuotaService.quota.waitForRevalidation();
|
||||||
|
if (
|
||||||
|
blob.size > (workspaceQuotaService.quota.quota$.value?.blobLimit ?? 0)
|
||||||
|
) {
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setOpen, workspaceQuotaService]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!workspaceQuota) {
|
if (!workspaceQuota) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
currentWorkspace.engine.blob.singleBlobSizeLimit = bytes.parse(
|
|
||||||
workspaceQuota.blobLimit.toString()
|
|
||||||
)!;
|
|
||||||
|
|
||||||
const disposable = currentWorkspace.engine.blob.onAbortLargeBlob.on(() => {
|
currentWorkspace.engine.blob.singleBlobSizeLimit = workspaceQuota.blobLimit;
|
||||||
setOpen(true);
|
|
||||||
});
|
const disposable =
|
||||||
|
currentWorkspace.engine.blob.onAbortLargeBlob.on(onAbortLargeBlob);
|
||||||
return () => {
|
return () => {
|
||||||
disposable?.dispose();
|
disposable?.dispose();
|
||||||
};
|
};
|
||||||
}, [currentWorkspace.engine.blob, setOpen, workspaceQuota]);
|
}, [currentWorkspace.engine.blob, onAbortLargeBlob, workspaceQuota]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
import {
|
||||||
|
SubscriptionService,
|
||||||
|
UserQuotaService,
|
||||||
|
} from '@affine/core/modules/cloud';
|
||||||
import { UrlService } from '@affine/core/modules/url';
|
import { UrlService } from '@affine/core/modules/url';
|
||||||
import type { CreateCheckoutSessionInput } from '@affine/graphql';
|
import type { CreateCheckoutSessionInput } from '@affine/graphql';
|
||||||
import { useService } from '@toeverything/infra';
|
import { useService } from '@toeverything/infra';
|
||||||
@ -7,6 +10,7 @@ import { nanoid } from 'nanoid';
|
|||||||
import {
|
import {
|
||||||
type PropsWithChildren,
|
type PropsWithChildren,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
@ -35,26 +39,23 @@ export const CheckoutSlot = ({
|
|||||||
const urlService = useService(UrlService);
|
const urlService = useService(UrlService);
|
||||||
|
|
||||||
const subscriptionService = useService(SubscriptionService);
|
const subscriptionService = useService(SubscriptionService);
|
||||||
|
const userQuotaService = useService(UserQuotaService);
|
||||||
|
|
||||||
|
const revalidate = useCallback(() => {
|
||||||
|
subscriptionService.subscription.revalidate();
|
||||||
|
userQuotaService.quota.revalidate();
|
||||||
|
}, [subscriptionService, userQuotaService]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
subscriptionService.prices.revalidate();
|
|
||||||
}, [subscriptionService]);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpenedExternalWindow) {
|
if (isOpenedExternalWindow) {
|
||||||
// when the external window is opened, revalidate the subscription when window get focus
|
// when the external window is opened, revalidate the subscription when window get focus
|
||||||
window.addEventListener(
|
window.addEventListener('focus', revalidate);
|
||||||
'focus',
|
|
||||||
subscriptionService.subscription.revalidate
|
|
||||||
);
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener(
|
window.removeEventListener('focus', revalidate);
|
||||||
'focus',
|
|
||||||
subscriptionService.subscription.revalidate
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}, [isOpenedExternalWindow, subscriptionService]);
|
}, [isOpenedExternalWindow, revalidate, subscriptionService]);
|
||||||
|
|
||||||
const subscribe = useAsyncCallback(async () => {
|
const subscribe = useAsyncCallback(async () => {
|
||||||
setMutating(true);
|
setMutating(true);
|
||||||
|
@ -75,7 +75,7 @@ export const CloudWorkspaceMembersPanel = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
workspaceQuotaService.quota.revalidate();
|
workspaceQuotaService.quota.revalidate();
|
||||||
}, [workspaceQuotaService]);
|
}, [workspaceQuotaService]);
|
||||||
const isLoading = useLiveData(workspaceQuotaService.quota.isLoading$);
|
const isLoading = useLiveData(workspaceQuotaService.quota.isRevalidating$);
|
||||||
const error = useLiveData(workspaceQuotaService.quota.error$);
|
const error = useLiveData(workspaceQuotaService.quota.error$);
|
||||||
const workspaceQuota = useLiveData(workspaceQuotaService.quota.quota$);
|
const workspaceQuota = useLiveData(workspaceQuotaService.quota.quota$);
|
||||||
const subscriptionService = useService(SubscriptionService);
|
const subscriptionService = useService(SubscriptionService);
|
||||||
|
@ -29,7 +29,7 @@ export const StorageProgress = () => {
|
|||||||
).permission;
|
).permission;
|
||||||
const workspaceQuotaService = useService(WorkspaceQuotaService).quota;
|
const workspaceQuotaService = useService(WorkspaceQuotaService).quota;
|
||||||
const isTeam = useLiveData(workspacePermissionService.isTeam$);
|
const isTeam = useLiveData(workspacePermissionService.isTeam$);
|
||||||
const isLoading = useLiveData(workspaceQuotaService.isLoading$);
|
const isLoading = useLiveData(workspaceQuotaService.isRevalidating$);
|
||||||
const usedFormatted = useLiveData(workspaceQuotaService.usedFormatted$);
|
const usedFormatted = useLiveData(workspaceQuotaService.usedFormatted$);
|
||||||
const maxFormatted = useLiveData(workspaceQuotaService.maxFormatted$);
|
const maxFormatted = useLiveData(workspaceQuotaService.maxFormatted$);
|
||||||
const percent = useLiveData(workspaceQuotaService.percent$);
|
const percent = useLiveData(workspaceQuotaService.percent$);
|
||||||
|
@ -25,7 +25,7 @@ const logger = new DebugLogger('affine:workspace-permission');
|
|||||||
|
|
||||||
export class WorkspaceQuota extends Entity {
|
export class WorkspaceQuota extends Entity {
|
||||||
quota$ = new LiveData<QuotaType | null>(null);
|
quota$ = new LiveData<QuotaType | null>(null);
|
||||||
isLoading$ = new LiveData(false);
|
isRevalidating$ = new LiveData(false);
|
||||||
error$ = new LiveData<any>(null);
|
error$ = new LiveData<any>(null);
|
||||||
|
|
||||||
/** Used storage in bytes */
|
/** Used storage in bytes */
|
||||||
@ -106,18 +106,26 @@ export class WorkspaceQuota extends Entity {
|
|||||||
catchErrorInto(this.error$, error => {
|
catchErrorInto(this.error$, error => {
|
||||||
logger.error('Failed to fetch workspace quota', error);
|
logger.error('Failed to fetch workspace quota', error);
|
||||||
}),
|
}),
|
||||||
onStart(() => this.isLoading$.setValue(true)),
|
onStart(() => this.isRevalidating$.setValue(true)),
|
||||||
onComplete(() => this.isLoading$.setValue(false))
|
onComplete(() => this.isRevalidating$.setValue(false))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
waitForRevalidation(signal?: AbortSignal) {
|
||||||
|
this.revalidate();
|
||||||
|
return this.isRevalidating$.waitFor(
|
||||||
|
isRevalidating => !isRevalidating,
|
||||||
|
signal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.quota$.next(null);
|
this.quota$.next(null);
|
||||||
this.used$.next(null);
|
this.used$.next(null);
|
||||||
this.error$.next(null);
|
this.error$.next(null);
|
||||||
this.isLoading$.next(false);
|
this.isRevalidating$.next(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
override dispose(): void {
|
override dispose(): void {
|
||||||
|
Loading…
Reference in New Issue
Block a user