From cd4f43d9718337aaf0f13b3c5cf278a04281f701 Mon Sep 17 00:00:00 2001 From: Georgi Parlakov Date: Fri, 1 Nov 2024 09:30:30 +0200 Subject: [PATCH] feat: search campaigns prototype --- README.md | 2 + .../client/campaigns/CampaignFilter.tsx | 65 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 333133d46..08cb004bc 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,9 @@ Watch releases of this repository to be notified about future updates: ## Contributors ✨ + [![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) + Please check [contributors guide](https://github.com/podkrepi-bg/frontend/blob/master/CONTRIBUTING.md) for: diff --git a/src/components/client/campaigns/CampaignFilter.tsx b/src/components/client/campaigns/CampaignFilter.tsx index 90f77afdb..fed2b9ec0 100644 --- a/src/components/client/campaigns/CampaignFilter.tsx +++ b/src/components/client/campaigns/CampaignFilter.tsx @@ -1,6 +1,15 @@ import React, { useMemo, useState } from 'react' import { styled } from '@mui/material/styles' -import { Box, CircularProgress, Grid, IconButton, Typography } from '@mui/material' +import { + Box, + CircularProgress, + Grid, + IconButton, + TextField, + TextFieldProps, + Typography, +} from '@mui/material' +import { debounce } from 'lodash' import { useCampaignList } from 'common/hooks/campaigns' import CampaignsList from './CampaignsList' import { CampaignResponse } from 'gql/campaigns' @@ -79,19 +88,64 @@ const categories: { others: {}, } +export type SearchFieldProps = TextFieldProps & { + debounceMs?: number + onSearch: (v: string) => void +} +export function SearchField({ debounceMs, onSearch, ...textProps }: SearchFieldProps) { + const debounceSearch = useMemo( + () => debounce(onSearch, debounceMs, { leading: false, trailing: true }), + [], + ) + + const handleSearch = (event: React.ChangeEvent) => { + event.preventDefault() + const searchText = event.target.value + const normalizedText = typeof searchText === 'string' ? searchText.trim() : '' + Number(debounceMs) > 0 ? debounceSearch(normalizedText) : onSearch(normalizedText) + } + return ( + + ) +} + export default function CampaignFilter() { const { t } = useTranslation() const { data: campaigns, isLoading } = useCampaignList(true) const [selectedCategory, setSelectedCategory] = useState('ALL') + const [searchValue, setSearchValue] = useState('') + // TODO: add filters&sorting of campaigns so people can select based on personal preferences - const campaignToShow = useMemo(() => { + const filteredCampaigns = useMemo(() => { if (selectedCategory === 'ALL') { return campaigns ?? [] } return ( campaigns?.filter((campaign) => campaign.campaignType.category === selectedCategory) ?? [] ) - }, [campaigns, selectedCategory]) + }, [campaigns, selectedCategory, searchValue]) + + const campaignToShow = useMemo(() => { + if (searchValue == null || searchValue === '') { + return filteredCampaigns + } + + return ( + filteredCampaigns?.filter((c) => + typeof searchValue === 'string' && searchValue != '' + ? c.title?.toLocaleLowerCase()?.includes(searchValue) + : true, + ) ?? [] + ) + }, [filteredCampaigns, searchValue]) return ( <> @@ -134,6 +188,11 @@ export default function CampaignFilter() { + + + + + {isLoading ? (