diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index 127d713cfe..f0e91e2e1e 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -632,7 +632,7 @@ const Page: React.FC = () => { return updater; }, []); - const createCollectionOpHandler = + const createOnSelectForCollectionOp = (op: CollectionOp) => async (selectedCollection: Collection) => { showLoadingBar(); try { @@ -701,7 +701,7 @@ const Page: React.FC = () => { } }; - const handleCreateAlbumForOp = useCallback( + const createOnCreateForCollectionOp = useCallback( (op: CollectionOp) => { setPostCreateAlbumOp(op); return showAlbumNameInput; @@ -715,11 +715,13 @@ const Page: React.FC = () => { setPostCreateAlbumOp((postCreateAlbumOp) => { // The function returned by createHandleCollectionOp does its // own progress and error reporting, defer to that. - void createCollectionOpHandler(postCreateAlbumOp!)(collection); + void createOnSelectForCollectionOp(postCreateAlbumOp!)( + collection, + ); return undefined; }); }, - [createCollectionOpHandler], + [createOnSelectForCollectionOp], ); const handleSelectSearchOption = ( @@ -931,9 +933,11 @@ const Page: React.FC = () => { selectedFileCount={selected.count} selectedOwnFileCount={selected.ownCount} onClearSelection={clearSelection} - onShowCreateCollectionModal={handleCreateAlbumForOp} onOpenCollectionSelector={handleOpenCollectionSelector} - onCreateCollectionOpHandler={createCollectionOpHandler} + {...{ + createOnCreateForCollectionOp, + createOnSelectForCollectionOp, + }} handleFileOp={fileOpHelper} /> ) : barMode == "hidden-albums" ? ( diff --git a/web/packages/new/photos/components/CollectionSelector.tsx b/web/packages/new/photos/components/CollectionSelector.tsx index f95f42c049..18876f193e 100644 --- a/web/packages/new/photos/components/CollectionSelector.tsx +++ b/web/packages/new/photos/components/CollectionSelector.tsx @@ -47,16 +47,16 @@ export interface CollectionSelectorAttributes { * {@link sourceCollectionID} to omit showing it in the list again. */ sourceCollectionSummaryID?: number; - /** - * Callback invoked when the user selects one the existing collections - * listed in the dialog. - */ - onSelectCollection: (collection: Collection) => void; /** * Callback invoked when the user selects the option to create a new * collection. */ onCreateCollection: () => void; + /** + * Callback invoked when the user selects one the existing collections + * listed in the dialog. + */ + onSelectCollection: (collection: Collection) => void; /** * Callback invoked when the user cancels the collection selection dialog. */ diff --git a/web/packages/new/photos/components/SelectedFileOptions.tsx b/web/packages/new/photos/components/SelectedFileOptions.tsx index e742f37412..8a45c57d72 100644 --- a/web/packages/new/photos/components/SelectedFileOptions.tsx +++ b/web/packages/new/photos/components/SelectedFileOptions.tsx @@ -12,6 +12,7 @@ import UnArchiveIcon from "@mui/icons-material/Unarchive"; import VisibilityOffOutlinedIcon from "@mui/icons-material/VisibilityOffOutlined"; import VisibilityOutlinedIcon from "@mui/icons-material/VisibilityOutlined"; import { IconButton, Tooltip, Typography } from "@mui/material"; +import { assertionFailed } from "ente-base/assert"; import { SpacedRow } from "ente-base/components/containers"; import type { ButtonishProps } from "ente-base/components/mui"; import { useBaseContext } from "ente-base/context"; @@ -85,13 +86,6 @@ interface SelectedFileOptionsProps { * on the selection bar. */ onClearSelection: () => void; - /** - * Called when an operation requires prompting the user to create a new - * collection (e.g. adding to a new album). - * - * The callback is also passed the operation that caused it to be shown. - */ - onShowCreateCollectionModal: (op: CollectionOp) => () => void; /** * Callback to open a dialog where the user can choose a collection. * @@ -102,21 +96,40 @@ interface SelectedFileOptionsProps { attributes: CollectionSelectorAttributes, ) => void; /** - * A function called to obtain a handler for the provided {@link op}. + * A function called to obtain a new album creation handler for the provided + * {@link op}. + * + * This function will be passed the operation to be be performed. It will + * return a new function G can be used as the {@link onCreateCollection} + * attribute for {@link onOpenCollectionSelector}. + * + * Once the user enters the name and a new album with that name gets + * created, the newly created collection will be passed to G. + * + * @param op The operation that should be performed using the newly created + * collection. + * + * @returns A function that can be called with to create a new collection + * and then perform {@link op} on successful creation of the new collection. + */ + createOnCreateForCollectionOp: (op: CollectionOp) => () => void; + /** + * A function called to obtain an existing album selection handler for the + * provided {@link op}. * * This function will be passed the operation to be be performed. It will * return a new function G can be used as the {@link onSelectCollection} * attribute for {@link onOpenCollectionSelector}. * - * Once the user selects a collection (or creates a new one), then that - * selected collection will be passed to G. + * Once the user selects a collection, then the selected collection will be + * passed to G. * * @param op The operation that should be performed using the selected * collection. * * @returns A function that can be called with a selected collection. */ - onCreateCollectionOpHandler: ( + createOnSelectForCollectionOp: ( op: CollectionOp, ) => (selectedCollection: Collection) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -135,9 +148,9 @@ export const SelectedFileOptions: React.FC = ({ selectedFileCount, selectedOwnFileCount, onClearSelection, - onShowCreateCollectionModal, onOpenCollectionSelector, - onCreateCollectionOpHandler, + createOnCreateForCollectionOp, + createOnSelectForCollectionOp, handleFileOp, }) => { const { showMiniDialog } = useBaseContext(); @@ -145,14 +158,6 @@ export const SelectedFileOptions: React.FC = ({ const isUserFavorites = !!collectionSummary?.attributes.has("userFavorites"); - const handleUnhide = () => { - onOpenCollectionSelector({ - action: "unhide", - onSelectCollection: onCreateCollectionOpHandler("unhide"), - onCreateCollection: onShowCreateCollectionModal("unhide"), - }); - }; - const handleDelete = () => showMiniDialog({ title: t("trash_files_title"), @@ -167,8 +172,8 @@ export const SelectedFileOptions: React.FC = ({ const handleRestore = () => onOpenCollectionSelector({ action: "restore", - onSelectCollection: onCreateCollectionOpHandler("restore"), - onCreateCollection: onShowCreateCollectionModal("restore"), + onCreateCollection: createOnCreateForCollectionOp("restore"), + onSelectCollection: createOnSelectForCollectionOp("restore"), }); const handleDeletePermanently = () => @@ -186,11 +191,21 @@ export const SelectedFileOptions: React.FC = ({ onOpenCollectionSelector({ action: "add", sourceCollectionSummaryID: collectionSummary?.id, - onSelectCollection: onCreateCollectionOpHandler("add"), - onCreateCollection: onShowCreateCollectionModal("add"), + onCreateCollection: createOnCreateForCollectionOp("add"), + onSelectCollection: createOnSelectForCollectionOp("add"), }); const handleRemoveFromOwnCollection = () => { + if (!collection) { + assertionFailed(); + return; + } + + // Reuse the scaffolding provided by the collection selection mechanism, + // even though we already know the selected collection. + const remove = () => + createOnSelectForCollectionOp("remove")(collection); + showMiniDialog( selectedFileCount == selectedOwnFileCount ? { @@ -199,10 +214,7 @@ export const SelectedFileOptions: React.FC = ({ continue: { text: t("yes_remove"), color: "primary", - action: () => - onCreateCollectionOpHandler("remove")( - collection!, - ), + action: remove, }, } : { @@ -211,10 +223,7 @@ export const SelectedFileOptions: React.FC = ({ continue: { text: t("yes_remove"), color: "critical", - action: () => - onCreateCollectionOpHandler("remove")( - collection!, - ), + action: remove, }, }, ); @@ -224,8 +233,16 @@ export const SelectedFileOptions: React.FC = ({ onOpenCollectionSelector({ action: "move", sourceCollectionSummaryID: collectionSummary?.id, - onSelectCollection: onCreateCollectionOpHandler("move"), - onCreateCollection: onShowCreateCollectionModal("move"), + onCreateCollection: createOnCreateForCollectionOp("move"), + onSelectCollection: createOnSelectForCollectionOp("move"), + }); + }; + + const handleUnhide = () => { + onOpenCollectionSelector({ + action: "unhide", + onCreateCollection: createOnCreateForCollectionOp("unhide"), + onSelectCollection: createOnSelectForCollectionOp("unhide"), }); };