From 68a9140abca8c6645ebbcbf6867e2b0c6945de1b Mon Sep 17 00:00:00 2001 From: David Mzareulyan Date: Tue, 3 Dec 2024 20:27:36 +0300 Subject: [PATCH 1/2] Handle the 'fetchOptions' action field in the apiMiddleware --- src/redux/middlewares.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/redux/middlewares.js b/src/redux/middlewares.js index 26440d3a..dcb28e99 100644 --- a/src/redux/middlewares.js +++ b/src/redux/middlewares.js @@ -174,9 +174,9 @@ export const apiMiddleware = (store) => (next) => async (action) => { //dispatch request begin action //clean apiRequest to not get caught by this middleware - store.dispatch({ ...action, type: request(action.type), apiRequest: null }); + store.dispatch({ ...action, type: request(action.type), apiRequest: null, fetchOptions: null }); try { - const apiResponse = await action.apiRequest(action.payload); + const apiResponse = await action.apiRequest(action.payload, action.fetchOptions); const obj = await apiResponse.json(); if (apiResponse.status >= 200 && apiResponse.status < 300) { From 3f713621386d49399e321210e9374b01348e2c68 Mon Sep 17 00:00:00 2001 From: David Mzareulyan Date: Tue, 3 Dec 2024 20:28:14 +0300 Subject: [PATCH 2/2] Query the server for autocomplete during type --- CHANGELOG.md | 3 +++ src/components/autocomplete/selector.jsx | 33 ++++++++++++++---------- src/redux/action-creators.js | 3 ++- src/services/api.js | 10 +++---- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bab1445..e834492d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.137.0] - Not released +### Changed +- The autocomplete is now queries server during typing. It allows to show exact + matches of private users and groups. ## [1.136.0] - 2024-11-08 ### Changed diff --git a/src/components/autocomplete/selector.jsx b/src/components/autocomplete/selector.jsx index 740c32d1..182f3df4 100644 --- a/src/components/autocomplete/selector.jsx +++ b/src/components/autocomplete/selector.jsx @@ -1,7 +1,7 @@ import { useDispatch, useSelector, useStore } from 'react-redux'; import { Link } from 'react-router'; import cn from 'classnames'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useEvent } from 'react-use-event-hook'; import { faExternalLinkAlt, faUserFriends } from '@fortawesome/free-solid-svg-icons'; import { Finder } from '../../utils/sparse-match'; @@ -23,19 +23,8 @@ import { export function Selector({ query, events, onSelect, context, localLinks = false }) { query = query.toLowerCase(); - const dispatch = useDispatch(); const [usernames, accountsMap, compare] = useAccountsMap({ context }); - - // Request all users/groups when query longer than 2 chars - const lastQuery = useRef(''); - useEffect(() => { - const lc = lastQuery.current; - if (query.length < 2 || (lc && query.slice(0, lc.length) === lc)) { - return; - } - lastQuery.current = query; - dispatch(getMatchedUsers(query)); - }, [dispatch, query]); + useUsersRequest(query); const matches = useMemo(() => { const compareWithExact = (a, b) => { @@ -196,3 +185,21 @@ function useAccountsMap({ context }) { return [[...accountsMap.keys()], accountsMap, compare]; }, [context, post, store, lastAutocompleteQuery]); } + +function useUsersRequest(query) { + const dispatch = useDispatch(); + + useEffect(() => { + if (query.length < 2) { + return; + } + + const abortController = new AbortController(); + const { signal } = abortController; + + const t = setTimeout(() => dispatch(getMatchedUsers(query, { signal })), 500); + signal.addEventListener('abort', () => clearTimeout(t)); + + return () => abortController.abort(); + }, [query, dispatch]); +} diff --git a/src/redux/action-creators.js b/src/redux/action-creators.js index bcd9326e..c31b83e9 100644 --- a/src/redux/action-creators.js +++ b/src/redux/action-creators.js @@ -1396,10 +1396,11 @@ export function unlockComment(id) { }; } -export function getMatchedUsers(query) { +export function getMatchedUsers(query, fetchOptions) { return { type: ActionTypes.GET_MATCHED_USERS, apiRequest: Api.getMatchedUsers, payload: { query }, + fetchOptions, }; } diff --git a/src/services/api.js b/src/services/api.js index d748f688..56e6326f 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -841,9 +841,9 @@ export function notifyOfAllComments({ postId, enabled }) { ); } -export function getMatchedUsers({ query }) { - return fetch( - `${apiPrefix}/users/sparseMatches?qs=${encodeURIComponent(query)}`, - getRequestOptions(), - ); +export function getMatchedUsers({ query }, fetchOptions = {}) { + return fetch(`${apiPrefix}/users/sparseMatches?qs=${encodeURIComponent(query)}`, { + ...getRequestOptions(), + ...fetchOptions, + }); }