feat(core): check user's subscription at ai onboarding stage (#6608)

This commit is contained in:
CatsJuice
2024-04-18 11:28:06 +00:00
parent e232b0b285
commit 9cb6dcd93d
3 changed files with 126 additions and 25 deletions

View File

@@ -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,
},
},
});

View File

@@ -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>
</>