diff --git a/package-lock.json b/package-lock.json index 4af0e4c777..a406a8944f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-helmet": "6.1.0", + "react-query": "^3.39.3", "react-redux": "7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", diff --git a/package.json b/package.json index b773c342dd..164dd4761e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-helmet": "6.1.0", + "react-query": "^3.39.3", "react-redux": "7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", diff --git a/src/assets/place-holders/favicon.svg b/src/assets/place-holders/favicon.svg new file mode 100644 index 0000000000..1d513a5e5b --- /dev/null +++ b/src/assets/place-holders/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/constants/react-query-constants.js b/src/constants/react-query-constants.js new file mode 100644 index 0000000000..39179b7ed6 --- /dev/null +++ b/src/constants/react-query-constants.js @@ -0,0 +1,15 @@ +const REACT_QUERY_CONSTANTS = { + queries: { + // Set staleTime to 5 minutes + staleTime: 5 * 60 * 1000, + // Set cacheTime to 60 minutes + cacheTime: 60 * 60 * 1000, + // Set the retry count for queries here + retry: 1, // Set the retry count for queries here + }, + mutations: { + retry: 1, // Set the retry count for mutations here + }, +}; + +export default REACT_QUERY_CONSTANTS; diff --git a/src/courseware/course/Course.jsx b/src/courseware/course/Course.jsx index 607f8f3ccc..88718bd6b1 100644 --- a/src/courseware/course/Course.jsx +++ b/src/courseware/course/Course.jsx @@ -18,6 +18,8 @@ import SidebarTriggers from './sidebar/SidebarTriggers'; import { useModel } from '../../generic/model-store'; import { getSessionStorage, setSessionStorage } from '../../data/sessionStorage'; +import useGetConfig from '../../hooks/useGetConfig'; + const Course = ({ courseId, sequenceId, @@ -44,6 +46,10 @@ const Course = ({ // Below the tabs, above the breadcrumbs alerts (appearing in the order listed here) const dispatch = useDispatch(); + const { + platformName, + } = useGetConfig(); + const [firstSectionCelebrationOpen, setFirstSectionCelebrationOpen] = useState(false); // If streakLengthToCelebrate is populated, that modal takes precedence. Wait til the next load to display // the weekly goal celebration modal. @@ -80,7 +86,7 @@ const Course = ({ return ( - {`${pageTitleBreadCrumbs.join(' | ')} | ${getConfig().SITE_NAME}`} + {`${pageTitleBreadCrumbs.join(' | ')} | ${platformName || getConfig().siteName}`}
{ const { administrator } = getAuthenticatedUser(); + const { + platformName, + } = useGetConfig(); + const dashboardLink = ; const idVerificationSupportLink = ; const profileLink = ; @@ -278,7 +283,7 @@ const CourseCelebration = ({ intl }) => { return ( <> - {`${intl.formatMessage(messages.congratulationsHeader)} | ${title} | ${getConfig().SITE_NAME}`} + {`${intl.formatMessage(messages.congratulationsHeader)} | ${title} | ${platformName || getConfig().siteName}`}
diff --git a/src/courseware/course/course-exit/CourseInProgress.jsx b/src/courseware/course/course-exit/CourseInProgress.jsx index a6b29096bd..84ebeae27b 100644 --- a/src/courseware/course/course-exit/CourseInProgress.jsx +++ b/src/courseware/course/course-exit/CourseInProgress.jsx @@ -13,6 +13,7 @@ import CatalogSuggestion from './CatalogSuggestion'; import DashboardFootnote from './DashboardFootnote'; import messages from './messages'; import { logClick, logVisit } from './utils'; +import useGetConfig from '../../../hooks/useGetConfig'; const CourseInProgress = ({ intl }) => { const { courseId } = useSelector(state => state.courseware); @@ -23,6 +24,10 @@ const CourseInProgress = ({ intl }) => { } = useModel('courseHomeMeta', courseId); const { administrator } = getAuthenticatedUser(); + const { + platformName, + } = useGetConfig(); + // Get dates tab link for 'view course schedule' button const datesTab = tabs.find(tab => tab.slug === 'dates'); const datesTabLink = datesTab && datesTab.url; @@ -32,7 +37,7 @@ const CourseInProgress = ({ intl }) => { return ( <> - {`${intl.formatMessage(messages.endOfCourseTitle)} | ${title} | ${getConfig().SITE_NAME}`} + {`${intl.formatMessage(messages.endOfCourseTitle)} | ${title} | ${platformName || getConfig().siteName}`}
diff --git a/src/courseware/course/course-exit/CourseNonPassing.jsx b/src/courseware/course/course-exit/CourseNonPassing.jsx index e63b9a704e..a277966af1 100644 --- a/src/courseware/course/course-exit/CourseNonPassing.jsx +++ b/src/courseware/course/course-exit/CourseNonPassing.jsx @@ -13,6 +13,7 @@ import CatalogSuggestion from './CatalogSuggestion'; import DashboardFootnote from './DashboardFootnote'; import messages from './messages'; import { logClick, logVisit } from './utils'; +import useGetConfig from '../../../hooks/useGetConfig'; const CourseNonPassing = ({ intl }) => { const { courseId } = useSelector(state => state.courseware); @@ -23,6 +24,10 @@ const CourseNonPassing = ({ intl }) => { } = useModel('courseHomeMeta', courseId); const { administrator } = getAuthenticatedUser(); + const { + platformName, + } = useGetConfig(); + // Get progress tab link for 'view grades' button const progressTab = tabs.find(tab => tab.slug === 'progress'); const progressLink = progressTab && progressTab.url; @@ -32,7 +37,7 @@ const CourseNonPassing = ({ intl }) => { return ( <> - {`${intl.formatMessage(messages.endOfCourseTitle)} | ${title} | ${getConfig().SITE_NAME}`} + {`${intl.formatMessage(messages.endOfCourseTitle)} | ${title} | ${platformName || getConfig().siteName}`}
diff --git a/src/hooks/useGetConfig.js b/src/hooks/useGetConfig.js new file mode 100644 index 0000000000..b897ef0355 --- /dev/null +++ b/src/hooks/useGetConfig.js @@ -0,0 +1,39 @@ +import { getConfig } from '@edx/frontend-platform'; +import { useQuery } from 'react-query'; +import faviconPlaceholder from '../assets/place-holders/favicon.svg'; + +const useGetConfig = () => { + const fetchConfig = async ({ baseURL, instanceConfigAPIUrl }) => { + const response = await fetch(`${baseURL}${instanceConfigAPIUrl}`); + const result = await response.json(); + return result; + }; + + const { data, isLoading, isError } = useQuery( + 'headerLogo', + () => fetchConfig({ + baseURL: getConfig().LMS_BASE_URL, + instanceConfigAPIUrl: getConfig().AC_INSTANCE_CONFIG_API_URL, + }), + { + enabled: + !!getConfig().LMS_BASE_URL && !!getConfig().AC_INSTANCE_CONFIG_API_URL, + }, + ); + const faviconVersion = Date.now(); // Update this version number when the favicon updates + const favicon = data?.favicon + ? `${data.favicon}?v=${faviconVersion}` + : faviconPlaceholder; + return { + headerLogo: data?.logo, + hasBilling: data?.has_billing, + favicon, + platformName: data?.platform_name, + gtm: data?.gtm, + isTPAOnly: data?.use_tpa_only, + TPAQueryparam: data?.tpa_queryparam, + loading: isLoading, + isError, + }; +}; +export default useGetConfig; diff --git a/src/index.jsx b/src/index.jsx index 2a82c13e60..12dc75e4af 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -12,6 +12,8 @@ import { Switch } from 'react-router-dom'; import { messages as footerMessages } from '@edx/frontend-component-footer'; import { messages as headerMessages } from '@edx/frontend-component-header'; +import { QueryClient, QueryClientProvider } from 'react-query'; +import REACT_QUERY_CONSTANTS from './constants/react-query-constants'; import { fetchDiscussionTab, fetchLiveTab } from './course-home/data/thunks'; import DiscussionTab from './course-home/discussion-tab/DiscussionTab'; @@ -38,67 +40,75 @@ import CourseAccessErrorPage from './generic/CourseAccessErrorPage'; import DecodePageRoute from './decode-page-route'; subscribe(APP_READY, () => { + const queryClient = new QueryClient({ + defaultOptions: { + ...REACT_QUERY_CONSTANTS, + }, + }); + ReactDOM.render( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ( - fetchProgressTab(courseId, match.params.targetUserId)} - slice="courseHome" - > - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + fetchProgressTab(courseId, match.params.targetUserId)} + slice="courseHome" + > + + + )} + /> + + + - )} - /> - - - - - - - - - - + + + + + + + , document.getElementById('root'), ); diff --git a/src/tab-page/LoadedTabPage.jsx b/src/tab-page/LoadedTabPage.jsx index 2ba3067d9e..f12126a27d 100644 --- a/src/tab-page/LoadedTabPage.jsx +++ b/src/tab-page/LoadedTabPage.jsx @@ -14,6 +14,7 @@ import useEnrollmentAlert from '../alerts/enrollment-alert'; import useLogistrationAlert from '../alerts/logistration-alert'; import ProductTours from '../product-tours/ProductTours'; +import useGetConfig from '../hooks/useGetConfig'; const LoadedTabPage = ({ activeTabSlug, @@ -36,6 +37,10 @@ const LoadedTabPage = ({ const logistrationAlert = useLogistrationAlert(courseId); const enrollmentAlert = useEnrollmentAlert(courseId); + const { + platformName, + } = useGetConfig(); + const activeTab = tabs.filter(tab => tab.slug === activeTabSlug)[0]; const streakLengthToCelebrate = celebrations && celebrations.streakLengthToCelebrate; @@ -51,7 +56,7 @@ const LoadedTabPage = ({ org={org} /> - {`${activeTab ? `${activeTab.title} | ` : ''}${title} | ${getConfig().SITE_NAME}`} + {`${activeTab ? `${activeTab.title} | ` : ''}${title} | ${platformName || getConfig().siteName}`} {originalUserIsStaff && (