diff --git a/web/apps/photos/src/components/Sidebar/UtilitySection.tsx b/web/apps/photos/src/components/Sidebar/UtilitySection.tsx
deleted file mode 100644
index 32f61d976..000000000
--- a/web/apps/photos/src/components/Sidebar/UtilitySection.tsx
+++ /dev/null
@@ -1,222 +0,0 @@
-import log from "@/next/log";
-import RecoveryKey from "@ente/shared/components/RecoveryKey";
-import {
- ACCOUNTS_PAGES,
- PHOTOS_PAGES as PAGES,
-} from "@ente/shared/constants/pages";
-import TwoFactorModal from "components/TwoFactor/Modal";
-import { t } from "i18next";
-import { useRouter } from "next/router";
-import { AppContext } from "pages/_app";
-import { useContext, useState } from "react";
-// import mlIDbStorage from 'services/ml/db';
-import {
- configurePasskeyRecovery,
- isPasskeyRecoveryEnabled,
-} from "@ente/accounts/services/passkey";
-import { APPS, CLIENT_PACKAGE_NAMES } from "@ente/shared/apps/constants";
-import ThemeSwitcher from "@ente/shared/components/ThemeSwitcher";
-import { getRecoveryKey } from "@ente/shared/crypto/helpers";
-import {
- encryptToB64,
- generateEncryptionKey,
-} from "@ente/shared/crypto/internal/libsodium";
-import { getAccountsURL } from "@ente/shared/network/api";
-import { THEME_COLOR } from "@ente/shared/themes/constants";
-import { EnteMenuItem } from "components/Menu/EnteMenuItem";
-import { WatchFolder } from "components/WatchFolder";
-import isElectron from "is-electron";
-import { getAccountsToken } from "services/userService";
-import { getDownloadAppMessage } from "utils/ui";
-import { isInternalUser } from "utils/user";
-import Preferences from "./Preferences";
-
-export default function UtilitySection({ closeSidebar }) {
- const router = useRouter();
- const appContext = useContext(AppContext);
- const {
- setDialogMessage,
- startLoading,
- watchFolderView,
- setWatchFolderView,
- themeColor,
- setThemeColor,
- } = appContext;
-
- const [recoverModalView, setRecoveryModalView] = useState(false);
- const [twoFactorModalView, setTwoFactorModalView] = useState(false);
- const [preferencesView, setPreferencesView] = useState(false);
-
- const openPreferencesOptions = () => setPreferencesView(true);
- const closePreferencesOptions = () => setPreferencesView(false);
-
- const openRecoveryKeyModal = () => setRecoveryModalView(true);
- const closeRecoveryKeyModal = () => setRecoveryModalView(false);
-
- const openTwoFactorModal = () => setTwoFactorModalView(true);
- const closeTwoFactorModal = () => setTwoFactorModalView(false);
-
- const openWatchFolder = () => {
- if (isElectron()) {
- setWatchFolderView(true);
- } else {
- setDialogMessage(getDownloadAppMessage());
- }
- };
- const closeWatchFolder = () => setWatchFolderView(false);
-
- const redirectToChangePasswordPage = () => {
- closeSidebar();
- router.push(PAGES.CHANGE_PASSWORD);
- };
-
- const redirectToChangeEmailPage = () => {
- closeSidebar();
- router.push(PAGES.CHANGE_EMAIL);
- };
-
- const redirectToAccountsPage = async () => {
- closeSidebar();
-
- try {
- // check if the user has passkey recovery enabled
- const recoveryEnabled = await isPasskeyRecoveryEnabled();
- if (!recoveryEnabled) {
- // let's create the necessary recovery information
- const recoveryKey = await getRecoveryKey();
-
- const resetSecret = await generateEncryptionKey();
-
- const encryptionResult = await encryptToB64(
- resetSecret,
- recoveryKey,
- );
-
- await configurePasskeyRecovery(
- resetSecret,
- encryptionResult.encryptedData,
- encryptionResult.nonce,
- );
- }
-
- const accountsToken = await getAccountsToken();
-
- window.open(
- `${getAccountsURL()}${
- ACCOUNTS_PAGES.ACCOUNT_HANDOFF
- }?package=${CLIENT_PACKAGE_NAMES.get(
- APPS.PHOTOS,
- )}&token=${accountsToken}`,
- );
- } catch (e) {
- log.error("failed to redirect to accounts page", e);
- }
- };
-
- const redirectToDeduplicatePage = () => router.push(PAGES.DEDUPLICATE);
-
- const somethingWentWrong = () =>
- setDialogMessage({
- title: t("ERROR"),
- content: t("RECOVER_KEY_GENERATION_FAILED"),
- close: { variant: "critical" },
- });
-
- const toggleTheme = () => {
- setThemeColor((themeColor) =>
- themeColor === THEME_COLOR.DARK
- ? THEME_COLOR.LIGHT
- : THEME_COLOR.DARK,
- );
- };
-
- return (
- <>
- {isElectron() && (
-
- )}
-
- {isInternalUser() && (
-
- }
- />
- )}
-
-
- {isInternalUser() && (
-
- )}
-
-
-
-
-
-
-
-
-
-
- {isElectron() && (
-
- )}
-
- >
- );
-}
diff --git a/web/apps/photos/src/components/Sidebar/index.tsx b/web/apps/photos/src/components/Sidebar/index.tsx
index efa10a4b0..0d048645d 100644
--- a/web/apps/photos/src/components/Sidebar/index.tsx
+++ b/web/apps/photos/src/components/Sidebar/index.tsx
@@ -1,27 +1,49 @@
import log from "@/next/log";
import { savedLogs } from "@/next/log-web";
+import {
+ configurePasskeyRecovery,
+ isPasskeyRecoveryEnabled,
+} from "@ente/accounts/services/passkey";
+import { APPS, CLIENT_PACKAGE_NAMES } from "@ente/shared/apps/constants";
import EnteSpinner from "@ente/shared/components/EnteSpinner";
+import RecoveryKey from "@ente/shared/components/RecoveryKey";
+import ThemeSwitcher from "@ente/shared/components/ThemeSwitcher";
+import {
+ ACCOUNTS_PAGES,
+ PHOTOS_PAGES as PAGES,
+} from "@ente/shared/constants/pages";
+import { getRecoveryKey } from "@ente/shared/crypto/helpers";
+import {
+ encryptToB64,
+ generateEncryptionKey,
+} from "@ente/shared/crypto/internal/libsodium";
+import { getAccountsURL } from "@ente/shared/network/api";
+import { THEME_COLOR } from "@ente/shared/themes/constants";
import { downloadAsFile } from "@ente/shared/utils";
import { Divider, Stack } from "@mui/material";
import Typography from "@mui/material/Typography";
import DeleteAccountModal from "components/DeleteAccountModal";
import { EnteMenuItem } from "components/Menu/EnteMenuItem";
+import TwoFactorModal from "components/TwoFactor/Modal";
+import { WatchFolder } from "components/WatchFolder";
import { NoStyleAnchor } from "components/pages/sharedAlbum/GoToEnte";
import { t } from "i18next";
import isElectron from "is-electron";
+import { useRouter } from "next/router";
import { AppContext } from "pages/_app";
import { GalleryContext } from "pages/gallery";
import { useContext, useEffect, useState } from "react";
import { Trans } from "react-i18next";
import exportService from "services/export";
+import { getAccountsToken } from "services/userService";
import { CollectionSummaries } from "types/collection";
import { openLink } from "utils/common";
import { getDownloadAppMessage } from "utils/ui";
import { isInternalUser } from "utils/user";
import { testUpload } from "../../../tests/upload.test";
import HeaderSection from "./Header";
+import Preferences from "./Preferences";
import ShortcutSection from "./ShortcutSection";
-import UtilitySection from "./UtilitySection";
import { DrawerSidebar } from "./styledComponents";
import UserDetailsSection from "./userDetailsSection";
@@ -57,6 +79,200 @@ export default function Sidebar({
);
}
+interface UtilitySectionProps {
+ closeSidebar: () => void;
+}
+
+const UtilitySection: React.FC = ({ closeSidebar }) => {
+ const router = useRouter();
+ const appContext = useContext(AppContext);
+ const {
+ setDialogMessage,
+ startLoading,
+ watchFolderView,
+ setWatchFolderView,
+ themeColor,
+ setThemeColor,
+ } = appContext;
+
+ const [recoverModalView, setRecoveryModalView] = useState(false);
+ const [twoFactorModalView, setTwoFactorModalView] = useState(false);
+ const [preferencesView, setPreferencesView] = useState(false);
+
+ const openPreferencesOptions = () => setPreferencesView(true);
+ const closePreferencesOptions = () => setPreferencesView(false);
+
+ const openRecoveryKeyModal = () => setRecoveryModalView(true);
+ const closeRecoveryKeyModal = () => setRecoveryModalView(false);
+
+ const openTwoFactorModal = () => setTwoFactorModalView(true);
+ const closeTwoFactorModal = () => setTwoFactorModalView(false);
+
+ const openWatchFolder = () => {
+ if (isElectron()) {
+ setWatchFolderView(true);
+ } else {
+ setDialogMessage(getDownloadAppMessage());
+ }
+ };
+ const closeWatchFolder = () => setWatchFolderView(false);
+
+ const redirectToChangePasswordPage = () => {
+ closeSidebar();
+ router.push(PAGES.CHANGE_PASSWORD);
+ };
+
+ const redirectToChangeEmailPage = () => {
+ closeSidebar();
+ router.push(PAGES.CHANGE_EMAIL);
+ };
+
+ const redirectToAccountsPage = async () => {
+ closeSidebar();
+
+ try {
+ // check if the user has passkey recovery enabled
+ const recoveryEnabled = await isPasskeyRecoveryEnabled();
+ if (!recoveryEnabled) {
+ // let's create the necessary recovery information
+ const recoveryKey = await getRecoveryKey();
+
+ const resetSecret = await generateEncryptionKey();
+
+ const encryptionResult = await encryptToB64(
+ resetSecret,
+ recoveryKey,
+ );
+
+ await configurePasskeyRecovery(
+ resetSecret,
+ encryptionResult.encryptedData,
+ encryptionResult.nonce,
+ );
+ }
+
+ const accountsToken = await getAccountsToken();
+
+ window.open(
+ `${getAccountsURL()}${
+ ACCOUNTS_PAGES.ACCOUNT_HANDOFF
+ }?package=${CLIENT_PACKAGE_NAMES.get(
+ APPS.PHOTOS,
+ )}&token=${accountsToken}`,
+ );
+ } catch (e) {
+ log.error("failed to redirect to accounts page", e);
+ }
+ };
+
+ const redirectToDeduplicatePage = () => router.push(PAGES.DEDUPLICATE);
+
+ const somethingWentWrong = () =>
+ setDialogMessage({
+ title: t("ERROR"),
+ content: t("RECOVER_KEY_GENERATION_FAILED"),
+ close: { variant: "critical" },
+ });
+
+ const toggleTheme = () => {
+ setThemeColor((themeColor) =>
+ themeColor === THEME_COLOR.DARK
+ ? THEME_COLOR.LIGHT
+ : THEME_COLOR.DARK,
+ );
+ };
+
+ return (
+ <>
+ {isElectron() && (
+
+ )}
+
+ {isInternalUser() && (
+
+ }
+ />
+ )}
+
+
+ {isInternalUser() && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ {isElectron() && (
+
+ )}
+
+ >
+ );
+};
+
const HelpSection: React.FC = () => {
const { setDialogMessage } = useContext(AppContext);
const { openExportModal } = useContext(GalleryContext);