From 35b1c54bdece076beeb5b6cb4e19d2da345177cb Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Thu, 2 May 2024 17:57:53 +0200 Subject: [PATCH] [frontend] Do optimistic update when approving/rejecting/suspending account (#2892) --- web/source/settings/lib/query/admin/index.ts | 67 +++++++++++++++----- web/source/settings/lib/types/account.ts | 7 ++ 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/web/source/settings/lib/query/admin/index.ts b/web/source/settings/lib/query/admin/index.ts index 3e7b1a0a0..fd3e1ca1b 100644 --- a/web/source/settings/lib/query/admin/index.ts +++ b/web/source/settings/lib/query/admin/index.ts @@ -20,7 +20,7 @@ import { replaceCacheOnMutation, removeFromCacheOnMutation } from "../query-modifiers"; import { gtsApi } from "../gts-api"; import { listToKeyedObject } from "../transforms"; -import { AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account"; +import { ActionAccountParams, AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account"; import { InstanceRule, MappedRules } from "../../types/rules"; import parse from "parse-link-header"; @@ -84,22 +84,19 @@ const extended = gtsApi.injectEndpoints({ url: `/api/v2/admin/accounts${query}` }; }, + // Headers required for paging. transformResponse: (apiResp: AdminAccount[], meta) => { const accounts = apiResp; const linksStr = meta?.response?.headers.get("Link"); const links = parse(linksStr); return { accounts, links }; }, - providesTags: (res) => - res - ? [ - ...res.accounts.map(({ id }) => ({ type: 'Account' as const, id })), - { type: 'Account', id: 'LIST' }, - ] - : [{ type: 'Account', id: 'LIST' }], + // Only provide LIST tag id since this model is not the + // same as getAccount model (due to transformResponse). + providesTags: [{ type: "Account", id: "TRANSFORMED" }] }), - actionAccount: build.mutation({ + actionAccount: build.mutation({ query: ({ id, action, reason }) => ({ method: "POST", url: `/api/v1/admin/accounts/${id}/action`, @@ -109,9 +106,26 @@ const extended = gtsApi.injectEndpoints({ text: reason } }), - invalidatesTags: (_result, _error, { id }) => [ - { type: 'Account', id }, - ], + // Do an optimistic update on this account to mark + // it according to whatever action was submitted. + async onQueryStarted({ id, action }, { dispatch, queryFulfilled }) { + const patchResult = dispatch( + extended.util.updateQueryData("getAccount", id, (draft) => { + if (action === "suspend") { + draft.suspended = true; + draft.account.suspended = true; + } + }) + ); + + // Revert optimistic + // update if query fails. + try { + await queryFulfilled; + } catch { + patchResult.undo(); + } + } }), handleSignup: build.mutation({ @@ -123,9 +137,32 @@ const extended = gtsApi.injectEndpoints({ body: approve_or_reject === "reject" ?? formData, }; }, - invalidatesTags: (_result, _error, { id }) => [ - { type: 'Account', id }, - ], + // Do an optimistic update on this account to mark it approved + // if approved was true, else just invalidate getAccount. + async onQueryStarted({ id, approve_or_reject }, { dispatch, queryFulfilled }) { + if (approve_or_reject === "reject") { + // Just invalidate this ID and getAccounts. + dispatch(extended.util.invalidateTags([ + { type: "Account", id: id }, + { type: "Account", id: "TRANSFORMED" } + ])); + return; + } + + const patchResult = dispatch( + extended.util.updateQueryData("getAccount", id, (draft) => { + draft.approved = true; + }) + ); + + // Revert optimistic + // update if query fails. + try { + await queryFulfilled; + } catch { + patchResult.undo(); + } + } }), instanceRules: build.query({ diff --git a/web/source/settings/lib/types/account.ts b/web/source/settings/lib/types/account.ts index db97001ac..8fd4e0356 100644 --- a/web/source/settings/lib/types/account.ts +++ b/web/source/settings/lib/types/account.ts @@ -63,6 +63,7 @@ export interface Account { fields: [], enable_rss: boolean, role: any, + suspended?: boolean, } export interface SearchAccountParams { @@ -92,3 +93,9 @@ export interface HandleSignupParams { message?: string, send_email?: boolean, } + +export interface ActionAccountParams { + id: string; + action: "suspend"; + reason: string; +}