From ab0e9b28bed576eabc321587e97e9a90fd1f6028 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 30 Jul 2024 21:00:18 +0800 Subject: [PATCH] Move bulk action to react-query --- .../templates/homeFeed/HomeFeedContainer.tsx | 2 +- .../templates/homeFeed/LibraryHeader.tsx | 2 +- .../homeFeed/MultiSelectControls.tsx | 4 +- .../templates/library/LibraryContainer.tsx | 11 ++-- .../templates/library/LibraryHeader.tsx | 2 +- .../templates/library/LibrarySideBar.tsx | 54 +---------------- .../web/lib/networking/library_items/gql.tsx | 23 +++++++ .../library_items/useLibraryItems.tsx | 51 ++++++++++++++++ .../mutations/bulkActionMutation.ts | 60 ------------------- packages/web/pages/tools/bulk.tsx | 17 ++++-- 10 files changed, 97 insertions(+), 129 deletions(-) diff --git a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx index 2c455dfb0..91425b1f6 100644 --- a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx +++ b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx @@ -1,7 +1,7 @@ import type { LibraryItem } from '../../../lib/networking/library_items/useLibraryItems' import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes' import { MultiSelectMode } from './LibraryHeader' -import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation' +import { BulkAction } from '../../../lib/networking/library_items/useLibraryItems' export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT' export type LibraryMode = 'reads' | 'highlights' | 'tldr' diff --git a/packages/web/components/templates/homeFeed/LibraryHeader.tsx b/packages/web/components/templates/homeFeed/LibraryHeader.tsx index 99412b1df..cde6ae68c 100644 --- a/packages/web/components/templates/homeFeed/LibraryHeader.tsx +++ b/packages/web/components/templates/homeFeed/LibraryHeader.tsx @@ -10,7 +10,7 @@ import { LayoutType, LibraryMode } from './HomeFeedContainer' import { OmnivoreSmallLogo } from '../../elements/images/OmnivoreNameLogo' import { DEFAULT_HEADER_HEIGHT, HeaderSpacer } from './HeaderSpacer' import { LIBRARY_LEFT_MENU_WIDTH } from '../navMenu/LibraryMenu' -import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation' +import { BulkAction } from '../../../lib/networking/library_items/useLibraryItems' import { HeaderToggleGridIcon } from '../../elements/icons/HeaderToggleGridIcon' import { HeaderToggleListIcon } from '../../elements/icons/HeaderToggleListIcon' import { HeaderToggleTLDRIcon } from '../../elements/icons/HeaderToggleTLDRIcon' diff --git a/packages/web/components/templates/homeFeed/MultiSelectControls.tsx b/packages/web/components/templates/homeFeed/MultiSelectControls.tsx index 693cb606e..9e4dd63df 100644 --- a/packages/web/components/templates/homeFeed/MultiSelectControls.tsx +++ b/packages/web/components/templates/homeFeed/MultiSelectControls.tsx @@ -2,7 +2,7 @@ import { useState } from 'react' import { theme } from '../../tokens/stitches.config' import { Box, HStack, SpanBox } from '../../elements/LayoutPrimitives' import { Button } from '../../elements/Button' -import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation' +import { BulkAction } from '../../../lib/networking/library_items/useLibraryItems' import { ArchiveIcon } from '../../elements/icons/ArchiveIcon' import { LabelIcon } from '../../elements/icons/LabelIcon' import { TrashIcon } from '../../elements/icons/TrashIcon' @@ -116,7 +116,7 @@ export const MultiSelectControls = (props: MultiSelectProps): JSX.Element => { { }) } +export const useBulkActions = () => { + const queryClient = useQueryClient() + const bulkAction = async (variables: { + action: BulkAction + query: string + expectedCount: number + labelIds?: string[] + }) => { + const result = (await gqlFetcher(GQL_BULK_ACTION, { + ...variables, + })) as BulkActionData + if (result.bulkAction?.errorCodes?.length) { + throw new Error(result.bulkAction.errorCodes[0]) + } + return result.bulkAction.success + } + return useMutation({ + mutationFn: bulkAction, + onMutate: async (variables: { + action: BulkAction + query: string + expectedCount: number + labelIds?: string[] + }) => { + await queryClient.cancelQueries({ queryKey: ['libraryItems'] }) + }, + onSettled: async (newLabels, variables) => { + await queryClient.invalidateQueries({ + queryKey: ['libraryItems'], + }) + }, + }) +} + +export enum BulkAction { + ARCHIVE = 'ARCHIVE', + DELETE = 'DELETE', + ADD_LABELS = 'ADD_LABELS', + MARK_AS_READ = 'MARK_AS_READ', +} + +type BulkActionResult = { + success?: boolean + errorCodes?: string[] +} + +type BulkActionData = { + bulkAction: BulkActionResult +} + type UpdateLibraryItemInput = { pageId: string title?: string diff --git a/packages/web/lib/networking/mutations/bulkActionMutation.ts b/packages/web/lib/networking/mutations/bulkActionMutation.ts index fd02e66c0..186de7087 100644 --- a/packages/web/lib/networking/mutations/bulkActionMutation.ts +++ b/packages/web/lib/networking/mutations/bulkActionMutation.ts @@ -1,62 +1,2 @@ import { gql } from 'graphql-request' import { gqlFetcher } from '../networkHelpers' - -export enum BulkAction { - ARCHIVE = 'ARCHIVE', - DELETE = 'DELETE', - ADD_LABELS = 'ADD_LABELS', - MARK_AS_READ = 'MARK_AS_READ', -} - -type BulkActionResponseData = { - success: boolean -} - -type BulkActionResponse = { - errorCodes?: string[] - bulkAction?: BulkActionResponseData -} - -export async function bulkActionMutation( - action: BulkAction, - query: string, - expectedCount: number, - labelIds?: string[] -): Promise { - const mutation = gql` - mutation BulkAction( - $action: BulkActionType! - $query: String! - $expectedCount: Int - $labelIds: [ID!] - ) { - bulkAction( - query: $query - action: $action - labelIds: $labelIds - expectedCount: $expectedCount - ) { - ... on BulkActionSuccess { - success - } - ... on BulkActionError { - errorCodes - } - } - } - ` - - try { - const response = await gqlFetcher(mutation, { - action, - query, - labelIds, - expectedCount, - }) - const data = response as BulkActionResponse | undefined - return data?.bulkAction?.success ?? false - } catch (error) { - console.error(error) - return false - } -} diff --git a/packages/web/pages/tools/bulk.tsx b/packages/web/pages/tools/bulk.tsx index 3d98aee98..028d9a716 100644 --- a/packages/web/pages/tools/bulk.tsx +++ b/packages/web/pages/tools/bulk.tsx @@ -5,16 +5,16 @@ import { VStack } from '../../components/elements/LayoutPrimitives' import { StyledText } from '../../components/elements/StyledText' import { ProfileLayout } from '../../components/templates/ProfileLayout' -import { - BulkAction, - bulkActionMutation, -} from '../../lib/networking/mutations/bulkActionMutation' +import { BulkAction } from '../../lib/networking/library_items/useLibraryItems' import { Button } from '../../components/elements/Button' import { theme } from '../../components/tokens/stitches.config' import { ConfirmationModal } from '../../components/patterns/ConfirmationModal' import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' import { useRouter } from 'next/router' -import { useGetLibraryItems } from '../../lib/networking/library_items/useLibraryItems' +import { + useBulkActions, + useGetLibraryItems, +} from '../../lib/networking/library_items/useLibraryItems' import { BorderedFormInput, FormLabel, @@ -33,6 +33,7 @@ export default function BulkPerformer(): JSX.Element { const [expectedCount, setExpectedCount] = useState() const [errorMessage, setErrorMessage] = useState() const [runningState, setRunningState] = useState('none') + const bulkAction = useBulkActions() const { data: itemsPages, isLoading } = useGetLibraryItems(undefined, { searchQuery: query, @@ -64,7 +65,11 @@ export default function BulkPerformer(): JSX.Element { return } try { - const success = await bulkActionMutation(action, query, expectedCount) + const success = await bulkAction.mutateAsync({ + action, + query, + expectedCount, + }) if (!success) { throw 'Success not returned' }