import React, { useState } from "react"; import { Form, Col, Row, InputGroup, Button, FormControl, Badge, } from "react-bootstrap"; import { CollapseButton } from "../CollapseButton"; import { Icon } from "../Icon"; import { ModalComponent } from "../Modal"; import clone from "lodash-es/clone"; import { FormattedMessage, useIntl } from "react-intl"; import { faCheck, faPencilAlt, faPlus, faTimes, } from "@fortawesome/free-solid-svg-icons"; import { getCountryByISO } from "src/utils/country"; import { CountrySelect } from "../CountrySelect"; import { StringListInput } from "../StringListInput"; import { ImageSelector } from "../ImageSelector"; import { ScrapeResult } from "./scrapeResult"; export interface IHasName { name: string | undefined; } interface IScrapedFieldProps { result: ScrapeResult; } interface IScrapedRowProps extends IScrapedFieldProps { className?: string; title: string; renderOriginalField: (result: ScrapeResult) => JSX.Element | undefined; renderNewField: (result: ScrapeResult) => JSX.Element | undefined; onChange: (value: ScrapeResult) => void; newValues?: V[]; onCreateNew?: (index: number) => void; } function renderButtonIcon(selected: boolean) { const className = selected ? "text-success" : "text-muted"; return ( ); } export const ScrapeDialogRow = ( props: IScrapedRowProps ) => { function handleSelectClick(isNew: boolean) { const ret = clone(props.result); ret.useNewValue = isNew; props.onChange(ret); } function hasNewValues() { return props.newValues && props.newValues.length > 0 && props.onCreateNew; } if (!props.result.scraped && !hasNewValues()) { return <>; } function renderNewValues() { if (!hasNewValues()) { return; } const ret = ( <> {props.newValues!.map((t, i) => ( props.onCreateNew!(i)} > {t.name} ))} ); const minCollapseLength = 10; if (props.newValues!.length >= minCollapseLength) { return ( {ret} ); } return ret; } return ( {props.title} {props.renderOriginalField(props.result)} {props.renderNewField(props.result)} {renderNewValues()} ); }; interface IScrapedInputGroupProps { isNew?: boolean; placeholder?: string; locked?: boolean; result: ScrapeResult; onChange?: (value: string) => void; } const ScrapedInputGroup: React.FC = (props) => { return ( { if (props.isNew && props.onChange) { props.onChange(e.target.value); } }} className="bg-secondary text-white border-secondary" /> ); }; interface IScrapedInputGroupRowProps { title: string; placeholder?: string; result: ScrapeResult; locked?: boolean; onChange: (value: ScrapeResult) => void; } export const ScrapedInputGroupRow: React.FC = ( props ) => { return ( ( )} renderNewField={() => ( props.onChange(props.result.cloneWithValue(value)) } /> )} onChange={props.onChange} /> ); }; interface IScrapedStringListProps { isNew?: boolean; placeholder?: string; locked?: boolean; result: ScrapeResult; onChange?: (value: string[]) => void; } const ScrapedStringList: React.FC = (props) => { const value = props.isNew ? props.result.newValue : props.result.originalValue; return ( { if (props.isNew && props.onChange) { props.onChange(v); } }} placeholder={props.placeholder} readOnly={!props.isNew || props.locked} /> ); }; interface IScrapedStringListRowProps { title: string; placeholder?: string; result: ScrapeResult; locked?: boolean; onChange: (value: ScrapeResult) => void; } export const ScrapedStringListRow: React.FC = ( props ) => { return ( ( )} renderNewField={() => ( props.onChange(props.result.cloneWithValue(value)) } /> )} onChange={props.onChange} /> ); }; const ScrapedTextArea: React.FC = (props) => { return ( { if (props.isNew && props.onChange) { props.onChange(e.target.value); } }} className="bg-secondary text-white border-secondary scene-description" /> ); }; export const ScrapedTextAreaRow: React.FC = ( props ) => { return ( ( )} renderNewField={() => ( props.onChange(props.result.cloneWithValue(value)) } /> )} onChange={props.onChange} /> ); }; interface IScrapedImageProps { isNew?: boolean; className?: string; placeholder?: string; result: ScrapeResult; } const ScrapedImage: React.FC = (props) => { const value = props.isNew ? props.result.newValue : props.result.originalValue; if (!value) { return <>; } return ( {props.placeholder} ); }; interface IScrapedImageRowProps { title: string; className?: string; result: ScrapeResult; onChange: (value: ScrapeResult) => void; } export const ScrapedImageRow: React.FC = (props) => { return ( ( )} renderNewField={() => ( )} onChange={props.onChange} /> ); }; interface IScrapedImagesRowProps { title: string; className?: string; result: ScrapeResult; images: string[]; onChange: (value: ScrapeResult) => void; } export const ScrapedImagesRow: React.FC = (props) => { const [imageIndex, setImageIndex] = useState(0); function onSetImageIndex(newIdx: number) { const ret = props.result.cloneWithValue(props.images[newIdx]); props.onChange(ret); setImageIndex(newIdx); } return ( ( )} renderNewField={() => (
)} onChange={props.onChange} /> ); }; interface IScrapeDialogProps { title: string; existingLabel?: string; scrapedLabel?: string; renderScrapeRows: () => JSX.Element; onClose: (apply?: boolean) => void; } export const ScrapeDialog: React.FC = ( props: IScrapeDialogProps ) => { const intl = useIntl(); return ( { props.onClose(true); }, text: intl.formatMessage({ id: "actions.apply" }), }} cancel={{ onClick: () => props.onClose(), text: intl.formatMessage({ id: "actions.cancel" }), variant: "secondary", }} modalProps={{ size: "lg", dialogClassName: "scrape-dialog" }} >
{props.existingLabel ?? ( )} {props.scrapedLabel ?? ( )} {props.renderScrapeRows()}
); }; interface IScrapedCountryRowProps { title: string; result: ScrapeResult; onChange: (value: ScrapeResult) => void; locked?: boolean; locale?: string; } export const ScrapedCountryRow: React.FC = ({ title, result, onChange, locked, locale, }) => ( ( )} renderNewField={() => ( { if (onChange) { onChange(result.cloneWithValue(value)); } }} showFlag={false} isClearable={false} className="flex-grow-1" /> )} onChange={onChange} /> );