mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-21 16:26:58 +08:00
Compare commits
6 Commits
v0.26.3-be
...
v0.18.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1623f5d82f | ||
|
|
2abf40b465 | ||
|
|
dea0574a89 | ||
|
|
a73c08ff24 | ||
|
|
c4410751e4 | ||
|
|
47899a7eaf |
@@ -370,7 +370,7 @@ export class UserSubscriptionResolver {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.db.userSubscription.findUnique({
|
const subscription = await this.db.userSubscription.findUnique({
|
||||||
where: {
|
where: {
|
||||||
userId_plan: {
|
userId_plan: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@@ -379,6 +379,18 @@ export class UserSubscriptionResolver {
|
|||||||
status: SubscriptionStatus.Active,
|
status: SubscriptionStatus.Active,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
subscription &&
|
||||||
|
subscription.variant &&
|
||||||
|
![SubscriptionVariant.EA, SubscriptionVariant.Onetime].includes(
|
||||||
|
subscription.variant as SubscriptionVariant
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
subscription.variant = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => [UserSubscriptionType])
|
@ResolveField(() => [UserSubscriptionType])
|
||||||
@@ -390,12 +402,25 @@ export class UserSubscriptionResolver {
|
|||||||
throw new AccessDenied();
|
throw new AccessDenied();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.db.userSubscription.findMany({
|
const subscriptions = await this.db.userSubscription.findMany({
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
status: SubscriptionStatus.Active,
|
status: SubscriptionStatus.Active,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
subscriptions.forEach(subscription => {
|
||||||
|
if (
|
||||||
|
subscription.variant &&
|
||||||
|
![SubscriptionVariant.EA, SubscriptionVariant.Onetime].includes(
|
||||||
|
subscription.variant as SubscriptionVariant
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
subscription.variant = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return subscriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => [UserInvoiceType])
|
@ResolveField(() => [UserInvoiceType])
|
||||||
|
|||||||
@@ -13,23 +13,28 @@ export class DocRecordList extends Entity {
|
|||||||
|
|
||||||
private readonly pool = new Map<string, DocRecord>();
|
private readonly pool = new Map<string, DocRecord>();
|
||||||
|
|
||||||
public readonly docs$ = LiveData.from<DocRecord[]>(
|
public readonly docsMap$ = LiveData.from<Map<string, DocRecord>>(
|
||||||
this.store.watchDocIds().pipe(
|
this.store.watchDocIds().pipe(
|
||||||
map(ids =>
|
map(
|
||||||
|
ids =>
|
||||||
|
new Map(
|
||||||
ids.map(id => {
|
ids.map(id => {
|
||||||
const exists = this.pool.get(id);
|
const exists = this.pool.get(id);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
return exists;
|
return [id, exists];
|
||||||
}
|
}
|
||||||
const record = this.framework.createEntity(DocRecord, { id });
|
const record = this.framework.createEntity(DocRecord, { id });
|
||||||
this.pool.set(id, record);
|
this.pool.set(id, record);
|
||||||
return record;
|
return [id, record];
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
[]
|
new Map()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public readonly docs$ = this.docsMap$.selector(d => Array.from(d.values()));
|
||||||
|
|
||||||
public readonly trashDocs$ = LiveData.from<DocRecord[]>(
|
public readonly trashDocs$ = LiveData.from<DocRecord[]>(
|
||||||
this.store.watchTrashDocIds().pipe(
|
this.store.watchTrashDocIds().pipe(
|
||||||
map(ids =>
|
map(ids =>
|
||||||
@@ -53,7 +58,7 @@ export class DocRecordList extends Entity {
|
|||||||
);
|
);
|
||||||
|
|
||||||
public doc$(id: string) {
|
public doc$(id: string) {
|
||||||
return this.docs$.map(record => record.find(record => record.id === id));
|
return this.docsMap$.selector(map => map.get(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPrimaryMode(id: string, mode: DocMode) {
|
public setPrimaryMode(id: string, mode: DocMode) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class DocsStore extends Store {
|
|||||||
switchMap(yjsObserve),
|
switchMap(yjsObserve),
|
||||||
map(meta => {
|
map(meta => {
|
||||||
if (meta instanceof YArray) {
|
if (meta instanceof YArray) {
|
||||||
return meta.map(v => v.get('id'));
|
return meta.map(v => v.get('id') as string);
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,7 @@ export class DocsStore extends Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watchDocMeta(id: string) {
|
watchDocMeta(id: string) {
|
||||||
|
let docMetaIndexCache = -1;
|
||||||
return yjsObserveByPath(
|
return yjsObserveByPath(
|
||||||
this.workspaceService.workspace.rootYDoc.getMap('meta'),
|
this.workspaceService.workspace.rootYDoc.getMap('meta'),
|
||||||
'pages'
|
'pages'
|
||||||
@@ -66,13 +67,23 @@ export class DocsStore extends Store {
|
|||||||
switchMap(yjsObserve),
|
switchMap(yjsObserve),
|
||||||
map(meta => {
|
map(meta => {
|
||||||
if (meta instanceof YArray) {
|
if (meta instanceof YArray) {
|
||||||
let docMetaYMap = null as YMap<any> | null;
|
if (docMetaIndexCache >= 0) {
|
||||||
meta.forEach(doc => {
|
const doc = meta.get(docMetaIndexCache);
|
||||||
if (doc.get('id') === id) {
|
if (doc && doc.get('id') === id) {
|
||||||
docMetaYMap = doc;
|
return doc as YMap<any>;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return docMetaYMap;
|
|
||||||
|
// meta is YArray, `for-of` is faster then `for`
|
||||||
|
let i = 0;
|
||||||
|
for (const doc of meta) {
|
||||||
|
if (doc && doc.get('id') === id) {
|
||||||
|
docMetaIndexCache = i;
|
||||||
|
return doc as YMap<any>;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
AttachmentBlockService,
|
AttachmentBlockService,
|
||||||
AttachmentBlockSpec,
|
AttachmentBlockSpec,
|
||||||
|
ImageBlockService,
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import bytes from 'bytes';
|
import bytes from 'bytes';
|
||||||
|
|
||||||
@@ -19,6 +20,15 @@ class CustomAttachmentBlockService extends AttachmentBlockService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CustomImageBlockService extends ImageBlockService {
|
||||||
|
override mounted(): void {
|
||||||
|
// blocksuite default max file size is 10MB, we override it to 2GB
|
||||||
|
// but the real place to limit blob size is CloudQuotaModal / LocalQuotaModal
|
||||||
|
this.maxFileSize = bytes.parse('2GB');
|
||||||
|
super.mounted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const CustomAttachmentBlockSpec: ExtensionType[] = [
|
export const CustomAttachmentBlockSpec: ExtensionType[] = [
|
||||||
...AttachmentBlockSpec,
|
...AttachmentBlockSpec,
|
||||||
{
|
{
|
||||||
@@ -28,6 +38,11 @@ export const CustomAttachmentBlockSpec: ExtensionType[] = [
|
|||||||
CustomAttachmentBlockService,
|
CustomAttachmentBlockService,
|
||||||
[StdIdentifier, BlockFlavourIdentifier('affine:attachment')]
|
[StdIdentifier, BlockFlavourIdentifier('affine:attachment')]
|
||||||
);
|
);
|
||||||
|
di.override(
|
||||||
|
BlockServiceIdentifier('affine:image'),
|
||||||
|
CustomImageBlockService,
|
||||||
|
[StdIdentifier, BlockFlavourIdentifier('affine:image')]
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Button } from '@affine/component';
|
import { Button } from '@affine/component';
|
||||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
|
||||||
import { SubscriptionRecurring } from '@affine/graphql';
|
import { SubscriptionRecurring } from '@affine/graphql';
|
||||||
import { Trans, useI18n } from '@affine/i18n';
|
import { Trans, useI18n } from '@affine/i18n';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
|
||||||
import { Upgrade } from '../plan-card';
|
import { SignUpAction, Upgrade } from '../plan-card';
|
||||||
import { BelieverCard } from './believer-card';
|
import { BelieverCard } from './believer-card';
|
||||||
import { BelieverBenefits } from './benefits';
|
import { BelieverBenefits } from './benefits';
|
||||||
import * as styles from './style.css';
|
import * as styles from './style.css';
|
||||||
@@ -12,6 +12,8 @@ import * as styles from './style.css';
|
|||||||
export const LifetimePlan = () => {
|
export const LifetimePlan = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const subscriptionService = useService(SubscriptionService);
|
const subscriptionService = useService(SubscriptionService);
|
||||||
|
const loggedIn =
|
||||||
|
useLiveData(useService(AuthService).session.status$) === 'authenticated';
|
||||||
|
|
||||||
const readableLifetimePrice = useLiveData(
|
const readableLifetimePrice = useLiveData(
|
||||||
subscriptionService.prices.readableLifetimePrice$
|
subscriptionService.prices.readableLifetimePrice$
|
||||||
@@ -32,7 +34,11 @@ export const LifetimePlan = () => {
|
|||||||
|
|
||||||
<div className={styles.price}>{readableLifetimePrice}</div>
|
<div className={styles.price}>{readableLifetimePrice}</div>
|
||||||
|
|
||||||
{isBeliever ? (
|
{!loggedIn ? (
|
||||||
|
<SignUpAction className={styles.purchase}>
|
||||||
|
{t['com.affine.payment.sign-up-free']()}
|
||||||
|
</SignUpAction>
|
||||||
|
) : isBeliever ? (
|
||||||
<Button className={styles.purchase} size="default" disabled>
|
<Button className={styles.purchase} size="default" disabled>
|
||||||
{t['com.affine.payment.lifetime.purchased']()}
|
{t['com.affine.payment.lifetime.purchased']()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -383,7 +383,10 @@ const ChangeRecurring = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SignUpAction = ({ children }: PropsWithChildren) => {
|
export const SignUpAction = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: PropsWithChildren<{ className?: string }>) => {
|
||||||
const setOpen = useSetAtom(authAtom);
|
const setOpen = useSetAtom(authAtom);
|
||||||
|
|
||||||
const onClickSignIn = useCallback(() => {
|
const onClickSignIn = useCallback(() => {
|
||||||
@@ -396,7 +399,7 @@ const SignUpAction = ({ children }: PropsWithChildren) => {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={onClickSignIn}
|
onClick={onClickSignIn}
|
||||||
className={styles.planAction}
|
className={clsx(styles.planAction, className)}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { OpenInAppPage } from '@affine/core/modules/open-in-app/views/open-in-app-page';
|
import { OpenInAppPage } from '@affine/core/modules/open-in-app/views/open-in-app-page';
|
||||||
import { appSchemes } from '@affine/core/utils/channel';
|
import { appSchemes, channelToScheme } from '@affine/core/utils/channel';
|
||||||
import type { GetCurrentUserQuery } from '@affine/graphql';
|
import type { GetCurrentUserQuery } from '@affine/graphql';
|
||||||
import { fetcher, getCurrentUserQuery } from '@affine/graphql';
|
import { fetcher, getCurrentUserQuery } from '@affine/graphql';
|
||||||
import type { LoaderFunction } from 'react-router-dom';
|
import type { LoaderFunction } from 'react-router-dom';
|
||||||
@@ -37,7 +37,9 @@ const OpenOAuthJwt = () => {
|
|||||||
const [params] = useSearchParams();
|
const [params] = useSearchParams();
|
||||||
|
|
||||||
const maybeScheme = appSchemes.safeParse(params.get('scheme'));
|
const maybeScheme = appSchemes.safeParse(params.get('scheme'));
|
||||||
const scheme = maybeScheme.success ? maybeScheme.data : 'affine';
|
const scheme = maybeScheme.success
|
||||||
|
? maybeScheme.data
|
||||||
|
: channelToScheme[BUILD_CONFIG.appBuildType];
|
||||||
const next = params.get('next');
|
const next = params.get('next');
|
||||||
|
|
||||||
if (!currentUser || !currentUser?.token?.sessionToken) {
|
if (!currentUser || !currentUser?.token?.sessionToken) {
|
||||||
|
|||||||
Reference in New Issue
Block a user