import React, { ChangeEvent, useEffect, useLayoutEffect, useRef, useState, } from "react"; import { AttachCreatedFile, IDisplayComponentRef } from "./DisplayComponent"; import { Components, PropNames } from "./Components"; import { ComponentTitle, Container, GridItem, Label, TextInput, WideGridItem, WideTextInput, WideTextArea, } from "./EditComponents"; import Repository from "../../common/repository/repository"; import config from "../../config.json"; import { ColorSelector } from "./ColorSelector"; import { AssetType, IAsset, IDirection, IObjectFit, ITemperatureType, IAnimatedDrmDotPosition, AssetNames, } from "../../digital_assets_management/interfaces/IAsset"; import { useTranslations } from "../../i18n/useTranslations"; import { Input } from "reactstrap"; import { ThumbnailModal } from "../../common/components/ThumbnailModal"; import * as Constants from "../constants/component-constants"; import * as Global_Constants from "../../common/constants/shared-constants"; import * as Property_Constants from "../../common/constants/property-constants"; interface IComponentProps { component: IDisplayComponentRef | null; configuration: any; onValueChanged: (x: number, y: number, width: number, height: number) => void; onDeleteComponent?: (c: string) => void; onDuplicateComponent?: (c: IDisplayComponentRef) => void; } export const ComponentPropertyBar = ({ component, configuration, onValueChanged, onDeleteComponent, onDuplicateComponent, }: IComponentProps) => { const [checked, setChecked] = useState(true); const [isPlaying, setIsPlaying] = useState(false); const [align, setAlign] = useState(""); const [extraProps, setExtraProps] = useState( {} as { [key: string]: any | number | boolean } ); const refX = useRef<any>(); const refY = useRef<any>(); const refW = useRef<any>(); const refH = useRef<any>(); const i18n = useTranslations(); const [createdFile, setCreatedFile] = useState({ name: "", fileptr: Global_Constants.NOT_A_FP, } as AttachCreatedFile); const [styleAssets, setStyleAssets] = useState<IAsset[]>([]); const [arrowImage, setArrowImage] = useState<string | undefined>(undefined); const [imageAssets, setImageAssets] = useState<IAsset[]>([]); const [videoAssets, setVideoAssets] = useState<IAsset[]>([]); const [multiTextChecked, setMultiTextChecked] = useState(false); const [direction, setDirection] = useState<string>("left"); const directionOptional = useRef([ IDirection.LEFT, IDirection.RIGHT, IDirection.UP, IDirection.DOWN, ]); const [fitObject, setFitObject] = useState<string>(); const objectsFitOptions = useRef([ IObjectFit.CONTAIN, IObjectFit.COVER, IObjectFit.fill, ]); const [, setTempartureType] = useState(); const tempartureTypesOptions = useRef([ ITemperatureType.CELSIUS, ITemperatureType.FAHRENHEIT, ]); const [temperatureUnit, setTemperatureUnit] = useState<string>(); const [ddrInputEvents, setDDRInputEvents] = useState<string>(); const [animatedDrmDotOptionValue, setAnimatedDrmDotOptionValue] = useState("default"); const animatedDrmDotPosition = useRef([ IAnimatedDrmDotPosition.DEFAULT, IAnimatedDrmDotPosition.UPPER, IAnimatedDrmDotPosition.LOWER, IAnimatedDrmDotPosition.ZIGZAG, ]); const [showImageModal, setShowImageModal] = useState(false); const openImageModal = () => { setShowImageModal(true); }; const closeImageModal = () => { setShowImageModal(false); }; const [searchQuery, setSearchQuery] = useState(""); const [numStations, setNumStations] = useState(2); // Default number of stations const [numberofArrows, setArrowIndex] = useState(0); const [fontOptions, setFontOptions] = useState([]); const [selectedFont, setSelectedFont] = useState(""); const dataChanged = () => { const bounds = component!.getBounds(); let x = parseInt(refX.current!.value); x = isNaN(x) ? bounds.x : x; let y = parseInt(refY.current!.value); y = isNaN(y) ? bounds.y : y; let width = parseInt(refW.current!.value); width = isNaN(width) ? bounds.width : width; let height = parseInt(refH.current!.value); height = isNaN(height) ? bounds.height : height; onValueChanged(x, y, width, height); }; useEffect(() => { if (extraProps.direction) { setDirection(extraProps.direction.toString()); } else { setDirection("left"); } }, [extraProps.direction]); useEffect(() => { setExtraProps({}); if (!component) return; const bounds = component.getBounds(); setValue(refX.current!, Math.round(bounds.x)); setValue(refY.current!, Math.round(bounds.y)); setValue(refW.current!, Math.round(bounds.width)); setValue(refH.current!, Math.round(bounds.height)); const props = component.getExtraProps(); if (props) { setExtraProps(props); setChecked(props[Property_Constants.IS_ANIMATED]); setAlign(props[Property_Constants.ALIGNMENT]); setIsPlaying(props[Property_Constants.IS_PLAYING]); setMultiTextChecked(props[Constants.MULTI_LINE_TEXT]); setFitObject(props[Constants.OBJECT_FIT]); setTempartureType(props[Property_Constants.TEMPERATURE_TYPE]); setDDRInputEvents(props[Property_Constants.DDR_EVENTS]); setNumStations(props[Property_Constants.NUM_STATIONS]); setArrowIndex(props[Property_Constants.NUMBER_OF_ARROWS]); } const attachedFile = component.getCreatedFile(); if (attachedFile) { setCreatedFile(attachedFile); } }, [component]); useEffect(() => { const retreiveAssets = async () => { const styleAssets = ( await Repository.getInstance().getAssets(0, 0, "", AssetType.Style) ).items; setStyleAssets(styleAssets); const imageAssets = ( await Repository.getInstance().getAssets(0, 0, "", AssetType.Image) ).items; setImageAssets(imageAssets); const videoAssets = ( await Repository.getInstance().getAssets(0, 0, "", AssetType.Video) ).items; setVideoAssets(videoAssets); }; retreiveAssets(); }, []); const setValue = (el: HTMLInputElement, value: number) => { el.value = value.toString(); }; const animateChanged = (t: HTMLInputElement) => { const newValue = t.checked; setChecked(newValue); const props = { ...extraProps, isAnimated: newValue }; setExtraProps(props); component!.setExtraProps(props); }; const multiLineChanged = (t: HTMLInputElement) => { const newValue = t.checked; setMultiTextChecked(newValue); const props = { ...extraProps, multiLineText: newValue }; setExtraProps(props); component!.setExtraProps(props); }; const changeAnimationDirection = (t: React.ChangeEvent<HTMLInputElement>) => { const newValue = t.target.value; setDirection(newValue); const props = { ...extraProps, direction: newValue }; setExtraProps(props); component!.setExtraProps(props); }; const handleTemperatureChange = (t: React.ChangeEvent<HTMLInputElement>) => { const newValue = t.target.value; const props = { ...extraProps, temperatureScales: newValue }; setTemperatureUnit(newValue); setExtraProps(props); component!.setExtraProps(props); }; const handleDotOptionChange = (t: React.ChangeEvent<HTMLInputElement>) => { const newValue = t.target.value; setAnimatedDrmDotOptionValue(newValue); const props = { ...extraProps, animatedDrmDotOptionValue: newValue }; setExtraProps(props); component!.setExtraProps(props); }; const handleFileUploadChange = ( event: React.ChangeEvent<HTMLInputElement> ) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const uploadedFile = e.target?.result as string; // Set uploaded file as background image setArrowImage(uploadedFile); }; reader.readAsDataURL(file); } }; const changeProp = ( propName: string, propValue: string | number | boolean ) => { const currentValue = extraProps[propName]; if (currentValue !== propValue) { const props = { ...extraProps, [propName]: propValue }; setExtraProps(props); component!.setExtraProps(props); } }; const propChanged = (e: ChangeEvent<HTMLInputElement>) => { const propName = e.target.id.toString().substring(5); const newValue = typeof extraProps[propName] === "number" ? +e.target.value : typeof extraProps[propName] === "boolean" ? e.target.checked : e.target.value; changeProp(propName, newValue); }; const propChangedForTextarea = (e: ChangeEvent<HTMLTextAreaElement>) => { const propName = e.target.id.toString().substring(5); const newValue = e.target.value; changeProp(propName, newValue); }; const alignChanged = (e: ChangeEvent<HTMLInputElement>) => { const propName = e.target.id.toString().split("-")[1]; const newValue = e.target.value; setAlign(newValue); changeProp(propName, newValue); }; const changeInputDDREventState = (e: React.ChangeEvent<HTMLInputElement>) => { const ddrValue = e.target.value; const props = { ...extraProps, ddrEvents: ddrValue }; setDDRInputEvents(ddrValue); setExtraProps(props); component!.setExtraProps(props); }; const changeComponetObjectFit = (e: React.ChangeEvent<HTMLInputElement>) => { const targetValue = e.target.value; const props = { ...extraProps, objectFit: targetValue }; setFitObject(targetValue); setExtraProps(props); component!.setExtraProps(props); }; const handleStationChange = (e: React.ChangeEvent<HTMLInputElement>) => { // const newNumStations = +e.target.value; const newNumStations = parseInt(e.target.value); setNumStations(newNumStations); // Ensure arrow index doesn't exceed the number of stations setArrowIndex(Math.min(numberofArrows, newNumStations - 1)); const props = { ...extraProps, numStations: newNumStations }; setExtraProps(props); component!.setExtraProps(props); }; const handleArrowChange = (e: React.ChangeEvent<HTMLInputElement>) => { const newArrowIndex = Number(e.target.value); setArrowIndex(Math.max(0, Math.min(newArrowIndex, numStations - 1))); const props = { ...extraProps, numberofArrows: newArrowIndex }; setExtraProps(props); component!.setExtraProps(props); }; const changeComponentAssetSelector = ( e: React.ChangeEvent<HTMLInputElement>, assetType: string | undefined ) => { let createdFile = { name: "", fileptr: Global_Constants.NOT_A_FP, } as AttachCreatedFile; let props = extraProps; if (e.target.value === Global_Constants.NOT_A_FP) { setCreatedFile(createdFile); return; } if (assetType === AssetType.Style) { const asset = styleAssets?.find((v) => v.file_pointer === e.target.value); if (!asset) return; props = { ...props, style: asset?.infoJson ?? "{}" }; createdFile = { name: asset.name, fileptr: asset.file_pointer, } as AttachCreatedFile; } else { const asset = assetType === AssetType.Image ? imageAssets?.find((v) => v.file_pointer === e.target.value) : videoAssets?.find((v) => v.file_pointer === e.target.value); if (!asset) return; props = { ...extraProps, src: `${config.assetsUrl}/${asset.file_pointer}`, source: asset.name, }; createdFile = { name: asset.name, fileptr: asset.file_pointer, } as AttachCreatedFile; if (assetType === AssetType.Video) { const bounds = component!.getBounds(); const newSize = JSON.parse(asset.infoJson); component!.setBounds({ ...bounds, width: newSize["width"], height: newSize["height"], }); } } setExtraProps(props); component!.setExtraProps(props); setCreatedFile(createdFile); component!.setCreatedFile(createdFile); }; function updateMultilanguage(locale: string, duration: any) { let multiLanguage = JSON.parse( String(extraProps[Property_Constants.MULTI_LANGUAGE]) ); multiLanguage = { ...multiLanguage, [locale]: { ...multiLanguage[locale], duration: duration }, }; return multiLanguage; } const handleMultilingualCheckboxChange = ( e: any, localecode: string, sampleMessage: string ) => { const sortedLocales = [...configuration.medialocales.locales].sort( (a, b) => a.order - b.order ); const allLocales = sortedLocales.map((item: any) => item.localecode); let multiLanguage = JSON.parse( String(extraProps[Property_Constants.MULTI_LANGUAGE]) ); const currentLocaleIndex = allLocales.indexOf(localecode); for ( let index = currentLocaleIndex + 1; index < allLocales.length; index++ ) { const nextLocale = allLocales[index]; if (!e.target.checked) { if (multiLanguage[nextLocale].checked) { const nextLocaleDuration = parseInt(multiLanguage[nextLocale][Property_Constants.DURATION]) + parseInt(multiLanguage[localecode][Property_Constants.DURATION]); multiLanguage = updateMultilanguage(nextLocale, nextLocaleDuration); break; } } else { if (multiLanguage[nextLocale].checked) { let nextLocaleDuration = parseInt(multiLanguage[nextLocale][Property_Constants.DURATION]) - parseInt(multiLanguage[localecode][Property_Constants.DURATION]); nextLocaleDuration = Math.max(nextLocaleDuration, 0); multiLanguage = updateMultilanguage(nextLocale, nextLocaleDuration); break; } } } multiLanguage = { ...multiLanguage, [localecode]: { ...multiLanguage[localecode], id: localecode, sampleText: sampleMessage, checked: e.target.checked, }, }; const props = { ...extraProps, [Property_Constants.MULTI_LANGUAGE]: JSON.stringify(multiLanguage), }; setExtraProps(props); component!.setExtraProps(props); }; const handleDurationsInputChange = ( event: React.ChangeEvent<HTMLInputElement>, locale: string ) => { const { value } = event.target; const multiLanguage = updateMultilanguage(locale, value); const props = { ...extraProps, [Property_Constants.MULTI_LANGUAGE]: JSON.stringify(multiLanguage), }; setExtraProps(props); component!.setExtraProps(props); }; const onMultilanguageTextChanged = (e: ChangeEvent<HTMLTextAreaElement>) => { const propName = e.target.id.toString().split("-")[1]; const newValue = e.target.value; let multiLanguage = JSON.parse( String(extraProps[Property_Constants.MULTI_LANGUAGE]) ); multiLanguage = { ...multiLanguage, [propName]: { id: propName, sampleText: newValue, checked: true, duration: multiLanguage[propName][Property_Constants.DURATION], }, }; const props = { ...extraProps, [Property_Constants.MULTI_LANGUAGE]: JSON.stringify(multiLanguage), }; setExtraProps(props); component!.setExtraProps(props); }; const toProperCase = (s: string) => s.charAt(0).toUpperCase() + s.slice(1); const playPause = () => { const newValue = !isPlaying; setIsPlaying(newValue); changeProp(Property_Constants.IS_PLAYING, newValue); document .getElementById("icon-play")! .setAttribute("class", `fa fa-fw ${newValue ? "fa-pause" : "fa-play"}`); }; const hiddenProps = [ Property_Constants.SOURCE, Property_Constants.SRC, Property_Constants.IS_PLAYING, Constants.MULTI_LINE_TEXT, Constants.OBJECT_FIT, Property_Constants.TEMPERATURE_SCALES, Property_Constants.INPUT_BOX, ]; const radioChanged = () => { // }; const alignmentInput = (p: string, propId: string): JSX.Element => { return ( <WideGridItem className="px-2" key={p}> <label> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </label> <div onChange={alignChanged} className="d-flex justify-content-between"> <div> <input type="radio" id={propId + "-left"} value="left" checked={align === "left"} onChange={radioChanged} /> <i className="fa fa-align-left mx-1" /> </div> <div> <input type="radio" id={propId + "-center"} value="center" checked={align === "center"} onChange={radioChanged} /> <i className="fa fa-align-center mx-1" /> </div> <div> <input type="radio" id={propId + "-right"} value="right" checked={align === "right"} onChange={radioChanged} /> <i className="fa fa-align-right mx-1" /> </div> </div> </WideGridItem> ); }; const styleInput = (p: string, propId: string): JSX.Element => ( <WideGridItem key="style"> <Label htmlFor="prop-source" accessKey="s"> {i18n(Global_Constants.GLOBAL, Global_Constants.STYLE)} </Label> <Input type="select" value={createdFile.fileptr} onChange={(e) => changeComponentAssetSelector(e, AssetType.Style)} id="comp-text-style-sel" name="comp-text-style-sel" title="Text Style selector" className="comp-textStyle-select" > <option value="_not_a_fp__" key="non_comp-text-style-id"> {i18n(Global_Constants.SCENE_LOCALES, Constants.CHOOSE_STYLE)} </option> {styleAssets?.map((sa) => ( <option key={`comp-text-style-id-${sa.file_pointer}`} value={sa.file_pointer} > {sa.name} </option> ))} </Input> </WideGridItem> ); const DynamicField = (p: string) => { const renderFields = () => { const sortedLocales = [...configuration.medialocales.locales].sort( (a, b) => a.order - b.order ); const multiLanguageText = JSON.parse(String(extraProps[p])); const inputBox = Boolean(extraProps.inputBox); const fields = sortedLocales.map((item: any) => { const { title, sampleText, localecode } = item; const languageTextObj = multiLanguageText && multiLanguageText[localecode] ? multiLanguageText[localecode] : { id: localecode, sampleText: sampleText, checked: true, duration: "4", }; if (!multiLanguageText[localecode]) { multiLanguageText[localecode] = languageTextObj; const props = { ...extraProps, [p]: JSON.stringify(multiLanguageText), }; setExtraProps(props); component!.setExtraProps(props); } return getInputWithCheckboxComponent( `${p}-${localecode}`, `multilanguage-${localecode}`, multiLanguageText[localecode].sampleText, onMultilanguageTextChanged, null, multiLanguageText[localecode].checked, title, inputBox, multiLanguageText[localecode].duration ); }); return fields; }; return <>{renderFields()}</>; }; const handleDropdownChange = ( e: React.ChangeEvent<HTMLInputElement>, component: any, p: string, index: number ) => { const newValue = e.target.value; const updatedDropdown = extraProps.dropdown.map( (dropdownItem: any, idx: number) => { if (idx === index) { return { ...dropdownItem, selectedValue: newValue }; } return dropdownItem; } ); const props = { ...extraProps, dropdown: updatedDropdown, }; setExtraProps(props); component!.setExtraProps(props); }; const createDropdown = (p: string, component: any) => { const renderFields = () => { if (!Array.isArray(extraProps.dropdown)) { return null; } return extraProps.dropdown.map((dropdownItem: any, index: number) => { const dropdownData: any = Components[component.componentType].properties?.[dropdownItem.name]; const dropdownOptions = dropdownData?.options || []; const selectedValue = dropdownItem.selectedValue; return ( <WideGridItem key={index}> <Label htmlFor={`${component.componentType}${dropdownItem.name}Dropdown`} > {i18n(Global_Constants.SCENE_LOCALES, dropdownItem.name)} </Label> <Input type="select" onChange={(e) => handleDropdownChange(e, component, p, index)} className="animation-direction text-capitalize" value={selectedValue} > {dropdownOptions.map((value: any, idx: number) => ( <option key={idx} value={value}> {value} </option> ))} </Input> </WideGridItem> ); }); }; return <>{renderFields()}</>; }; const getInputWithCheckboxComponent = ( pElementkey: string, propId: string, inputValue: string, onChangeHandler: any, numberProps: any, isChecked: boolean, label: string, inputBox: boolean, duration: any ) => { return ( <WideGridItem key={pElementkey}> <Label htmlFor={propId} accessKey={PropNames[pElementkey]?.accessKey}> {label ? label : i18n( Global_Constants.SCENE_LOCALES, PropNames[pElementkey]?.displayText ) ?? toProperCase(pElementkey)} <input className="check-multilang" id={propId} key={`checkbox-${propId}`} checked={isChecked} onChange={(e) => handleMultilingualCheckboxChange( e, propId.split("-")[1], inputValue ) } type="checkbox" /> {inputBox && ( <input type="number" id={`text-${propId}`} key={`text-${propId}`} min={0} max={3600} style={{ width: "50px", border: "1px solid black", borderRadius: "5px", marginLeft: "5px", marginBottom: "2px", }} value={duration} onChange={(e) => handleDurationsInputChange(e, propId.split("-")[1]) } /> )} </Label> <WideTextArea id={propId} value={inputValue} onChange={onChangeHandler} {...numberProps} /> </WideGridItem> ); }; const textInput = ( p: string, propId: string, inputType: string ): JSX.Element => { let numberProps = {}; if ( component && component.componentType === Constants.COMPONENT_TYPE_MULTILINE_TEXT ) { numberProps = { min: 1, max: 3 }; } return propId === "prop-text" ? ( <WideGridItem key={p}> <Label htmlFor={propId} accessKey={PropNames[p]?.accessKey}> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </Label> <WideTextArea id={propId} value={extraProps[p].toString()} onChange={propChangedForTextarea} {...numberProps} /> </WideGridItem> ) : propId === "prop-ddrEvents" ? ( <WideGridItem key={p}> <Label htmlFor={propId} accessKey={PropNames[p]?.accessKey}> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </Label> <WideTextInput id={propId} value={ddrInputEvents} placeholder={i18n( Global_Constants.SCENE_LOCALES, Constants.ENTER_DDR_VAR_NAMES )} onChange={changeInputDDREventState} {...numberProps} /> </WideGridItem> ) : propId == "prop-numStations" ? ( <WideGridItem key={p}> <Label htmlFor={propId} accessKey={PropNames[p]?.accessKey}> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </Label> <WideTextInput id={propId} type="number" className="numarrows" value={numStations} min={2} onChange={handleStationChange} {...numberProps} /> </WideGridItem> ) : propId == "prop-numberofArrows" ? ( <WideGridItem key={p}> <Label htmlFor={propId} accessKey={PropNames[p]?.accessKey}> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </Label> <WideTextInput id={propId} type="number" value={numberofArrows} className="numarrows" max={numStations - 1} min={0} onChange={handleArrowChange} {...numberProps} /> </WideGridItem> ) : propId !== "prop-direction" ? ( <WideGridItem key={p}> <Label htmlFor={propId} accessKey={PropNames[p]?.accessKey}> {i18n(Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText) ?? toProperCase(p)} </Label> <WideTextInput id={propId} value={extraProps[p].toString()} onChange={propChanged} {...numberProps} /> </WideGridItem> ) : ( <></> ); }; return component ? ( <Container> <ComponentTitle> {i18n( Global_Constants.SCENE_LOCALES, Components[component.componentType].displayName )} </ComponentTitle> <GridItem> <Label htmlFor="prop-x" accessKey="x"> x </Label> <TextInput id="prop-x" ref={refX} onChange={dataChanged} type="number" /> </GridItem> <GridItem> <Label htmlFor="prop-y" accessKey="y"> y </Label> <TextInput id="prop-y" ref={refY} onChange={dataChanged} type="number" /> </GridItem> <GridItem> <Label htmlFor="prop-width" accessKey="l"> {i18n( Global_Constants.SEQUENCE_LOCALES, PropNames["width"]?.displayText ) ?? "Width"} </Label> <TextInput id="prop-width" ref={refW} onChange={dataChanged} type="number" readOnly={component.componentType === "Video"} /> </GridItem> <GridItem> <Label htmlFor="prop-height" accessKey="h"> {i18n( Global_Constants.SEQUENCE_LOCALES, PropNames["height"]?.displayText ) ?? "Height"} </Label> <TextInput id="prop-height" ref={refH} onChange={dataChanged} type="number" /> </GridItem> {component && Components[component.componentType].canAnimate ? ( <WideGridItem className="form-check form-switch"> <input className="form-check-input" onChange={(e) => animateChanged(e.target)} type="checkbox" id="checkAnimate" checked={checked} /> <label className="form-check-label" htmlFor="checkAnimate" accessKey="a" > {i18n(Global_Constants.SCENE_LOCALES, Constants.ANIMATE)} </label> </WideGridItem> ) : ( <></> )} {Components[component.componentType].assetType === AssetType.AnimatedDrmDropdown ? ( <WideGridItem> <Label htmlFor="animatedDrmDropdown" accessKey="d"> Line Style </Label> <Input type="select" onChange={(e) => handleDotOptionChange(e)} className="animation-direction text-capitalize" value={animatedDrmDotOptionValue} > {animatedDrmDotPosition.current.map((value, index) => ( <option key={index} value={value}> {value} </option> ))} </Input> </WideGridItem> ) : ( <></> )} {Components[component.componentType].assetNames === AssetNames.AT_DotsDropdown ? ( <WideGridItem> <Label htmlFor="DotsDropdown" accessKey="d"> Arrow Type{" "} </Label> <input type="file" id="fileUpload" onChange={handleFileUploadChange} /> </WideGridItem> ) : ( <></> )} {component && Components[component.componentType].canMultiLine ? ( <WideGridItem className="form-check form-switch"> <input className="form-check-input" onChange={(e) => multiLineChanged(e.target)} type="checkbox" id="multiLine" checked={multiTextChecked} /> <label className="form-check-label" htmlFor="multiLine" accessKey="m"> {i18n(Global_Constants.SCENE_LOCALES, Constants.MULTI_LINE_TEXT)} </label> </WideGridItem> ) : ( <></> )} {extraProps && Object.keys(extraProps) .filter((p) => p !== "isAnimated" && !hiddenProps.includes(p)) .map((p) => { const inputType = p.toLowerCase().includes("color") ? "color" : typeof extraProps[p] === "number" ? "number" : "text"; const propId = `prop-${p}`; return p.toLowerCase().includes("color") ? ( <ColorSelector key={p} propId={propId} colorValue={extraProps[p].toString()} onColorChanged={(c) => changeProp(p, c)} component={component} /> ) : typeof extraProps[p] === "boolean" ? ( <WideGridItem className="form-check form-switch" key={p}> <input className="form-check-input" onChange={propChanged} type="checkbox" id={propId} /> <label className="form-check-label" htmlFor={propId} accessKey={PropNames[p]?.accessKey} > {i18n( Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText ) ?? toProperCase(p)} </label> </WideGridItem> ) : p.toLowerCase() === "alignment" ? ( alignmentInput(p, propId) ) : p.toLowerCase() === "style" ? ( styleInput(p, propId) ) : p.toLowerCase() === "direction" ? ( <WideGridItem> <Label htmlFor={propId} accessKey="s"> {i18n( Global_Constants.SCENE_LOCALES, PropNames[p]?.displayText ) ?? toProperCase(p)} </Label> <Input type="select" onChange={(e) => changeAnimationDirection(e)} id={propId} name={propId} className="animation-direction text-capitalize" value={direction} > {directionOptional.current.map((value, index) => ( <option key={index} value={value}> {value} </option> ))} </Input> </WideGridItem> ) : p === "multilanguage" ? ( DynamicField(p) ) : p === "dropdown" ? ( createDropdown(p, component) ) : ( textInput(p, propId, inputType) ); })} {Components[component.componentType].assetType === "AT_Temprature" ? ( <WideGridItem key="Type"> <Label htmlFor="prop-Temperature" accessKey="t"> Type </Label> <Input type="select" onChange={(e) => handleTemperatureChange(e)} id="prop-Temperature" name="Temprature" title="Type Temprature" className="comp-temprature-select" value={temperatureUnit} > {tempartureTypesOptions.current.map((item) => ( <option key={item} value={item}> {item} </option> ))} </Input> </WideGridItem> ) : ( Components[component.componentType].assetType && Components[component.componentType].assetType !== AssetType.AnimatedDrmDropdown && ( <WideGridItem key="Source"> <Label htmlFor="prop-source" accessKey="s"> Source </Label> {showImageModal && ( <ThumbnailModal show={showImageModal} header="Select Resource" onCloseModal={closeImageModal} isOkVisible={false} isCanVisible={true} searchQuery={searchQuery} setSearchQuery={setSearchQuery} // eslint-disable-next-line @typescript-eslint/no-empty-function // onOkClick={() => {}} i18n={i18n} > <div style={{ display: "flex", flexWrap: "wrap", overflowX: "hidden", height: "100%", width: "1100px", minHeight: "600px", minWidth: "1100px", justifyContent: "center", }} > {(Components[component.componentType].assetType === AssetType.Image ? imageAssets : videoAssets ) ?.filter((asset) => asset.name .toLowerCase() .includes(searchQuery.toLowerCase()) ) .map((asset) => ( <div style={{ padding: "5px", justifyContent: "center", alignItems: "center", flex: "0 0 250px", marginRight: "20px", marginBottom: "20px", border: "5px solid black", height: "250px", position: "relative", display: "flex", flexDirection: "column", paddingTop: "15px", }} key={asset.file_pointer} onClick={() => { const syntheticEvent = { target: { value: asset.file_pointer }, } as React.ChangeEvent<HTMLInputElement>; changeComponentAssetSelector( syntheticEvent, Components[component.componentType].assetType === AssetType.Image ? AssetType.Image : AssetType.Video ); closeImageModal(); }} > <div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100%", }} > {Components[component.componentType].assetType === AssetType.Image ? ( <img src={`${config.assetsUrl}/${asset.file_pointer}`} alt={asset.name} style={{ maxWidth: "150px", maxHeight: "150px", cursor: "pointer", marginBottom: "10px", alignSelf: "center", }} /> ) : ( <video src={`${config.assetsUrl}/${asset.file_pointer}`} style={{ maxWidth: "150px", maxHeight: "150px", cursor: "pointer", marginBottom: "10px", alignSelf: "center", }} /> )} </div> <p style={{ textAlign: "center", marginTop: "auto", marginBottom: "0", backgroundColor: "#548b8b", padding: "5px", color: "white", fontWeight: "bold", height: "50px", width: "100%", overflow: "auto", }} > {asset.name} </p> </div> ))} </div> </ThumbnailModal> )} <button className="btn btn-secondary" onClick={openImageModal}> {i18n(Global_Constants.SCENE_LOCALES, Constants.SELECT_RESOURCE)} </button> </WideGridItem> ) )} {Components[component.componentType].assetType === AssetType.Image ? ( <WideGridItem key="Object-fit"> <Label htmlFor="prop-objectFit" accessKey="s"> {i18n(Global_Constants.SCENE_LOCALES, Constants.OBJECT_FIT)} </Label> <Input type="select" name="prop-objectFit" id="prop-objectFit" title="ObjectFit" onChange={(e) => changeComponetObjectFit(e)} value={fitObject} className="text-capitalize" > {objectsFitOptions.current.map((item) => ( <option className="text-capitalize" key={item} value={item}> {item} </option> ))} </Input> </WideGridItem> ) : ( <></> )} {Components[component.componentType].assetType === AssetType.Video ? ( <WideGridItem> <button className="btn btn-primary" onClick={playPause}> <i className="fa fa-play fa-fw" id="icon-play" /> </button> </WideGridItem> ) : ( <></> )} {onDeleteComponent && ( <GridItem> <button className="btn btn-primary" onClick={() => onDeleteComponent(component.compId)} > <i className="fa fa-trash fa-fw" /> </button> </GridItem> )} {onDuplicateComponent && ( <GridItem> <button className="btn btn-success" onClick={() => onDuplicateComponent(component)} > <i className="fa fa-clone fa-fw" /> </button> </GridItem> )} </Container> ) : ( <div> {i18n(Global_Constants.SCENE_LOCALES, Constants.SELECT_COMPONENT)} </div> ); };
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter