diff --git a/src/renderer/features/albums/components/advanced-filters.tsx b/src/renderer/features/albums/components/advanced-filters.tsx new file mode 100644 index 000000000..4af325d7d --- /dev/null +++ b/src/renderer/features/albums/components/advanced-filters.tsx @@ -0,0 +1,467 @@ +import { useState } from 'react'; +import { Box, Stack, Group } from '@mantine/core'; +import _ from 'lodash'; +import { nanoid } from 'nanoid/non-secure'; +import { RiAddLine, RiMore2Line, RiSubtractLine } from 'react-icons/ri'; +import { + Button, + DropdownMenu, + NumberInput, + Select, + TextInput, +} from '@/renderer/components'; + +enum FilterGroupType { + AND = 'and', + OR = 'or', +} + +type AdvancedFilterRule = { + field: string; + operator: string; + uniqueId: string; + value: string; +}; + +type AdvancedFilterGroup = { + group: AdvancedFilterGroup[]; + rules: AdvancedFilterRule[]; + type: FilterGroupType; + uniqueId: string; +}; + +const DATE_FILTER_OPTIONS_DATA = [ + { label: 'is before', value: '<' }, + { label: 'is after', value: '>' }, +]; + +const STRING_FILTER_OPTIONS_DATA = [ + { label: 'contains', value: '~' }, + { label: 'does not contain', value: '!~' }, + { label: 'is', value: '=' }, + { label: 'is not', value: '!=' }, + { label: 'starts with', value: '^' }, + { label: 'ends with', value: '$' }, +]; + +const NUMBER_FILTER_OPTIONS_DATA = [ + { label: 'is', value: '=' }, + { label: 'is not', value: '!=' }, + { label: 'is greater than', value: '>' }, + { label: 'is less than', value: '<' }, +]; + +const FILTER_GROUP_OPTIONS_DATA = [ + { + label: 'Match ALL', + value: FilterGroupType.AND, + }, + { + label: 'Match ANY', + value: FilterGroupType.OR, + }, +]; + +const FILTER_OPTIONS_DATA = [ + { + label: 'Artist Title', + value: 'artist.title', + }, + { + label: 'Artist Rating', + value: 'artist.rating', + }, + { + label: 'Artist Genre', + value: 'artist.genre', + }, + { + label: 'Album Title', + value: 'album.title', + }, + { + label: 'Album Genre', + value: 'album.genre', + }, + { + label: 'Album Rating', + value: 'album.rating', + }, + { + label: 'Album Year', + value: 'album.year', + }, + { + label: 'Album Release Date', + value: 'album.releaseDate', + }, + { + label: 'Album Plays', + value: 'album.playCount', + }, + { + label: 'Album Date Added', + value: 'album.dateAdded', + }, + { + label: 'Track Title', + value: 'track.title', + }, + { + label: 'Track Plays', + value: 'track.plays', + }, + { + label: 'Track Rating', + value: 'track.rating', + }, +]; + +const OPTIONS_MAP = { + 'album.dateAdded': { + type: 'date', + }, + 'album.favorite': { + type: 'boolean', + }, + 'album.genre': { + type: 'string', + }, + 'album.playCount': { + type: 'number', + }, + 'album.rating': { + type: 'number', + }, + 'album.releaseDate': { + type: 'date', + }, + 'album.title': { + type: 'string', + }, + 'album.year': { + type: 'number', + }, + 'artist.genre': { + type: 'string', + }, + 'artist.rating': { + type: 'number', + }, + 'artist.title': { + type: 'string', + }, + 'track.plays': { + type: 'number', + }, + 'track.rating': { + type: 'number', + }, + 'track.title': { + type: 'string', + }, +}; + +const FilterOption = ({ level, onDeleteRule, uniqueId, groupIndex }: any) => { + const [selectedOption, setSelectedOption] = useState< + string | null | typeof OPTIONS_MAP + >(FILTER_OPTIONS_DATA[0].value); + + const handleDeleteRule = () => { + onDeleteRule({ groupIndex, level, uniqueId }); + }; + + const filterMap = { + date: , + string: , + 'album.playCount': , + 'album.rating': , + 'album.releaseDate': , + 'album.title': , + 'album.year': , + 'artist.genre': + {selectedOption && + filterMap[ + OPTIONS_MAP[selectedOption as keyof typeof OPTIONS_MAP] + .type as keyof typeof filterMap + ]} + {selectedOption && + filterInputMap[selectedOption as keyof typeof filterInputMap]} + + + ); +}; + +type AddArgs = { + groupIndex: number[]; + level: number; +}; + +type DeleteArgs = { + groupIndex: number[]; + level: number; + uniqueId: string; +}; + +interface FilterGroupProps { + data: AdvancedFilterGroup; + groupIndex: number[]; + level: number; + onAddRule: (args: AddArgs) => void; + onAddRuleGroup: (args: AddArgs) => void; + onDeleteRule: (args: DeleteArgs) => void; + onDeleteRuleGroup: (args: DeleteArgs) => void; + uniqueId: string; +} + +const FilterGroup = ({ + data, + level, + onAddRule, + onDeleteRuleGroup, + onDeleteRule, + onAddRuleGroup, + groupIndex, + uniqueId, +}: FilterGroupProps) => { + const handleAddRule = () => { + onAddRule({ groupIndex, level }); + }; + + const handleAddRuleGroup = () => { + onAddRuleGroup({ groupIndex, level }); + }; + + const handleDeleteRuleGroup = () => { + onDeleteRuleGroup({ groupIndex, level, uniqueId }); + }; + + return ( + + +