diff --git a/components/keywords/AddKeywords.tsx b/components/keywords/AddKeywords.tsx index eef788c..567a601 100644 --- a/components/keywords/AddKeywords.tsx +++ b/components/keywords/AddKeywords.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useMemo, useRef, useState } from 'react'; import Icon from '../common/Icon'; import Modal from '../common/Modal'; import SelectField from '../common/SelectField'; @@ -24,10 +24,16 @@ type KeywordsInput = { const AddKeywords = ({ closeModal, domain, keywords, scraperName = '', allowsCity = false }: AddKeywordsProps) => { const [error, setError] = useState(''); + const [showTagSuggestions, setShowTagSuggestions] = useState(false); + const inputRef = useRef(null); const defCountry = localStorage.getItem('default_country') || 'US'; const [newKeywordsData, setNewKeywordsData] = useState({ keywords: '', device: 'desktop', country: defCountry, domain, tags: '' }); const { mutate: addMutate, isLoading: isAdding } = useAddKeywords(() => closeModal(false)); - const deviceTabStyle = 'cursor-pointer px-3 py-2 rounded mr-2'; + + const existingTags: string[] = useMemo(() => { + const allTags = keywords.reduce((acc: string[], keyword) => [...acc, ...keyword.tags], []).filter((t) => t && t.trim() !== ''); + return [...new Set(allTags)]; + }, [keywords]); const addKeywords = () => { if (newKeywordsData.keywords) { @@ -50,6 +56,8 @@ const AddKeywords = ({ closeModal, domain, keywords, scraperName = '', allowsCit } }; + const deviceTabStyle = 'cursor-pointer px-3 py-2 rounded mr-2'; + return ( { closeModal(false); }} title={'Add New Keywords'} width="[420px]">
@@ -91,14 +99,37 @@ const AddKeywords = ({ closeModal, domain, keywords, scraperName = '', allowsCit
- {/* TODO: Insert Existing Tags as Suggestions */} setNewKeywordsData({ ...newKeywordsData, tags: e.target.value })} /> - + setShowTagSuggestions(!showTagSuggestions)}> + + + + {showTagSuggestions && ( +
    + {existingTags.length > 0 && existingTags.map((tag, index) => { + return newKeywordsData.tags.split(',').map((t) => t.trim()).includes(tag) === false &&
  • { + const tagInput = newKeywordsData.tags; + // eslint-disable-next-line no-nested-ternary + const tagToInsert = tagInput + (tagInput.trim().slice(-1) === ',' ? '' : (tagInput.trim() ? ', ' : '')) + tag; + setNewKeywordsData({ ...newKeywordsData, tags: tagToInsert }); + setShowTagSuggestions(false); + if (inputRef?.current) (inputRef.current as HTMLInputElement).focus(); + }}> + {tag} +
  • ; + })} + {existingTags.length === 0 &&

    No Existing Tags Found...

    } +
+ )}
{ - const [tagInput, setTagInput] = useState(''); +const AddTags = ({ keywords = [], existingTags = [], closeModal }: AddTagsProps) => { + const [tagInput, setTagInput] = useState(() => (keywords.length === 1 ? keywords[0].tags.join(', ') : '')); const [inputError, setInputError] = useState(''); + const [showSuggestions, setShowSuggestions] = useState(false); const { mutate: updateMutate } = useUpdateKeywordTags(() => { setTagInput(''); }); + const inputRef = useRef(null); const addTag = () => { if (keywords.length === 0) { return; } - if (!tagInput) { + if (!tagInput && keywords.length > 1) { setInputError('Please Insert a Tag!'); setTimeout(() => { setInputError(''); }, 3000); return; @@ -24,7 +27,7 @@ const AddTags = ({ keywords = [], closeModal }: AddTagsProps) => { const tagsArray = tagInput.split(',').map((t) => t.trim()); const tagsPayload:any = {}; keywords.forEach((keyword:KeywordType) => { - tagsPayload[keyword.ID] = [...keyword.tags, ...tagsArray]; + tagsPayload[keyword.ID] = keywords.length === 1 ? tagsArray : [...(new Set([...keyword.tags, ...tagsArray]))]; }); updateMutate({ tags: tagsPayload }); }; @@ -33,9 +36,13 @@ const AddTags = ({ keywords = [], closeModal }: AddTagsProps) => { { closeModal(false); }} title={`Add New Tags to ${keywords.length} Selected Keyword`}>
{inputError && {inputError}} - + setShowSuggestions(!showSuggestions)}> + + + setTagInput(e.target.value)} @@ -46,6 +53,27 @@ const AddTags = ({ keywords = [], closeModal }: AddTagsProps) => { } }} /> + {showSuggestions && ( +
    + {existingTags.length > 0 && existingTags.map((tag, index) => { + return tagInput.split(',').map((t) => t.trim()).includes(tag) === false &&
  • { + // eslint-disable-next-line no-nested-ternary + const tagToInsert = tagInput + (tagInput.trim().slice(-1) === ',' ? '' : (tagInput.trim() ? ', ' : '')) + tag; + setTagInput(tagToInsert); + setShowSuggestions(false); + if (inputRef?.current) (inputRef.current as HTMLInputElement).focus(); + }}> + {tag} +
  • ; + })} + {existingTags.length === 0 &&

    No Existing Tags Found...

    } +
+ )} +
{showAddTag && keyword && ( setShowAddTag(false)} /> diff --git a/components/keywords/KeywordsTable.tsx b/components/keywords/KeywordsTable.tsx index af6e9ab..d107719 100644 --- a/components/keywords/KeywordsTable.tsx +++ b/components/keywords/KeywordsTable.tsx @@ -59,7 +59,7 @@ const KeywordsTable = (props: KeywordsTableProps) => { }, [keywords, device, sortBy, filterParams, scDataType]); const allDomainTags: string[] = useMemo(() => { - const allTags = keywords.reduce((acc: string[], keyword) => [...acc, ...keyword.tags], []); + const allTags = keywords.reduce((acc: string[], keyword) => [...acc, ...keyword.tags], []).filter((t) => t && t.trim() !== ''); return [...new Set(allTags)]; }, [keywords]); @@ -251,6 +251,7 @@ const KeywordsTable = (props: KeywordsTableProps) => { )} {showAddTags && ( selectedKeywords.includes(k.ID))} closeModal={() => setShowAddTags(false)} />