import React, { useEffect, useState } from "react"; import { Button, Form, Col, Row } from "react-bootstrap"; import { FormattedMessage, useIntl } from "react-intl"; import Mousetrap from "mousetrap"; import * as GQL from "src/core/generated-graphql"; import * as yup from "yup"; import { TagSelect, StudioSelect } from "src/components/Shared/Select"; import { LoadingIndicator } from "src/components/Shared/LoadingIndicator"; import { useToast } from "src/hooks/Toast"; import { useFormik } from "formik"; import { Prompt } from "react-router-dom"; import { useRatingKeybinds } from "src/hooks/keybinds"; import { ConfigurationContext } from "src/hooks/Config"; import isEqual from "lodash-es/isEqual"; import { yupDateString, yupFormikValidate, yupUniqueStringList, } from "src/utils/yup"; import { Performer, PerformerSelect, } from "src/components/Performers/PerformerSelect"; import { formikUtils } from "src/utils/form"; interface IProps { image: GQL.ImageDataFragment; isVisible: boolean; onSubmit: (input: GQL.ImageUpdateInput) => Promise; onDelete: () => void; } export const ImageEditPanel: React.FC = ({ image, isVisible, onSubmit, onDelete, }) => { const intl = useIntl(); const Toast = useToast(); // Network state const [isLoading, setIsLoading] = useState(false); const { configuration } = React.useContext(ConfigurationContext); const [performers, setPerformers] = useState([]); const schema = yup.object({ title: yup.string().ensure(), code: yup.string().ensure(), urls: yupUniqueStringList(intl), date: yupDateString(intl), details: yup.string().ensure(), photographer: yup.string().ensure(), rating100: yup.number().integer().nullable().defined(), studio_id: yup.string().required().nullable(), performer_ids: yup.array(yup.string().required()).defined(), tag_ids: yup.array(yup.string().required()).defined(), }); const initialValues = { title: image.title ?? "", code: image.code ?? "", urls: image?.urls ?? [], date: image?.date ?? "", details: image.details ?? "", photographer: image.photographer ?? "", rating100: image.rating100 ?? null, studio_id: image.studio?.id ?? null, performer_ids: (image.performers ?? []).map((p) => p.id), tag_ids: (image.tags ?? []).map((t) => t.id), }; type InputValues = yup.InferType; const formik = useFormik({ initialValues, enableReinitialize: true, validate: yupFormikValidate(schema), onSubmit: (values) => onSave(schema.cast(values)), }); function setRating(v: number) { formik.setFieldValue("rating100", v); } function onSetPerformers(items: Performer[]) { setPerformers(items); formik.setFieldValue( "performer_ids", items.map((item) => item.id) ); } useRatingKeybinds( true, configuration?.ui?.ratingSystemOptions?.type, setRating ); useEffect(() => { setPerformers(image.performers ?? []); }, [image.performers]); useEffect(() => { if (isVisible) { Mousetrap.bind("s s", () => { if (formik.dirty) { formik.submitForm(); } }); Mousetrap.bind("d d", () => { onDelete(); }); return () => { Mousetrap.unbind("s s"); Mousetrap.unbind("d d"); }; } }); async function onSave(input: InputValues) { setIsLoading(true); try { await onSubmit({ id: image.id, ...input, }); formik.resetForm(); } catch (e) { Toast.error(e); } setIsLoading(false); } if (isLoading) return ; const splitProps = { labelProps: { column: true, sm: 3, }, fieldProps: { sm: 9, }, }; const fullWidthProps = { labelProps: { column: true, sm: 3, xl: 12, }, fieldProps: { sm: 9, xl: 12, }, }; const { renderField, renderInputField, renderDateField, renderRatingField, renderURLListField, } = formikUtils(intl, formik, splitProps); function renderStudioField() { const title = intl.formatMessage({ id: "studio" }); const control = ( formik.setFieldValue( "studio_id", items.length > 0 ? items[0]?.id : null ) } ids={formik.values.studio_id ? [formik.values.studio_id] : []} /> ); return renderField("studio_id", title, control); } function renderPerformersField() { const title = intl.formatMessage({ id: "performers" }); const control = ( ); return renderField("performer_ids", title, control, fullWidthProps); } function renderTagsField() { const title = intl.formatMessage({ id: "tags" }); const control = ( formik.setFieldValue( "tag_ids", items.map((item) => item.id) ) } ids={formik.values.tag_ids} hoverPlacement="right" /> ); return renderField("tag_ids", title, control, fullWidthProps); } function renderDetailsField() { const props = { labelProps: { column: true, sm: 3, lg: 12, }, fieldProps: { sm: 9, lg: 12, }, }; return renderInputField("details", "textarea", "details", props); } return (
{renderInputField("title")} {renderInputField("code", "text", "scene_code")} {renderURLListField("urls")} {renderDateField("date")} {renderInputField("photographer")} {renderRatingField("rating100", "rating")} {renderStudioField()} {renderPerformersField()} {renderTagsField()} {renderDetailsField()}
); };