[Glitch] Move account search into hook

Port 7e27ba990e to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
diondiondion
2026-02-06 14:08:29 +01:00
committed by Claire
parent 9eb718836e
commit 8caaffe435
2 changed files with 85 additions and 47 deletions

View File

@@ -1,12 +1,10 @@
import { useCallback, useState, useEffect, useRef } from 'react';
import { useCallback, useState, useEffect } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet';
import { useParams, Link } from 'react-router-dom';
import { useDebouncedCallback } from 'use-debounce';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
import { fetchRelationships } from 'flavours/glitch/actions/accounts';
@@ -14,14 +12,12 @@ import { showAlertForError } from 'flavours/glitch/actions/alerts';
import { importFetchedAccounts } from 'flavours/glitch/actions/importer';
import { fetchList } from 'flavours/glitch/actions/lists';
import { openModal } from 'flavours/glitch/actions/modal';
import { apiRequest } from 'flavours/glitch/api';
import { apiFollowAccount } from 'flavours/glitch/api/accounts';
import {
apiGetAccounts,
apiAddAccountToList,
apiRemoveAccountFromList,
} from 'flavours/glitch/api/lists';
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
import { Avatar } from 'flavours/glitch/components/avatar';
import { Button } from 'flavours/glitch/components/button';
import { Column } from 'flavours/glitch/components/column';
@@ -35,6 +31,8 @@ import { VerifiedBadge } from 'flavours/glitch/components/verified_badge';
import { me } from 'flavours/glitch/initial_state';
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
import { useSearchAccounts } from './use_search_accounts';
export const messages = defineMessages({
manageMembers: {
id: 'column.list_members',
@@ -163,10 +161,23 @@ const ListMembers: React.FC<{
const [searching, setSearching] = useState(false);
const [accountIds, setAccountIds] = useState<string[]>([]);
const [searchAccountIds, setSearchAccountIds] = useState<string[]>([]);
const [loading, setLoading] = useState(!!id);
const [mode, setMode] = useState<Mode>('remove');
const {
accountIds: searchAccountIds = [],
isLoading: loadingSearchResults,
searchAccounts: handleSearch,
} = useSearchAccounts({
onSettled: (value) => {
if (value.trim().length === 0) {
setSearching(false);
} else {
setSearching(true);
}
},
});
useEffect(() => {
if (id) {
dispatch(fetchList(id));
@@ -206,46 +217,6 @@ const ListMembers: React.FC<{
[accountIds, setAccountIds],
);
const searchRequestRef = useRef<AbortController | null>(null);
const handleSearch = useDebouncedCallback(
(value: string) => {
if (searchRequestRef.current) {
searchRequestRef.current.abort();
}
if (value.trim().length === 0) {
setSearching(false);
return;
}
setLoading(true);
searchRequestRef.current = new AbortController();
void apiRequest<ApiAccountJSON[]>('GET', 'v1/accounts/search', {
signal: searchRequestRef.current.signal,
params: {
q: value,
resolve: true,
},
})
.then((data) => {
dispatch(importFetchedAccounts(data));
setSearchAccountIds(data.map((a) => a.id));
setLoading(false);
setSearching(true);
return '';
})
.catch(() => {
setSearching(true);
setLoading(false);
});
},
500,
{ leading: true, trailing: true },
);
let displayedAccountIds: string[];
if (mode === 'add' && searching) {
@@ -279,7 +250,7 @@ const ListMembers: React.FC<{
scrollKey='list_members'
trackScroll={!multiColumn}
bindToDocument={!multiColumn}
isLoading={loading}
isLoading={loading || loadingSearchResults}
showLoading={loading && displayedAccountIds.length === 0}
hasMore={false}
footer={

View File

@@ -0,0 +1,67 @@
import { useRef, useState } from 'react';
import { useDebouncedCallback } from 'use-debounce';
import { importFetchedAccounts } from 'flavours/glitch/actions/importer';
import { apiRequest } from 'flavours/glitch/api';
import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
import { useAppDispatch } from 'flavours/glitch/store';
export function useSearchAccounts({
onSettled,
}: {
onSettled?: (value: string) => void;
} = {}) {
const dispatch = useAppDispatch();
const [accountIds, setAccountIds] = useState<string[]>();
const [loadingState, setLoadingState] = useState<
'idle' | 'loading' | 'error'
>('idle');
const searchRequestRef = useRef<AbortController | null>(null);
const searchAccounts = useDebouncedCallback(
(value: string) => {
if (searchRequestRef.current) {
searchRequestRef.current.abort();
}
if (value.trim().length === 0) {
onSettled?.('');
return;
}
setLoadingState('loading');
searchRequestRef.current = new AbortController();
void apiRequest<ApiAccountJSON[]>('GET', 'v1/accounts/search', {
signal: searchRequestRef.current.signal,
params: {
q: value,
resolve: true,
},
})
.then((data) => {
dispatch(importFetchedAccounts(data));
setAccountIds(data.map((a) => a.id));
setLoadingState('idle');
onSettled?.(value);
})
.catch(() => {
setLoadingState('error');
onSettled?.(value);
});
},
500,
{ leading: true, trailing: true },
);
return {
searchAccounts,
accountIds,
isLoading: loadingState === 'loading',
isError: loadingState === 'error',
};
}