import { CategoryPreview } from "$components/CategoryPreview/CategoryPreview"; import { CategorySearchItem } from "$components/CategorySearchItem/CategorySearchItem"; import { DefaultSearchItem } from "$components/DefaultSearchItem/DefaultSearchItem"; import * as React from "react"; import memoizeOne from "memoize-one"; import { debounce, isEmpty } from "lodash/fp"; // TODO: decide whether to use lodash/fp or normal import { Component } from "react"; import styled from "react-emotion"; import { FilteringHandler } from "./FilteringHandler"; import { NestedInputTagsProps, NestedInputTagsState } from "./NestedInputTags.types"; import { TagInput } from "$components/TagInput/TagInput"; import { SelectBox } from "$components/SelectBox/SelectBox"; import { Option, getOptionKey } from "$components/Option/Option"; import { OptionMode } from "$components/Option/Option.types"; import { Option as OptionType } from "$lib-core-types/Option.types"; import { OptionDetails } from "$lib-core-types/OptionDetails.types"; import { OptionsDetailsCache } from "./OptionsDetailsCache"; import { toDetails } from "$utils/toDetails"; import { toOptionsWithParents } from "$utils/toOptionsWithPartens"; import { NITContext } from "./NITContext"; import { getDetailFromInitialValues } from "$utils/toDetails"; import { FlatOption } from "$components/FlatOption/FlatOption"; const Body = styled("div")` width: 100%; position: relative; display: inline-block; & * { box-sizing: border-box; } `; const getPristineState = (options: OptionDetails[] = []) => ({ currentSearchStr: null, currentFilterStr: null, currentOptions: options, displayMode: OptionMode.Full }); const getIdleState = () => ({ // TODO: add box opening selectBoxVisible: false, currentSearchStr: null, currentFilterStr: null, currentOptions: null, displayMode: OptionMode.Full }); export class NestedInputTags extends Component< NestedInputTagsProps, NestedInputTagsState > { state = { // TODO: add box opening selectBoxVisible: false, currentSearchStr: null, currentFilterStr: null, currentOptions: null, displayMode: OptionMode.Full }; filteringHandler = new FilteringHandler(); //TODO: rename this item detailsCache: OptionsDetailsCache; bodyRef: any; selectBoxRef: any; constructor(props: NestedInputTagsProps) { super(props); const { options, initialValues } = props; this.detailsCache = new OptionsDetailsCache(); if (initialValues) { const getOptionDetail = getDetailFromInitialValues(options); const details = initialValues.map(getOptionDetail); details.forEach(detail => this.detailsCache.add(detail)); } } componentDidMount() { document.addEventListener("mousedown", this.onDocumentMouseDown); } // TODO: move to mapPropsToState UNSAFE_componentWillReceiveProps({ options: nextOptions }: NestedInputTagsProps) { const { options } = this.props; if (nextOptions !== options) { this.detailsCache = new OptionsDetailsCache(); this.setState(getIdleState()); } } componentWillUnmount() { document.removeEventListener("mousedown", this.onDocumentMouseDown); } getInitialOptions() { const { options } = this.props; return this.toOptionsDetails(options); } toOptionsDetails = memoizeOne((options: OptionType[]) => options.map(option => toDetails(option)) ); prepareOptions(optionsDetails: OptionDetails[], categories: string[]) { const { displayMode } = this.state; const { isFlat } = this.props; const flatOptions = this.detailsCache.selectedOptions.get("") || { optionsDetails: [] as OptionDetails[] }; const flatOptionsIds = flatOptions.optionsDetails.map( ({ option: { id } }) => id ); return displayMode === OptionMode.Short ? this.prepareSearchItems(optionsDetails, categories) : optionsDetails.map(details => { const { option: { allowAny, categoryPreview, label } } = details; if (categoryPreview) { return ( ); } else if (!isFlat) { return (