mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 18:42:58 +03:00
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:
parent
a4cd51e503
commit
9127bfae67
@ -1,11 +1,10 @@
|
|||||||
import type { PasswordLimitsFragment } from '@affine/graphql';
|
import type { PasswordLimitsFragment } from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { Button } from '../../ui/button';
|
import { Button } from '../../ui/button';
|
||||||
import { pushNotificationAtom } from '../notification-center';
|
import { notify } from '../../ui/notification';
|
||||||
import { AuthPageContainer } from './auth-page-container';
|
import { AuthPageContainer } from './auth-page-container';
|
||||||
import { SetPassword } from './set-password';
|
import { SetPassword } from './set-password';
|
||||||
import type { User } from './type';
|
import type { User } from './type';
|
||||||
@ -23,22 +22,19 @@ export const ChangePasswordPage: FC<{
|
|||||||
}) => {
|
}) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const [hasSetUp, setHasSetUp] = useState(false);
|
const [hasSetUp, setHasSetUp] = useState(false);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const onSetPassword = useCallback(
|
const onSetPassword = useCallback(
|
||||||
(passWord: string) => {
|
(passWord: string) => {
|
||||||
propsOnSetPassword(passWord)
|
propsOnSetPassword(passWord)
|
||||||
.then(() => setHasSetUp(true))
|
.then(() => setHasSetUp(true))
|
||||||
.catch(e =>
|
.catch(e =>
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t['com.affine.auth.password.set-failed'](),
|
title: t['com.affine.auth.password.set-failed'](),
|
||||||
message: String(e),
|
message: String(e),
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'error',
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[propsOnSetPassword, t, pushNotification]
|
[propsOnSetPassword, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { PasswordLimitsFragment } from '@affine/graphql';
|
import type { PasswordLimitsFragment } from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { Button } from '../../ui/button';
|
import { Button } from '../../ui/button';
|
||||||
import { pushNotificationAtom } from '../notification-center';
|
import { notify } from '../../ui/notification';
|
||||||
import { AuthPageContainer } from './auth-page-container';
|
import { AuthPageContainer } from './auth-page-container';
|
||||||
import { SetPassword } from './set-password';
|
import { SetPassword } from './set-password';
|
||||||
import type { User } from './type';
|
import type { User } from './type';
|
||||||
@ -23,22 +22,19 @@ export const SetPasswordPage: FC<{
|
|||||||
}) => {
|
}) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const [hasSetUp, setHasSetUp] = useState(false);
|
const [hasSetUp, setHasSetUp] = useState(false);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const onSetPassword = useCallback(
|
const onSetPassword = useCallback(
|
||||||
(passWord: string) => {
|
(passWord: string) => {
|
||||||
propsOnSetPassword(passWord)
|
propsOnSetPassword(passWord)
|
||||||
.then(() => setHasSetUp(true))
|
.then(() => setHasSetUp(true))
|
||||||
.catch(e =>
|
.catch(e =>
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t['com.affine.auth.password.set-failed'](),
|
title: t['com.affine.auth.password.set-failed'](),
|
||||||
message: String(e),
|
message: String(e),
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'error',
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[propsOnSetPassword, pushNotification, t]
|
[propsOnSetPassword, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { PasswordLimitsFragment } from '@affine/graphql';
|
import type { PasswordLimitsFragment } from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { Button } from '../../ui/button';
|
import { Button } from '../../ui/button';
|
||||||
import { pushNotificationAtom } from '../notification-center';
|
import { notify } from '../../ui/notification';
|
||||||
import { AuthPageContainer } from './auth-page-container';
|
import { AuthPageContainer } from './auth-page-container';
|
||||||
import { SetPassword } from './set-password';
|
import { SetPassword } from './set-password';
|
||||||
import type { User } from './type';
|
import type { User } from './type';
|
||||||
@ -25,22 +24,19 @@ export const SignUpPage: FC<{
|
|||||||
}) => {
|
}) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const [hasSetUp, setHasSetUp] = useState(false);
|
const [hasSetUp, setHasSetUp] = useState(false);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const onSetPassword = useCallback(
|
const onSetPassword = useCallback(
|
||||||
(passWord: string) => {
|
(passWord: string) => {
|
||||||
propsOnSetPassword(passWord)
|
propsOnSetPassword(passWord)
|
||||||
.then(() => setHasSetUp(true))
|
.then(() => setHasSetUp(true))
|
||||||
.catch(e =>
|
.catch(e =>
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t['com.affine.auth.password.set-failed'](),
|
title: t['com.affine.auth.password.set-failed'](),
|
||||||
message: String(e),
|
message: String(e),
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'error',
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[propsOnSetPassword, pushNotification, t]
|
[propsOnSetPassword, t]
|
||||||
);
|
);
|
||||||
const onLater = useCallback(() => {
|
const onLater = useCallback(() => {
|
||||||
setHasSetUp(true);
|
setHasSetUp(true);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { atom } from 'jotai';
|
import { atom } from 'jotai';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `import type { Notification } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export type Notification = {
|
export type Notification = {
|
||||||
key?: string;
|
key?: string;
|
||||||
title: string;
|
title: string;
|
||||||
@ -19,6 +22,9 @@ const notificationsBaseAtom = atom<Notification[]>([]);
|
|||||||
|
|
||||||
const expandNotificationCenterBaseAtom = atom(false);
|
const expandNotificationCenterBaseAtom = atom(false);
|
||||||
const cleanupQueueAtom = atom<(() => unknown)[]>([]);
|
const cleanupQueueAtom = atom<(() => unknown)[]>([]);
|
||||||
|
/**
|
||||||
|
* @deprecated use `import { notify } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export const expandNotificationCenterAtom = atom<boolean, [boolean], void>(
|
export const expandNotificationCenterAtom = atom<boolean, [boolean], void>(
|
||||||
get => get(expandNotificationCenterBaseAtom),
|
get => get(expandNotificationCenterBaseAtom),
|
||||||
(get, set, value) => {
|
(get, set, value) => {
|
||||||
@ -29,17 +35,24 @@ export const expandNotificationCenterAtom = atom<boolean, [boolean], void>(
|
|||||||
set(expandNotificationCenterBaseAtom, value);
|
set(expandNotificationCenterBaseAtom, value);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
|
* @deprecated use `import { notify } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export const notificationsAtom = atom<Notification[]>(get =>
|
export const notificationsAtom = atom<Notification[]>(get =>
|
||||||
get(notificationsBaseAtom)
|
get(notificationsBaseAtom)
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
|
* @deprecated use `import { notify } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export const removeNotificationAtom = atom(null, (_, set, key: string) => {
|
export const removeNotificationAtom = atom(null, (_, set, key: string) => {
|
||||||
set(notificationsBaseAtom, notifications =>
|
set(notificationsBaseAtom, notifications =>
|
||||||
notifications.filter(notification => notification.key !== key)
|
notifications.filter(notification => notification.key !== key)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `import { notify } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export const pushNotificationAtom = atom<null, [Notification], void>(
|
export const pushNotificationAtom = atom<null, [Notification], void>(
|
||||||
null,
|
null,
|
||||||
(_, set, newNotification) => {
|
(_, set, newNotification) => {
|
||||||
|
@ -375,6 +375,9 @@ function NotificationCard(props: NotificationCardProps): ReactNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use `import { NotificationCenter } from '@affine/component'` instead
|
||||||
|
*/
|
||||||
export function NotificationCenter(): ReactNode {
|
export function NotificationCenter(): ReactNode {
|
||||||
const notifications = useAtomValue(notificationsAtom);
|
const notifications = useAtomValue(notificationsAtom);
|
||||||
const [expand, setExpand] = useAtom(expandNotificationCenterAtom);
|
const [expand, setExpand] = useAtom(expandNotificationCenterAtom);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons';
|
||||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
import { type CSSProperties, type FC, useMemo } from 'react';
|
import { type CSSProperties, type FC, useMemo } from 'react';
|
||||||
import { type ExternalToast, toast, Toaster } from 'sonner';
|
import { type ExternalToast, toast, Toaster } from 'sonner';
|
||||||
@ -54,6 +55,29 @@ export function notify(notification: Notification, options?: ExternalToast) {
|
|||||||
}, options);
|
}, 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 = (
|
notify.custom = (
|
||||||
Component: FC<NotificationCustomRendererProps>,
|
Component: FC<NotificationCustomRendererProps>,
|
||||||
options?: ExternalToast
|
options?: ExternalToast
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Wrapper } from '@affine/component';
|
import { notify, Wrapper } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
AuthContent,
|
AuthContent,
|
||||||
AuthInput,
|
AuthInput,
|
||||||
BackButton,
|
BackButton,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
} from '@affine/component/auth-components';
|
} from '@affine/component/auth-components';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { Button } from '@affine/component/ui/button';
|
import { Button } from '@affine/component/ui/button';
|
||||||
import { useCredentialsRequirement } from '@affine/core/hooks/affine/use-server-config';
|
import { useCredentialsRequirement } from '@affine/core/hooks/affine/use-server-config';
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
@ -17,7 +16,6 @@ import {
|
|||||||
sendVerifyEmailMutation,
|
sendVerifyEmailMutation,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai/react';
|
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { useMutation } from '../../../hooks/use-mutation';
|
import { useMutation } from '../../../hooks/use-mutation';
|
||||||
@ -165,7 +163,6 @@ export const SendEmail = ({
|
|||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const { password: passwordLimits } = useCredentialsRequirement();
|
const { password: passwordLimits } = useCredentialsRequirement();
|
||||||
const [hasSentEmail, setHasSentEmail] = useState(false);
|
const [hasSentEmail, setHasSentEmail] = useState(false);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const title = useEmailTitle(emailType);
|
const title = useEmailTitle(emailType);
|
||||||
const hint = useNotificationHint(emailType);
|
const hint = useNotificationHint(emailType);
|
||||||
@ -177,14 +174,9 @@ export const SendEmail = ({
|
|||||||
// TODO: add error handler
|
// TODO: add error handler
|
||||||
await sendEmail(email);
|
await sendEmail(email);
|
||||||
|
|
||||||
pushNotification({
|
notify.success({ title: hint });
|
||||||
title: hint,
|
|
||||||
message: '',
|
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
setHasSentEmail(true);
|
setHasSentEmail(true);
|
||||||
}, [email, hint, pushNotification, sendEmail]);
|
}, [email, hint, sendEmail]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import type { Notification } from '@affine/component/notification-center/index.jotai';
|
|
||||||
import type { OAuthProviderType } from '@affine/graphql';
|
import type { OAuthProviderType } from '@affine/graphql';
|
||||||
import { atom, useAtom, useSetAtom } from 'jotai';
|
import { atom, useAtom, useSetAtom } from 'jotai';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
@ -10,19 +9,6 @@ import { useSubscriptionSearch } from './use-subscription';
|
|||||||
const COUNT_DOWN_TIME = 60;
|
const COUNT_DOWN_TIME = 60;
|
||||||
export const INTERNAL_BETA_URL = `https://community.affine.pro/c/insider-general/`;
|
export const INTERNAL_BETA_URL = `https://community.affine.pro/c/insider-general/`;
|
||||||
|
|
||||||
function handleSendEmailError(
|
|
||||||
res: Response | undefined | void,
|
|
||||||
pushNotification: (notification: Notification) => void
|
|
||||||
) {
|
|
||||||
if (!res?.ok) {
|
|
||||||
pushNotification({
|
|
||||||
title: 'Send email error',
|
|
||||||
message: 'Please back to home and try again',
|
|
||||||
type: 'error',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthStoreAtom = {
|
type AuthStoreAtom = {
|
||||||
allowSendEmail: boolean;
|
allowSendEmail: boolean;
|
||||||
resendCountDown: number;
|
resendCountDown: number;
|
||||||
@ -60,7 +46,6 @@ const countDownAtom = atom(
|
|||||||
|
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
const subscriptionData = useSubscriptionSearch();
|
const subscriptionData = useSubscriptionSearch();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const [authStore, setAuthStore] = useAtom(authStoreAtom);
|
const [authStore, setAuthStore] = useAtom(authStoreAtom);
|
||||||
const startResendCountDown = useSetAtom(countDownAtom);
|
const startResendCountDown = useSetAtom(countDownAtom);
|
||||||
|
|
||||||
@ -96,7 +81,13 @@ export const useAuth = () => {
|
|||||||
}
|
}
|
||||||
).catch(console.error);
|
).catch(console.error);
|
||||||
|
|
||||||
handleSendEmailError(res, pushNotification);
|
if (!res?.ok) {
|
||||||
|
// TODO: i18n
|
||||||
|
notify.error({
|
||||||
|
title: 'Send email error',
|
||||||
|
message: 'Please back to home and try again',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setAuthStore({
|
setAuthStore({
|
||||||
isMutating: false,
|
isMutating: false,
|
||||||
@ -104,11 +95,12 @@ export const useAuth = () => {
|
|||||||
resendCountDown: COUNT_DOWN_TIME,
|
resendCountDown: COUNT_DOWN_TIME,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: when errored, should reset the count down
|
||||||
startResendCountDown();
|
startResendCountDown();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[pushNotification, setAuthStore, startResendCountDown, subscriptionData]
|
[setAuthStore, startResendCountDown, subscriptionData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const signUp = useCallback(
|
const signUp = useCallback(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { FlexWrapper, Input } from '@affine/component';
|
import { FlexWrapper, Input, notify } from '@affine/component';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import {
|
import {
|
||||||
SettingHeader,
|
SettingHeader,
|
||||||
SettingRow,
|
SettingRow,
|
||||||
@ -35,7 +34,6 @@ import * as styles from './style.css';
|
|||||||
export const UserAvatar = () => {
|
export const UserAvatar = () => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const user = useCurrentUser();
|
const user = useCurrentUser();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const { trigger: avatarTrigger } = useMutation({
|
const { trigger: avatarTrigger } = useMutation({
|
||||||
mutation: uploadAvatarMutation,
|
mutation: uploadAvatarMutation,
|
||||||
@ -55,19 +53,17 @@ export const UserAvatar = () => {
|
|||||||
avatar: reducedFile, // Pass the reducedFile directly to the avatarTrigger
|
avatar: reducedFile, // Pass the reducedFile directly to the avatarTrigger
|
||||||
});
|
});
|
||||||
user.update({ avatarUrl: data.uploadAvatar.avatarUrl });
|
user.update({ avatarUrl: data.uploadAvatar.avatarUrl });
|
||||||
pushNotification({
|
// TODO: i18n
|
||||||
title: 'Update user avatar success',
|
notify.success({ title: 'Update user avatar success' });
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
pushNotification({
|
// TODO: i18n
|
||||||
|
notify.error({
|
||||||
title: 'Update user avatar failed',
|
title: 'Update user avatar failed',
|
||||||
message: String(e),
|
message: String(e),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[avatarTrigger, pushNotification, user]
|
[avatarTrigger, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRemoveUserAvatar = useCallback(
|
const handleRemoveUserAvatar = useCallback(
|
||||||
@ -109,7 +105,6 @@ export const AvatarAndName = () => {
|
|||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const user = useCurrentUser();
|
const user = useCurrentUser();
|
||||||
const [input, setInput] = useState<string>(user.name);
|
const [input, setInput] = useState<string>(user.name);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const { trigger: updateProfile } = useMutation({
|
const { trigger: updateProfile } = useMutation({
|
||||||
mutation: updateUserProfileMutation,
|
mutation: updateUserProfileMutation,
|
||||||
@ -129,13 +124,12 @@ export const AvatarAndName = () => {
|
|||||||
});
|
});
|
||||||
user.update({ name: data.updateProfile.name });
|
user.update({ name: data.updateProfile.name });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: 'Failed to update user name.',
|
title: 'Failed to update user name.',
|
||||||
message: String(e),
|
message: String(e),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [allowUpdate, input, user, updateProfile, pushNotification]);
|
}, [allowUpdate, input, user, updateProfile]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingRow
|
<SettingRow
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { RadioButton, RadioButtonGroup } from '@affine/component';
|
import { notify, RadioButton, RadioButtonGroup } from '@affine/component';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import {
|
import {
|
||||||
pricesQuery,
|
pricesQuery,
|
||||||
SubscriptionPlan,
|
SubscriptionPlan,
|
||||||
@ -7,7 +6,8 @@ import {
|
|||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { Trans } from '@affine/i18n';
|
import { Trans } from '@affine/i18n';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai';
|
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons';
|
||||||
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { Suspense, useEffect, useRef, useState } from 'react';
|
import { Suspense, useEffect, useRef, useState } from 'react';
|
||||||
import type { FallbackProps } from 'react-error-boundary';
|
import type { FallbackProps } from 'react-error-boundary';
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ const getRecurringLabel = ({
|
|||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const [subscription, mutateSubscription] = useUserSubscription();
|
const [subscription, mutateSubscription] = useUserSubscription();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const loggedIn = useCurrentLoginStatus() === 'authenticated';
|
const loggedIn = useCurrentLoginStatus() === 'authenticated';
|
||||||
const planDetail = getPlanDetail(t);
|
const planDetail = getPlanDetail(t);
|
||||||
@ -165,9 +164,11 @@ const Settings = () => {
|
|||||||
key={detail.plan}
|
key={detail.plan}
|
||||||
onSubscriptionUpdate={mutateSubscription}
|
onSubscriptionUpdate={mutateSubscription}
|
||||||
onNotify={({ detail, recurring }) => {
|
onNotify={({ detail, recurring }) => {
|
||||||
pushNotification({
|
notify({
|
||||||
type: 'success',
|
style: 'normal',
|
||||||
theme: 'default',
|
icon: (
|
||||||
|
<SingleSelectSelectSolidIcon color={cssVar('primaryColor')} />
|
||||||
|
),
|
||||||
title: t['com.affine.payment.updated-notify-title'](),
|
title: t['com.affine.payment.updated-notify-title'](),
|
||||||
message:
|
message:
|
||||||
detail.plan === SubscriptionPlan.Free
|
detail.plan === SubscriptionPlan.Free
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import { SettingRow } from '@affine/component/setting-components';
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
import { ConfirmModal } from '@affine/component/ui/modal';
|
import { ConfirmModal } from '@affine/component/ui/modal';
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
@ -39,7 +39,6 @@ export const DeleteLeaveWorkspace = ({
|
|||||||
const workspaceManager = useService(WorkspaceManager);
|
const workspaceManager = useService(WorkspaceManager);
|
||||||
const workspaceList = useLiveData(workspaceManager.list.workspaceList$);
|
const workspaceList = useLiveData(workspaceManager.list.workspaceList$);
|
||||||
const currentWorkspace = useService(Workspace);
|
const currentWorkspace = useService(Workspace);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const onLeaveOrDelete = useCallback(() => {
|
const onLeaveOrDelete = useCallback(() => {
|
||||||
if (isOwner) {
|
if (isOwner) {
|
||||||
@ -69,15 +68,11 @@ export const DeleteLeaveWorkspace = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await workspaceManager.deleteWorkspace(workspaceMetadata);
|
await workspaceManager.deleteWorkspace(workspaceMetadata);
|
||||||
pushNotification({
|
notify.success({ title: t['Successfully deleted']() });
|
||||||
title: t['Successfully deleted'](),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
}, [
|
}, [
|
||||||
currentWorkspace?.id,
|
currentWorkspace?.id,
|
||||||
jumpToIndex,
|
jumpToIndex,
|
||||||
jumpToSubPath,
|
jumpToSubPath,
|
||||||
pushNotification,
|
|
||||||
setSettingModal,
|
setSettingModal,
|
||||||
t,
|
t,
|
||||||
workspaceList,
|
workspaceList,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import { SettingRow } from '@affine/component/setting-components';
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
import { Button } from '@affine/component/ui/button';
|
import { Button } from '@affine/component/ui/button';
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
@ -6,7 +6,6 @@ import { useSystemOnline } from '@affine/core/hooks/use-system-online';
|
|||||||
import { apis } from '@affine/electron-api';
|
import { apis } from '@affine/electron-api';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
interface ExportPanelProps {
|
interface ExportPanelProps {
|
||||||
@ -23,7 +22,6 @@ export const ExportPanel = ({
|
|||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const isOnline = useSystemOnline();
|
const isOnline = useSystemOnline();
|
||||||
|
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const onExport = useAsyncCallback(async () => {
|
const onExport = useAsyncCallback(async () => {
|
||||||
if (saving || !workspace) {
|
if (saving || !workspace) {
|
||||||
return;
|
return;
|
||||||
@ -39,21 +37,14 @@ export const ExportPanel = ({
|
|||||||
if (result?.error) {
|
if (result?.error) {
|
||||||
throw new Error(result.error);
|
throw new Error(result.error);
|
||||||
} else if (!result?.canceled) {
|
} else if (!result?.canceled) {
|
||||||
pushNotification({
|
notify.success({ title: t['Export success']() });
|
||||||
type: 'success',
|
|
||||||
title: t['Export success'](),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
pushNotification({
|
notify.error({ title: t['Export failed'](), message: e.message });
|
||||||
type: 'error',
|
|
||||||
title: t['Export failed'](),
|
|
||||||
message: e.message,
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
}
|
}
|
||||||
}, [isOnline, pushNotification, saving, t, workspace, workspaceId]);
|
}, [isOnline, saving, t, workspace, workspaceId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingRow name={t['Export']()} desc={t['Export Description']()}>
|
<SettingRow name={t['Export']()} desc={t['Export Description']()}>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { notify } from '@affine/component';
|
||||||
import type {
|
import type {
|
||||||
InviteModalProps,
|
InviteModalProps,
|
||||||
PaginationProps,
|
PaginationProps,
|
||||||
@ -7,7 +8,6 @@ import {
|
|||||||
MemberLimitModal,
|
MemberLimitModal,
|
||||||
Pagination,
|
Pagination,
|
||||||
} from '@affine/component/member-components';
|
} from '@affine/component/member-components';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { SettingRow } from '@affine/component/setting-components';
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
import { Avatar } from '@affine/component/ui/avatar';
|
import { Avatar } from '@affine/component/ui/avatar';
|
||||||
import { Button, IconButton } from '@affine/component/ui/button';
|
import { Button, IconButton } from '@affine/component/ui/button';
|
||||||
@ -90,8 +90,6 @@ export const CloudWorkspaceMembersPanel = ({
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [memberSkip, setMemberSkip] = useState(0);
|
const [memberSkip, setMemberSkip] = useState(0);
|
||||||
|
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const openModal = useCallback(() => {
|
const openModal = useCallback(() => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}, []);
|
}, []);
|
||||||
@ -109,15 +107,14 @@ export const CloudWorkspaceMembersPanel = ({
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
if (success) {
|
if (success) {
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t['Invitation sent'](),
|
title: t['Invitation sent'](),
|
||||||
message: t['Invitation sent hint'](),
|
message: t['Invitation sent hint'](),
|
||||||
type: 'success',
|
|
||||||
});
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[invite, pushNotification, t]
|
[invite, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||||
@ -146,13 +143,10 @@ export const CloudWorkspaceMembersPanel = ({
|
|||||||
async memberId => {
|
async memberId => {
|
||||||
const res = await revokeMemberPermission(memberId);
|
const res = await revokeMemberPermission(memberId);
|
||||||
if (res?.revoke) {
|
if (res?.revoke) {
|
||||||
pushNotification({
|
notify.success({ title: t['Removed successfully']() });
|
||||||
title: t['Removed successfully'](),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[pushNotification, revokeMemberPermission, t]
|
[revokeMemberPermission, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const desc = useMemo(() => {
|
const desc = useMemo(() => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { FlexWrapper, Input, Wrapper } from '@affine/component';
|
import { FlexWrapper, Input, notify, Wrapper } from '@affine/component';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { Avatar } from '@affine/component/ui/avatar';
|
import { Avatar } from '@affine/component/ui/avatar';
|
||||||
import { Button } from '@affine/component/ui/button';
|
import { Button } from '@affine/component/ui/button';
|
||||||
import { Upload } from '@affine/core/components/pure/file-upload';
|
import { Upload } from '@affine/core/components/pure/file-upload';
|
||||||
@ -11,7 +10,6 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
|||||||
import { CameraIcon } from '@blocksuite/icons';
|
import { CameraIcon } from '@blocksuite/icons';
|
||||||
import type { Workspace } from '@toeverything/infra';
|
import type { Workspace } from '@toeverything/infra';
|
||||||
import { useLiveData } from '@toeverything/infra';
|
import { useLiveData } from '@toeverything/infra';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { KeyboardEvent, MouseEvent } from 'react';
|
import type { KeyboardEvent, MouseEvent } from 'react';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
@ -24,7 +22,6 @@ export interface ProfilePanelProps extends WorkspaceSettingDetailProps {
|
|||||||
|
|
||||||
export const ProfilePanel = ({ isOwner, workspace }: ProfilePanelProps) => {
|
export const ProfilePanel = ({ isOwner, workspace }: ProfilePanelProps) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const workspaceIsReady = useLiveData(workspace?.engine.rootDocState$)?.ready;
|
const workspaceIsReady = useLiveData(workspace?.engine.rootDocState$)?.ready;
|
||||||
|
|
||||||
@ -93,12 +90,9 @@ export const ProfilePanel = ({ isOwner, workspace }: ProfilePanelProps) => {
|
|||||||
const handleUpdateWorkspaceName = useCallback(
|
const handleUpdateWorkspaceName = useCallback(
|
||||||
(name: string) => {
|
(name: string) => {
|
||||||
setWorkspaceName(name);
|
setWorkspaceName(name);
|
||||||
pushNotification({
|
notify.success({ title: t['Update workspace name success']() });
|
||||||
title: t['Update workspace name success'](),
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[pushNotification, setWorkspaceName, t]
|
[setWorkspaceName, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSetInput = useCallback((value: string) => {
|
const handleSetInput = useCallback((value: string) => {
|
||||||
@ -130,20 +124,16 @@ export const ProfilePanel = ({ isOwner, workspace }: ProfilePanelProps) => {
|
|||||||
(file: File) => {
|
(file: File) => {
|
||||||
setWorkspaceAvatar(file)
|
setWorkspaceAvatar(file)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
pushNotification({
|
notify.success({ title: 'Update workspace avatar success' });
|
||||||
title: 'Update workspace avatar success',
|
|
||||||
type: 'success',
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: 'Update workspace avatar failed',
|
title: 'Update workspace avatar failed',
|
||||||
message: error,
|
message: error,
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[pushNotification, setWorkspaceAvatar]
|
[setWorkspaceAvatar]
|
||||||
);
|
);
|
||||||
|
|
||||||
const canAdjustAvatar = workspaceIsReady && avatarUrl && isOwner;
|
const canAdjustAvatar = workspaceIsReady && avatarUrl && isOwner;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Tooltip } from '@affine/component';
|
import { notify, Tooltip } from '@affine/component';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { Avatar, type AvatarProps } from '@affine/component/ui/avatar';
|
import { Avatar, type AvatarProps } from '@affine/component/ui/avatar';
|
||||||
import { Loading } from '@affine/component/ui/loading';
|
import { Loading } from '@affine/component/ui/loading';
|
||||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||||
@ -81,7 +80,6 @@ const OfflineStatus = () => {
|
|||||||
const useSyncEngineSyncProgress = () => {
|
const useSyncEngineSyncProgress = () => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const isOnline = useSystemOnline();
|
const isOnline = useSystemOnline();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const { syncing, progress, retrying, errorMessage } = useDocEngineStatus();
|
const { syncing, progress, retrying, errorMessage } = useDocEngineStatus();
|
||||||
const [isOverCapacity, setIsOverCapacity] = useState(false);
|
const [isOverCapacity, setIsOverCapacity] = useState(false);
|
||||||
|
|
||||||
@ -89,7 +87,7 @@ const useSyncEngineSyncProgress = () => {
|
|||||||
const isOwner = useIsWorkspaceOwner(currentWorkspace.meta);
|
const isOwner = useIsWorkspaceOwner(currentWorkspace.meta);
|
||||||
|
|
||||||
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||||
const jumpToPricePlan = useCallback(async () => {
|
const jumpToPricePlan = useCallback(() => {
|
||||||
setSettingModalAtom({
|
setSettingModalAtom({
|
||||||
open: true,
|
open: true,
|
||||||
activeTab: 'plans',
|
activeTab: 'plans',
|
||||||
@ -108,17 +106,17 @@ const useSyncEngineSyncProgress = () => {
|
|||||||
}
|
}
|
||||||
setIsOverCapacity(true);
|
setIsOverCapacity(true);
|
||||||
if (isOwner) {
|
if (isOwner) {
|
||||||
pushNotification({
|
notify.warning({
|
||||||
type: 'warning',
|
|
||||||
title: t['com.affine.payment.storage-limit.title'](),
|
title: t['com.affine.payment.storage-limit.title'](),
|
||||||
message:
|
message:
|
||||||
t['com.affine.payment.storage-limit.description.owner'](),
|
t['com.affine.payment.storage-limit.description.owner'](),
|
||||||
actionLabel: t['com.affine.payment.storage-limit.view'](),
|
action: {
|
||||||
action: jumpToPricePlan,
|
label: t['com.affine.payment.storage-limit.view'](),
|
||||||
|
onClick: jumpToPricePlan,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushNotification({
|
notify.warning({
|
||||||
type: 'warning',
|
|
||||||
title: t['com.affine.payment.storage-limit.title'](),
|
title: t['com.affine.payment.storage-limit.title'](),
|
||||||
message:
|
message:
|
||||||
t['com.affine.payment.storage-limit.description.member'](),
|
t['com.affine.payment.storage-limit.description.member'](),
|
||||||
@ -129,7 +127,7 @@ const useSyncEngineSyncProgress = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
disposableOverCapacity?.dispose();
|
disposableOverCapacity?.dispose();
|
||||||
};
|
};
|
||||||
}, [currentWorkspace, isOwner, jumpToPricePlan, pushNotification, t]);
|
}, [currentWorkspace, isOwner, jumpToPricePlan, t]);
|
||||||
|
|
||||||
const content = useMemo(() => {
|
const content = useMemo(() => {
|
||||||
// TODO: add i18n
|
// TODO: add i18n
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { notify } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
pushGlobalLoadingEventAtom,
|
pushGlobalLoadingEventAtom,
|
||||||
resolveGlobalLoadingEventAtom,
|
resolveGlobalLoadingEventAtom,
|
||||||
} from '@affine/component/global-loading';
|
} from '@affine/component/global-loading';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { apis } from '@affine/electron-api';
|
import { apis } from '@affine/electron-api';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import type { PageRootService, RootBlockModel } from '@blocksuite/blocks';
|
import type { PageRootService, RootBlockModel } from '@blocksuite/blocks';
|
||||||
@ -51,7 +51,6 @@ async function exportHandler({ page, type }: ExportHandlerOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useExportPage = (page: Doc) => {
|
export const useExportPage = (page: Doc) => {
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const pushGlobalLoadingEvent = useSetAtom(pushGlobalLoadingEventAtom);
|
const pushGlobalLoadingEvent = useSetAtom(pushGlobalLoadingEventAtom);
|
||||||
const resolveGlobalLoadingEvent = useSetAtom(resolveGlobalLoadingEventAtom);
|
const resolveGlobalLoadingEvent = useSetAtom(resolveGlobalLoadingEventAtom);
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
@ -67,29 +66,21 @@ export const useExportPage = (page: Doc) => {
|
|||||||
page,
|
page,
|
||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t['com.affine.export.success.title'](),
|
title: t['com.affine.export.success.title'](),
|
||||||
message: t['com.affine.export.success.message'](),
|
message: t['com.affine.export.success.message'](),
|
||||||
type: 'success',
|
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t['com.affine.export.error.title'](),
|
title: t['com.affine.export.error.title'](),
|
||||||
message: t['com.affine.export.error.message'](),
|
message: t['com.affine.export.error.message'](),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
resolveGlobalLoadingEvent(globalLoadingID);
|
resolveGlobalLoadingEvent(globalLoadingID);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[page, pushGlobalLoadingEvent, resolveGlobalLoadingEvent, t]
|
||||||
page,
|
|
||||||
pushGlobalLoadingEvent,
|
|
||||||
pushNotification,
|
|
||||||
resolveGlobalLoadingEvent,
|
|
||||||
t,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return onClickHandler;
|
return onClickHandler;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||||
import {
|
import {
|
||||||
getWorkspacePublicPagesQuery,
|
getWorkspacePublicPagesQuery,
|
||||||
@ -7,8 +7,9 @@ import {
|
|||||||
revokePublicPageMutation,
|
revokePublicPageMutation,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
|
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons';
|
||||||
import type { PageMode, Workspace } from '@toeverything/infra';
|
import type { PageMode, Workspace } from '@toeverything/infra';
|
||||||
import { useSetAtom } from 'jotai';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { useMutation } from '../use-mutation';
|
import { useMutation } from '../use-mutation';
|
||||||
@ -69,7 +70,6 @@ export function useIsSharedPage(
|
|||||||
enableShare: (mode: PageMode) => void;
|
enableShare: (mode: PageMode) => void;
|
||||||
} {
|
} {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const { data, mutate } = useQuery({
|
const { data, mutate } = useQuery({
|
||||||
query: getWorkspacePublicPagesQuery,
|
query: getWorkspacePublicPagesQuery,
|
||||||
variables: {
|
variables: {
|
||||||
@ -103,24 +103,25 @@ export function useIsSharedPage(
|
|||||||
|
|
||||||
enableSharePage({ workspaceId, pageId, mode: publishMode })
|
enableSharePage({ workspaceId, pageId, mode: publishMode })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t[notificationToI18nKey['enableSuccessTitle']](),
|
title: t[notificationToI18nKey['enableSuccessTitle']](),
|
||||||
message: t[notificationToI18nKey['enableSuccessMessage']](),
|
message: t[notificationToI18nKey['enableSuccessMessage']](),
|
||||||
type: 'success',
|
style: 'normal',
|
||||||
theme: 'default',
|
icon: (
|
||||||
|
<SingleSelectSelectSolidIcon color={cssVar('primaryColor')} />
|
||||||
|
),
|
||||||
});
|
});
|
||||||
return mutate();
|
return mutate();
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t[notificationToI18nKey['enableErrorTitle']](),
|
title: t[notificationToI18nKey['enableErrorTitle']](),
|
||||||
message: t[notificationToI18nKey['enableErrorMessage']](),
|
message: t[notificationToI18nKey['enableErrorMessage']](),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[enableSharePage, mutate, pageId, pushNotification, t, workspaceId]
|
[enableSharePage, mutate, pageId, t, workspaceId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const changeShare = useCallback(
|
const changeShare = useCallback(
|
||||||
@ -130,7 +131,7 @@ export function useIsSharedPage(
|
|||||||
|
|
||||||
enableSharePage({ workspaceId, pageId, mode: publishMode })
|
enableSharePage({ workspaceId, pageId, mode: publishMode })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t[notificationToI18nKey['changeSuccessTitle']](),
|
title: t[notificationToI18nKey['changeSuccessTitle']](),
|
||||||
message: t[
|
message: t[
|
||||||
'com.affine.share-menu.confirm-modify-mode.notification.success.message'
|
'com.affine.share-menu.confirm-modify-mode.notification.success.message'
|
||||||
@ -144,43 +145,43 @@ export function useIsSharedPage(
|
|||||||
? t['Edgeless']()
|
? t['Edgeless']()
|
||||||
: t['Page'](),
|
: t['Page'](),
|
||||||
}),
|
}),
|
||||||
type: 'success',
|
style: 'normal',
|
||||||
theme: 'default',
|
icon: (
|
||||||
|
<SingleSelectSelectSolidIcon color={cssVar('primaryColor')} />
|
||||||
|
),
|
||||||
});
|
});
|
||||||
return mutate();
|
return mutate();
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t[notificationToI18nKey['changeErrorTitle']](),
|
title: t[notificationToI18nKey['changeErrorTitle']](),
|
||||||
message: t[notificationToI18nKey['changeErrorMessage']](),
|
message: t[notificationToI18nKey['changeErrorMessage']](),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[enableSharePage, mutate, pageId, pushNotification, t, workspaceId]
|
[enableSharePage, mutate, pageId, t, workspaceId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const disableShare = useCallback(() => {
|
const disableShare = useCallback(() => {
|
||||||
disableSharePage({ workspaceId, pageId })
|
disableSharePage({ workspaceId, pageId })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t[notificationToI18nKey['disableSuccessTitle']](),
|
title: t[notificationToI18nKey['disableSuccessTitle']](),
|
||||||
message: t[notificationToI18nKey['disableSuccessMessage']](),
|
message: t[notificationToI18nKey['disableSuccessMessage']](),
|
||||||
type: 'success',
|
style: 'normal',
|
||||||
theme: 'default',
|
icon: <SingleSelectSelectSolidIcon color={cssVar('primaryColor')} />,
|
||||||
});
|
});
|
||||||
return mutate();
|
return mutate();
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t[notificationToI18nKey['disableErrorTitle']](),
|
title: t[notificationToI18nKey['disableErrorTitle']](),
|
||||||
message: t[notificationToI18nKey['disableErrorMessage']](),
|
message: t[notificationToI18nKey['disableErrorMessage']](),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
}, [disableSharePage, mutate, pageId, pushNotification, t, workspaceId]);
|
}, [disableSharePage, mutate, pageId, t, workspaceId]);
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
@ -1,3 +1,4 @@
|
|||||||
|
import { notify } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
ChangeEmailPage,
|
ChangeEmailPage,
|
||||||
ChangePasswordPage,
|
ChangePasswordPage,
|
||||||
@ -7,7 +8,6 @@ import {
|
|||||||
SignInSuccessPage,
|
SignInSuccessPage,
|
||||||
SignUpPage,
|
SignUpPage,
|
||||||
} from '@affine/component/auth-components';
|
} from '@affine/component/auth-components';
|
||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
|
||||||
import { useCredentialsRequirement } from '@affine/core/hooks/affine/use-server-config';
|
import { useCredentialsRequirement } from '@affine/core/hooks/affine/use-server-config';
|
||||||
import {
|
import {
|
||||||
changeEmailMutation,
|
changeEmailMutation,
|
||||||
@ -17,7 +17,6 @@ import {
|
|||||||
verifyEmailMutation,
|
verifyEmailMutation,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useSetAtom } from 'jotai/react';
|
|
||||||
import type { ReactElement } from 'react';
|
import type { ReactElement } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { LoaderFunction } from 'react-router-dom';
|
import type { LoaderFunction } from 'react-router-dom';
|
||||||
@ -50,7 +49,6 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
|
|
||||||
const { authType } = useParams();
|
const { authType } = useParams();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
|
|
||||||
const { trigger: changePassword } = useMutation({
|
const { trigger: changePassword } = useMutation({
|
||||||
mutation: changePasswordMutation,
|
mutation: changePasswordMutation,
|
||||||
@ -72,20 +70,18 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
|
|
||||||
// FIXME: There is not notification
|
// FIXME: There is not notification
|
||||||
if (res?.sendVerifyChangeEmail) {
|
if (res?.sendVerifyChangeEmail) {
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t['com.affine.auth.sent.verify.email.hint'](),
|
title: t['com.affine.auth.sent.verify.email.hint'](),
|
||||||
type: 'success',
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: t['com.affine.auth.sent.change.email.fail'](),
|
title: t['com.affine.auth.sent.change.email.fail'](),
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!res?.sendVerifyChangeEmail;
|
return !!res?.sendVerifyChangeEmail;
|
||||||
},
|
},
|
||||||
[pushNotification, searchParams, sendVerifyChangeEmail, t]
|
[searchParams, sendVerifyChangeEmail, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSetPassword = useCallback(
|
const onSetPassword = useCallback(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
AffineShapeIcon,
|
AffineShapeIcon,
|
||||||
useEditCollection,
|
useEditCollection,
|
||||||
@ -17,7 +17,6 @@ import {
|
|||||||
ViewLayersIcon,
|
ViewLayersIcon,
|
||||||
} from '@blocksuite/icons';
|
} from '@blocksuite/icons';
|
||||||
import { useLiveData, useService, Workspace } from '@toeverything/infra';
|
import { useLiveData, useService, Workspace } from '@toeverything/infra';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@ -70,7 +69,6 @@ export const Component = function CollectionPage() {
|
|||||||
const params = useParams();
|
const params = useParams();
|
||||||
const workspace = useService(Workspace);
|
const workspace = useService(Workspace);
|
||||||
const collection = collections.find(v => v.id === params.collectionId);
|
const collection = collections.find(v => v.id === params.collectionId);
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!collection) {
|
if (!collection) {
|
||||||
navigate.jumpToSubPath(workspace.id, WorkspaceSubPath.ALL);
|
navigate.jumpToSubPath(workspace.id, WorkspaceSubPath.ALL);
|
||||||
@ -85,17 +83,13 @@ export const Component = function CollectionPage() {
|
|||||||
text = `${collection.collection.name} has been deleted`;
|
text = `${collection.collection.name} has been deleted`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pushNotification({
|
notify.error({ title: text });
|
||||||
type: 'error',
|
|
||||||
title: text,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
collection,
|
collection,
|
||||||
collectionService.collectionsTrash$.value,
|
collectionService.collectionsTrash$.value,
|
||||||
navigate,
|
navigate,
|
||||||
params.collectionId,
|
params.collectionId,
|
||||||
pushNotification,
|
|
||||||
workspace.docCollection,
|
workspace.docCollection,
|
||||||
workspace.id,
|
workspace.id,
|
||||||
]);
|
]);
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import { useSession } from '@affine/core/hooks/affine/use-current-user';
|
import { useSession } from '@affine/core/hooks/affine/use-current-user';
|
||||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||||
import { affine } from '@affine/electron-api';
|
import { affine } from '@affine/electron-api';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { CLOUD_WORKSPACE_CHANGED_BROADCAST_CHANNEL_KEY } from '@affine/workspace-impl';
|
import { CLOUD_WORKSPACE_CHANGED_BROADCAST_CHANNEL_KEY } from '@affine/workspace-impl';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import { startTransition, useEffect, useRef } from 'react';
|
import { startTransition, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ import { mixpanel } from '../utils';
|
|||||||
export const CloudSessionProvider = (props: PropsWithChildren) => {
|
export const CloudSessionProvider = (props: PropsWithChildren) => {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const prevSession = useRef<ReturnType<typeof useSession>>();
|
const prevSession = useRef<ReturnType<typeof useSession>>();
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const onceSignedInEvents = useOnceSignedInEvents();
|
const onceSignedInEvents = useOnceSignedInEvents();
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
|
|
||||||
@ -39,10 +37,9 @@ export const CloudSessionProvider = (props: PropsWithChildren) => {
|
|||||||
session.status === 'authenticated'
|
session.status === 'authenticated'
|
||||||
) {
|
) {
|
||||||
startTransition(() => refreshAfterSignedInEvents());
|
startTransition(() => refreshAfterSignedInEvents());
|
||||||
pushNotification({
|
notify.success({
|
||||||
title: t['com.affine.auth.has.signed'](),
|
title: t['com.affine.auth.has.signed'](),
|
||||||
message: t['com.affine.auth.has.signed.message'](),
|
message: t['com.affine.auth.has.signed.message'](),
|
||||||
type: 'success',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (environment.isDesktop) {
|
if (environment.isDesktop) {
|
||||||
@ -51,7 +48,7 @@ export const CloudSessionProvider = (props: PropsWithChildren) => {
|
|||||||
}
|
}
|
||||||
prevSession.current = session;
|
prevSession.current = session;
|
||||||
}
|
}
|
||||||
}, [session, prevSession, pushNotification, refreshAfterSignedInEvents, t]);
|
}, [session, prevSession, refreshAfterSignedInEvents, t]);
|
||||||
|
|
||||||
return props.children;
|
return props.children;
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
import { notify } from '@affine/component';
|
||||||
import { assertExists } from '@blocksuite/global/utils';
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import { GraphQLError } from 'graphql';
|
import { GraphQLError } from 'graphql';
|
||||||
import { useSetAtom } from 'jotai';
|
|
||||||
import type { PropsWithChildren, ReactNode } from 'react';
|
import type { PropsWithChildren, ReactNode } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { SWRConfiguration } from 'swr';
|
import type { SWRConfiguration } from 'swr';
|
||||||
@ -11,7 +10,6 @@ const swrConfig: SWRConfiguration = {
|
|||||||
suspense: true,
|
suspense: true,
|
||||||
use: [
|
use: [
|
||||||
useSWRNext => (key, fetcher, config) => {
|
useSWRNext => (key, fetcher, config) => {
|
||||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
|
||||||
const fetcherWrapper = useCallback(
|
const fetcherWrapper = useCallback(
|
||||||
async (...args: any[]) => {
|
async (...args: any[]) => {
|
||||||
assertExists(fetcher);
|
assertExists(fetcher);
|
||||||
@ -23,18 +21,14 @@ const swrConfig: SWRConfiguration = {
|
|||||||
(Array.isArray(e) && e[0] instanceof GraphQLError)
|
(Array.isArray(e) && e[0] instanceof GraphQLError)
|
||||||
) {
|
) {
|
||||||
const graphQLError = e instanceof GraphQLError ? e : e[0];
|
const graphQLError = e instanceof GraphQLError ? e : e[0];
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: 'GraphQL Error',
|
title: 'GraphQL Error',
|
||||||
message: graphQLError.toString(),
|
message: graphQLError.toString(),
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushNotification({
|
notify.error({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
message: e.toString(),
|
message: e.toString(),
|
||||||
key: Date.now().toString(),
|
|
||||||
type: 'error',
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
@ -42,7 +36,7 @@ const swrConfig: SWRConfiguration = {
|
|||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
[fetcher, pushNotification]
|
[fetcher]
|
||||||
);
|
);
|
||||||
return useSWRNext(key, fetcher ? fetcherWrapper : fetcher, config);
|
return useSWRNext(key, fetcher ? fetcherWrapper : fetcher, config);
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import '@affine/component/theme/global.css';
|
import '@affine/component/theme/global.css';
|
||||||
import '@affine/component/theme/theme.css';
|
import '@affine/component/theme/theme.css';
|
||||||
|
|
||||||
|
import { NotificationCenter } from '@affine/component';
|
||||||
import { AffineContext } from '@affine/component/context';
|
import { AffineContext } from '@affine/component/context';
|
||||||
import { GlobalLoading } from '@affine/component/global-loading';
|
import { GlobalLoading } from '@affine/component/global-loading';
|
||||||
import { NotificationCenter } from '@affine/component/notification-center';
|
|
||||||
import { WorkspaceFallback } from '@affine/core/components/workspace';
|
import { WorkspaceFallback } from '@affine/core/components/workspace';
|
||||||
import { GlobalScopeProvider } from '@affine/core/modules/infra-web/global-scope';
|
import { GlobalScopeProvider } from '@affine/core/modules/infra-web/global-scope';
|
||||||
import { CloudSessionProvider } from '@affine/core/providers/session-provider';
|
import { CloudSessionProvider } from '@affine/core/providers/session-provider';
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import '@affine/component/theme/global.css';
|
import '@affine/component/theme/global.css';
|
||||||
import '@affine/component/theme/theme.css';
|
import '@affine/component/theme/theme.css';
|
||||||
|
|
||||||
|
import { NotificationCenter } from '@affine/component';
|
||||||
import { AffineContext } from '@affine/component/context';
|
import { AffineContext } from '@affine/component/context';
|
||||||
import { GlobalLoading } from '@affine/component/global-loading';
|
import { GlobalLoading } from '@affine/component/global-loading';
|
||||||
import { NotificationCenter } from '@affine/component/notification-center';
|
|
||||||
import { WorkspaceFallback } from '@affine/core/components/workspace';
|
import { WorkspaceFallback } from '@affine/core/components/workspace';
|
||||||
import { GlobalScopeProvider } from '@affine/core/modules/infra-web/global-scope';
|
import { GlobalScopeProvider } from '@affine/core/modules/infra-web/global-scope';
|
||||||
import { CloudSessionProvider } from '@affine/core/providers/session-provider';
|
import { CloudSessionProvider } from '@affine/core/providers/session-provider';
|
||||||
|
@ -27,7 +27,7 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => {
|
|||||||
await openWorkspaceSettingPanel(page, 'Test Workspace');
|
await openWorkspaceSettingPanel(page, 'Test Workspace');
|
||||||
await page.getByTestId('delete-workspace-button').click();
|
await page.getByTestId('delete-workspace-button').click();
|
||||||
await expect(
|
await expect(
|
||||||
page.getByTestId('affine-notification').first()
|
page.locator('.affine-notification-center').first()
|
||||||
).not.toBeVisible();
|
).not.toBeVisible();
|
||||||
const workspaceNameDom = page.getByTestId('workspace-name');
|
const workspaceNameDom = page.getByTestId('workspace-name');
|
||||||
const currentWorkspaceName = (await workspaceNameDom.evaluate(
|
const currentWorkspaceName = (await workspaceNameDom.evaluate(
|
||||||
@ -38,7 +38,8 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => {
|
|||||||
.getByTestId('delete-workspace-input')
|
.getByTestId('delete-workspace-input')
|
||||||
.pressSequentially(currentWorkspaceName);
|
.pressSequentially(currentWorkspaceName);
|
||||||
const promise = page
|
const promise = page
|
||||||
.getByTestId('affine-notification')
|
.locator('.affine-notification-center')
|
||||||
|
.first()
|
||||||
.waitFor({ state: 'attached' });
|
.waitFor({ state: 'attached' });
|
||||||
await page.getByTestId('delete-workspace-confirm-button').click();
|
await page.getByTestId('delete-workspace-confirm-button').click();
|
||||||
await promise;
|
await promise;
|
||||||
|
Loading…
Reference in New Issue
Block a user