diff --git a/packages/pl-api/lib/entities/status.ts b/packages/pl-api/lib/entities/status.ts index 4512e8062..69dc9e2b4 100644 --- a/packages/pl-api/lib/entities/status.ts +++ b/packages/pl-api/lib/entities/status.ts @@ -1,7 +1,7 @@ import pick from 'lodash.pick'; import { z } from 'zod'; -import { accountSchema } from './account'; +import { type Account, accountSchema } from './account'; import { customEmojiSchema } from './custom-emoji'; import { emojiReactionSchema } from './emoji-reaction'; import { filterResultSchema } from './filter-result'; @@ -147,9 +147,15 @@ const statusWithoutAccountSchema = z.preprocess(preprocess, baseStatusSchema.omi quote: z.lazy(() => statusSchema).nullable().catch(null), })); +type StatusWithoutAccount = Omit, 'account'> & { + account: Account | null; + reblog: Status | null; + quote: Status | null; +} + type Status = z.infer & { reblog: Status | null; quote: Status | null; } -export { statusSchema, statusWithoutAccountSchema, type Status }; +export { statusSchema, statusWithoutAccountSchema, type Status, type StatusWithoutAccount }; diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index c558fb1b3..134ad20ce 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -60,7 +60,7 @@ "@reach/popover": "^0.18.0", "@reach/rect": "^0.18.0", "@reach/tabs": "^0.18.0", - "@reduxjs/toolkit": "^2.2.7", + "@reduxjs/toolkit": "^2.0.1", "@sentry/browser": "^7.74.1", "@sentry/react": "^7.74.1", "@tabler/icons": "^3.18.0", @@ -121,7 +121,7 @@ "react-inlinesvg": "^4.0.0", "react-intl": "^6.7.0", "react-motion": "^0.5.2", - "react-redux": "^9.1.2", + "react-redux": "^9.0.4", "react-router-dom": "^5.3.4", "react-router-dom-v5-compat": "^6.24.1", "react-router-scroll-4": "^1.0.0-beta.2", @@ -129,7 +129,7 @@ "react-sparklines": "^1.7.0", "react-sticky-box": "^2.0.0", "react-swipeable-views": "^0.14.0", - "redux": "^5.0.1", + "redux": "^5.0.0", "redux-immutable": "^4.0.0", "redux-thunk": "^3.1.0", "reselect": "^5.0.0", diff --git a/packages/pl-fe/src/actions/about.ts b/packages/pl-fe/src/actions/about.ts index a1927d1da..c2237403a 100644 --- a/packages/pl-fe/src/actions/about.ts +++ b/packages/pl-fe/src/actions/about.ts @@ -1,4 +1,4 @@ -import { staticFetch } from '../api'; +import { staticFetch } from 'pl-fe/api'; import type { RootState } from 'pl-fe/store'; import type { AnyAction } from 'redux'; diff --git a/packages/pl-fe/src/actions/account-notes.ts b/packages/pl-fe/src/actions/account-notes.ts index 31159ee94..98794dd69 100644 --- a/packages/pl-fe/src/actions/account-notes.ts +++ b/packages/pl-fe/src/actions/account-notes.ts @@ -1,42 +1,13 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/entity-store/actions'; +import { Entities } from 'pl-fe/entity-store/entities'; import type { RootState } from 'pl-fe/store'; import type { AnyAction } from 'redux'; -const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST' as const; -const ACCOUNT_NOTE_SUBMIT_SUCCESS = 'ACCOUNT_NOTE_SUBMIT_SUCCESS' as const; -const ACCOUNT_NOTE_SUBMIT_FAIL = 'ACCOUNT_NOTE_SUBMIT_FAIL' as const; - const submitAccountNote = (accountId: string, value: string) => - (dispatch: React.Dispatch, getState: () => RootState) => { - dispatch(submitAccountNoteRequest(accountId)); + (dispatch: React.Dispatch, getState: () => RootState) => + getClient(getState).accounts.updateAccountNote(accountId, value) + .then(response => dispatch(importEntities([response], Entities.RELATIONSHIPS))); - return getClient(getState).accounts.updateAccountNote(accountId, value) - .then(response => { - dispatch(submitAccountNoteSuccess(response)); - }).catch(error => dispatch(submitAccountNoteFail(accountId, error))); - }; - -const submitAccountNoteRequest = (accountId: string) => ({ - type: ACCOUNT_NOTE_SUBMIT_REQUEST, - accountId, -}); - -const submitAccountNoteSuccess = (relationship: any) => ({ - type: ACCOUNT_NOTE_SUBMIT_SUCCESS, - accountId: relationship.id, - relationship, -}); - -const submitAccountNoteFail = (accountId: string, error: unknown) => ({ - type: ACCOUNT_NOTE_SUBMIT_FAIL, - accountId, - error, -}); - -export { - submitAccountNote, - ACCOUNT_NOTE_SUBMIT_REQUEST, - ACCOUNT_NOTE_SUBMIT_SUCCESS, - ACCOUNT_NOTE_SUBMIT_FAIL, -}; +export { submitAccountNote }; diff --git a/packages/pl-fe/src/actions/accounts.ts b/packages/pl-fe/src/actions/accounts.ts index 0f8e72805..f52b6002e 100644 --- a/packages/pl-fe/src/actions/accounts.ts +++ b/packages/pl-fe/src/actions/accounts.ts @@ -1,11 +1,11 @@ import { PLEROMA, type UpdateNotificationSettingsParams, type Account, type CreateAccountParams, type PaginatedResponse, type Relationship } from 'pl-api'; +import { getClient, type PlfeResponse } from 'pl-fe/api'; +import { Entities } from 'pl-fe/entity-store/entities'; import { importEntities } from 'pl-fe/pl-hooks/importer'; import { selectAccount } from 'pl-fe/selectors'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient, type PlfeResponse } from '../api'; - import type { Map as ImmutableMap } from 'immutable'; import type { MinifiedStatus } from 'pl-fe/reducers/statuses'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -23,30 +23,10 @@ const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST' as const; const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS' as const; const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL' as const; -const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST' as const; -const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS' as const; -const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL' as const; - const ACCOUNT_MUTE_REQUEST = 'ACCOUNT_MUTE_REQUEST' as const; const ACCOUNT_MUTE_SUCCESS = 'ACCOUNT_MUTE_SUCCESS' as const; const ACCOUNT_MUTE_FAIL = 'ACCOUNT_MUTE_FAIL' as const; -const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST' as const; -const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS' as const; -const ACCOUNT_UNMUTE_FAIL = 'ACCOUNT_UNMUTE_FAIL' as const; - -const ACCOUNT_PIN_REQUEST = 'ACCOUNT_PIN_REQUEST' as const; -const ACCOUNT_PIN_SUCCESS = 'ACCOUNT_PIN_SUCCESS' as const; -const ACCOUNT_PIN_FAIL = 'ACCOUNT_PIN_FAIL' as const; - -const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST' as const; -const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS' as const; -const ACCOUNT_UNPIN_FAIL = 'ACCOUNT_UNPIN_FAIL' as const; - -const ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST = 'ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST' as const; -const ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS = 'ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS' as const; -const ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL = 'ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL' as const; - const PINNED_ACCOUNTS_FETCH_REQUEST = 'PINNED_ACCOUNTS_FETCH_REQUEST' as const; const PINNED_ACCOUNTS_FETCH_SUCCESS = 'PINNED_ACCOUNTS_FETCH_SUCCESS' as const; const PINNED_ACCOUNTS_FETCH_FAIL = 'PINNED_ACCOUNTS_FETCH_FAIL' as const; @@ -59,10 +39,6 @@ const ACCOUNT_LOOKUP_REQUEST = 'ACCOUNT_LOOKUP_REQUEST' as const; const ACCOUNT_LOOKUP_SUCCESS = 'ACCOUNT_LOOKUP_SUCCESS' as const; const ACCOUNT_LOOKUP_FAIL = 'ACCOUNT_LOOKUP_FAIL' as const; -const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST' as const; -const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS' as const; -const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL' as const; - const FOLLOW_REQUESTS_FETCH_REQUEST = 'FOLLOW_REQUESTS_FETCH_REQUEST' as const; const FOLLOW_REQUESTS_FETCH_SUCCESS = 'FOLLOW_REQUESTS_FETCH_SUCCESS' as const; const FOLLOW_REQUESTS_FETCH_FAIL = 'FOLLOW_REQUESTS_FETCH_FAIL' as const; @@ -87,10 +63,6 @@ const BIRTHDAY_REMINDERS_FETCH_REQUEST = 'BIRTHDAY_REMINDERS_FETCH_REQUEST' as c const BIRTHDAY_REMINDERS_FETCH_SUCCESS = 'BIRTHDAY_REMINDERS_FETCH_SUCCESS' as const; const BIRTHDAY_REMINDERS_FETCH_FAIL = 'BIRTHDAY_REMINDERS_FETCH_FAIL' as const; -const ACCOUNT_BITE_REQUEST = 'ACCOUNT_BITE_REQUEST' as const; -const ACCOUNT_BITE_SUCCESS = 'ACCOUNT_BITE_SUCCESS' as const; -const ACCOUNT_BITE_FAIL = 'ACCOUNT_BITE_FAIL' as const; - const maybeRedirectLogin = (error: { response: PlfeResponse }, history?: History) => { // The client is unauthorized - redirect to login. if (history && error?.response?.status === 401) { @@ -205,14 +177,8 @@ const unblockAccount = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; - dispatch(unblockAccountRequest(accountId)); - return getClient(getState).filtering.unblockAccount(accountId) - .then(response => { - importEntities({ relationships: [response] }); - return dispatch(unblockAccountSuccess(response)); - }) - .catch(error => dispatch(unblockAccountFail(error))); + .then(response => importEntities({ relationships: [response] })); }; const blockAccountRequest = (accountId: string) => ({ @@ -231,21 +197,6 @@ const blockAccountFail = (error: unknown) => ({ error, }); -const unblockAccountRequest = (accountId: string) => ({ - type: ACCOUNT_UNBLOCK_REQUEST, - accountId, -}); - -const unblockAccountSuccess = (relationship: Relationship) => ({ - type: ACCOUNT_UNBLOCK_SUCCESS, - relationship, -}); - -const unblockAccountFail = (error: unknown) => ({ - type: ACCOUNT_UNBLOCK_FAIL, - error, -}); - const muteAccount = (accountId: string, notifications?: boolean, duration = 0) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; @@ -281,14 +232,8 @@ const unmuteAccount = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; - dispatch(unmuteAccountRequest(accountId)); - return getClient(getState()).filtering.unmuteAccount(accountId) - .then(response => { - importEntities({ relationships: [response] }); - return dispatch(unmuteAccountSuccess(response)); - }) - .catch(error => dispatch(unmuteAccountFail(accountId, error))); + .then(response => importEntities({ relationships: [response] })); }; const muteAccountRequest = (accountId: string) => ({ @@ -308,85 +253,29 @@ const muteAccountFail = (accountId: string, error: unknown) => ({ error, }); -const unmuteAccountRequest = (accountId: string) => ({ - type: ACCOUNT_UNMUTE_REQUEST, - accountId, -}); - -const unmuteAccountSuccess = (relationship: Relationship) => ({ - type: ACCOUNT_UNMUTE_SUCCESS, - relationship, -}); - -const unmuteAccountFail = (accountId: string, error: unknown) => ({ - type: ACCOUNT_UNMUTE_FAIL, - accountId, - error, -}); - const removeFromFollowers = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; - dispatch(removeFromFollowersRequest(accountId)); - return getClient(getState()).accounts.removeAccountFromFollowers(accountId) - .then(response => dispatch(removeFromFollowersSuccess(response))) - .catch(error => dispatch(removeFromFollowersFail(accountId, error))); + .then(response => importEntities({ relationships: [response] })); }; -const removeFromFollowersRequest = (accountId: string) => ({ - type: ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST, - accountId, -}); - -const removeFromFollowersSuccess = (relationship: Relationship) => ({ - type: ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS, - relationship, -}); - -const removeFromFollowersFail = (accountId: string, error: unknown) => ({ - type: ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL, - accountId, - error, -}); - const fetchRelationships = (accountIds: string[]) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; - const loadedRelationships = getState().relationships; - const newAccountIds = accountIds.filter(id => loadedRelationships.get(id, null) === null); + const loadedRelationships = getState().entities[Entities.RELATIONSHIPS]?.store; + const newAccountIds = accountIds.filter(id => !loadedRelationships?.[id]); if (newAccountIds.length === 0) { return null; } - dispatch(fetchRelationshipsRequest(newAccountIds)); - return getClient(getState()).accounts.getRelationships(newAccountIds) - .then(response => { - importEntities({ relationships: response }); - dispatch(fetchRelationshipsSuccess(response)); - }) - .catch(error => dispatch(fetchRelationshipsFail(error))); + .then(response => importEntities({ relationships: response })); }; -const fetchRelationshipsRequest = (accountIds: string[]) => ({ - type: RELATIONSHIPS_FETCH_REQUEST, - accountIds, -}); - -const fetchRelationshipsSuccess = (relationships: Array) => ({ - type: RELATIONSHIPS_FETCH_SUCCESS, - relationships, -}); - -const fetchRelationshipsFail = (error: unknown) => ({ - type: RELATIONSHIPS_FETCH_FAIL, - error, -}); - const fetchFollowRequests = () => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return null; @@ -505,26 +394,16 @@ const pinAccount = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return dispatch(noOp); - dispatch(pinAccountRequest(accountId)); - - return getClient(getState).accounts.pinAccount(accountId).then(response => { - dispatch(pinAccountSuccess(response)); - }).catch(error => { - dispatch(pinAccountFail(error)); - }); + return getClient(getState).accounts.pinAccount(accountId) + .then(response => importEntities({ relationships: [response] })); }; const unpinAccount = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return dispatch(noOp); - dispatch(unpinAccountRequest(accountId)); - - return getClient(getState).accounts.unpinAccount(accountId).then(response => { - dispatch(unpinAccountSuccess(response)); - }).catch(error => { - dispatch(unpinAccountFail(error)); - }); + return getClient(getState).accounts.unpinAccount(accountId) + .then(response => importEntities({ relationships: [response] })); }; const updateNotificationSettings = (params: UpdateNotificationSettingsParams) => @@ -538,36 +417,6 @@ const updateNotificationSettings = (params: UpdateNotificationSettingsParams) => }); }; -const pinAccountRequest = (accountId: string) => ({ - type: ACCOUNT_PIN_REQUEST, - accountId, -}); - -const pinAccountSuccess = (relationship: Relationship) => ({ - type: ACCOUNT_PIN_SUCCESS, - relationship, -}); - -const pinAccountFail = (error: unknown) => ({ - type: ACCOUNT_PIN_FAIL, - error, -}); - -const unpinAccountRequest = (accountId: string) => ({ - type: ACCOUNT_UNPIN_REQUEST, - accountId, -}); - -const unpinAccountSuccess = (relationship: Relationship) => ({ - type: ACCOUNT_UNPIN_SUCCESS, - relationship, -}); - -const unpinAccountFail = (error: unknown) => ({ - type: ACCOUNT_UNPIN_FAIL, - error, -}); - const fetchPinnedAccounts = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch(fetchPinnedAccountsRequest(accountId)); @@ -650,33 +499,9 @@ const biteAccount = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { const client = getClient(getState); - dispatch(biteAccountRequest(accountId)); - - return client.accounts.biteAccount(accountId) - .then(() => { - return dispatch(biteAccountSuccess(accountId)); - }) - .catch(error => { - dispatch(biteAccountFail(accountId, error)); - throw error; - }); + return client.accounts.biteAccount(accountId); }; -const biteAccountRequest = (accountId: string) => ({ - type: ACCOUNT_BITE_REQUEST, - accountId, -}); - -const biteAccountSuccess = (accountId: string) => ({ - type: ACCOUNT_BITE_SUCCESS, -}); - -const biteAccountFail = (accountId: string, error: unknown) => ({ - type: ACCOUNT_BITE_FAIL, - accountId, - error, -}); - export { ACCOUNT_CREATE_REQUEST, ACCOUNT_CREATE_SUCCESS, @@ -687,24 +512,9 @@ export { ACCOUNT_BLOCK_REQUEST, ACCOUNT_BLOCK_SUCCESS, ACCOUNT_BLOCK_FAIL, - ACCOUNT_UNBLOCK_REQUEST, - ACCOUNT_UNBLOCK_SUCCESS, - ACCOUNT_UNBLOCK_FAIL, ACCOUNT_MUTE_REQUEST, ACCOUNT_MUTE_SUCCESS, ACCOUNT_MUTE_FAIL, - ACCOUNT_UNMUTE_REQUEST, - ACCOUNT_UNMUTE_SUCCESS, - ACCOUNT_UNMUTE_FAIL, - ACCOUNT_PIN_REQUEST, - ACCOUNT_PIN_SUCCESS, - ACCOUNT_PIN_FAIL, - ACCOUNT_UNPIN_REQUEST, - ACCOUNT_UNPIN_SUCCESS, - ACCOUNT_UNPIN_FAIL, - ACCOUNT_REMOVE_FROM_FOLLOWERS_REQUEST, - ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS, - ACCOUNT_REMOVE_FROM_FOLLOWERS_FAIL, PINNED_ACCOUNTS_FETCH_REQUEST, PINNED_ACCOUNTS_FETCH_SUCCESS, PINNED_ACCOUNTS_FETCH_FAIL, @@ -714,9 +524,6 @@ export { ACCOUNT_LOOKUP_REQUEST, ACCOUNT_LOOKUP_SUCCESS, ACCOUNT_LOOKUP_FAIL, - RELATIONSHIPS_FETCH_REQUEST, - RELATIONSHIPS_FETCH_SUCCESS, - RELATIONSHIPS_FETCH_FAIL, FOLLOW_REQUESTS_FETCH_REQUEST, FOLLOW_REQUESTS_FETCH_SUCCESS, FOLLOW_REQUESTS_FETCH_FAIL, @@ -735,9 +542,6 @@ export { BIRTHDAY_REMINDERS_FETCH_REQUEST, BIRTHDAY_REMINDERS_FETCH_SUCCESS, BIRTHDAY_REMINDERS_FETCH_FAIL, - ACCOUNT_BITE_REQUEST, - ACCOUNT_BITE_SUCCESS, - ACCOUNT_BITE_FAIL, createAccount, fetchAccount, fetchAccountByUsername, @@ -749,25 +553,13 @@ export { blockAccountRequest, blockAccountSuccess, blockAccountFail, - unblockAccountRequest, - unblockAccountSuccess, - unblockAccountFail, muteAccount, unmuteAccount, muteAccountRequest, muteAccountSuccess, muteAccountFail, - unmuteAccountRequest, - unmuteAccountSuccess, - unmuteAccountFail, removeFromFollowers, - removeFromFollowersRequest, - removeFromFollowersSuccess, - removeFromFollowersFail, fetchRelationships, - fetchRelationshipsRequest, - fetchRelationshipsSuccess, - fetchRelationshipsFail, fetchFollowRequests, fetchFollowRequestsRequest, fetchFollowRequestsSuccess, @@ -787,12 +579,6 @@ export { pinAccount, unpinAccount, updateNotificationSettings, - pinAccountRequest, - pinAccountSuccess, - pinAccountFail, - unpinAccountRequest, - unpinAccountSuccess, - unpinAccountFail, fetchPinnedAccounts, fetchPinnedAccountsRequest, fetchPinnedAccountsSuccess, @@ -801,7 +587,4 @@ export { accountLookup, fetchBirthdayReminders, biteAccount, - biteAccountRequest, - biteAccountSuccess, - biteAccountFail, }; diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index 23d11ff07..9f6f3ff8c 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -1,9 +1,8 @@ import { fetchRelationships } from 'pl-fe/actions/accounts'; -import { importFetchedAccount, importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from 'pl-fe/actions/importer'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { filterBadges, getTagDiff } from 'pl-fe/utils/badges'; -import { getClient } from '../api'; - import { deleteFromTimelines } from './timelines'; import type { Account, AdminGetAccountsParams, AdminGetReportsParams, PleromaConfig } from 'pl-api'; @@ -111,9 +110,10 @@ const fetchReports = (params?: AdminGetReportsParams) => return getClient(state).admin.reports.getReports(params) .then(({ items }) => { items.forEach((report) => { - if (report.account?.account) dispatch(importFetchedAccount(report.account.account)); - if (report.target_account?.account) dispatch(importFetchedAccount(report.target_account.account)); - dispatch(importFetchedStatuses(report.statuses)); + const accounts = []; + if (report.account?.account) accounts.push(report.account.account); + if (report.target_account?.account) accounts.push(report.target_account.account); + importEntities({ accounts, statuses: report.statuses }); dispatch({ type: ADMIN_REPORTS_FETCH_SUCCESS, reports: items, params }); }); }).catch(error => { @@ -141,7 +141,8 @@ const fetchUsers = (params?: AdminGetAccountsParams) => dispatch({ type: ADMIN_USERS_FETCH_REQUEST, params }); return getClient(state).admin.accounts.getAccounts(params).then((res) => { - dispatch(importFetchedAccounts(res.items.map(({ account }) => account).filter((account): account is Account => account !== null))); + const accounts = res.items.map(({ account }) => account).filter((account): account is Account => account !== null); + importEntities({ accounts }); dispatch(fetchRelationships(res.items.map((account) => account.id))); dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users: res.items, params, next: res.next }); return res; @@ -203,7 +204,7 @@ const toggleStatusSensitivity = (statusId: string, sensitive: boolean) => dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, statusId }); return getClient(getState).admin.statuses.updateStatus(statusId, { sensitive: !sensitive }) .then((status) => { - dispatch(importFetchedStatus(status)); + importEntities({ statuses: [status] }); dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS, statusId, status }); }).catch(error => { dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, error, statusId }); diff --git a/packages/pl-fe/src/actions/aliases.ts b/packages/pl-fe/src/actions/aliases.ts index c0af413d2..aad1dc396 100644 --- a/packages/pl-fe/src/actions/aliases.ts +++ b/packages/pl-fe/src/actions/aliases.ts @@ -1,12 +1,10 @@ import { defineMessages } from 'react-intl'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { importFetchedAccounts } from './importer'; - import type { Account as BaseAccount } from 'pl-api'; import type { Account } from 'pl-fe/normalizers'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -63,7 +61,7 @@ const fetchAliasesSuggestions = (q: string) => return getClient(getState()).accounts.searchAccounts(q, { resolve: true, limit: 4 }) .then((data) => { - dispatch(importFetchedAccounts(data)); + importEntities({ accounts: data }); dispatch(fetchAliasesSuggestionsReady(q, data)); }).catch(error => toast.showAlertForError(error)); }; diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index a438cef01..efb65ec74 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -14,8 +14,10 @@ import { createApp } from 'pl-fe/actions/apps'; import { fetchMeSuccess, fetchMeFail } from 'pl-fe/actions/me'; import { obtainOAuthToken, revokeOAuthToken } from 'pl-fe/actions/oauth'; import { startOnboarding } from 'pl-fe/actions/onboarding'; +import { type PlfeResponse, getClient } from 'pl-fe/api'; import * as BuildConfig from 'pl-fe/build-config'; import { custom } from 'pl-fe/custom'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { queryClient } from 'pl-fe/queries/client'; import { selectAccount } from 'pl-fe/selectors'; import { unsetSentryAccount } from 'pl-fe/sentry'; @@ -27,10 +29,6 @@ import { normalizeUsername } from 'pl-fe/utils/input'; import { getScopes } from 'pl-fe/utils/scopes'; import { isStandalone } from 'pl-fe/utils/state'; -import { type PlfeResponse, getClient } from '../api'; - -import { importFetchedAccount } from './importer'; - import type { AppDispatch, RootState } from 'pl-fe/store'; const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT' as const; @@ -149,7 +147,7 @@ const verifyCredentials = (token: string, accountUrl?: string) => const client = new PlApiClient(baseURL, token); return client.settings.verifyCredentials().then((account) => { - dispatch(importFetchedAccount(account)); + importEntities({ accounts: [account] }); dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account }); if (account.id === getState().me) dispatch(fetchMeSuccess(account)); return account; @@ -158,7 +156,7 @@ const verifyCredentials = (token: string, accountUrl?: string) => // The user is waitlisted const account = error.response.json; const parsedAccount = credentialAccountSchema.parse(error.response.json); - dispatch(importFetchedAccount(parsedAccount)); + importEntities({ accounts: [parsedAccount] }); dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account: parsedAccount }); if (account.id === getState().me) dispatch(fetchMeSuccess(parsedAccount)); return parsedAccount; @@ -174,7 +172,7 @@ const rememberAuthAccount = (accountUrl: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl }); return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => { - dispatch(importFetchedAccount(account)); + importEntities({ accounts: [account] }); dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl }); if (account.id === getState().me) dispatch(fetchMeSuccess(account)); return account; diff --git a/packages/pl-fe/src/actions/backups.ts b/packages/pl-fe/src/actions/backups.ts index 4a3d85994..f16178f42 100644 --- a/packages/pl-fe/src/actions/backups.ts +++ b/packages/pl-fe/src/actions/backups.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/bookmarks.ts b/packages/pl-fe/src/actions/bookmarks.ts index 276e1b397..f116a5995 100644 --- a/packages/pl-fe/src/actions/bookmarks.ts +++ b/packages/pl-fe/src/actions/bookmarks.ts @@ -1,6 +1,5 @@ -import { getClient } from '../api'; - -import { importFetchedStatuses } from './importer'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import type { PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +23,7 @@ const fetchBookmarkedStatuses = (folderId?: string) => dispatch(fetchBookmarkedStatusesRequest(folderId)); return getClient(getState()).myAccount.getBookmarks({ folder_id: folderId }).then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); return dispatch(fetchBookmarkedStatusesSuccess(response.items, response.next, folderId)); }).catch(error => { dispatch(fetchBookmarkedStatusesFail(error, folderId)); @@ -61,7 +60,7 @@ const expandBookmarkedStatuses = (folderId?: string) => dispatch(expandBookmarkedStatusesRequest(folderId)); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); return dispatch(expandBookmarkedStatusesSuccess(response.items, response.next, folderId)); }).catch(error => { dispatch(expandBookmarkedStatusesFail(error, folderId)); diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index 2e2c10d52..64d6d643f 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -5,6 +5,7 @@ import { getClient } from 'pl-fe/api'; import { isNativeEmoji } from 'pl-fe/features/emoji'; import emojiSearch from 'pl-fe/features/emoji/search'; import { Language } from 'pl-fe/features/preferences'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { selectAccount, selectOwnAccount, makeGetAccount } from 'pl-fe/selectors'; import { tagHistory } from 'pl-fe/settings'; import { useModalsStore } from 'pl-fe/stores'; @@ -12,7 +13,6 @@ import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { chooseEmoji } from './emojis'; -import { importFetchedAccounts } from './importer'; import { rememberLanguageUse } from './languages'; import { uploadFile, updateMedia } from './media'; import { getSettings } from './settings'; @@ -590,7 +590,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, composeId, return getClient(getState).accounts.searchAccounts(token.slice(1), { resolve: false, limit: 10 }, { signal }) .then(response => { - dispatch(importFetchedAccounts(response)); + importEntities({ accounts: response }); dispatch(readyComposeSuggestionsAccounts(composeId, token, response)); }).catch(error => { if (!signal.aborted) { diff --git a/packages/pl-fe/src/actions/conversations.ts b/packages/pl-fe/src/actions/conversations.ts index 3f4a26ba7..adac3b19f 100644 --- a/packages/pl-fe/src/actions/conversations.ts +++ b/packages/pl-fe/src/actions/conversations.ts @@ -1,13 +1,7 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { - importFetchedAccounts, - importFetchedStatuses, - importFetchedStatus, -} from './importer'; - import type { Account, Conversation, PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -48,8 +42,11 @@ const expandConversations = (expand = true) => (dispatch: AppDispatch, getState: return (state.conversations.next?.() || getClient(state).timelines.getConversations()) .then(response => { - dispatch(importFetchedAccounts(response.items.reduce((aggr: Array, item) => aggr.concat(item.accounts), []))); - dispatch(importFetchedStatuses(response.items.map((item) => item.last_status).filter((x): x is Status => x !== null))); + const accounts = response.items.reduce((aggr: Array, item) => aggr.concat(item.accounts), []); + const statuses = response.items.map((item) => item.last_status).filter((x): x is Status => x !== null); + + importEntities({ accounts, statuses }); + dispatch(expandConversationsSuccess(response.items, response.next, isLoadingRecent)); }) .catch(err => dispatch(expandConversationsFail(err))); @@ -74,12 +71,14 @@ const expandConversationsFail = (error: unknown) => ({ }); const updateConversations = (conversation: Conversation) => (dispatch: AppDispatch) => { - dispatch(importFetchedAccounts(conversation.accounts)); + const statuses: Array = []; if (conversation.last_status) { - dispatch(importFetchedStatus(conversation.last_status)); + statuses.push(conversation.last_status); } + importEntities({ accounts: conversation.accounts, statuses }); + return dispatch({ type: CONVERSATIONS_UPDATE, conversation, diff --git a/packages/pl-fe/src/actions/custom-emojis.ts b/packages/pl-fe/src/actions/custom-emojis.ts index f5733b8fc..1e057cc8a 100644 --- a/packages/pl-fe/src/actions/custom-emojis.ts +++ b/packages/pl-fe/src/actions/custom-emojis.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { CustomEmoji } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/directory.ts b/packages/pl-fe/src/actions/directory.ts index 4fecad216..bff0c19ba 100644 --- a/packages/pl-fe/src/actions/directory.ts +++ b/packages/pl-fe/src/actions/directory.ts @@ -1,7 +1,6 @@ +import { getClient } from 'pl-fe/api'; import { importEntities } from 'pl-fe/pl-hooks/importer'; -import { getClient } from '../api'; - import { fetchRelationships } from './accounts'; import type { Account, ProfileDirectoryParams } from 'pl-api'; diff --git a/packages/pl-fe/src/actions/domain-blocks.ts b/packages/pl-fe/src/actions/domain-blocks.ts index 8787c8227..be29cdc8b 100644 --- a/packages/pl-fe/src/actions/domain-blocks.ts +++ b/packages/pl-fe/src/actions/domain-blocks.ts @@ -1,8 +1,7 @@ +import { getClient } from 'pl-fe/api'; import { Entities } from 'pl-fe/entity-store/entities'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - import type { PaginatedResponse } from 'pl-api'; import type { EntityStore } from 'pl-fe/entity-store/types'; import type { Account } from 'pl-fe/normalizers'; @@ -31,6 +30,7 @@ const blockDomain = (domain: string) => dispatch(blockDomainRequest(domain)); return getClient(getState).filtering.blockDomain(domain).then(() => { + // TODO: Update relationships on block const accounts = selectAccountsByDomain(getState(), domain); if (!accounts) return; dispatch(blockDomainSuccess(domain, accounts)); @@ -63,6 +63,7 @@ const unblockDomain = (domain: string) => dispatch(unblockDomainRequest(domain)); return getClient(getState).filtering.unblockDomain(domain).then(() => { + // TODO: Update relationships on unblock const accounts = selectAccountsByDomain(getState(), domain); if (!accounts) return; dispatch(unblockDomainSuccess(domain, accounts)); diff --git a/packages/pl-fe/src/actions/draft-statuses.ts b/packages/pl-fe/src/actions/draft-statuses.ts index 09acdfae5..336121e13 100644 --- a/packages/pl-fe/src/actions/draft-statuses.ts +++ b/packages/pl-fe/src/actions/draft-statuses.ts @@ -5,10 +5,10 @@ import KVStore from 'pl-fe/storage/kv-store'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const DRAFT_STATUSES_FETCH_SUCCESS = 'DRAFT_STATUSES_FETCH_SUCCESS'; +const DRAFT_STATUSES_FETCH_SUCCESS = 'DRAFT_STATUSES_FETCH_SUCCESS' as const; -const PERSIST_DRAFT_STATUS = 'PERSIST_DRAFT_STATUS'; -const CANCEL_DRAFT_STATUS = 'DELETE_DRAFT_STATUS'; +const PERSIST_DRAFT_STATUS = 'PERSIST_DRAFT_STATUS' as const; +const CANCEL_DRAFT_STATUS = 'DELETE_DRAFT_STATUS' as const; const getAccount = makeGetAccount(); diff --git a/packages/pl-fe/src/actions/emoji-reacts.ts b/packages/pl-fe/src/actions/emoji-reacts.ts index 5643b8b8f..54bc4899d 100644 --- a/packages/pl-fe/src/actions/emoji-reacts.ts +++ b/packages/pl-fe/src/actions/emoji-reacts.ts @@ -1,9 +1,7 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { importFetchedStatus } from './importer'; - import type { Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +22,7 @@ const emojiReact = (status: Pick, emoji: string, custom?: string) dispatch(emojiReactRequest(status.id, emoji, custom)); return getClient(getState).statuses.createStatusReaction(status.id, emoji).then((response) => { - dispatch(importFetchedStatus(response)); + importEntities({ statuses: [response] }); dispatch(emojiReactSuccess(response, emoji)); }).catch((error) => { dispatch(emojiReactFail(status.id, emoji, error)); @@ -38,7 +36,7 @@ const unEmojiReact = (status: Pick, emoji: string) => dispatch(unEmojiReactRequest(status.id, emoji)); return getClient(getState).statuses.deleteStatusReaction(status.id, emoji).then(response => { - dispatch(importFetchedStatus(response)); + importEntities({ statuses: [response] }); dispatch(unEmojiReactSuccess(response, emoji)); }).catch(error => { dispatch(unEmojiReactFail(status.id, emoji, error)); diff --git a/packages/pl-fe/src/actions/events.ts b/packages/pl-fe/src/actions/events.ts index 1ac8520db..515646a71 100644 --- a/packages/pl-fe/src/actions/events.ts +++ b/packages/pl-fe/src/actions/events.ts @@ -1,13 +1,11 @@ import { defineMessages } from 'react-intl'; +import { STATUS_FETCH_SOURCE_FAIL, STATUS_FETCH_SOURCE_REQUEST, STATUS_FETCH_SOURCE_SUCCESS } from 'pl-fe/actions/statuses'; import { getClient } from 'pl-fe/api'; import { importEntities } from 'pl-fe/pl-hooks/importer'; import { useModalsStore } from 'pl-fe/stores'; import toast from 'pl-fe/toast'; -import { importFetchedStatus, importFetchedStatuses } from './importer'; -import { STATUS_FETCH_SOURCE_FAIL, STATUS_FETCH_SOURCE_REQUEST, STATUS_FETCH_SOURCE_SUCCESS } from './statuses'; - import type { Account, CreateEventParams, Location, MediaAttachment, PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -133,7 +131,7 @@ const submitEvent = ({ : getClient(state).events.editEvent(statusId, params) ).then((data) => { useModalsStore.getState().closeModal('COMPOSE_EVENT'); - dispatch(importFetchedStatus(data)); + importEntities({ statuses: [data] }); dispatch(submitEventSuccess(data)); toast.success( statusId ? messages.editSuccess : messages.success, @@ -172,7 +170,7 @@ const joinEvent = (statusId: string, participationMessage?: string) => dispatch(joinEventRequest(status.id)); return getClient(getState).events.joinEvent(statusId, participationMessage).then((data) => { - dispatch(importFetchedStatus(data)); + importEntities({ statuses: [data] }); dispatch(joinEventSuccess(status.id)); toast.success( data.event?.join_state === 'pending' ? messages.joinRequestSuccess : messages.joinSuccess, @@ -214,7 +212,7 @@ const leaveEvent = (statusId: string) => dispatch(leaveEventRequest(status.id)); return getClient(getState).events.leaveEvent(statusId).then((data) => { - dispatch(importFetchedStatus(data)); + importEntities({ statuses: [data] }); dispatch(leaveEventSuccess(status.id)); }).catch((error) => { dispatch(leaveEventFail(error, status.id)); @@ -480,7 +478,7 @@ const fetchRecentEvents = () => return getClient(getState()).timelines.publicTimeline({ only_events: true, }).then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch({ type: RECENT_EVENTS_FETCH_SUCCESS, statuses: response.items, @@ -500,7 +498,7 @@ const fetchJoinedEvents = () => dispatch({ type: JOINED_EVENTS_FETCH_REQUEST }); getClient(getState).events.getJoinedEvents().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch({ type: JOINED_EVENTS_FETCH_SUCCESS, statuses: response.items, diff --git a/packages/pl-fe/src/actions/familiar-followers.ts b/packages/pl-fe/src/actions/familiar-followers.ts index d314f9128..404a99259 100644 --- a/packages/pl-fe/src/actions/familiar-followers.ts +++ b/packages/pl-fe/src/actions/familiar-followers.ts @@ -1,8 +1,7 @@ +import { getClient } from 'pl-fe/api'; import { importEntities } from 'pl-fe/pl-hooks/importer'; import { AppDispatch, RootState } from 'pl-fe/store'; -import { getClient } from '../api'; - import { fetchRelationships } from './accounts'; const FAMILIAR_FOLLOWERS_FETCH_REQUEST = 'FAMILIAR_FOLLOWERS_FETCH_REQUEST' as const; diff --git a/packages/pl-fe/src/actions/favourites.ts b/packages/pl-fe/src/actions/favourites.ts index 958e6517b..2ba10fcd5 100644 --- a/packages/pl-fe/src/actions/favourites.ts +++ b/packages/pl-fe/src/actions/favourites.ts @@ -1,9 +1,7 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { importFetchedStatuses } from './importer'; - import type { PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -34,7 +32,7 @@ const fetchFavouritedStatuses = () => dispatch(fetchFavouritedStatusesRequest()); return getClient(getState()).myAccount.getFavourites().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch(fetchFavouritedStatusesSuccess(response.items, response.next)); }).catch(error => { dispatch(fetchFavouritedStatusesFail(error)); @@ -69,7 +67,7 @@ const expandFavouritedStatuses = () => dispatch(expandFavouritedStatusesRequest()); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch(expandFavouritedStatusesSuccess(response.items, response.next)); }).catch(error => { dispatch(expandFavouritedStatusesFail(error)); @@ -102,7 +100,7 @@ const fetchAccountFavouritedStatuses = (accountId: string) => dispatch(fetchAccountFavouritedStatusesRequest(accountId)); return getClient(getState).accounts.getAccountFavourites(accountId).then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch(fetchAccountFavouritedStatusesSuccess(accountId, response.items, response.next)); }).catch(error => { dispatch(fetchAccountFavouritedStatusesFail(accountId, error)); @@ -140,7 +138,7 @@ const expandAccountFavouritedStatuses = (accountId: string) => dispatch(expandAccountFavouritedStatusesRequest(accountId)); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch(expandAccountFavouritedStatusesSuccess(accountId, response.items, response.next)); }).catch(error => { dispatch(expandAccountFavouritedStatusesFail(accountId, error)); diff --git a/packages/pl-fe/src/actions/filters.ts b/packages/pl-fe/src/actions/filters.ts index 1499664ea..0959b10b3 100644 --- a/packages/pl-fe/src/actions/filters.ts +++ b/packages/pl-fe/src/actions/filters.ts @@ -1,10 +1,9 @@ import { defineMessages } from 'react-intl'; +import { getClient } from 'pl-fe/api'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - import type { FilterContext } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/groups.ts b/packages/pl-fe/src/actions/groups.ts index fc8b469db..3c719c877 100644 --- a/packages/pl-fe/src/actions/groups.ts +++ b/packages/pl-fe/src/actions/groups.ts @@ -1,7 +1,6 @@ +import { getClient } from 'pl-fe/api'; import { importEntities } from 'pl-fe/pl-hooks/importer'; -import { getClient } from '../api'; - import type { Account, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/import-data.ts b/packages/pl-fe/src/actions/import-data.ts index b5a01f72b..8fdb9a093 100644 --- a/packages/pl-fe/src/actions/import-data.ts +++ b/packages/pl-fe/src/actions/import-data.ts @@ -1,9 +1,8 @@ import { defineMessages } from 'react-intl'; +import { getClient } from 'pl-fe/api'; import toast from 'pl-fe/toast'; -import { getClient } from '../api'; - import type { RootState } from 'pl-fe/store'; const IMPORT_FOLLOWS_REQUEST = 'IMPORT_FOLLOWS_REQUEST' as const; diff --git a/packages/pl-fe/src/actions/importer/index.ts b/packages/pl-fe/src/actions/importer/index.ts index b205cc4c4..f1d1955ef 100644 --- a/packages/pl-fe/src/actions/importer/index.ts +++ b/packages/pl-fe/src/actions/importer/index.ts @@ -5,14 +5,10 @@ import { normalizeAccount, normalizeGroup, type Account, type Group } from 'pl-f import type { Account as BaseAccount, Group as BaseGroup, Poll, Status as BaseStatus } from 'pl-api'; import type { AppDispatch } from 'pl-fe/store'; -const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT'; -const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT'; const STATUS_IMPORT = 'STATUS_IMPORT'; const STATUSES_IMPORT = 'STATUSES_IMPORT'; const POLLS_IMPORT = 'POLLS_IMPORT'; -const importAccount = (data: BaseAccount) => importAccounts([data]); - const importAccounts = (data: Array) => { let accounts: Array = []; @@ -113,65 +109,19 @@ const isBroken = (status: BaseStatus) => { } }; -const importFetchedStatuses = (statuses: Array & { account: BaseAccount | null }>) => (dispatch: AppDispatch) => { - const accounts: Record = {}; - const normalStatuses: Array = []; - const polls: Array = []; - - const processStatus = (status: BaseStatus) => { - if (status.account === null) return; - // Skip broken statuses - if (isBroken(status)) return; - - normalStatuses.push(status); - - accounts[status.account.id] = status.account; - // if (status.accounts) { - // accounts.push(...status.accounts); - // } - - if (status.reblog?.id) { - processStatus(status.reblog as BaseStatus); - } - - // Fedibird quotes - if (status.quote?.id) { - processStatus(status.quote as BaseStatus); - } - - if (status.poll?.id) { - polls.push(status.poll); - } - }; - - (statuses as Array).forEach(processStatus); - - dispatch(importPolls(polls)); - dispatch(importFetchedAccounts(Object.values(accounts))); - dispatch(importStatuses(normalStatuses)); -}; - const importFetchedPoll = (poll: Poll) => (dispatch: AppDispatch) => { dispatch(importPolls([poll])); }; export { - ACCOUNT_IMPORT, - ACCOUNTS_IMPORT, STATUS_IMPORT, STATUSES_IMPORT, POLLS_IMPORT, - importAccount, importAccounts, - importGroup, importGroups, importStatus, importStatuses, importPolls, - importFetchedAccount, - importFetchedAccounts, importFetchedStatus, - importFetchedStatuses, - importFetchedPoll, }; diff --git a/packages/pl-fe/src/actions/instance.ts b/packages/pl-fe/src/actions/instance.ts index 629db73f8..565f97f45 100644 --- a/packages/pl-fe/src/actions/instance.ts +++ b/packages/pl-fe/src/actions/instance.ts @@ -1,7 +1,6 @@ +import { getClient } from 'pl-fe/api'; import { getAuthUserUrl, getMeUrl } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - import type { Instance } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/interactions.ts b/packages/pl-fe/src/actions/interactions.ts index 2473768e2..81a36c9c8 100644 --- a/packages/pl-fe/src/actions/interactions.ts +++ b/packages/pl-fe/src/actions/interactions.ts @@ -1,12 +1,11 @@ import { defineMessages } from 'react-intl'; +import { getClient } from 'pl-fe/api'; import { importEntities } from 'pl-fe/pl-hooks/importer'; import { useModalsStore } from 'pl-fe/stores'; import toast, { type IToastOptions } from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - import { fetchRelationships } from './accounts'; import type { Account, EmojiReaction, PaginatedResponse, Status } from 'pl-api'; diff --git a/packages/pl-fe/src/actions/lists.ts b/packages/pl-fe/src/actions/lists.ts index df7ba4c0e..502a363a9 100644 --- a/packages/pl-fe/src/actions/lists.ts +++ b/packages/pl-fe/src/actions/lists.ts @@ -1,11 +1,9 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { selectAccount } from 'pl-fe/selectors'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { importFetchedAccounts } from './importer'; - import type { Account, List, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -229,7 +227,7 @@ const fetchListAccounts = (listId: string) => (dispatch: AppDispatch, getState: dispatch(fetchListAccountsRequest(listId)); return getClient(getState()).lists.getListAccounts(listId).then(({ items, next }) => { - dispatch(importFetchedAccounts(items)); + importEntities({ accounts: items }); dispatch(fetchListAccountsSuccess(listId, items, next)); }).catch(err => dispatch(fetchListAccountsFail(listId, err))); }; @@ -256,7 +254,7 @@ const fetchListSuggestions = (q: string) => (dispatch: AppDispatch, getState: () if (!isLoggedIn(getState)) return; return getClient(getState()).accounts.searchAccounts(q, { resolve: false, limit: 4, following: true }).then((data) => { - dispatch(importFetchedAccounts(data)); + importEntities({ accounts: data }); dispatch(fetchListSuggestionsReady(q, data)); }).catch(error => toast.showAlertForError(error)); }; diff --git a/packages/pl-fe/src/actions/markers.ts b/packages/pl-fe/src/actions/markers.ts index 743a54744..988236b73 100644 --- a/packages/pl-fe/src/actions/markers.ts +++ b/packages/pl-fe/src/actions/markers.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { SaveMarkersParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/me.ts b/packages/pl-fe/src/actions/me.ts index 25d5fe41d..0febc7f61 100644 --- a/packages/pl-fe/src/actions/me.ts +++ b/packages/pl-fe/src/actions/me.ts @@ -1,12 +1,11 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { selectAccount } from 'pl-fe/selectors'; import { setSentryAccount } from 'pl-fe/sentry'; import KVStore from 'pl-fe/storage/kv-store'; import { getAuthUserId, getAuthUserUrl } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - import { loadCredentials } from './auth'; -import { importFetchedAccount } from './importer'; import type { CredentialAccount, UpdateCredentialsParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -123,7 +122,7 @@ const patchMeSuccess = (me: CredentialAccount) => me, }; - dispatch(importFetchedAccount(me)); + importEntities({ accounts: [me] }); dispatch(action); }; diff --git a/packages/pl-fe/src/actions/media.ts b/packages/pl-fe/src/actions/media.ts index 7bfd4b293..f70d6f31c 100644 --- a/packages/pl-fe/src/actions/media.ts +++ b/packages/pl-fe/src/actions/media.ts @@ -1,12 +1,11 @@ import { defineMessages, type IntlShape } from 'react-intl'; +import { getClient } from 'pl-fe/api'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { formatBytes, getVideoDuration } from 'pl-fe/utils/media'; import resizeImage from 'pl-fe/utils/resize-image'; -import { getClient } from '../api'; - import type { MediaAttachment, UploadMediaParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/mfa.ts b/packages/pl-fe/src/actions/mfa.ts index dbdad8d8e..9f63d43b0 100644 --- a/packages/pl-fe/src/actions/mfa.ts +++ b/packages/pl-fe/src/actions/mfa.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/notifications.ts b/packages/pl-fe/src/actions/notifications.ts index 201ff4657..a8e8dbad2 100644 --- a/packages/pl-fe/src/actions/notifications.ts +++ b/packages/pl-fe/src/actions/notifications.ts @@ -4,6 +4,7 @@ import { defineMessages } from 'react-intl'; import { getNotificationStatus } from 'pl-fe/features/notifications/components/notification'; import { normalizeNotification } from 'pl-fe/normalizers'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { getFilters, regexFromFilters } from 'pl-fe/selectors'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { compareId } from 'pl-fe/utils/comparators'; @@ -11,14 +12,10 @@ import { unescapeHTML } from 'pl-fe/utils/html'; import { joinPublicPath } from 'pl-fe/utils/static'; import { fetchRelationships } from './accounts'; -import { - importFetchedAccount, - importFetchedStatus, -} from './importer'; import { saveMarker } from './markers'; import { getSettings, saveSettings } from './settings'; -import type { Notification as BaseNotification } from 'pl-api'; +import type { Notification } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE' as const; @@ -54,7 +51,7 @@ defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, }); -const fetchRelatedRelationships = (dispatch: AppDispatch, notifications: Array) => { +const fetchRelatedRelationships = (dispatch: AppDispatch, notifications: Array) => { const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id); if (accountIds.length > 0) { @@ -62,24 +59,11 @@ const fetchRelatedRelationships = (dispatch: AppDispatch, notifications: Array +const updateNotifications = (notification: Notification) => (dispatch: AppDispatch, getState: () => RootState) => { const showInColumn = getSettings(getState()).getIn(['notifications', 'shows', notification.type], true); - if (notification.account) { - dispatch(importFetchedAccount(notification.account)); - } - - // Used by Move notification - if (notification.type === 'move' && notification.target) { - dispatch(importFetchedAccount(notification.target)); - } - - const status = getNotificationStatus(notification); - - if (status) { - dispatch(importFetchedStatus(status)); - } + importEntities({ notifications: [{ ...notification, accounts: [notification.account], duplicate: false }] }); if (showInColumn) { dispatch({ @@ -91,7 +75,7 @@ const updateNotifications = (notification: BaseNotification) => } }; -const updateNotificationsQueue = (notification: BaseNotification, intlMessages: Record, intlLocale: string, curPath: string) => +const updateNotificationsQueue = (notification: Notification, intlMessages: Record, intlLocale: string, curPath: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!notification.type) return; // drop invalid notifications if (notification.type === 'chat_mention') return; // Drop chat notifications, handle them per-chat diff --git a/packages/pl-fe/src/actions/pin-statuses.ts b/packages/pl-fe/src/actions/pin-statuses.ts index 86b18e6b9..f4968f194 100644 --- a/packages/pl-fe/src/actions/pin-statuses.ts +++ b/packages/pl-fe/src/actions/pin-statuses.ts @@ -1,9 +1,7 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import { importFetchedStatuses } from './importer'; - import type { Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -19,7 +17,7 @@ const fetchPinnedStatuses = () => dispatch(fetchPinnedStatusesRequest()); return getClient(getState()).accounts.getAccountStatuses(me as string, { pinned: true }).then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); dispatch(fetchPinnedStatusesSuccess(response.items, null)); }).catch(error => { dispatch(fetchPinnedStatusesFail(error)); diff --git a/packages/pl-fe/src/actions/pl-fe.ts b/packages/pl-fe/src/actions/pl-fe.ts index 899be612c..7a150d263 100644 --- a/packages/pl-fe/src/actions/pl-fe.ts +++ b/packages/pl-fe/src/actions/pl-fe.ts @@ -1,11 +1,10 @@ import { createSelector } from 'reselect'; import { getHost } from 'pl-fe/actions/instance'; +import { getClient, staticFetch } from 'pl-fe/api'; import { normalizePlFeConfig } from 'pl-fe/normalizers'; import KVStore from 'pl-fe/storage/kv-store'; -import { getClient, staticFetch } from '../api'; - import type { AppDispatch, RootState } from 'pl-fe/store'; import type { APIEntity } from 'pl-fe/types/entities'; diff --git a/packages/pl-fe/src/actions/polls.ts b/packages/pl-fe/src/actions/polls.ts index f343be4ec..c913f9ef8 100644 --- a/packages/pl-fe/src/actions/polls.ts +++ b/packages/pl-fe/src/actions/polls.ts @@ -1,6 +1,5 @@ -import { getClient } from '../api'; - -import { importFetchedPoll } from './importer'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import type { Poll } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -18,7 +17,7 @@ const vote = (pollId: string, choices: number[]) => dispatch(voteRequest()); return getClient(getState()).polls.vote(pollId, choices).then((data) => { - dispatch(importFetchedPoll(data)); + importEntities({ polls: [data] }); dispatch(voteSuccess(data)); }).catch(err => dispatch(voteFail(err))); }; @@ -28,7 +27,7 @@ const fetchPoll = (pollId: string) => dispatch(fetchPollRequest()); return getClient(getState()).polls.getPoll(pollId).then((data) => { - dispatch(importFetchedPoll(data)); + importEntities({ polls: [data] }); dispatch(fetchPollSuccess(data)); }).catch(err => dispatch(fetchPollFail(err))); }; diff --git a/packages/pl-fe/src/actions/preload.ts b/packages/pl-fe/src/actions/preload.ts index 4b77263eb..7925046ea 100644 --- a/packages/pl-fe/src/actions/preload.ts +++ b/packages/pl-fe/src/actions/preload.ts @@ -1,7 +1,8 @@ import mapValues from 'lodash/mapValues'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; + import { verifyCredentials } from './auth'; -import { importFetchedAccounts } from './importer'; import type { AppDispatch } from 'pl-fe/store'; @@ -54,7 +55,7 @@ const preloadMastodon = (data: Record) => const { me, access_token } = data.meta; const { url } = data.accounts[me]; - dispatch(importFetchedAccounts(Object.values(data.accounts))); + importEntities({ accounts: Object.values(data.accounts) }); dispatch(verifyCredentials(access_token, url)); dispatch({ type: MASTODON_PRELOAD_IMPORT, data }); }; diff --git a/packages/pl-fe/src/actions/push-subscriptions.ts b/packages/pl-fe/src/actions/push-subscriptions.ts index 306fc5dfc..08d1370ed 100644 --- a/packages/pl-fe/src/actions/push-subscriptions.ts +++ b/packages/pl-fe/src/actions/push-subscriptions.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { CreatePushNotificationsSubscriptionParams, UpdatePushNotificationsSubscriptionParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/reports.ts b/packages/pl-fe/src/actions/reports.ts index c0a1701c6..457403a5a 100644 --- a/packages/pl-fe/src/actions/reports.ts +++ b/packages/pl-fe/src/actions/reports.ts @@ -1,7 +1,6 @@ +import { getClient } from 'pl-fe/api'; import { useModalsStore } from 'pl-fe/stores'; -import { getClient } from '../api'; - import type { Account, Status } from 'pl-fe/normalizers'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/scheduled-statuses.ts b/packages/pl-fe/src/actions/scheduled-statuses.ts index 75da24ddf..6cc32e32b 100644 --- a/packages/pl-fe/src/actions/scheduled-statuses.ts +++ b/packages/pl-fe/src/actions/scheduled-statuses.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { PaginatedResponse, ScheduledStatus } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/search.ts b/packages/pl-fe/src/actions/search.ts index d37c7f469..c7c03ad81 100644 --- a/packages/pl-fe/src/actions/search.ts +++ b/packages/pl-fe/src/actions/search.ts @@ -1,7 +1,7 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts, importFetchedStatuses } from './importer'; import type { Search } from 'pl-api'; import type { SearchFilter } from 'pl-fe/reducers/search'; @@ -52,13 +52,7 @@ const submitSearch = (value: string, filter?: SearchFilter) => if (accountId) params.account_id = accountId; return getClient(getState()).search.search(value, params).then(response => { - if (response.accounts) { - dispatch(importFetchedAccounts(response.accounts)); - } - - if (response.statuses) { - dispatch(importFetchedStatuses(response.statuses)); - } + importEntities({ accounts: response.accounts, statuses: response.statuses, groups: response.groups }); dispatch(fetchSearchSuccess(response, value, type)); dispatch(fetchRelationships(response.accounts.map((item) => item.id))); @@ -110,13 +104,7 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: ( if (accountId) params.account_id = accountId; return getClient(getState()).search.search(value, params).then(response => { - if (response.accounts) { - dispatch(importFetchedAccounts(response.accounts)); - } - - if (response.statuses) { - dispatch(importFetchedStatuses(response.statuses)); - } + importEntities({ accounts: response.accounts, statuses: response.statuses, groups: response.groups }); dispatch(expandSearchSuccess(response, value, type)); dispatch(fetchRelationships(response.accounts.map((item) => item.id))); diff --git a/packages/pl-fe/src/actions/status-quotes.ts b/packages/pl-fe/src/actions/status-quotes.ts index b0669e409..a865e23cd 100644 --- a/packages/pl-fe/src/actions/status-quotes.ts +++ b/packages/pl-fe/src/actions/status-quotes.ts @@ -1,6 +1,5 @@ -import { getClient } from '../api'; - -import { importFetchedStatuses } from './importer'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import type { Status as BaseStatus, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -43,7 +42,7 @@ const fetchStatusQuotes = (statusId: string) => dispatch(action); return getClient(getState).statuses.getStatusQuotes(statusId).then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); const action: FetchStatusQuotesSuccessAction = { type: STATUS_QUOTES_FETCH_SUCCESS, statusId, @@ -94,7 +93,7 @@ const expandStatusQuotes = (statusId: string) => dispatch(action); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + importEntities({ statuses: response.items }); const action: ExpandStatusQuotesSuccessAction = { type: STATUS_QUOTES_EXPAND_SUCCESS, statusId, diff --git a/packages/pl-fe/src/actions/statuses.ts b/packages/pl-fe/src/actions/statuses.ts index 5be8c1341..cd0934ece 100644 --- a/packages/pl-fe/src/actions/statuses.ts +++ b/packages/pl-fe/src/actions/statuses.ts @@ -1,11 +1,11 @@ +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { useModalsStore } from 'pl-fe/stores'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { shouldHaveCard } from 'pl-fe/utils/status'; -import { getClient } from '../api'; - import { setComposeToStatus } from './compose'; -import { importFetchedStatus, importFetchedStatuses } from './importer'; +import { importFetchedStatus } from './importer'; import { getSettings } from './settings'; import { deleteFromTimelines } from './timelines'; @@ -76,7 +76,7 @@ const createStatus = (params: CreateStatusParams, idempotencyKey: string, status const poll = (retries = 5) => { return getClient(getState()).statuses.getStatus(status.id).then(response => { if (response.card) { - dispatch(importFetchedStatus(response)); + importEntities({ statuses: [response] }); } else if (retries > 0 && response) { setTimeout(() => poll(retries - 1), delay); } @@ -119,7 +119,7 @@ const fetchStatus = (statusId: string, intl?: IntlShape) => } : undefined; return getClient(getState()).statuses.getStatus(statusId, params).then(status => { - dispatch(importFetchedStatus(status)); + importEntities({ statuses: [status] }); dispatch({ type: STATUS_FETCH_SUCCESS, status }); return status; }).catch(error => { @@ -153,7 +153,7 @@ const deleteStatus = (statusId: string, withRedraft = false) => }; const updateStatus = (status: BaseStatus) => (dispatch: AppDispatch) => - dispatch(importFetchedStatus(status)); + importEntities({ statuses: [status] }); const fetchContext = (statusId: string, intl?: IntlShape) => (dispatch: AppDispatch, getState: () => RootState) => { @@ -167,7 +167,7 @@ const fetchContext = (statusId: string, intl?: IntlShape) => if (typeof context === 'object') { const { ancestors, descendants } = context; const statuses = ancestors.concat(descendants); - dispatch(importFetchedStatuses(statuses)); + importEntities({ statuses }); dispatch({ type: CONTEXT_FETCH_SUCCESS, statusId, ancestors, descendants }); } else { throw context; diff --git a/packages/pl-fe/src/actions/suggestions.ts b/packages/pl-fe/src/actions/suggestions.ts index 8e8a8a7ad..59baafb7c 100644 --- a/packages/pl-fe/src/actions/suggestions.ts +++ b/packages/pl-fe/src/actions/suggestions.ts @@ -1,7 +1,7 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; import { insertSuggestionsIntoTimeline } from './timelines'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +24,8 @@ const fetchSuggestions = (limit = 50) => return getClient(getState).myAccount.getSuggestions(limit).then((suggestions) => { const accounts = suggestions.map(({ account }) => account); - dispatch(importFetchedAccounts(accounts)); + importEntities({ accounts }); + dispatch({ type: SUGGESTIONS_FETCH_SUCCESS, suggestions }); dispatch(fetchRelationships(accounts.map(({ id }) => id))); diff --git a/packages/pl-fe/src/actions/tags.ts b/packages/pl-fe/src/actions/tags.ts index bb7c6a3b6..72b428440 100644 --- a/packages/pl-fe/src/actions/tags.ts +++ b/packages/pl-fe/src/actions/tags.ts @@ -1,4 +1,4 @@ -import { getClient } from '../api'; +import { getClient } from 'pl-fe/api'; import type { PaginatedResponse, Tag } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; diff --git a/packages/pl-fe/src/actions/timelines.ts b/packages/pl-fe/src/actions/timelines.ts index bf7545367..641fe377f 100644 --- a/packages/pl-fe/src/actions/timelines.ts +++ b/packages/pl-fe/src/actions/timelines.ts @@ -1,12 +1,10 @@ import { Map as ImmutableMap } from 'immutable'; import { getLocale, getSettings } from 'pl-fe/actions/settings'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { shouldFilter } from 'pl-fe/utils/timelines'; -import { getClient } from '../api'; - -import { importFetchedStatus, importFetchedStatuses } from './importer'; - import type { PaginatedResponse, Status as BaseStatus, PublicTimelineParams, HomeTimelineParams, ListTimelineParams, HashtagTimelineParams, GetAccountStatusesParams, GroupTimelineParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -45,7 +43,7 @@ const processTimelineUpdate = (timeline: string, status: BaseStatus) => return; } - dispatch(importFetchedStatus(status)); + importEntities({ statuses: [status] }); if (shouldSkipQueue) { dispatch(updateTimeline(timeline, status.id)); @@ -158,10 +156,9 @@ const handleTimelineExpand = (timelineId: string, fn: Promise { - dispatch(importFetchedStatuses(response.items)); - const statuses = deduplicateStatuses(response.items); - dispatch(importFetchedStatuses(statuses.filter(status => status.accounts))); + + importEntities({ statuses: [...response.items, ...statuses.filter(status => status.accounts)] }); dispatch(expandTimelineSuccess( timelineId, diff --git a/packages/pl-fe/src/actions/trending-statuses.ts b/packages/pl-fe/src/actions/trending-statuses.ts index 692f13241..9534c4e18 100644 --- a/packages/pl-fe/src/actions/trending-statuses.ts +++ b/packages/pl-fe/src/actions/trending-statuses.ts @@ -1,6 +1,5 @@ -import { getClient } from '../api'; - -import { importFetchedStatuses } from './importer'; +import { getClient } from 'pl-fe/api'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -18,7 +17,7 @@ const fetchTrendingStatuses = () => dispatch({ type: TRENDING_STATUSES_FETCH_REQUEST }); return client.trends.getTrendingStatuses().then((statuses) => { - dispatch(importFetchedStatuses(statuses)); + importEntities({ statuses }); dispatch({ type: TRENDING_STATUSES_FETCH_SUCCESS, statuses }); return statuses; }).catch(error => { diff --git a/packages/pl-fe/src/actions/trends.ts b/packages/pl-fe/src/actions/trends.ts index 703b0cd43..ae7f7e01a 100644 --- a/packages/pl-fe/src/actions/trends.ts +++ b/packages/pl-fe/src/actions/trends.ts @@ -1,6 +1,6 @@ import type { Tag } from 'pl-api'; -const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS'; +const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS' as const; const fetchTrendsSuccess = (tags: Array) => ({ type: TRENDS_FETCH_SUCCESS, diff --git a/packages/pl-fe/src/components/status-content.tsx b/packages/pl-fe/src/components/status-content.tsx index b5c68b05e..7186d7609 100644 --- a/packages/pl-fe/src/components/status-content.tsx +++ b/packages/pl-fe/src/components/status-content.tsx @@ -1,7 +1,7 @@ import clsx from 'clsx'; import parse, { Element, type HTMLReactParserOptions, domToReact, type DOMNode } from 'html-react-parser'; import React, { useState, useRef, useLayoutEffect, useMemo, useEffect } from 'react'; -import { FormattedMessage } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import { collapseStatusSpoiler, expandStatusSpoiler } from 'pl-fe/actions/statuses'; diff --git a/packages/pl-fe/src/features/test-timeline/index.tsx b/packages/pl-fe/src/features/test-timeline/index.tsx index 74c8006a0..ac7a8c8e2 100644 --- a/packages/pl-fe/src/features/test-timeline/index.tsx +++ b/packages/pl-fe/src/features/test-timeline/index.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; -import { importFetchedStatuses } from 'pl-fe/actions/importer'; import { expandTimelineSuccess } from 'pl-fe/actions/timelines'; import { useAppDispatch, useTheme } from 'pl-fe/hooks'; import { useIsMobile } from 'pl-fe/hooks/useIsMobile'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { Column } from '../../components/ui'; import Timeline from '../ui/components/timeline'; @@ -35,7 +35,7 @@ const TestTimeline: React.FC = () => { const isMobile = useIsMobile(); React.useEffect(() => { - dispatch(importFetchedStatuses(MOCK_STATUSES)); + importEntities({ statuses: MOCK_STATUSES }); dispatch(expandTimelineSuccess(timelineId, MOCK_STATUSES, null, null, false, false)); }, []); diff --git a/packages/pl-fe/src/features/ui/components/modals/compose-event-modal/upload-button.tsx b/packages/pl-fe/src/features/ui/components/modals/compose-event-modal/upload-button.tsx index 7931b8d32..842ec67a5 100644 --- a/packages/pl-fe/src/features/ui/components/modals/compose-event-modal/upload-button.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/compose-event-modal/upload-button.tsx @@ -29,7 +29,6 @@ const UploadButton: React.FC = ({ disabled, onSelectFile }) => { fileElement.current?.click(); }; - return ( ({ - ...notification, + accounts: [notification.account], duplicate: false, - account: normalizeAccount(notification.account), - account_id: notification.account.id, - accounts: [normalizeAccount(notification.account)], - account_ids: [notification.account.id], + ...notification, }); -const normalizeNotifications = (notifications: Array, stateNotifications?: ImmutableOrderedMap) => { - const deduplicatedNotifications: Notification[] = []; - - for (const notification of notifications) { - const existingNotification = stateNotifications?.get(notification.id); - - // Do not update grouped notifications - if (existingNotification && (existingNotification.duplicate || existingNotification.account_ids.length)) continue; - - if (STATUS_NOTIFICATION_TYPES.includes(notification.type)) { - const existingNotification = deduplicatedNotifications - .find(deduplicated => - deduplicated.type === notification.type - && ((notification.type === 'emoji_reaction' && deduplicated.type === 'emoji_reaction') ? notification.emoji === deduplicated.emoji : true) - && getNotificationStatus(deduplicated)?.id === getNotificationStatus(notification)?.id, - ); - - if (existingNotification) { - existingNotification.accounts.push(normalizeAccount(notification.account)); - existingNotification.account_ids.push(notification.account.id); - deduplicatedNotifications.push({ ...normalizeNotification(notification), duplicate: true }); - } else { - deduplicatedNotifications.push(normalizeNotification(notification)); - } - } else { - deduplicatedNotifications.push(normalizeNotification(notification)); - } - } - - return deduplicatedNotifications; -}; - type Notification = ReturnType; -export { normalizeNotification, normalizeNotifications, type Notification }; +export { normalizeNotification, type Notification }; diff --git a/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotification.ts b/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotification.ts index 9b65e8f37..8274260ff 100644 --- a/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotification.ts +++ b/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotification.ts @@ -1,85 +1,13 @@ import { useQuery } from '@tanstack/react-query'; -import omit from 'lodash/omit'; import { useAppSelector, useClient } from 'pl-fe/hooks'; import { normalizeNotification, type Notification } from 'pl-fe/normalizers'; +import { type MinifiedNotification, minifyNotification } from 'pl-fe/pl-hooks/minifiers/minifyNotification'; import { queryClient } from 'pl-fe/queries/client'; import { selectAccount, selectAccounts } from 'pl-fe/selectors'; -import type { AccountWarning, RelationshipSeveranceEvent } from 'pl-api'; - type Account = ReturnType; -const minifyNotification = (notification: Notification) => { - // @ts-ignore - const minifiedNotification: { - duplicate: boolean; - account_id: string; - account_ids: string[]; - created_at: string; - id: string; - group_key: string; - } & ( - | { type: 'follow' | 'follow_request' | 'admin.sign_up' | 'bite' } - | { - type: 'mention'; - subtype?: 'reply'; - status_id: string; - } - | { - type: 'status' | 'reblog' | 'favourite' | 'poll' | 'update' | 'event_reminder'; - status_id: string; - } - | { - type: 'admin.report'; - report: Report; - } - | { - type: 'severed_relationships'; - relationship_severance_event: RelationshipSeveranceEvent; - } - | { - type: 'moderation_warning'; - moderation_warning: AccountWarning; - } - | { - type: 'move'; - target_id: string; - } - | { - type: 'emoji_reaction'; - emoji: string; - emoji_url: string | null; - status_id: string; - } - | { - type: 'chat_mention'; - chat_message_id: string; - } - | { - type: 'participation_accepted' | 'participation_request'; - status_id: string; - participation_message: string | null; - } - ) = { - ...omit(notification, ['account', 'accounts']), - created_at: notification.created_at, - id: notification.id, - type: notification.type, - }; - - // @ts-ignore - if (notification.status) minifiedNotification.status_id = notification.status.id; - // @ts-ignore - if (notification.target) minifiedNotification.target_id = notification.target.id; - // @ts-ignore - if (notification.chat_message) minifiedNotification.chat_message_id = notification.chat_message.id; - - return minifiedNotification; -}; - -type MinifiedNotification = ReturnType; - const importNotification = (notification: MinifiedNotification) => { queryClient.setQueryData( ['notifications', 'entities', notification.id], diff --git a/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotifications.ts b/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotifications.ts index c38f3a938..b8b6e92c2 100644 --- a/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotifications.ts +++ b/packages/pl-fe/src/pl-hooks/hooks/notifications/useNotifications.ts @@ -1,20 +1,14 @@ import { useInfiniteQuery } from '@tanstack/react-query'; -import { getNotificationStatus } from 'pl-fe/features/notifications/components/notification'; import { useClient } from 'pl-fe/hooks'; import { importEntities } from 'pl-fe/pl-hooks/importer'; +import { deduplicateNotifications } from 'pl-fe/pl-hooks/normalizers/deduplicateNotifications'; import { queryClient } from 'pl-fe/queries/client'; import { flattenPages } from 'pl-fe/utils/queries'; -import type { - Account as BaseAccount, - Notification as BaseNotification, - PaginatedResponse, - PlApiClient, -} from 'pl-api'; +import type { Notification as BaseNotification, PaginatedResponse, PlApiClient } from 'pl-api'; import type { NotificationType } from 'pl-fe/utils/notification'; - type UseNotificationParams = { types?: Array; excludeTypes?: Array; @@ -25,46 +19,6 @@ const getQueryKey = (params: UseNotificationParams) => [ params.types ? params.types.join('|') : params.excludeTypes ? ('exclude:' + params.excludeTypes.join('|')) : 'all', ]; -type DeduplicatedNotification = BaseNotification & { - accounts: Array; - duplicate?: boolean; -} - -const STATUS_NOTIFICATION_TYPES = [ - 'favourite', - 'reblog', - 'emoji_reaction', - 'event_reminder', - 'participation_accepted', - 'participation_request', -]; - -const deduplicateNotifications = (notifications: Array) => { - const deduplicatedNotifications: DeduplicatedNotification[] = []; - - for (const notification of notifications) { - if (STATUS_NOTIFICATION_TYPES.includes(notification.type)) { - const existingNotification = deduplicatedNotifications - .find(deduplicated => - deduplicated.type === notification.type - && ((notification.type === 'emoji_reaction' && deduplicated.type === 'emoji_reaction') ? notification.emoji === deduplicated.emoji : true) - && getNotificationStatus(deduplicated)?.id === getNotificationStatus(notification)?.id, - ); - - if (existingNotification) { - existingNotification.accounts.push(notification.account); - deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: true }); - } else { - deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: false }); - } - } else { - deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: false }); - } - } - - return deduplicatedNotifications; -}; - const importNotifications = (response: PaginatedResponse) => { const deduplicatedNotifications = deduplicateNotifications(response.items); @@ -72,10 +26,6 @@ const importNotifications = (response: PaginatedResponse) => { notifications: deduplicatedNotifications, }); - // const normalizedNotifications = normalizeNotifications(response.items); - - // normalizedNotifications.map(minifyNotification).forEach(importNotification); - return { items: deduplicatedNotifications.filter(({ duplicate }) => !duplicate).map(({ id }) => id), previous: response.previous, @@ -115,4 +65,4 @@ const prefetchNotifications = (client: PlApiClient, params: UseNotificationParam getNextPageParam: (response) => response, }); -export { useNotifications, prefetchNotifications, type DeduplicatedNotification }; +export { useNotifications, prefetchNotifications }; diff --git a/packages/pl-fe/src/pl-hooks/importer.ts b/packages/pl-fe/src/pl-hooks/importer.ts index c1155a625..bf7743ddf 100644 --- a/packages/pl-fe/src/pl-hooks/importer.ts +++ b/packages/pl-fe/src/pl-hooks/importer.ts @@ -1,5 +1,3 @@ -import omit from 'lodash/omit'; - import { importAccounts, importGroups, importPolls, importStatuses } from 'pl-fe/actions/importer'; import { importEntities as importEntityStoreEntities } from 'pl-fe/entity-store/actions'; import { Entities } from 'pl-fe/entity-store/entities'; @@ -9,92 +7,18 @@ let dispatch: AppDispatch; import('pl-fe/store').then(value => dispatch = value.store.dispatch).catch(() => {}); -import { DeduplicatedNotification } from './hooks/notifications/useNotifications'; +import { MinifiedNotification, minifyNotification } from './minifiers/minifyNotification'; +import { DeduplicatedNotification } from './normalizers/deduplicateNotifications'; import type { - AccountWarning, Account as BaseAccount, Group as BaseGroup, Poll as BasePoll, Relationship as BaseRelationship, - Status as BaseStatus, - RelationshipSeveranceEvent, + StatusWithoutAccount as BaseStatus, } from 'pl-api'; import type { AppDispatch } from 'pl-fe/store'; - -const minifyNotification = (notification: DeduplicatedNotification) => { - // @ts-ignore - const minifiedNotification: { - duplicate: boolean; - account_id: string; - account_ids: string[]; - created_at: string; - id: string; - group_key: string; - } & ( - | { type: 'follow' | 'follow_request' | 'admin.sign_up' | 'bite' } - | { - type: 'mention'; - subtype?: 'reply'; - status_id: string; - } - | { - type: 'status' | 'reblog' | 'favourite' | 'poll' | 'update' | 'event_reminder'; - status_id: string; - } - | { - type: 'admin.report'; - report: Report; - } - | { - type: 'severed_relationships'; - relationship_severance_event: RelationshipSeveranceEvent; - } - | { - type: 'moderation_warning'; - moderation_warning: AccountWarning; - } - | { - type: 'move'; - target_id: string; - } - | { - type: 'emoji_reaction'; - emoji: string; - emoji_url: string | null; - status_id: string; - } - | { - type: 'chat_mention'; - chat_message_id: string; - } - | { - type: 'participation_accepted' | 'participation_request'; - status_id: string; - participation_message: string | null; - } - ) = { - ...omit(notification, ['account', 'accounts', 'status', 'target', 'chat_message']), - account_id: notification.account.id, - account_ids: notification.accounts.map(({ id }) => id), - created_at: notification.created_at, - id: notification.id, - type: notification.type, - }; - - // @ts-ignore - if (notification.status) minifiedNotification.status_id = notification.status.id; - // @ts-ignore - if (notification.target) minifiedNotification.target_id = notification.target.id; - // @ts-ignore - if (notification.chat_message) minifiedNotification.chat_message_id = notification.chat_message.id; - - return minifiedNotification; -}; - -type MinifiedNotification = ReturnType; - const importNotification = (notification: DeduplicatedNotification) => { queryClient.setQueryData( ['notifications', 'entities', notification.id], @@ -102,9 +26,16 @@ const importNotification = (notification: DeduplicatedNotification) => { ); }; +const isEmpty = (object: Record) => { + for (const i in object) return false; + return true; +}; + const importEntities = (entities: { accounts?: Array; + groups?: Array; notifications?: Array; + polls?: Array; statuses?: Array; relationships?: Array; }) => { @@ -133,8 +64,9 @@ const importEntities = (entities: { }; const processStatus = (status: BaseStatus) => { - statuses[status.id] = status; + if (!statuses[status.id] || status.account || !statuses[status.id].account) statuses[status.id] = status; + if (status.account) processAccount(status.account); if (status.quote) processStatus(status.quote); if (status.reblog) processStatus(status.reblog); if (status.poll) polls[status.poll.id] = status.poll; @@ -142,15 +74,18 @@ const importEntities = (entities: { }; entities.accounts?.forEach(processAccount); + entities.groups?.forEach(group => groups[group.id] = group); entities.notifications?.forEach(processNotification); + entities.polls?.forEach(poll => polls[poll.id] = poll); + entities.relationships?.forEach(relationship => relationships[relationship.id] = relationship); entities.statuses?.forEach(processStatus); - dispatch(importAccounts(Object.values(accounts))); - dispatch(importGroups(Object.values(groups))); - Object.values(notifications).forEach(importNotification); - dispatch(importPolls(Object.values(polls))); - dispatch(importStatuses(Object.values(statuses))); - dispatch(importEntityStoreEntities(Object.values(relationships), Entities.RELATIONSHIPS)); + if (!isEmpty(accounts)) dispatch(importAccounts(Object.values(accounts))); + if (!isEmpty(groups)) dispatch(importGroups(Object.values(groups))); + if (!isEmpty(notifications)) Object.values(notifications).forEach(importNotification); + if (!isEmpty(polls)) dispatch(importPolls(Object.values(polls))); + if (!isEmpty(relationships)) dispatch(importEntityStoreEntities(Object.values(relationships), Entities.RELATIONSHIPS)); + if (!isEmpty(statuses)) dispatch(importStatuses(Object.values(statuses))); }; export { importEntities }; diff --git a/packages/pl-fe/src/pl-hooks/minifiers/minifyNotification.ts b/packages/pl-fe/src/pl-hooks/minifiers/minifyNotification.ts new file mode 100644 index 000000000..3a972088c --- /dev/null +++ b/packages/pl-fe/src/pl-hooks/minifiers/minifyNotification.ts @@ -0,0 +1,79 @@ +import omit from 'lodash/omit'; + +import { DeduplicatedNotification } from '../normalizers/deduplicateNotifications'; + +import type { AccountWarning, RelationshipSeveranceEvent } from 'pl-api'; + +const minifyNotification = (notification: DeduplicatedNotification) => { + // @ts-ignore + const minifiedNotification: { + duplicate: boolean; + account_id: string; + account_ids: string[]; + created_at: string; + id: string; + group_key: string; + } & ( + | { type: 'follow' | 'follow_request' | 'admin.sign_up' | 'bite' } + | { + type: 'mention'; + subtype?: 'reply'; + status_id: string; + } + | { + type: 'status' | 'reblog' | 'favourite' | 'poll' | 'update' | 'event_reminder'; + status_id: string; + } + | { + type: 'admin.report'; + report: Report; + } + | { + type: 'severed_relationships'; + relationship_severance_event: RelationshipSeveranceEvent; + } + | { + type: 'moderation_warning'; + moderation_warning: AccountWarning; + } + | { + type: 'move'; + target_id: string; + } + | { + type: 'emoji_reaction'; + emoji: string; + emoji_url: string | null; + status_id: string; + } + | { + type: 'chat_mention'; + chat_message_id: string; + } + | { + type: 'participation_accepted' | 'participation_request'; + status_id: string; + participation_message: string | null; + } + ) = { + ...omit(notification, ['account', 'accounts', 'status', 'target', 'chat_message']), + account_id: notification.account.id, + account_ids: notification.accounts.map(({ id }) => id), + created_at: notification.created_at, + id: notification.id, + type: notification.type, + }; + + // @ts-ignore + if (notification.status) minifiedNotification.status_id = notification.status.id; + // @ts-ignore + if (notification.target) minifiedNotification.target_id = notification.target.id; + // @ts-ignore + if (notification.chat_message) minifiedNotification.chat_message_id = notification.chat_message.id; + + return minifiedNotification; +}; + +type MinifiedNotification = ReturnType; + +export { minifyNotification, type MinifiedNotification }; diff --git a/packages/pl-fe/src/pl-hooks/normalizers/deduplicateNotifications.ts b/packages/pl-fe/src/pl-hooks/normalizers/deduplicateNotifications.ts new file mode 100644 index 000000000..41e0d7cfd --- /dev/null +++ b/packages/pl-fe/src/pl-hooks/normalizers/deduplicateNotifications.ts @@ -0,0 +1,45 @@ +import { getNotificationStatus } from 'pl-fe/features/notifications/components/notification'; + +import type { Account as BaseAccount, Notification as BaseNotification } from 'pl-api'; + +type DeduplicatedNotification = BaseNotification & { + accounts: Array; + duplicate?: boolean; +} + +const STATUS_NOTIFICATION_TYPES = [ + 'favourite', + 'reblog', + 'emoji_reaction', + 'event_reminder', + 'participation_accepted', + 'participation_request', +]; + +const deduplicateNotifications = (notifications: Array) => { + const deduplicatedNotifications: DeduplicatedNotification[] = []; + + for (const notification of notifications) { + if (STATUS_NOTIFICATION_TYPES.includes(notification.type)) { + const existingNotification = deduplicatedNotifications + .find(deduplicated => + deduplicated.type === notification.type + && ((notification.type === 'emoji_reaction' && deduplicated.type === 'emoji_reaction') ? notification.emoji === deduplicated.emoji : true) + && getNotificationStatus(deduplicated)?.id === getNotificationStatus(notification)?.id, + ); + + if (existingNotification) { + existingNotification.accounts.push(notification.account); + deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: true }); + } else { + deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: false }); + } + } else { + deduplicatedNotifications.push({ ...notification, accounts: [notification.account], duplicate: false }); + } + } + + return deduplicatedNotifications; +}; + +export { deduplicateNotifications, type DeduplicatedNotification }; diff --git a/packages/pl-fe/src/queries/relationships.ts b/packages/pl-fe/src/queries/relationships.ts index b7e8daf7a..b0e2a6c14 100644 --- a/packages/pl-fe/src/queries/relationships.ts +++ b/packages/pl-fe/src/queries/relationships.ts @@ -1,22 +1,14 @@ import { useMutation } from '@tanstack/react-query'; -import { fetchRelationshipsFail, fetchRelationshipsSuccess } from 'pl-fe/actions/accounts'; -import { useAppDispatch, useClient } from 'pl-fe/hooks'; +import { useClient } from 'pl-fe/hooks'; const useFetchRelationships = () => { const client = useClient(); - const dispatch = useAppDispatch(); return useMutation({ mutationFn: ({ accountIds }: { accountIds: string[]}) => { return client.accounts.getRelationships(accountIds); }, - onSuccess(response) { - dispatch(fetchRelationshipsSuccess(response)); - }, - onError(error) { - dispatch(fetchRelationshipsFail(error)); - }, }); }; diff --git a/packages/pl-fe/src/queries/suggestions.ts b/packages/pl-fe/src/queries/suggestions.ts index 427c73dcd..3484a03eb 100644 --- a/packages/pl-fe/src/queries/suggestions.ts +++ b/packages/pl-fe/src/queries/suggestions.ts @@ -1,8 +1,8 @@ import { useMutation, keepPreviousData, useQuery } from '@tanstack/react-query'; import { fetchRelationships } from 'pl-fe/actions/accounts'; -import { importFetchedAccounts } from 'pl-fe/actions/importer'; import { useAppDispatch, useClient } from 'pl-fe/hooks'; +import { importEntities } from 'pl-fe/pl-hooks/importer'; import { removePageItem } from '../utils/queries'; @@ -19,7 +19,7 @@ const useSuggestions = () => { const accounts = response.map(({ account }) => account); const accountIds = accounts.map((account) => account.id); - dispatch(importFetchedAccounts(accounts)); + importEntities({ accounts }); dispatch(fetchRelationships(accountIds)); return response.map(({ account, ...x }) => ({ ...x, account_id: account.id })); @@ -59,7 +59,7 @@ const useOnboardingSuggestions = () => { const accounts = response.map(({ account }) => account); const accountIds = accounts.map((account) => account.id); - dispatch(importFetchedAccounts(accounts)); + importEntities({ accounts }); dispatch(fetchRelationships(accountIds)); return response; diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index f6a69e71a..4f24b9e52 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -1,7 +1,6 @@ import { Record as ImmutableRecord } from 'immutable'; import { combineReducers } from 'redux-immutable'; -import { AUTH_LOGGED_OUT } from 'pl-fe/actions/auth'; import * as BuildConfig from 'pl-fe/build-config'; import entities from 'pl-fe/entity-store/reducer'; @@ -35,7 +34,6 @@ import plfe from './pl-fe'; import polls from './polls'; import profile_hover_card from './profile-hover-card'; import push_notifications from './push-notifications'; -import relationships from './relationships'; import scheduled_statuses from './scheduled-statuses'; import search from './search'; import security from './security'; @@ -83,7 +81,6 @@ const reducers = { polls, profile_hover_card, push_notifications, - relationships, scheduled_statuses, search, security, @@ -128,7 +125,7 @@ const logOut = (state: any = StateRecord()): ReturnType => { const rootReducer: typeof appReducer = (state, action) => { switch (action.type) { - case AUTH_LOGGED_OUT: + case 'AUTH_LOGGED_OUT': return appReducer(logOut(state), action); default: return appReducer(state, action); diff --git a/packages/pl-fe/src/reducers/relationships.test.ts b/packages/pl-fe/src/reducers/relationships.test.ts deleted file mode 100644 index 3b058bc40..000000000 --- a/packages/pl-fe/src/reducers/relationships.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Map as ImmutableMap } from 'immutable'; - -import lain from 'pl-fe/__fixtures__/lain.json'; -import { ACCOUNT_IMPORT } from 'pl-fe/actions/importer'; - -import reducer from './relationships'; - -describe('relationships reducer', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {} as any)).toEqual(ImmutableMap()); - }); - - describe('ACCOUNT_IMPORT', () => { - it('should import the relationship', () => { - const action = { - type: ACCOUNT_IMPORT, - account: lain, - }; - const state = ImmutableMap(); - expect(reducer(state, action).toJS()).toEqual({ - '9v5bqYwY2jfmvPNhTM': { - blocked_by: false, - blocking: false, - domain_blocking: false, - endorsed: false, - followed_by: true, - following: true, - id: '9v5bqYwY2jfmvPNhTM', - muting: false, - muting_notifications: false, - note: '', - notifying: false, - requested: false, - showing_reblogs: true, - subscribing: false, - }, - }); - }); - }); -}); diff --git a/packages/pl-fe/src/reducers/relationships.ts b/packages/pl-fe/src/reducers/relationships.ts deleted file mode 100644 index 9161b0bb2..000000000 --- a/packages/pl-fe/src/reducers/relationships.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Map as ImmutableMap } from 'immutable'; -import get from 'lodash/get'; -import { type Relationship, relationshipSchema } from 'pl-api'; - -import { ACCOUNT_NOTE_SUBMIT_SUCCESS } from '../actions/account-notes'; -import { - ACCOUNT_BLOCK_SUCCESS, - ACCOUNT_UNBLOCK_SUCCESS, - ACCOUNT_MUTE_SUCCESS, - ACCOUNT_UNMUTE_SUCCESS, - ACCOUNT_PIN_SUCCESS, - ACCOUNT_UNPIN_SUCCESS, - ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS, - RELATIONSHIPS_FETCH_SUCCESS, -} from '../actions/accounts'; -import { DOMAIN_BLOCK_SUCCESS, DOMAIN_UNBLOCK_SUCCESS } from '../actions/domain-blocks'; -import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; - -import type { APIEntity } from 'pl-fe/types/entities'; -import type { AnyAction } from 'redux'; - -type State = ImmutableMap; -type APIEntities = Array; - -const normalizeRelationships = (state: State, relationships: APIEntities) => { - relationships.forEach(relationship => { - try { - state = state.set(relationship.id, relationshipSchema.parse(relationship)); - } catch (_e) { - // do nothing - } - }); - - return state; -}; - -const setDomainBlocking = (state: State, accounts: string[], blocking: boolean) => - state.withMutations(map => { - accounts.forEach(id => { - map.setIn([id, 'domain_blocking'], blocking); - }); - }); - -const importPleromaAccount = (state: State, account: APIEntity) => { - const relationship = get(account, ['pleroma', 'relationship'], {}); - if (relationship.id) - return normalizeRelationships(state, [relationship]); - return state; -}; - -const importPleromaAccounts = (state: State, accounts: APIEntities) => { - accounts.forEach(account => { - state = importPleromaAccount(state, account); - }); - - return state; -}; - -const relationships = (state: State = ImmutableMap(), action: AnyAction) => { - switch (action.type) { - case ACCOUNT_IMPORT: - return importPleromaAccount(state, action.account); - case ACCOUNTS_IMPORT: - return importPleromaAccounts(state, action.accounts); - case ACCOUNT_BLOCK_SUCCESS: - case ACCOUNT_UNBLOCK_SUCCESS: - case ACCOUNT_MUTE_SUCCESS: - case ACCOUNT_UNMUTE_SUCCESS: - case ACCOUNT_PIN_SUCCESS: - case ACCOUNT_UNPIN_SUCCESS: - case ACCOUNT_NOTE_SUBMIT_SUCCESS: - case ACCOUNT_REMOVE_FROM_FOLLOWERS_SUCCESS: - return normalizeRelationships(state, [action.relationship]); - case RELATIONSHIPS_FETCH_SUCCESS: - return normalizeRelationships(state, action.relationships); - case DOMAIN_BLOCK_SUCCESS: - return setDomainBlocking(state, action.accounts, true); - case DOMAIN_UNBLOCK_SUCCESS: - return setDomainBlocking(state, action.accounts, false); - default: - return state; - } -}; - -export { relationships as default }; diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index b84bac052..068e76136 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -13,7 +13,7 @@ import { validId } from 'pl-fe/utils/auth'; import ConfigDB from 'pl-fe/utils/config-db'; import { shouldFilter } from 'pl-fe/utils/timelines'; -import type { Account as BaseAccount, Filter, MediaAttachment } from 'pl-api'; +import type { Account as BaseAccount, Filter, MediaAttachment, Relationship } from 'pl-api'; import type { EntityStore } from 'pl-fe/entity-store/types'; import type { Account, Group } from 'pl-fe/normalizers'; import type { MinifiedStatus } from 'pl-fe/reducers/statuses'; @@ -33,7 +33,7 @@ const selectOwnAccount = (state: RootState) => { }; const getAccountBase = (state: RootState, accountId: string) => state.entities[Entities.ACCOUNTS]?.store[accountId] as Account | undefined; -const getAccountRelationship = (state: RootState, accountId: string) => state.relationships.get(accountId); +const getAccountRelationship = (state: RootState, accountId: string) => state.entities[Entities.RELATIONSHIPS]?.store[accountId] as Relationship | undefined; const getAccountMeta = (state: RootState, accountId: string) => state.accounts_meta[accountId]; const makeGetAccount = () => createSelector([ diff --git a/packages/pl-fe/yarn.lock b/packages/pl-fe/yarn.lock index 4375ddf75..a937fcc2c 100644 --- a/packages/pl-fe/yarn.lock +++ b/packages/pl-fe/yarn.lock @@ -2171,15 +2171,15 @@ resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.18.0.tgz#4f3cebe093dd436eeaff633809bf0f68f4f9d2ee" integrity sha512-KdVMdpTgDyK8FzdKO9SCpiibuy/kbv3pwgfXshTI6tEcQT1OOwj7BAksnzGC0rPz0UholwC+AgkqEl3EJX3M1A== -"@reduxjs/toolkit@^2.2.7": - version "2.2.7" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.7.tgz#199e3d10ccb39267cb5aee92c0262fd9da7fdfb2" - integrity sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g== +"@reduxjs/toolkit@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.0.1.tgz#0a5233c1e35c1941b03aece39cceade3467a1062" + integrity sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA== dependencies: immer "^10.0.3" - redux "^5.0.1" + redux "^5.0.0" redux-thunk "^3.1.0" - reselect "^5.1.0" + reselect "^5.0.1" "@remix-run/router@1.18.0": version "1.18.0" @@ -9713,10 +9713,10 @@ react-property@2.0.2: resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6" integrity sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug== -react-redux@^9.1.2: - version "9.1.2" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.2.tgz#deba38c64c3403e9abd0c3fbeab69ffd9d8a7e4b" - integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w== +react-redux@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.0.4.tgz#6892d465f086507a517d4b53eb589876e6bc8344" + integrity sha512-9J1xh8sWO0vYq2sCxK2My/QO7MzUMRi3rpiILP/+tDr8krBHixC6JMM17fMK88+Oh3e4Ae6/sHIhNBgkUivwFA== dependencies: "@types/use-sync-external-store" "^0.0.3" use-sync-external-store "^1.0.0" @@ -9908,10 +9908,10 @@ redux@^4.0.5: dependencies: "@babel/runtime" "^7.9.2" -redux@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" - integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== +redux@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.0.tgz#29572e29a439e094ff8fec46883fc45053f6736d" + integrity sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA== reflect.getprototypeof@^1.0.4: version "1.0.4" @@ -10051,16 +10051,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^5.0.0: +reselect@^5.0.0, reselect@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.0.1.tgz#587cdaaeb4e0e8927cff80ebe2bbef05f74b1648" integrity sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg== -reselect@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e" - integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== - resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"