Skip to content

Commit

Permalink
chore: Update to Tanstack Query 5
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdigdir committed Oct 1, 2024
1 parent 93668eb commit 47c0d99
Show file tree
Hide file tree
Showing 22 changed files with 116 additions and 138 deletions.
2 changes: 1 addition & 1 deletion packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@microsoft/applicationinsights-react-js": "17.3.2",
"@microsoft/applicationinsights-web": "3.3.3",
"@navikt/aksel-icons": "^6.16.1",
"@tanstack/react-query": "^5.56.2",
"bff-types-generated": "workspace:*",
"classnames": "^2.5.1",
"date-fns": "^3.6.0",
Expand All @@ -36,7 +37,6 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.0.1",
"react-query": "^3.39.3",
"react-router-dom": "^6.16.0",
"sse.js": "^2.5.0",
"use-debounce": "^10.0.1"
Expand Down
7 changes: 4 additions & 3 deletions packages/frontend/src/api/useDialogById.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useQuery } from '@tanstack/react-query';
import type {
AttachmentFieldsFragment,
DialogActivityFragment,
DialogByIdFieldsFragment,
GetDialogByIdQuery,
PartyFieldsFragment,
} from 'bff-types-generated';
import { useQuery } from 'react-query';
import type { GuiActionButtonProps, InboxItemMetaField } from '../components';
import { QUERY_KEYS } from '../constants/queryKeys.ts';
import { i18n } from '../i18n/config.ts';
import { getOrganisation } from './organisations.ts';
import { graphQLSDK } from './queries.ts';
Expand Down Expand Up @@ -183,8 +184,8 @@ export function mapDialogDtoToInboxItem(
export const useDialogById = (parties: PartyFieldsFragment[], id?: string): UseDialogByIdOutput => {
const partyURIs = parties.map((party) => party.party);
const { data, isSuccess, isLoading } = useQuery<GetDialogByIdQuery>({
queryKey: ['dialogById', id],
cacheTime: 1000 * 60 * 10,
queryKey: [QUERY_KEYS.DIALOG_BY_ID, id],
staleTime: 1000 * 60 * 10,
retry: 3,
queryFn: () => getDialogsById(id!),
enabled: typeof id !== 'undefined' && partyURIs.length > 0,
Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/src/api/useDialogByIdSubscription.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useQueryClient } from '@tanstack/react-query';
import { DialogEventType } from 'bff-types-generated';
import { useEffect } from 'react';
import { useQueryClient } from 'react-query';
import { useNavigate } from 'react-router-dom';
import { SSE } from 'sse.js';
import { QUERY_KEYS } from '../constants/queryKeys.ts';
import { Routes } from '../pages/Inbox/Inbox.tsx';

export const useDialogByIdSubscription = (dialogId: string | undefined, dialogToken: string | undefined) => {
Expand All @@ -29,7 +30,7 @@ export const useDialogByIdSubscription = (dialogId: string | undefined, dialogTo
// Redirect to inbox if the dialog was deleted
navigate(Routes.inbox);
} else if (updatedType && updatedType === DialogEventType.DialogUpdated) {
void queryClient.invalidateQueries('dialogById');
void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.DIALOG_BY_ID] });
}
} catch (e) {
console.error('Error parsing event data:', e);
Expand Down
11 changes: 6 additions & 5 deletions packages/frontend/src/api/useDialogs.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useQuery } from '@tanstack/react-query';
import type {
GetAllDialogsForPartiesQuery,
PartyFieldsFragment,
SearchDialogFieldsFragment,
} from 'bff-types-generated';
import { DialogStatus } from 'bff-types-generated';
import { useEffect, useState } from 'react';
import { useQuery } from 'react-query';
import { useDebounce } from 'use-debounce';
import type { InboxItemMetaField, InboxItemMetaFieldType } from '../components';
import { QUERY_KEYS } from '../constants/queryKeys.ts';
import { i18n } from '../i18n/config.ts';
import type { InboxItemInput } from '../pages/Inbox/Inbox.tsx';
import { getOrganisation } from './organisations.ts';
Expand Down Expand Up @@ -103,9 +104,9 @@ export const useSearchDialogs = ({ parties, searchString, org }: searchDialogsPr
const debouncedSearchString = useDebounce(searchString, 300)[0];
const enabled = !!debouncedSearchString && debouncedSearchString.length > 2;
const { data, isSuccess, isLoading, isFetching } = useQuery<GetAllDialogsForPartiesQuery>({
queryKey: ['searchDialogs', partyURIs, debouncedSearchString, org],
queryKey: [QUERY_KEYS.SEARCH_DIALOGS, partyURIs, debouncedSearchString, org],
queryFn: () => searchDialogs(partyURIs, debouncedSearchString, org),
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60 * 10,
enabled,
});
const [searchResults, setSearchResults] = useState([] as InboxItemInput[]);
Expand Down Expand Up @@ -146,8 +147,8 @@ export const getViewType = (dialog: InboxItemInput): InboxViewType => {
export const useDialogs = (parties: PartyFieldsFragment[]): UseDialogsOutput => {
const partyURIs = parties.map((party) => party.party);
const { data, isSuccess, isLoading } = useQuery<GetAllDialogsForPartiesQuery>({
queryKey: ['dialogs', partyURIs],
cacheTime: 1000 * 60 * 10,
queryKey: [QUERY_KEYS.DIALOGS, partyURIs],
staleTime: 1000 * 60 * 10,
retry: 3,
queryFn: () => getDialogs(partyURIs),
enabled: partyURIs.length > 0,
Expand Down
50 changes: 28 additions & 22 deletions packages/frontend/src/api/useParties.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import type { PartiesQuery, PartyFieldsFragment } from 'bff-types-generated';
import { useMemo } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import { useEffect, useMemo } from 'react';
import { QUERY_KEYS } from '../constants/queryKeys.ts';
import { toTitleCase } from '../profile';
import { graphQLSDK } from './queries.ts';

Expand All @@ -26,14 +27,19 @@ const fetchParties = (): Promise<PartiesQuery> => graphQLSDK.parties();

export const useParties = (): UsePartiesOutput => {
const queryClient = useQueryClient();
const { data: selectedParties = [] } = useQuery<PartyFieldsFragment[]>(['selectedParties'], {

const selectedPartiesQuery = useQuery<PartyFieldsFragment[]>({
queryKey: [QUERY_KEYS.SELECTED_PARTIES],
enabled: false,
staleTime: Number.POSITIVE_INFINITY,
initialData: [],
});
const { data, isLoading, isSuccess } = useQuery<PartiesResult>(
'parties',
async () => {

const selectedParties = selectedPartiesQuery.data ?? [];

const { data, isLoading, isSuccess } = useQuery<PartiesResult>({
queryKey: [QUERY_KEYS.PARTIES],
queryFn: async () => {
const response = await fetchParties();
const partiesWithNormalizedNames =
response.parties.map((party) => ({
Expand All @@ -45,35 +51,35 @@ export const useParties = (): UsePartiesOutput => {
deletedParties: partiesWithNormalizedNames.filter((party) => party.isDeleted),
};
},
{
cacheTime: Number.POSITIVE_INFINITY,
onSuccess: (data: PartiesResult) => {
if (!selectedParties.length && data?.parties?.length > 0) {
const currentEndUser = data.parties.find((party) => party.isCurrentEndUser);
if (currentEndUser) {
setSelectedParties([currentEndUser]);
} else {
console.warn('No current end user found, unable to select default parties.');
}
}
},
},
);
staleTime: Number.POSITIVE_INFINITY,
gcTime: Number.POSITIVE_INFINITY,
});

const setSelectedParties = (parties: PartyFieldsFragment[] | null) => {
if (parties?.length) {
queryClient.setQueryData('selectedParties', parties);
queryClient.setQueryData([QUERY_KEYS.SELECTED_PARTIES], parties);
}
};

const setSelectedPartyIds = (partyIds: string[]) => {
setSelectedParties(data?.parties.filter((party) => partyIds.includes(party.party)) ?? []);
};

// biome-ignore lint/correctness/useExhaustiveDependencies: Full control of what triggers this code is needed
useEffect(() => {
if (isSuccess && !selectedParties.length && data?.parties?.length > 0) {
const currentEndUser = data.parties.find((party) => party.isCurrentEndUser);
if (currentEndUser) {
setSelectedParties([currentEndUser]);
} else {
console.warn('No current end user found, unable to select default parties.');
}
}
}, [isSuccess, selectedParties.length, data?.parties]);

const allOrganizationsSelected = useMemo(() => {
const allOrgParties = data?.parties.filter((party) => party.partyType === 'Organization') ?? [];
const selectedOrgParties = selectedParties.filter((party) => party.partyType === 'Organization');

return selectedOrgParties.length > 0 && allOrgParties.length === selectedOrgParties.length;
}, [selectedParties, data]);

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/Login/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import type React from 'react';
import { createContext, useContext, useEffect } from 'react';
import { useQuery } from 'react-query';
import { getIsAuthenticated, getStoredURL, isRedirectURL, removeStoredURL, saveURL } from '../../auth';

interface AuthContextProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useQuery } from '@tanstack/react-query';
import { Markdown } from 'embeddable-markdown-html';
import { useQuery } from 'react-query';
import type { DialogByIdDetails } from '../../api/useDialogById.tsx';
import { QUERY_KEYS } from '../../constants/queryKeys.ts';
import styles from './mainContentReference.module.css';

export const MainContentReference = ({
args,
dialogToken,
}: { args: DialogByIdDetails['mainContentReference']; dialogToken: string }) => {
const { data, isSuccess, error } = useQuery({
queryKey: ['mainContentReference', args?.url],
queryKey: [QUERY_KEYS.MAIN_CONTENT_REFERENCE, args?.url],
queryFn: () =>
fetch(args!.url, {
headers: {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/PageLayout/PageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useQueryClient } from '@tanstack/react-query';
import cx from 'classnames';
import type React from 'react';
import { memo, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { Outlet, useLocation, useSearchParams } from 'react-router-dom';
import { type AvatarProfile, Footer, Header, type ItemPerViewCount, Sidebar } from '..';
import { useWindowSize } from '../../../utils/useWindowSize.tsx';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useQueryClient } from 'react-query';
import { useDialogs } from '../../api/useDialogs.tsx';
import { useParties } from '../../api/useParties.ts';
import { QUERY_KEYS } from '../../constants/queryKeys.ts';
import { useSavedSearches } from '../../pages/SavedSearches/useSavedSearches.ts';
import type { SideBarView } from '../Sidebar';
import { PartyList } from './PartyList.tsx';
Expand Down Expand Up @@ -31,7 +32,7 @@ const PartyListAdapter = ({ counterContext = 'inbox', children }: PartyListAdapt

const onSelect = (ids: string[]) => {
setSelectedPartyIds(ids);
void queryClient.invalidateQueries({ queryKey: [['dialogs'], ['savedSearches']] });
void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.DIALOGS, QUERY_KEYS.SAVED_SEARCHES] });
};

const optionsGroups: MergedPartyGroup = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { QueryClient } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient } from 'react-query';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createCustomWrapper } from '../../../utils/test-utils.tsx';
import { SnackbarDuration, useSnackbar } from './useSnackbar';
Expand Down
8 changes: 5 additions & 3 deletions packages/frontend/src/components/Snackbar/useSnackbar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useCallback, useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from 'react-query';

export enum SnackbarDuration {
infinite = 0,
Expand Down Expand Up @@ -51,7 +51,9 @@ export function useSnackbar(): SnackbarOutput {
storedMessages: [],
};

const { data } = useQuery<SnackbarConfig>([queryKey], () => initialData, {
const { data } = useQuery<SnackbarConfig>({
queryKey: [queryKey],
queryFn: () => initialData,
enabled: false,
staleTime: Number.POSITIVE_INFINITY,
});
Expand Down Expand Up @@ -92,7 +94,7 @@ export function useSnackbar(): SnackbarOutput {
);

useEffect(() => {
const storedMessageItem = data?.storedMessages?.filter((item) => item.duration > 0)[0];
const storedMessageItem = data?.storedMessages?.filter((item: SnackbarStoreRecord) => item.duration > 0)[0];
if (typeof storedMessageItem !== 'undefined') {
closingTime.current = setTimeout(() => {
closeSnackbarItem(storedMessageItem?.id);
Expand Down
10 changes: 10 additions & 0 deletions packages/frontend/src/constants/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const QUERY_KEYS = {
DIALOG_BY_ID: 'dialogById',
PARTIES: 'parties',
SELECTED_PARTIES: 'selectedParties',
SEARCH_DIALOGS: 'searchDialogs',
DIALOGS: 'dialogs',
MAIN_CONTENT_REFERENCE: 'mainContentReference',
SAVED_SEARCHES: 'savedSearches',
PROFILE: 'profile',
};
2 changes: 1 addition & 1 deletion packages/frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from 'react-query';
import { BrowserRouter } from 'react-router-dom';
import './i18n/config.ts';

import '@digdir/designsystemet-css';
import '@digdir/designsystemet-theme';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App.tsx';
import { AuthProvider } from './components/Login/AuthContext.tsx';
import { LoggerContextProvider } from './contexts/LoggerContext.tsx';
Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/src/pages/Inbox/Inbox.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ArrowForwardIcon, ClockDashedIcon, EnvelopeOpenIcon, TrashIcon } from '@navikt/aksel-icons';
import { useQueryClient } from '@tanstack/react-query';
import type { DialogStatus, SavedSearchData, SearchDataValueFilter } from 'bff-types-generated';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { useLocation, useSearchParams } from 'react-router-dom';
import { createSavedSearch } from '../../api/queries.ts';
import type { Participant } from '../../api/useDialogById.tsx';
Expand All @@ -19,6 +19,7 @@ import { FosToolbar } from '../../components/FosToolbar';
import { InboxItemsHeader } from '../../components/InboxItem/InboxItemsHeader.tsx';
import { SaveSearchButton } from '../../components/SavedSearchButton/SaveSearchButton.tsx';
import type { SortOrderDropdownRef, SortingOrder } from '../../components/SortOrderDropdown/SortOrderDropdown.tsx';
import { QUERY_KEYS } from '../../constants/queryKeys.ts';
import { FeatureFlagKeys } from '../../featureFlags';
import { useFeatureFlag } from '../../featureFlags';
import { useFormat } from '../../i18n/useDateFnsLocale.tsx';
Expand Down Expand Up @@ -195,7 +196,7 @@ export const Inbox = ({ viewType }: InboxProps) => {
console.error('Error creating saved search: ', error);
} finally {
setIsSavingSearch(false);
void queryClient.invalidateQueries(['savedSearches']);
void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.SAVED_SEARCHES] });
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Button, Modal } from '@digdir/designsystemet-react';
import { useQueryClient } from '@tanstack/react-query';
import { type ForwardedRef, forwardRef, useImperativeHandle, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { deleteSavedSearch } from '../../../api/queries.ts';
import { HorizontalLine, useSnackbar } from '../../../components';
import { QUERY_KEYS } from '../../../constants/queryKeys.ts';

interface DeleteSearchDialogProps {
savedSearchId?: number;
Expand Down Expand Up @@ -38,7 +39,7 @@ export const ConfirmDeleteDialog = forwardRef(
message: t('savedSearches.deleted_success'),
variant: 'success',
});
await queryClient.invalidateQueries('savedSearches');
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.SAVED_SEARCHES] });
} catch (error) {
console.error('Failed to delete saved search:', error);
openSnackbar({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Button, Modal } from '@digdir/designsystemet-react';
import { TrashIcon } from '@navikt/aksel-icons';
import { useQueryClient } from '@tanstack/react-query';
import type { SavedSearchData, SavedSearchesFieldsFragment } from 'bff-types-generated';
import { type ForwardedRef, forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { updateSavedSearch } from '../../../api/queries.ts';
import { HorizontalLine, useSnackbar } from '../../../components';
import { QUERY_KEYS } from '../../../constants/queryKeys.ts';
import { useFormatDistance } from '../../../i18n/useDateFnsLocale.tsx';
import { autoFormatRelativeTime } from '../searchUtils.ts';
import styles from './editSavedSearchDialog.module.css';
Expand Down Expand Up @@ -50,7 +51,7 @@ export const EditSavedSearchDialog = forwardRef(
message: t('savedSearches.update_success'),
variant: 'success',
});
void queryClient.invalidateQueries('savedSearches');
void queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.SAVED_SEARCHES] });
onClose?.();
});
};
Expand Down
Loading

0 comments on commit 47c0d99

Please sign in to comment.