Files
omni-tools/src/pages/tools-by-category/index.tsx

167 lines
5.5 KiB
TypeScript
Raw Normal View History

2025-07-09 17:58:22 +01:00
import {
Box,
Divider,
Stack,
styled,
2025-07-14 12:47:05 +01:00
TextField,
2025-07-09 17:58:22 +01:00
useTheme
} from '@mui/material';
2024-06-25 09:35:44 +01:00
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import { Link, useNavigate, useParams } from 'react-router-dom';
2025-04-05 00:28:31 +00:00
import { filterTools, getToolsByCategory } from '../../tools';
2024-06-25 09:35:44 +01:00
import Hero from 'components/Hero';
2025-07-14 14:51:46 +01:00
import {
getI18nNamespaceFromToolCategory,
getToolCategoryTitle
} from '@utils/string';
2025-02-25 06:17:10 +00:00
import { Icon } from '@iconify/react';
import { categoriesColors } from 'config/uiConfig';
2025-03-09 19:20:40 +00:00
import React, { useEffect } from 'react';
2025-03-29 16:40:14 +00:00
import IconButton from '@mui/material/IconButton';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
2025-04-05 00:28:31 +00:00
import SearchIcon from '@mui/icons-material/Search';
2025-07-07 01:07:48 +01:00
import { Helmet } from 'react-helmet';
2025-07-22 18:53:03 +01:00
import UserTypeFilter from '@components/UserTypeFilter';
2025-07-14 12:47:05 +01:00
import { useTranslation } from 'react-i18next';
2025-07-15 18:30:02 +01:00
import { I18nNamespaces, validNamespaces } from '../../i18n';
2025-07-22 18:53:03 +01:00
import { useUserTypeFilter } from '../../providers/UserTypeFilterProvider';
2024-06-25 09:35:44 +01:00
2025-07-09 17:58:22 +01:00
const StyledLink = styled(Link)(({ theme }) => ({
'&:hover': {
color: theme.palette.mode === 'dark' ? 'white' : theme.palette.primary.light
}
}));
2025-04-05 00:28:31 +00:00
export default function ToolsByCategory() {
2024-06-25 09:35:44 +01:00
const navigate = useNavigate();
const theme = useTheme();
2025-03-09 19:20:40 +00:00
const mainContentRef = React.useRef<HTMLDivElement>(null);
2024-06-25 09:35:44 +01:00
const { categoryName } = useParams();
2025-04-05 00:28:31 +00:00
const [searchTerm, setSearchTerm] = React.useState<string>('');
const { selectedUserTypes, setSelectedUserTypes } = useUserTypeFilter();
2025-07-15 18:30:02 +01:00
const { t } = useTranslation(validNamespaces);
const rawTitle = getToolCategoryTitle(categoryName as string, t);
2025-07-14 18:04:30 +01:00
// First get tools by category without filtering
const toolsByCategory = getToolsByCategory(selectedUserTypes, t).find(
({ type }) => type === categoryName
);
const categoryDefinedTools = toolsByCategory?.tools ?? [];
2025-07-14 18:04:30 +01:00
const categoryTools = filterTools(
categoryDefinedTools,
searchTerm,
selectedUserTypes,
t
);
2025-03-09 19:20:40 +00:00
useEffect(() => {
if (mainContentRef.current) {
mainContentRef.current.scrollIntoView({ behavior: 'smooth' });
}
}, []);
2024-06-25 09:35:44 +01:00
return (
2025-03-31 01:27:44 +00:00
<Box sx={{ backgroundColor: 'background.default' }}>
2025-07-07 01:07:48 +01:00
<Helmet>
2025-07-16 13:58:05 +01:00
<title>{rawTitle}</title>
2025-07-07 01:07:48 +01:00
</Helmet>
2024-06-25 09:35:44 +01:00
<Box
2024-06-26 00:29:53 +01:00
padding={{ xs: 1, md: 3, lg: 5 }}
2024-06-25 09:35:44 +01:00
display={'flex'}
flexDirection={'column'}
alignItems={'center'}
justifyContent={'center'}
width={'100%'}
>
<Hero />
</Box>
<Divider sx={{ borderColor: theme.palette.primary.main }} />
2025-03-09 19:20:40 +00:00
<Box ref={mainContentRef} mt={3} ml={{ xs: 1, md: 2, lg: 3 }} padding={3}>
2025-04-05 00:28:31 +00:00
<Stack direction={'row'} justifyContent={'space-between'} spacing={2}>
<Stack direction={'row'} alignItems={'center'} spacing={1}>
<IconButton onClick={() => navigate('/')}>
<ArrowBackIcon color={'primary'} />
</IconButton>
2025-07-15 18:30:02 +01:00
<Typography fontSize={22} color={theme.palette.primary.main}>
{t('translation:toolLayout.allToolsTitle', { type: rawTitle })}
</Typography>
2025-04-05 00:28:31 +00:00
</Stack>
2025-07-22 18:53:03 +01:00
<TextField
placeholder={'Search'}
InputProps={{
endAdornment: <SearchIcon />,
sx: {
borderRadius: 4,
backgroundColor: 'background.paper',
maxWidth: 400
}
}}
onChange={(event) => setSearchTerm(event.target.value)}
/>
2025-03-29 16:40:14 +00:00
</Stack>
2025-07-22 18:53:03 +01:00
<Box
width={'100%'}
display={'flex'}
alignItems={'center'}
justifyContent={'center'}
my={2}
>
<UserTypeFilter
userTypes={toolsByCategory?.userTypes ?? undefined}
2025-07-22 18:53:03 +01:00
selectedUserTypes={selectedUserTypes}
onUserTypesChange={setSelectedUserTypes}
/>
</Box>
<Grid container spacing={2}>
2025-07-14 12:47:05 +01:00
{categoryTools.map((tool, index) => (
2025-04-05 00:28:31 +00:00
<Grid item xs={12} md={6} lg={4} key={tool.path}>
<Stack
sx={{
backgroundColor: 'background.paper',
boxShadow: `5px 4px 2px ${
theme.palette.mode === 'dark' ? 'black' : '#E9E9ED'
}`,
cursor: 'pointer',
height: '100%',
'&:hover': {
backgroundColor: theme.palette.background.hover
}
}}
onClick={() => navigate('/' + tool.path)}
direction={'row'}
alignItems={'center'}
spacing={2}
padding={2}
border={`1px solid ${theme.palette.background.default}`}
borderRadius={2}
>
<Icon
icon={tool.icon ?? 'ph:compass-tool-thin'}
fontSize={'60px'}
color={categoriesColors[index % categoriesColors.length]}
/>
<Box>
2025-07-09 17:58:22 +01:00
<StyledLink
2025-04-05 00:28:31 +00:00
style={{
fontSize: 20
}}
to={'/' + tool.path}
>
2025-07-14 14:51:46 +01:00
{/*@ts-ignore*/}
2025-07-14 12:47:05 +01:00
{t(tool.name)}
2025-07-09 17:58:22 +01:00
</StyledLink>
2025-04-05 00:28:31 +00:00
<Typography sx={{ mt: 2 }}>
2025-07-14 14:51:46 +01:00
{/*@ts-ignore*/}
2025-07-14 12:47:05 +01:00
{t(tool.shortDescription)}
2025-04-05 00:28:31 +00:00
</Typography>
</Box>
</Stack>
</Grid>
))}
2024-06-25 09:35:44 +01:00
</Grid>
</Box>
</Box>
);
}