From 5a89830556c3789a485ab5043b2ee1a54dab4c44 Mon Sep 17 00:00:00 2001 From: "mirlan.maksitaliev" Date: Wed, 17 Jun 2020 18:03:35 +0600 Subject: [PATCH] feat(ott-91): own filtering and sorting function --- .../helpers/__tests__/index.tsx | 69 +++++++++++++++++ .../CountrySelector/helpers/index.tsx | 77 +++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/features/CountrySelector/helpers/__tests__/index.tsx create mode 100644 src/features/CountrySelector/helpers/index.tsx diff --git a/src/features/CountrySelector/helpers/__tests__/index.tsx b/src/features/CountrySelector/helpers/__tests__/index.tsx new file mode 100644 index 00000000..1b78ecbb --- /dev/null +++ b/src/features/CountrySelector/helpers/__tests__/index.tsx @@ -0,0 +1,69 @@ +import { matchSort } from '..' + +it('does not sort items when query is empty', () => { + const items = [ + { name: 'app' }, + { name: 'apple' }, + ] + const query = '' + const result = matchSort( + items, + 'name', + query, + ) + expect(result).toEqual(items) +}) + +it('non matching words omitted', () => { + const items = [ + { name: 'banana' }, + { name: 'app' }, + { name: 'apple' }, + ] + const query = 'app' + const result = matchSort( + items, + 'name', + query, + ) + expect(result).toEqual([ + items[1], + items[2], + ]) +}) + +it('matching words go first', () => { + const items = [ + { name: 'apple' }, + { name: 'app' }, + ] + const query = 'app' + const result = matchSort( + items, + 'name', + query, + ) + expect(result).toEqual([ + items[1], + items[0], + ]) +}) + +it('words starting with query word go second', () => { + const items = [ + { name: 'apple' }, + { name: 'app' }, + { name: 'buggy app' }, + ] + const query = 'app' + const result = matchSort( + items, + 'name', + query, + ) + expect(result).toEqual([ + items[1], + items[0], + items[2], + ]) +}) diff --git a/src/features/CountrySelector/helpers/index.tsx b/src/features/CountrySelector/helpers/index.tsx new file mode 100644 index 00000000..e891445b --- /dev/null +++ b/src/features/CountrySelector/helpers/index.tsx @@ -0,0 +1,77 @@ +import startsWith from 'lodash/startsWith' +import orderBy from 'lodash/orderBy' +import toLower from 'lodash/toLower' +import filter from 'lodash/filter' +import split from 'lodash/split' +import size from 'lodash/size' +import some from 'lodash/some' + +type Item = { [key: string]: any } + +type Func = ( + items: Array, + key: K, + query: string, +) => Array + +const startsWithIgnore = (word: string, target: string) => ( + startsWith(toLower(word), toLower(target)) +) + +const hasManyWords = (word: string) => size(split(word, ' ')) > 1 + +const atLeastOneWordStartsWith = (word: string, target: string) => { + const words = split(word, ' ') + return some(words, (w) => startsWithIgnore(w, target)) +} + +const filterMatching: Func = ( + items, + key, + query, +) => ( + filter(items, (item) => { + const value = item[key] + if (startsWithIgnore(value, query)) return true + if (hasManyWords(value)) return atLeastOneWordStartsWith(value, query) + return false + }) +) + +const sortMatching: Func = ( + items, + key, + query, +) => ( + orderBy( + items, + (item) => { + if (item[key] === query) return 10 + if (startsWithIgnore(item[key], query)) { + return 5 + } + return 0 + }, + 'desc', + ) +) + +export const matchSort: Func = ( + items, + key, + query, +) => { + if (!query) return items + + const filteredItems = filterMatching( + items, + key, + query, + ) + + return sortMatching( + filteredItems, + key, + query, + ) +}