Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added new /tools page #940

Merged
merged 94 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
26b3f05
Tools UI initiated
akshatnema Aug 7, 2022
dfd25b2
Merge branch 'asyncapi:master' into tools-dashboard
akshatnema Aug 25, 2022
9111717
Merge branch 'asyncapi:master' into tools-dashboard
akshatnema Sep 7, 2022
ed9a45a
inital layout created
akshatnema Sep 7, 2022
79494b8
Merge remote-tracking branch 'refs/remotes/origin/tools-dashboard' in…
akshatnema Sep 7, 2022
b281f1e
Merge branch 'master' into tools-dashboard
akshatnema Sep 10, 2022
ecacece
updated tools
akshatnema Sep 11, 2022
44a14c4
Merge branch 'master' into tools-dashboard
akshatnema Sep 24, 2022
8add97a
props color fixed
akshatnema Sep 26, 2022
9acf6ec
Merge branch 'master' into tools-dashboard
akshatnema Sep 29, 2022
13d4c9e
context api setup
akshatnema Oct 1, 2022
662f07a
Merge branch 'master' into tools-dashboard
akshatnema Oct 1, 2022
6654313
Filters Context created
akshatnema Oct 1, 2022
7a72d63
Merge branch 'asyncapi:master' into tools-dashboard
akshatnema Oct 2, 2022
711e8d4
updated view
akshatnema Oct 4, 2022
fbe336d
Merge branch 'master' into tools-dashboard
akshatnema Oct 6, 2022
0f8933b
Merge branch 'master' into tools-dashboard
akshatnema Oct 12, 2022
3b8a6e1
Merge branch 'master' into tools-dashboard
akshatnema Oct 13, 2022
feeb4f8
colors error fixed
akshatnema Oct 13, 2022
34e606f
Merge branch 'master' into tools-dashboard
akshatnema Oct 23, 2022
9931d00
updated view
akshatnema Oct 23, 2022
078d839
Merge remote-tracking branch 'refs/remotes/origin/tools-dashboard' in…
akshatnema Oct 23, 2022
5eecd42
tag colors added
akshatnema Oct 24, 2022
6329066
all filters completed
akshatnema Oct 25, 2022
6c5ca9b
bugs fixed
akshatnema Oct 25, 2022
91f4048
Merge branch 'master' into tools-dashboard
akshatnema Oct 26, 2022
b9e0f18
Merge branch 'master' into tools-dashboard
akshatnema Oct 27, 2022
bcd182a
UI corrected in mobile view
akshatnema Oct 27, 2022
50831d4
New Blog initiated
akshatnema Oct 27, 2022
4ff1ab5
blog content in progress
akshatnema Oct 28, 2022
1b6b3f1
Merge branch 'master' into tools-dashboard
akshatnema Oct 28, 2022
b7e5ede
updated UI
akshatnema Oct 28, 2022
5cdaef2
Blog creation in process
akshatnema Oct 28, 2022
6e90d40
Merge branch 'master' into tools-dashboard
akshatnema Oct 28, 2022
d9a80d5
blog creation in progress
akshatnema Oct 28, 2022
faa162f
false commit
akshatnema Nov 1, 2022
706de9d
Revert "false commit"
akshatnema Nov 1, 2022
a63e7f9
Merge branch 'master' into tools-dashboard
akshatnema Nov 2, 2022
fe5878d
Merge branch 'master' into tools-dashboard
akshatnema Nov 4, 2022
d5740dc
Merge branch 'master' into tools-dashboard
akshatnema Nov 5, 2022
06054e5
changes made
akshatnema Nov 6, 2022
8eb5d68
Merge branch 'master' into tools-dashboard
akshatnema Nov 6, 2022
86dc889
close button added
akshatnema Nov 6, 2022
66fb7f0
changes made according to review
akshatnema Nov 6, 2022
8f9819a
Blog updated
akshatnema Nov 6, 2022
f983cd4
Merge branch 'master' into tools-dashboard
derberg Nov 8, 2022
d9f083b
Merge branch 'master' into tools-dashboard
akshatnema Nov 9, 2022
e5bf72f
Merge branch 'master' into tools-dashboard
akshatnema Nov 9, 2022
97ad1a6
removed blog
akshatnema Nov 10, 2022
69d2891
Merge remote-tracking branch 'refs/remotes/origin/tools-dashboard' in…
akshatnema Nov 10, 2022
7b67201
Merge branch 'master' into tools-dashboard
akshatnema Nov 10, 2022
4b7149b
illustration added for no tools found
akshatnema Nov 10, 2022
16ec12e
Merge branch 'master' into tools-dashboard
quetzalliwrites Nov 12, 2022
4688a66
Apply suggestions from code review
akshatnema Nov 12, 2022
04d3ab6
Merge branch 'master' into tools-dashboard
akshatnema Nov 14, 2022
cf8084f
Merge branch 'master' into tools-dashboard
quetzalliwrites Nov 16, 2022
145f119
Merge branch 'master' into tools-dashboard
akshatnema Nov 16, 2022
0bde259
Merge branch 'master' into tools-dashboard
akshatnema Nov 26, 2022
f800fa3
Merge branch 'master' into tools-dashboard
akshatnema Nov 30, 2022
94b4c02
View Source code button added
akshatnema Nov 30, 2022
4403818
Merge branch 'master' into tools-dashboard
akshatnema Nov 30, 2022
d02b6c4
Merge branch 'master' of github.com:akshatnema/website
akshatnema Dec 1, 2022
402f6a6
Merge branch 'master' into tools-dashboard
akshatnema Dec 1, 2022
533a913
Merge branch 'master' into tools-dashboard
akshatnema Dec 7, 2022
e79b08b
Merge branch 'master' into tools-dashboard
akshatnema Dec 7, 2022
ca782b5
Merge branch 'master' into tools-dashboard
akshatnema Dec 12, 2022
684f7c8
tools file updated
akshatnema Dec 12, 2022
5839841
repoUrl added in schema
akshatnema Dec 12, 2022
c49cb9a
Dashboard updated
akshatnema Dec 12, 2022
c96cdd5
updated files
akshatnema Dec 13, 2022
7ecef2b
removed token
akshatnema Dec 13, 2022
95ae82b
updated files
akshatnema Dec 13, 2022
a970e84
paid tools corrected
akshatnema Dec 13, 2022
14e808b
Merge branch 'master' into tools-dashboard
akshatnema Dec 13, 2022
c0f57e1
Apply suggestions from code review
akshatnema Dec 13, 2022
853fbf0
changes according to review
akshatnema Dec 13, 2022
8460f4e
Merge branch 'master' into tools-dashboard
akshatnema Dec 15, 2022
4fc7a61
Merge branch 'master' into tools-dashboard
akshatnema Dec 15, 2022
655ff2f
replaced issue link
akshatnema Dec 15, 2022
3d1050b
category filter moved to Filter
akshatnema Dec 15, 2022
4da47c4
Apply suggestions from code review
akshatnema Dec 15, 2022
141b564
dynamic addition of technologies and languages in the filters
akshatnema Dec 15, 2022
7b70229
Merge branches 'tools-dashboard' and 'tools-dashboard' of github.com:…
akshatnema Dec 15, 2022
07fc409
added tooltip
akshatnema Dec 16, 2022
721b15f
comments added
akshatnema Dec 17, 2022
d2b82bc
comments added for clarity
akshatnema Dec 19, 2022
ae9656f
Merge branch 'master' into tools-dashboard
akshatnema Dec 19, 2022
14de97a
updated the tools.json file
akshatnema Dec 19, 2022
52629a9
Merge branch 'master' into tools-dashboard
akshatnema Dec 21, 2022
2857fb1
changes applied
akshatnema Dec 21, 2022
ba8eefb
changes in categories
akshatnema Dec 21, 2022
94da02b
Merge branch 'master' into tools-dashboard
quetzalliwrites Dec 22, 2022
1594c22
Merge branch 'master' into tools-dashboard
akshatnema Dec 22, 2022
eb73a88
removed dashboard from Nav
akshatnema Dec 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/buttons/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export default function Button({
...props
}) {

const smallButtonClasses = twMerge(` ${bgClassName} ${textClassName} transition-all duration-500 ease-in-out rounded-md px-3 py-2 text-sm font-medium tracking-heading ${className || ''}`)
const classNames = twMerge(` ${bgClassName} ${textClassName} transition-all duration-500 ease-in-out rounded-md px-4 py-3 text-md font-semibold tracking-heading ${className || ''}`)
const smallButtonClasses = twMerge(`${bgClassName} ${textClassName} transition-all duration-500 ease-in-out rounded-md px-3 py-2 text-sm font-medium tracking-heading ${className || ''}`)
const classNames = twMerge(`${bgClassName} ${textClassName} transition-all duration-500 ease-in-out rounded-md px-4 py-3 text-md font-semibold tracking-heading ${className || ''}`)

if (!href) {
return (
Expand Down
7 changes: 7 additions & 0 deletions components/icons/ArrowDown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function IconArrowDown({ className= '' }) {
return (
<svg width="11" height="7" viewBox="0 0 11 7" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path d="M1 1.25L5.5 5.75L10 1.25" stroke="#8B9394" />
</svg>
)
}
14 changes: 14 additions & 0 deletions components/icons/Filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function IconFilter({className=''}) {
return (
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<g clipPath="url(#clip0_894_656)">
<path d="M1.11536 0.615479H15.8846V3.38471L10.3461 7.63646V13.2309L6.65382 15.3847V7.63646L1.11536 3.38471V0.615479Z" stroke="#556061" strokeWidth="1.5" strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_894_656">
<rect width="16" height="16" fill="white" transform="translate(0.5)" />
</clipPath>
</defs>
</svg>
)
}
7 changes: 7 additions & 0 deletions components/icons/Search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function IconSearch({className = ''}) {
return (
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path d="M14.875 14.8751L11.6974 11.6918L14.875 14.8751ZM13.4583 7.43758C13.4583 9.03441 12.824 10.5658 11.6949 11.695C10.5657 12.8241 9.03432 13.4584 7.4375 13.4584C5.84067 13.4584 4.30925 12.8241 3.18013 11.695C2.051 10.5658 1.41666 9.03441 1.41666 7.43758C1.41666 5.84076 2.051 4.30933 3.18013 3.18021C4.30925 2.05108 5.84067 1.41675 7.4375 1.41675C9.03432 1.41675 10.5657 2.05108 11.6949 3.18021C12.824 4.30933 13.4583 5.84076 13.4583 7.43758V7.43758Z" stroke="#556061" strokeWidth="2" strokeLinecap="round" />
</svg>
)
}
2 changes: 1 addition & 1 deletion components/navigation/communityItems.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import IconNewsroom from '../icons/Newsroom'

export default [

{ icon: IconTools, title: 'Tools & Services', href: '/docs/community/tooling', description: 'Explore the tools and services our awesome community has created.' },
{ icon: IconTools, title: 'Tools & Services', href: '/docs/tools', description: 'Explore the tools and services our awesome community has created.' },
{ icon: IconGithubOrganization, title: 'GitHub Organization', href: 'https://github.com/asyncapi', target: '_blank', description: 'Want to sneak in the code? Everything we do is open-sourced in our GitHub organization.' },
{ icon: IconSlack, title: 'Slack Workspace', href: 'https://asyncapi.com/slack-invite', target: '_blank', description: `Need help? Want to share something? Join our Slack workspace. We're nice people :)` },
{ icon: IconContributing, title: 'Contributing', href: 'https://github.com/asyncapi?type=source#-contribute-to-asyncapi', target: '_blank', description: `We are always welcoming and looking for contributions. If you are interested check out our contribution guide.` },
Expand Down
134 changes: 134 additions & 0 deletions components/tools/Filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { useState, useContext } from 'react';
import {twMerge} from 'tailwind-merge'
import {ToolFilterContext} from '../../context/ToolFilterContext'
import ArrowDown from '../icons/ArrowDown';
import FiltersDropdown from './FiltersDropdown';
import Button from '../buttons/Button'
import tags from '../../config/all-tags.json'
import {categoryList} from '../../scripts/tools/categorylist'

export default function Filters({setOpenFilter}) {
// all the filter state variables and functions are extracted from the Context to set filters according to the UI.
const {isPaid, isAsyncAPIOwner, languages, technologies, categories, setCategories, setLanguages, setTechnologies, setisPaid, setAsyncAPIOwner} = useContext(ToolFilterContext)

// State variables to operate dropdowns of respective filters
const [openLanguage, setopenLanguage] = useState(false)
const [openTechnology, setopenTechnology] = useState(false)
const [openCategory, setopenCategory] = useState(false)

// Filter state variables for user checked values are created, initialising it with the values already set by user.
const [checkPaid, setCheckPaid] = useState(isPaid)
const [checkedLanguage, setCheckedLanguage] = useState(languages)
const [checkedTechnology, setCheckedTechnology] = useState(technologies)
const [checkedCategory, setCheckedCategory] = useState(categories)
const [checkOwner, setCheckOwner] = useState(isAsyncAPIOwner)

// contains the list of languages and technologies
let languageList = tags["languages"]
let technologyList = tags["technologies"]

// function to apply all the filters, which are selected, when `Apply Filters` is clicked.
const handleApplyFilters = () => {
setLanguages(checkedLanguage);
setTechnologies(checkedTechnology)
setCategories(checkedCategory)
setisPaid(checkPaid)
setAsyncAPIOwner(checkOwner)
setOpenFilter(false)
}

// function to clear all the filters when `Clear Filters` is clicked.
const clearFilters =() => {
setLanguages([])
setTechnologies([])
setCategories([])
setisPaid("all")
setAsyncAPIOwner(false)
setOpenFilter(false)
}

return (
<div className="bg-white z-10 py-4 border rounded-lg border-gray-300 shadow-md">
<div className="flex flex-col gap-2 mx-4">
<div className="flex gap-2 items-baseline justify-between">
<div className="text-sm text-gray-500 uppercase">Pricing</div>
<div className="text-xs mb-0 flex cursor-pointer hover:underline gap-0.5" onClick={clearFilters}>
Clear Filters
</div>
</div>
<div className="flex gap-2">
<div className={twMerge(`bg-gray-200 px-4 py-2 flex gap-1 rounded-md hover:bg-secondary-100 border hover:border-secondary-500 cursor-pointer ${checkPaid==="free" ? 'bg-secondary-100 border-secondary-500' : ''}`)} onClick={() => setCheckPaid("free")}>
<div className='text-sm'>Open Source</div>
<img src="/img/illustrations/icons/FreeIcon.svg" />
</div>
<div className={`bg-gray-200 px-4 py-2 flex gap-1 rounded-md hover:bg-secondary-100 border hover:border-secondary-500 cursor-pointer ${checkPaid==="paid" ? 'bg-secondary-100 border-secondary-500' : ''}`} onClick={() => setCheckPaid("paid")}>
<div className='text-sm'>Commercial</div>
<img src="/img/illustrations/icons/PaidIcon.svg" />
</div>
</div>
</div>
<hr className="my-4" />
<div className="flex flex-col gap-2 mx-4">
<div className="text-sm text-gray-500">OWNERSHIP</div>
<div className="flex gap-4">
<label className="inline-flex relative items-center cursor-pointer">
<input type="checkbox" value={checkOwner} className="sr-only peer" onChange={() => setCheckOwner(!checkOwner)} />
<div className={twMerge(`w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all ${checkOwner ? "after:translate-x-full after:border-white bg-secondary-500" : ''}`)}></div>
</label>
<div className="font-medium text-sm">
Show only AsyncAPI-owned tools
</div>
</div>
</div>
<hr className="my-4" />
<div className="flex flex-col gap-2 mx-4">
<div className="text-sm text-gray-500">LANGUAGE</div>
<div className="w-full">
<div className={twMerge(`px-4 py-2 flex justify-between rounded-lg border border-gray-400 w-full bg-gray-200 text-gray-700 shadow text-sm cursor-pointer ${openLanguage ? 'rounded-b-none' : ''}`)} onClick={() => setopenLanguage(!openLanguage)}>
<div className="flex items-center text-dark">
Select Languages...
</div>
<ArrowDown className={`my-auto ${openLanguage ? 'rotate-180' : ''}`} />
</div>
{openLanguage && <div className="bg-gray-200 border border-gray-400 w-auto rounded-b-lg duration-150 overflow-x-auto">
<FiltersDropdown dataList={languageList} checkedOptions={checkedLanguage} setStateFunction={setCheckedLanguage} />
</div>}
</div>
</div>
<hr className="my-4" />
<div className="flex flex-col gap-2 mx-4">
<div className="text-sm text-gray-500">TECHNOLOGY</div>
<div className="w-full">
<div className={twMerge(`px-4 py-2 flex justify-between rounded-lg border border-gray-400 w-full bg-gray-200 text-gray-700 shadow text-sm cursor-pointer ${openTechnology ? 'rounded-b-none' : ''}`)} onClick={() => setopenTechnology(!openTechnology)}>
<div className="flex items-center text-dark">
Select technologies...
</div>
<ArrowDown className={`my-auto ${openTechnology ? 'rotate-180' : ''}`} />
</div>
{openTechnology && <div className="bg-gray-200 border border-gray-400 w-auto rounded-b-lg duration-150 overflow-x-auto">
<FiltersDropdown dataList={technologyList} checkedOptions={checkedTechnology} setStateFunction={setCheckedTechnology} />
</div>}
</div>
</div>
<hr className="my-4" />
<div className="flex flex-col gap-2 mx-4">
<div className="text-sm text-gray-500">CATEGORY</div>
<div className="w-full">
<div className={twMerge(`px-4 py-2 flex justify-between rounded-lg border border-gray-400 w-full bg-gray-200 text-gray-700 shadow text-sm cursor-pointer ${openCategory ? 'rounded-b-none' : ''}`)} onClick={() => setopenCategory(!openCategory)}>
<div className="flex items-center text-dark">
Select categories...
</div>
<ArrowDown className={`my-auto ${openCategory ? 'rotate-180' : ''}`} />
</div>
{openCategory && <div className="bg-gray-200 border border-gray-400 w-auto rounded-b-lg duration-150 overflow-x-auto">
<FiltersDropdown dataList={categoryList} checkedOptions={checkedCategory} setStateFunction={setCheckedCategory} />
</div>}
</div>
</div>
<hr className="my-4" />
<div className='w-auto my-6 mx-4 mb-0' onClick={handleApplyFilters}>
<Button text='Apply Filters' className='w-full' />
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions components/tools/FiltersDropdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { twMerge } from "tailwind-merge";

export default function FiltersDropdown({dataList=[], checkedOptions=[], setStateFunction, className=''}) {

const handleClickOption = (e, option) => {
let tempValueArray = [...checkedOptions]
let index = checkedOptions.indexOf(option)
if(index>-1){
tempValueArray.splice(index, 1);
}else{
tempValueArray.push(option);
}
setStateFunction(tempValueArray)
}
return (
<div className={twMerge(`max-w-lg flex gap-2 flex-wrap p-2 duration-200 delay-150 ${className}`)}>
{dataList.map((data, index) => {
let checked = checkedOptions.indexOf(data.name)!=-1 ? true : false
return (
<div key={index} className={twMerge(`border border-secondary-600 text-secondary-600 p-1 pb-0 rounded-2xl flex gap-1 cursor-pointer items-start ${checked ? 'bg-secondary-600 text-white' : ''}`)} onClick={(e) => handleClickOption(e, data.name)}>
{checked ? <img src='/img/illustrations/icons/CheckedIcon.svg' /> : <img src='/img/illustrations/icons/UncheckedIcon.svg' />}
<div className='text-xs -mt-[1px] mb-[1px]'>{data.name}</div>
</div>
)})}
</div>
)
}
7 changes: 7 additions & 0 deletions components/tools/Tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function SelectTags({name='', bgColor, borderColor}) {
return (
<div className={`text-center text-sm py-1 px-2 rounded-lg ${bgColor} border ${borderColor}`}>
{name}
</div>
)
}
134 changes: 134 additions & 0 deletions components/tools/ToolDashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { useState, useContext, useEffect, useRef } from 'react';
import { ToolFilterContext } from '../../context/ToolFilterContext'
import ToolsData from '../../config/tools.json'
import FilterIcon from '../icons/Filter';
import SearchIcon from '../icons/Search';
import ToolsList from './ToolsList';
import Filters from './Filters';

export default function ToolDashboard() {
const filterRef = useRef() // used to provide ref to the Filter menu and outside click close feature
const [openFilter, setOpenFilter] = useState(false)
// filter parameters extracted from the context
const { isPaid, isAsyncAPIOwner, languages, technologies, categories } = useContext(ToolFilterContext)
const [searchName, setSearchName] = useState('') // state variable used to get the search name
const [toolsList, setToolsList] = useState({}) // state variable used to set the list of tools according to the filters applied
const [checkToolsList, setCheckToolsList] = useState(true) // state variable used to check whether any tool is available according to the needs of user.

// useEffect function to enable the close Modal feature when clicked outside of the modal
useEffect(() => {
const checkIfClickOutside = (e) => {
if ((openFilter && filterRef.current && !filterRef.current.contains(e.target)))
setOpenFilter(false)
}
document.addEventListener("mousedown", checkIfClickOutside)
return () => {
document.removeEventListener("mousedown", checkIfClickOutside)
}
})

// Function to update the list of tools according to the current filters applied
const updateToolsList = () => {
let tempToolsList = {}

// Tools data list is first filtered according to the category filter if applied by the user.
// Hence if any category is selected, then only respective tools will be selected for further check on filters
if (categories.length > 0) {
for (let category of categories) {
Object.keys(ToolsData).forEach((key) => {
if (key === category) tempToolsList[key] = JSON.parse(JSON.stringify(ToolsData[key]))
})
}
} else {
// if no category is selected, then all tools are selected for further check on filters
tempToolsList = JSON.parse(JSON.stringify(ToolsData));
}

// checkToolsList is initially made false to check whether any tools are present according to the filters.
setCheckToolsList(false)

// Each tool selected, is then traversed to check against each filter variable (only if the filter is applied),
// whether they match with the filter applied or not.
Object.keys(tempToolsList).forEach((category) => {
tempToolsList[category].toolsList = tempToolsList[category].toolsList.filter((tool) => {

// These are filter check variable for respective filters, which is initially made true.
// If the particular filter is applied by user, the respective check variable is made false first,
// and then tool parameters are checked against the filter variable value to decide it matches the filter
// criteria or not.
let isLanguageTool = true, isTechnologyTool = true, isSearchTool = true, isAsyncAPITool = true, isPaidTool = true;
if (languages.length) {
isLanguageTool = false;
for (let language of languages) {
if (tool?.filters?.language && language === tool.filters.language.name) isLanguageTool = true;
}
}
if (technologies.length) {
isTechnologyTool = false;
for (let technology of technologies) {
if (tool?.filters?.technology && tool.filters.technology.find((item) => item.name === technology)) isTechnologyTool = true;
}
}
if (searchName) {
isSearchTool = tool.title.toLowerCase().includes(searchName.toLowerCase())
}
if (isAsyncAPIOwner)
isAsyncAPITool = tool.filters.isAsyncAPIOwner === isAsyncAPIOwner ? true : false

if (isPaid !== "all") {
if (isPaid === "free") isPaidTool = tool.filters.hasCommercial === false;
else isPaidTool = tool.filters.hasCommercial === true;
}

return isLanguageTool && isTechnologyTool && isSearchTool && isAsyncAPITool && isPaidTool;
})
if (tempToolsList[category].toolsList.length) setCheckToolsList(true)
})
setToolsList(tempToolsList)
}

useEffect(() => {
updateToolsList()
}, [isPaid, isAsyncAPIOwner, languages, technologies, categories, searchName])

return (
<div>
<div className="flex flex-row gap-4 my-10">
<div className='flex w-1/3 lg:w-1/5 gap-5 h-auto'>
<div className="relative w-full h-auto" ref={filterRef}>
<div
className="flex py-2 justify-center items-center gap-2 rounded-lg border w-full h-full border-gray-300 hover:shadow-md hover:border-gray-600 text-gray-700 shadow text-sm cursor-pointer"
onClick={() => setOpenFilter(!openFilter)}>
<FilterIcon />
<div>Filter</div>
</div>
{openFilter && (
<div className="z-10 absolute top-16 min-w-[20rem]">
<Filters setOpenFilter={setOpenFilter} />
</div>
)}
</div>
</div>
<div className="py-1 px-4 flex rounded-lg border w-2/3 lg:w-4/5 border-gray-300 hover:border-gray-600 focus:border-gray-600 text-gray-700 shadow text-sm">
<SearchIcon className="my-auto opacity-70" />
<input
className="border-none outline-none flex-1 w-11/12 focus:ring-0"
placeholder="Search by name"
type="text"
value={searchName}
onChange={(e) => setSearchName(e.target.value)}
/>
{searchName && <button className="hover:bg-gray-100 p-2 rounded-full h-fit my-auto" onClick={() => setSearchName('')}>
<img src="/img/illustrations/icons/close-icon.svg" width="10" />
</button>}
</div>
</div>
<div className="mt-10">
{checkToolsList ? <ToolsList toolsData={toolsList} /> : <div className='p-4'>
<img src='/img/illustrations/not-found.webp' className='w-1/2 m-auto' />
<div className='text-center text-lg'> Sorry, we don't have tools according to your needs. </div>
</div>}
</div>
</div>
)
}
Loading