feat(category): check if user defined already exists, remove duplicates

This commit is contained in:
enes 2024-12-11 14:36:07 +01:00
parent f7f8778707
commit b9d6820405
2 changed files with 55 additions and 34 deletions

View File

@ -1,10 +1,11 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import { Category } from 'types' import { Category } from 'types'
import { import {
addToUserCategories, addToUserCategories,
capitalizeEachWord, capitalizeEachWord,
deleteFromUserCategories deleteFromUserCategories,
flattenCategories
} from 'utils' } from 'utils'
import { useLocalStorage } from 'hooks' import { useLocalStorage } from 'hooks'
import styles from './CategoryFilterPopup.module.scss' import styles from './CategoryFilterPopup.module.scss'
@ -35,6 +36,21 @@ export const CategoryFilterPopup = ({
setHierarchies(filterHierarchies) setHierarchies(filterHierarchies)
} }
const [inputValue, setInputValue] = useState<string>('') const [inputValue, setInputValue] = useState<string>('')
const userHierarchiesMatching = useMemo(
() =>
flattenCategories(userHierarchies, []).some((h) =>
h.hierarchy.includes(inputValue.toLowerCase())
),
[inputValue, userHierarchies]
)
const hierarchiesMatching = useMemo(
() =>
flattenCategories(categoriesData, []).some((h) =>
h.hierarchy.includes(inputValue.toLowerCase())
),
[inputValue]
)
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value) setInputValue(e.target.value)
} }
@ -75,13 +91,14 @@ export const CategoryFilterPopup = ({
const path = values.join(':') const path = values.join(':')
// Add new hierarchy to current selection and active selection // Add new hierarchy to current selection and active selection
// Convert through set to remove duplicates
setFilterHierarchies((prev) => { setFilterHierarchies((prev) => {
prev.push(path) prev.push(path)
return [...prev] return Array.from(new Set([...prev]))
}) })
setHierarchies((prev) => { setHierarchies((prev) => {
prev.push(path) prev.push(path)
return [...prev] return Array.from(new Set([...prev]))
}) })
setInputValue('') setInputValue('')
} }
@ -149,6 +166,7 @@ export const CategoryFilterPopup = ({
overflow: 'auto' overflow: 'auto'
}} }}
> >
{!userHierarchiesMatching && <div>No results.</div>}
{userHierarchies {userHierarchies
.filter((c) => typeof c !== 'string') .filter((c) => typeof c !== 'string')
.map((c, i) => ( .map((c, i) => (
@ -187,6 +205,15 @@ export const CategoryFilterPopup = ({
</> </>
)} )}
<div className='inputLabelWrapperMain'> <div className='inputLabelWrapperMain'>
<div className='inputLabelWrapperMain'>
<label
className='form-label labelMain'
style={{ fontWeight: 'bold' }}
>
Categories
</label>
<p className='labelDescriptionMain'>Maybe</p>
</div>
<div <div
className='inputMain' className='inputMain'
style={{ style={{
@ -199,27 +226,31 @@ export const CategoryFilterPopup = ({
<div className={`${styles.noResult}`}> <div className={`${styles.noResult}`}>
<div>No results.</div> <div>No results.</div>
<br /> <br />
<div {userHierarchiesMatching ? (
className='dropdown-item dropdownMainMenuItem' <div>Already defined in your categories</div>
onClick={handleAddNew} ) : (
> <div
Add and search for "{inputValue}" category className='dropdown-item dropdownMainMenuItem'
<button onClick={handleAddNew}
type='button'
className='btn btnMain btnMainInsideField btnMainAdd'
title='Add'
> >
<svg Add and search for "{inputValue}" category
xmlns='http://www.w3.org/2000/svg' <button
viewBox='-32 0 512 512' type='button'
width='1em' className='btn btnMain btnMainInsideField btnMainAdd'
height='1em' title='Add'
fill='currentColor'
> >
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path> <svg
</svg> xmlns='http://www.w3.org/2000/svg'
</button> viewBox='-32 0 512 512'
</div> width='1em'
height='1em'
fill='currentColor'
>
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
</svg>
</button>
</div>
)}
</div> </div>
{(categoriesData as Category[]).map((category, i) => ( {(categoriesData as Category[]).map((category, i) => (
<CategoryCheckbox <CategoryCheckbox

View File

@ -1,7 +1,7 @@
import { Categories, Category } from 'types/category' import { Categories, Category } from 'types/category'
import categoriesData from './../assets/categories/categories.json' import categoriesData from './../assets/categories/categories.json'
const flattenCategories = ( export const flattenCategories = (
categories: (Category | string)[], categories: (Category | string)[],
parentPath: string[] = [] parentPath: string[] = []
): Categories[] => { ): Categories[] => {
@ -26,16 +26,6 @@ export const getCategories = () => {
return flattenCategories(categoriesData) return flattenCategories(categoriesData)
} }
export const buildCategories = (input: string[]) => {
const categories: (string | Category)[] = []
input.forEach((cat) => {
addToUserCategories(categories, cat)
})
return categories
}
export const addToUserCategories = ( export const addToUserCategories = (
categories: (string | Category)[], categories: (string | Category)[],
input: string input: string