Skip to content

Commit

Permalink
feat(components): add wordpage search text
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed May 20, 2018
1 parent 029cdca commit f4a61fd
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/_helpers/record-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function getWords (
filters: { [field: string]: string[] | undefined },
sortField?: string,
sortOrder?: 'ascend' | 'descend' | false,
searchText?: string,
}
): Promise<MsgGetWordsResponse> {
return message.send<MsgGetWords, MsgGetWordsResponse>({
Expand Down
45 changes: 31 additions & 14 deletions src/background/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,29 +88,46 @@ export async function getWords ({
filters = {},
sortField = 'date',
sortOrder = 'descend',
searchText,
}: MsgGetWords): Promise<MsgGetWordsResponse> {
const col = db[area].orderBy(sortField)
const collection = db[area].orderBy(sortField)

const sortedCol = sortOrder === 'descend' ? col.reverse() : col
if (sortOrder === 'descend') {
collection.reverse()
}

let filteredCol = sortedCol
if (Array.isArray(filters.text) && filters.text.length > 0) {
const validLangs = filters.text.reduce((o, l) => (o[l] = true, o) ,{})
filteredCol = sortedCol.and(({ text }) => (
(validLangs['zh'] && isContainChinese(text)) ||
(validLangs['en'] && isContainEnglish(text))
))
const shouldFilter = Array.isArray(filters.text) && filters.text.length > 0
if (shouldFilter || searchText) {
const validLangs = shouldFilter
? (filters.text as string[]).reduce((o, l) => (o[l] = true, o) ,{})
: {}
const ls = searchText ? searchText.toLocaleLowerCase() : ''
collection.filter(record => {
const rText = shouldFilter
? (validLangs['en'] && isContainEnglish(record.text)) ||
(validLangs['ch'] && isContainChinese(record.text))
: true

const rSearch = searchText
? Object.values(record).some(v => (
typeof v === 'string' &&
v.toLocaleLowerCase().indexOf(ls) !== -1
))
: true

return rText && rSearch
})
}

const total = await filteredCol.count()
const total = await collection.count()

const paginatedCol = typeof itemsPerPage !== 'undefined' && typeof pageNum !== 'undefined'
? filteredCol
if (typeof itemsPerPage !== 'undefined' && typeof pageNum !== 'undefined') {
collection
.offset(itemsPerPage * (pageNum - 1))
.limit(itemsPerPage)
: filteredCol
}

const words = await paginatedCol.toArray()
const words = await collection.toArray()

return { total, words }
}
Expand Down
55 changes: 49 additions & 6 deletions src/components/WordPage/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import { translate, TranslationFunction } from 'react-i18next'
import { Layout, Table, Tooltip, Button, Dropdown, Icon, Menu, Modal } from 'antd'
import { Layout, Table, Tooltip, Button, Dropdown, Icon, Menu, Modal, Input } from 'antd'
import { TablePaginationConfig, TableRowSelection, ColumnProps } from 'antd/lib/table/interface'
import { ClickParam as MenuClickParam } from 'antd/lib/menu'

Expand All @@ -12,6 +12,9 @@ import { Area, Word, getWords, deleteWords } from '@/_helpers/record-manager'
import { message } from '@/_helpers/browser-api'
import { MsgType, MsgEditWord } from '@/typings/message'

import { Observable, Subject } from 'rxjs'
import { mergeMap, audit, mapTo, share, startWith, debounceTime } from 'rxjs/operators'

const { Header, Footer, Sider, Content } = Layout

const ITEMS_PER_PAGE = 20
Expand All @@ -22,6 +25,7 @@ export interface WordPageMainProps {
}

export interface WordPageMainState {
searchText: string
words: Word[]
pagination: TablePaginationConfig
rowSelection: TableRowSelection<Word>
Expand All @@ -41,13 +45,17 @@ interface FetchDataConfig {
filters: { [field: string]: string[] | undefined },
sortField?: string,
sortOrder?: 'ascend' | 'descend' | false,
searchText: string,
}

export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPageMainState> {
readonly tableColumns: ColumnProps<Word>[]
readonly emptyRow = []
readonly contentRef = React.createRef<any>()
readonly fetchData$$: Subject<FetchDataConfig>

lastFetchDataConfig: FetchDataConfig = {
searchText: '',
itemsPerPage: ITEMS_PER_PAGE,
pageNum: 1,
filters: { },
Expand All @@ -57,6 +65,23 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
super(props)
const { t, area } = props

let signal$: Observable<boolean>
this.fetchData$$ = new Subject<FetchDataConfig>()
const fetchData$$ = this.fetchData$$.pipe(
debounceTime(200),
// ignore values while fetchData is running
// if source emits any value during fetchData,
// retrieve the latest after fetchData is completed
audit(() => signal$),
mergeMap(config => this.fetchData(config)),
share(),
)
signal$ = fetchData$$.pipe(
mapTo(true), // last fetchData is completed
startWith(true),
)
fetchData$$.subscribe()

const colSelectionWidth = 48
const colDateWidth = 150
const colEditWidth = 80
Expand All @@ -65,6 +90,7 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
const restWidth = `calc((100vw - ${fixedWidth}px) * 2 / 7)`

this.state = {
searchText: '',
words: [],
selectedRows: [],
pagination: {
Expand Down Expand Up @@ -135,7 +161,7 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
]
}

fetchData = (config?: FetchDataConfig) => {
fetchData = (config?: FetchDataConfig): Promise<void> => {
config = config || this.lastFetchDataConfig
this.lastFetchDataConfig = config

Expand All @@ -162,12 +188,22 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
}
})

this.fetchData({
this.fetchData$$.next({
itemsPerPage: pagination && pagination.pageSize || ITEMS_PER_PAGE,
pageNum: pagination && pagination.current || 1,
filters: filters,
sortField: sorter && sorter.field,
sortOrder: sorter && sorter.order,
searchText: this.state.searchText,
})
}

handleSearchTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const searchText = e.currentTarget.value
this.setState({ searchText })
this.fetchData$$.next({
...this.lastFetchDataConfig,
searchText,
})
}

Expand Down Expand Up @@ -228,17 +264,17 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
? this.state.rowSelection.selectedRowKeys as number[]
: undefined
deleteWords(area, keys)
.then(() => this.fetchData())
.then(() => this.fetchData$$.next())
},
})
}
}

componentDidMount () {
this.fetchData()
this.fetchData$$.next()

message.addListener(MsgType.WordSaved, () => {
this.fetchData()
this.fetchData$$.next()
})

// From popup page
Expand Down Expand Up @@ -310,6 +346,7 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
} = this.props

const {
searchText,
words,
selectedRows,
pagination,
Expand All @@ -325,6 +362,12 @@ export class WordPageMain extends React.Component<WordPageMainInnerProps, WordPa
<Header className='wordpage-Header'>
<h1 style={{ color: '#fff' }}>{t(`title_${area}`)}</h1>
<div style={{ marginLeft: 'auto' }}>
<Input
style={{ width: '15em' }}
placeholder='Search'
onChange={this.handleSearchTextChange}
value={searchText}
/>
<Dropdown overlay={
<Menu onClick={this.handleBtnExportClick}>
<Menu.Item key='all'>{t('export_all')}</Menu.Item>
Expand Down
4 changes: 4 additions & 0 deletions src/components/WordPage/_style.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
body {
overflow-y: scroll;
}

textarea {
resize: none;
}
Expand Down
1 change: 1 addition & 0 deletions src/typings/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export interface MsgGetWords {
readonly filters: { [field: string]: string[] | undefined }
readonly sortField?: string
readonly sortOrder?: 'ascend' | 'descend' | false
readonly searchText?: string
}

export interface MsgGetWordsResponse {
Expand Down

0 comments on commit f4a61fd

Please sign in to comment.