diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerImagesPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerImagesPanel.tsx index bd1484a17a..0563d423ed 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerImagesPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerImagesPanel.tsx @@ -1,9 +1,14 @@ -import React from "react"; +import React, { useCallback, useMemo } from "react"; +import { useIntl } from "react-intl"; import * as GQL from "src/core/generated-graphql"; import { FilteredImageList } from "src/components/Images/ImageList"; +import { IItemListOperation } from "src/components/List/FilteredListToolbar"; +import { usePerformerUpdate } from "src/core/StashService"; import { usePerformerFilterHook } from "src/core/performers"; +import { useToast } from "src/hooks/Toast"; import { View } from "src/components/List/views"; import { PatchComponent } from "src/patch"; +import ImageUtils from "src/utils/image"; interface IPerformerImagesPanel { active: boolean; @@ -12,11 +17,70 @@ interface IPerformerImagesPanel { export const PerformerImagesPanel: React.FC = PatchComponent("PerformerImagesPanel", ({ active, performer }) => { + const intl = useIntl(); + const Toast = useToast(); + const [updatePerformer] = usePerformerUpdate(); const filterHook = usePerformerFilterHook(performer); + + const handleSetAsPerformerImage = useCallback< + IItemListOperation["onClick"] + >( + async (result, _filter, selectedIds) => { + try { + const [selectedId] = Array.from(selectedIds); + const selectedImage = result.data?.findImages.images.find( + (image) => image.id === selectedId + ); + const imagePath = selectedImage?.paths.image; + + if (!imagePath) { + throw new Error("Selected image does not have an image path"); + } + + const imageData = await ImageUtils.imageToDataURL(imagePath); + await updatePerformer({ + variables: { + input: { + id: performer.id, + image: imageData, + }, + }, + }); + + Toast.success( + intl.formatMessage( + { id: "toast.updated_entity" }, + { entity: intl.formatMessage({ id: "performer" }) } + ) + ); + } catch (e) { + Toast.error(e); + } + }, + [Toast, intl, performer.id, updatePerformer] + ); + + const extraOperations = useMemo< + IItemListOperation[] + >( + () => [ + { + text: intl.formatMessage({ + id: "actions.set_as_performer_image", + }), + isDisplayed: (_result, _filter, selectedIds) => + selectedIds.size === 1, + onClick: handleSetAsPerformerImage, + }, + ], + [handleSetAsPerformerImage, intl] + ); + return ( ); diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 701e3d5b35..6619d25ebd 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -129,6 +129,7 @@ "selective_generate": "Selective generate", "selective_scan": "Selective scan", "set_as_default": "Set as default", + "set_as_performer_image": "Set as performer image", "set_back_image": "Back image…", "set_cover": "Set as Cover", "set_front_image": "Front image…",