pl-fe: further lists migrations

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2025-07-28 08:14:56 +02:00
parent 822fff36f8
commit 18e67aec72
5 changed files with 30 additions and 93 deletions

View File

@ -1,13 +1,7 @@
import { queryClient } from 'pl-fe/queries/client';
import toast from 'pl-fe/toast';
import { isLoggedIn } from 'pl-fe/utils/auth';
import { getClient } from '../api';
import { importEntities } from './importer';
import type { Account, List } from 'pl-api';
import type { AppDispatch, RootState } from 'pl-fe/store';
import type { List } from 'pl-api';
import type { AppDispatch } from 'pl-fe/store';
const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE' as const;
const LIST_EDITOR_REPLIES_POLICY_CHANGE = 'LIST_EDITOR_REPLIES_POLICY_CHANGE' as const;
@ -15,10 +9,6 @@ const LIST_EDITOR_EXCLUSIVE_CHANGE = 'LIST_EDITOR_EXCLUSIVE_CHANGE' as const;
const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET' as const;
const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP' as const;
const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE' as const;
const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY' as const;
const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR' as const;
interface ListEditorSetupAction {
type: typeof LIST_EDITOR_SETUP;
list: List;
@ -53,39 +43,12 @@ const resetListEditor = () => ({
type: LIST_EDITOR_RESET,
});
const fetchListSuggestions = (q: string) => (dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return;
return getClient(getState()).accounts.searchAccounts(q, { resolve: false, limit: 4, following: true }).then((data) => {
dispatch(importEntities({ accounts: data }));
dispatch(fetchListSuggestionsReady(q, data));
}).catch(error => toast.showAlertForError(error));
};
const fetchListSuggestionsReady = (query: string, accounts: Array<Account>) => ({
type: LIST_EDITOR_SUGGESTIONS_READY,
query,
accounts,
});
const clearListSuggestions = () => ({
type: LIST_EDITOR_SUGGESTIONS_CLEAR,
});
const changeListSuggestions = (value: string) => ({
type: LIST_EDITOR_SUGGESTIONS_CHANGE,
value,
});
type ListsAction =
| ListEditorSetupAction
| ReturnType<typeof changeListEditorTitle>
| ReturnType<typeof changeListEditorRepliesPolicy>
| ReturnType<typeof changeListEditorExclusive>
| ReturnType<typeof resetListEditor>
| ReturnType<typeof fetchListSuggestionsReady>
| ReturnType<typeof clearListSuggestions>
| ReturnType<typeof changeListSuggestions>;
| ReturnType<typeof resetListEditor>;
export {
LIST_EDITOR_TITLE_CHANGE,
@ -93,16 +56,10 @@ export {
LIST_EDITOR_EXCLUSIVE_CHANGE,
LIST_EDITOR_RESET,
LIST_EDITOR_SETUP,
LIST_EDITOR_SUGGESTIONS_CHANGE,
LIST_EDITOR_SUGGESTIONS_READY,
LIST_EDITOR_SUGGESTIONS_CLEAR,
setupListEditor,
changeListEditorTitle,
changeListEditorRepliesPolicy,
changeListEditorExclusive,
resetListEditor,
fetchListSuggestions,
clearListSuggestions,
changeListSuggestions,
type ListsAction,
};

View File

@ -2,39 +2,36 @@ import clsx from 'clsx';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from 'pl-fe/actions/lists';
import Icon from 'pl-fe/components/icon';
import Button from 'pl-fe/components/ui/button';
import Form from 'pl-fe/components/ui/form';
import HStack from 'pl-fe/components/ui/hstack';
import Input from 'pl-fe/components/ui/input';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
const messages = defineMessages({
search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },
searchTitle: { id: 'tabs_bar.search', defaultMessage: 'Search' },
});
const Search = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
interface ISearch {
value: string;
onSubmit: (value: string) => void;
}
const value = useAppSelector((state) => state.listEditor.suggestions.value);
const Search: React.FC<ISearch> = ({ value, onSubmit }) => {
const intl = useIntl();
const [searchValue, setSearchValue] = React.useState(value);
const handleChange: React.ChangeEventHandler<HTMLInputElement> = e => {
dispatch(changeListSuggestions(e.target.value));
setSearchValue(e.target.value);
};
const handleSubmit = () => {
dispatch(fetchListSuggestions(value));
onSubmit(searchValue);
};
const handleClear = () => {
dispatch(clearListSuggestions());
};
const hasValue = value.length > 0;
const hasValue = searchValue.length > 0;
return (
<Form onSubmit={handleSubmit}>
@ -44,11 +41,19 @@ const Search = () => {
<Input
type='text'
value={value}
value={searchValue}
onChange={handleChange}
placeholder={intl.formatMessage(messages.search)}
/>
<div role='button' tabIndex={0} className='absolute inset-y-0 right-0 flex cursor-pointer items-center px-3 rtl:left-0 rtl:right-auto' onClick={handleClear}>
<div
role='button'
tabIndex={0}
className='absolute inset-y-0 right-0 flex cursor-pointer items-center px-3 rtl:left-0 rtl:right-auto'
onClick={() => {
setSearchValue('');
onSubmit('');
}}
>
<Icon src={require('@tabler/icons/outline/backspace.svg')} aria-label={intl.formatMessage(messages.search)} className={clsx('size-5 text-gray-600', { hidden: !hasValue })} />
</div>
</label>

View File

@ -5,8 +5,8 @@ import { setupListEditor, resetListEditor } from 'pl-fe/actions/lists';
import { CardHeader, CardTitle } from 'pl-fe/components/ui/card';
import Modal from 'pl-fe/components/ui/modal';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
import { useListAccounts } from 'pl-fe/queries/accounts/use-lists';
import { useAccountSearch } from 'pl-fe/queries/search/use-search-accounts';
import Account from './components/account';
import EditListForm from './components/edit-list-form';
@ -29,9 +29,10 @@ const ListEditorModal: React.FC<BaseModalProps & ListEditorModalProps> = ({ list
const dispatch = useAppDispatch();
const [tab, setTab] = useState<'info' | 'members'>('info');
const [searchValue, setSearchValue] = useState('');
const { data: accountIds = [] } = useListAccounts(listId);
const searchAccountIds = useAppSelector((state) => state.listEditor.suggestions.items);
const { data: searchAccountIds = [] } = useAccountSearch(searchValue, { following: true, limit: 5 });
useEffect(() => {
dispatch(setupListEditor(listId));
@ -72,7 +73,7 @@ const ListEditorModal: React.FC<BaseModalProps & ListEditorModalProps> = ({ list
<CardHeader>
<CardTitle title={intl.formatMessage(messages.addToList)} />
</CardHeader>
<Search />
<Search value={searchValue} onSubmit={setSearchValue} />
<div className='max-h-48 overflow-y-auto'>
{searchAccountIds.map(accountId => <Account key={accountId} listId={listId} accountId={accountId} added={accountIds.includes(accountId)} />)}
</div>

View File

@ -8,7 +8,7 @@ import type { SearchAccountParams } from 'pl-api';
const useAccountSearch = (
query: string,
params?: Omit<SearchAccountParams, 'limit' | 'offset'>,
params?: Omit<SearchAccountParams, 'offset'>,
) => {
const client = useClient();
const dispatch = useAppDispatch();

View File

@ -4,12 +4,9 @@ import {
LIST_EDITOR_RESET,
LIST_EDITOR_SETUP,
LIST_EDITOR_TITLE_CHANGE,
LIST_EDITOR_SUGGESTIONS_READY,
LIST_EDITOR_SUGGESTIONS_CLEAR,
LIST_EDITOR_SUGGESTIONS_CHANGE,
type ListsAction,
LIST_EDITOR_EXCLUSIVE_CHANGE,
LIST_EDITOR_REPLIES_POLICY_CHANGE,
type ListsAction,
} from '../actions/lists';
import type { List } from 'pl-api';
@ -21,11 +18,6 @@ interface State {
title: string;
repliesPolicy: List['replies_policy'];
exclusive?: boolean;
suggestions: {
value: string;
items: Array<string>;
};
}
const initialState: State = {
@ -34,11 +26,6 @@ const initialState: State = {
title: '',
repliesPolicy: undefined,
exclusive: false,
suggestions: {
value: '',
items: [],
},
};
const listEditorReducer = (state: State = initialState, action: ListsAction): State => {
@ -65,19 +52,6 @@ const listEditorReducer = (state: State = initialState, action: ListsAction): St
return create(state, (draft) => {
draft.repliesPolicy = action.repliesPolicy;
});
case LIST_EDITOR_SUGGESTIONS_CHANGE:
return create(state, (draft) => {
draft.suggestions.value = action.value;
});
case LIST_EDITOR_SUGGESTIONS_READY:
return create(state, (draft) => {
draft.suggestions.items = action.accounts.map((item: { id: string }) => item.id);
});
case LIST_EDITOR_SUGGESTIONS_CLEAR:
return create(state, (draft) => {
draft.suggestions.items = [];
draft.suggestions.value = '';
});
default:
return state;
}