diff --git a/app/graphql/types/client_configuration_type.rb b/app/graphql/types/client_configuration_type.rb index 7c1dc8ac12..249230d34b 100644 --- a/app/graphql/types/client_configuration_type.rb +++ b/app/graphql/types/client_configuration_type.rb @@ -1,14 +1,14 @@ class Types::ClientConfigurationType < Types::BaseObject description "Client-side configuration values needed for frontend initialization" - field :rails_default_active_storage_service_name, String, null: false, - description: "The default Active Storage service name configured in Rails" + field :rails_default_active_storage_service_name, + String, + null: false, + description: "The default Active Storage service name configured in Rails" # rubocop:disable GraphQL/ExtractType - field :rails_direct_uploads_url, String, null: false, - description: "The URL endpoint for Rails Direct Uploads" + field :rails_direct_uploads_url, String, null: false, description: "The URL endpoint for Rails Direct Uploads" # rubocop:enable GraphQL/ExtractType - field :recaptcha_site_key, String, null: false, - description: "The reCAPTCHA site key for client-side verification" + field :recaptcha_site_key, String, null: false, description: "The reCAPTCHA site key for client-side verification" def rails_default_active_storage_service_name Rails.application.config.active_storage.service.to_s diff --git a/app/javascript/AppWrapper.tsx b/app/javascript/AppWrapper.tsx index 01955c3156..8558a3b91e 100644 --- a/app/javascript/AppWrapper.tsx +++ b/app/javascript/AppWrapper.tsx @@ -1,5 +1,4 @@ import { Suspense, useCallback, useRef, useEffect, ReactNode, useState, useMemo, useContext } from 'react'; -import * as React from 'react'; import { Outlet } from 'react-router'; import { i18n } from 'i18next'; import { I18nextProvider } from 'react-i18next'; @@ -75,37 +74,35 @@ export function ProviderStack(props: AppWrapperProps) { ); return ( - - - - {/* TODO bring this back when we re-add prompting getUserConfirmation={getUserConfirmation}> */} - - <> - {!unauthenticatedError && ( - }> - - {(i18nInstance) => ( - - - DateTime.now().minus(Duration.fromMillis(timeAgo.milliseconds)).toRelative() - } - > - - - - - - )} - - - )} - - - - - - + + + {/* TODO bring this back when we re-add prompting getUserConfirmation={getUserConfirmation}> */} + + <> + {!unauthenticatedError && ( + }> + + {(i18nInstance) => ( + + + DateTime.now().minus(Duration.fromMillis(timeAgo.milliseconds)).toRelative() + } + > + + + + + + )} + + + )} + + + + + ); } diff --git a/app/javascript/packs/application.tsx b/app/javascript/packs/application.tsx index 533e95fe24..3aa5af2d80 100644 --- a/app/javascript/packs/application.tsx +++ b/app/javascript/packs/application.tsx @@ -7,7 +7,6 @@ import AuthenticityTokensManager, { getAuthenticityTokensURL, } from 'AuthenticityTokensContext'; import { createBrowserRouter, RouterContextProvider, RouterProvider } from 'react-router'; -import { ProviderStack } from 'AppWrapper'; import { buildBrowserApolloClient } from 'useIntercodeApolloClient'; import { apolloClientContext, @@ -26,13 +25,13 @@ const refreshPromise = manager.refresh(); export type DataModeApplicationEntryProps = { recaptchaSiteKey: string; railsDefaultActiveStorageServiceName: string; - railsDirectUploadsURL: string; + railsDirectUploadsUrl: string; }; function DataModeApplicationEntry({ recaptchaSiteKey, railsDefaultActiveStorageServiceName, - railsDirectUploadsURL, + railsDirectUploadsUrl, }: DataModeApplicationEntryProps) { use(refreshPromise); @@ -45,10 +44,10 @@ function DataModeApplicationEntry({ __typename: 'ClientConfiguration', recaptcha_site_key: recaptchaSiteKey, rails_default_active_storage_service_name: railsDefaultActiveStorageServiceName, - rails_direct_uploads_url: railsDirectUploadsURL, + rails_direct_uploads_url: railsDirectUploadsUrl, }, }), - [recaptchaSiteKey, railsDefaultActiveStorageServiceName, railsDirectUploadsURL], + [recaptchaSiteKey, railsDefaultActiveStorageServiceName, railsDirectUploadsUrl], ); const router = useMemo( @@ -56,7 +55,7 @@ function DataModeApplicationEntry({ createBrowserRouter( [ { - Component: ProviderStack, + lazy: () => import('root'), children: appRootRoutes, }, ], diff --git a/app/javascript/root.tsx b/app/javascript/root.tsx index 47fc9e6dc8..80d39c0596 100644 --- a/app/javascript/root.tsx +++ b/app/javascript/root.tsx @@ -1,14 +1,24 @@ import { ApolloProvider } from '@apollo/client/react'; +import { authenticityTokensManagerContext, clientConfigurationDataContext } from 'AppContexts'; import { ProviderStack } from 'AppWrapper'; -import AuthenticityTokensManager, { - AuthenticityTokensContext, - getAuthenticityTokensURL, -} from 'AuthenticityTokensContext'; +import AuthenticityTokensManager, { AuthenticityTokensContext } from 'AuthenticityTokensContext'; import { ClientConfiguration } from 'graphqlTypes.generated'; -import { StrictMode, useContext, useMemo } from 'react'; -import { useLoaderData } from 'react-router'; +import { StrictMode, useMemo } from 'react'; +import { LoaderFunction, useLoaderData } from 'react-router'; +import { ClientConfigurationQueryData } from 'serverQueries.generated'; import { buildBrowserApolloClient } from 'useIntercodeApolloClient'; +type RootLoaderData = { + clientConfigurationData: ClientConfigurationQueryData; + authenticityTokensManager: AuthenticityTokensManager; +}; + +export const loader: LoaderFunction = ({ context }) => { + const clientConfigurationData = context.get(clientConfigurationDataContext); + const authenticityTokensManager = context.get(authenticityTokensManagerContext); + return { clientConfigurationData, authenticityTokensManager } satisfies RootLoaderData; +}; + function RootProviderStack({ clientConfiguration }: { clientConfiguration: ClientConfiguration }) { return ( buildBrowserApolloClient(manager), [manager]); - - return ( - - - +export default function Root() { + const loaderData = useLoaderData() as RootLoaderData; + const client = useMemo( + () => buildBrowserApolloClient(loaderData.authenticityTokensManager), + [loaderData.authenticityTokensManager], ); -} - -export function ClientEntry() { - const manager = useMemo(() => new AuthenticityTokensManager(fetch, undefined, getAuthenticityTokensURL()), []); return ( - - + + + + ); } + +export const Component = Root;