import { isEmpty } from 'lodash' ; import { nanoid } from 'nanoid' ; import { ChangeEvent , Dispatch , MouseEvent as ReactMouseEvent , SetStateAction , useEffect } from 'react' ; import { HiPlus } from 'react-icons/hi' ; import { MdClose } from 'react-icons/md' ; import { ContainerTag } from '../../../types' ; import InputField from '../../common/InputField' ; import styles from './TagsList.module.css' ; interface Props { tags : ContainerTag [ ] ; setContainerTags : Dispatch < SetStateAction < ContainerTag [ ] > > ; repeatedTagNames : boolean ; setRepeatedTagNames : Dispatch < SetStateAction < boolean > > ; } const EMPTY_TAG = { name : '' , mutable : false } ; const TagsList = ( props ) => { const cleanRepeatedError = ( ) => { if ( props . repeatedTagNames ) { props . setRepeatedTagNames ( false ) ; } } ; const deleteTag = ( index ) => { cleanRepeatedError ( ) ; let updatedTags = [ ... props . tags ] ; updatedTags . splice ( index , 1 ) ; props . setContainerTags ( updatedTags ) ; } ; const addTag = ( ) => { props . setContainerTags ( [ ... props . tags , { ... EMPTY_TAG , id : nanoid ( ) } ] ) ; } ; const onUpdateTag = ( index , field , value ? ) => { cleanRepeatedError ( ) ; let tagToUpdate = props . tags [ index ] ; if ( field === 'name' ) { tagToUpdate [ field ] = value as string ; } else { tagToUpdate [ field ] = ! tagToUpdate . mutable ; } let updatedTags = [ ... props . tags ] ; updatedTags [ index ] = tagToUpdate ; props . setContainerTags ( updatedTags ) ; } ; useEffect ( ( ) => { if ( isEmpty ( props . tags ) ) { props . setContainerTags ( [ { ... EMPTY_TAG , id : nanoid ( ) } ] ) ; } } , [ props . tags ] ) ; return ( < div className = "mb-4" > < label className = { `form-check-label fw-bold mb-2 ${ styles . label }` } > Tags < button type = "button" className = { `btn btn-primary btn-sm ms-2 rounded-circle p-0 position-relative lh-1 ${ styles . btn } ${ styles . inTitle }` } onClick = { addTag } disabled = { props . tags . length === 10 } > < HiPlus /> < /button> < /label> { props . tags . length > 0 && ( < > { props . tags . map ( ( item , idx ) => { return ( < div className = "d-flex flex-row align-items-strecht justify-content-between" key = { `tag_${ item . id ! }` } > < InputField className = "flex-grow-1" type = "text" name = { `tag_${ idx }` } autoComplete = "off" value = { item . name } placeholder = "Tag name" onChange = { ( e ) => { onUpdateTag ( idx , 'name' , e . target . value ) ; } } smallBottomMargin / > < div className = "d-flex flex-row align-items-center mb-3 ms-3 flex-nowrap" > < div className = { `ms-2 me-5 position-relative ${ styles . inputWrapper }` } > < div className = "form-check form-switch ps-0" > < label htmlFor = { `mutable_${ idx }` } className = { `form-check-label fw-bold ${ styles . label }` } > Mutable < /label> < input id = { `mutable_${ idx }` } type = "checkbox" className = "form-check-input position-absolute ms-2" role = "switch" value = "true" checked = { item . mutable } onChange = { ( ) => { onUpdateTag ( idx , 'mutable' ) ; } } /> < /div> < /div> < div className = { `position-relative text-end ${ styles . btnWrapper }` } > < button className = { `btn btn-danger btn-sm ms-auto rounded-circle p-0 position-relative lh-1 ${ styles . btn }` } type = "button" onClick = { ( event ) => { event . preventDefault ( ) ; event . stopPropagation ( ) ; deleteTag ( idx ) ; } } aria - label = "Delete tag from repository" > < MdClose /> < /button> < /div> < /div> < /div>); } ) } < />)} { props . repeatedTagNames && < div className = "form-text text-danger mt-0" > Tags names must be unique . < /div>} < div className = "form-text text-muted mt-2" > The tags you 'd like to list on Artifact Hub must be explicitly added. You can add up to{' '} < span className = "fw-bold" > 10 < /span> (they can be edited later though). Mutable tags will be processed periodically , whereas immutable tags will be only processed once . < /div> < /div>); } ; export default TagsList ;