Skip to content

Commit

Permalink
feat(core): expose toggle ai onboarding apis (#7039)
Browse files Browse the repository at this point in the history
```ts
import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onboarding/apis';

// show
// toggleGeneralAIOnboarding();
toggleGeneralAIOnboarding(true);

// dismiss
toggleGeneralAIOnboarding(false);
```
  • Loading branch information
CatsJuice committed May 28, 2024
1 parent aa4fa44 commit f4fdbbe
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 49 deletions.
38 changes: 38 additions & 0 deletions packages/frontend/core/src/components/affine/ai-onboarding/apis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AIOnboardingType } from './type';

function createStorageEvent(key: string, newValue: string) {
const event = new StorageEvent('storage', {
key,
newValue,
oldValue: localStorage.getItem(key),
storageArea: localStorage,
});
window.dispatchEvent(event);
}

const setItem = function (key: string, value: string) {
const oldValue = localStorage.getItem(key);
localStorage.setItem.call(localStorage, key, value);
if (oldValue !== value) createStorageEvent(key, value);
};

/**
* Show/Hide AI onboarding manually
*/
export const toggleGeneralAIOnboarding = (show = true) => {
setItem(AIOnboardingType.GENERAL, show ? 'false' : 'true');
};

/**
* Show/Hide local AI toast manually
*/
export const toggleLocalAIOnboarding = (show = true) => {
setItem(AIOnboardingType.LOCAL, show ? 'false' : 'true');
};

