From 3e74d4995fe04613e42c35dc816807a30fd79c8a Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Wed, 23 Oct 2024 12:57:12 +0200 Subject: [PATCH 01/17] install packages working persistent cache --- packages/shared/package.json | 2 ++ .../src/components/sidebar/SquadSection.tsx | 13 ++++++- packages/shared/src/graphql/squads.ts | 35 +++++++++++++++++++ packages/shared/src/lib/persistedQuery.ts | 30 ++++++++++++++++ packages/webapp/package.json | 1 + packages/webapp/pages/_app.tsx | 18 +++++----- pnpm-lock.yaml | 30 ++++++++++++++++ 7 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 packages/shared/src/lib/persistedQuery.ts diff --git a/packages/shared/package.json b/packages/shared/package.json index 0d07bfd25e..509b4394ff 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -107,6 +107,8 @@ "dependencies": { "@growthbook/growthbook": "https://gitpkg.now.sh/dailydotdev/growthbook/packages/sdk-js?b8f31f9e80879fe2bcc42b275087b50e1357f1cb", "@growthbook/growthbook-react": "^0.17.0", + "@tanstack/query-sync-storage-persister": "4.36.1", + "@tanstack/react-query-persist-client": "4.36.1", "@tippyjs/react": "^4.2.5", "balloon-css": "^1.2.0", "check-password-strength": "^2.0.7", diff --git a/packages/shared/src/components/sidebar/SquadSection.tsx b/packages/shared/src/components/sidebar/SquadSection.tsx index c7353684d6..ea15d02083 100644 --- a/packages/shared/src/components/sidebar/SquadSection.tsx +++ b/packages/shared/src/components/sidebar/SquadSection.tsx @@ -1,4 +1,5 @@ import React, { ReactElement, useContext } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { ListIcon, SidebarMenuItem } from './common'; import { Section, SectionCommonProps } from './Section'; import { NewSquadIcon, DefaultSquadIcon, SourceIcon } from '../icons'; @@ -6,11 +7,21 @@ import { Origin } from '../../lib/log'; import { useSquadNavigation } from '../../hooks'; import AuthContext from '../../contexts/AuthContext'; import { SquadImage } from '../squads/SquadImage'; +import { getSquads } from '../../graphql/squads'; export function SquadSection(props: SectionCommonProps): ReactElement { - const { squads } = useContext(AuthContext); + // const { squads } = useContext(AuthContext); + const { user } = useContext(AuthContext); + + const { data: squads, isLoading } = useQuery(['squads'], () => + getSquads(user?.id), + ); const { openNewSquad } = useSquadNavigation(); + if (isLoading) { + return loading; + } + const squadMenuItems: SidebarMenuItem[] = [ { icon: (active: boolean) => ( diff --git a/packages/shared/src/graphql/squads.ts b/packages/shared/src/graphql/squads.ts index 2f6c67e675..8d3c55af36 100644 --- a/packages/shared/src/graphql/squads.ts +++ b/packages/shared/src/graphql/squads.ts @@ -230,6 +230,27 @@ export const SQUAD_QUERY = gql` ${SQUAD_BASE_FRAGMENT} `; +export const SQUAD_MEMBERSHIPS_QUERY = gql` + query SourceMemberships { + mySourceMemberships { + pageInfo { + endCursor + hasNextPage + } + edges { + node { + source { + id + name + image + permalink + } + } + } + } + } +`; + export const SQUAD_STATIC_FIELDS_QUERY = gql` query Source($handle: ID!) { source(id: $handle) { @@ -358,6 +379,10 @@ export interface SquadEdgesData { sourceMembers: Connection; } +export type SourceMembershipsData = { + mySourceMemberships: Connection; +}; + interface SquadMemberMutationProps { sourceId: string; memberId: string; @@ -393,6 +418,16 @@ export async function getSquad(handle: string): Promise { return res.source; } +export async function getSquads(userId: string): Promise { + const res = await gqlClient.request( + SQUAD_MEMBERSHIPS_QUERY, + { + id: userId, + }, + ); + return res.mySourceMemberships.edges.map((edge) => edge.node.source); +} + export async function getSquadMembers(id: string): Promise { const res = await gqlClient.request(SQUAD_MEMBERS_QUERY, { id, diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts new file mode 100644 index 0000000000..eeb60269fe --- /dev/null +++ b/packages/shared/src/lib/persistedQuery.ts @@ -0,0 +1,30 @@ +import { QueryClient } from '@tanstack/react-query'; +import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'; +import { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'; +import { StaleTime } from './query'; + +export const persistedQueryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: StaleTime.OneHour, + // TODO: When upgrading to version 5, this needs to be renamed to gcTime + cacheTime: StaleTime.OneDay, + }, + }, +}); + +export const queryClientPersister = createSyncStoragePersister({ + storage: typeof window !== 'undefined' ? window.localStorage : undefined, +}); + +export const persistedQueryClientOptions: Omit< + PersistQueryClientOptions, + 'queryClient' +> = { + persister: queryClientPersister, + dehydrateOptions: { + shouldDehydrateQuery: ({ queryKey }) => { + return queryKey[0] === 'squads'; + }, + }, +}; diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 4c099cb641..64a6719db6 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -18,6 +18,7 @@ "@serwist/next": "^9.0.9", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.35.3", + "@tanstack/react-query-persist-client": "4.36.1", "classnames": "^2.3.2", "date-fns": "^2.28.0", "date-fns-tz": "1.0.0", diff --git a/packages/webapp/pages/_app.tsx b/packages/webapp/pages/_app.tsx index b974c8d301..e9ea83f1bb 100644 --- a/packages/webapp/pages/_app.tsx +++ b/packages/webapp/pages/_app.tsx @@ -4,7 +4,6 @@ import React, { useContext, useEffect, useRef, - useState, } from 'react'; import { AppProps } from 'next/app'; import dynamic from 'next/dynamic'; @@ -12,7 +11,6 @@ import Head from 'next/head'; import 'focus-visible'; import { useConsoleLogo } from '@dailydotdev/shared/src/hooks/useConsoleLogo'; import { DefaultSeo } from 'next-seo'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import AuthContext from '@dailydotdev/shared/src/contexts/AuthContext'; import { useCookieBanner } from '@dailydotdev/shared/src/hooks/useCookieBanner'; import { ProgressiveEnhancementContextProvider } from '@dailydotdev/shared/src/contexts/ProgressiveEnhancementContext'; @@ -28,7 +26,6 @@ import { useNotificationContext } from '@dailydotdev/shared/src/contexts/Notific import { getUnreadText } from '@dailydotdev/shared/src/components/notifications/utils'; import { useLazyModal } from '@dailydotdev/shared/src/hooks/useLazyModal'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import { defaultQueryClientConfig } from '@dailydotdev/shared/src/lib/query'; import { useWebVitals } from '@dailydotdev/shared/src/hooks/useWebVitals'; import { LazyModalElement } from '@dailydotdev/shared/src/components/modals/LazyModalElement'; import { useManualScrollRestoration } from '@dailydotdev/shared/src/hooks'; @@ -36,6 +33,11 @@ import { PushNotificationContextProvider } from '@dailydotdev/shared/src/context import { useThemedAsset } from '@dailydotdev/shared/src/hooks/utils'; import { DndContextProvider } from '@dailydotdev/shared/src/contexts/DndContext'; import { structuredCloneJsonPolyfill } from '@dailydotdev/shared/src/lib/structuredClone'; +import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; +import { + persistedQueryClient, + persistedQueryClientOptions, +} from '@dailydotdev/shared/src/lib/persistedQuery'; import Seo, { defaultSeo, defaultSeoTitle } from '../next-seo'; import useWebappVersion from '../hooks/useWebappVersion'; @@ -199,9 +201,6 @@ function InternalApp({ Component, pageProps, router }: AppProps): ReactElement { } export default function App(props: AppProps): ReactElement { - const [queryClient] = useState( - () => new QueryClient(defaultQueryClientConfig), - ); const version = useWebappVersion(); const deviceId = useDeviceId(); useError(); @@ -209,7 +208,10 @@ export default function App(props: AppProps): ReactElement { return ( - + - + ); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b31fcfe55..511d265ee7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -398,6 +398,12 @@ importers: '@growthbook/growthbook-react': specifier: ^0.17.0 version: 0.17.0(react@18.3.1) + '@tanstack/query-sync-storage-persister': + specifier: 4.36.1 + version: 4.36.1 + '@tanstack/react-query-persist-client': + specifier: 4.36.1 + version: 4.36.1(@tanstack/react-query@4.36.1) '@tippyjs/react': specifier: ^4.2.5 version: 4.2.5(react-dom@18.3.1)(react@18.3.1) @@ -826,6 +832,9 @@ importers: '@tanstack/react-query-devtools': specifier: ^4.35.3 version: 4.35.3(@tanstack/react-query@4.36.1)(react-dom@18.3.1)(react@18.3.1) + '@tanstack/react-query-persist-client': + specifier: 4.36.1 + version: 4.36.1(@tanstack/react-query@4.36.1) classnames: specifier: ^2.3.2 version: 2.3.2 @@ -5914,6 +5923,18 @@ packages: /@tanstack/query-core@4.36.1: resolution: {integrity: sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==} + /@tanstack/query-persist-client-core@4.36.1: + resolution: {integrity: sha512-eocgCeI7D7TRv1IUUBMfVwOI0wdSmMkBIbkKhqEdTrnUHUQEeOaYac8oeZk2cumAWJdycu6P/wB+WqGynTnzXg==} + dependencies: + '@tanstack/query-core': 4.36.1 + dev: false + + /@tanstack/query-sync-storage-persister@4.36.1: + resolution: {integrity: sha512-yMEt5hWe2+1eclf1agMtXHnPIkxEida0lYWkfdhR8U6KXk/lO4Vca6piJmhKI85t0NHlx3l/z6zX+t/Fn5O9NA==} + dependencies: + '@tanstack/query-persist-client-core': 4.36.1 + dev: false + /@tanstack/react-query-devtools@4.35.3(@tanstack/react-query@4.36.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UvLT7qPzCuCZ3NfjwsOqDUVN84JvSOuW6ukrjZmSqgjPqVxD6ra/HUp1CEOatQY2TRvKCp8y1lTVu+trXM30fg==} peerDependencies: @@ -5928,6 +5949,15 @@ packages: superjson: 1.13.3 use-sync-external-store: 1.2.0(react@18.3.1) + /@tanstack/react-query-persist-client@4.36.1(@tanstack/react-query@4.36.1): + resolution: {integrity: sha512-32I5b9aAu4NCiXZ7Te/KEQLfHbYeTNriVPrKYcvEThnZ9tlW01vLcSoxpUIsMYRsembvJUUAkzYBAiZHLOd6pQ==} + peerDependencies: + '@tanstack/react-query': ^4.36.1 + dependencies: + '@tanstack/query-persist-client-core': 4.36.1 + '@tanstack/react-query': 4.36.1(react-dom@18.3.1)(react@18.3.1) + dev: false + /@tanstack/react-query@4.36.1(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==} peerDependencies: From 181f08e72240a005597cfe42418478abf5ad48a7 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Thu, 24 Oct 2024 16:54:35 +0200 Subject: [PATCH 02/17] Add loader function to SquadSection --- package-lock.json | 38 +++++++++++++++++++ .../shared/src/components/sidebar/Section.tsx | 27 +++++++++++++ .../src/components/sidebar/SquadSection.tsx | 7 +--- packages/shared/src/lib/boot.ts | 3 -- 4 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..b86f306b21 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,38 @@ +{ + "name": "daily-apps", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "daily-apps", + "dependencies": { + "@babel/runtime": "^7.25.9", + "postcss-rem-to-responsive-pixel": "^6.0.2" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-rem-to-responsive-pixel": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-rem-to-responsive-pixel/-/postcss-rem-to-responsive-pixel-6.0.2.tgz", + "integrity": "sha512-Qseol4vPNC+WJIzwU7AWXGc7pjcw+7c2YRh6bwpwz/4akmtL9Zu/mZ87yeaiGuqQaBgQy45266uxIBQY+BMUfQ==", + "engines": { + "node": ">=16.6.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + } + } +} diff --git a/packages/shared/src/components/sidebar/Section.tsx b/packages/shared/src/components/sidebar/Section.tsx index 7a1a0b61a5..b338d99705 100644 --- a/packages/shared/src/components/sidebar/Section.tsx +++ b/packages/shared/src/components/sidebar/Section.tsx @@ -11,6 +11,7 @@ import { SidebarMenuItem, } from './common'; import { AuthTriggersType } from '../../lib/auth'; +import { TextPlaceholder } from '../widgets/common'; export interface SectionCommonProps extends Pick { @@ -24,6 +25,7 @@ interface SectionProps extends SectionCommonProps { title?: string; items: SidebarMenuItem[]; isItemsButton: boolean; + isLoading?: boolean } export function Section({ @@ -35,6 +37,7 @@ export function Section({ activePage, isItemsButton, className, + isLoading }: SectionProps): ReactElement { const { user, showLogin } = useContext(AuthContext); @@ -57,6 +60,7 @@ export function Section({ {title} )} + {isLoading && } {items.filter(mobileItemsFilter).map((item) => ( ); } + +const ItemsSkeleton = () => { + return ( + <> +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + ) +} diff --git a/packages/shared/src/components/sidebar/SquadSection.tsx b/packages/shared/src/components/sidebar/SquadSection.tsx index ea15d02083..fc471c89db 100644 --- a/packages/shared/src/components/sidebar/SquadSection.tsx +++ b/packages/shared/src/components/sidebar/SquadSection.tsx @@ -8,9 +8,9 @@ import { useSquadNavigation } from '../../hooks'; import AuthContext from '../../contexts/AuthContext'; import { SquadImage } from '../squads/SquadImage'; import { getSquads } from '../../graphql/squads'; +import { TextPlaceholder } from '../widgets/common'; export function SquadSection(props: SectionCommonProps): ReactElement { - // const { squads } = useContext(AuthContext); const { user } = useContext(AuthContext); const { data: squads, isLoading } = useQuery(['squads'], () => @@ -18,10 +18,6 @@ export function SquadSection(props: SectionCommonProps): ReactElement { ); const { openNewSquad } = useSquadNavigation(); - if (isLoading) { - return loading; - } - const squadMenuItems: SidebarMenuItem[] = [ { icon: (active: boolean) => ( @@ -60,6 +56,7 @@ export function SquadSection(props: SectionCommonProps): ReactElement { items={squadMenuItems} {...props} isItemsButton={false} + isLoading={isLoading} /> ); } diff --git a/packages/shared/src/lib/boot.ts b/packages/shared/src/lib/boot.ts index 0014803e65..ef2216b6fc 100644 --- a/packages/shared/src/lib/boot.ts +++ b/packages/shared/src/lib/boot.ts @@ -4,7 +4,6 @@ import { apiUrl } from './config'; import { Alerts } from '../graphql/alerts'; import { RemoteSettings } from '../graphql/settings'; import { Post } from '../graphql/posts'; -import { Squad } from '../graphql/sources'; import { decrypt } from '../components/crypto'; import { MarketingCta } from '../components/marketingCta/common'; import { Feed } from '../graphql/feed'; @@ -53,7 +52,6 @@ export type Boot = { visit: Visit; notifications: NotificationsBootData; settings: RemoteSettings; - squads: Squad[]; postData?: PostBootData; isLegacyLogout?: boolean; exp?: { @@ -74,7 +72,6 @@ export type BootCacheData = Pick< | 'settings' | 'postData' | 'notifications' - | 'squads' | 'exp' | 'feeds' > & { lastModifier?: string }; From 462f1e2fd782be5ee8f7b4fb1b47acf2edfeb5f0 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Thu, 24 Oct 2024 19:39:30 +0200 Subject: [PATCH 03/17] Rewrite boot functions to hooks with useQuery --- .../src/components/sidebar/SquadSection.tsx | 13 ++---- packages/shared/src/contexts/BootProvider.tsx | 4 +- packages/shared/src/hooks/squads/useSquad.ts | 17 ++++++- .../shared/src/hooks/squads/useSquadCreate.ts | 8 ++-- packages/shared/src/hooks/useBoot.ts | 44 ++----------------- packages/shared/src/hooks/useDeleteSquad.ts | 14 ++++-- packages/shared/src/hooks/useJoinSquad.ts | 17 ++++--- packages/shared/src/hooks/useLeaveSquad.ts | 15 ++++--- packages/shared/src/lib/persistedQuery.ts | 6 ++- packages/shared/src/lib/query.ts | 1 + .../webapp/pages/squads/[handle]/edit.tsx | 5 +-- 11 files changed, 67 insertions(+), 77 deletions(-) diff --git a/packages/shared/src/components/sidebar/SquadSection.tsx b/packages/shared/src/components/sidebar/SquadSection.tsx index fc471c89db..84425097b0 100644 --- a/packages/shared/src/components/sidebar/SquadSection.tsx +++ b/packages/shared/src/components/sidebar/SquadSection.tsx @@ -1,21 +1,14 @@ -import React, { ReactElement, useContext } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import React, { ReactElement } from 'react'; import { ListIcon, SidebarMenuItem } from './common'; import { Section, SectionCommonProps } from './Section'; import { NewSquadIcon, DefaultSquadIcon, SourceIcon } from '../icons'; import { Origin } from '../../lib/log'; -import { useSquadNavigation } from '../../hooks'; -import AuthContext from '../../contexts/AuthContext'; +import { useSquadNavigation, useSquads } from '../../hooks'; import { SquadImage } from '../squads/SquadImage'; -import { getSquads } from '../../graphql/squads'; -import { TextPlaceholder } from '../widgets/common'; export function SquadSection(props: SectionCommonProps): ReactElement { - const { user } = useContext(AuthContext); + const { squads, isLoading } = useSquads(); - const { data: squads, isLoading } = useQuery(['squads'], () => - getSquads(user?.id), - ); const { openNewSquad } = useSquadNavigation(); const squadMenuItems: SidebarMenuItem[] = [ diff --git a/packages/shared/src/contexts/BootProvider.tsx b/packages/shared/src/contexts/BootProvider.tsx index d95cbcbf26..57c0b13a89 100644 --- a/packages/shared/src/contexts/BootProvider.tsx +++ b/packages/shared/src/contexts/BootProvider.tsx @@ -74,7 +74,6 @@ const updateLocalBootData = ( 'notifications', 'user', 'lastModifier', - 'squads', 'exp', 'feeds', ]); @@ -182,7 +181,7 @@ export const BootDataProvider = ({ const isBootReady = isFetched && !isError; const loadedFromCache = !!bootData; - const { user, settings, alerts, notifications, squads } = bootData || {}; + const { user, settings, alerts, notifications } = bootData || {}; useRefreshToken(bootData?.accessToken, refetch); const updatedAtActive = user ? dataUpdatedAt : null; @@ -277,7 +276,6 @@ export const BootDataProvider = ({ isLegacyLogout={bootData?.isLegacyLogout} accessToken={bootData?.accessToken} isPastRegistration={isInitialFetch.current} - squads={squads} > { : !!getApiError(error as ApiErrorResult, ApiError.Forbidden), }; }; + +export const useSquads = () => { + const { isFetched: isBootFetched, user } = useContext(AuthContext); + // const queryKey = generateQueryKey(RequestKey.Squads); + + const { data: squads, isLoading, isFetched } = useQuery([RequestKey.Squads], () => + getSquads(user?.id), + ); +console.log("squads",squads) + return { + squads, + isLoading, + isFetched, + } +} \ No newline at end of file diff --git a/packages/shared/src/hooks/squads/useSquadCreate.ts b/packages/shared/src/hooks/squads/useSquadCreate.ts index 10008bd3ad..c5a3f52c46 100644 --- a/packages/shared/src/hooks/squads/useSquadCreate.ts +++ b/packages/shared/src/hooks/squads/useSquadCreate.ts @@ -6,12 +6,13 @@ import { LogEvent } from '../../lib/log'; import { ActionType } from '../../graphql/actions'; import LogContext from '../../contexts/LogContext'; import { useToastNotification } from '../useToastNotification'; -import { useBoot } from '../useBoot'; import { useActions } from '../useActions'; import { Squad } from '../../graphql/sources'; import { ApiErrorResult } from '../../graphql/common'; import { parseOrDefault } from '../../lib/func'; import { getRandom4Digits } from '../../lib'; +import { persistedQueryClient } from '../../lib/persistedQuery'; +import { RequestKey } from '../../lib/query'; interface UseSquadCreateProps { onSuccess?: (squad: Squad) => void; @@ -32,7 +33,6 @@ export const useSquadCreate: CustomHook = ({ onSuccess, retryWithRandomizedHandle, } = {}) => { - const { addSquad } = useBoot(); const { logEvent } = useContext(LogContext); const { displayToast } = useToastNotification(); const { completeAction } = useActions(); @@ -43,11 +43,13 @@ export const useSquadCreate: CustomHook = ({ event_name: LogEvent.CompleteSquadCreation, }); - addSquad(squad); completeAction(ActionType.CreateSquad); if (onSuccess) { onSuccess(squad); + persistedQueryClient.invalidateQueries({ + queryKey: [RequestKey.Squads], + }); } else { router.replace(squad.permalink); } diff --git a/packages/shared/src/hooks/useBoot.ts b/packages/shared/src/hooks/useBoot.ts index f5c21766d1..a5b5b1e4fa 100644 --- a/packages/shared/src/hooks/useBoot.ts +++ b/packages/shared/src/hooks/useBoot.ts @@ -10,52 +10,19 @@ import { CLEAR_MARKETING_CTA_MUTATION } from '../graphql/users'; import { gqlClient } from '../graphql/common'; type UseBoot = { - addSquad: (squad: Squad) => void; - deleteSquad: (squadId: string) => void; - updateSquad: (squad: Squad) => void; getMarketingCta: (variant: MarketingCtaVariant) => MarketingCta | null; clearMarketingCta: (campaignId: string) => void; }; -const sortByName = (squads: Squad[]): Squad[] => - [...squads].sort((a, b) => - a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase() ? 1 : -1, - ); +// const sortByName = (squads: Squad[]): Squad[] => +// [...squads].sort((a, b) => +// a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase() ? 1 : -1, +// ); export const useBoot = (): UseBoot => { const client = useQueryClient(); const getBootData = () => client.getQueryData(BOOT_QUERY_KEY); - const addSquad = (squad: Squad) => { - const bootData = getBootData(); - const currentSquads = bootData?.squads || []; - const squadExists = currentSquads.some((item) => item.id === squad.id); - - if (squadExists) { - return; - } - - const squads = sortByName([...currentSquads, squad]); - client.setQueryData(BOOT_QUERY_KEY, { ...bootData, squads }); - }; - - const deleteSquad = (squadId: string) => { - const bootData = getBootData(); - const squads = bootData.squads?.filter((squad) => squad.id !== squadId); - client.setQueryData(BOOT_QUERY_KEY, { ...bootData, squads }); - }; - - const updateSquad = (squad: Squad) => { - const bootData = getBootData(); - const squads = bootData.squads?.map((bootSquad) => - squad.id !== bootSquad.id ? bootSquad : squad, - ); - client.setQueryData(BOOT_QUERY_KEY, { - ...bootData, - squads: sortByName(squads ?? []), - }); - }; - const getMarketingCta = ( variant: MarketingCtaVariant, ): MarketingCta | null => { @@ -84,9 +51,6 @@ export const useBoot = (): UseBoot => { }; return { - addSquad, - deleteSquad, - updateSquad, getMarketingCta, clearMarketingCta, }; diff --git a/packages/shared/src/hooks/useDeleteSquad.ts b/packages/shared/src/hooks/useDeleteSquad.ts index 7b0c495060..2cede334d9 100644 --- a/packages/shared/src/hooks/useDeleteSquad.ts +++ b/packages/shared/src/hooks/useDeleteSquad.ts @@ -1,11 +1,13 @@ import { useContext, useMemo } from 'react'; +import { useMutation } from '@tanstack/react-query'; import { deleteSquad } from '../graphql/squads'; import { Squad } from '../graphql/sources'; import { PromptOptions, usePrompt } from './usePrompt'; -import { useBoot } from './useBoot'; import LogContext from '../contexts/LogContext'; import { LogEvent } from '../lib/log'; import { ButtonColor } from '../components/buttons/Button'; +import { persistedQueryClient } from '../lib/persistedQuery'; +import { RequestKey } from '../lib/query'; interface UseDeleteSquadModal { onDeleteSquad: () => void; @@ -22,7 +24,12 @@ export const useDeleteSquad = ({ }: UseDeleteSquadProps): UseDeleteSquadModal => { const { logEvent } = useContext(LogContext); const { showPrompt } = usePrompt(); - const { deleteSquad: deleteCachedSquad } = useBoot(); + // const { deleteSquad: deleteCachedSquad } = useBoot(); + const { mutate } = useMutation([squad.id], deleteSquad, { + onSuccess: () => { + persistedQueryClient.invalidateQueries([RequestKey.Squads]); + }, + }); // @NOTE see https://dailydotdev.atlassian.net/l/cp/dK9h1zoM // eslint-disable-next-line react-hooks/exhaustive-deps @@ -42,8 +49,7 @@ export const useDeleteSquad = ({ event_name: LogEvent.DeleteSquad, extra: JSON.stringify({ squad: squad.id }), }); - await deleteSquad(squad.id); - deleteCachedSquad(squad.id); + await mutate(squad.id); await callback?.(); } }; diff --git a/packages/shared/src/hooks/useJoinSquad.ts b/packages/shared/src/hooks/useJoinSquad.ts index d3a406fbac..3d6b2df85f 100644 --- a/packages/shared/src/hooks/useJoinSquad.ts +++ b/packages/shared/src/hooks/useJoinSquad.ts @@ -1,13 +1,13 @@ -import { useQueryClient } from '@tanstack/react-query'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useCallback } from 'react'; import { joinSquadInvitation, SquadInvitationProps } from '../graphql/squads'; import { useLogContext } from '../contexts/LogContext'; import { Squad } from '../graphql/sources'; import { LogEvent } from '../lib/log'; -import { useBoot } from './useBoot'; import { generateQueryKey, RequestKey } from '../lib/query'; import { ActionType } from '../graphql/actions'; import { useActions } from './useActions'; +import { persistedQueryClient } from '../lib/persistedQuery'; type UseJoinSquadProps = { squad: Pick; @@ -21,9 +21,17 @@ export const useJoinSquad = ({ referralToken, }: UseJoinSquadProps): UseJoinSquad => { const queryClient = useQueryClient(); - const { addSquad } = useBoot(); const { logEvent } = useLogContext(); const { completeAction } = useActions(); + const { mutateAsync: addSquad } = useMutation( + [squad.id], + joinSquadInvitation, + { + onSuccess: () => { + persistedQueryClient.invalidateQueries([RequestKey.Squads]); + }, + }, + ); const joinSquad = useCallback(async () => { const payload: SquadInvitationProps = { @@ -44,8 +52,6 @@ export const useJoinSquad = ({ }), }); - addSquad(result); - const queryKey = generateQueryKey( RequestKey.Squad, result.currentMember.user, @@ -61,7 +67,6 @@ export const useJoinSquad = ({ squad.handle, referralToken, logEvent, - addSquad, completeAction, queryClient, ]); diff --git a/packages/shared/src/hooks/useLeaveSquad.ts b/packages/shared/src/hooks/useLeaveSquad.ts index 2121a451fb..44bf8dd07b 100644 --- a/packages/shared/src/hooks/useLeaveSquad.ts +++ b/packages/shared/src/hooks/useLeaveSquad.ts @@ -1,11 +1,13 @@ import { useCallback, useContext } from 'react'; +import { useMutation } from '@tanstack/react-query'; import { leaveSquad } from '../graphql/squads'; import { Squad } from '../graphql/sources'; import { PromptOptions, usePrompt } from './usePrompt'; -import { useBoot } from './useBoot'; import LogContext from '../contexts/LogContext'; import { LogEvent } from '../lib/log'; import { ButtonColor } from '../components/buttons/Button'; +import { persistedQueryClient } from '../lib/persistedQuery'; +import { RequestKey } from '../lib/query'; interface Params { forceLeave?: boolean; @@ -21,7 +23,11 @@ type UseLeaveSquadProps = { export const useLeaveSquad = ({ squad }: UseLeaveSquadProps): UseLeaveSquad => { const { logEvent } = useContext(LogContext); const { showPrompt } = usePrompt(); - const { deleteSquad: deleteCachedSquad } = useBoot(); + const { mutate } = useMutation(leaveSquad, { + onSuccess: () => { + persistedQueryClient.invalidateQueries({ queryKey: [RequestKey.Squads] }); + }, + }); const onLeaveSquad = useCallback( async ({ forceLeave = false }: Params = {}) => { @@ -40,13 +46,12 @@ export const useLeaveSquad = ({ squad }: UseLeaveSquadProps): UseLeaveSquad => { event_name: LogEvent.LeaveSquad, extra: JSON.stringify({ squad: squad.id }), }); - await leaveSquad(squad.id); - deleteCachedSquad(squad.id); + mutate(squad.id); } return left; }, - [deleteCachedSquad, showPrompt, squad, logEvent], + [showPrompt, squad, logEvent], ); return onLeaveSquad; diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index eeb60269fe..e4129c6fae 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -1,7 +1,7 @@ import { QueryClient } from '@tanstack/react-query'; import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'; import { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'; -import { StaleTime } from './query'; +import { RequestKey, StaleTime } from './query'; export const persistedQueryClient = new QueryClient({ defaultOptions: { @@ -24,7 +24,9 @@ export const persistedQueryClientOptions: Omit< persister: queryClientPersister, dehydrateOptions: { shouldDehydrateQuery: ({ queryKey }) => { - return queryKey[0] === 'squads'; + console.log('queryKey', queryKey); + // TODO: Figure out how to check on both first and second key. + return queryKey[0] === RequestKey.Squads; }, }, }; diff --git a/packages/shared/src/lib/query.ts b/packages/shared/src/lib/query.ts index dc801a8059..7c5c6be9a5 100644 --- a/packages/shared/src/lib/query.ts +++ b/packages/shared/src/lib/query.ts @@ -94,6 +94,7 @@ export enum RequestKey { PostCommentsMutations = 'post_comments_mutations', Actions = 'actions', Squad = 'squad', + Squads = 'squads', SquadMembers = 'squad_members', Search = 'search', SearchHistory = 'searchHistory', diff --git a/packages/webapp/pages/squads/[handle]/edit.tsx b/packages/webapp/pages/squads/[handle]/edit.tsx index 2350157985..c9e9292c9f 100644 --- a/packages/webapp/pages/squads/[handle]/edit.tsx +++ b/packages/webapp/pages/squads/[handle]/edit.tsx @@ -5,7 +5,6 @@ import { useAuthContext } from '@dailydotdev/shared/src/contexts/AuthContext'; import Unauthorized from '@dailydotdev/shared/src/components/errors/Unauthorized'; import { SquadDetails } from '@dailydotdev/shared/src/components/squads/Details'; import { editSquad } from '@dailydotdev/shared/src/graphql/squads'; -import { useBoot } from '@dailydotdev/shared/src/hooks/useBoot'; import { useToastNotification } from '@dailydotdev/shared/src/hooks/useToastNotification'; import { ManageSquadPageContainer } from '@dailydotdev/shared/src/components/squads/utils'; import { MangeSquadPageSkeleton } from '@dailydotdev/shared/src/components/squads/MangeSquadPageSkeleton'; @@ -23,6 +22,7 @@ import { } from '@dailydotdev/shared/src/lib/query'; import { parseOrDefault } from '@dailydotdev/shared/src/lib/func'; import { ApiErrorResult } from '@dailydotdev/shared/src/graphql/common'; +import { persistedQueryClient } from '@dailydotdev/shared/src/lib/persistedQuery'; import { getLayout as getMainLayout } from '../../../components/layouts/MainLayout'; import { defaultOpenGraph, defaultSeo } from '../../../next-seo'; @@ -47,14 +47,13 @@ const EditSquad = ({ handle }: EditSquadPageProps): ReactElement => { isForbidden, } = useSquad({ handle }); const queryClient = useQueryClient(); - const { updateSquad } = useBoot(); const { displayToast } = useToastNotification(); const { mutateAsync: onUpdateSquad, isLoading: isUpdatingSquad } = useMutation(editSquad, { onSuccess: async (data) => { const queryKey = generateQueryKey(RequestKey.Squad, user, data.handle); await queryClient.invalidateQueries(queryKey); - updateSquad(data); + await persistedQueryClient.invalidateQueries([RequestKey.Squads]); displayToast('The Squad has been updated'); }, onError: (error: ApiErrorResult) => { From a26008872f468ec52eb4aa67c07a88b53b7c4b52 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Thu, 24 Oct 2024 20:00:11 +0200 Subject: [PATCH 04/17] Update formatting --- .../shared/src/components/sidebar/Sidebar.tsx | 5 +++-- packages/shared/src/hooks/squads/useSquad.ts | 21 ++++++++++++------- packages/shared/src/lib/persistedQuery.ts | 1 - 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/shared/src/components/sidebar/Sidebar.tsx b/packages/shared/src/components/sidebar/Sidebar.tsx index cf282032c5..2ef5ff0698 100644 --- a/packages/shared/src/components/sidebar/Sidebar.tsx +++ b/packages/shared/src/components/sidebar/Sidebar.tsx @@ -28,7 +28,7 @@ import { getFeedName } from '../../lib/feed'; import { LazyModal } from '../modals/common/types'; import { useLazyModal } from '../../hooks/useLazyModal'; import Logo, { LogoPosition } from '../Logo'; -import { useFeeds, useViewSize, ViewSize } from '../../hooks'; +import { useFeeds, useSquads, useViewSize, ViewSize } from '../../hooks'; import { Button, ButtonIconPosition, @@ -74,7 +74,8 @@ export default function Sidebar({ onLogoClick, }: SidebarProps): ReactElement { const router = useRouter(); - const { user, isLoggedIn, squads, isAuthReady } = useAuthContext(); + const { user, isLoggedIn, isAuthReady } = useAuthContext(); + const { squads } = useSquads(); const { alerts } = useAlertsContext(); const { toggleSidebarExpanded, diff --git a/packages/shared/src/hooks/squads/useSquad.ts b/packages/shared/src/hooks/squads/useSquad.ts index 9dd730ca0f..7b82aea182 100644 --- a/packages/shared/src/hooks/squads/useSquad.ts +++ b/packages/shared/src/hooks/squads/useSquad.ts @@ -42,17 +42,24 @@ export const useSquad = ({ handle }: UseSquadProps): UseSquad => { }; }; -export const useSquads = () => { +type UseSquads = { + squads: Squad[]; + isLoading: boolean; +}; + +export const useSquads = (): UseSquads => { const { isFetched: isBootFetched, user } = useContext(AuthContext); // const queryKey = generateQueryKey(RequestKey.Squads); - const { data: squads, isLoading, isFetched } = useQuery([RequestKey.Squads], () => - getSquads(user?.id), + const { data: squads, isLoading } = useQuery( + [RequestKey.Squads], + () => getSquads(user?.id), + { + enabled: isBootFetched && !!user, + }, ); -console.log("squads",squads) return { squads, isLoading, - isFetched, - } -} \ No newline at end of file + }; +}; diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index e4129c6fae..61cc41d52b 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -24,7 +24,6 @@ export const persistedQueryClientOptions: Omit< persister: queryClientPersister, dehydrateOptions: { shouldDehydrateQuery: ({ queryKey }) => { - console.log('queryKey', queryKey); // TODO: Figure out how to check on both first and second key. return queryKey[0] === RequestKey.Squads; }, From 5735d04c06fd2c2684069f3b0db87602fe5da726 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Thu, 24 Oct 2024 23:55:13 +0200 Subject: [PATCH 05/17] remove comment --- packages/shared/src/lib/persistedQuery.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index 61cc41d52b..48ede8b03e 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -7,7 +7,6 @@ export const persistedQueryClient = new QueryClient({ defaultOptions: { queries: { staleTime: StaleTime.OneHour, - // TODO: When upgrading to version 5, this needs to be renamed to gcTime cacheTime: StaleTime.OneDay, }, }, From e3f4dced0bb13dc965577c0b13eaa8f563d45841 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 00:00:37 +0200 Subject: [PATCH 06/17] Add comment --- packages/shared/src/lib/persistedQuery.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index 48ede8b03e..61cc41d52b 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -7,6 +7,7 @@ export const persistedQueryClient = new QueryClient({ defaultOptions: { queries: { staleTime: StaleTime.OneHour, + // TODO: When upgrading to version 5, this needs to be renamed to gcTime cacheTime: StaleTime.OneDay, }, }, From 3b6bda00b3cc9ee0d1d6a82136fbd4f98b012a0f Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 00:08:38 +0200 Subject: [PATCH 07/17] fix type errors --- packages/extension/src/companion/App.tsx | 11 +---------- .../src/newtab/ShortcutLinks/ShortcutLinks.spec.tsx | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/extension/src/companion/App.tsx b/packages/extension/src/companion/App.tsx index f2c9413305..144332bf1e 100644 --- a/packages/extension/src/companion/App.tsx +++ b/packages/extension/src/companion/App.tsx @@ -34,14 +34,7 @@ const router = new CustomRouter(); export type CompanionData = { url: string; deviceId: string } & Pick< Boot, - | 'postData' - | 'settings' - | 'alerts' - | 'user' - | 'visit' - | 'accessToken' - | 'squads' - | 'exp' + 'postData' | 'settings' | 'alerts' | 'user' | 'visit' | 'accessToken' | 'exp' >; const app = BootApp.Companion; @@ -55,7 +48,6 @@ export default function App({ alerts, visit, accessToken, - squads, exp, }: CompanionData): ReactElement { useError(); @@ -105,7 +97,6 @@ export default function App({ tokenRefreshed getRedirectUri={() => browser.runtime.getURL('index.html')} updateUser={() => null} - squads={squads} > diff --git a/packages/extension/src/newtab/ShortcutLinks/ShortcutLinks.spec.tsx b/packages/extension/src/newtab/ShortcutLinks/ShortcutLinks.spec.tsx index 9bc959ba81..e30df75d1f 100644 --- a/packages/extension/src/newtab/ShortcutLinks/ShortcutLinks.spec.tsx +++ b/packages/extension/src/newtab/ShortcutLinks/ShortcutLinks.spec.tsx @@ -102,7 +102,6 @@ const defaultBootData: BootCacheData = { alerts: defaultAlerts, user: { ...defaultUser, createdAt: '2024-02-16T00:00:00.000Z' }, settings: defaultSettings, - squads: [], notifications: { unreadNotificationsCount: 0 }, feeds: [], }; From acbf83e1a015c411115ff325f9961472c71aa790 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 00:12:11 +0200 Subject: [PATCH 08/17] fix additional type errors --- packages/extension/src/companion/Companion.spec.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/extension/src/companion/Companion.spec.tsx b/packages/extension/src/companion/Companion.spec.tsx index 6bee3a51f5..00a03cd84c 100644 --- a/packages/extension/src/companion/Companion.spec.tsx +++ b/packages/extension/src/companion/Companion.spec.tsx @@ -80,7 +80,6 @@ const renderComponent = (postdata, settings): RenderResult => { user={defaultUser} deviceId="123" accessToken={{ token: '', expiresIn: '' }} - squads={[]} />, ); }; From c3c3882c70dfeb60386bcab525337b4b9847899e Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 01:14:48 +0200 Subject: [PATCH 09/17] Set mutation cache --- packages/shared/src/lib/persistedQuery.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index 61cc41d52b..323ab3fe5e 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -1,9 +1,10 @@ import { QueryClient } from '@tanstack/react-query'; import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'; import { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'; -import { RequestKey, StaleTime } from './query'; +import { globalMutationCache, RequestKey, StaleTime } from './query'; export const persistedQueryClient = new QueryClient({ + mutationCache: globalMutationCache, defaultOptions: { queries: { staleTime: StaleTime.OneHour, @@ -24,7 +25,6 @@ export const persistedQueryClientOptions: Omit< persister: queryClientPersister, dehydrateOptions: { shouldDehydrateQuery: ({ queryKey }) => { - // TODO: Figure out how to check on both first and second key. return queryKey[0] === RequestKey.Squads; }, }, From 6db23431a5f4dbc48bf328f6705097bc550a1458 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 01:15:05 +0200 Subject: [PATCH 10/17] Update companion app --- packages/extension/package.json | 1 + packages/extension/src/companion/App.tsx | 15 ++++++++++----- packages/shared/src/contexts/AuthContext.tsx | 9 +++++++++ pnpm-lock.yaml | 3 +++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/extension/package.json b/packages/extension/package.json index 6caee0ebde..ceb008d8d8 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -20,6 +20,7 @@ "@dailydotdev/shared": "*", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.35.3", + "@tanstack/react-query-persist-client": "^4.36.1", "classnames": "^2.5.1", "date-fns": "^2.25.0", "date-fns-tz": "1.0.0", diff --git a/packages/extension/src/companion/App.tsx b/packages/extension/src/companion/App.tsx index 144332bf1e..4633d1be0f 100644 --- a/packages/extension/src/companion/App.tsx +++ b/packages/extension/src/companion/App.tsx @@ -1,5 +1,4 @@ import React, { ReactElement, useState } from 'react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import browser from 'webextension-polyfill'; import { Boot, BootApp } from '@dailydotdev/shared/src/lib/boot'; import { AuthContextProvider } from '@dailydotdev/shared/src/contexts/AuthContext'; @@ -15,13 +14,17 @@ import { ExtensionMessageType, getCompanionWrapper, } from '@dailydotdev/shared/src/lib/extension'; -import { defaultQueryClientConfig } from '@dailydotdev/shared/src/lib/query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { PromptElement } from '@dailydotdev/shared/src/components/modals/Prompt'; import { GrowthBookProvider } from '@dailydotdev/shared/src/components/GrowthBookProvider'; import { NotificationsContextProvider } from '@dailydotdev/shared/src/contexts/NotificationsContext'; import { useEventListener } from '@dailydotdev/shared/src/hooks'; import { structuredCloneJsonPolyfill } from '@dailydotdev/shared/src/lib/structuredClone'; +import { + persistedQueryClient, + persistedQueryClientOptions, +} from '@dailydotdev/shared/src/lib/persistedQuery'; +import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; import Companion from './Companion'; import CustomRouter from '../lib/CustomRouter'; import { companionFetch } from './companionFetch'; @@ -29,7 +32,6 @@ import { version } from '../../package.json'; structuredCloneJsonPolyfill(); -const queryClient = new QueryClient(defaultQueryClientConfig); const router = new CustomRouter(); export type CompanionData = { url: string; deviceId: string } & Pick< @@ -84,7 +86,10 @@ export default function App({ @import "{browser.runtime.getURL('css/companion.css')}"; - + - + ); diff --git a/packages/shared/src/contexts/AuthContext.tsx b/packages/shared/src/contexts/AuthContext.tsx index b5ded01b5a..1340eed29d 100644 --- a/packages/shared/src/contexts/AuthContext.tsx +++ b/packages/shared/src/contexts/AuthContext.tsx @@ -18,6 +18,10 @@ import { isCompanionActivated } from '../lib/element'; import { AuthTriggers, AuthTriggersType } from '../lib/auth'; import { Squad } from '../graphql/sources'; import { checkIsExtension } from '../lib/func'; +import { + persistedQueryClient, + queryClientPersister, +} from '../lib/persistedQuery'; export interface LoginState { trigger: AuthTriggersType; @@ -84,6 +88,11 @@ export const REGISTRATION_PATH = '/register'; const logout = async (reason: string): Promise => { await dispatchLogout(reason); + // Removes the in memory cache + persistedQueryClient.clear(); + // Removes the persisted cache, which is localStorage in our case. + queryClientPersister.removeClient(); + const params = getQueryParams(); if (params.redirect_uri) { window.location.replace(params.redirect_uri); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e34cb4a165..e1337b745b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,9 @@ importers: '@tanstack/react-query-devtools': specifier: ^4.35.3 version: 4.35.3(@tanstack/react-query@4.36.1)(react-dom@18.3.1)(react@18.3.1) + '@tanstack/react-query-persist-client': + specifier: ^4.36.1 + version: 4.36.1(@tanstack/react-query@4.36.1) classnames: specifier: ^2.5.1 version: 2.5.1 From 77eef05fa782776fe2b6b366efd557a35aa68a91 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 11:05:43 +0200 Subject: [PATCH 11/17] Update squad edit page --- packages/webapp/pages/squads/[handle]/edit.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/webapp/pages/squads/[handle]/edit.tsx b/packages/webapp/pages/squads/[handle]/edit.tsx index c9e9292c9f..11e3dea04a 100644 --- a/packages/webapp/pages/squads/[handle]/edit.tsx +++ b/packages/webapp/pages/squads/[handle]/edit.tsx @@ -9,7 +9,7 @@ import { useToastNotification } from '@dailydotdev/shared/src/hooks/useToastNoti import { ManageSquadPageContainer } from '@dailydotdev/shared/src/components/squads/utils'; import { MangeSquadPageSkeleton } from '@dailydotdev/shared/src/components/squads/MangeSquadPageSkeleton'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useSquad } from '@dailydotdev/shared/src/hooks'; +import { useSquad, useSquads } from '@dailydotdev/shared/src/hooks'; import { GetStaticPathsResult, GetStaticPropsContext, @@ -40,7 +40,8 @@ const DEFAULT_ERROR = "Oops! That didn't seem to work. Let's try again!"; const EditSquad = ({ handle }: EditSquadPageProps): ReactElement => { const { isReady: isRouteReady } = useRouter(); - const { squads, user, isAuthReady, isFetched } = useAuthContext(); + const { user, isAuthReady, isFetched } = useAuthContext(); + const { squads } = useSquads(); const { squad, isLoading: isSquadLoading, From 889f9b1f1cddd8b47018e1744f4aadca86dad120 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 11:18:05 +0200 Subject: [PATCH 12/17] Sort squads by name --- packages/shared/src/graphql/squads.ts | 4 +++- packages/shared/src/hooks/squads/useSquad.ts | 1 - packages/shared/src/hooks/useBoot.ts | 6 ------ packages/shared/src/hooks/useDeleteSquad.ts | 5 ++--- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/shared/src/graphql/squads.ts b/packages/shared/src/graphql/squads.ts index 8d3c55af36..d8db32f921 100644 --- a/packages/shared/src/graphql/squads.ts +++ b/packages/shared/src/graphql/squads.ts @@ -425,7 +425,9 @@ export async function getSquads(userId: string): Promise { id: userId, }, ); - return res.mySourceMemberships.edges.map((edge) => edge.node.source); + const squads = res.mySourceMemberships.edges.map((edge) => edge.node.source); + const sortedByName = squads.sort((a, b) => a.name.localeCompare(b.name)); + return sortedByName; } export async function getSquadMembers(id: string): Promise { diff --git a/packages/shared/src/hooks/squads/useSquad.ts b/packages/shared/src/hooks/squads/useSquad.ts index 7b82aea182..1026f76c75 100644 --- a/packages/shared/src/hooks/squads/useSquad.ts +++ b/packages/shared/src/hooks/squads/useSquad.ts @@ -49,7 +49,6 @@ type UseSquads = { export const useSquads = (): UseSquads => { const { isFetched: isBootFetched, user } = useContext(AuthContext); - // const queryKey = generateQueryKey(RequestKey.Squads); const { data: squads, isLoading } = useQuery( [RequestKey.Squads], diff --git a/packages/shared/src/hooks/useBoot.ts b/packages/shared/src/hooks/useBoot.ts index a5b5b1e4fa..d3f613409b 100644 --- a/packages/shared/src/hooks/useBoot.ts +++ b/packages/shared/src/hooks/useBoot.ts @@ -1,6 +1,5 @@ import { useQueryClient } from '@tanstack/react-query'; import { BOOT_QUERY_KEY } from '../contexts/common'; -import { Squad } from '../graphql/sources'; import { Boot } from '../lib/boot'; import { MarketingCta, @@ -14,11 +13,6 @@ type UseBoot = { clearMarketingCta: (campaignId: string) => void; }; -// const sortByName = (squads: Squad[]): Squad[] => -// [...squads].sort((a, b) => -// a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase() ? 1 : -1, -// ); - export const useBoot = (): UseBoot => { const client = useQueryClient(); const getBootData = () => client.getQueryData(BOOT_QUERY_KEY); diff --git a/packages/shared/src/hooks/useDeleteSquad.ts b/packages/shared/src/hooks/useDeleteSquad.ts index 2cede334d9..d71fa01672 100644 --- a/packages/shared/src/hooks/useDeleteSquad.ts +++ b/packages/shared/src/hooks/useDeleteSquad.ts @@ -24,7 +24,6 @@ export const useDeleteSquad = ({ }: UseDeleteSquadProps): UseDeleteSquadModal => { const { logEvent } = useContext(LogContext); const { showPrompt } = usePrompt(); - // const { deleteSquad: deleteCachedSquad } = useBoot(); const { mutate } = useMutation([squad.id], deleteSquad, { onSuccess: () => { persistedQueryClient.invalidateQueries([RequestKey.Squads]); @@ -49,8 +48,8 @@ export const useDeleteSquad = ({ event_name: LogEvent.DeleteSquad, extra: JSON.stringify({ squad: squad.id }), }); - await mutate(squad.id); - await callback?.(); + mutate(squad.id); + callback?.(); } }; From b4a773e98c94a6cbbe5961d50ca7388ef72e4c97 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 12:39:22 +0200 Subject: [PATCH 13/17] Added default retry properties --- packages/shared/src/lib/persistedQuery.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index 323ab3fe5e..3c6c6f08d1 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -1,7 +1,9 @@ import { QueryClient } from '@tanstack/react-query'; import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'; import { PersistQueryClientOptions } from '@tanstack/react-query-persist-client'; +import { ClientError } from 'graphql-request'; import { globalMutationCache, RequestKey, StaleTime } from './query'; +import { GARMR_ERROR } from '../graphql/common'; export const persistedQueryClient = new QueryClient({ mutationCache: globalMutationCache, @@ -10,6 +12,16 @@ export const persistedQueryClient = new QueryClient({ staleTime: StaleTime.OneHour, // TODO: When upgrading to version 5, this needs to be renamed to gcTime cacheTime: StaleTime.OneDay, + retry: (failureCount, error) => { + const clientError = error as ClientError; + if ( + clientError?.response?.errors?.[0]?.extensions?.code === GARMR_ERROR + ) { + return false; + } + return failureCount < 3; + }, + refetchOnWindowFocus: process.env.NODE_ENV !== 'development', }, }, }); From fb5b14941e1cd903e864cfa299944ecb36f8ca66 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 13:01:30 +0200 Subject: [PATCH 14/17] Update squad join --- packages/shared/src/hooks/squads/useSquadCreate.ts | 4 +--- packages/shared/src/hooks/useJoinSquad.ts | 14 +++++--------- packages/shared/src/lib/persistedQuery.ts | 4 +++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/shared/src/hooks/squads/useSquadCreate.ts b/packages/shared/src/hooks/squads/useSquadCreate.ts index c5a3f52c46..c3272de4b6 100644 --- a/packages/shared/src/hooks/squads/useSquadCreate.ts +++ b/packages/shared/src/hooks/squads/useSquadCreate.ts @@ -47,9 +47,7 @@ export const useSquadCreate: CustomHook = ({ if (onSuccess) { onSuccess(squad); - persistedQueryClient.invalidateQueries({ - queryKey: [RequestKey.Squads], - }); + persistedQueryClient.invalidateQueries([RequestKey.Squads]); } else { router.replace(squad.permalink); } diff --git a/packages/shared/src/hooks/useJoinSquad.ts b/packages/shared/src/hooks/useJoinSquad.ts index 3d6b2df85f..490266b181 100644 --- a/packages/shared/src/hooks/useJoinSquad.ts +++ b/packages/shared/src/hooks/useJoinSquad.ts @@ -23,15 +23,11 @@ export const useJoinSquad = ({ const queryClient = useQueryClient(); const { logEvent } = useLogContext(); const { completeAction } = useActions(); - const { mutateAsync: addSquad } = useMutation( - [squad.id], - joinSquadInvitation, - { - onSuccess: () => { - persistedQueryClient.invalidateQueries([RequestKey.Squads]); - }, + const { mutateAsync } = useMutation([squad.id], joinSquadInvitation, { + onSuccess: () => { + persistedQueryClient.invalidateQueries([RequestKey.Squads]); }, - ); + }); const joinSquad = useCallback(async () => { const payload: SquadInvitationProps = { @@ -42,7 +38,7 @@ export const useJoinSquad = ({ payload.token = referralToken; } - const result = await joinSquadInvitation(payload); + const result = await mutateAsync(payload); logEvent({ event_name: LogEvent.CompleteJoiningSquad, diff --git a/packages/shared/src/lib/persistedQuery.ts b/packages/shared/src/lib/persistedQuery.ts index 3c6c6f08d1..0cdf75f5ed 100644 --- a/packages/shared/src/lib/persistedQuery.ts +++ b/packages/shared/src/lib/persistedQuery.ts @@ -5,6 +5,8 @@ import { ClientError } from 'graphql-request'; import { globalMutationCache, RequestKey, StaleTime } from './query'; import { GARMR_ERROR } from '../graphql/common'; +const persistedKeys = [RequestKey.Squads]; + export const persistedQueryClient = new QueryClient({ mutationCache: globalMutationCache, defaultOptions: { @@ -37,7 +39,7 @@ export const persistedQueryClientOptions: Omit< persister: queryClientPersister, dehydrateOptions: { shouldDehydrateQuery: ({ queryKey }) => { - return queryKey[0] === RequestKey.Squads; + return persistedKeys.includes(queryKey[0] as RequestKey); }, }, }; From 80ad810a2c8bce8ddca537c014d77a054a096c32 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 13:04:43 +0200 Subject: [PATCH 15/17] Add missing dependency --- packages/shared/src/hooks/useJoinSquad.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/hooks/useJoinSquad.ts b/packages/shared/src/hooks/useJoinSquad.ts index 490266b181..b0b41338d3 100644 --- a/packages/shared/src/hooks/useJoinSquad.ts +++ b/packages/shared/src/hooks/useJoinSquad.ts @@ -65,6 +65,7 @@ export const useJoinSquad = ({ logEvent, completeAction, queryClient, + mutateAsync, ]); return joinSquad; From 3f5be5ff1dbc69c696f94b358e91f811476b71e0 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 13:23:53 +0200 Subject: [PATCH 16/17] Linting fixes --- .../shared/src/components/sidebar/Section.tsx | 50 +++++++++---------- packages/shared/src/hooks/useLeaveSquad.ts | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/shared/src/components/sidebar/Section.tsx b/packages/shared/src/components/sidebar/Section.tsx index b338d99705..a20037b9ca 100644 --- a/packages/shared/src/components/sidebar/Section.tsx +++ b/packages/shared/src/components/sidebar/Section.tsx @@ -25,9 +25,32 @@ interface SectionProps extends SectionCommonProps { title?: string; items: SidebarMenuItem[]; isItemsButton: boolean; - isLoading?: boolean + isLoading?: boolean; } +const ItemsSkeleton = () => { + return ( + <> +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + ); +}; + export function Section({ title, items, @@ -37,7 +60,7 @@ export function Section({ activePage, isItemsButton, className, - isLoading + isLoading, }: SectionProps): ReactElement { const { user, showLogin } = useContext(AuthContext); @@ -88,26 +111,3 @@ export function Section({ ); } - -const ItemsSkeleton = () => { - return ( - <> -
- - -
-
- - -
-
- - -
-
- - -
- - ) -} diff --git a/packages/shared/src/hooks/useLeaveSquad.ts b/packages/shared/src/hooks/useLeaveSquad.ts index 44bf8dd07b..33f4243b69 100644 --- a/packages/shared/src/hooks/useLeaveSquad.ts +++ b/packages/shared/src/hooks/useLeaveSquad.ts @@ -51,7 +51,7 @@ export const useLeaveSquad = ({ squad }: UseLeaveSquadProps): UseLeaveSquad => { return left; }, - [showPrompt, squad, logEvent], + [showPrompt, squad, logEvent, mutate], ); return onLeaveSquad; From 32cf049c5f45efa5fab38541978143d0616a5743 Mon Sep 17 00:00:00 2001 From: Amar Trebinjac Date: Fri, 25 Oct 2024 13:38:56 +0200 Subject: [PATCH 17/17] Remove unneeded changes to companion app --- packages/extension/src/companion/App.tsx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/extension/src/companion/App.tsx b/packages/extension/src/companion/App.tsx index 4633d1be0f..f90748e721 100644 --- a/packages/extension/src/companion/App.tsx +++ b/packages/extension/src/companion/App.tsx @@ -20,11 +20,8 @@ import { GrowthBookProvider } from '@dailydotdev/shared/src/components/GrowthBoo import { NotificationsContextProvider } from '@dailydotdev/shared/src/contexts/NotificationsContext'; import { useEventListener } from '@dailydotdev/shared/src/hooks'; import { structuredCloneJsonPolyfill } from '@dailydotdev/shared/src/lib/structuredClone'; -import { - persistedQueryClient, - persistedQueryClientOptions, -} from '@dailydotdev/shared/src/lib/persistedQuery'; -import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { defaultQueryClientConfig } from '@dailydotdev/shared/src/lib/query'; import Companion from './Companion'; import CustomRouter from '../lib/CustomRouter'; import { companionFetch } from './companionFetch'; @@ -32,6 +29,7 @@ import { version } from '../../package.json'; structuredCloneJsonPolyfill(); +const queryClient = new QueryClient(defaultQueryClientConfig); const router = new CustomRouter(); export type CompanionData = { url: string; deviceId: string } & Pick< @@ -86,10 +84,7 @@ export default function App({ @import "{browser.runtime.getURL('css/companion.css')}"; - + - + );