This commit is contained in:
Manav Rathi
2025-01-10 18:00:40 +05:30
parent 21c6e1eae2
commit 4e9e50fc4b
5 changed files with 71 additions and 90 deletions

View File

@@ -1,6 +1,6 @@
import { photosDialogZIndex } from "@/new/photos/components/utils/z-index";
import { useAppContext } from "@/new/photos/types/context";
import Notification from "components/Notification";
import { Notification } from "components/Notification";
import { t } from "i18next";
import { GalleryContext } from "pages/gallery";
import { useContext } from "react";

View File

@@ -1,6 +1,6 @@
import { EllipsizedTypography } from "@/base/components/Typography";
import { FilledIconButton } from "@/base/components/mui";
import { NotificationAttributes } from "@/new/photos/types/notification";
import type { ModalVisibilityProps } from "@/base/components/utils/modal";
import CloseIcon from "@mui/icons-material/Close";
import InfoIcon from "@mui/icons-material/InfoOutlined";
import {
@@ -12,18 +12,58 @@ import {
Theme,
type ButtonProps,
} from "@mui/material";
import React, { ReactNode } from "react";
interface Iprops {
open: boolean;
onClose: () => void;
/**
* Customize the contents of an {@link Notification}.
*/
export type NotificationAttributes =
| MessageSubTextNotificationAttributes
| TitleCaptionNotificationAttributes;
interface MessageSubTextNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
message?: React.JSX.Element | string;
subtext?: React.JSX.Element | string;
title?: never;
caption?: never;
onClick: () => void;
endIcon?: ReactNode;
}
interface TitleCaptionNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
title?: React.JSX.Element | string;
caption?: React.JSX.Element | string;
message?: never;
subtext?: never;
onClick: () => void;
endIcon?: ReactNode;
}
type NotificationProps = ModalVisibilityProps & {
keepOpenOnClick?: boolean;
attributes: NotificationAttributes;
horizontal?: "left" | "right";
vertical?: "top" | "bottom";
sx?: SxProps<Theme>;
}
};
export default function Notification({
/**
* A small notification popup shown on some edge of the screen to notify the
* user of some asynchronous update or error.
*
* In Material UI terms, this is a custom "Snackbar".
*
* A single Notification component can be shared by multiple sources of
* notifications (which means that there can't be multiple of them outstanding
* at the same time from the same source). The source can customize the actual
* contents and appearance of this notification by providing appropriate
* {@link NotificationAttributes}.
*/
export const Notification: React.FC<NotificationProps> = ({
open,
onClose,
horizontal,
@@ -31,7 +71,7 @@ export default function Notification({
sx,
attributes,
keepOpenOnClick,
}: Iprops) {
}) => {
if (!attributes) {
return <></>;
}
@@ -124,4 +164,4 @@ export default function Notification({
</Button>
</Snackbar>
);
}
};

View File

@@ -7,6 +7,7 @@ import {
useAttributedMiniDialog,
} from "@/base/components/utils/dialog";
import { useSetupI18n, useSetupLogs } from "@/base/components/utils/hooks-app";
import { useModalVisibility } from "@/base/components/utils/modal";
import { THEME_COLOR, getTheme } from "@/base/components/utils/theme";
import log from "@/base/log";
import { logStartupBanner } from "@/base/log-web";
@@ -31,9 +32,12 @@ import {
import type { User } from "@ente/shared/user/types";
import "@fontsource-variable/inter";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import { CssBaseline, styled } from "@mui/material";
import { CssBaseline } from "@mui/material";
import { ThemeProvider } from "@mui/material/styles";
import Notification from "components/Notification";
import {
Notification,
type NotificationAttributes,
} from "components/Notification";
import { t } from "i18next";
import type { AppProps } from "next/app";
import { useRouter } from "next/router";
@@ -42,23 +46,14 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import LoadingBar from "react-top-loading-bar";
import { resumeExportsIfNeeded } from "services/export";
import { photosLogout } from "services/logout";
import { NotificationAttributes } from "types/Notification";
import "styles/global.css";
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
useSetupLogs();
const router = useRouter();
const [loading, setLoading] = useState(false);
const [watchFolderView, setWatchFolderView] = useState(false);
const [watchFolderFiles, setWatchFolderFiles] = useState<FileList>(null);
const [notificationView, setNotificationView] = useState(false);
const closeNotification = () => setNotificationView(false);
const [notificationAttributes, setNotificationAttributes] =
useState<NotificationAttributes>(null);
const isI18nReady = useSetupI18n();
const router = useRouter();
const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog();
const { loadingBarRef, showLoadingBar, hideLoadingBar } = useLoadingBar();
const [themeColor, setThemeColor] = useLocalState(
@@ -66,6 +61,16 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
THEME_COLOR.DARK,
);
const { show: showNotification, props: notificationVisibilityProps } =
useModalVisibility();
const [notificationAttributes, setNotificationAttributes] = useState<
NotificationAttributes | undefined
>(undefined);
const [loading, setLoading] = useState(false);
const [watchFolderView, setWatchFolderView] = useState(false);
const [watchFolderFiles, setWatchFolderFiles] = useState<FileList>(null);
useEffect(() => {
const user = getData(LS_KEYS.USER) as User | undefined | null;
void migrateKVToken(user);
@@ -148,9 +153,10 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
});
}, []);
useEffect(() => {
setNotificationView(true);
}, [notificationAttributes]);
useEffect(
() => notificationAttributes && showNotification(),
[notificationAttributes],
);
const onGenericError = useCallback((e: unknown) => {
log.error(e);
@@ -209,8 +215,7 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
/>
<Notification
open={notificationView}
onClose={closeNotification}
{...notificationVisibilityProps}
attributes={notificationAttributes}
/>

View File

@@ -1,32 +0,0 @@
import { ButtonProps } from "@mui/material/Button";
import { ReactNode } from "react";
export type NotificationAttributes =
| MessageSubTextNotificationAttributes
| TitleCaptionNotificationAttributes;
interface MessageSubTextNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
message?: React.JSX.Element | string;
subtext?: React.JSX.Element | string;
title?: never;
caption?: never;
onClick: () => void;
endIcon?: ReactNode;
}
interface TitleCaptionNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
title?: React.JSX.Element | string;
caption?: React.JSX.Element | string;
message?: never;
subtext?: never;
onClick: () => void;
endIcon?: ReactNode;
}
export type SetNotificationAttributes = React.Dispatch<
React.SetStateAction<NotificationAttributes>
>;

View File

@@ -1,32 +0,0 @@
import type { ButtonProps } from "@mui/material/Button";
import type { ReactNode } from "react";
export type NotificationAttributes =
| MessageSubTextNotificationAttributes
| TitleCaptionNotificationAttributes;
interface MessageSubTextNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
message?: React.JSX.Element | string;
subtext?: React.JSX.Element | string;
title?: never;
caption?: never;
onClick: () => void;
endIcon?: ReactNode;
}
interface TitleCaptionNotificationAttributes {
startIcon?: ReactNode;
variant: ButtonProps["color"];
title?: React.JSX.Element | string;
caption?: React.JSX.Element | string;
message?: never;
subtext?: never;
onClick: () => void;
endIcon?: ReactNode;
}
export type SetNotificationAttributes = React.Dispatch<
React.SetStateAction<NotificationAttributes>
>;