From 2f4c4e09488da29382830a8c5c34ed3444009c0b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 07:58:31 +0530 Subject: [PATCH 01/43] Remove unused --- web/packages/base/components/MiniDialog.tsx | 46 ++------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 550ea4c231..703dcd85a9 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -26,7 +26,7 @@ import React, { useState } from "react"; export interface MiniDialogAttributes { icon?: React.ReactNode; /** - * The dialog's title + * The dialog's title. * * Usually this will be a string, but it can be any {@link ReactNode}. Note * that it always gets wrapped in a Typography element to set the font @@ -82,12 +82,6 @@ export interface MiniDialogAttributes { variant?: ButtonProps["color"]; disabled?: boolean; }; - buttons?: { - text: string; - action: () => void; - variant: ButtonProps["color"]; - disabled?: boolean; - }[]; buttonDirection?: "row" | "column"; } @@ -166,9 +160,7 @@ export function MiniDialog({ ))} - {(attributes.proceed || - attributes.close || - attributes.buttons?.length) && ( + {(attributes.proceed || attributes.close) && ( )} - {attributes.buttons && - attributes.buttons.map((b) => ( - { - b.action(); - onClose(); - }} - disabled={b.disabled} - > - {b.text} - - ))} )} @@ -316,9 +293,7 @@ export function DialogBoxV2({ ))} - {(attributes.proceed || - attributes.close || - attributes.buttons?.length) && ( + {(attributes.proceed || attributes.close) && ( )} - {attributes.buttons && - attributes.buttons.map((b) => ( - { - b.action(); - onClose(); - }} - disabled={b.disabled} - > - {b.text} - - ))} )} From 9e10ec7ff60cc1a96bcab04bf2a1ea996ff8c9d8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 08:01:09 +0530 Subject: [PATCH 02/43] Dup --- web/packages/base/components/MiniDialog.tsx | 71 ++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 703dcd85a9..226d4b1f85 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -227,6 +227,75 @@ export function MiniDialog({ // } // } +export interface DialogBoxV2Attributes { + icon?: React.ReactNode; + /** + * The dialog's title. + * + * Usually this will be a string, but it can be any {@link ReactNode}. Note + * that it always gets wrapped in a Typography element to set the font + * style, so if your ReactNode wants to do its own thing, it'll need to + * reset or override these customizations. + */ + title?: React.ReactNode; + staticBackdrop?: boolean; + nonClosable?: boolean; + /** + * The dialog's content. + */ + content?: React.ReactNode; + /** + * Customize the cancel (dismiss) action button offered by the dialog box. + * + * Usually dialog boxes should have a cancel action, but this can be skipped + * to only show one of the other types of buttons. + */ + close?: { + /** The string to use as the label for the cancel button. */ + text?: string; + /** The color of the button. */ + variant?: ButtonProps["color"]; + /** + * The function to call when the user cancels. + * + * If provided, this callback is invoked before closing the dialog. + */ + action?: () => void; + }; + /** + * Customize the primary action button offered by the dialog box. + */ + proceed?: { + /** The string to use as the label for the primary action. */ + text: string; + /** + * The function to call when the user presses the primary action button. + * + * It is passed a {@link setLoading} function that can be used to show + * or hide loading indicator or the primary action button. + */ + action: + | (() => void | Promise) + | ((setLoading: (value: boolean) => void) => void | Promise); + variant?: ButtonProps["color"]; + disabled?: boolean; + }; + secondary?: { + text: string; + action: () => void; + variant?: ButtonProps["color"]; + disabled?: boolean; + }; + buttonDirection?: "row" | "column"; +} + +type DialogBoxV2Props = React.PropsWithChildren< + Omit & { + onClose: () => void; + attributes?: DialogBoxV2Attributes; + } +>; + /** * TODO This is a duplicate of MiniDialog. This is for use by call sites that * were using the MiniDialog not as a dialog but as a base container. Such use @@ -240,7 +309,7 @@ export function DialogBoxV2({ open, onClose, ...props -}: MiniDialogProps) { +}: DialogBoxV2Props) { const [loading, setLoading] = useState(false); if (!attributes) { return <>; From 66ac35cbccf18580f448a8bff141c5bdb1d03091 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 08:01:50 +0530 Subject: [PATCH 03/43] Prune --- web/packages/base/components/MiniDialog.tsx | 24 ++------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 226d4b1f85..e3f710d584 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -228,7 +228,6 @@ export function MiniDialog({ // } export interface DialogBoxV2Attributes { - icon?: React.ReactNode; /** * The dialog's title. * @@ -240,10 +239,7 @@ export interface DialogBoxV2Attributes { title?: React.ReactNode; staticBackdrop?: boolean; nonClosable?: boolean; - /** - * The dialog's content. - */ - content?: React.ReactNode; + /** * Customize the cancel (dismiss) action button offered by the dialog box. * @@ -339,28 +335,12 @@ export function DialogBoxV2({ > - {attributes.icon && ( - svg": { - fontSize: "32px", - }, - }} - > - {attributes.icon} - - )} {attributes.title && ( {attributes.title} )} - {children || - (attributes?.content && ( - - {attributes.content} - - ))} + {children} {(attributes.proceed || attributes.close) && ( Date: Thu, 10 Oct 2024 08:05:39 +0530 Subject: [PATCH 04/43] Prune (secondary prop was set but was not being used) --- .../src/components/DeleteAccountModal.tsx | 4 -- web/packages/base/components/MiniDialog.tsx | 51 +------------------ 2 files changed, 1 insertion(+), 54 deletions(-) diff --git a/web/apps/photos/src/components/DeleteAccountModal.tsx b/web/apps/photos/src/components/DeleteAccountModal.tsx index e30180e8d6..fa4e6d5ae7 100644 --- a/web/apps/photos/src/components/DeleteAccountModal.tsx +++ b/web/apps/photos/src/components/DeleteAccountModal.tsx @@ -145,10 +145,6 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { fullScreen={isMobile} attributes={{ title: t("delete_account"), - secondary: { - action: onClose, - text: t("cancel"), - }, }} > diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index e3f710d584..59e285299c 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -76,12 +76,6 @@ export interface MiniDialogAttributes { variant?: ButtonProps["color"]; disabled?: boolean; }; - secondary?: { - text: string; - action: () => void; - variant?: ButtonProps["color"]; - disabled?: boolean; - }; buttonDirection?: "row" | "column"; } @@ -239,7 +233,6 @@ export interface DialogBoxV2Attributes { title?: React.ReactNode; staticBackdrop?: boolean; nonClosable?: boolean; - /** * Customize the cancel (dismiss) action button offered by the dialog box. * @@ -258,30 +251,6 @@ export interface DialogBoxV2Attributes { */ action?: () => void; }; - /** - * Customize the primary action button offered by the dialog box. - */ - proceed?: { - /** The string to use as the label for the primary action. */ - text: string; - /** - * The function to call when the user presses the primary action button. - * - * It is passed a {@link setLoading} function that can be used to show - * or hide loading indicator or the primary action button. - */ - action: - | (() => void | Promise) - | ((setLoading: (value: boolean) => void) => void | Promise); - variant?: ButtonProps["color"]; - disabled?: boolean; - }; - secondary?: { - text: string; - action: () => void; - variant?: ButtonProps["color"]; - disabled?: boolean; - }; buttonDirection?: "row" | "column"; } @@ -306,7 +275,6 @@ export function DialogBoxV2({ onClose, ...props }: DialogBoxV2Props) { - const [loading, setLoading] = useState(false); if (!attributes) { return <>; } @@ -342,7 +310,7 @@ export function DialogBoxV2({ )} {children} - {(attributes.proceed || attributes.close) && ( + {attributes.close && ( - {attributes.proceed && ( - { - await attributes.proceed?.action( - setLoading, - ); - - onClose(); - }} - disabled={attributes.proceed.disabled} - > - {attributes.proceed.text} - - )} {attributes.close && ( Date: Thu, 10 Oct 2024 08:10:42 +0530 Subject: [PATCH 05/43] Prune --- web/packages/base/components/MiniDialog.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 59e285299c..63b50cd237 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -231,8 +231,6 @@ export interface DialogBoxV2Attributes { * reset or override these customizations. */ title?: React.ReactNode; - staticBackdrop?: boolean; - nonClosable?: boolean; /** * Customize the cancel (dismiss) action button offered by the dialog box. * @@ -279,18 +277,12 @@ export function DialogBoxV2({ return <>; } - const handleClose = dialogCloseHandler({ - staticBackdrop: attributes.staticBackdrop, - nonClosable: attributes.nonClosable, - onClose: onClose, - }); - const { PaperProps, ...rest } = props; return ( Date: Thu, 10 Oct 2024 08:23:20 +0530 Subject: [PATCH 06/43] Inline --- .../src/components/ExportPendingList.tsx | 12 +++-- web/packages/base/components/MiniDialog.tsx | 44 ------------------- 2 files changed, 8 insertions(+), 48 deletions(-) diff --git a/web/apps/photos/src/components/ExportPendingList.tsx b/web/apps/photos/src/components/ExportPendingList.tsx index 2f8888b734..99690b2c61 100644 --- a/web/apps/photos/src/components/ExportPendingList.tsx +++ b/web/apps/photos/src/components/ExportPendingList.tsx @@ -1,4 +1,5 @@ import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { ItemCard, PreviewItemTile } from "@/new/photos/components/Tiles"; import { EnteFile } from "@/new/photos/types/file"; import { FlexWrapper } from "@ente/shared/components/Container"; @@ -63,10 +64,6 @@ const ExportPendingList = (props: Iprops) => { }} attributes={{ title: t("PENDING_ITEMS"), - close: { - action: props.onClose, - text: t("close"), - }, }} > { getItemTitle={getItemTitle} generateItemKey={generateItemKey} /> + + {t("close")} + ); }; diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 63b50cd237..849c4fddbd 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -231,25 +231,6 @@ export interface DialogBoxV2Attributes { * reset or override these customizations. */ title?: React.ReactNode; - /** - * Customize the cancel (dismiss) action button offered by the dialog box. - * - * Usually dialog boxes should have a cancel action, but this can be skipped - * to only show one of the other types of buttons. - */ - close?: { - /** The string to use as the label for the cancel button. */ - text?: string; - /** The color of the button. */ - variant?: ButtonProps["color"]; - /** - * The function to call when the user cancels. - * - * If provided, this callback is invoked before closing the dialog. - */ - action?: () => void; - }; - buttonDirection?: "row" | "column"; } type DialogBoxV2Props = React.PropsWithChildren< @@ -302,31 +283,6 @@ export function DialogBoxV2({ )} {children} - {attributes.close && ( - - {attributes.close && ( - { - attributes.close?.action && - attributes.close?.action(); - onClose(); - }} - > - {attributes.close?.text ?? t("ok")} - - )} - - )} ); From 2cede3a46fb3d4f2049e1eff62ca8f3d451c76b7 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 08:30:06 +0530 Subject: [PATCH 07/43] Reify --- .../src/components/AuthenticateUserModal.tsx | 4 +-- .../Collections/AlbumCastDialog.tsx | 2 +- .../Collections/CollectionNamer.tsx | 4 +-- .../src/components/DeleteAccountModal.tsx | 4 +-- .../src/components/ExportPendingList.tsx | 4 +-- .../FileInfo/FileNameEditDialog.tsx | 4 +-- web/packages/base/components/MiniDialog.tsx | 36 +++++++------------ 7 files changed, 19 insertions(+), 39 deletions(-) diff --git a/web/apps/photos/src/components/AuthenticateUserModal.tsx b/web/apps/photos/src/components/AuthenticateUserModal.tsx index e8d3c76626..0002760a82 100644 --- a/web/apps/photos/src/components/AuthenticateUserModal.tsx +++ b/web/apps/photos/src/components/AuthenticateUserModal.tsx @@ -102,9 +102,7 @@ export default function AuthenticateUserModal({ open={open} onClose={onClose} sx={{ position: "absolute" }} - attributes={{ - title: t("password"), - }} + title={t("password")} > = ({ {view == "choose" && ( diff --git a/web/apps/photos/src/components/Collections/CollectionNamer.tsx b/web/apps/photos/src/components/Collections/CollectionNamer.tsx index 7294b44ed6..0374b8dc14 100644 --- a/web/apps/photos/src/components/Collections/CollectionNamer.tsx +++ b/web/apps/photos/src/components/Collections/CollectionNamer.tsx @@ -42,9 +42,7 @@ export default function CollectionNamer({ attributes, ...props }: Props) { { open={open} onClose={onClose} fullScreen={isMobile} - attributes={{ - title: t("delete_account"), - }} + title={t("delete_account")} > initialValues={{ diff --git a/web/apps/photos/src/components/ExportPendingList.tsx b/web/apps/photos/src/components/ExportPendingList.tsx index 99690b2c61..667926afdd 100644 --- a/web/apps/photos/src/components/ExportPendingList.tsx +++ b/web/apps/photos/src/components/ExportPendingList.tsx @@ -62,9 +62,7 @@ const ExportPendingList = (props: Iprops) => { PaperProps={{ sx: { maxWidth: "444px" }, }} - attributes={{ - title: t("PENDING_ITEMS"), - }} + title={t("PENDING_ITEMS")} > & { onClose: () => void; - attributes?: DialogBoxV2Attributes; + /** + * The dialog's title. + * + * Usually this will be a string, but it can be any {@link ReactNode}. Note + * that it always gets wrapped in a Typography element to set the font + * style, so if your ReactNode wants to do its own thing, it'll need to + * reset or override these customizations. + */ + title?: React.ReactNode; } >; @@ -248,16 +244,12 @@ type DialogBoxV2Props = React.PropsWithChildren< * API for the notify/confirm case separately. */ export function DialogBoxV2({ - attributes, + title, children, open, onClose, ...props }: DialogBoxV2Props) { - if (!attributes) { - return <>; - } - const { PaperProps, ...rest } = props; return ( @@ -276,11 +268,9 @@ export function DialogBoxV2({ > - {attributes.title && ( - - {attributes.title} - - )} + + {title} + {children} From bc3488cb9c8c9aea9e52a13185191a4de3d6f0c8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 08:31:50 +0530 Subject: [PATCH 08/43] Dedup --- web/packages/base/components/MiniDialog.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 3419693fdc..efac413e7c 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -266,13 +266,11 @@ export function DialogBoxV2({ }} {...rest} > - - - - {title} - - {children} - + + + {title} + + {children} ); From 0dd5fd6d23a9a8a3370130c951fb259375376410 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 08:44:19 +0530 Subject: [PATCH 09/43] Use standard components --- web/packages/base/components/MiniDialog.tsx | 14 +++++++------- web/packages/shared/themes/components.ts | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index efac413e7c..cc628bacdb 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -9,6 +9,8 @@ import type { ButtonProps } from "@mui/material"; import { Box, Dialog, + DialogContent, + DialogTitle, Stack, Typography, type DialogProps, @@ -259,19 +261,17 @@ export function DialogBoxV2({ PaperProps={{ ...PaperProps, sx: { - padding: "8px 12px", + // padding: "8px 12px", maxWidth: "360px", ...PaperProps?.sx, }, }} {...rest} > - - - {title} - - {children} - + + {title} + + {children} ); } diff --git a/web/packages/shared/themes/components.ts b/web/packages/shared/themes/components.ts index d117d9043a..d807f02f45 100644 --- a/web/packages/shared/themes/components.ts +++ b/web/packages/shared/themes/components.ts @@ -52,7 +52,7 @@ export const getComponents = ( // This is not a great choice either, usually most dialogs, for // one reason or the other, will need to customize this padding // anyway. But not resetting it to 16px leaves it at the MUI - // defaults, which just don't work with our designs. + // defaults, which just doesn't work well with our designs. "& .MuiDialogTitle-root": { // MUI default is '16px 24px'. padding: "16px", @@ -66,9 +66,9 @@ export const getComponents = ( overflowY: "auto", }, "& .MuiDialogActions-root": { - // MUI default is way since they cluster the buttons to the - // right, our designs usually want the buttons to align with - // the heading / content. + // MUI default is way off for us since they cluster the + // buttons to the right, while our designs usually want the + // buttons to align with the heading / content. padding: "16px", }, ".MuiDialogTitle-root + .MuiDialogContent-root": { From 145c7356a8a9a79cc393157656fd31993c549134 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 09:07:34 +0530 Subject: [PATCH 10/43] Rename 1 --- .../src/components/AuthenticateUserModal.tsx | 6 +-- .../Collections/AlbumCastDialog.tsx | 6 +-- .../Collections/CollectionNamer.tsx | 6 +-- .../src/components/DeleteAccountModal.tsx | 6 +-- .../src/components/ExportPendingList.tsx | 7 ++- .../FileInfo/FileNameEditDialog.tsx | 6 +-- web/packages/base/components/MiniDialog.tsx | 53 +++++++++---------- 7 files changed, 42 insertions(+), 48 deletions(-) diff --git a/web/apps/photos/src/components/AuthenticateUserModal.tsx b/web/apps/photos/src/components/AuthenticateUserModal.tsx index 0002760a82..9c230cc220 100644 --- a/web/apps/photos/src/components/AuthenticateUserModal.tsx +++ b/web/apps/photos/src/components/AuthenticateUserModal.tsx @@ -1,6 +1,6 @@ import { checkSessionValidity } from "@/accounts/services/session"; import { - DialogBoxV2, + TitledMiniDialog, type MiniDialogAttributes, } from "@/base/components/MiniDialog"; import log from "@/base/log"; @@ -98,7 +98,7 @@ export default function AuthenticateUserModal({ }; return ( - - + ); } diff --git a/web/apps/photos/src/components/Collections/AlbumCastDialog.tsx b/web/apps/photos/src/components/Collections/AlbumCastDialog.tsx index a3f56c6ca6..67b4b2d678 100644 --- a/web/apps/photos/src/components/Collections/AlbumCastDialog.tsx +++ b/web/apps/photos/src/components/Collections/AlbumCastDialog.tsx @@ -1,4 +1,4 @@ -import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { TitledMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { boxSeal } from "@/base/crypto/libsodium"; import log from "@/base/log"; @@ -135,7 +135,7 @@ export const AlbumCastDialog: React.FC = ({ }, [open]); return ( - = ({ )} - + ); }; diff --git a/web/apps/photos/src/components/Collections/CollectionNamer.tsx b/web/apps/photos/src/components/Collections/CollectionNamer.tsx index 0374b8dc14..bf64267499 100644 --- a/web/apps/photos/src/components/Collections/CollectionNamer.tsx +++ b/web/apps/photos/src/components/Collections/CollectionNamer.tsx @@ -1,4 +1,4 @@ -import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { TitledMiniDialog } from "@/base/components/MiniDialog"; import SingleInputForm, { type SingleInputFormProps, } from "@ente/shared/components/SingleInputForm"; @@ -39,7 +39,7 @@ export default function CollectionNamer({ attributes, ...props }: Props) { }; return ( - - + ); } diff --git a/web/apps/photos/src/components/DeleteAccountModal.tsx b/web/apps/photos/src/components/DeleteAccountModal.tsx index ba2d6488f1..72494f9455 100644 --- a/web/apps/photos/src/components/DeleteAccountModal.tsx +++ b/web/apps/photos/src/components/DeleteAccountModal.tsx @@ -1,4 +1,4 @@ -import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { TitledMiniDialog } from "@/base/components/MiniDialog"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { LoadingButton } from "@/base/components/mui/LoadingButton"; import log from "@/base/log"; @@ -138,7 +138,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { return ( <> - { )} - + ); }; diff --git a/web/apps/photos/src/components/ExportPendingList.tsx b/web/apps/photos/src/components/ExportPendingList.tsx index 667926afdd..087f31d3d0 100644 --- a/web/apps/photos/src/components/ExportPendingList.tsx +++ b/web/apps/photos/src/components/ExportPendingList.tsx @@ -1,4 +1,4 @@ -import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { TitledMiniDialog } from "@/base/components/MiniDialog"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { ItemCard, PreviewItemTile } from "@/new/photos/components/Tiles"; import { EnteFile } from "@/new/photos/types/file"; @@ -55,10 +55,9 @@ const ExportPendingList = (props: Iprops) => { }; return ( - { > {t("close")} - + ); }; diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx index b21a3ac58d..886328ddbf 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx @@ -1,4 +1,4 @@ -import { DialogBoxV2 } from "@/base/components/MiniDialog"; +import { TitledMiniDialog } from "@/base/components/MiniDialog"; import SingleInputForm, { type SingleInputFormProps, } from "@ente/shared/components/SingleInputForm"; @@ -23,7 +23,7 @@ export const FileNameEditDialog = ({ } }; return ( - - + ); }; diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index cc628bacdb..8ddabc611b 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -223,55 +223,50 @@ export function MiniDialog({ // } // } -type DialogBoxV2Props = React.PropsWithChildren< - Omit & { - onClose: () => void; - /** - * The dialog's title. - * - * Usually this will be a string, but it can be any {@link ReactNode}. Note - * that it always gets wrapped in a Typography element to set the font - * style, so if your ReactNode wants to do its own thing, it'll need to - * reset or override these customizations. - */ - title?: React.ReactNode; - } ->; +type TitledMiniDialogProps = Omit & { + onClose: () => void; + /** + * The dialog's title. + */ + title?: React.ReactNode; +}; /** - * TODO This is a duplicate of MiniDialog. This is for use by call sites that - * were using the MiniDialog not as a dialog but as a base container. Such use - * cases are better served by directly using the MUI {@link Dialog}, so these - * are considered deprecated. Splitting these here so that we can streamline the - * API for the notify/confirm case separately. + * MiniDialog in a "shell" form. + * + * This is a {@link Dialog} for use at places which need more customization than + * what {@link MiniDialog} provides, but wish to retain the same size and + * general look without duplicating the MiniDialog code. + * + * It does three things: + * + * - Sets a fixed size same as {@link MiniDialog}, and sets up similar padding. + * - Takes the title as a prop, and wraps it in a {@link DialogTitle}. + * - Wraps children in a scrollable {@link DialogContent}. */ -export function DialogBoxV2({ - title, - children, - open, - onClose, - ...props -}: DialogBoxV2Props) { +export const TitledMiniDialog: React.FC< + React.PropsWithChildren +> = ({ title, children, open, onClose, ...props }) => { const { PaperProps, ...rest } = props; return ( - + {title} {children} ); -} +}; From 126904c68f1d8540e7f54d65eda835feb2a51798 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 09:42:27 +0530 Subject: [PATCH 11/43] Move --- .../new/photos/components/{PhotoViewer.tsx => z-index.tsx} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename web/packages/new/photos/components/{PhotoViewer.tsx => z-index.tsx} (63%) diff --git a/web/packages/new/photos/components/PhotoViewer.tsx b/web/packages/new/photos/components/z-index.tsx similarity index 63% rename from web/packages/new/photos/components/PhotoViewer.tsx rename to web/packages/new/photos/components/z-index.tsx index c320a73cf5..e66e8435c8 100644 --- a/web/packages/new/photos/components/PhotoViewer.tsx +++ b/web/packages/new/photos/components/z-index.tsx @@ -1,5 +1,5 @@ /** * PhotoSwipe sets the zIndex of its "pswp" class to 1500. We need to go higher - * than that for our drawers and dialogs to show above it. + * than that for our drawers and dialogs to get them to show above it. */ export const photoSwipeZIndex = 1500; From c7dd5dcbcaa26a53d66aa00f8dc31f8a3a58db93 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 09:59:08 +0530 Subject: [PATCH 12/43] zi --- web/apps/accounts/src/pages/_app.tsx | 1 - web/apps/auth/src/pages/_app.tsx | 1 - .../src/components/Collections/AlbumCastDialog.tsx | 3 ++- .../photos/src/components/FilesDownloadProgress.tsx | 3 ++- .../PhotoViewer/FileInfo/FileNameEditDialog.tsx | 3 ++- .../src/components/PhotoViewer/FileInfo/index.tsx | 4 ++-- .../PhotoViewer/ImageEditorOverlay/index.tsx | 3 ++- web/apps/photos/src/pages/_app.tsx | 5 +++-- .../new/photos/components/PhotoDateTimePicker.tsx | 4 ++-- web/packages/new/photos/components/z-index.tsx | 12 ++++++++++++ 10 files changed, 27 insertions(+), 12 deletions(-) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index e23692b86e..4c46ed4e56 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -56,7 +56,6 @@ const App: React.FC = ({ Component, pageProps }) => { = ({ Component, pageProps }) => { = ({ open={open} onClose={onClose} title={t("cast_album_to_tv")} - sx={{ zIndex: 1600 }} + sx={{ zIndex: photosDialogZIndex }} > {view == "choose" && ( diff --git a/web/apps/photos/src/components/FilesDownloadProgress.tsx b/web/apps/photos/src/components/FilesDownloadProgress.tsx index 86e5e0508c..7b82b17ee4 100644 --- a/web/apps/photos/src/components/FilesDownloadProgress.tsx +++ b/web/apps/photos/src/components/FilesDownloadProgress.tsx @@ -1,3 +1,4 @@ +import { photosDialogZIndex } from "@/new/photos/components/z-index"; import { AppContext } from "@/new/photos/types/context"; import Notification from "components/Notification"; import { t } from "i18next"; @@ -123,7 +124,7 @@ export const FilesDownloadProgress: React.FC = ({ horizontal="left" sx={{ "&&": { bottom: `${index * 80 + 20}px` }, - zIndex: 1600, + zIndex: photosDialogZIndex, }} open={isFilesDownloadStarted(attributes)} onClose={handleClose(attributes)} diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx index 886328ddbf..555b52ad0c 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/FileNameEditDialog.tsx @@ -1,4 +1,5 @@ import { TitledMiniDialog } from "@/base/components/MiniDialog"; +import { photosDialogZIndex } from "@/new/photos/components/z-index"; import SingleInputForm, { type SingleInputFormProps, } from "@ente/shared/components/SingleInputForm"; @@ -24,7 +25,7 @@ export const FileNameEditDialog = ({ }; return ( ( ))({ - zIndex: photoSwipeZIndex + 1, + zIndex: fileInfoDrawerZIndex, "& .MuiPaper-root": { padding: 8, }, diff --git a/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx b/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx index 7be07c08e4..02cd636e09 100644 --- a/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx @@ -6,6 +6,7 @@ import { } from "@/base/components/Menu"; import { nameAndExtension } from "@/base/file"; import log from "@/base/log"; +import { photosDialogZIndex } from "@/new/photos/components/z-index"; import downloadManager from "@/new/photos/services/download"; import { AppContext } from "@/new/photos/types/context"; import { EnteFile } from "@/new/photos/types/file"; @@ -522,7 +523,7 @@ const ImageEditorOverlay = (props: IProps) => { = ({ photo viewer and the info drawer */ dialog: { sx: { - zIndex: photoSwipeZIndex + 2, + zIndex: fileInfoDrawerZIndex + 1, }, }, }} diff --git a/web/packages/new/photos/components/z-index.tsx b/web/packages/new/photos/components/z-index.tsx index e66e8435c8..a988a362b6 100644 --- a/web/packages/new/photos/components/z-index.tsx +++ b/web/packages/new/photos/components/z-index.tsx @@ -3,3 +3,15 @@ * than that for our drawers and dialogs to get them to show above it. */ export const photoSwipeZIndex = 1500; + +/** + * The file info drawer needs to be higher than the photo viewer. + */ +export const fileInfoDrawerZIndex = photoSwipeZIndex + 1; + +/** + * Dialogs (not necessarily always) need to be higher still so to ensure they + * are visible above the drawer in case they are shown in response to some + * action taken in the file info drawer. + */ +export const photosDialogZIndex = 1600; From 84798091099beb17e391525318c85e54fac5e537 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 09:59:45 +0530 Subject: [PATCH 13/43] Rename --- web/apps/accounts/src/pages/_app.tsx | 4 +-- web/apps/photos/src/pages/_app.tsx | 4 +-- web/packages/base/components/MiniDialog.tsx | 34 ++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 4c46ed4e56..02d27bd390 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -2,7 +2,7 @@ import { staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; import { type MiniDialogAttributes, - MiniDialog, + AttributedMiniDialog, } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; @@ -55,7 +55,7 @@ const App: React.FC = ({ Component, pageProps }) => { - - component. */ title?: React.ReactNode; staticBackdrop?: boolean; nonClosable?: boolean; /** - * The dialog's content. + * The dialog's message. + * + * Similar to {@link title}, this is usually provided, and a string. */ content?: React.ReactNode; /** @@ -93,10 +93,10 @@ type MiniDialogProps = React.PropsWithChildren< * user, or ask for confirmation before actions. * * The rendered dialog can be customized by modifying the {@link attributes} - * prop. If you find yourself wanting to customize it further, consider just - * creating a new bespoke instantiation of a {@link Dialog}. + * prop. If you find yourself wanting to customize it further, consider either + * using a {@link TitledMiniDialog} or {@link Dialog}. */ -export function MiniDialog({ +export function AttributedMiniDialog({ attributes, children, open, @@ -235,18 +235,18 @@ type TitledMiniDialogProps = Omit & { * MiniDialog in a "shell" form. * * This is a {@link Dialog} for use at places which need more customization than - * what {@link MiniDialog} provides, but wish to retain the same size and - * general look without duplicating the MiniDialog code. + * what {@link AttributedMiniDialog} provides, but wish to retain a similar look + * and feel without duplicating code. * * It does three things: * - * - Sets a fixed size same as {@link MiniDialog}, and sets up similar padding. + * - Sets a fixed size and padding similar to {@link AttributedMiniDialog}. * - Takes the title as a prop, and wraps it in a {@link DialogTitle}. * - Wraps children in a scrollable {@link DialogContent}. */ export const TitledMiniDialog: React.FC< React.PropsWithChildren -> = ({ title, children, open, onClose, ...props }) => { +> = ({ open, onClose, title, children, ...props }) => { const { PaperProps, ...rest } = props; return ( From d5d015c13c466c9950f95f4563710012e69b4862 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 10:25:17 +0530 Subject: [PATCH 14/43] Tweak --- web/packages/base/components/MiniDialog.tsx | 22 ++++++++------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index ffd78745fb..197ce808da 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -81,12 +81,10 @@ export interface MiniDialogAttributes { buttonDirection?: "row" | "column"; } -type MiniDialogProps = React.PropsWithChildren< - Omit & { - onClose: () => void; - attributes?: MiniDialogAttributes; - } ->; +type MiniDialogProps = Omit & { + onClose: () => void; + attributes?: MiniDialogAttributes; +}; /** * A small, mostly predefined, MUI {@link Dialog} that can be used to notify the @@ -96,13 +94,9 @@ type MiniDialogProps = React.PropsWithChildren< * prop. If you find yourself wanting to customize it further, consider either * using a {@link TitledMiniDialog} or {@link Dialog}. */ -export function AttributedMiniDialog({ - attributes, - children, - open, - onClose, - ...props -}: MiniDialogProps) { +export const AttributedMiniDialog: React.FC< + React.PropsWithChildren +> = ({ open, onClose, attributes, children, ...props }) => { const [loading, setLoading] = useState(false); if (!attributes) { return <>; @@ -201,7 +195,7 @@ export function AttributedMiniDialog({ ); -} +}; // TODO: Sketch of a possible approach to using this. Haven't throught this // through, just noting down the outline inspired by an API I saw. From 8999c7045a8e66cf798cbfa2a35c7c844dabe239 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 10:35:39 +0530 Subject: [PATCH 15/43] Avoid a useEffect (eventually) --- web/apps/photos/src/pages/_app.tsx | 6 ++++++ web/packages/new/photos/types/context.ts | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index f71d370626..e39ba3562c 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -237,6 +237,11 @@ export default function App({ Component, pageProps }: AppProps) { ); const closeDialogBoxV2 = () => setDialogBoxV2View(false); + const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { + setDialogBoxAttributesV2(attributes); + setDialogBoxV2View(true); + }, []); + // Use `onGenericError` instead. const somethingWentWrong = useCallback( () => @@ -277,6 +282,7 @@ export default function App({ Component, pageProps }: AppProps) { setNotificationAttributes, themeColor, setThemeColor, + showMiniDialog, somethingWentWrong, onGenericError, setDialogBoxAttributesV2, diff --git a/web/packages/new/photos/types/context.ts b/web/packages/new/photos/types/context.ts index 2235c35c11..4c11a9bb01 100644 --- a/web/packages/new/photos/types/context.ts +++ b/web/packages/new/photos/types/context.ts @@ -4,6 +4,7 @@ import type { SetDialogBoxAttributes } from "@ente/shared/components/DialogBox/t import { THEME_COLOR } from "@ente/shared/themes/constants"; import { createContext, useContext } from "react"; import type { SetNotificationAttributes } from "./notification"; +import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; /** * The type of the React context available to all pages in the photos app. @@ -17,6 +18,14 @@ export type AppContextT = AccountsContextT & { * Hide the global activity indicator. */ finishLoading: () => void; + /** + * Show a "mini dialog" with the given attributes. + * + * Mini dialogs (see {@link AttributedMiniDialog}) are meant for simple + * confirmation or notication dialogs. Their appearance and functionality + * can be customized by providing relevant {@link MiniDialogAttributes}. + */ + showMiniDialog: (attributes: MiniDialogAttributes) => void; somethingWentWrong: () => void; setDialogMessage: SetDialogBoxAttributes; setNotificationAttributes: SetNotificationAttributes; From d2d5f630aa59a6c0039078fe77cb1929ced267b2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 10:43:15 +0530 Subject: [PATCH 16/43] Use --- web/apps/photos/src/components/Sidebar/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/components/Sidebar/index.tsx b/web/apps/photos/src/components/Sidebar/index.tsx index ca4fad9fa7..f1e2ba8b2b 100644 --- a/web/apps/photos/src/components/Sidebar/index.tsx +++ b/web/apps/photos/src/components/Sidebar/index.tsx @@ -7,7 +7,7 @@ import log from "@/base/log"; import { savedLogs } from "@/base/log-web"; import { customAPIHost } from "@/base/origins"; import type { CollectionSummaries } from "@/new/photos/services/collection/ui"; -import { AppContext } from "@/new/photos/types/context"; +import { AppContext, useAppContext } from "@/new/photos/types/context"; import { initiateEmail, openURL } from "@/new/photos/utils/web"; import { SpaceBetweenFlex } from "@ente/shared/components/Container"; import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem"; @@ -667,7 +667,7 @@ const ExitSection: React.FC = () => { }; const DebugSection: React.FC = () => { - const appContext = useContext(AppContext); + const { showMiniDialog } = useAppContext(); const [appVersion, setAppVersion] = useState(); const [host, setHost] = useState(); @@ -679,7 +679,7 @@ const DebugSection: React.FC = () => { }); const confirmLogDownload = () => - appContext.setDialogMessage({ + showMiniDialog({ title: t("DOWNLOAD_LOGS"), content: , proceed: { From 49086481371f180730303326136ba4a04179c3a2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 11:08:52 +0530 Subject: [PATCH 17/43] Similar to TitledMiniDialog --- web/packages/base/components/MiniDialog.tsx | 60 +++++++++++---------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 197ce808da..bf5408ca70 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -98,6 +98,7 @@ export const AttributedMiniDialog: React.FC< React.PropsWithChildren > = ({ open, onClose, attributes, children, ...props }) => { const [loading, setLoading] = useState(false); + if (!attributes) { return <>; } @@ -118,47 +119,48 @@ export const AttributedMiniDialog: React.FC< PaperProps={{ ...PaperProps, sx: { - padding: "8px 12px", maxWidth: "360px", ...PaperProps?.sx, }, }} {...rest} > - - - {attributes.icon && ( - svg": { - fontSize: "32px", - }, - }} - > - {attributes.icon} - - )} - {attributes.title && ( - - {attributes.title} - - )} - {children || - (attributes?.content && ( - - {attributes.content} - - ))} - + {attributes.icon && ( + svg": { + fontSize: "32px", + }, + color: "text.muted", + padding: "20px 16px 0px 16px", + }} + > + {attributes.icon} + + )} + {attributes.title && ( + + {attributes.title} + + )} + + {attributes.content && ( + + {attributes.content} + + )} + {children} {(attributes.proceed || attributes.close) && ( {attributes.proceed && ( )} - + ); }; From f5ebecfa699bb49336252e39215dace0befd1112 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 11:30:24 +0530 Subject: [PATCH 18/43] Move icon to the right --- web/packages/base/components/MiniDialog.tsx | 35 +++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index bf5408ca70..29a5b7243e 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -22,24 +22,24 @@ import React, { useState } from "react"; * Customize the contents of an {@link AttributedMiniDialog}. */ export interface MiniDialogAttributes { - /** - * An optional icon shown above the title. - */ - icon?: React.ReactNode; /** * The dialog's title. * - * While optional, it is usually provided. It will almost always be a - * string, but the prop accepts any React node to allow passing a i18next - * component. + * This will be usually be a string, but the prop accepts any React node to + * allow passing a i18next component. */ title?: React.ReactNode; + /** + * An optional component shown next to the title. + */ + icon?: React.ReactNode; staticBackdrop?: boolean; nonClosable?: boolean; /** * The dialog's message. * - * Similar to {@link title}, this is usually provided, and a string. + * This will be usually be a string, but the prop accepts any React node to + * allow passing a i18next component. */ content?: React.ReactNode; /** @@ -125,24 +125,27 @@ export const AttributedMiniDialog: React.FC< }} {...rest} > - {attributes.icon && ( + {(attributes.icon || attributes.title) && ( svg": { fontSize: "32px", + color: "text.faint", }, - color: "text.muted", - padding: "20px 16px 0px 16px", + padding: "24px 16px 16px 16px", }} > + {attributes.title && ( + + {attributes.title} + + )} {attributes.icon} )} - {attributes.title && ( - - {attributes.title} - - )} + {attributes.content && ( From 0e46287eeebd76da880c28a94fcb2a22ffed3d0b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 11:40:09 +0530 Subject: [PATCH 19/43] Add icon to error --- web/apps/photos/src/pages/_app.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index e39ba3562c..c0047b83eb 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -5,6 +5,7 @@ import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; import { setupI18n } from "@/base/i18n"; +import ErrorOutline from "@mui/icons-material/ErrorOutline"; import log from "@/base/log"; import { logStartupBanner, @@ -258,6 +259,7 @@ export default function App({ Component, pageProps }: AppProps) { log.error("Error", e), setDialogBoxAttributesV2({ title: t("error"), + icon: , content: t("generic_error"), close: { variant: "critical" }, }) From d904b9318a3fbf59c6137e57e7ec4a724b0bdea0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 11:41:39 +0530 Subject: [PATCH 20/43] Remove unnecessary setter deps > React guarantees that setState function identity is stable and won't change on > re-renders. Thus it is safe to omit it from the useEffect or useCallback > dependency list. > > https://legacy.reactjs.org/docs/hooks-reference.html#usestate --- web/apps/photos/src/pages/_app.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index c0047b83eb..5b68b6839b 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -5,7 +5,6 @@ import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; import { setupI18n } from "@/base/i18n"; -import ErrorOutline from "@mui/icons-material/ErrorOutline"; import log from "@/base/log"; import { logStartupBanner, @@ -37,6 +36,7 @@ import { getTheme } from "@ente/shared/themes"; import { THEME_COLOR } from "@ente/shared/themes/constants"; import type { User } from "@ente/shared/user/types"; import ArrowForward from "@mui/icons-material/ArrowForward"; +import ErrorOutline from "@mui/icons-material/ErrorOutline"; import { CssBaseline } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import Notification from "components/Notification"; @@ -251,7 +251,7 @@ export default function App({ Component, pageProps }: AppProps) { close: { variant: "critical" }, content: t("generic_error_retry"), }), - [setDialogMessage], + [], ); const onGenericError = useCallback( @@ -264,7 +264,7 @@ export default function App({ Component, pageProps }: AppProps) { close: { variant: "critical" }, }) ), - [setDialogBoxAttributesV2], + [], ); const logout = useCallback(() => { From 86f0dbb6205bb45ca73cd091d00a562fc25c602e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 11:49:54 +0530 Subject: [PATCH 21/43] Rename --- .../accounts/src/pages/passkeys/index.tsx | 4 +- .../src/components/AuthenticateUserModal.tsx | 2 +- .../src/components/DeleteAccountModal.tsx | 6 +- .../photos/src/components/Sidebar/index.tsx | 2 +- web/apps/photos/src/pages/_app.tsx | 2 +- web/packages/accounts/pages/recover.tsx | 2 +- .../accounts/pages/two-factor/recover.tsx | 2 +- web/packages/base/components/MiniDialog.tsx | 71 +++++++++++-------- .../new/photos/components/MLSettings.tsx | 2 +- .../components/gallery/PeopleHeader.tsx | 2 +- .../shared/components/LoginComponents.tsx | 4 +- 11 files changed, 55 insertions(+), 44 deletions(-) diff --git a/web/apps/accounts/src/pages/passkeys/index.tsx b/web/apps/accounts/src/pages/passkeys/index.tsx index 56d09d0fbd..d365af0b6d 100644 --- a/web/apps/accounts/src/pages/passkeys/index.tsx +++ b/web/apps/accounts/src/pages/passkeys/index.tsx @@ -46,7 +46,7 @@ const Page: React.FC = () => { const showPasskeyFetchFailedErrorDialog = useCallback(() => { setDialogBoxAttributesV2({ title: t("error"), - content: t("passkey_fetch_failed"), + message: t("passkey_fetch_failed"), close: {}, }); }, [setDialogBoxAttributesV2]); @@ -282,7 +282,7 @@ const ManagePasskeyDrawer: React.FC = ({ setDialogBoxAttributesV2({ title: t("delete_passkey"), - content: t("delete_passkey_confirmation"), + message: t("delete_passkey_confirmation"), proceed: { text: t("delete"), action: handleDelete, diff --git a/web/apps/photos/src/components/AuthenticateUserModal.tsx b/web/apps/photos/src/components/AuthenticateUserModal.tsx index 9c230cc220..0b6a83b7f9 100644 --- a/web/apps/photos/src/components/AuthenticateUserModal.tsx +++ b/web/apps/photos/src/components/AuthenticateUserModal.tsx @@ -126,7 +126,7 @@ const passwordChangedElsewhereDialogAttributes = ( onLogin: () => void, ): MiniDialogAttributes => ({ title: t("password_changed_elsewhere"), - content: t("password_changed_elsewhere_message"), + message: t("password_changed_elsewhere_message"), proceed: { text: t("login"), action: onLogin, diff --git a/web/apps/photos/src/components/DeleteAccountModal.tsx b/web/apps/photos/src/components/DeleteAccountModal.tsx index 72494f9455..8b75b2a630 100644 --- a/web/apps/photos/src/components/DeleteAccountModal.tsx +++ b/web/apps/photos/src/components/DeleteAccountModal.tsx @@ -43,7 +43,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { setDialogBoxAttributesV2({ title: t("error"), close: { variant: "critical" }, - content: t("generic_error_retry"), + message: t("generic_error_retry"), }); const initiateDelete = async ( @@ -86,7 +86,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { const confirmAccountDeletion = () => { setDialogBoxAttributesV2({ title: t("delete_account"), - content: , + message: , proceed: { text: t("delete"), action: solveChallengeAndDeleteAccount, @@ -101,7 +101,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { setDialogBoxAttributesV2({ title: t("delete_account"), - content: ( + message: ( }} diff --git a/web/apps/photos/src/components/Sidebar/index.tsx b/web/apps/photos/src/components/Sidebar/index.tsx index f1e2ba8b2b..0275a1f92a 100644 --- a/web/apps/photos/src/components/Sidebar/index.tsx +++ b/web/apps/photos/src/components/Sidebar/index.tsx @@ -681,7 +681,7 @@ const DebugSection: React.FC = () => { const confirmLogDownload = () => showMiniDialog({ title: t("DOWNLOAD_LOGS"), - content: , + message: , proceed: { text: t("download"), variant: "accent", diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 5b68b6839b..9ecc2eb6b5 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -260,7 +260,7 @@ export default function App({ Component, pageProps }: AppProps) { setDialogBoxAttributesV2({ title: t("error"), icon: , - content: t("generic_error"), + message: t("generic_error"), close: { variant: "critical" }, }) ), diff --git a/web/packages/accounts/pages/recover.tsx b/web/packages/accounts/pages/recover.tsx index 531f37763f..c6e86cdafc 100644 --- a/web/packages/accounts/pages/recover.tsx +++ b/web/packages/accounts/pages/recover.tsx @@ -101,7 +101,7 @@ const Page: React.FC = ({ appContext }) => { setDialogBoxAttributesV2({ title: t("sorry"), close: {}, - content: t("NO_RECOVERY_KEY_MESSAGE"), + message: t("NO_RECOVERY_KEY_MESSAGE"), }); return ( diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx index 820a0707e4..be2d2227fd 100644 --- a/web/packages/accounts/pages/two-factor/recover.tsx +++ b/web/packages/accounts/pages/two-factor/recover.tsx @@ -151,7 +151,7 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { appContext.setDialogBoxAttributesV2({ title: t("contact_support"), close: dialogClose ?? {}, - content: ( + message: ( component. */ - content?: React.ReactNode; + message?: React.ReactNode; + /** + * If `true`, then clicks in the backdrop are ignored. The default behaviour + * is to close the dialog when the background is clicked. + */ + staticBackdrop?: boolean; + /** + * If `true`, then the dialog cannot be closed (e.g. with the ESC key, or + * clicking on the backdrop) except through one of the explicitly provided + * actions. + */ + nonClosable?: boolean; + /** + * Customize the primary action button offered by the dialog box. + * + * This is provided by boxes which serve as some sort of confirmation. For + * dialogs which are informational notifications, this is usually skipped, + * only the {@link close} action button is configured. + */ + proceed?: { + /** The string to use as the label for the primary action button. */ + text: string; + /** The color of the button. */ + variant?: ButtonProps["color"]; + /** + * The function to call when the user presses the primary action button. + * + * It is passed a {@link setLoading} function that can be used to show + * or hide loading indicator or the primary action button. + */ + action: + | (() => void | Promise) + | ((setLoading: (value: boolean) => void) => void | Promise); + }; /** * Customize the cancel (dismiss) action button offered by the dialog box. * - * Usually dialog boxes should have a cancel action, but this can be skipped - * to only show one of the other types of buttons. + * Usually all dialog boxes should have a cancel action. */ close?: { /** The string to use as the label for the cancel button. */ @@ -60,24 +90,7 @@ export interface MiniDialogAttributes { */ action?: () => void; }; - /** - * Customize the primary action button offered by the dialog box. - */ - proceed?: { - /** The string to use as the label for the primary action. */ - text: string; - /** - * The function to call when the user presses the primary action button. - * - * It is passed a {@link setLoading} function that can be used to show - * or hide loading indicator or the primary action button. - */ - action: - | (() => void | Promise) - | ((setLoading: (value: boolean) => void) => void | Promise); - variant?: ButtonProps["color"]; - disabled?: boolean; - }; + /** The direction in which the buttons are stacked. Default is "column". */ buttonDirection?: "row" | "column"; } @@ -145,11 +158,10 @@ export const AttributedMiniDialog: React.FC< {attributes.icon} )} - - {attributes.content && ( + {attributes.message && ( - {attributes.content} + {attributes.message} )} {children} @@ -160,7 +172,7 @@ export const AttributedMiniDialog: React.FC< gap: "12px", }} direction={ - attributes.buttonDirection === "row" + attributes.buttonDirection == "row" ? "row-reverse" : "column" } @@ -168,7 +180,7 @@ export const AttributedMiniDialog: React.FC< {attributes.proceed && ( { await attributes.proceed?.action( @@ -177,14 +189,13 @@ export const AttributedMiniDialog: React.FC< onClose(); }} - disabled={attributes.proceed.disabled} > {attributes.proceed.text} )} {attributes.close && ( { attributes.close?.action && diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index cf55625bf3..3b1db3002b 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -292,7 +292,7 @@ const ManageML: React.FC = ({ const confirmDisableML = () => { setDialogBoxAttributesV2({ title: t("ml_search_disable"), - content: t("ml_search_disable_confirm"), + message: t("ml_search_disable_confirm"), close: { text: t("cancel") }, proceed: { variant: "critical", diff --git a/web/packages/new/photos/components/gallery/PeopleHeader.tsx b/web/packages/new/photos/components/gallery/PeopleHeader.tsx index debe3cf9f6..aa0b05922e 100644 --- a/web/packages/new/photos/components/gallery/PeopleHeader.tsx +++ b/web/packages/new/photos/components/gallery/PeopleHeader.tsx @@ -105,7 +105,7 @@ const CGroupPersonOptions: React.FC = ({ const handleDeletePerson = () => setDialogBoxAttributesV2({ title: pt("Reset person?"), - content: pt( + message: pt( "The name, face groupings and suggestions for this person will be reset", ), close: { text: t("cancel") }, diff --git a/web/packages/shared/components/LoginComponents.tsx b/web/packages/shared/components/LoginComponents.tsx index 4f0366a834..7ba8e7ae80 100644 --- a/web/packages/shared/components/LoginComponents.tsx +++ b/web/packages/shared/components/LoginComponents.tsx @@ -207,7 +207,7 @@ export const sessionExpiredDialogAttributes = ( onLogin: () => void, ): MiniDialogAttributes => ({ title: t("SESSION_EXPIRED"), - content: t("SESSION_EXPIRED_MESSAGE"), + message: t("SESSION_EXPIRED_MESSAGE"), nonClosable: true, proceed: { text: t("login"), @@ -222,5 +222,5 @@ export const sessionExpiredDialogAttributes = ( const genericErrorAttributes = (): MiniDialogAttributes => ({ title: t("error"), close: { variant: "critical" }, - content: t("generic_error_retry"), + message: t("generic_error_retry"), }); From a0ecc943d4e9cdab8fcb82b110830e9d195f54b5 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 12:22:02 +0530 Subject: [PATCH 22/43] Fix --- web/apps/auth/src/pages/_app.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx index b2cffcd165..f11505073f 100644 --- a/web/apps/auth/src/pages/_app.tsx +++ b/web/apps/auth/src/pages/_app.tsx @@ -4,7 +4,7 @@ import { clientPackageName, staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; import { type MiniDialogAttributes, - MiniDialog, + AttributedMiniDialog, } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; @@ -134,7 +134,7 @@ const App: React.FC = ({ Component, pageProps }) => { setDialogBoxAttributesV2({ title: t("error"), close: { variant: "critical" }, - content: t("generic_error_retry"), + message: t("generic_error_retry"), }); const logout = () => { @@ -167,7 +167,7 @@ const App: React.FC = ({ Component, pageProps }) => { - Date: Thu, 10 Oct 2024 12:39:50 +0530 Subject: [PATCH 23/43] wip: checkpoint --- web/packages/base/components/MiniDialog.tsx | 50 +++++++++++-------- .../shared/components/LoginComponents.tsx | 4 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 369b150424..a946bc3eeb 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -52,44 +52,50 @@ export interface MiniDialogAttributes { */ nonClosable?: boolean; /** - * Customize the primary action button offered by the dialog box. + * Customize the primary action button shown in the dialog. * * This is provided by boxes which serve as some sort of confirmation. For * dialogs which are informational notifications, this is usually skipped, * only the {@link close} action button is configured. */ - proceed?: { - /** The string to use as the label for the primary action button. */ - text: string; - /** The color of the button. */ - variant?: ButtonProps["color"]; + continue?: { /** - * The function to call when the user presses the primary action button. + * The string to use as the label for the primary action button. + * + * Default is `t("ok")`. + */ + text?: string; + /** + * The color of the button. + * + * Default is "accent". + */ + color?: ButtonProps["color"]; + /** + * If `true`, the primary action button is auto focused when the dialog + * is opened, allowing the user to confirm just by pressing ENTER. + */ + autoFocus?: boolean; + /** + * The function to call when the user activates the button. + * + * Default is to close the dialog. * * It is passed a {@link setLoading} function that can be used to show * or hide loading indicator or the primary action button. */ - action: + action?: | (() => void | Promise) | ((setLoading: (value: boolean) => void) => void | Promise); }; /** - * Customize the cancel (dismiss) action button offered by the dialog box. + * The string to use as the label for the cancel button. * - * Usually all dialog boxes should have a cancel action. + * Default is `t("cancel")`. + * + * Set this to `false` to omit the cancel button altogether. */ - close?: { - /** The string to use as the label for the cancel button. */ - text?: string; - /** The color of the button. */ - variant?: ButtonProps["color"]; - /** - * The function to call when the user cancels. - * - * If provided, this callback is invoked before closing the dialog. - */ - action?: () => void; - }; + cancel?: string | false; /** The direction in which the buttons are stacked. Default is "column". */ buttonDirection?: "row" | "column"; } diff --git a/web/packages/shared/components/LoginComponents.tsx b/web/packages/shared/components/LoginComponents.tsx index 7ba8e7ae80..652900ab60 100644 --- a/web/packages/shared/components/LoginComponents.tsx +++ b/web/packages/shared/components/LoginComponents.tsx @@ -209,11 +209,11 @@ export const sessionExpiredDialogAttributes = ( title: t("SESSION_EXPIRED"), message: t("SESSION_EXPIRED_MESSAGE"), nonClosable: true, - proceed: { + continue: { text: t("login"), action: onLogin, - variant: "accent", }, + cancel: false, }); /** From 473e22c0c1d6ac86e90be1d0efe50eac9b38fd42 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 12:44:07 +0530 Subject: [PATCH 24/43] wip checkpoint --- web/packages/base/components/MiniDialog.tsx | 85 +++++++++------------ 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index a946bc3eeb..0744077582 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -4,7 +4,6 @@ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { LoadingButton } from "@/base/components/mui/LoadingButton"; -import { dialogCloseHandler } from "@ente/shared/components/DialogBox/TitleWithCloseButton"; import type { ButtonProps } from "@mui/material"; import { Box, @@ -122,11 +121,10 @@ export const AttributedMiniDialog: React.FC< return <>; } - const handleClose = dialogCloseHandler({ - staticBackdrop: attributes.staticBackdrop, - nonClosable: attributes.nonClosable, - onClose: onClose, - }); + const handleClose = () => { + if (attributes.nonClosable) return; + onClose(); + }; const { PaperProps, ...rest } = props; @@ -171,49 +169,38 @@ export const AttributedMiniDialog: React.FC< )} {children} - {(attributes.proceed || attributes.close) && ( - - {attributes.proceed && ( - { - await attributes.proceed?.action( - setLoading, - ); - - onClose(); - }} - > - {attributes.proceed.text} - - )} - {attributes.close && ( - { - attributes.close?.action && - attributes.close?.action(); - onClose(); - }} - > - {attributes.close?.text ?? t("ok")} - - )} - - )} + + {attributes.continue && ( + { + await attributes.continue?.action?.(setLoading); + onClose(); + }} + > + {attributes.continue?.text ?? t("ok")} + + )} + {attributes.cancel && ( + + {attributes.cancel ?? t("cancel")} + + )} + ); From 8b24225fbbfc9416de41a902affeaaf660cd2b43 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 13:07:34 +0530 Subject: [PATCH 25/43] wip checkpoint --- web/apps/accounts/src/pages/_app.tsx | 25 ++++++++++++------- .../photos/src/components/Sidebar/index.tsx | 6 +---- web/packages/accounts/types/context.ts | 17 ++++++++++--- web/packages/new/photos/types/context.ts | 11 +------- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 02d27bd390..32cdeff553 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -16,7 +16,7 @@ import { CssBaseline } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import { t } from "i18next"; import type { AppProps } from "next/app"; -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { AppContext } from "../types/context"; import "styles/global.css"; @@ -24,10 +24,23 @@ import "styles/global.css"; const App: React.FC = ({ Component, pageProps }) => { const [isI18nReady, setIsI18nReady] = useState(false); const [showNavbar, setShowNavbar] = useState(false); - const [dialogBoxAttributeV2, setDialogBoxAttributesV2] = useState< + + // Mini Dialog scaffolding -- + + const [miniDialogAttributes, setMiniDialogAttributes] = useState< MiniDialogAttributes | undefined >(); - const [dialogBoxV2View, setDialogBoxV2View] = useState(false); + + const [openMiniDialog, setOpenMiniDialog] = useState(false); + + const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { + setMiniDialogAttributes(attributes); + setOpenMiniDialog(true); + }, []); + + const closeMiniDialog = useCallback(() => setOpenMiniDialog(false), []); + + // -- useEffect(() => { disableDiskLogs(); @@ -36,12 +49,6 @@ const App: React.FC = ({ Component, pageProps }) => { return () => logUnhandledErrorsAndRejections(false); }, []); - useEffect(() => { - setDialogBoxV2View(true); - }, [dialogBoxAttributeV2]); - - const closeDialogBoxV2 = () => setDialogBoxV2View(false); - const appContext = { showNavBar: setShowNavbar, setDialogBoxAttributesV2, diff --git a/web/apps/photos/src/components/Sidebar/index.tsx b/web/apps/photos/src/components/Sidebar/index.tsx index 0275a1f92a..6f54c88582 100644 --- a/web/apps/photos/src/components/Sidebar/index.tsx +++ b/web/apps/photos/src/components/Sidebar/index.tsx @@ -682,14 +682,10 @@ const DebugSection: React.FC = () => { showMiniDialog({ title: t("DOWNLOAD_LOGS"), message: , - proceed: { + continue: { text: t("download"), - variant: "accent", action: downloadLogs, }, - close: { - text: t("cancel"), - }, }); const downloadLogs = () => { diff --git a/web/packages/accounts/types/context.ts b/web/packages/accounts/types/context.ts index ae9fd7b9b6..d625db096c 100644 --- a/web/packages/accounts/types/context.ts +++ b/web/packages/accounts/types/context.ts @@ -5,9 +5,20 @@ import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; * defer to the pages provided by the accounts package. */ export interface AccountsContextT { - /** Perform the (possibly app specific) logout sequence. */ + /** + * Perform the (possibly app specific) logout sequence. + */ logout: () => void; - /** Show or hide the app's navigation bar. */ + /** + * Show or hide the app's navigation bar. + */ showNavBar: (show: boolean) => void; - setDialogBoxAttributesV2: (attrs: MiniDialogAttributes) => void; + /** + * Show a "mini dialog" with the given attributes. + * + * Mini dialogs (see {@link AttributedMiniDialog}) are meant for simple + * confirmation or notications. Their appearance and functionality can be + * customized by providing appropriate {@link MiniDialogAttributes}. + */ + showMiniDialog: (attributes: MiniDialogAttributes) => void; } diff --git a/web/packages/new/photos/types/context.ts b/web/packages/new/photos/types/context.ts index 4c11a9bb01..993bab29e5 100644 --- a/web/packages/new/photos/types/context.ts +++ b/web/packages/new/photos/types/context.ts @@ -4,7 +4,6 @@ import type { SetDialogBoxAttributes } from "@ente/shared/components/DialogBox/t import { THEME_COLOR } from "@ente/shared/themes/constants"; import { createContext, useContext } from "react"; import type { SetNotificationAttributes } from "./notification"; -import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; /** * The type of the React context available to all pages in the photos app. @@ -18,18 +17,10 @@ export type AppContextT = AccountsContextT & { * Hide the global activity indicator. */ finishLoading: () => void; - /** - * Show a "mini dialog" with the given attributes. - * - * Mini dialogs (see {@link AttributedMiniDialog}) are meant for simple - * confirmation or notication dialogs. Their appearance and functionality - * can be customized by providing relevant {@link MiniDialogAttributes}. - */ - showMiniDialog: (attributes: MiniDialogAttributes) => void; + onGenericError: (error: unknown) => void; somethingWentWrong: () => void; setDialogMessage: SetDialogBoxAttributes; setNotificationAttributes: SetNotificationAttributes; - onGenericError: (error: unknown) => void; closeMessageDialog: () => void; mapEnabled: boolean; updateMapEnabled: (enabled: boolean) => Promise; From 88c10db52d7cc2d6f89c5abd4b74707261f5733f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 14:18:34 +0530 Subject: [PATCH 26/43] Create helper hook --- web/apps/accounts/src/pages/_app.tsx | 43 ++++++------------- web/apps/accounts/src/types/context.ts | 8 +--- web/packages/base/components/MiniDialog.tsx | 20 --------- .../base/components/hooks/use-mini-dialog.ts | 31 +++++++++++++ 4 files changed, 45 insertions(+), 57 deletions(-) create mode 100644 web/packages/base/components/hooks/use-mini-dialog.ts diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 32cdeff553..87a1008602 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -1,9 +1,7 @@ import { staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; -import { - type MiniDialogAttributes, - AttributedMiniDialog, -} from "@/base/components/MiniDialog"; +import { useAttributedMiniDialog } from "@/base/components/hooks/use-mini-dialog"; +import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; import { setupI18n } from "@/base/i18n"; @@ -16,7 +14,7 @@ import { CssBaseline } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import { t } from "i18next"; import type { AppProps } from "next/app"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { AppContext } from "../types/context"; import "styles/global.css"; @@ -24,23 +22,7 @@ import "styles/global.css"; const App: React.FC = ({ Component, pageProps }) => { const [isI18nReady, setIsI18nReady] = useState(false); const [showNavbar, setShowNavbar] = useState(false); - - // Mini Dialog scaffolding -- - - const [miniDialogAttributes, setMiniDialogAttributes] = useState< - MiniDialogAttributes | undefined - >(); - - const [openMiniDialog, setOpenMiniDialog] = useState(false); - - const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { - setMiniDialogAttributes(attributes); - setOpenMiniDialog(true); - }, []); - - const closeMiniDialog = useCallback(() => setOpenMiniDialog(false), []); - - // -- + const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); useEffect(() => { disableDiskLogs(); @@ -49,10 +31,13 @@ const App: React.FC = ({ Component, pageProps }) => { return () => logUnhandledErrorsAndRejections(false); }, []); - const appContext = { - showNavBar: setShowNavbar, - setDialogBoxAttributesV2, - }; + const appContext = useMemo( + () => ({ + showNavBar: setShowNavbar, + showMiniDialog, + }), + [showMiniDialog], + ); const title = isI18nReady ? t("title_accounts") : staticAppTitle; @@ -62,11 +47,7 @@ const App: React.FC = ({ Component, pageProps }) => { - + {!isI18nReady && ( diff --git a/web/apps/accounts/src/types/context.ts b/web/apps/accounts/src/types/context.ts index e095490524..dece58358d 100644 --- a/web/apps/accounts/src/types/context.ts +++ b/web/apps/accounts/src/types/context.ts @@ -1,15 +1,11 @@ -import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; +import type { AccountsContextT } from "@/accounts/types/context"; import { ensure } from "@/utils/ensure"; import { createContext, useContext } from "react"; /** * The type of the context for pages in the accounts app. */ -interface AppContextT { - /** Show or hide the app's navigation bar. */ - showNavBar: (show: boolean) => void; - setDialogBoxAttributesV2: (attrs: MiniDialogAttributes) => void; -} +type AppContextT = Omit; /** * The React {@link Context} available to all nodes in the React tree. diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 0744077582..dcf0a53239 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -206,26 +206,6 @@ export const AttributedMiniDialog: React.FC< ); }; -// TODO: Sketch of a possible approach to using this. Haven't throught this -// through, just noting down the outline inspired by an API I saw. -// /** -// * A React hook for simplifying use of MiniDialog within the photos app context. -// * -// * It relies on the presence of the {@link setDialogBoxAttributesV2} function -// * provided by the Photos app's {@link AppContext}. -// */ -// export const useConfirm = (attr) => { -// const {setDialogBoxAttributesV2} = useAppContext(); -// return () => { -// new Promise((resolve) => { -// setDialogBoxAttributesV2( -// proceed: { -// action: attr.action.then(resolve) -// } -// ) -// } -// } - type TitledMiniDialogProps = Omit & { onClose: () => void; /** diff --git a/web/packages/base/components/hooks/use-mini-dialog.ts b/web/packages/base/components/hooks/use-mini-dialog.ts new file mode 100644 index 0000000000..8ac74536a0 --- /dev/null +++ b/web/packages/base/components/hooks/use-mini-dialog.ts @@ -0,0 +1,31 @@ +import { useCallback, useState } from "react"; +import type { MiniDialogAttributes } from "../MiniDialog"; + +/** + * A React hook for simplifying the provisioning of a {@link showMiniDialog} + * function to inject in app contexts, and the other props that are needed for + * to pass on to the {@link AttributedMiniDialog}. + */ +export const useAttributedMiniDialog = () => { + const [miniDialogAttributes, setMiniDialogAttributes] = useState< + MiniDialogAttributes | undefined + >(); + + const [openMiniDialog, setOpenMiniDialog] = useState(false); + + const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { + setMiniDialogAttributes(attributes); + setOpenMiniDialog(true); + }, []); + + const onCloseMiniDialog = useCallback(() => setOpenMiniDialog(false), []); + + return { + showMiniDialog, + miniDialogProps: { + open: openMiniDialog, + onClose: onCloseMiniDialog, + attributes: miniDialogAttributes, + }, + }; +}; From 68e7a38463a08ae0ea1680515066c786642b1ec6 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 14:37:06 +0530 Subject: [PATCH 27/43] Another helper --- web/apps/accounts/src/pages/_app.tsx | 2 +- .../accounts/src/pages/passkeys/index.tsx | 8 +++--- .../use-mini-dialog.tsx} | 28 +++++++++++++++++++ web/packages/build-config/eslintrc-react.js | 5 ++++ 4 files changed, 38 insertions(+), 5 deletions(-) rename web/packages/base/components/{hooks/use-mini-dialog.ts => utils/use-mini-dialog.tsx} (55%) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 87a1008602..36bbcd39ab 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -1,9 +1,9 @@ import { staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; -import { useAttributedMiniDialog } from "@/base/components/hooks/use-mini-dialog"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; +import { useAttributedMiniDialog } from "@/base/hooks/use-mini-dialog"; import { setupI18n } from "@/base/i18n"; import { disableDiskLogs } from "@/base/log"; import { logUnhandledErrorsAndRejections } from "@/base/log-web"; diff --git a/web/apps/accounts/src/pages/passkeys/index.tsx b/web/apps/accounts/src/pages/passkeys/index.tsx index d365af0b6d..c909602910 100644 --- a/web/apps/accounts/src/pages/passkeys/index.tsx +++ b/web/apps/accounts/src/pages/passkeys/index.tsx @@ -34,7 +34,7 @@ import { import { useAppContext } from "../../types/context"; const Page: React.FC = () => { - const { showNavBar, setDialogBoxAttributesV2 } = useAppContext(); + const { showNavBar, showMiniDialog } = useAppContext(); const [token, setToken] = useState(); const [passkeys, setPasskeys] = useState([]); @@ -44,12 +44,12 @@ const Page: React.FC = () => { >(); const showPasskeyFetchFailedErrorDialog = useCallback(() => { - setDialogBoxAttributesV2({ + showMiniDialog({ title: t("error"), message: t("passkey_fetch_failed"), - close: {}, + cancel: false, }); - }, [setDialogBoxAttributesV2]); + }, [showMiniDialog]); useEffect(() => { showNavBar(true); diff --git a/web/packages/base/components/hooks/use-mini-dialog.ts b/web/packages/base/components/utils/use-mini-dialog.tsx similarity index 55% rename from web/packages/base/components/hooks/use-mini-dialog.ts rename to web/packages/base/components/utils/use-mini-dialog.tsx index 8ac74536a0..cad7a557f2 100644 --- a/web/packages/base/components/hooks/use-mini-dialog.ts +++ b/web/packages/base/components/utils/use-mini-dialog.tsx @@ -1,3 +1,5 @@ +import ErrorOutline from "@mui/icons-material/ErrorOutline"; +import { t } from "i18next"; import { useCallback, useState } from "react"; import type { MiniDialogAttributes } from "../MiniDialog"; @@ -29,3 +31,29 @@ export const useAttributedMiniDialog = () => { }, }; }; + +/** + * A convenience function to construct {@link MiniDialogAttributes} for showing + * error dialogs. + * + * It takes one or two arguments. + * + * - If both are provided, then the first one is taken as the title and the + * second one as the message. + * + * - Otherwise it sets a default title and use the only argument as the message. + */ +export const errorAttributes = ( + messageOrTitle: string, + optionalMessage?: string, +): MiniDialogAttributes => { + const title = optionalMessage ? messageOrTitle : t("error"); + const message = optionalMessage ? optionalMessage : messageOrTitle; + + return { + title, + icon: , + message, + continue: { color: "critical" }, + }; +}; diff --git a/web/packages/build-config/eslintrc-react.js b/web/packages/build-config/eslintrc-react.js index 571d37e622..098403b08b 100644 --- a/web/packages/build-config/eslintrc-react.js +++ b/web/packages/build-config/eslintrc-react.js @@ -13,9 +13,14 @@ module.exports = { "react/jsx-no-target-blank": ["warn", { allowReferrer: true }], /* Otherwise we need to do unnecessary boilerplating when using memo. */ "react/display-name": "off", + /* Apparently Fast refresh only works if a file only exports components, + and this rule warns about that. Constants are okay though (otherwise + we'll need to create unnecessary helper files). */ "react-refresh/only-export-components": [ "warn", { allowConstantExport: true }, ], + /* Next.js supports the JSX transform introduced in React 17 */ + "react/react-in-jsx-scope": "off", }, }; From 79eb912a420d2619481f9cfcf27b0d0b9661184d Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 14:41:30 +0530 Subject: [PATCH 28/43] Fin apps/accounts --- web/apps/accounts/src/pages/_app.tsx | 2 +- .../accounts/src/pages/passkeys/index.tsx | 19 ++++++++----------- .../{use-mini-dialog.tsx => mini-dialog.tsx} | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) rename web/packages/base/components/utils/{use-mini-dialog.tsx => mini-dialog.tsx} (98%) diff --git a/web/apps/accounts/src/pages/_app.tsx b/web/apps/accounts/src/pages/_app.tsx index 36bbcd39ab..49e9739ea1 100644 --- a/web/apps/accounts/src/pages/_app.tsx +++ b/web/apps/accounts/src/pages/_app.tsx @@ -3,7 +3,7 @@ import { CustomHead } from "@/base/components/Head"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; -import { useAttributedMiniDialog } from "@/base/hooks/use-mini-dialog"; +import { useAttributedMiniDialog } from "@/base/components/utils/mini-dialog"; import { setupI18n } from "@/base/i18n"; import { disableDiskLogs } from "@/base/log"; import { logUnhandledErrorsAndRejections } from "@/base/log-web"; diff --git a/web/apps/accounts/src/pages/passkeys/index.tsx b/web/apps/accounts/src/pages/passkeys/index.tsx index c909602910..3b6f6af2d2 100644 --- a/web/apps/accounts/src/pages/passkeys/index.tsx +++ b/web/apps/accounts/src/pages/passkeys/index.tsx @@ -1,6 +1,7 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; +import { mdErrorAttributes } from "@/base/components/utils/mini-dialog"; import log from "@/base/log"; import { ensure } from "@/utils/ensure"; import { CenteredFlex } from "@ente/shared/components/Container"; @@ -44,11 +45,7 @@ const Page: React.FC = () => { >(); const showPasskeyFetchFailedErrorDialog = useCallback(() => { - showMiniDialog({ - title: t("error"), - message: t("passkey_fetch_failed"), - cancel: false, - }); + showMiniDialog(mdErrorAttributes(t("passkey_fetch_failed"))); }, [showMiniDialog]); useEffect(() => { @@ -263,11 +260,12 @@ const ManagePasskeyDrawer: React.FC = ({ passkey, onUpdateOrDeletePasskey, }) => { - const { setDialogBoxAttributesV2 } = useAppContext(); + const { showMiniDialog } = useAppContext(); const [showRenameDialog, setShowRenameDialog] = useState(false); const showDeleteConfirmationDialog = useCallback(() => { + /* mark: uses-loading */ const handleDelete = async (setLoading: (value: boolean) => void) => { setLoading(true); try { @@ -280,17 +278,16 @@ const ManagePasskeyDrawer: React.FC = ({ } }; - setDialogBoxAttributesV2({ + showMiniDialog({ title: t("delete_passkey"), message: t("delete_passkey_confirmation"), - proceed: { + continue: { text: t("delete"), + color: "critical", action: handleDelete, - variant: "critical", }, - close: { text: t("cancel") }, }); - }, [token, passkey, onUpdateOrDeletePasskey, setDialogBoxAttributesV2]); + }, [showMiniDialog, token, passkey, onUpdateOrDeletePasskey]); return ( <> diff --git a/web/packages/base/components/utils/use-mini-dialog.tsx b/web/packages/base/components/utils/mini-dialog.tsx similarity index 98% rename from web/packages/base/components/utils/use-mini-dialog.tsx rename to web/packages/base/components/utils/mini-dialog.tsx index cad7a557f2..0b81aea53b 100644 --- a/web/packages/base/components/utils/use-mini-dialog.tsx +++ b/web/packages/base/components/utils/mini-dialog.tsx @@ -43,7 +43,7 @@ export const useAttributedMiniDialog = () => { * * - Otherwise it sets a default title and use the only argument as the message. */ -export const errorAttributes = ( +export const mdErrorAttributes = ( messageOrTitle: string, optionalMessage?: string, ): MiniDialogAttributes => { From 03e5e16bc3307e53ad33975784a11827d38af574 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 15:00:28 +0530 Subject: [PATCH 29/43] Move --- .../components/LoginComponents.tsx | 8 ++++---- web/packages/accounts/pages/credentials.tsx | 12 ++++++------ web/packages/accounts/pages/verify.tsx | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) rename web/packages/{shared => accounts}/components/LoginComponents.tsx (96%) diff --git a/web/packages/shared/components/LoginComponents.tsx b/web/packages/accounts/components/LoginComponents.tsx similarity index 96% rename from web/packages/shared/components/LoginComponents.tsx rename to web/packages/accounts/components/LoginComponents.tsx index 652900ab60..a1b5158bda 100644 --- a/web/packages/shared/components/LoginComponents.tsx +++ b/web/packages/accounts/components/LoginComponents.tsx @@ -7,14 +7,14 @@ import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import log from "@/base/log"; import { customAPIHost } from "@/base/origins"; +import { VerticallyCentered } from "@ente/shared/components/Container"; +import FormPaper from "@ente/shared/components/Form/FormPaper"; +import FormPaperFooter from "@ente/shared/components/Form/FormPaper/Footer"; +import LinkButton from "@ente/shared/components/LinkButton"; import { CircularProgress, Stack, Typography, styled } from "@mui/material"; import { t } from "i18next"; import { useRouter } from "next/router"; import React, { useEffect, useState } from "react"; -import { VerticallyCentered } from "./Container"; -import FormPaper from "./Form/FormPaper"; -import FormPaperFooter from "./Form/FormPaper/Footer"; -import LinkButton from "./LinkButton"; export const PasswordHeader: React.FC = ({ children, diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index 5ffb93b73b..ca8245258f 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -7,12 +7,6 @@ import { ensure } from "@/utils/ensure"; import { VerticallyCentered } from "@ente/shared/components/Container"; import FormPaper from "@ente/shared/components/Form/FormPaper"; import LinkButton from "@ente/shared/components/LinkButton"; -import { - LoginFlowFormFooter, - PasswordHeader, - VerifyingPasskey, - sessionExpiredDialogAttributes, -} from "@ente/shared/components/LoginComponents"; import VerifyMasterPasswordForm, { type VerifyMasterPasswordFormProps, } from "@ente/shared/components/VerifyMasterPasswordForm"; @@ -46,6 +40,12 @@ import { t } from "i18next"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; import { getSRPAttributes } from "../api/srp"; +import { + LoginFlowFormFooter, + PasswordHeader, + VerifyingPasskey, + sessionExpiredDialogAttributes, +} from "../components/LoginComponents"; import { PAGES } from "../constants/pages"; import { openPasskeyVerificationURL, diff --git a/web/packages/accounts/pages/verify.tsx b/web/packages/accounts/pages/verify.tsx index 860459d3c9..c3b334cdd7 100644 --- a/web/packages/accounts/pages/verify.tsx +++ b/web/packages/accounts/pages/verify.tsx @@ -6,10 +6,6 @@ import { VerticallyCentered } from "@ente/shared/components/Container"; import FormPaper from "@ente/shared/components/Form/FormPaper"; import FormPaperTitle from "@ente/shared/components/Form/FormPaper/Title"; import LinkButton from "@ente/shared/components/LinkButton"; -import { - LoginFlowFormFooter, - VerifyingPasskey, -} from "@ente/shared/components/LoginComponents"; import SingleInputForm, { type SingleInputFormProps, } from "@ente/shared/components/SingleInputForm"; @@ -35,6 +31,10 @@ import { useEffect, useState } from "react"; import { Trans } from "react-i18next"; import { getSRPAttributes } from "../api/srp"; import { putAttributes, sendOtt, verifyOtt } from "../api/user"; +import { + LoginFlowFormFooter, + VerifyingPasskey, +} from "../components/LoginComponents"; import { PAGES } from "../constants/pages"; import { openPasskeyVerificationURL, From 6b64e20a7ea5405e88853342ad2ec6b3ae1c3d58 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 15:22:21 +0530 Subject: [PATCH 30/43] Move --- .../accounts/src/pages/passkeys/index.tsx | 4 ++-- .../accounts/components/LoginComponents.tsx | 19 +++++-------------- .../base/components/utils/mini-dialog.tsx | 5 ++++- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/web/apps/accounts/src/pages/passkeys/index.tsx b/web/apps/accounts/src/pages/passkeys/index.tsx index 3b6f6af2d2..fb9f591ad5 100644 --- a/web/apps/accounts/src/pages/passkeys/index.tsx +++ b/web/apps/accounts/src/pages/passkeys/index.tsx @@ -1,7 +1,7 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; import { MenuItemDivider, MenuItemGroup } from "@/base/components/Menu"; import { Titlebar } from "@/base/components/Titlebar"; -import { mdErrorAttributes } from "@/base/components/utils/mini-dialog"; +import { errorDialogAttributes } from "@/base/components/utils/mini-dialog"; import log from "@/base/log"; import { ensure } from "@/utils/ensure"; import { CenteredFlex } from "@ente/shared/components/Container"; @@ -45,7 +45,7 @@ const Page: React.FC = () => { >(); const showPasskeyFetchFailedErrorDialog = useCallback(() => { - showMiniDialog(mdErrorAttributes(t("passkey_fetch_failed"))); + showMiniDialog(errorDialogAttributes(t("passkey_fetch_failed"))); }, [showMiniDialog]); useEffect(() => { diff --git a/web/packages/accounts/components/LoginComponents.tsx b/web/packages/accounts/components/LoginComponents.tsx index a1b5158bda..b7bdb675c3 100644 --- a/web/packages/accounts/components/LoginComponents.tsx +++ b/web/packages/accounts/components/LoginComponents.tsx @@ -5,6 +5,7 @@ import { } from "@/accounts/services/passkey"; import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; +import { genericErrorDialogAttributes } from "@/base/components/utils/mini-dialog"; import log from "@/base/log"; import { customAPIHost } from "@/base/origins"; import { VerticallyCentered } from "@ente/shared/components/Container"; @@ -108,7 +109,7 @@ export const VerifyingPasskey: React.FC = ({ e instanceof Error && e.message == passkeySessionExpiredErrorMessage ? sessionExpiredDialogAttributes(logout) - : genericErrorAttributes(), + : genericErrorDialogAttributes(), ); setVerificationStatus("waiting"); } @@ -194,11 +195,10 @@ const ButtonStack = styled("div")` `; /** - * {@link DialogBoxAttributesV2} for showing the error when the user's session - * has expired. + * {@link MiniDialogAttributes} for showing asking the user to login again when + * their session has expired. * - * It asks them to login again. There is one button, which allows them to - * logout. + * There is one button, which allows them to logout. * * @param onLogin Called when the user presses the "Login" button on the error * dialog. @@ -215,12 +215,3 @@ export const sessionExpiredDialogAttributes = ( }, cancel: false, }); - -/** - * {@link DialogBoxAttributesV2} for showing a generic error. - */ -const genericErrorAttributes = (): MiniDialogAttributes => ({ - title: t("error"), - close: { variant: "critical" }, - message: t("generic_error_retry"), -}); diff --git a/web/packages/base/components/utils/mini-dialog.tsx b/web/packages/base/components/utils/mini-dialog.tsx index 0b81aea53b..088e8511f2 100644 --- a/web/packages/base/components/utils/mini-dialog.tsx +++ b/web/packages/base/components/utils/mini-dialog.tsx @@ -43,7 +43,7 @@ export const useAttributedMiniDialog = () => { * * - Otherwise it sets a default title and use the only argument as the message. */ -export const mdErrorAttributes = ( +export const errorDialogAttributes = ( messageOrTitle: string, optionalMessage?: string, ): MiniDialogAttributes => { @@ -57,3 +57,6 @@ export const mdErrorAttributes = ( continue: { color: "critical" }, }; }; + +export const genericErrorDialogAttributes = () => + errorDialogAttributes(t("generic_error")); From d6a39ae45262364e5979ba63d09a20b5f334c374 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 15:27:31 +0530 Subject: [PATCH 31/43] wip checkpoint --- web/apps/auth/src/pages/_app.tsx | 37 +++++---------- web/apps/auth/src/pages/auth.tsx | 6 +-- .../src/components/AuthenticateUserModal.tsx | 11 ++--- .../src/components/DeleteAccountModal.tsx | 31 +++++-------- .../components/PhotoViewer/FileInfo/index.tsx | 45 +++++++++++++++---- web/apps/photos/src/utils/ui/index.tsx | 40 +---------------- .../accounts/components/LoginComponents.tsx | 6 +-- web/packages/accounts/pages/credentials.tsx | 8 ++-- web/packages/accounts/pages/verify.tsx | 4 +- 9 files changed, 75 insertions(+), 113 deletions(-) diff --git a/web/apps/auth/src/pages/_app.tsx b/web/apps/auth/src/pages/_app.tsx index f11505073f..e18b0684ff 100644 --- a/web/apps/auth/src/pages/_app.tsx +++ b/web/apps/auth/src/pages/_app.tsx @@ -2,12 +2,13 @@ import { accountLogout } from "@/accounts/services/logout"; import type { AccountsContextT } from "@/accounts/types/context"; import { clientPackageName, staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; -import { - type MiniDialogAttributes, - AttributedMiniDialog, -} from "@/base/components/MiniDialog"; +import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; +import { + genericErrorDialogAttributes, + useAttributedMiniDialog, +} from "@/base/components/utils/mini-dialog"; import { setupI18n } from "@/base/i18n"; import { logStartupBanner, @@ -39,6 +40,7 @@ import React, { useState, } from "react"; import LoadingBar, { type LoadingBarRef } from "react-top-loading-bar"; + import "../../public/css/global.css"; /** @@ -68,10 +70,8 @@ const App: React.FC = ({ Component, pageProps }) => { const [showNavbar, setShowNavBar] = useState(false); const isLoadingBarRunning = useRef(false); const loadingBar = useRef(null); - const [dialogBoxAttributeV2, setDialogBoxAttributesV2] = useState< - MiniDialogAttributes | undefined - >(); - const [dialogBoxV2View, setDialogBoxV2View] = useState(false); + + const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); const [themeColor, setThemeColor] = useLocalState( LS_KEYS.THEME, THEME_COLOR.DARK, @@ -111,16 +111,13 @@ const App: React.FC = ({ Component, pageProps }) => { }; }, []); - useEffect(() => { - setDialogBoxV2View(true); - }, [dialogBoxAttributeV2]); - const showNavBar = (show: boolean) => setShowNavBar(show); const startLoading = () => { !isLoadingBarRunning.current && loadingBar.current?.continuousStart(); isLoadingBarRunning.current = true; }; + const finishLoading = () => { setTimeout(() => { isLoadingBarRunning.current && loadingBar.current?.complete(); @@ -128,14 +125,8 @@ const App: React.FC = ({ Component, pageProps }) => { }, 100); }; - const closeDialogBoxV2 = () => setDialogBoxV2View(false); - const somethingWentWrong = () => - setDialogBoxAttributesV2({ - title: t("error"), - close: { variant: "critical" }, - message: t("generic_error_retry"), - }); + showMiniDialog(genericErrorDialogAttributes()); const logout = () => { void accountLogout().then(() => router.push("/")); @@ -144,7 +135,7 @@ const App: React.FC = ({ Component, pageProps }) => { const appContext = { logout, showNavBar, - setDialogBoxAttributesV2, + showMiniDialog, startLoading, finishLoading, themeColor, @@ -167,11 +158,7 @@ const App: React.FC = ({ Component, pageProps }) => { - + {(loading || !isI18nReady) && ( diff --git a/web/apps/auth/src/pages/auth.tsx b/web/apps/auth/src/pages/auth.tsx index 917808bd83..6fb996cf3f 100644 --- a/web/apps/auth/src/pages/auth.tsx +++ b/web/apps/auth/src/pages/auth.tsx @@ -1,3 +1,4 @@ +import { sessionExpiredDialogAttributes } from "@/accounts/components/LoginComponents"; import { stashRedirect } from "@/accounts/services/redirect"; import { EnteLogo } from "@/base/components/EnteLogo"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; @@ -7,7 +8,6 @@ import { HorizontalFlex, VerticallyCentered, } from "@ente/shared/components/Container"; -import { sessionExpiredDialogAttributes } from "@ente/shared/components/LoginComponents"; import OverflowMenu from "@ente/shared/components/OverflowMenu/menu"; import { OverflowMenuOption } from "@ente/shared/components/OverflowMenu/option"; import { AUTH_PAGES as PAGES } from "@ente/shared/constants/pages"; @@ -23,7 +23,7 @@ import { getAuthCodes } from "services/remote"; import { AppContext } from "./_app"; const Page: React.FC = () => { - const { logout, showNavBar, setDialogBoxAttributesV2 } = ensure( + const { logout, showNavBar, showMiniDialog } = ensure( useContext(AppContext), ); const router = useRouter(); @@ -32,7 +32,7 @@ const Page: React.FC = () => { const [searchTerm, setSearchTerm] = useState(""); const showSessionExpiredDialog = () => - setDialogBoxAttributesV2(sessionExpiredDialogAttributes(logout)); + showMiniDialog(sessionExpiredDialogAttributes(logout)); useEffect(() => { const fetchCodes = async () => { diff --git a/web/apps/photos/src/components/AuthenticateUserModal.tsx b/web/apps/photos/src/components/AuthenticateUserModal.tsx index 0b6a83b7f9..6f17a61bc7 100644 --- a/web/apps/photos/src/components/AuthenticateUserModal.tsx +++ b/web/apps/photos/src/components/AuthenticateUserModal.tsx @@ -24,8 +24,7 @@ export default function AuthenticateUserModal({ onClose, onAuthenticate, }: Iprops) { - const { setDialogMessage, setDialogBoxAttributesV2, logout } = - useContext(AppContext); + const { setDialogMessage, showMiniDialog, logout } = useContext(AppContext); const [user, setUser] = useState(); const [keyAttributes, setKeyAttributes] = useState(); @@ -46,7 +45,7 @@ export default function AuthenticateUserModal({ const session = await checkSessionValidity(); if (session.status != "valid") { onClose(); - setDialogBoxAttributesV2( + showMiniDialog( passwordChangedElsewhereDialogAttributes(logout), ); } @@ -55,7 +54,7 @@ export default function AuthenticateUserModal({ // potentially transient issues. log.warn("Ignoring error when determining session validity", e); } - }, [setDialogBoxAttributesV2, logout]); + }, [showMiniDialog, logout]); useEffect(() => { const main = async () => { @@ -127,10 +126,8 @@ const passwordChangedElsewhereDialogAttributes = ( ): MiniDialogAttributes => ({ title: t("password_changed_elsewhere"), message: t("password_changed_elsewhere_message"), - proceed: { + continue: { text: t("login"), action: onLogin, - variant: "accent", }, - close: { text: t("cancel") }, }); diff --git a/web/apps/photos/src/components/DeleteAccountModal.tsx b/web/apps/photos/src/components/DeleteAccountModal.tsx index 8b75b2a630..82cd039c44 100644 --- a/web/apps/photos/src/components/DeleteAccountModal.tsx +++ b/web/apps/photos/src/components/DeleteAccountModal.tsx @@ -1,7 +1,6 @@ import { TitledMiniDialog } from "@/base/components/MiniDialog"; import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { LoadingButton } from "@/base/components/mui/LoadingButton"; -import log from "@/base/log"; import { AppContext } from "@/new/photos/types/context"; import { initiateEmail } from "@/new/photos/utils/web"; import { Link, Stack, useMediaQuery } from "@mui/material"; @@ -28,7 +27,7 @@ interface FormValues { } const DeleteAccountModal = ({ open, onClose }: Iprops) => { - const { setDialogBoxAttributesV2, logout } = useContext(AppContext); + const { showMiniDialog, onGenericError, logout } = useContext(AppContext); const { authenticateUser } = useContext(GalleryContext); const [loading, setLoading] = useState(false); @@ -39,13 +38,6 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { const isMobile = useMediaQuery("(max-width: 428px)"); - const somethingWentWrong = () => - setDialogBoxAttributesV2({ - title: t("error"), - close: { variant: "critical" }, - message: t("generic_error_retry"), - }); - const initiateDelete = async ( { reason, feedback }: FormValues, { setFieldError }: FormikHelpers, @@ -76,30 +68,28 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { askToMailForDeletion(); } } catch (e) { - log.error("Error while initiating account deletion", e); - somethingWentWrong(); + onGenericError(e); } finally { setLoading(false); } }; const confirmAccountDeletion = () => { - setDialogBoxAttributesV2({ + showMiniDialog({ title: t("delete_account"), message: , - proceed: { + continue: { text: t("delete"), + color: "critical", action: solveChallengeAndDeleteAccount, - variant: "critical", }, - close: { text: t("cancel") }, }); }; const askToMailForDeletion = () => { const emailID = "account-deletion@ente.io"; - setDialogBoxAttributesV2({ + showMiniDialog({ title: t("delete_account"), message: ( { values={{ emailID }} /> ), - proceed: { + continue: { text: t("delete"), + color: "critical", action: () => initiateEmail(emailID), - variant: "critical", }, - close: { text: t("cancel") }, }); }; + /* mark: uses-loading */ const solveChallengeAndDeleteAccount = async ( setLoading: (value: boolean) => void, ) => { @@ -129,8 +119,7 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { await deleteAccount(decryptedChallenge, reason, feedback); logout(); } catch (e) { - log.error("solveChallengeAndDeleteAccount failed", e); - somethingWentWrong(); + onGenericError(e); } finally { setLoading(false); } diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx index f558b2e480..9c39ae3f87 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx @@ -1,4 +1,5 @@ import { EnteDrawer } from "@/base/components/EnteDrawer"; +import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { Titlebar } from "@/base/components/Titlebar"; import { EllipsizedTypography } from "@/base/components/Typography"; @@ -53,12 +54,9 @@ import LinkButton from "components/pages/gallery/LinkButton"; import { t } from "i18next"; import { GalleryContext } from "pages/gallery"; import React, { useContext, useEffect, useMemo, useState } from "react"; +import { Trans } from "react-i18next"; import { changeFileName, updateExistingFilePubMetadata } from "utils/file"; import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery"; -import { - getMapDisableConfirmationDialog, - getMapEnableConfirmationDialog, -} from "utils/ui"; import { FileNameEditDialog } from "./FileNameEditDialog"; import InfoItem from "./InfoItem"; import MapBox from "./MapBox"; @@ -101,7 +99,7 @@ export const FileInfo: React.FC = ({ closePhotoViewer, onSelectPerson, }) => { - const { mapEnabled, updateMapEnabled, setDialogBoxAttributesV2 } = + const { mapEnabled, updateMapEnabled, showMiniDialog } = useContext(AppContext); const galleryContext = useContext(GalleryContext); const publicCollectionGalleryContext = useContext( @@ -151,13 +149,13 @@ export const FileInfo: React.FC = ({ }; const openEnableMapConfirmationDialog = () => - setDialogBoxAttributesV2( - getMapEnableConfirmationDialog(() => updateMapEnabled(true)), + showMiniDialog( + confirmEnableMapsDialogAttributes(() => updateMapEnabled(true)), ); const openDisableMapConfirmationDialog = () => - setDialogBoxAttributesV2( - getMapDisableConfirmationDialog(() => updateMapEnabled(false)), + showMiniDialog( + confirmDisableMapsDialogAttributes(() => updateMapEnabled(false)), ); const handleSelectFace = (annotatedFaceID: AnnotatedFaceID) => { @@ -379,6 +377,35 @@ const parseExifInfo = ( return info; }; +const confirmEnableMapsDialogAttributes = ( + onConfirm: () => void, +): MiniDialogAttributes => ({ + title: t("ENABLE_MAPS"), + message: ( + + ), + }} + /> + ), + continue: { text: t("enable"), action: onConfirm }, +}); + +const confirmDisableMapsDialogAttributes = ( + onConfirm: () => void, +): MiniDialogAttributes => ({ + title: t("DISABLE_MAPS"), + message: , + continue: { text: t("disable"), action: onConfirm }, +}); + const FileInfoSidebar = styled((props: DialogProps) => ( ))({ diff --git a/web/apps/photos/src/utils/ui/index.tsx b/web/apps/photos/src/utils/ui/index.tsx index ecd25edb64..4d259f2310 100644 --- a/web/apps/photos/src/utils/ui/index.tsx +++ b/web/apps/photos/src/utils/ui/index.tsx @@ -1,3 +1,4 @@ +import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { ensureElectron } from "@/base/electron"; import { AppUpdate } from "@/base/types/ipc"; import { openURL } from "@/new/photos/utils/web"; @@ -136,45 +137,6 @@ export const getSessionExpiredMessage = ( }, }); -export const getMapEnableConfirmationDialog = ( - enableMapHelper, -): DialogBoxAttributes => ({ - title: t("ENABLE_MAPS"), - content: ( - - ), - }} - /> - ), - proceed: { - action: enableMapHelper, - text: t("enable"), - variant: "accent", - }, - close: { text: t("cancel") }, -}); - -export const getMapDisableConfirmationDialog = ( - disableMapHelper, -): DialogBoxAttributes => ({ - title: t("DISABLE_MAPS"), - content: , - proceed: { - action: disableMapHelper, - text: t("disable"), - variant: "accent", - }, - close: { text: t("cancel") }, -}); - export const getEditorCloseConfirmationMessage = ( doClose: () => void, ): DialogBoxAttributes => ({ diff --git a/web/packages/accounts/components/LoginComponents.tsx b/web/packages/accounts/components/LoginComponents.tsx index b7bdb675c3..cece699417 100644 --- a/web/packages/accounts/components/LoginComponents.tsx +++ b/web/packages/accounts/components/LoginComponents.tsx @@ -75,7 +75,7 @@ interface VerifyingPasskeyProps { onRetry: () => void; /** Perform the (possibly app specific) logout sequence. */ logout: () => void; - setDialogBoxAttributesV2: (attrs: MiniDialogAttributes) => void; + showMiniDialog: (attrs: MiniDialogAttributes) => void; } export const VerifyingPasskey: React.FC = ({ @@ -83,7 +83,7 @@ export const VerifyingPasskey: React.FC = ({ email, onRetry, logout, - setDialogBoxAttributesV2, + showMiniDialog, }) => { type VerificationStatus = "waiting" | "checking" | "pending"; const [verificationStatus, setVerificationStatus] = @@ -105,7 +105,7 @@ export const VerifyingPasskey: React.FC = ({ else router.push(await saveCredentialsAndNavigateTo(response)); } catch (e) { log.error("Passkey verification status check failed", e); - setDialogBoxAttributesV2( + showMiniDialog( e instanceof Error && e.message == passkeySessionExpiredErrorMessage ? sessionExpiredDialogAttributes(logout) diff --git a/web/packages/accounts/pages/credentials.tsx b/web/packages/accounts/pages/credentials.tsx index ca8245258f..5287a7fbcf 100644 --- a/web/packages/accounts/pages/credentials.tsx +++ b/web/packages/accounts/pages/credentials.tsx @@ -66,7 +66,7 @@ import type { PageProps } from "../types/page"; import type { SRPAttributes } from "../types/srp"; const Page: React.FC = ({ appContext }) => { - const { logout, showNavBar, setDialogBoxAttributesV2 } = appContext; + const { logout, showNavBar, showMiniDialog } = appContext; const [srpAttributes, setSrpAttributes] = useState(); const [keyAttributes, setKeyAttributes] = useState(); @@ -82,7 +82,7 @@ const Page: React.FC = ({ appContext }) => { const validateSession = useCallback(async () => { const showSessionExpiredDialog = () => - setDialogBoxAttributesV2(sessionExpiredDialogAttributes(logout)); + showMiniDialog(sessionExpiredDialogAttributes(logout)); try { const session = await checkSessionValidity(); @@ -114,7 +114,7 @@ const Page: React.FC = ({ appContext }) => { // potentially transient issues. log.warn("Ignoring error when determining session validity", e); } - }, [setDialogBoxAttributesV2, logout]); + }, [showMiniDialog, logout]); useEffect(() => { const main = async () => { @@ -354,7 +354,7 @@ const Page: React.FC = ({ appContext }) => { onRetry={() => openPasskeyVerificationURL(passkeyVerificationData) } - {...{ logout, setDialogBoxAttributesV2 }} + {...{ logout, showMiniDialog }} /> ); } diff --git a/web/packages/accounts/pages/verify.tsx b/web/packages/accounts/pages/verify.tsx index c3b334cdd7..f11e77f2f8 100644 --- a/web/packages/accounts/pages/verify.tsx +++ b/web/packages/accounts/pages/verify.tsx @@ -46,7 +46,7 @@ import type { PageProps } from "../types/page"; import type { SRPAttributes, SRPSetupAttributes } from "../types/srp"; const Page: React.FC = ({ appContext }) => { - const { logout, showNavBar, setDialogBoxAttributesV2 } = appContext; + const { logout, showNavBar, showMiniDialog } = appContext; const [email, setEmail] = useState(""); const [resend, setResend] = useState(0); @@ -202,7 +202,7 @@ const Page: React.FC = ({ appContext }) => { onRetry={() => openPasskeyVerificationURL(passkeyVerificationData) } - {...{ logout, setDialogBoxAttributesV2 }} + {...{ logout, showMiniDialog }} /> ); } From f9209e212d0cba3d60f08eee51ead68eaaf66418 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 15:44:55 +0530 Subject: [PATCH 32/43] wip checkpoint --- .../PhotoViewer/ImageEditorOverlay/index.tsx | 20 ++++++--- web/apps/photos/src/pages/_app.tsx | 43 +++++-------------- web/apps/photos/src/utils/ui/index.tsx | 15 ------- web/packages/accounts/pages/recover.tsx | 7 +-- .../accounts/pages/two-factor/recover.tsx | 11 +++-- web/packages/base/components/MiniDialog.tsx | 5 +++ 6 files changed, 42 insertions(+), 59 deletions(-) diff --git a/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx b/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx index 02cd636e09..5cdfe0b8a7 100644 --- a/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/ImageEditorOverlay/index.tsx @@ -4,6 +4,7 @@ import { MenuItemGroup, MenuSectionTitle, } from "@/base/components/Menu"; +import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { nameAndExtension } from "@/base/file"; import log from "@/base/log"; import { photosDialogZIndex } from "@/new/photos/components/z-index"; @@ -39,7 +40,6 @@ import type { Dispatch, MutableRefObject, SetStateAction } from "react"; import { createContext, useContext, useEffect, useRef, useState } from "react"; import { getLocalCollections } from "services/collectionService"; import uploadManager from "services/upload/uploadManager"; -import { getEditorCloseConfirmationMessage } from "utils/ui"; import ColoursMenu from "./ColoursMenu"; import CropMenu, { cropRegionOfCanvas, getCropRegionArgs } from "./CropMenu"; import FreehandCropRegion from "./FreehandCropRegion"; @@ -84,7 +84,7 @@ export interface CropBoxProps { } const ImageEditorOverlay = (props: IProps) => { - const appContext = useContext(AppContext); + const { showMiniDialog } = useContext(AppContext); const canvasRef = useRef(null); const originalSizeCanvasRef = useRef(null); @@ -442,9 +442,7 @@ const ImageEditorOverlay = (props: IProps) => { const handleCloseWithConfirmation = () => { if (transformationPerformed || coloursAdjusted) { - appContext.setDialogBoxAttributesV2( - getEditorCloseConfirmationMessage(handleClose), - ); + showMiniDialog(confirmEditorCloseDialogAttributes(handleClose)); } else { handleClose(); } @@ -733,6 +731,18 @@ const ImageEditorOverlay = (props: IProps) => { export default ImageEditorOverlay; +const confirmEditorCloseDialogAttributes = ( + onConfirm: () => void, +): MiniDialogAttributes => ({ + title: t("CONFIRM_EDITOR_CLOSE_MESSAGE"), + message: t("CONFIRM_EDITOR_CLOSE_DESCRIPTION"), + continue: { + text: t("close"), + color: "critical", + action: onConfirm, + }, +}); + /** * Create a new {@link File} with the contents of the given canvas. * diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 9ecc2eb6b5..3fec77edc3 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -1,9 +1,12 @@ import { clientPackageName, staticAppTitle } from "@/base/app"; import { CustomHead } from "@/base/components/Head"; -import type { MiniDialogAttributes } from "@/base/components/MiniDialog"; import { AttributedMiniDialog } from "@/base/components/MiniDialog"; import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator"; import { AppNavbar } from "@/base/components/Navbar"; +import { + genericErrorDialogAttributes, + useAttributedMiniDialog, +} from "@/base/components/utils/mini-dialog"; import { setupI18n } from "@/base/i18n"; import log from "@/base/log"; import { @@ -36,7 +39,6 @@ import { getTheme } from "@ente/shared/themes"; import { THEME_COLOR } from "@ente/shared/themes/constants"; import type { User } from "@ente/shared/user/types"; import ArrowForward from "@mui/icons-material/ArrowForward"; -import ErrorOutline from "@mui/icons-material/ErrorOutline"; import { CssBaseline } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import Notification from "components/Notification"; @@ -72,17 +74,15 @@ export default function App({ Component, pageProps }: AppProps) { const isLoadingBarRunning = useRef(false); const loadingBar = useRef(null); const [dialogMessage, setDialogMessage] = useState(); - const [dialogBoxAttributeV2, setDialogBoxAttributesV2] = useState< - MiniDialogAttributes | undefined - >(); const [messageDialogView, setMessageDialogView] = useState(false); - const [dialogBoxV2View, setDialogBoxV2View] = useState(false); const [watchFolderView, setWatchFolderView] = useState(false); const [watchFolderFiles, setWatchFolderFiles] = useState(null); const [notificationView, setNotificationView] = useState(false); const closeNotification = () => setNotificationView(false); const [notificationAttributes, setNotificationAttributes] = useState(null); + + const { showMiniDialog, miniDialogProps } = useAttributedMiniDialog(); const [themeColor, setThemeColor] = useLocalState( LS_KEYS.THEME, THEME_COLOR.DARK, @@ -201,10 +201,6 @@ export default function App({ Component, pageProps }: AppProps) { setMessageDialogView(true); }, [dialogMessage]); - useEffect(() => { - setDialogBoxV2View(true); - }, [dialogBoxAttributeV2]); - useEffect(() => { setNotificationView(true); }, [notificationAttributes]); @@ -236,12 +232,6 @@ export default function App({ Component, pageProps }: AppProps) { () => setMessageDialogView(false), [], ); - const closeDialogBoxV2 = () => setDialogBoxV2View(false); - - const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { - setDialogBoxAttributesV2(attributes); - setDialogBoxV2View(true); - }, []); // Use `onGenericError` instead. const somethingWentWrong = useCallback( @@ -254,18 +244,10 @@ export default function App({ Component, pageProps }: AppProps) { [], ); - const onGenericError = useCallback( - (e: unknown) => ( - log.error("Error", e), - setDialogBoxAttributesV2({ - title: t("error"), - icon: , - message: t("generic_error"), - close: { variant: "critical" }, - }) - ), - [], - ); + const onGenericError = useCallback((e: unknown) => { + log.error("Error", e); + showMiniDialog(genericErrorDialogAttributes()); + }, []); const logout = useCallback(() => { void photosLogout().then(() => router.push("/")); @@ -287,7 +269,6 @@ export default function App({ Component, pageProps }: AppProps) { showMiniDialog, somethingWentWrong, onGenericError, - setDialogBoxAttributesV2, mapEnabled, updateMapEnabled, // <- changes on each render isCFProxyDisabled, @@ -318,9 +299,7 @@ export default function App({ Component, pageProps }: AppProps) { /> void, -): DialogBoxAttributes => ({ - title: t("CONFIRM_EDITOR_CLOSE_MESSAGE"), - content: t("CONFIRM_EDITOR_CLOSE_DESCRIPTION"), - proceed: { - action: doClose, - text: t("close"), - variant: "critical", - }, - close: { text: t("cancel") }, -}); diff --git a/web/packages/accounts/pages/recover.tsx b/web/packages/accounts/pages/recover.tsx index c6e86cdafc..c4ad1ba20f 100644 --- a/web/packages/accounts/pages/recover.tsx +++ b/web/packages/accounts/pages/recover.tsx @@ -29,7 +29,7 @@ const bip39 = require("bip39"); bip39.setDefaultWordlist("english"); const Page: React.FC = ({ appContext }) => { - const { showNavBar, setDialogBoxAttributesV2 } = appContext; + const { showNavBar, showMiniDialog } = appContext; const [keyAttributes, setKeyAttributes] = useState< KeyAttributes | undefined @@ -98,10 +98,11 @@ const Page: React.FC = ({ appContext }) => { }; const showNoRecoveryKeyMessage = () => - setDialogBoxAttributesV2({ + showMiniDialog({ title: t("sorry"), - close: {}, message: t("NO_RECOVERY_KEY_MESSAGE"), + continue: { color: "secondary" }, + cancel: false, }); return ( diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx index be2d2227fd..0aa1406b6f 100644 --- a/web/packages/accounts/pages/two-factor/recover.tsx +++ b/web/packages/accounts/pages/two-factor/recover.tsx @@ -42,7 +42,7 @@ export interface RecoverPageProps { } const Page: React.FC = ({ appContext, twoFactorType }) => { - const { logout } = appContext; + const { showMiniDialog, logout } = appContext; const [encryptedTwoFactorSecret, setEncryptedTwoFactorSecret] = useState | null>(null); @@ -72,6 +72,7 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { if (!resp.encryptedSecret) { showContactSupportDialog({ text: t("GO_BACK"), + autoClose: true, action: router.back, }); } else { @@ -91,6 +92,7 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { setDoesHaveEncryptedRecoveryKey(false); showContactSupportDialog({ text: t("GO_BACK"), + autoClose: true, action: router.back, }); } @@ -146,11 +148,10 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { }; const showContactSupportDialog = ( - dialogClose?: MiniDialogAttributes["close"], + dialogContinue?: MiniDialogAttributes["continue"], ) => { - appContext.setDialogBoxAttributesV2({ + showMiniDialog({ title: t("contact_support"), - close: dialogClose ?? {}, message: ( = ({ appContext, twoFactorType }) => { values={{ emailID: "support@ente.io" }} /> ), + continue: { color: "secondary", ...(dialogContinue ?? {}) }, + cancel: false, }); }; diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index dcf0a53239..037d887845 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -75,6 +75,11 @@ export interface MiniDialogAttributes { * is opened, allowing the user to confirm just by pressing ENTER. */ autoFocus?: boolean; + /** + * If `true`, close the dialog after {@link action} completes. + * TODO: Test/Impl/Is this needed? + */ + autoClose?: boolean; /** * The function to call when the user activates the button. * From 288d66dfa74fcd9c64d56128f9292ce815cbfe4a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 15:59:27 +0530 Subject: [PATCH 33/43] Finish re --- web/packages/base/components/MiniDialog.tsx | 12 +++----- .../new/photos/components/MLSettings.tsx | 29 ++++++------------- .../components/gallery/PeopleHeader.tsx | 9 +++--- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 037d887845..820be8e061 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -1,7 +1,3 @@ -// TODO: -/* eslint-disable @typescript-eslint/prefer-optional-chain */ -/* eslint-disable @typescript-eslint/no-unnecessary-condition */ -/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton"; import { LoadingButton } from "@/base/components/mui/LoadingButton"; import type { ButtonProps } from "@mui/material"; @@ -147,7 +143,7 @@ export const AttributedMiniDialog: React.FC< }} {...rest} > - {(attributes.icon || attributes.title) && ( + {(attributes.icon ?? attributes.title) && ( { await attributes.continue?.action?.(setLoading); onClose(); }} > - {attributes.continue?.text ?? t("ok")} + {attributes.continue.text ?? t("ok")} )} {attributes.cancel && ( diff --git a/web/packages/new/photos/components/MLSettings.tsx b/web/packages/new/photos/components/MLSettings.tsx index 3b1db3002b..15480eddf4 100644 --- a/web/packages/new/photos/components/MLSettings.tsx +++ b/web/packages/new/photos/components/MLSettings.tsx @@ -27,7 +27,7 @@ import { import { t } from "i18next"; import React, { useEffect, useState, useSyncExternalStore } from "react"; import { Trans } from "react-i18next"; -import { useAppContext, type AppContextT } from "../types/context"; +import { useAppContext } from "../types/context"; import { openURL } from "../utils/web"; import { useWrapAsyncOperation } from "./use-wrap-async"; @@ -36,8 +36,6 @@ export const MLSettings: React.FC = ({ onClose, onRootClose, }) => { - const { setDialogBoxAttributesV2 } = useAppContext(); - const mlStatus = useSyncExternalStore(mlStatusSubscribe, mlStatusSnapshot); const [openFaceConsent, setOpenFaceConsent] = useState(false); @@ -68,10 +66,7 @@ export const MLSettings: React.FC = ({ component = ; } else { component = ( - + ); } @@ -252,15 +247,11 @@ interface ManageMLProps { mlStatus: Exclude; /** Called when the user wants to disable ML. */ onDisableML: () => void; - /** Subset of appContext. */ - setDialogBoxAttributesV2: AppContextT["setDialogBoxAttributesV2"]; } -const ManageML: React.FC = ({ - mlStatus, - onDisableML, - setDialogBoxAttributesV2, -}) => { +const ManageML: React.FC = ({ mlStatus, onDisableML }) => { + const { showMiniDialog } = useAppContext(); + const { phase, nSyncedFiles, nTotalFiles } = mlStatus; let status: string; @@ -289,19 +280,17 @@ const ManageML: React.FC = ({ ? `${Math.round((100 * nSyncedFiles) / nTotalFiles)}%` : `${nSyncedFiles} / ${nTotalFiles}`; - const confirmDisableML = () => { - setDialogBoxAttributesV2({ + const confirmDisableML = () => + showMiniDialog({ title: t("ml_search_disable"), message: t("ml_search_disable_confirm"), - close: { text: t("cancel") }, - proceed: { - variant: "critical", + continue: { text: t("disable"), + color: "critical", action: onDisableML, }, buttonDirection: "row", }); - }; return ( diff --git a/web/packages/new/photos/components/gallery/PeopleHeader.tsx b/web/packages/new/photos/components/gallery/PeopleHeader.tsx index aa0b05922e..2b59b96967 100644 --- a/web/packages/new/photos/components/gallery/PeopleHeader.tsx +++ b/web/packages/new/photos/components/gallery/PeopleHeader.tsx @@ -92,7 +92,7 @@ const CGroupPersonOptions: React.FC = ({ cgroup, onSelectPerson, }) => { - const { setDialogBoxAttributesV2 } = useAppContext(); + const { showMiniDialog } = useAppContext(); const [openAddNameInput, setOpenAddNameInput] = useState(false); @@ -103,17 +103,16 @@ const CGroupPersonOptions: React.FC = ({ ); const handleDeletePerson = () => - setDialogBoxAttributesV2({ + showMiniDialog({ title: pt("Reset person?"), message: pt( "The name, face groupings and suggestions for this person will be reset", ), - close: { text: t("cancel") }, - proceed: { + continue: { text: t("reset"), + color: "primary", action: deletePerson, }, - buttonDirection: "row", }); const deletePerson = useWrapAsyncOperation(async () => { From dde2b8894aba7dbb0daa9f2dc41b49735f31c68a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 16:04:59 +0530 Subject: [PATCH 34/43] Test 1 --- web/packages/base/components/MiniDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 820be8e061..0efada4f47 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -192,7 +192,7 @@ export const AttributedMiniDialog: React.FC< {attributes.continue.text ?? t("ok")} )} - {attributes.cancel && ( + {attributes.cancel !== false && ( Date: Thu, 10 Oct 2024 16:27:00 +0530 Subject: [PATCH 35/43] Tune semantics --- web/packages/base/components/MiniDialog.tsx | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 0efada4f47..91d8e78736 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -71,22 +71,17 @@ export interface MiniDialogAttributes { * is opened, allowing the user to confirm just by pressing ENTER. */ autoFocus?: boolean; - /** - * If `true`, close the dialog after {@link action} completes. - * TODO: Test/Impl/Is this needed? - */ - autoClose?: boolean; /** * The function to call when the user activates the button. * - * Default is to close the dialog. + * If this function returns a promise, then an activity indicator will + * be shown on the button until the promise settles. * - * It is passed a {@link setLoading} function that can be used to show - * or hide loading indicator or the primary action button. + * If this function is not provided, or if the function completes / + * fullfills, then then the dialog is automatically closed. Otherwise + * (that is, if the provided function throws), the dialog remains open. */ - action?: - | (() => void | Promise) - | ((setLoading: (value: boolean) => void) => void | Promise); + action?: () => void | Promise; }; /** * The string to use as the label for the cancel button. @@ -185,8 +180,14 @@ export const AttributedMiniDialog: React.FC< color={attributes.continue.color ?? "accent"} autoFocus={attributes.continue.autoFocus} onClick={async () => { - await attributes.continue?.action?.(setLoading); - onClose(); + setLoading(true); + try { + await attributes.continue?.action?.(); + setLoading(false); + onClose(); + } catch { + setLoading(false); + } }} > {attributes.continue.text ?? t("ok")} From ed17206f51dbcf4079317e7d243c36b21edb9d3c Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 16:37:08 +0530 Subject: [PATCH 36/43] Fix warnings --- web/packages/base/components/MiniDialog.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 91d8e78736..6179773b82 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -127,7 +127,6 @@ export const AttributedMiniDialog: React.FC< return ( {(attributes.icon ?? attributes.title) && ( From e822d327e46a03048e21b661e1b456c663931177 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 16:41:05 +0530 Subject: [PATCH 37/43] All cases --- web/packages/base/components/MiniDialog.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 6179773b82..510ab6082f 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -80,6 +80,16 @@ export interface MiniDialogAttributes { * If this function is not provided, or if the function completes / * fullfills, then then the dialog is automatically closed. Otherwise * (that is, if the provided function throws), the dialog remains open. + * + * That's quite a mouthful, here's a flowchart: + * + * - Not provided: Close + * - Provided sync: + * - Success: Close + * - Failure: Remain open + * - Provided async: + * - Success: Close + * - Failure: Remain open */ action?: () => void | Promise; }; From 24dc72eee31da2cdff7ad08be0aae9e421973374 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 16:13:34 +0530 Subject: [PATCH 38/43] Loose ends --- web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx | 2 +- web/apps/photos/src/pages/_app.tsx | 1 + web/packages/base/components/utils/mini-dialog.tsx | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx index 9c39ae3f87..9f3c87ca7b 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx @@ -403,7 +403,7 @@ const confirmDisableMapsDialogAttributes = ( ): MiniDialogAttributes => ({ title: t("DISABLE_MAPS"), message: , - continue: { text: t("disable"), action: onConfirm }, + continue: { text: t("disable"), color: "critical", action: onConfirm }, }); const FileInfoSidebar = styled((props: DialogProps) => ( diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 3fec77edc3..17ff25cc40 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -213,6 +213,7 @@ export default function App({ Component, pageProps }: AppProps) { setLocalMapEnabled(enabled); setMapEnabled(enabled); } catch (e) { + // TODO: Handle the error here. log.error("Error while updating mapEnabled", e); } }; diff --git a/web/packages/base/components/utils/mini-dialog.tsx b/web/packages/base/components/utils/mini-dialog.tsx index 088e8511f2..5118e52a62 100644 --- a/web/packages/base/components/utils/mini-dialog.tsx +++ b/web/packages/base/components/utils/mini-dialog.tsx @@ -55,6 +55,7 @@ export const errorDialogAttributes = ( icon: , message, continue: { color: "critical" }, + cancel: false, }; }; From 5e639e972978fe6ac60d766aed29a2be5a419ed8 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 17:03:29 +0530 Subject: [PATCH 39/43] Provision an error handler --- web/packages/base/components/MiniDialog.tsx | 41 ++++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index 510ab6082f..ce88463ab9 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -12,6 +12,7 @@ import { } from "@mui/material"; import { t } from "i18next"; import React, { useState } from "react"; +import log from "../log"; /** * Customize the contents of an {@link AttributedMiniDialog}. @@ -70,7 +71,7 @@ export interface MiniDialogAttributes { * If `true`, the primary action button is auto focused when the dialog * is opened, allowing the user to confirm just by pressing ENTER. */ - autoFocus?: boolean; + autoFocus?: ButtonProps["autoFocus"]; /** * The function to call when the user activates the button. * @@ -78,18 +79,20 @@ export interface MiniDialogAttributes { * be shown on the button until the promise settles. * * If this function is not provided, or if the function completes / - * fullfills, then then the dialog is automatically closed. Otherwise - * (that is, if the provided function throws), the dialog remains open. + * fullfills, then then the dialog is automatically closed. + * + * Otherwise (that is, if the provided function throws), the dialog + * remains open, showing a generic error. * * That's quite a mouthful, here's a flowchart: * * - Not provided: Close * - Provided sync: * - Success: Close - * - Failure: Remain open + * - Failure: Remain open, showing generic error * - Provided async: * - Success: Close - * - Failure: Remain open + * - Failure: Remain open, showing generic error */ action?: () => void | Promise; }; @@ -121,15 +124,20 @@ type MiniDialogProps = Omit & { export const AttributedMiniDialog: React.FC< React.PropsWithChildren > = ({ open, onClose, attributes, children, ...props }) => { - const [loading, setLoading] = useState(false); + const [phase, setPhase] = useState<"loading" | "failed" | undefined>(); if (!attributes) { return <>; } + const resetPhaseAndClose = () => { + setPhase(undefined); + onClose(); + }; + const handleClose = () => { if (attributes.nonClosable) return; - onClose(); + resetPhaseAndClose(); }; const { PaperProps, ...rest } = props; @@ -188,20 +196,25 @@ export const AttributedMiniDialog: React.FC< : "column" } > + {phase == "failed" && ( + + {t("generic_error")} + + )} {attributes.continue && ( { - setLoading(true); + setPhase("loading"); try { await attributes.continue?.action?.(); - setLoading(false); - onClose(); - } catch { - setLoading(false); + resetPhaseAndClose(); + } catch (e) { + log.error("Error", e); + setPhase("failed"); } }} > @@ -212,7 +225,7 @@ export const AttributedMiniDialog: React.FC< {attributes.cancel ?? t("cancel")} From 4d3b89048c0fead6f9cee25cfd46cd2d0ea8df59 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 17:06:22 +0530 Subject: [PATCH 40/43] Fix error about nesting p in div --- web/packages/base/components/MiniDialog.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index ce88463ab9..ff124a035e 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -183,7 +183,12 @@ export const AttributedMiniDialog: React.FC< )} {attributes.message && ( - + {attributes.message} )} From de74acedab9f10e0a3dd60888a878e6687fff23a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 17:11:25 +0530 Subject: [PATCH 41/43] Use inbuilt error handler --- .../accounts/src/pages/passkeys/index.tsx | 40 ++++++++----------- web/apps/photos/src/pages/_app.tsx | 11 ++--- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/web/apps/accounts/src/pages/passkeys/index.tsx b/web/apps/accounts/src/pages/passkeys/index.tsx index fb9f591ad5..88bf77b80b 100644 --- a/web/apps/accounts/src/pages/passkeys/index.tsx +++ b/web/apps/accounts/src/pages/passkeys/index.tsx @@ -264,30 +264,22 @@ const ManagePasskeyDrawer: React.FC = ({ const [showRenameDialog, setShowRenameDialog] = useState(false); - const showDeleteConfirmationDialog = useCallback(() => { - /* mark: uses-loading */ - const handleDelete = async (setLoading: (value: boolean) => void) => { - setLoading(true); - try { - await deletePasskey(ensure(token), ensure(passkey).id); - onUpdateOrDeletePasskey(); - } catch (e) { - log.error("Failed to delete passkey", e); - } finally { - setLoading(false); - } - }; - - showMiniDialog({ - title: t("delete_passkey"), - message: t("delete_passkey_confirmation"), - continue: { - text: t("delete"), - color: "critical", - action: handleDelete, - }, - }); - }, [showMiniDialog, token, passkey, onUpdateOrDeletePasskey]); + const showDeleteConfirmationDialog = useCallback( + () => + showMiniDialog({ + title: t("delete_passkey"), + message: t("delete_passkey_confirmation"), + continue: { + text: t("delete"), + color: "critical", + action: async () => { + await deletePasskey(ensure(token), ensure(passkey).id); + onUpdateOrDeletePasskey(); + }, + }, + }), + [showMiniDialog, token, passkey, onUpdateOrDeletePasskey], + ); return ( <> diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 17ff25cc40..0c7b0f61c0 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -208,14 +208,9 @@ export default function App({ Component, pageProps }: AppProps) { const showNavBar = (show: boolean) => setShowNavBar(show); const updateMapEnabled = async (enabled: boolean) => { - try { - await updateMapEnabledStatus(enabled); - setLocalMapEnabled(enabled); - setMapEnabled(enabled); - } catch (e) { - // TODO: Handle the error here. - log.error("Error while updating mapEnabled", e); - } + await updateMapEnabledStatus(enabled); + setLocalMapEnabled(enabled); + setMapEnabled(enabled); }; const startLoading = () => { From 78962b261179877d9677858e096d3551c04376d9 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 17:16:56 +0530 Subject: [PATCH 42/43] Touchups --- .../src/components/AuthenticateUserModal.tsx | 1 + .../src/components/DeleteAccountModal.tsx | 24 ++++++------------- .../accounts/pages/two-factor/recover.tsx | 2 -- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/web/apps/photos/src/components/AuthenticateUserModal.tsx b/web/apps/photos/src/components/AuthenticateUserModal.tsx index 6f17a61bc7..1fe92900e9 100644 --- a/web/apps/photos/src/components/AuthenticateUserModal.tsx +++ b/web/apps/photos/src/components/AuthenticateUserModal.tsx @@ -130,4 +130,5 @@ const passwordChangedElsewhereDialogAttributes = ( text: t("login"), action: onLogin, }, + cancel: false, }); diff --git a/web/apps/photos/src/components/DeleteAccountModal.tsx b/web/apps/photos/src/components/DeleteAccountModal.tsx index 82cd039c44..795d96bfb3 100644 --- a/web/apps/photos/src/components/DeleteAccountModal.tsx +++ b/web/apps/photos/src/components/DeleteAccountModal.tsx @@ -106,23 +106,13 @@ const DeleteAccountModal = ({ open, onClose }: Iprops) => { }); }; - /* mark: uses-loading */ - const solveChallengeAndDeleteAccount = async ( - setLoading: (value: boolean) => void, - ) => { - try { - setLoading(true); - const decryptedChallenge = await decryptDeleteAccountChallenge( - deleteAccountChallenge.current, - ); - const { reason, feedback } = reasonAndFeedbackRef.current; - await deleteAccount(decryptedChallenge, reason, feedback); - logout(); - } catch (e) { - onGenericError(e); - } finally { - setLoading(false); - } + const solveChallengeAndDeleteAccount = async () => { + const decryptedChallenge = await decryptDeleteAccountChallenge( + deleteAccountChallenge.current, + ); + const { reason, feedback } = reasonAndFeedbackRef.current; + await deleteAccount(decryptedChallenge, reason, feedback); + logout(); }; return ( diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx index 0aa1406b6f..8fdfd4dbb8 100644 --- a/web/packages/accounts/pages/two-factor/recover.tsx +++ b/web/packages/accounts/pages/two-factor/recover.tsx @@ -72,7 +72,6 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { if (!resp.encryptedSecret) { showContactSupportDialog({ text: t("GO_BACK"), - autoClose: true, action: router.back, }); } else { @@ -92,7 +91,6 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { setDoesHaveEncryptedRecoveryKey(false); showContactSupportDialog({ text: t("GO_BACK"), - autoClose: true, action: router.back, }); } From 710b7e93dc5ed4e10d1ffdab1cd95a88d2d177d2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 10 Oct 2024 17:25:58 +0530 Subject: [PATCH 43/43] Ok is a better title, the go back is a bit confusing --- web/packages/accounts/pages/two-factor/recover.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/web/packages/accounts/pages/two-factor/recover.tsx b/web/packages/accounts/pages/two-factor/recover.tsx index 8fdfd4dbb8..d090160d11 100644 --- a/web/packages/accounts/pages/two-factor/recover.tsx +++ b/web/packages/accounts/pages/two-factor/recover.tsx @@ -70,10 +70,7 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { const resp = await recoverTwoFactor(sid, twoFactorType); setDoesHaveEncryptedRecoveryKey(!!resp.encryptedSecret); if (!resp.encryptedSecret) { - showContactSupportDialog({ - text: t("GO_BACK"), - action: router.back, - }); + showContactSupportDialog({ action: router.back }); } else { setEncryptedTwoFactorSecret({ encryptedData: resp.encryptedSecret, @@ -89,10 +86,7 @@ const Page: React.FC = ({ appContext, twoFactorType }) => { } else { log.error("two factor recovery page setup failed", e); setDoesHaveEncryptedRecoveryKey(false); - showContactSupportDialog({ - text: t("GO_BACK"), - action: router.back, - }); + showContactSupportDialog({ action: router.back }); } } };