From f4e260cfb32f31b43974059cf7b940daf9d84bc5 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Sat, 21 Sep 2024 12:46:36 +0530 Subject: [PATCH] Inline --- .../Collections/CollectionInfoWithOptions.tsx | 698 ++++++++++++++++- .../Collections/CollectionOptions/index.tsx | 704 ------------------ 2 files changed, 696 insertions(+), 706 deletions(-) diff --git a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx index 184348f470..b30d8d97f0 100644 --- a/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx +++ b/web/apps/photos/src/components/Collections/CollectionInfoWithOptions.tsx @@ -1,4 +1,6 @@ +import log from "@/base/log"; import type { Collection } from "@/media/collection"; +import { ItemVisibility } from "@/media/file-metadata"; import { GalleryItemsHeaderAdapter, GalleryItemsSummary, @@ -7,15 +9,53 @@ import type { CollectionSummary, CollectionSummaryType, } from "@/new/photos/types/collection"; -import { SpaceBetweenFlex } from "@ente/shared/components/Container"; +import { + HorizontalFlex, + SpaceBetweenFlex, +} from "@ente/shared/components/Container"; +import EnteSpinner from "@ente/shared/components/EnteSpinner"; +import OverflowMenu, { + StyledMenu, +} from "@ente/shared/components/OverflowMenu/menu"; +import { OverflowMenuOption } from "@ente/shared/components/OverflowMenu/option"; import ArchiveOutlined from "@mui/icons-material/ArchiveOutlined"; +import DeleteOutlinedIcon from "@mui/icons-material/DeleteOutlined"; +import EditIcon from "@mui/icons-material/Edit"; import Favorite from "@mui/icons-material/FavoriteRounded"; +import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined"; import LinkIcon from "@mui/icons-material/Link"; +import LogoutIcon from "@mui/icons-material/Logout"; +import MoreHoriz from "@mui/icons-material/MoreHoriz"; import PeopleIcon from "@mui/icons-material/People"; +import PushPinOutlined from "@mui/icons-material/PushPinOutlined"; +import SortIcon from "@mui/icons-material/Sort"; +import TvIcon from "@mui/icons-material/Tv"; +import Unarchive from "@mui/icons-material/Unarchive"; +import VisibilityOffOutlined from "@mui/icons-material/VisibilityOffOutlined"; +import VisibilityOutlined from "@mui/icons-material/VisibilityOutlined"; +import { Box, IconButton, Stack, Tooltip } from "@mui/material"; import { SetCollectionNamerAttributes } from "components/Collections/CollectionNamer"; -import CollectionOptions from "components/Collections/CollectionOptions"; +import { UnPinIcon } from "components/icons/UnPinIcon"; +import { t } from "i18next"; +import { AppContext } from "pages/_app"; +import { GalleryContext } from "pages/gallery"; import type { Dispatch, SetStateAction } from "react"; +import { useCallback, useContext, useRef, useState } from "react"; +import { Trans } from "react-i18next"; +import * as CollectionAPI from "services/collectionService"; +import * as TrashService from "services/trashService"; import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; +import { + ALL_SECTION, + changeCollectionOrder, + changeCollectionSortOrder, + changeCollectionVisibility, + downloadCollectionHelper, + downloadDefaultHiddenCollectionHelper, + HIDDEN_ITEMS_SECTION, + isHiddenCollection, +} from "utils/collection"; +import { isArchivedCollection, isPinnedCollection } from "utils/magicMetadata"; interface Iprops { activeCollection: Collection; @@ -77,3 +117,657 @@ export default function CollectionInfoWithOptions({ const shouldShowOptions = (type: CollectionSummaryType) => type != "all" && type != "archive"; + +interface CollectionOptionsProps { + setCollectionNamerAttributes: SetCollectionNamerAttributes; + setFilesDownloadProgressAttributesCreator: SetFilesDownloadProgressAttributesCreator; + isActiveCollectionDownloadInProgress: () => boolean; + activeCollection: Collection; + collectionSummaryType: CollectionSummaryType; + showCollectionShareModal: () => void; + setActiveCollectionID: (collectionID: number) => void; + setShowAlbumCastDialog: Dispatch>; +} + +const CollectionOptions: React.FC = ({ + activeCollection, + collectionSummaryType, + setActiveCollectionID, + setCollectionNamerAttributes, + showCollectionShareModal, + setFilesDownloadProgressAttributesCreator, + isActiveCollectionDownloadInProgress, + setShowAlbumCastDialog, +}) => { + const { startLoading, finishLoading, setDialogMessage } = + useContext(AppContext); + const { syncWithRemote } = useContext(GalleryContext); + const overFlowMenuIconRef = useRef(null); + const [openSortOrderMenu, setOpenSortOrderMenu] = useState(false); + + const handleError = useCallback( + (e: unknown) => { + log.error("Collection action failed", e); + setDialogMessage({ + title: t("ERROR"), + content: t("UNKNOWN_ERROR"), + close: { variant: "critical" }, + }); + }, + [setDialogMessage], + ); + + /** + * Return a new function by wrapping an async function in an error handler, + * showing the global loading bar when the function runs, and syncing with + * remote on completion. + */ + const wrap = useCallback( + (f: () => Promise) => { + const wrapped = async () => { + startLoading(); + try { + await f(); + } catch (e) { + handleError(e); + } finally { + void syncWithRemote(false, true); + finishLoading(); + } + }; + return (): void => void wrapped(); + }, + [handleError, syncWithRemote, startLoading, finishLoading], + ); + + const showRenameCollectionModal = () => { + setCollectionNamerAttributes({ + title: t("RENAME_COLLECTION"), + buttonText: t("RENAME"), + autoFilledName: activeCollection.name, + callback: renameCollection, + }); + }; + + const _renameCollection = async (newName: string) => { + if (activeCollection.name !== newName) { + await CollectionAPI.renameCollection(activeCollection, newName); + } + }; + + const renameCollection = (newName: string) => + wrap(() => _renameCollection(newName))(); + + const confirmDeleteCollection = () => { + setDialogMessage({ + title: t("DELETE_COLLECTION_TITLE"), + content: ( + , + }} + /> + ), + proceed: { + text: t("DELETE_PHOTOS"), + action: deleteCollectionAlongWithFiles, + variant: "critical", + }, + secondary: { + text: t("KEEP_PHOTOS"), + action: deleteCollectionButKeepFiles, + variant: "primary", + }, + close: { + text: t("cancel"), + }, + }); + }; + + const deleteCollectionAlongWithFiles = wrap(async () => { + await CollectionAPI.deleteCollection(activeCollection.id, false); + setActiveCollectionID(ALL_SECTION); + }); + + const deleteCollectionButKeepFiles = wrap(async () => { + await CollectionAPI.deleteCollection(activeCollection.id, true); + setActiveCollectionID(ALL_SECTION); + }); + + const confirmEmptyTrash = () => + setDialogMessage({ + title: t("EMPTY_TRASH_TITLE"), + content: t("EMPTY_TRASH_MESSAGE"), + proceed: { + action: emptyTrash, + text: t("EMPTY_TRASH"), + variant: "critical", + }, + close: { text: t("cancel") }, + }); + + const emptyTrash = wrap(async () => { + await TrashService.emptyTrash(); + await TrashService.clearLocalTrash(); + setActiveCollectionID(ALL_SECTION); + }); + + const _downloadCollection = () => { + if (isActiveCollectionDownloadInProgress()) return; + + if (collectionSummaryType == "hiddenItems") { + return downloadDefaultHiddenCollectionHelper( + setFilesDownloadProgressAttributesCreator( + activeCollection.name, + HIDDEN_ITEMS_SECTION, + true, + ), + ); + } else { + return downloadCollectionHelper( + activeCollection.id, + setFilesDownloadProgressAttributesCreator( + activeCollection.name, + activeCollection.id, + isHiddenCollection(activeCollection), + ), + ); + } + }; + + const downloadCollection = () => + void _downloadCollection().catch(handleError); + + const archiveAlbum = wrap(() => + changeCollectionVisibility(activeCollection, ItemVisibility.archived), + ); + + const unarchiveAlbum = wrap(() => + changeCollectionVisibility(activeCollection, ItemVisibility.visible), + ); + + const confirmLeaveSharedAlbum = () => { + setDialogMessage({ + title: t("LEAVE_SHARED_ALBUM_TITLE"), + content: t("LEAVE_SHARED_ALBUM_MESSAGE"), + proceed: { + text: t("LEAVE_SHARED_ALBUM"), + action: leaveSharedAlbum, + variant: "critical", + }, + close: { + text: t("cancel"), + }, + }); + }; + + const leaveSharedAlbum = wrap(async () => { + await CollectionAPI.leaveSharedAlbum(activeCollection.id); + setActiveCollectionID(ALL_SECTION); + }); + + const showCastAlbumDialog = () => setShowAlbumCastDialog(true); + + const pinAlbum = wrap(() => changeCollectionOrder(activeCollection, 1)); + + const unpinAlbum = wrap(() => changeCollectionOrder(activeCollection, 0)); + + const hideAlbum = wrap(async () => { + await changeCollectionVisibility( + activeCollection, + ItemVisibility.hidden, + ); + setActiveCollectionID(ALL_SECTION); + }); + + const unhideAlbum = wrap(async () => { + await changeCollectionVisibility( + activeCollection, + ItemVisibility.visible, + ); + setActiveCollectionID(HIDDEN_ITEMS_SECTION); + }); + + const showSortOrderMenu = () => setOpenSortOrderMenu(true); + + const closeSortOrderMenu = () => setOpenSortOrderMenu(false); + + const changeSortOrderAsc = wrap(() => + changeCollectionSortOrder(activeCollection, true), + ); + + const changeSortOrderDesc = wrap(() => + changeCollectionSortOrder(activeCollection, false), + ); + + return ( + + + + } + > + {collectionSummaryType == "trash" ? ( + + ) : collectionSummaryType == "favorites" ? ( + + {t("DOWNLOAD_FAVORITES")} + + ) : collectionSummaryType == "uncategorized" ? ( + + {t("DOWNLOAD_UNCATEGORIZED")} + + ) : collectionSummaryType == "hiddenItems" ? ( + + {t("DOWNLOAD_HIDDEN_ITEMS")} + + ) : collectionSummaryType == "incomingShareViewer" || + collectionSummaryType == "incomingShareCollaborator" ? ( + + ) : ( + + )} + + + + ); +}; + +/** Props for a generic option. */ +interface OptionProps { + onClick: () => void; +} + +interface QuickOptionsProps { + collectionSummaryType: CollectionSummaryType; + isDownloadInProgress: () => boolean; + onEmptyTrashClick: () => void; + onDownloadClick: () => void; + onShareClick: () => void; +} + +const QuickOptions: React.FC = ({ + onEmptyTrashClick, + onDownloadClick, + onShareClick, + collectionSummaryType: type, + isDownloadInProgress, +}) => ( + + {showEmptyTrashQuickOption(type) && ( + + )} + {showDownloadQuickOption(type) && + (isDownloadInProgress() ? ( + + ) : ( + + ))} + {showShareQuickOption(type) && ( + + )} + +); + +const showEmptyTrashQuickOption = (type: CollectionSummaryType) => + type == "trash"; + +const EmptyTrashQuickOption: React.FC = ({ onClick }) => ( + + + + + +); + +const showDownloadQuickOption = (type: CollectionSummaryType) => + type == "folder" || + type == "favorites" || + type == "album" || + type == "uncategorized" || + type == "hiddenItems" || + type == "incomingShareViewer" || + type == "incomingShareCollaborator" || + type == "outgoingShare" || + type == "sharedOnlyViaLink" || + type == "archived" || + type == "pinned"; + +type DownloadQuickOptionProps = OptionProps & { + collectionSummaryType: CollectionSummaryType; +}; + +const DownloadQuickOption: React.FC = ({ + onClick, + collectionSummaryType, +}) => ( + + + + + +); + +const showShareQuickOption = (type: CollectionSummaryType) => + type == "folder" || + type == "album" || + type == "outgoingShare" || + type == "sharedOnlyViaLink" || + type == "archived" || + type == "incomingShareViewer" || + type == "incomingShareCollaborator" || + type == "pinned"; + +interface ShareQuickOptionProps { + onClick: () => void; + collectionSummaryType: CollectionSummaryType; +} + +const ShareQuickOption: React.FC = ({ + onClick, + collectionSummaryType, +}) => ( + + + + + +); + +const EmptyTrashOption: React.FC = ({ onClick }) => ( + } + onClick={onClick} + > + {t("EMPTY_TRASH")} + +); + +type DownloadOptionProps = OptionProps & { + isDownloadInProgress?: () => boolean; +}; + +const DownloadOption: React.FC< + React.PropsWithChildren +> = ({ isDownloadInProgress, onClick, children }) => ( + + ) : ( + + ) + } + onClick={onClick} + > + {children} + +); + +interface SharedCollectionOptionProps { + isArchived: boolean; + onArchiveClick: () => void; + onUnarchiveClick: () => void; + onLeaveSharedAlbumClick: () => void; + onCastClick: () => void; +} + +const SharedCollectionOptions: React.FC = ({ + isArchived, + onArchiveClick, + onUnarchiveClick, + onLeaveSharedAlbumClick, + onCastClick, +}) => ( + <> + {isArchived ? ( + } + > + {t("UNARCHIVE_COLLECTION")} + + ) : ( + } + > + {t("ARCHIVE_COLLECTION")} + + )} + } + onClick={onLeaveSharedAlbumClick} + > + {t("LEAVE_ALBUM")} + + } onClick={onCastClick}> + {t("CAST_ALBUM_TO_TV")} + + +); + +interface AlbumCollectionOptionsProps { + isArchived: boolean; + isPinned: boolean; + isHidden: boolean; + onRenameClick: () => void; + onSortClick: () => void; + onArchiveClick: () => void; + onUnarchiveClick: () => void; + onPinClick: () => void; + onUnpinClick: () => void; + onHideClick: () => void; + onUnhideClick: () => void; + onDeleteClick: () => void; + onShareClick: () => void; + onCastClick: () => void; +} + +const AlbumCollectionOptions: React.FC = ({ + isArchived, + isPinned, + isHidden, + onRenameClick, + onSortClick, + onArchiveClick, + onUnarchiveClick, + onPinClick, + onUnpinClick, + onHideClick, + onUnhideClick, + onDeleteClick, + onShareClick, + onCastClick, +}) => ( + <> + }> + {t("RENAME_COLLECTION")} + + }> + {t("SORT_BY")} + + {isPinned ? ( + } + > + {t("UNPIN_ALBUM")} + + ) : ( + } + > + {t("PIN_ALBUM")} + + )} + {!isHidden && ( + <> + {isArchived ? ( + } + > + {t("UNARCHIVE_COLLECTION")} + + ) : ( + } + > + {t("ARCHIVE_COLLECTION")} + + )} + + )} + {isHidden ? ( + } + > + {t("UNHIDE_COLLECTION")} + + ) : ( + } + > + {t("HIDE_COLLECTION")} + + )} + } + onClick={onDeleteClick} + > + {t("DELETE_COLLECTION")} + + }> + {t("SHARE_COLLECTION")} + + } onClick={onCastClick}> + {t("CAST_ALBUM_TO_TV")} + + +); + +interface CollectionSortOrderMenuProps { + open: boolean; + onClose: () => void; + overFlowMenuIconRef: React.MutableRefObject; + onAscClick: () => void; + onDescClick: () => void; +} + +const CollectionSortOrderMenu: React.FC = ({ + open, + onClose, + overFlowMenuIconRef, + onAscClick, + onDescClick, +}) => { + const handleAscClick = () => { + onClose(); + onAscClick(); + }; + + const handleDescClick = () => { + onClose(); + onDescClick(); + }; + + return ( + + + {t("NEWEST_FIRST")} + + + {t("OLDEST_FIRST")} + + + ); +}; diff --git a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx index 472cd57194..e69de29bb2 100644 --- a/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx +++ b/web/apps/photos/src/components/Collections/CollectionOptions/index.tsx @@ -1,704 +0,0 @@ -import log from "@/base/log"; -import type { Collection } from "@/media/collection"; -import { ItemVisibility } from "@/media/file-metadata"; -import type { CollectionSummaryType } from "@/new/photos/types/collection"; -import { HorizontalFlex } from "@ente/shared/components/Container"; -import EnteSpinner from "@ente/shared/components/EnteSpinner"; -import OverflowMenu, { - StyledMenu, -} from "@ente/shared/components/OverflowMenu/menu"; -import { OverflowMenuOption } from "@ente/shared/components/OverflowMenu/option"; -import ArchiveOutlined from "@mui/icons-material/ArchiveOutlined"; -import DeleteOutlinedIcon from "@mui/icons-material/DeleteOutlined"; -import EditIcon from "@mui/icons-material/Edit"; -import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined"; -import LogoutIcon from "@mui/icons-material/Logout"; -import MoreHoriz from "@mui/icons-material/MoreHoriz"; -import PeopleIcon from "@mui/icons-material/People"; -import PushPinOutlined from "@mui/icons-material/PushPinOutlined"; -import SortIcon from "@mui/icons-material/Sort"; -import TvIcon from "@mui/icons-material/Tv"; -import Unarchive from "@mui/icons-material/Unarchive"; -import VisibilityOffOutlined from "@mui/icons-material/VisibilityOffOutlined"; -import VisibilityOutlined from "@mui/icons-material/VisibilityOutlined"; -import { Box, IconButton, Stack, Tooltip } from "@mui/material"; -import { UnPinIcon } from "components/icons/UnPinIcon"; -import { t } from "i18next"; -import { AppContext } from "pages/_app"; -import { GalleryContext } from "pages/gallery"; -import type { Dispatch, SetStateAction } from "react"; -import { useCallback, useContext, useRef, useState } from "react"; -import { Trans } from "react-i18next"; -import * as CollectionAPI from "services/collectionService"; -import * as TrashService from "services/trashService"; -import { SetFilesDownloadProgressAttributesCreator } from "types/gallery"; -import { - ALL_SECTION, - changeCollectionOrder, - changeCollectionSortOrder, - changeCollectionVisibility, - downloadCollectionHelper, - downloadDefaultHiddenCollectionHelper, - HIDDEN_ITEMS_SECTION, - isHiddenCollection, -} from "utils/collection"; -import { isArchivedCollection, isPinnedCollection } from "utils/magicMetadata"; -import { SetCollectionNamerAttributes } from "../CollectionNamer"; - -interface CollectionOptionsProps { - setCollectionNamerAttributes: SetCollectionNamerAttributes; - setFilesDownloadProgressAttributesCreator: SetFilesDownloadProgressAttributesCreator; - isActiveCollectionDownloadInProgress: () => boolean; - activeCollection: Collection; - collectionSummaryType: CollectionSummaryType; - showCollectionShareModal: () => void; - setActiveCollectionID: (collectionID: number) => void; - setShowAlbumCastDialog: Dispatch>; -} - -const CollectionOptions = (props: CollectionOptionsProps) => { - const { - activeCollection, - collectionSummaryType, - setActiveCollectionID, - setCollectionNamerAttributes, - showCollectionShareModal, - setFilesDownloadProgressAttributesCreator, - isActiveCollectionDownloadInProgress, - setShowAlbumCastDialog, - } = props; - - const { startLoading, finishLoading, setDialogMessage } = - useContext(AppContext); - const { syncWithRemote } = useContext(GalleryContext); - const overFlowMenuIconRef = useRef(null); - const [openSortOrderMenu, setOpenSortOrderMenu] = useState(false); - - const handleError = useCallback( - (e: unknown) => { - log.error("Collection action failed", e); - setDialogMessage({ - title: t("ERROR"), - content: t("UNKNOWN_ERROR"), - close: { variant: "critical" }, - }); - }, - [setDialogMessage], - ); - - /** - * Return a new function by wrapping an async function in an error handler, - * showing the global loading bar when the function runs, and syncing with - * remote on completion. - */ - const wrap = useCallback( - (f: () => Promise) => { - const wrapped = async () => { - startLoading(); - try { - await f(); - } catch (e) { - handleError(e); - } finally { - void syncWithRemote(false, true); - finishLoading(); - } - }; - return (): void => void wrapped(); - }, - [handleError, syncWithRemote, startLoading, finishLoading], - ); - - const showRenameCollectionModal = () => { - setCollectionNamerAttributes({ - title: t("RENAME_COLLECTION"), - buttonText: t("RENAME"), - autoFilledName: activeCollection.name, - callback: renameCollection, - }); - }; - - const _renameCollection = async (newName: string) => { - if (activeCollection.name !== newName) { - await CollectionAPI.renameCollection(activeCollection, newName); - } - }; - - const renameCollection = (newName: string) => - wrap(() => _renameCollection(newName))(); - - const confirmDeleteCollection = () => { - setDialogMessage({ - title: t("DELETE_COLLECTION_TITLE"), - content: ( - , - }} - /> - ), - proceed: { - text: t("DELETE_PHOTOS"), - action: deleteCollectionAlongWithFiles, - variant: "critical", - }, - secondary: { - text: t("KEEP_PHOTOS"), - action: deleteCollectionButKeepFiles, - variant: "primary", - }, - close: { - text: t("cancel"), - }, - }); - }; - - const deleteCollectionAlongWithFiles = wrap(async () => { - await CollectionAPI.deleteCollection(activeCollection.id, false); - setActiveCollectionID(ALL_SECTION); - }); - - const deleteCollectionButKeepFiles = wrap(async () => { - await CollectionAPI.deleteCollection(activeCollection.id, true); - setActiveCollectionID(ALL_SECTION); - }); - - const confirmEmptyTrash = () => - setDialogMessage({ - title: t("EMPTY_TRASH_TITLE"), - content: t("EMPTY_TRASH_MESSAGE"), - proceed: { - action: emptyTrash, - text: t("EMPTY_TRASH"), - variant: "critical", - }, - close: { text: t("cancel") }, - }); - - const emptyTrash = wrap(async () => { - await TrashService.emptyTrash(); - await TrashService.clearLocalTrash(); - setActiveCollectionID(ALL_SECTION); - }); - - const _downloadCollection = () => { - if (isActiveCollectionDownloadInProgress()) return; - - if (collectionSummaryType == "hiddenItems") { - return downloadDefaultHiddenCollectionHelper( - setFilesDownloadProgressAttributesCreator( - activeCollection.name, - HIDDEN_ITEMS_SECTION, - true, - ), - ); - } else { - return downloadCollectionHelper( - activeCollection.id, - setFilesDownloadProgressAttributesCreator( - activeCollection.name, - activeCollection.id, - isHiddenCollection(activeCollection), - ), - ); - } - }; - - const downloadCollection = () => - void _downloadCollection().catch(handleError); - - const archiveAlbum = wrap(() => - changeCollectionVisibility(activeCollection, ItemVisibility.archived), - ); - - const unarchiveAlbum = wrap(() => - changeCollectionVisibility(activeCollection, ItemVisibility.visible), - ); - - const confirmLeaveSharedAlbum = () => { - setDialogMessage({ - title: t("LEAVE_SHARED_ALBUM_TITLE"), - content: t("LEAVE_SHARED_ALBUM_MESSAGE"), - proceed: { - text: t("LEAVE_SHARED_ALBUM"), - action: leaveSharedAlbum, - variant: "critical", - }, - close: { - text: t("cancel"), - }, - }); - }; - - const leaveSharedAlbum = wrap(async () => { - await CollectionAPI.leaveSharedAlbum(activeCollection.id); - setActiveCollectionID(ALL_SECTION); - }); - - const showCastAlbumDialog = () => setShowAlbumCastDialog(true); - - const pinAlbum = wrap(() => changeCollectionOrder(activeCollection, 1)); - - const unpinAlbum = wrap(() => changeCollectionOrder(activeCollection, 0)); - - const hideAlbum = wrap(async () => { - await changeCollectionVisibility( - activeCollection, - ItemVisibility.hidden, - ); - setActiveCollectionID(ALL_SECTION); - }); - - const unhideAlbum = wrap(async () => { - await changeCollectionVisibility( - activeCollection, - ItemVisibility.visible, - ); - setActiveCollectionID(HIDDEN_ITEMS_SECTION); - }); - - const showSortOrderMenu = () => setOpenSortOrderMenu(true); - - const closeSortOrderMenu = () => setOpenSortOrderMenu(false); - - const changeSortOrderAsc = wrap(() => - changeCollectionSortOrder(activeCollection, true), - ); - - const changeSortOrderDesc = wrap(() => - changeCollectionSortOrder(activeCollection, false), - ); - - return ( - - - - } - > - {collectionSummaryType == "trash" ? ( - - ) : collectionSummaryType == "favorites" ? ( - - {t("DOWNLOAD_FAVORITES")} - - ) : collectionSummaryType == "uncategorized" ? ( - - {t("DOWNLOAD_UNCATEGORIZED")} - - ) : collectionSummaryType == "hiddenItems" ? ( - - {t("DOWNLOAD_HIDDEN_ITEMS")} - - ) : collectionSummaryType == "incomingShareViewer" || - collectionSummaryType == "incomingShareCollaborator" ? ( - - ) : ( - - )} - - - - ); -}; - -export default CollectionOptions; - -/** Props for a generic option. */ -interface OptionProps { - onClick: () => void; -} - -interface QuickOptionsProps { - collectionSummaryType: CollectionSummaryType; - isDownloadInProgress: () => boolean; - onEmptyTrashClick: () => void; - onDownloadClick: () => void; - onShareClick: () => void; -} - -const QuickOptions: React.FC = ({ - onEmptyTrashClick, - onDownloadClick, - onShareClick, - collectionSummaryType: type, - isDownloadInProgress, -}) => ( - - {showEmptyTrashQuickOption(type) && ( - - )} - {showDownloadQuickOption(type) && - (isDownloadInProgress() ? ( - - ) : ( - - ))} - {showShareQuickOption(type) && ( - - )} - -); - -const showEmptyTrashQuickOption = (type: CollectionSummaryType) => - type == "trash"; - -const EmptyTrashQuickOption: React.FC = ({ onClick }) => ( - - - - - -); - -const showDownloadQuickOption = (type: CollectionSummaryType) => - type == "folder" || - type == "favorites" || - type == "album" || - type == "uncategorized" || - type == "hiddenItems" || - type == "incomingShareViewer" || - type == "incomingShareCollaborator" || - type == "outgoingShare" || - type == "sharedOnlyViaLink" || - type == "archived" || - type == "pinned"; - -type DownloadQuickOptionProps = OptionProps & { - collectionSummaryType: CollectionSummaryType; -}; - -const DownloadQuickOption: React.FC = ({ - onClick, - collectionSummaryType, -}) => ( - - - - - -); - -const showShareQuickOption = (type: CollectionSummaryType) => - type == "folder" || - type == "album" || - type == "outgoingShare" || - type == "sharedOnlyViaLink" || - type == "archived" || - type == "incomingShareViewer" || - type == "incomingShareCollaborator" || - type == "pinned"; - -interface ShareQuickOptionProps { - onClick: () => void; - collectionSummaryType: CollectionSummaryType; -} - -const ShareQuickOption: React.FC = ({ - onClick, - collectionSummaryType, -}) => ( - - - - - -); - -const EmptyTrashOption: React.FC = ({ onClick }) => ( - } - onClick={onClick} - > - {t("EMPTY_TRASH")} - -); - -type DownloadOptionProps = OptionProps & { - isDownloadInProgress?: () => boolean; -}; - -const DownloadOption: React.FC< - React.PropsWithChildren -> = ({ isDownloadInProgress, onClick, children }) => ( - - ) : ( - - ) - } - onClick={onClick} - > - {children} - -); - -interface SharedCollectionOptionProps { - isArchived: boolean; - onArchiveClick: () => void; - onUnarchiveClick: () => void; - onLeaveSharedAlbumClick: () => void; - onCastClick: () => void; -} - -const SharedCollectionOptions: React.FC = ({ - isArchived, - onArchiveClick, - onUnarchiveClick, - onLeaveSharedAlbumClick, - onCastClick, -}) => ( - <> - {isArchived ? ( - } - > - {t("UNARCHIVE_COLLECTION")} - - ) : ( - } - > - {t("ARCHIVE_COLLECTION")} - - )} - } - onClick={onLeaveSharedAlbumClick} - > - {t("LEAVE_ALBUM")} - - } onClick={onCastClick}> - {t("CAST_ALBUM_TO_TV")} - - -); - -interface AlbumCollectionOptionsProps { - isArchived: boolean; - isPinned: boolean; - isHidden: boolean; - onRenameClick: () => void; - onSortClick: () => void; - onArchiveClick: () => void; - onUnarchiveClick: () => void; - onPinClick: () => void; - onUnpinClick: () => void; - onHideClick: () => void; - onUnhideClick: () => void; - onDeleteClick: () => void; - onShareClick: () => void; - onCastClick: () => void; -} - -const AlbumCollectionOptions: React.FC = ({ - isArchived, - isPinned, - isHidden, - onRenameClick, - onSortClick, - onArchiveClick, - onUnarchiveClick, - onPinClick, - onUnpinClick, - onHideClick, - onUnhideClick, - onDeleteClick, - onShareClick, - onCastClick, -}) => ( - <> - }> - {t("RENAME_COLLECTION")} - - }> - {t("SORT_BY")} - - {isPinned ? ( - } - > - {t("UNPIN_ALBUM")} - - ) : ( - } - > - {t("PIN_ALBUM")} - - )} - {!isHidden && ( - <> - {isArchived ? ( - } - > - {t("UNARCHIVE_COLLECTION")} - - ) : ( - } - > - {t("ARCHIVE_COLLECTION")} - - )} - - )} - {isHidden ? ( - } - > - {t("UNHIDE_COLLECTION")} - - ) : ( - } - > - {t("HIDE_COLLECTION")} - - )} - } - onClick={onDeleteClick} - > - {t("DELETE_COLLECTION")} - - }> - {t("SHARE_COLLECTION")} - - } onClick={onCastClick}> - {t("CAST_ALBUM_TO_TV")} - - -); - -interface CollectionSortOrderMenuProps { - open: boolean; - onClose: () => void; - overFlowMenuIconRef: React.MutableRefObject; - onAscClick: () => void; - onDescClick: () => void; -} - -const CollectionSortOrderMenu: React.FC = ({ - open, - onClose, - overFlowMenuIconRef, - onAscClick, - onDescClick, -}) => { - const handleAscClick = () => { - onClose(); - onAscClick(); - }; - - const handleDescClick = () => { - onClose(); - onDescClick(); - }; - - return ( - - - {t("NEWEST_FIRST")} - - - {t("OLDEST_FIRST")} - - - ); -};