Поиск по пользователям переведён на RxJs

This commit is contained in:
Александр Сироткин 2022-02-24 15:41:38 +05:00
parent 6eb6f0f4c2
commit 8ed948a14d

View File

@ -1,10 +1,11 @@
import { Input, Modal, Radio } from 'antd' import { Input, Modal, Radio } from 'antd'
import { memo, useCallback, useEffect, useState } from 'react' import { memo, useCallback, useEffect, useState } from 'react'
import { BehaviorSubject, debounceTime, distinctUntilChanged, filter, map } from 'rxjs'
import { UserView } from '@components/views' import { UserView } from '@components/views'
import LoaderPortal from '@components/LoaderPortal' import LoaderPortal from '@components/LoaderPortal'
import { makeColumn, makeNumericSorter, Table } from '@components/Table'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { makeColumn, makeNumericSorter, Table } from '@components/Table'
import { DrillingProgramService } from '@api' import { DrillingProgramService } from '@api'
import { arrayOrDefault } from '@utils' import { arrayOrDefault } from '@utils'
@ -14,31 +15,19 @@ const userRules = [
{ label: 'Согласовант', value: 2 }, { label: 'Согласовант', value: 2 },
] ]
const SEARCH_TIMEOUT = 1000 const SEARCH_TIMEOUT = 400
export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) => { export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) => {
const [title, setTitle] = useState() const [title, setTitle] = useState()
const [users, setUsers] = useState([]) const [users, setUsers] = useState([])
const [allUsers, setAllUsers] = useState([]) const [allUsers, setAllUsers] = useState([])
const [filteredUsers, setFilteredUsers] = useState([]) const [filteredUsers, setFilteredUsers] = useState([])
const [searchTimeout, setSearchTimeout] = useState(null)
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('') const [searchValue, setSearchValue] = useState('')
const [subject, setSubject] = useState(null)
useEffect(() => invokeWebApiWrapperAsync( useEffect(() => invokeWebApiWrapperAsync(
async () => { async () => {
const allUsers = arrayOrDefault(await DrillingProgramService.getAvailableUsers(idWell))
setAllUsers(allUsers)
},
setShowLoader,
`Не удалось загрузить список доступных пользователей скважины "${idWell}"`
), [idWell])
const calcFilteredUsers = useCallback(async (value, users) => await invokeWebApiWrapperAsync(
async () => {
if (searchTimeout)
clearTimeout(searchTimeout)
setSearchTimeout(null)
const filteredUsers = users.filter(({ user }) => user && [ const filteredUsers = users.filter(({ user }) => user && [
user.login ?? '', user.login ?? '',
user.name ?? '', user.name ?? '',
@ -48,12 +37,40 @@ export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) =>
user.phone ?? '', user.phone ?? '',
user.position ?? '', user.position ?? '',
user.company?.caption ?? '', user.company?.caption ?? '',
].join(' ').toLowerCase().includes(value)) ].join(' ').toLowerCase().includes(searchValue))
setFilteredUsers(filteredUsers) setFilteredUsers(filteredUsers)
}, },
setShowLoader, setShowLoader,
`Не удалось произвести поиск пользователей` `Не удалось произвести поиск пользователей`
), [searchTimeout]) ), [users, searchValue])
useEffect(() => {
if (!subject) {
const sub = new BehaviorSubject('')
setSubject(sub)
} else {
const observable = subject.pipe(
debounceTime(SEARCH_TIMEOUT),
map(s => s.trim().toLowerCase() ?? ''),
distinctUntilChanged(),
filter(s => s.length <= 0 || s.length >= 2),
).subscribe(value => setSearchValue(value))
return () => {
observable.unsubscribe()
subject.unsubscribe()
}
}
}, [subject])
useEffect(() => invokeWebApiWrapperAsync(
async () => {
const allUsers = arrayOrDefault(await DrillingProgramService.getAvailableUsers(idWell))
setAllUsers(allUsers)
},
setShowLoader,
`Не удалось загрузить список доступных пользователей скважины "${idWell}"`
), [idWell])
const calcUsers = useCallback(() => { const calcUsers = useCallback(() => {
if (!visible) return if (!visible) return
@ -68,8 +85,7 @@ export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) =>
...approvers.map((user) => ({ user, status: 2 })), ...approvers.map((user) => ({ user, status: 2 })),
] ]
setUsers(users) setUsers(users)
calcFilteredUsers(searchValue, users) }, [category, visible, allUsers])
}, [category, visible, allUsers, calcFilteredUsers, searchValue])
useEffect(calcUsers, [calcUsers]) useEffect(calcUsers, [calcUsers])
@ -114,17 +130,9 @@ export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) =>
}) })
] ]
const onSearchTextChange = useCallback((value) => { const onSearchTextChange = useCallback((e) => subject?.next(e?.target?.value), [subject])
value = value.trim().toLowerCase() ?? ''
setSearchValue(value)
if (!searchTimeout) { const onModalClosed = useCallback(() => {
clearTimeout(searchTimeout)
setSearchTimeout(setTimeout(() => calcFilteredUsers(value, users), SEARCH_TIMEOUT))
}
}, [searchTimeout, calcFilteredUsers, users])
const onModalCanceled = useCallback(() => {
onClosed?.() onClosed?.()
calcUsers() calcUsers()
}, [onClosed, calcUsers]) }, [onClosed, calcUsers])
@ -135,16 +143,14 @@ export const CategoryEditor = memo(({ idWell, visible, category, onClosed }) =>
width={1000} width={1000}
visible={visible} visible={visible}
footer={null} footer={null}
onCancel={onModalCanceled} onCancel={onModalClosed}
title={`Редактирование категории ${title}`} title={`Редактирование пользователей категории ${title}`}
> >
<div> <div>
<Input.Search <Input.Search
allowClear allowClear
placeholder={'Поиск пользователя'} placeholder={'Поиск пользователя'}
onChange={(e) => onSearchTextChange(e?.target?.value)} onChange={onSearchTextChange}
onSearch={(text) => calcFilteredUsers(text, users)}
value={searchValue}
style={{ marginBottom: '15px' }} style={{ marginBottom: '15px' }}
/> />
<LoaderPortal show={showLoader}> <LoaderPortal show={showLoader}>