From 18ba3f70d88c8b1cde9ce8662517d4ba6259648e Mon Sep 17 00:00:00 2001 From: AshAnand34 Date: Fri, 11 Jul 2025 15:25:01 -0700 Subject: [PATCH] Added user types to filter the tools based on targeted audience --- src/components/Hero.tsx | 127 +++++++++++++---------- src/components/UserTypeFilter.tsx | 105 +++++++++++++++++++ src/pages/home/Categories.tsx | 9 +- src/pages/tools-by-category/index.tsx | 55 +++++++--- src/pages/tools/json/stringify/meta.ts | 1 + src/pages/tools/string/base64/meta.ts | 1 + src/pages/tools/string/censor/meta.ts | 1 + src/pages/tools/string/rot13/meta.ts | 1 + src/pages/tools/string/statistic/meta.ts | 1 + src/tools/defineTool.tsx | 17 ++- src/tools/index.ts | 56 ++++++++-- 11 files changed, 289 insertions(+), 85 deletions(-) create mode 100644 src/components/UserTypeFilter.tsx diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index c1c6487..cfd6afc 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -18,6 +18,7 @@ import { useNavigate } from 'react-router-dom'; import _ from 'lodash'; import { Icon } from '@iconify/react'; import { getToolCategoryTitle } from '@utils/string'; +import UserTypeFilter, { useUserTypeFilter } from './UserTypeFilter'; const GroupHeader = styled('div')(({ theme }) => ({ position: 'sticky', @@ -47,17 +48,25 @@ const exampleTools: { label: string; url: string }[] = [ { label: 'Trim video', url: '/video/trim' }, { label: 'Calculate number sum', url: '/number/sum' } ]; + export default function Hero() { const [inputValue, setInputValue] = useState(''); const theme = useTheme(); + const { selectedUserTypes, setSelectedUserTypes } = useUserTypeFilter(); const [filteredTools, setFilteredTools] = useState(tools); const navigate = useNavigate(); + const handleInputChange = ( event: React.ChangeEvent<{}>, newInputValue: string ) => { setInputValue(newInputValue); - setFilteredTools(filterTools(tools, newInputValue)); + setFilteredTools(filterTools(tools, newInputValue, selectedUserTypes)); + }; + + const handleUserTypesChange = (userTypes: string[]) => { + setSelectedUserTypes(userTypes as any); + setFilteredTools(filterTools(tools, inputValue, userTypes as any)); }; return ( @@ -84,59 +93,69 @@ export default function Hero() { editing images, text, lists, and data, all directly from your browser. - option.type} - renderGroup={(params) => { - return ( -
  • - {getToolCategoryTitle(params.group)} - {params.children} -
  • - ); - }} - inputValue={inputValue} - getOptionLabel={(option) => option.name} - renderInput={(params) => ( - , - sx: { - borderRadius: 4, - backgroundColor: 'background.paper' - } - }} - onChange={(event) => handleInputChange(event, event.target.value)} - /> - )} - renderOption={(props, option) => ( - navigate('/' + option.path)} - > - - - - {option.name} - {option.shortDescription} - - - - )} - onChange={(event, newValue) => { - if (newValue) { - navigate('/' + newValue.path); - } - }} - /> - + + option.type} + renderGroup={(params) => { + return ( +
  • + {getToolCategoryTitle(params.group)} + {params.children} +
  • + ); + }} + inputValue={inputValue} + getOptionLabel={(option) => option.name} + renderInput={(params) => ( + , + sx: { + borderRadius: 4, + backgroundColor: 'background.paper' + } + }} + onChange={(event) => handleInputChange(event, event.target.value)} + /> + )} + renderOption={(props, option) => ( + navigate('/' + option.path)} + > + + + + {option.name} + + {option.shortDescription} + + + + + )} + onChange={(event, newValue) => { + if (newValue) { + navigate('/' + newValue.path); + } + }} + /> + +
    + + {exampleTools.map((tool) => ( diff --git a/src/components/UserTypeFilter.tsx b/src/components/UserTypeFilter.tsx new file mode 100644 index 0000000..e7fe782 --- /dev/null +++ b/src/components/UserTypeFilter.tsx @@ -0,0 +1,105 @@ +import React, { useState, useEffect } from 'react'; +import { + Box, + Chip, + FormControl, + InputLabel, + MenuItem, + OutlinedInput, + Select, + SelectChangeEvent, + Typography, + useTheme +} from '@mui/material'; +import { UserType } from '@tools/defineTool'; + +const userTypes: UserType[] = [ + 'General Users', + 'Developers', + 'Designers', + 'Students', + 'CyberSec' +]; + +interface UserTypeFilterProps { + selectedUserTypes: UserType[]; + onUserTypesChange: (userTypes: UserType[]) => void; + label?: string; +} + +export default function UserTypeFilter({ + selectedUserTypes, + onUserTypesChange, + label = 'Filter by User Type' +}: UserTypeFilterProps) { + const theme = useTheme(); + + const handleChange = (event: SelectChangeEvent) => { + const { + target: { value } + } = event; + const newUserTypes = + typeof value === 'string' ? (value.split(',') as UserType[]) : value; + onUserTypesChange(newUserTypes); + }; + + return ( + + + {label} + + + + ); +} + +// Hook to manage user type filter state with localStorage +export function useUserTypeFilter() { + const [selectedUserTypes, setSelectedUserTypes] = useState(() => { + const saved = localStorage.getItem('selectedUserTypes'); + return saved ? JSON.parse(saved) : []; + }); + + useEffect(() => { + localStorage.setItem( + 'selectedUserTypes', + JSON.stringify(selectedUserTypes) + ); + }, [selectedUserTypes]); + + return { + selectedUserTypes, + setSelectedUserTypes + }; +} diff --git a/src/pages/home/Categories.tsx b/src/pages/home/Categories.tsx index 12ee949..ba41633 100644 --- a/src/pages/home/Categories.tsx +++ b/src/pages/home/Categories.tsx @@ -7,6 +7,7 @@ import Button from '@mui/material/Button'; import { useState } from 'react'; import { categoriesColors } from 'config/uiConfig'; import { Icon } from '@iconify/react'; +import { useUserTypeFilter } from '@components/UserTypeFilter'; type ArrayElement = ArrayType extends readonly (infer ElementType)[] ? ElementType : never; @@ -65,7 +66,7 @@ const SingleCategory = function ({ {category.description} - +