Fix `createDataLoadingThunk` and related actions (#30408)

shrike
Renaud Chaput 2024-05-23 20:22:42 +02:00 committed by GitHub
parent 133d98fb25
commit b6fd14f0e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 41 additions and 35 deletions

View File

@ -3,7 +3,8 @@ import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
export const submitAccountNote = createDataLoadingThunk(
'account_note/submit',
(accountId: string, note: string) => apiSubmitAccountNote(accountId, note),
({ accountId, note }: { accountId: string; note: string }) =>
apiSubmitAccountNote(accountId, note),
(relationship) => ({ relationship }),
{ skipLoading: true },
);

View File

@ -6,8 +6,13 @@ import { importFetchedStatus } from './importer';
export const reblog = createDataLoadingThunk(
'status/reblog',
(statusId: string, visibility: StatusVisibility) =>
apiReblog(statusId, visibility),
({
statusId,
visibility,
}: {
statusId: string;
visibility: StatusVisibility;
}) => apiReblog(statusId, visibility),
(data, { dispatch, discardLoadData }) => {
// The reblog API method returns a new status wrapped around the original. In this case we are only
// interested in how the original is modified, hence passing it skipping the wrapper
@ -20,7 +25,7 @@ export const reblog = createDataLoadingThunk(
export const unreblog = createDataLoadingThunk(
'status/unreblog',
(statusId: string) => apiUnreblog(statusId),
({ statusId }: { statusId: string }) => apiUnreblog(statusId),
(data, { dispatch, discardLoadData }) => {
dispatch(importFetchedStatus(data));

View File

@ -62,12 +62,12 @@ export default function api(withAuthorization = true) {
export async function apiRequest<ApiResponse = unknown>(
method: Method,
url: string,
params?: unknown,
params?: Record<string, unknown>,
) {
const { data } = await api().request<ApiResponse>({
method,
url,
params,
url: '/api/' + url,
data: params,
});
return data;

View File

@ -2,6 +2,6 @@ import { apiRequest } from 'mastodon/api';
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
export const apiSubmitAccountNote = (id: string, value: string) =>
apiRequest<ApiRelationshipJSON>('post', `/api/v1/accounts/${id}/note`, {
apiRequest<ApiRelationshipJSON>('post', `v1/accounts/${id}/note`, {
comment: value,
});

View File

@ -96,9 +96,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
onModalReblog (status, privacy) {
if (status.get('reblogged')) {
dispatch(unreblog(status.id));
dispatch(unreblog({ statusId: status.get('id') }));
} else {
dispatch(reblog(status.id, privacy));
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
}
},

View File

@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({
const mapDispatchToProps = (dispatch, { account }) => ({
onSave (value) {
dispatch(submitAccountNote(account.get('id'), value));
dispatch(submitAccountNote({ accountId: account.get('id'), note: value }));
},
});

View File

@ -39,12 +39,12 @@ const mapDispatchToProps = dispatch => ({
},
onModalReblog (status, privacy) {
dispatch(reblog(status.id, privacy));
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
},
onReblog (status, e) {
if (status.get('reblogged')) {
dispatch(unreblog(status.id));
dispatch(unreblog({ statusId: status.get('id') }));
} else {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status);

View File

@ -123,7 +123,7 @@ class Footer extends ImmutablePureComponent {
_performReblog = (status, privacy) => {
const { dispatch } = this.props;
dispatch(reblog(status.id, privacy));
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
};
handleReblogClick = e => {
@ -132,7 +132,7 @@ class Footer extends ImmutablePureComponent {
if (signedIn) {
if (status.get('reblogged')) {
dispatch(unreblog(status.id));
dispatch(unreblog({ statusId: status.get('id') }));
} else if ((e && e.shiftKey) || !boostModal) {
this._performReblog(status);
} else {

View File

@ -74,12 +74,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
onModalReblog (status, privacy) {
dispatch(reblog(status.id, privacy));
dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
},
onReblog (status, e) {
if (status.get('reblogged')) {
dispatch(unreblog(status.id));
dispatch(unreblog({ statusId: status.get('id') }));
} else {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status);

View File

@ -299,7 +299,7 @@ class Status extends ImmutablePureComponent {
};
handleModalReblog = (status, privacy) => {
this.props.dispatch(reblog(status.id, privacy));
this.props.dispatch(reblog({ statusId: status.get('id'), visibility: privacy }));
};
handleReblogClick = (status, e) => {
@ -308,7 +308,7 @@ class Status extends ImmutablePureComponent {
if (signedIn) {
if (status.get('reblogged')) {
dispatch(unreblog(status.id));
dispatch(unreblog({ statusId: status.get('id') }));
} else {
if ((e && e.shiftKey) || !boostModal) {
this.handleModalReblog(status);

View File

@ -122,13 +122,13 @@ export default function statuses(state = initialState, action) {
return statusTranslateUndo(state, action.id);
default:
if(reblog.pending.match(action))
return state.setIn([action.meta.params.statusId, 'reblogged'], true);
return state.setIn([action.meta.arg.statusId, 'reblogged'], true);
else if(reblog.rejected.match(action))
return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], false);
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], false);
else if(unreblog.pending.match(action))
return state.setIn([action.meta.params.statusId, 'reblogged'], false);
return state.setIn([action.meta.arg.statusId, 'reblogged'], false);
else if(unreblog.rejected.match(action))
return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], true);
return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], true);
else
return state;
}

View File

@ -92,20 +92,20 @@ type OnData<LoadDataResult, ReturnedData> = (
// Overload when there is no `onData` method, the payload is the `onData` result
export function createDataLoadingThunk<
LoadDataResult,
Args extends readonly unknown[],
Args extends Record<string, unknown>,
>(
name: string,
loadData: (...args: Args) => Promise<LoadDataResult>,
loadData: (args: Args) => Promise<LoadDataResult>,
thunkOptions?: AppThunkOptions,
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty
export function createDataLoadingThunk<
LoadDataResult,
Args extends readonly unknown[],
Args extends Record<string, unknown>,
>(
name: string,
loadData: (...args: Args) => Promise<LoadDataResult>,
loadData: (args: Args) => Promise<LoadDataResult>,
onDataOrThunkOptions?:
| AppThunkOptions
| OnData<LoadDataResult, DiscardLoadData>,
@ -115,10 +115,10 @@ export function createDataLoadingThunk<
// Overload when the `onData` method returns nothing, then the mayload is the `onData` result
export function createDataLoadingThunk<
LoadDataResult,
Args extends readonly unknown[],
Args extends Record<string, unknown>,
>(
name: string,
loadData: (...args: Args) => Promise<LoadDataResult>,
loadData: (args: Args) => Promise<LoadDataResult>,
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, void>,
thunkOptions?: AppThunkOptions,
): ReturnType<typeof createThunk<Args, LoadDataResult>>;
@ -126,11 +126,11 @@ export function createDataLoadingThunk<
// Overload when there is an `onData` method returning something
export function createDataLoadingThunk<
LoadDataResult,
Args extends readonly unknown[],
Args extends Record<string, unknown>,
Returned,
>(
name: string,
loadData: (...args: Args) => Promise<LoadDataResult>,
loadData: (args: Args) => Promise<LoadDataResult>,
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
thunkOptions?: AppThunkOptions,
): ReturnType<typeof createThunk<Args, Returned>>;
@ -142,7 +142,7 @@ export function createDataLoadingThunk<
*
* It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk)
* @param name Prefix for the actions types
* @param loadData Function that loads the data. It's arguments will become the thunk's arguments
* @param loadData Function that loads the data. It's (object) argument will become the thunk's argument
* @param onDataOrThunkOptions
* Callback called on the results from `loadData`.
*
@ -162,11 +162,11 @@ export function createDataLoadingThunk<
*/
export function createDataLoadingThunk<
LoadDataResult,
Args extends readonly unknown[],
Args extends Record<string, unknown>,
Returned,
>(
name: string,
loadData: (...args: Args) => Promise<LoadDataResult>,
loadData: (args: Args) => Promise<LoadDataResult>,
onDataOrThunkOptions?: AppThunkOptions | OnData<LoadDataResult, Returned>,
maybeThunkOptions?: AppThunkOptions,
) {
@ -184,7 +184,7 @@ export function createDataLoadingThunk<
return createThunk<Args, Returned>(
name,
async (arg, { getState, dispatch }) => {
const data = await loadData(...arg);
const data = await loadData(arg);
if (!onData) return data as Returned;