pl-fe: further lists migrations
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -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,
|
||||
};
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user