/**
* Show/Hide edgeless AI toast manually
*/
export const toggleEdgelessAIOnboarding = (show = true) => {
setItem(AIOnboardingType.EDGELESS, show ? 'false' : 'true');
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Button, FlexWrapper, notify } from '@affine/component';
import { openSettingModalAtom } from '@affine/core/atoms';
import { SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { AiIcon } from '@blocksuite/icons';
import {
Expand All @@ -17,6 +16,7 @@ import Lottie from 'lottie-react';
import { useTheme } from 'next-themes';
import { useCallback, useEffect, useMemo, useRef } from 'react';

import { toggleEdgelessAIOnboarding } from './apis';
import * as styles from './edgeless.dialog.css';
import mouseTrackDark from './lottie/edgeless/mouse-track-dark.json';
import mouseTrackLight from './lottie/edgeless/mouse-track-light.json';
Expand All @@ -25,7 +25,6 @@ import {
localNotifyId$,
showAIOnboardingGeneral$,
} from './state';
import type { BaseAIOnboardingDialogProps } from './type';

const EdgelessOnboardingAnimation = () => {
const { resolvedTheme } = useTheme();
Expand All @@ -46,10 +45,8 @@ const EdgelessOnboardingAnimation = () => {
);
};

export const AIOnboardingEdgeless = ({
onDismiss,
}: BaseAIOnboardingDialogProps) => {
const { workspaceService, docService, subscriptionService } = useServices({
export const AIOnboardingEdgeless = () => {
const { docService, subscriptionService } = useServices({
WorkspaceService,
DocService,
SubscriptionService,
Expand All @@ -61,8 +58,6 @@ export const AIOnboardingEdgeless = ({
const aiSubscription = useLiveData(subscriptionService.subscription.ai$);
const settingModalOpen = useAtomValue(openSettingModalAtom);
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
const isCloud =
workspaceService.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;

const setSettingModal = useSetAtom(openSettingModalAtom);

Expand All @@ -87,7 +82,6 @@ export const AIOnboardingEdgeless = ({
if (generalAIOnboardingOpened) return;
if (notifyId) return;
if (mode !== 'edgeless') return;
if (!isCloud) return;
clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => {
// try to close local onboarding
Expand All @@ -101,13 +95,13 @@ export const AIOnboardingEdgeless = ({
iconColor: cssVar('processingColor'),
thumb: <EdgelessOnboardingAnimation />,
alignMessage: 'icon',
onDismiss,
onDismiss: () => toggleEdgelessAIOnboarding(false),
footer: (
<FlexWrapper marginTop={8} justifyContent="flex-end" gap="12px">
<Button
onClick={() => {
notify.dismiss(id);
onDismiss();
toggleEdgelessAIOnboarding(false);
}}
type="plain"
className={styles.actionButton}
Expand All @@ -123,7 +117,7 @@ export const AIOnboardingEdgeless = ({
onClick={() => {
goToPricingPlans();
notify.dismiss(id);
onDismiss();
toggleEdgelessAIOnboarding(false);
}}
>
<span className={styles.purchaseButtonText}>
Expand All @@ -142,10 +136,8 @@ export const AIOnboardingEdgeless = ({
aiSubscription,
generalAIOnboardingOpened,
goToPricingPlans,
isCloud,
mode,
notifyId,
onDismiss,
settingModalOpen,
t,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import { useAtom } from 'jotai';
import type { ReactNode } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { toggleGeneralAIOnboarding } from './apis';
import * as baseStyles from './base-style.css';
import * as styles from './general.dialog.css';
import { Slider } from './slider';
import { showAIOnboardingGeneral$ } from './state';
import type { BaseAIOnboardingDialogProps } from './type';

type PlayListItem = { video: string; title: ReactNode; desc: ReactNode };
type Translate = ReturnType<typeof useAFFiNEI18N>;
Expand Down Expand Up @@ -82,9 +82,7 @@ function prefetchVideos() {
prefetched = true;
}

export const AIOnboardingGeneral = ({
onDismiss,
}: BaseAIOnboardingDialogProps) => {
export const AIOnboardingGeneral = () => {
const { authService, subscriptionService } = useServices({
AuthService,
SubscriptionService,
Expand All @@ -111,8 +109,8 @@ export const AIOnboardingGeneral = ({
}, []);
const closeAndDismiss = useCallback(() => {
showAIOnboardingGeneral$.next(false);
onDismiss();
}, [onDismiss]);
toggleGeneralAIOnboarding(false);
}, []);
const goToPricingPlans = useCallback(() => {
setSettingModal({
open: true,
Expand Down Expand Up @@ -190,7 +188,7 @@ export const AIOnboardingGeneral = ({
open={open}
onOpenChange={v => {
showAIOnboardingGeneral$.next(v);
if (!v && isLast) onDismiss();
if (!v && isLast) toggleGeneralAIOnboarding(false);
}}
contentOptions={{ className: styles.dialog }}
overlayOptions={{ className: baseStyles.dialogOverlay }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Suspense, useCallback, useState } from 'react';
import { Suspense, useCallback, useEffect, useState } from 'react';

import { AIOnboardingEdgeless } from './edgeless.dialog';
import { AIOnboardingGeneral } from './general.dialog';
Expand All @@ -8,6 +8,15 @@ import { AIOnboardingType } from './type';
const useDismiss = (key: AIOnboardingType) => {
const [dismiss, setDismiss] = useState(localStorage.getItem(key) === 'true');

useEffect(() => {
const handler = (e: StorageEvent) => {
if (e.key !== key) return;
setDismiss(localStorage.getItem(key) === 'true');
};
window.addEventListener('storage', handler);
return () => window.removeEventListener('storage', handler);
}, [key]);

const onDismiss = useCallback(() => {
setDismiss(true);
localStorage.setItem(key, 'true');
Expand All @@ -17,32 +26,21 @@ const useDismiss = (key: AIOnboardingType) => {
};

export const WorkspaceAIOnboarding = () => {
const [dismissGeneral, onDismissGeneral] = useDismiss(
AIOnboardingType.GENERAL
);
const [dismissLocal, onDismissLocal] = useDismiss(AIOnboardingType.LOCAL);
const [dismissGeneral] = useDismiss(AIOnboardingType.GENERAL);
const [dismissLocal] = useDismiss(AIOnboardingType.LOCAL);

return (
<Suspense>
{dismissGeneral ? null : (
<AIOnboardingGeneral onDismiss={onDismissGeneral} />
)}

{dismissLocal ? null : <AIOnboardingLocal onDismiss={onDismissLocal} />}
{dismissGeneral ? null : <AIOnboardingGeneral />}
{dismissLocal ? null : <AIOnboardingLocal />}
</Suspense>
);
};

export const PageAIOnboarding = () => {
const [dismissEdgeless, onDismissEdgeless] = useDismiss(
AIOnboardingType.EDGELESS
);
const [dismissEdgeless] = useDismiss(AIOnboardingType.EDGELESS);

return (
<Suspense>
{dismissEdgeless ? null : (
<AIOnboardingEdgeless onDismiss={onDismissEdgeless} />
)}
</Suspense>
<Suspense>{dismissEdgeless ? null : <AIOnboardingEdgeless />}</Suspense>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { useLiveData, useService } from '@toeverything/infra';
import { cssVar } from '@toeverything/theme';
import { useEffect, useRef } from 'react';

import { toggleLocalAIOnboarding } from './apis';
import * as styles from './local.dialog.css';
import { edgelessNotifyId$, localNotifyId$ } from './state';
import type { BaseAIOnboardingDialogProps } from './type';

const LocalOnboardingAnimation = () => {
return (
Expand Down Expand Up @@ -63,9 +63,7 @@ const FooterActions = ({ onDismiss }: { onDismiss: () => void }) => {
);
};

export const AIOnboardingLocal = ({
onDismiss,
}: BaseAIOnboardingDialogProps) => {
export const AIOnboardingLocal = () => {
const t = useAFFiNEI18N();
const authService = useService(AuthService);
const notifyId = useLiveData(localNotifyId$);
Expand Down Expand Up @@ -94,11 +92,11 @@ export const AIOnboardingLocal = ({
iconColor: cssVar('brandColor'),
thumb: <LocalOnboardingAnimation />,
alignMessage: 'icon',
onDismiss,
onDismiss: () => toggleLocalAIOnboarding(false),
footer: (
<FooterActions
onDismiss={() => {
onDismiss();
toggleLocalAIOnboarding(false);
notify.dismiss(id);
}}
/>
Expand All @@ -109,7 +107,7 @@ export const AIOnboardingLocal = ({
);
localNotifyId$.next(id);
}, 1000);
}, [notSignedIn, notifyId, onDismiss, t]);
}, [notSignedIn, notifyId, t]);

return null;
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
export interface BaseAIOnboardingDialogProps {
onDismiss: () => void;
}
export enum AIOnboardingType {
GENERAL = 'dismissAiOnboarding',
EDGELESS = 'dismissAiOnboardingEdgeless',
Expand Down

0 comments on commit f4fdbbe

Please sign in to comment.