mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(core): check user's subscription at ai onboarding stage (#6608)
This commit is contained in:
@@ -47,15 +47,19 @@ export const video = style({
|
||||
height: 'calc(100% + 4px)',
|
||||
});
|
||||
|
||||
export const mainContent = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4,
|
||||
padding: '20px 24px 0px 24px',
|
||||
});
|
||||
export const title = style({
|
||||
padding: '20px 24px 8px 24px',
|
||||
fontSize: cssVar('fontH6'),
|
||||
fontWeight: 600,
|
||||
lineHeight: '26px',
|
||||
color: cssVar('textPrimaryColor'),
|
||||
});
|
||||
export const description = style({
|
||||
padding: '0px 24px',
|
||||
fontSize: cssVar('fontBase'),
|
||||
lineHeight: '24px',
|
||||
minHeight: 48,
|
||||
@@ -66,14 +70,45 @@ export const link = style({
|
||||
color: cssVar('textEmphasisColor'),
|
||||
textDecoration: 'underline',
|
||||
});
|
||||
export const privacy = style({
|
||||
padding: '20px 24px 0px 24px',
|
||||
color: cssVar('textSecondaryColor'),
|
||||
fontSize: cssVar('fontXs'),
|
||||
fontWeight: 400,
|
||||
lineHeight: '20px',
|
||||
height: 44,
|
||||
transition: 'all 0.3s',
|
||||
overflow: 'hidden',
|
||||
|
||||
selectors: {
|
||||
'&[aria-hidden="true"]': {
|
||||
paddingTop: 0,
|
||||
height: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
export const privacyLink = style({
|
||||
color: 'inherit',
|
||||
textDecoration: 'underline',
|
||||
});
|
||||
|
||||
export const footer = style({
|
||||
width: '100%',
|
||||
padding: '20px 28px',
|
||||
gap: 12,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
justifyContent: 'space-between',
|
||||
selectors: {
|
||||
'&[data-is-last="true"], &[data-is-first="true"]': {
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const skipButton = style({
|
||||
fontWeight: 500,
|
||||
export const baseActionButton = style({
|
||||
fontSize: cssVar('fontBase'),
|
||||
selectors: {
|
||||
'&.large': {
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Button, Modal } from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { useBlurRoot } from '@affine/core/hooks/use-blur-root';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowLeftSmallIcon } from '@blocksuite/icons';
|
||||
import {
|
||||
useLiveData,
|
||||
useServices,
|
||||
@@ -68,7 +70,10 @@ const getPlayList = (t: Translate): Array<PlayListItem> => [
|
||||
export const AIOnboardingGeneral = ({
|
||||
onDismiss,
|
||||
}: BaseAIOnboardingDialogProps) => {
|
||||
const { workspaceService } = useServices({ WorkspaceService });
|
||||
const { workspaceService, subscriptionService } = useServices({
|
||||
WorkspaceService,
|
||||
SubscriptionService,
|
||||
});
|
||||
|
||||
const videoWrapperRef = useRef<HTMLDivElement | null>(null);
|
||||
const prevVideoRef = useRef<HTMLVideoElement | null>(null);
|
||||
@@ -76,6 +81,7 @@ export const AIOnboardingGeneral = ({
|
||||
workspaceService.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;
|
||||
const t = useAFFiNEI18N();
|
||||
const open = useLiveData(showAIOnboardingGeneral$);
|
||||
const aiSubscription = useLiveData(subscriptionService.subscription.ai$);
|
||||
const [index, setIndex] = useState(0);
|
||||
const list = useMemo(() => getPlayList(t), [t]);
|
||||
const setSettingModal = useSetAtom(openSettingModalAtom);
|
||||
@@ -96,7 +102,6 @@ export const AIOnboardingGeneral = ({
|
||||
});
|
||||
closeAndDismiss();
|
||||
}, [closeAndDismiss, setSettingModal]);
|
||||
const onClose = useCallback(() => showAIOnboardingGeneral$.next(false), []);
|
||||
const onPrev = useCallback(() => {
|
||||
setIndex(i => Math.max(0, i - 1));
|
||||
}, []);
|
||||
@@ -104,6 +109,10 @@ export const AIOnboardingGeneral = ({
|
||||
setIndex(i => Math.min(list.length - 1, i + 1));
|
||||
}, [list.length]);
|
||||
|
||||
useEffect(() => {
|
||||
subscriptionService.subscription.revalidate();
|
||||
}, [subscriptionService]);
|
||||
|
||||
const videoRenderer = useCallback(
|
||||
({ video }: PlayListItem, index: number) => (
|
||||
<div className={styles.videoWrapper}>
|
||||
@@ -152,7 +161,10 @@ export const AIOnboardingGeneral = ({
|
||||
return isCloud ? (
|
||||
<Modal
|
||||
open={open}
|
||||
onOpenChange={v => showAIOnboardingGeneral$.next(v)}
|
||||
onOpenChange={v => {
|
||||
showAIOnboardingGeneral$.next(v);
|
||||
if (!v && isLast) onDismiss();
|
||||
}}
|
||||
contentOptions={{ className: styles.dialog }}
|
||||
overlayOptions={{ className: baseStyles.dialogOverlay }}
|
||||
>
|
||||
@@ -166,7 +178,7 @@ export const AIOnboardingGeneral = ({
|
||||
itemRenderer={videoRenderer}
|
||||
/>
|
||||
|
||||
<main>
|
||||
<main className={styles.mainContent}>
|
||||
<Slider<PlayListItem>
|
||||
items={list}
|
||||
activeIndex={index}
|
||||
@@ -181,28 +193,76 @@ export const AIOnboardingGeneral = ({
|
||||
/>
|
||||
</main>
|
||||
|
||||
<footer className={styles.footer}>
|
||||
<section
|
||||
className={styles.privacy}
|
||||
aria-hidden={!isLast || !!aiSubscription}
|
||||
>
|
||||
<Trans
|
||||
i18nKey="com.affine.ai-onboarding.general.privacy"
|
||||
components={{
|
||||
a: (
|
||||
<a
|
||||
className={styles.privacyLink}
|
||||
href="https://ai.affine.pro"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<footer
|
||||
className={styles.footer}
|
||||
data-is-last={isLast}
|
||||
data-is-first={isFirst}
|
||||
>
|
||||
{isLast ? (
|
||||
<>
|
||||
<Button onClick={closeAndDismiss}>
|
||||
{t['com.affine.ai-onboarding.general.try-for-free']()}
|
||||
aiSubscription ? (
|
||||
<Button
|
||||
className={styles.baseActionButton}
|
||||
size="large"
|
||||
onClick={closeAndDismiss}
|
||||
type="primary"
|
||||
>
|
||||
{t['com.affine.ai-onboarding.general.get-started']()}
|
||||
</Button>
|
||||
<Button onClick={goToPricingPlans} type="primary">
|
||||
{t['com.affine.ai-onboarding.general.purchase']()}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
className={styles.baseActionButton}
|
||||
size="large"
|
||||
onClick={closeAndDismiss}
|
||||
>
|
||||
{t['com.affine.ai-onboarding.general.try-for-free']()}
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.baseActionButton}
|
||||
size="large"
|
||||
onClick={goToPricingPlans}
|
||||
type="primary"
|
||||
>
|
||||
{t['com.affine.ai-onboarding.general.purchase']()}
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{isFirst ? (
|
||||
<Button onClick={onClose} className={styles.skipButton}>
|
||||
{t['com.affine.ai-onboarding.general.skip']()}
|
||||
</Button>
|
||||
) : (
|
||||
<Button onClick={onPrev}>
|
||||
{isFirst ? null : (
|
||||
<Button
|
||||
icon={<ArrowLeftSmallIcon />}
|
||||
className={styles.baseActionButton}
|
||||
onClick={onPrev}
|
||||
type="plain"
|
||||
size="large"
|
||||
>
|
||||
{t['com.affine.ai-onboarding.general.prev']()}
|
||||
</Button>
|
||||
)}
|
||||
<Button type="primary" onClick={onNext}>
|
||||
<Button
|
||||
className={styles.baseActionButton}
|
||||
size="large"
|
||||
type="primary"
|
||||
onClick={onNext}
|
||||
>
|
||||
{t['com.affine.ai-onboarding.general.next']()}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -1297,6 +1297,12 @@
|
||||
"com.affine.ai-onboarding.general.prev": "Back",
|
||||
"com.affine.ai-onboarding.general.try-for-free": "Try for Free",
|
||||
"com.affine.ai-onboarding.general.purchase": "Get Unlimited Usage",
|
||||
"com.affine.ai-onboarding.general.privacy": "By continuing, you should agree our <a>Terms of Services</a>.",
|
||||
"com.affine.ai-onboarding.general.get-started": "Get Started",
|
||||
"com.affine.ai-onboarding.local.title": "Meet AFFiNE AI",
|
||||
"com.affine.ai-onboarding.local.message": "Lets you think bigger, create faster, work smarter and save time for every project.",
|
||||
"com.affine.ai-onboarding.local.action-dismiss": "Dismiss",
|
||||
"com.affine.ai-onboarding.local.action-learn-more": "Learn More",
|
||||
"com.affine.ai-onboarding.edgeless.title": "Meet AFFiNE AI",
|
||||
"com.affine.ai-onboarding.edgeless.message": "Lets you think bigger, create faster, work smarter and save time for every project."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user