From bba853893dd38a9aacfb513cb76d008baf68e673 Mon Sep 17 00:00:00 2001 From: danidfra Date: Tue, 25 Feb 2025 18:34:06 -0300 Subject: [PATCH] Complete search_filter reducer implementation and refactor code --- .../explorer/components/explorerFilter.tsx | 53 ++-- src/features/explorer/components/filters.tsx | 268 ++++++++---------- src/locales/en.json | 1 + src/reducers/index.ts | 2 + src/reducers/search-filter.ts | 112 ++++++-- 5 files changed, 236 insertions(+), 200 deletions(-) diff --git a/src/features/explorer/components/explorerFilter.tsx b/src/features/explorer/components/explorerFilter.tsx index 8035f8f45..496123b5b 100644 --- a/src/features/explorer/components/explorerFilter.tsx +++ b/src/features/explorer/components/explorerFilter.tsx @@ -11,57 +11,43 @@ import Text from 'soapbox/components/ui/text.tsx'; import { CreateFilter, LanguageFilter, - MediaFilter, PlatformFilters, - RepliesFilter, + ToggleFilter, generateFilter, } from 'soapbox/features/explorer/components/filters.tsx'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; +import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; const messages = defineMessages({ filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' }, - showReplies: { id: 'column.explorer.filters.show_replies', defaultMessage: 'Show replies:' }, - language: { id: 'column.explorer.filters.language', defaultMessage: 'Language:' }, - platforms: { id: 'column.explorer.filters.platforms', defaultMessage: 'Platforms:' }, - createYourFilter: { id: 'column.explorer.filters.create_your_filter', defaultMessage: 'Create your filter' }, - filterByWords: { id: 'column.explorer.filters.filter_by_words', defaultMessage: 'Filter by this/these words' }, - include: { id: 'column.explorer.filters.include', defaultMessage: 'Include' }, - exclude: { id: 'column.explorer.filters.exclude', defaultMessage: 'Exclude' }, - nostr: { id: 'column.explorer.filters.nostr', defaultMessage: 'Nostr' }, - bluesky: { id: 'column.explorer.filters.bluesky', defaultMessage: 'Bluesky' }, - fediverse: { id: 'column.explorer.filters.fediverse', defaultMessage: 'Fediverse' }, - cancel: { id: 'column.explorer.filters.cancel', defaultMessage: 'Cancel' }, - addFilter: { id: 'column.explorer.filters.add_filter', defaultMessage: 'Add Filter' }, }); interface IGenerateFilter { name: string; - state: boolean | null; + status: boolean | null; value: string; } const ExplorerFilter = () => { const dispatch = useAppDispatch(); + const filters = useAppSelector((state) => state.search_filter); const intl = useIntl(); - const [isOpen, setIsOpen] = useState(false); - - const [tagFilters, setTagFilters] = useState([ - { 'name': 'Nostr', state: null, 'value': 'protocol:nostr' }, - { 'name': 'Bluesky', state: null, 'value': 'protocol:atproto' }, - { 'name': 'Fediverse', state: null, 'value': 'protocol:activitypub' }, - ]); + const [isOpen, setIsOpen] = useState(true); useEffect( () => { - - const value = tagFilters - .filter((searchFilter) => !searchFilter.value.startsWith('protocol:')) + const language = filters[0].name.toLowerCase() !== 'default' ? filters[0].value : ''; + const protocols = filters.slice(1, 4).filter((protocol) => !protocol.status).map((filter) => filter.value).join(' '); + const defaultFilters = filters.slice(4, 7).filter((x) => x.status).map((filter) => filter.value).join(' '); + const newFilters = filters.slice(7) .map((searchFilter) => searchFilter.value) .join(' '); + const value = [ language, protocols, defaultFilters, newFilters ].join(' '); + dispatch(changeSearch(value)); dispatch(submitSearch(undefined, value)); - }, [tagFilters, dispatch], + }, [filters, dispatch], ); return ( @@ -74,7 +60,7 @@ const ExplorerFilter = () => { {intl.formatMessage(messages.filters)} - {tagFilters.length > 0 && [...tagFilters.slice(0, 3).filter((x)=> x.value[0] !== '-' && x.state === null).map((value) => generateFilter(value, setTagFilters)), ...tagFilters.slice(3).map((value) => generateFilter(value, setTagFilters))]} + {filters.length > 0 && [...filters.slice(0, 7).filter((value) => value.status).map((value) => generateFilter(dispatch, value)), ...filters.slice(7).map((value) => generateFilter(dispatch, value))]} { {/* Show Reply toggle */} - + {/* Media toggle */} - + + + {/* Video toggle */} + {/* Language */} - + {/* Platforms */} - + {/* Create your filter */} - + diff --git a/src/features/explorer/components/filters.tsx b/src/features/explorer/components/filters.tsx index 5d6b59bf1..4637f3c7a 100644 --- a/src/features/explorer/components/filters.tsx +++ b/src/features/explorer/components/filters.tsx @@ -15,11 +15,16 @@ import Text from 'soapbox/components/ui/text.tsx'; import Toggle from 'soapbox/components/ui/toggle.tsx'; import { IGenerateFilter } from 'soapbox/features/explorer/components/explorerFilter.tsx'; import { SelectDropdown } from 'soapbox/features/forms/index.tsx'; +import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; +import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; +import { changeLanguage, createFilter, handleToggle, removeFilter, selectProtocol } from 'soapbox/reducers/search-filter.ts'; +import { AppDispatch, RootState } from 'soapbox/store.ts'; +import toast from 'soapbox/toast.tsx'; const messages = defineMessages({ - filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' }, showReplies: { id: 'column.explorer.filters.show_replies', defaultMessage: 'Show replies:' }, showMedia: { id: 'column.explorer.filters.show_text_posts', defaultMessage: 'Just text posts:' }, + showVideo: { id: 'column.explorer.filters.show_video_posts', defaultMessage: 'Just posts with video:' }, language: { id: 'column.explorer.filters.language', defaultMessage: 'Language:' }, platforms: { id: 'column.explorer.filters.platforms', defaultMessage: 'Platforms:' }, createYourFilter: { id: 'column.explorer.filters.create_your_filter', defaultMessage: 'Create your filter' }, @@ -93,36 +98,46 @@ const languages = { zh: '中文', }; -interface IFilter { - onChangeFilters: React.Dispatch>; -} - -interface IPlatformFilters { - filters: IGenerateFilter[]; - onChangeFilters: React.Dispatch>; -} - -const PlatformFilters = ({ onChangeFilters, filters }: IPlatformFilters) => { +const PlatformFilters = () => { const intl = useIntl(); + const dispatch = useAppDispatch(); + const filterList = useAppSelector((state: RootState) => state.search_filter); - const toggleProtocolFilter = (protocolName: string, protocolValue: string) => { - onChangeFilters(prevFilters => { + const handleProtocolFilter = (e: React.ChangeEvent) => { + const protocol = e.target.name; - const exists = prevFilters.some(tag => tag.name.toLowerCase() === protocolName.toLowerCase() && tag.value[0] !== '-'); - const newFilterList = prevFilters.filter(tag => tag.name.toLowerCase() !== protocolName.toLowerCase()); + dispatch(selectProtocol(protocol)); + }; - const newFilter = { - name: protocolName, - state: null, - value: exists ? `-protocol:${protocolValue}` : `protocol:${protocolValue}`, - }; + const CheckBox = ({ protocolN } : { protocolN: string }) => { + const filter = filterList.find((filter) => filter.name.toLowerCase() === protocolN); + const checked = filter?.status; - if (newFilterList.length === 0) { - return [newFilter]; - } + let message; + switch (protocolN) { + case 'nostr': + message = messages.nostr; + break; + case 'bluesky': + message = messages.bluesky; + break; + default: + message = messages.fediverse; + } - return [newFilterList[0], newFilter, ...newFilterList.slice(1)]; - }); + + return ( + + + + {intl.formatMessage(message)} + + + ); }; return ( @@ -132,56 +147,33 @@ const PlatformFilters = ({ onChangeFilters, filters }: IPlatformFilters) => { {/* Nostr */} - - tag.name.toLowerCase() === 'nostr' && tag.value[0] !== '-')} - onChange={() => toggleProtocolFilter('Nostr', 'nostr')} - /> - - {intl.formatMessage(messages.nostr)} - - + {/* Bluesky */} - - tag.name.toLowerCase() === 'bluesky' && tag.value[0] !== '-')} - onChange={() => toggleProtocolFilter('Bluesky', 'atproto')} - /> - - {intl.formatMessage(messages.bluesky)} - - + {/* Fediverse */} - - tag.name.toLowerCase() === 'fediverse' && tag.value[0] !== '-')} - onChange={() => toggleProtocolFilter('Fediverse', 'activitypub')} - /> - - {intl.formatMessage(messages.fediverse)} - - + ); }; -const CreateFilter = ({ onChangeFilters }: IFilter) => { +const CreateFilter = () => { const intl = useIntl(); + const dispatch = useAppDispatch(); + const [inputValue, setInputValue] = useState(''); - const [include, setInclude] = useState(''); + const [include, setInclude] = useState(true); const hasValue = inputValue.length > 0; const handleAddFilter = () => { - onChangeFilters((prev) => { - return [...prev, { name: inputValue, state: include === '', value: `${include}${inputValue.split(' ').join(` ${include}`)}` }]; - }); + if (inputValue.length > 0) { + dispatch(createFilter({ name: inputValue, status: include })); + } else { + toast.error('Hey there... you forget to write the filter!'); + } }; return ( @@ -223,9 +215,9 @@ const CreateFilter = ({ onChangeFilters }: IFilter) => { 0)} + checked={include} onChange={() => { - setInclude(''); + setInclude(true); }} /> @@ -237,9 +229,9 @@ const CreateFilter = ({ onChangeFilters }: IFilter) => { 0)} + checked={!include} onChange={() => { - setInclude('-'); + setInclude(false); }} /> @@ -252,7 +244,7 @@ const CreateFilter = ({ onChangeFilters }: IFilter) => {