diff --git a/ui/v2/src/components/performers/PerformerDetails/Performer.tsx b/ui/v2/src/components/performers/PerformerDetails/Performer.tsx index 88ff8cbcc..41d777add 100644 --- a/ui/v2/src/components/performers/PerformerDetails/Performer.tsx +++ b/ui/v2/src/components/performers/PerformerDetails/Performer.tsx @@ -1,11 +1,10 @@ import { - Button, - Classes, - Dialog, - EditableText, - HTMLTable, Spinner, - FormGroup, + Tabs, + Tab, + Button, + AnchorButton, + IconName, } from "@blueprintjs/core"; import _ from "lodash"; import React, { FunctionComponent, useEffect, useState } from "react"; @@ -13,77 +12,29 @@ import * as GQL from "../../../core/generated-graphql"; import { StashService } from "../../../core/StashService"; import { IBaseProps } from "../../../models"; import { ErrorUtils } from "../../../utils/errors"; -import { TableUtils } from "../../../utils/table"; -import { ScrapePerformerSuggest } from "../../select/ScrapePerformerSuggest"; -import { DetailsEditNavbar } from "../../Shared/DetailsEditNavbar"; -import { ToastUtils } from "../../../utils/toasts"; -import { EditableTextUtils } from "../../../utils/editabletext"; -import { ImageUtils } from "../../../utils/image"; +import { PerformerDetailsPanel } from "./PerformerDetailsPanel"; +import { PerformerOperationsPanel } from "./PerformerOperationsPanel"; +import { PerformerScenesPanel } from "./PerformerScenesPanel"; +import { TextUtils } from "../../../utils/text"; +import Lightbox from "react-images"; interface IPerformerProps extends IBaseProps {} export const Performer: FunctionComponent = (props: IPerformerProps) => { const isNew = props.match.params.id === "new"; - // Editing state - const [isEditing, setIsEditing] = useState(isNew); - const [isDisplayingScraperDialog, setIsDisplayingScraperDialog] = useState(undefined); - const [scrapePerformerDetails, setScrapePerformerDetails] = useState(undefined); - - // Editing performer state - const [image, setImage] = useState(undefined); - const [name, setName] = useState(undefined); - const [aliases, setAliases] = useState(undefined); - const [favorite, setFavorite] = useState(undefined); - const [birthdate, setBirthdate] = useState(undefined); - const [ethnicity, setEthnicity] = useState(undefined); - const [country, setCountry] = useState(undefined); - const [eyeColor, setEyeColor] = useState(undefined); - const [height, setHeight] = useState(undefined); - const [measurements, setMeasurements] = useState(undefined); - const [fakeTits, setFakeTits] = useState(undefined); - const [careerLength, setCareerLength] = useState(undefined); - const [tattoos, setTattoos] = useState(undefined); - const [piercings, setPiercings] = useState(undefined); - const [url, setUrl] = useState(undefined); - const [twitter, setTwitter] = useState(undefined); - const [instagram, setInstagram] = useState(undefined); - // Performer state const [performer, setPerformer] = useState>({}); const [imagePreview, setImagePreview] = useState(undefined); + const [lightboxIsOpen, setLightboxIsOpen] = useState(false); // Network state const [isLoading, setIsLoading] = useState(false); - const Scrapers = StashService.useListPerformerScrapers(); - const [queryableScrapers, setQueryableScrapers] = useState([]); - const { data, error, loading } = StashService.useFindPerformer(props.match.params.id); - const updatePerformer = StashService.usePerformerUpdate(getPerformerInput() as GQL.PerformerUpdateInput); - const createPerformer = StashService.usePerformerCreate(getPerformerInput() as GQL.PerformerCreateInput); - const deletePerformer = StashService.usePerformerDestroy(getPerformerInput() as GQL.PerformerDestroyInput); - - function updatePerformerEditState(state: Partial) { - if ((state as GQL.PerformerDataFragment).favorite !== undefined) { - setFavorite((state as GQL.PerformerDataFragment).favorite); - } - setName(state.name); - setAliases(state.aliases); - setBirthdate(state.birthdate); - setEthnicity(state.ethnicity); - setCountry(state.country); - setEyeColor(state.eye_color); - setHeight(state.height); - setMeasurements(state.measurements); - setFakeTits(state.fake_tits); - setCareerLength(state.career_length); - setTattoos(state.tattoos); - setPiercings(state.piercings); - setUrl(state.url); - setTwitter(state.twitter); - setInstagram(state.instagram); - } + const updatePerformer = StashService.usePerformerUpdate(); + const createPerformer = StashService.usePerformerCreate(); + const deletePerformer = StashService.usePerformerDestroy(); useEffect(() => { setIsLoading(loading); @@ -93,73 +44,25 @@ export const Performer: FunctionComponent = (props: IPerformerP useEffect(() => { setImagePreview(performer.image_path); - setImage(undefined); - updatePerformerEditState(performer); - if (!isNew) { - setIsEditing(false); - } }, [performer]); - function onImageLoad(this: FileReader) { - setImagePreview(this.result as string); - setImage(this.result as string); + function onImageChange(image: string) { + setImagePreview(image); } - ImageUtils.addPasteImageHook(onImageLoad); - - useEffect(() => { - var newQueryableScrapers : GQL.ListPerformerScrapersListPerformerScrapers[] = []; - - if (!!Scrapers.data && Scrapers.data.listPerformerScrapers) { - newQueryableScrapers = Scrapers.data.listPerformerScrapers.filter((s) => { - return s.performer && s.performer.supported_scrapes.includes(GQL.ScrapeType.Name); - }); - } - - setQueryableScrapers(newQueryableScrapers); - - }, [Scrapers.data]); - - if ((!isNew && !isEditing && (!data || !data.findPerformer)) || isLoading) { + if ((!isNew && (!data || !data.findPerformer)) || isLoading) { return ; } if (!!error) { return <>error...; } - function getPerformerInput() { - const performerInput: Partial = { - name, - aliases, - favorite, - birthdate, - ethnicity, - country, - eye_color: eyeColor, - height, - measurements, - fake_tits: fakeTits, - career_length: careerLength, - tattoos, - piercings, - url, - twitter, - instagram, - image, - }; - - if (!isNew) { - (performerInput as GQL.PerformerUpdateInput).id = props.match.params.id; - } - return performerInput; - } - - async function onSave() { + async function onSave(performer : Partial | Partial) { setIsLoading(true); try { if (!isNew) { - const result = await updatePerformer(); + const result = await updatePerformer({variables: performer as GQL.PerformerUpdateInput}); setPerformer(result.data.performerUpdate); } else { - const result = await createPerformer(); + const result = await createPerformer({variables: performer as GQL.PerformerCreateInput}); setPerformer(result.data.performerCreate); props.history.push(`/performers/${result.data.performerCreate.id}`); } @@ -172,7 +75,7 @@ export const Performer: FunctionComponent = (props: IPerformerP async function onDelete() { setIsLoading(true); try { - const result = await deletePerformer(); + await deletePerformer({variables: {id: props.match.params.id}}); } catch (e) { ErrorUtils.handle(e); } @@ -182,214 +85,164 @@ export const Performer: FunctionComponent = (props: IPerformerP props.history.push(`/performers`); } - async function onAutoTag() { - if (!performer || !performer.id) { - return; + function renderTabs() { + function renderEditPanel() { + return ( + + ); } - try { - await StashService.queryMetadataAutoTag({ performers: [performer.id]}); - ToastUtils.success("Started auto tagging"); - } catch (e) { - ErrorUtils.handle(e); + + // render tabs if not new + if (!isNew) { + return ( + <> + + } /> + } /> + + } /> + + + ); + } else { + return renderEditPanel(); } } - function onImageChange(event: React.FormEvent) { - ImageUtils.onImageChange(event, onImageLoad); - } - - function onDisplayFreeOnesDialog(scraper: GQL.ListPerformerScrapersListPerformerScrapers) { - setIsDisplayingScraperDialog(scraper); - } - - function getQueryScraperPerformerInput() { - if (!scrapePerformerDetails) { - return {}; - } - - let ret = _.clone(scrapePerformerDetails); - delete ret.__typename; - return ret as GQL.ScrapedPerformerInput; - } - - async function onScrapePerformer() { - setIsDisplayingScraperDialog(undefined); - setIsLoading(true); - try { - if (!scrapePerformerDetails || !isDisplayingScraperDialog) { return; } - const result = await StashService.queryScrapePerformer(isDisplayingScraperDialog.id, getQueryScraperPerformerInput()); - if (!result.data || !result.data.scrapePerformer) { return; } - updatePerformerEditState(result.data.scrapePerformer); - } catch (e) { - ErrorUtils.handle(e); - } - setIsLoading(false); - } - - async function onScrapePerformerURL() { - if (!url) { return; } - setIsLoading(true); - try { - const result = await StashService.queryScrapePerformerURL(url); - if (!result.data || !result.data.scrapePerformerURL) { return; } - - // leave URL as is if not set explicitly - if (!result.data.scrapePerformerURL.url) { - result.data.scrapePerformerURL.url = url; - } - updatePerformerEditState(result.data.scrapePerformerURL); - } catch (e) { - ErrorUtils.handle(e); - } finally { - setIsLoading(false); - } - } - - function renderEthnicity() { - return TableUtils.renderHtmlSelect({ - title: "Ethnicity", - value: ethnicity, - isEditing, - onChange: (value: string) => setEthnicity(value), - selectOptions: ["white", "black", "asian", "hispanic"], - }); - } - - function renderScraperDialog() { - return ( - setIsDisplayingScraperDialog(undefined)} - title="Scrape" - > -
- setScrapePerformerDetails(query)} - /> -
-
-
- + function maybeRenderAge() { + if (performer && performer.birthdate) { + // calculate the age from birthdate. In future, this should probably be + // provided by the server + return ( + <> +
+ {TextUtils.age(performer.birthdate)} + years old
-
-
- ); - } - - function urlScrapable(url: string) : boolean { - return !!url && !!Scrapers.data && Scrapers.data.listPerformerScrapers && Scrapers.data.listPerformerScrapers.some((s) => { - return !!s.performer && !!s.performer.urls && s.performer.urls.some((u) => { return url.includes(u); }); - }); - } - - function maybeRenderScrapeButton() { - if (!url || !isEditing || !urlScrapable(url)) { - return undefined; + + ); } - return ( - + + + + ); + } + + function urlScrapable(url: string) : boolean { + return !!url && !!Scrapers.data && Scrapers.data.listPerformerScrapers && Scrapers.data.listPerformerScrapers.some((s) => { + return !!s.performer && !!s.performer.urls && s.performer.urls.some((u) => { return url.includes(u); }); + }); + } + + function maybeRenderScrapeButton() { + if (!url || !props.isEditing || !urlScrapable(url)) { + return undefined; + } + return ( +