Skip to content

Commit

Permalink
Merge pull request #570 from audioverse-org/prefetching-and-hydration…
Browse files Browse the repository at this point in the history
…-fixes

AV-1153: Fix prefetching and hydration
  • Loading branch information
narthur authored Sep 27, 2024
2 parents 3e7de6a + 50a949b commit b16dbb1
Show file tree
Hide file tree
Showing 16 changed files with 68 additions and 80 deletions.
3 changes: 2 additions & 1 deletion audit-ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"GHSA-qw6h-vgh9-j6wx", // Used by lighthouse CI, not at runtime
"GHSA-m6fv-jmcg-4jfg", // Used by lighthouse CI, not at runtime
"GHSA-m6fv-jmcg-4jfg", // Used by lighthouse CI, not at runtime
"GHSA-cm22-4g7w-348p" // Used by lighthouse CI, not at runtime
"GHSA-cm22-4g7w-348p", // Used by lighthouse CI, not at runtime
"GHSA-gp8f-8m3g-qvj9" // Deployments on Vercel are not affected
]
}
9 changes: 7 additions & 2 deletions graphql-codegen/graphql-plugin-prefetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ const options = { cacheTime: 24 * 60 * 60 * 1000 };
async function doPrefetch<T extends Key>(k: T, v: Vars[T], client: QueryClient) {
const r = await fns[k](v as any);
await client.prefetchQuery([k, v], () => r, options);
await client.prefetchInfiniteQuery([\`\${k}.infinite\`, v], () => r, options);
const hasVars = Object.keys(v as any).length > 0;
const queryKey = hasVars ? [k, v] : [k];
const infiniteQueryKey = hasVars ? [\`\${k}.infinite\`, v] : [\`\${k}.infinite\`];
await client.prefetchQuery(queryKey, () => r, options);
await client.prefetchInfiniteQuery(infiniteQueryKey, () => r, options);
}
export async function prefetchQueries(
Expand Down
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"react-facebook-login": "^4.1.1",
"react-google-login": "^5.2.2",
"react-intl": "^6.4.4",
"rollup": "^2.79.2",
"sass": "^1.42.1",
"sharp": "^0.33.4",
"striptags": "^3.2.0",
Expand Down Expand Up @@ -144,6 +145,11 @@
"type-fest": "^4.3.1",
"typescript": "^5.1.6"
},
"overrides": {
"next-pwa": {
"rollup": "$rollup"
}
},
"nextBundleAnalysis": {
"budget": 230400,
"budgetPercentIncreaseRed": 5,
Expand Down
7 changes: 3 additions & 4 deletions src/components/HOCs/withAuthGuard.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import React, { ReactElement } from 'react';
import withAuthGuard from '~components/HOCs/withAuthGuard';
import { RegisterSocialDocument } from '~containers/account/__generated__/register';
import { fetchApi } from '~lib/api/fetchApi';
import { GetIsAuthenticatedDocument } from '~lib/hooks/__generated__/useIsAuthenticated';
import renderWithProviders from '~lib/test/renderWithProviders';

import { GetWithAuthGuardDataDocument } from './__generated__/withAuthGuard';

function render() {
const Comp = withAuthGuard(() => <>hello world</>);
return (async function (
Expand All @@ -27,7 +26,7 @@ describe('withAuthGuard', () => {
beforeEach(() => __loadRouter({ query: {} }));
it('displays login if no email', async () => {
when(fetchApi)
.calledWith(GetWithAuthGuardDataDocument, expect.anything())
.calledWith(GetIsAuthenticatedDocument, expect.anything())
.mockResolvedValue({
me: {
user: {
Expand Down Expand Up @@ -74,7 +73,7 @@ describe('withAuthGuard', () => {
});

when(fetchApi)
.calledWith(GetWithAuthGuardDataDocument, expect.anything())
.calledWith(GetIsAuthenticatedDocument, expect.anything())
.mockResolvedValue({
me: {
user: {
Expand Down
4 changes: 2 additions & 2 deletions src/components/HOCs/withAuthGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ function withAuthGuard<P extends React.JSX.IntrinsicAttributes>(
): React.ComponentType<P> {
function WithAuthGuard(props: P) {
const sessionToken = getSessionToken(getCurrentRequest());
const { isUserLoggedIn, isLoading } = useIsAuthenticated();
const { isUserLoggedIn, isFetching } = useIsAuthenticated();

return (sessionToken && isLoading) || isUserLoggedIn ? (
return (sessionToken && isFetching) || isUserLoggedIn ? (
<Component {...props} />
) : (
<LoggedOutComponent />
Expand Down
15 changes: 3 additions & 12 deletions src/components/molecules/player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Image from 'next/legacy/image';
import React, { useContext, useEffect, useState } from 'react';
import { useIntl } from 'react-intl';

import { useGetWithAuthGuardDataQuery } from '~components/HOCs/__generated__/withAuthGuard';
import ButtonDownload from '~components/molecules/buttonDownload';
import ButtonNudge from '~components/molecules/buttonNudge';
import ButtonPlay, {
Expand All @@ -15,7 +14,6 @@ import PlaybackTimes from '~components/molecules/playbackTimes';
import RecordingProgressBar from '~components/molecules/recordingProgressBar';
import { AndMiniplayerFragment } from '~components/templates/__generated__/andMiniplayer';
import { BaseColors } from '~lib/constants';
import { getSessionToken } from '~lib/cookies';
import hasVideo from '~lib/hasVideo';
import useGlobalSpaceDown from '~lib/useGlobalSpaceDown';
import usePlaybackSession from '~lib/usePlaybackSession';
Expand All @@ -24,6 +22,7 @@ import IconChromeCast from '~public/img/icon-chromecast.svg';
import IconFullscreen from '~public/img/icons/icon-fullscreen.svg';
import IconPause from '~public/img/icons/icon-pause-large.svg';
import IconPlay from '~public/img/icons/icon-play-large.svg';
import useIsAuthenticated from '~src/lib/hooks/useIsAuthenticated';

import { PlaybackContext } from '../templates/andPlaybackContext';
import { PlayerFragment } from './__generated__/player';
Expand Down Expand Up @@ -84,15 +83,7 @@ const Player = ({
? BaseColors.WHITE
: BaseColors.DARK;

const sessionToken = getSessionToken(); // i will see if this give any issue
const authResult = useGetWithAuthGuardDataQuery(
{},
{
enabled: !!sessionToken,
retry: false,
}
);
const user = authResult.data?.me?.user;
const { isUserLoggedIn } = useIsAuthenticated();

return (
<div
Expand Down Expand Up @@ -244,7 +235,7 @@ const Player = ({
)}

<ButtonSpeed {...{ recording, backgroundColor }} />
{user ? (
{isUserLoggedIn ? (
<ButtonDownload {...{ recording, backgroundColor }} />
) : (
<ButtonDownloadBlank backgroundColor={backgroundColor} />
Expand Down
11 changes: 2 additions & 9 deletions src/components/organisms/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { FormattedMessage, useIntl } from 'react-intl';

import Heading3 from '~components/atoms/heading3';
import Heading6 from '~components/atoms/heading6';
import { useGetWithAuthGuardDataQuery } from '~components/HOCs/__generated__/withAuthGuard';
import Button from '~components/molecules/button';
import DownloadAppButton from '~components/molecules/downloadAppButton';
import LanguageButton from '~components/molecules/languageButton';
Expand All @@ -21,6 +20,7 @@ import IconUser from '~public/img/icons/fa-user-heavy.svg';
import IconDisclosure from '~public/img/icons/icon-disclosure-light-small.svg';
import IconExit from '~public/img/icons/icon-exit.svg';
import { BaseColors } from '~src/lib/constants';
import useIsAuthenticated from '~src/lib/hooks/useIsAuthenticated';

import { analytics } from '../../lib/analytics';
import IconButton from '../molecules/iconButton';
Expand Down Expand Up @@ -62,14 +62,7 @@ const Navigation = ({
}
}, [router.asPath, sessionToken]);

const authResult = useGetWithAuthGuardDataQuery(
{},
{
enabled: !!sessionToken,
retry: false,
}
);
const user = authResult.data?.me?.user;
const { user } = useIsAuthenticated();

const navigationItems = useNavigationItems();
const submenuItem = navigationItems.find(
Expand Down
12 changes: 4 additions & 8 deletions src/containers/library/playlist/libraryPlaylistDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';

import NotFound from '~components/organisms/notFound';
import PlaylistDetail from '~containers/library/playlist/detail';
import LoadingCards from '~src/components/molecules/loadingCards';

import { getLibraryPlaylistPageData } from './__generated__/detail';
import { useGetLibraryPlaylistPageDataQuery } from './__generated__/detail';

function LibraryPlaylistDetail(): JSX.Element {
const router = useRouter();
const playlistId = router.query.playlist as string;

const { data, isLoading } = useQuery(
['getLibraryPlaylistPageData', { id: playlistId }],
() => getLibraryPlaylistPageData({ id: playlistId }),
{ staleTime: Infinity }
);
const { data, isLoading } = useGetLibraryPlaylistPageDataQuery({
id: playlistId,
});

if (isLoading) {
return <LoadingCards />;
Expand Down
2 changes: 1 addition & 1 deletion src/containers/sponsor/list/all.graphql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
query getSponsorListAllPageData($language: Language!, $after: String) {
query getSponsorListAllPageData($language: Language!, $after: String = null) {
sponsors(
language: $language
orderBy: [{ field: TITLE, direction: ASC }]
Expand Down
39 changes: 20 additions & 19 deletions src/containers/sponsor/list/all.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import React, { useEffect, useRef } from 'react';
import { useIntl } from 'react-intl';

import { fetchApi } from '~lib/api/fetchApi';
import useOnScreen from '~lib/hooks/useOnScreen';
import { useLanguageId } from '~lib/useLanguageId';
import { Maybe } from '~src/__generated__/graphql';

import {
GetSponsorListAllPageDataDocument,
GetSponsorListAllPageDataQuery,
useInfiniteGetSponsorListAllPageDataQuery,
} from './__generated__/all';
import Sponsors, { SponsorsProps } from './list';

Expand All @@ -21,29 +19,32 @@ export default function AllSponsors(props: Props) {
const hasReachedEnd = useOnScreen(endRef);
const language = useLanguageId();

const { data, hasNextPage, fetchNextPage, isLoading } = useInfiniteQuery(
['sponsors'],
({ pageParam = null }) =>
fetchApi(GetSponsorListAllPageDataDocument, {
variables: {
language,
after: pageParam,
const { data, hasNextPage, fetchNextPage, isLoading, isFetchingNextPage } =
useInfiniteGetSponsorListAllPageDataQuery(
'after',
{ language },
{
getNextPageParam: (lastPage: Maybe<GetSponsorListAllPageDataQuery>) => {
const pageInfo = lastPage?.sponsors.pageInfo;
if (!pageInfo?.hasNextPage) return;
return { language, after: pageInfo.endCursor };
},
}),
{
getNextPageParam: (lastPage: Maybe<GetSponsorListAllPageDataQuery>) =>
lastPage?.sponsors.pageInfo.hasNextPage
? lastPage.sponsors.pageInfo.endCursor
: undefined,
}
);
}
);

useEffect(() => {
if (!hasNextPage) return;
if (!hasReachedEnd) return;
if (isLoading) return;
if (isFetchingNextPage) return;
fetchNextPage();
}, [hasNextPage, hasReachedEnd, fetchNextPage, isLoading]);
}, [
hasNextPage,
hasReachedEnd,
fetchNextPage,
isLoading,
isFetchingNextPage,
]);

const sponsors = data?.pages.flatMap((p) => p?.sponsors.nodes || []) || [];

Expand Down
2 changes: 1 addition & 1 deletion src/lib/api/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { analytics } from '../analytics';
import { login as _login } from './__generated__/login';

export const USER_SESSION_QUERY_KEYS = [
['getWithAuthGuardData'],
['getIsAuthenticated'],
['getProfileData'],
['isCollectionFavorited'],
['collectionIsFavorited'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
query getWithAuthGuardData {
query getIsAuthenticated {
me {
user {
email
Expand Down
23 changes: 8 additions & 15 deletions src/lib/hooks/useIsAuthenticated.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import { UseQueryResult } from '@tanstack/react-query';
import { useGetIsAuthenticatedQuery } from './__generated__/useIsAuthenticated';

import {
GetWithAuthGuardDataQuery,
useGetWithAuthGuardDataQuery,
} from '~components/HOCs/__generated__/withAuthGuard';
import { getSessionToken } from '~lib/cookies';

export default function useIsAuthenticated(): UseQueryResult<
GetWithAuthGuardDataQuery,
unknown
> & {
export default function useIsAuthenticated(): {
isUserLoggedIn: boolean;
isFetching: boolean;
user?: { name: string; email: string };
} {
const token = getSessionToken();
const result = useGetWithAuthGuardDataQuery({}, { retry: false });
const { data, isFetching } = useGetIsAuthenticatedQuery({}, { retry: false });

return {
...result,
isUserLoggedIn: !!token && !!result.data?.me?.user.email,
isUserLoggedIn: !!data?.me?.user.email,
isFetching,
user: data?.me?.user,
};
}
4 changes: 2 additions & 2 deletions src/lib/test/loadAuthGuardData.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { when } from 'jest-when';
import Cookie from 'js-cookie';

import { GetWithAuthGuardDataDocument } from '~components/HOCs/__generated__/withAuthGuard';
import { fetchApi } from '~lib/api/fetchApi';
import { GetIsAuthenticatedDocument } from '~lib/hooks/__generated__/useIsAuthenticated';

export function loadAuthGuardData(email: any = 'the_email'): void {
Cookie.get = jest.fn().mockReturnValue({ avSession: 'abc123' });

when(fetchApi)
.calledWith(GetWithAuthGuardDataDocument, expect.anything())
.calledWith(GetIsAuthenticatedDocument, expect.anything())
.mockResolvedValue({
me: {
user: {
Expand Down
2 changes: 2 additions & 0 deletions src/pages/[language]/discover/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export async function getStaticProps({
getSectionPresenters: { language },
getSectionBibleBooks: { language },
getSectionTrendingMusic: { language },
getSectionEgwAudiobooks: { language },
getSectionAudiobooks: { language },
});

return {
Expand Down

0 comments on commit b16dbb1

Please sign in to comment.