refactor(core): replace all notification relies on jotai (#6417)

- remove all notification that implemented with jotai and replaced with new `notify`
- Add some notify presets:
  - `notify.error`
  - `notify.success`
  - `notify.warning`
This commit is contained in:
CatsJuice
2024-04-02 03:19:06 +00:00
parent a4cd51e503
commit 9127bfae67
24 changed files with 150 additions and 201 deletions

View File

@@ -1,11 +1,10 @@
import type { PasswordLimitsFragment } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useSetAtom } from 'jotai';
import type { FC } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '../../ui/button';
import { pushNotificationAtom } from '../notification-center';
import { notify } from '../../ui/notification';
import { AuthPageContainer } from './auth-page-container';
import { SetPassword } from './set-password';
import type { User } from './type';
@@ -23,22 +22,19 @@ export const ChangePasswordPage: FC<{
}) => {
const t = useAFFiNEI18N();
const [hasSetUp, setHasSetUp] = useState(false);
const pushNotification = useSetAtom(pushNotificationAtom);
const onSetPassword = useCallback(
(passWord: string) => {
propsOnSetPassword(passWord)
.then(() => setHasSetUp(true))
.catch(e =>
pushNotification({
notify.error({
title: t['com.affine.auth.password.set-failed'](),
message: String(e),
key: Date.now().toString(),
type: 'error',
})
);
},
[propsOnSetPassword, t, pushNotification]
[propsOnSetPassword, t]
);
return (

View File

@@ -1,11 +1,10 @@
import type { PasswordLimitsFragment } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useSetAtom } from 'jotai';
import type { FC } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '../../ui/button';
import { pushNotificationAtom } from '../notification-center';
import { notify } from '../../ui/notification';
import { AuthPageContainer } from './auth-page-container';
import { SetPassword } from './set-password';
import type { User } from './type';
@@ -23,22 +22,19 @@ export const SetPasswordPage: FC<{
}) => {
const t = useAFFiNEI18N();
const [hasSetUp, setHasSetUp] = useState(false);
const pushNotification = useSetAtom(pushNotificationAtom);
const onSetPassword = useCallback(
(passWord: string) => {
propsOnSetPassword(passWord)
.then(() => setHasSetUp(true))
.catch(e =>
pushNotification({
notify.error({
title: t['com.affine.auth.password.set-failed'](),
message: String(e),
key: Date.now().toString(),
type: 'error',
})
);
},
[propsOnSetPassword, pushNotification, t]
[propsOnSetPassword, t]
);
return (

View File

@@ -1,11 +1,10 @@
import type { PasswordLimitsFragment } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useSetAtom } from 'jotai';
import type { FC } from 'react';
import { useCallback, useState } from 'react';
import { Button } from '../../ui/button';
import { pushNotificationAtom } from '../notification-center';
import { notify } from '../../ui/notification';
import { AuthPageContainer } from './auth-page-container';
import { SetPassword } from './set-password';
import type { User } from './type';
@@ -25,22 +24,19 @@ export const SignUpPage: FC<{
}) => {
const t = useAFFiNEI18N();
const [hasSetUp, setHasSetUp] = useState(false);
const pushNotification = useSetAtom(pushNotificationAtom);
const onSetPassword = useCallback(
(passWord: string) => {
propsOnSetPassword(passWord)
.then(() => setHasSetUp(true))
.catch(e =>
pushNotification({
notify.error({
title: t['com.affine.auth.password.set-failed'](),
message: String(e),
key: Date.now().toString(),
type: 'error',
})
);
},
[propsOnSetPassword, pushNotification, t]
[propsOnSetPassword, t]
);
const onLater = useCallback(() => {
setHasSetUp(true);

View File

@@ -1,6 +1,9 @@
import { atom } from 'jotai';
import { nanoid } from 'nanoid';
/**
* @deprecated use `import type { Notification } from '@affine/component'` instead
*/
export type Notification = {
key?: string;
title: string;
@@ -19,6 +22,9 @@ const notificationsBaseAtom = atom<Notification[]>([]);
const expandNotificationCenterBaseAtom = atom(false);
const cleanupQueueAtom = atom<(() => unknown)[]>([]);
/**
* @deprecated use `import { notify } from '@affine/component'` instead
*/
export const expandNotificationCenterAtom = atom<boolean, [boolean], void>(
get => get(expandNotificationCenterBaseAtom),
(get, set, value) => {
@@ -29,17 +35,24 @@ export const expandNotificationCenterAtom = atom<boolean, [boolean], void>(
set(expandNotificationCenterBaseAtom, value);
}
);
/**
* @deprecated use `import { notify } from '@affine/component'` instead
*/
export const notificationsAtom = atom<Notification[]>(get =>
get(notificationsBaseAtom)
);
/**
* @deprecated use `import { notify } from '@affine/component'` instead
*/
export const removeNotificationAtom = atom(null, (_, set, key: string) => {
set(notificationsBaseAtom, notifications =>
notifications.filter(notification => notification.key !== key)
);
});
/**
* @deprecated use `import { notify } from '@affine/component'` instead
*/
export const pushNotificationAtom = atom<null, [Notification], void>(
null,
(_, set, newNotification) => {

View File

@@ -375,6 +375,9 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
);
}
/**
* @deprecated use `import { NotificationCenter } from '@affine/component'` instead
*/
export function NotificationCenter(): ReactNode {
const notifications = useAtomValue(notificationsAtom);
const [expand, setExpand] = useAtom(expandNotificationCenterAtom);

View File

@@ -1,3 +1,4 @@
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import { type CSSProperties, type FC, useMemo } from 'react';
import { type ExternalToast, toast, Toaster } from 'sonner';
@@ -54,6 +55,29 @@ export function notify(notification: Notification, options?: ExternalToast) {
}, options);
}
notify.error = (notification: Notification, options?: ExternalToast) => {
return notify({ style: 'alert', theme: 'error', ...notification }, options);
};
notify.success = (notification: Notification, options?: ExternalToast) => {
return notify(
{
icon: <SingleSelectSelectSolidIcon />,
style: 'alert',
theme: 'success',
...notification,
},
options
);
};
notify.warning = (notification: Notification, options?: ExternalToast) => {
return notify(
{ style: 'information', theme: 'warning', ...notification },
options
);
};
notify.custom = (
Component: FC<NotificationCustomRendererProps>,
options?: ExternalToast