diff --git a/frontends/api/src/hooks/channels/index.ts b/frontends/api/src/hooks/channels/index.ts index cbcbf2c580..549e77778b 100644 --- a/frontends/api/src/hooks/channels/index.ts +++ b/frontends/api/src/hooks/channels/index.ts @@ -55,5 +55,5 @@ export { useChannelsList, useChannelPartialUpdate, useChannelCounts, - channels, + channels as channelsKeyFactory, } diff --git a/frontends/api/src/hooks/learningResources/index.ts b/frontends/api/src/hooks/learningResources/index.ts index 559b8b5b15..6c2ea60ef3 100644 --- a/frontends/api/src/hooks/learningResources/index.ts +++ b/frontends/api/src/hooks/learningResources/index.ts @@ -531,5 +531,5 @@ export { useListItemMove, usePlatformsList, useSchoolsList, - learningResources, + learningResources as learningResourcesKeyFactory, } diff --git a/frontends/api/src/hooks/learningResources/keyFactory.ts b/frontends/api/src/hooks/learningResources/keyFactory.ts index fb926fe467..82a81cbf23 100644 --- a/frontends/api/src/hooks/learningResources/keyFactory.ts +++ b/frontends/api/src/hooks/learningResources/keyFactory.ts @@ -33,11 +33,6 @@ import type { import { createQueryKeys } from "@lukemorales/query-key-factory" -/* TODO we can add this back in once resource user list membership is implemented in the front end - * Currently we fetch on the server for public resources and then refetch on the client for the - * user lists parents. Randomizing therefore causes a content flicker as the client loaded - * sequence replaces the server rendered sequence. - const shuffle = ([...arr]) => { let m = arr.length while (m) { @@ -66,7 +61,6 @@ const randomizeResults = ([...results]) => { }) return randomizedResults } -*/ const learningResources = createQueryKeys("learningResources", { detail: (id: number) => ({ @@ -87,7 +81,7 @@ const learningResources = createQueryKeys("learningResources", { queryKey: [params], queryFn: () => { return featuredApi.featuredList(params).then((res) => { - // res.data.results = randomizeResults(res.data?.results) + res.data.results = randomizeResults(res.data?.results) return res.data }) }, diff --git a/frontends/api/src/hooks/newsEvents/index.ts b/frontends/api/src/hooks/newsEvents/index.ts index 9d20868f2d..b6f0d9b26f 100644 --- a/frontends/api/src/hooks/newsEvents/index.ts +++ b/frontends/api/src/hooks/newsEvents/index.ts @@ -19,5 +19,5 @@ export { useNewsEventsList, useNewsEventsDetail, NewsEventsListFeedTypeEnum, - newsEvents, + newsEvents as newsEventsKeyFactory, } diff --git a/frontends/api/src/hooks/testimonials/index.ts b/frontends/api/src/hooks/testimonials/index.ts index 9cb3ebc212..da98b49afc 100644 --- a/frontends/api/src/hooks/testimonials/index.ts +++ b/frontends/api/src/hooks/testimonials/index.ts @@ -23,4 +23,8 @@ const useTestimonialDetail = (id: number | undefined) => { }) } -export { useTestimonialDetail, useTestimonialList, testimonials } +export { + useTestimonialDetail, + useTestimonialList, + testimonials as testimonialsKeyFactory, +} diff --git a/frontends/api/src/ssr/prefetch.ts b/frontends/api/src/ssr/prefetch.ts index 67e377e28c..6078fcafec 100644 --- a/frontends/api/src/ssr/prefetch.ts +++ b/frontends/api/src/ssr/prefetch.ts @@ -1,19 +1,13 @@ import { QueryClient, dehydrate } from "@tanstack/react-query" import type { Query } from "@tanstack/react-query" -/* Utility to avoid repetition in server components - * Optionally pass the queryClient returned from a previous prefetch - * where queries are dependent on previous results - */ -export const prefetch = async ( - queries: (Query | unknown)[], - queryClient?: QueryClient, -) => { - queryClient = queryClient || new QueryClient() +// Utility to avoid repetition in server components +export const prefetch = async (queries: (Query | unknown)[]) => { + const queryClient = new QueryClient() await Promise.all( queries.map((query) => queryClient.prefetchQuery(query as Query)), ) - return { dehydratedState: dehydrate(queryClient), queryClient } + return dehydrate(queryClient) } diff --git a/frontends/api/src/ssr/usePrefetchWarnings.test.ts b/frontends/api/src/ssr/usePrefetchWarnings.test.ts index 1b937459e1..ab34473ba8 100644 --- a/frontends/api/src/ssr/usePrefetchWarnings.test.ts +++ b/frontends/api/src/ssr/usePrefetchWarnings.test.ts @@ -4,7 +4,7 @@ import { usePrefetchWarnings } from "./usePrefetchWarnings" import { setupReactQueryTest } from "../hooks/test-utils" import { urls, factories, setMockResponse } from "../test-utils" import { - learningResources, + learningResourcesKeyFactory, useLearningResourcesDetail, } from "../hooks/learningResources" @@ -45,7 +45,7 @@ describe("SSR prefetch warnings", () => { expect.objectContaining({ disabled: false, initialStatus: "loading", - key: learningResources.detail(1).queryKey, + key: learningResourcesKeyFactory.detail(1).queryKey, observerCount: 1, }), ], @@ -65,7 +65,7 @@ describe("SSR prefetch warnings", () => { wrapper, initialProps: { queryClient, - exemptions: [learningResources.detail(1).queryKey], + exemptions: [learningResourcesKeyFactory.detail(1).queryKey], }, }) @@ -83,7 +83,7 @@ describe("SSR prefetch warnings", () => { const { unmount } = renderHook( () => useQuery({ - ...learningResources.detail(1), + ...learningResourcesKeyFactory.detail(1), initialData: data, }), { wrapper }, @@ -105,9 +105,9 @@ describe("SSR prefetch warnings", () => { [ { disabled: false, - hash: JSON.stringify(learningResources.detail(1).queryKey), + hash: JSON.stringify(learningResourcesKeyFactory.detail(1).queryKey), initialStatus: "success", - key: learningResources.detail(1).queryKey, + key: learningResourcesKeyFactory.detail(1).queryKey, observerCount: 0, status: "success", }, diff --git a/frontends/api/src/ssr/usePrefetchWarnings.ts b/frontends/api/src/ssr/usePrefetchWarnings.ts index 5ed40215aa..000d80261c 100644 --- a/frontends/api/src/ssr/usePrefetchWarnings.ts +++ b/frontends/api/src/ssr/usePrefetchWarnings.ts @@ -45,13 +45,6 @@ export const usePrefetchWarnings = ({ */ useEffect( () => { - /* Invalidate all learning resource queries so they are re-fetched in the client - * for session specific data (user list memberships). - * This is interim, until the memberships endpoint is implemented in the frontend - * TODO remove once complete (see https://github.com/mitodl/hq/issues/5159) - */ - queryClient.invalidateQueries(["learningResources"]) - if (process.env.NODE_ENV === "production") { return } diff --git a/frontends/api/src/test-utils/factories/channels.ts b/frontends/api/src/test-utils/factories/channels.ts index 3e7d4d9820..7a8a095388 100644 --- a/frontends/api/src/test-utils/factories/channels.ts +++ b/frontends/api/src/test-utils/factories/channels.ts @@ -148,7 +148,6 @@ const _channelShared = (): Partial> => { key: faker.lorem.slug(), value: faker.lorem.slug(), }), - channel_url: `${faker.internet.url({ appendSlash: false })}${faker.system.directoryPath()}`, } } diff --git a/frontends/api/src/test-utils/urls.ts b/frontends/api/src/test-utils/urls.ts index 670f876753..89324b1a00 100644 --- a/frontends/api/src/test-utils/urls.ts +++ b/frontends/api/src/test-utils/urls.ts @@ -8,7 +8,6 @@ import type { NewsEventsApiNewsEventsListRequest, TestimonialsApi, - ChannelsApi, } from "../generated/v0" import type { LearningResourcesApi as LRApi, @@ -180,8 +179,6 @@ const channels = { details: (channelType: string, name: string) => `${API_BASE_URL}/api/v0/channels/type/${channelType}/${name}/`, patch: (id: number) => `${API_BASE_URL}/api/v0/channels/${id}/`, - list: (params?: Paramsv0) => - `${API_BASE_URL}/api/v0/channels/${query(params)}`, } const widgetLists = { diff --git a/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx b/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx index 4a0390f39e..9767a828c1 100644 --- a/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx +++ b/frontends/main/src/app-pages/UnitsListingPage/UnitCard.tsx @@ -1,6 +1,5 @@ import React from "react" -import type { OfferedByEnum } from "api" -import type { UnitChannel } from "api/v0" +import { LearningResourceOfferorDetail, OfferedByEnum } from "api" import { Card, Skeleton, @@ -9,6 +8,7 @@ import { theme, UnitLogo, } from "ol-components" +import { useChannelDetail } from "api/hooks/channels" import Link from "next/link" const CardStyled = styled(Card)({ @@ -102,23 +102,25 @@ const CountsText = styled(Typography)(({ theme }) => ({ })) interface UnitCardsProps { - channels: UnitChannel[] | undefined + units: LearningResourceOfferorDetail[] | undefined courseCounts: Record programCounts: Record } interface UnitCardProps { - channel: UnitChannel + unit: LearningResourceOfferorDetail courseCount: number programCount: number } const UnitCard: React.FC = (props) => { - const { channel, courseCount, programCount } = props - const unit = channel.unit_detail.unit + const { unit, courseCount, programCount } = props + const channelDetailQuery = useChannelDetail("unit", unit.code) + const channelDetail = channelDetailQuery.data + const unitUrl = channelDetail?.channel_url - if (!channel.channel_url) return null - const href = new URL(channel.channel_url).pathname + if (!unitUrl) return null + const href = unitUrl && new URL(unitUrl).pathname return ( @@ -132,7 +134,9 @@ const UnitCard: React.FC = (props) => { - {channel?.configuration?.heading} + + {channelDetail?.configuration?.heading} + @@ -170,18 +174,17 @@ export const UnitCardLoading = () => { } export const UnitCards: React.FC = (props) => { - const { channels, courseCounts, programCounts } = props + const { units, courseCounts, programCounts } = props return ( <> - {channels?.map((channel) => { - const unit = channel.unit_detail.unit + {units?.map((unit) => { const courseCount = courseCounts[unit.code] || 0 const programCount = programCounts[unit.code] || 0 return unit.value_prop ? ( diff --git a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.test.tsx b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.test.tsx index c5d1a05c35..c4e6ba84cd 100644 --- a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.test.tsx +++ b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.test.tsx @@ -2,71 +2,44 @@ import React from "react" import { renderWithProviders, screen, waitFor, within } from "@/test-utils" import UnitsListingPage from "./UnitsListingPage" import { factories, setMockResponse, urls } from "api/test-utils" -import { ChannelTypeEnum } from "api/v0" -import type { UnitChannel } from "api/v0" import { assertHeadings } from "ol-test-utilities" -describe("UnitListingPage", () => { +describe("DepartmentListingPage", () => { const setupApis = () => { - const make = factories.channels - const academicUnit1 = make.channel({ - channel_type: ChannelTypeEnum.Unit, - name: "academicUnit1", - title: "Academic Unit 1", - unit_detail: { - unit: { - value_prop: "Academic Unit 1 value prop", - professional: false, - }, - }, + const make = factories.learningResources + const academicUnit1 = make.offeror({ + code: "academicUnit1", + name: "Academic Unit 1", + value_prop: "Academic Unit 1 value prop", + professional: false, }) - const academicUnit2 = make.channel({ - channel_type: ChannelTypeEnum.Unit, - name: "academicUnit2", - title: "Academic Unit 2", - unit_detail: { - unit: { - value_prop: "Academic Unit 2 value prop", - professional: false, - }, - }, + const academicUnit2 = make.offeror({ + code: "academicUnit2", + name: "Academic Unit 2", + value_prop: "Academic Unit 2 value prop", + professional: false, }) - const academicUnit3 = make.channel({ - channel_type: ChannelTypeEnum.Unit, - name: "academicUnit3", - title: "Academic Unit 3", - unit_detail: { - unit: { - value_prop: "Academic Unit 3 value prop", - professional: false, - }, - }, + const academicUnit3 = make.offeror({ + code: "academicUnit3", + name: "Academic Unit 3", + value_prop: "Academic Unit 3 value prop", + professional: false, }) - const professionalUnit1 = make.channel({ - channel_type: ChannelTypeEnum.Unit, - name: "professionalUnit1", - title: "Professional Unit 1", - unit_detail: { - unit: { - value_prop: "Professional Unit 1 value prop", - professional: true, - }, - }, + const professionalUnit1 = make.offeror({ + code: "professionalUnit1", + name: "Professional Unit 1", + value_prop: "Professional Unit 1 value prop", + professional: true, }) - const professionalUnit2 = make.channel({ - channel_type: ChannelTypeEnum.Unit, - name: "professionalUnit2", - title: "Professional Unit 2", - unit_detail: { - unit: { - value_prop: "Professional Unit 2 value prop", - professional: true, - }, - }, + const professionalUnit2 = make.offeror({ + code: "professionalUnit2", + name: "Professional Unit 2", + value_prop: "Professional Unit 2 value prop", + professional: true, }) - const unitChannels = [ + const units = [ academicUnit1, academicUnit2, academicUnit3, @@ -90,23 +63,29 @@ describe("UnitListingPage", () => { setMockResponse.get( urls.channels.counts("unit"), - unitChannels.map((channel) => { + units.map((unit) => { return { - name: channel.name, + name: unit.code, counts: { - courses: courseCounts[channel.name], - programs: programCounts[channel.name], + courses: courseCounts[unit.code], + programs: programCounts[unit.code], }, } }), ) - setMockResponse.get(urls.channels.list({ channel_type: "unit" }), { - count: unitChannels.length, - results: unitChannels, + setMockResponse.get(urls.offerors.list(), { + count: units.length, + results: units, + }) + + units.forEach((unit) => { + setMockResponse.get(urls.channels.details("unit", unit.code), { + channel_url: `${window.location.origin}/units/${unit.code}`, + }) }) return { - unitChannels, + units, courseCounts, programCounts, } @@ -119,7 +98,7 @@ describe("UnitListingPage", () => { }) it("Shows unit properties within the proper section", async () => { - const { unitChannels, courseCounts, programCounts } = setupApis() + const { units, courseCounts, programCounts } = setupApis() renderWithProviders() @@ -137,15 +116,11 @@ describe("UnitListingPage", () => { return links }) - unitChannels.forEach((channel) => { - const { unit } = (channel as UnitChannel).unit_detail + units.forEach((unit) => { const section = unit.professional ? professionalSection : academicSection const card = within(section).getByTestId(`unit-card-${unit.code}`) const link = within(card).getByRole("link") - expect(link).toHaveAttribute( - "href", - new URL(channel.channel_url!).pathname, - ) + expect(link).toHaveAttribute("href", `/units/${unit.code}`) const courseCount = courseCounts[unit.code] const programCount = programCounts[unit.code] diff --git a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx index 57586dc685..905f2edf22 100644 --- a/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx +++ b/frontends/main/src/app-pages/UnitsListingPage/UnitsListingPage.tsx @@ -1,7 +1,8 @@ "use client" import React from "react" -import { useChannelCounts, useChannelsList } from "api/hooks/channels" +import { useChannelCounts } from "api/hooks/channels" +import { useOfferorsList } from "api/hooks/learningResources" import { Banner, Container, @@ -13,23 +14,23 @@ import { import { backgroundSrcSetCSS } from "ol-utilities" import backgroundSteps from "@/public/images/backgrounds/background_steps.jpg" import { RiBookOpenLine, RiSuitcaseLine } from "@remixicon/react" -import type { Channel, UnitChannel } from "api/v0" +import { LearningResourceOfferorDetail } from "api" import { HOME } from "@/common/urls" import { UnitCards, UnitCardLoading } from "./UnitCard" import { aggregateProgramCounts, aggregateCourseCounts } from "@/common/utils" const DESKTOP_WIDTH = "1056px" -const sortUnitChannels = ( - channels: Array | undefined, +const sortUnits = ( + units: Array | undefined, courseCounts: Record, programCounts: Record, ) => { - return channels?.sort((a, b) => { - const courseCountA = courseCounts[a.name] || 0 - const programCountA = programCounts[a.name] || 0 - const courseCountB = courseCounts[b.name] || 0 - const programCountB = programCounts[b.name] || 0 + return units?.sort((a, b) => { + const courseCountA = courseCounts[a.code] || 0 + const programCountA = programCounts[a.code] || 0 + const courseCountB = courseCounts[b.code] || 0 + const programCountB = programCounts[b.code] || 0 const totalA = courseCountA + programCountA const totalB = courseCountB + programCountB return totalB - totalA @@ -150,7 +151,7 @@ interface UnitSectionProps { icon: React.ReactNode title: string description: string - channels: UnitChannel[] | undefined + units: LearningResourceOfferorDetail[] | undefined courseCounts: Record programCounts: Record isLoading?: boolean @@ -162,11 +163,12 @@ const UnitSection: React.FC = (props) => { icon, title, description, - channels, + units, courseCounts, programCounts, isLoading, } = props + return (
@@ -185,7 +187,7 @@ const UnitSection: React.FC = (props) => { .map((_null, i) => ) ) : ( @@ -196,7 +198,8 @@ const UnitSection: React.FC = (props) => { } const UnitsListingPage: React.FC = () => { - const channelsQuery = useChannelsList({ channel_type: "unit" }) + const unitsQuery = useOfferorsList() + const units = unitsQuery.data?.results const channelCountQuery = useChannelCounts("unit") const courseCounts = channelCountQuery.data @@ -205,33 +208,25 @@ const UnitsListingPage: React.FC = () => { const programCounts = channelCountQuery.data ? aggregateProgramCounts("name", channelCountQuery.data) : {} - - const channels = channelsQuery.data?.results - const academicUnits = sortUnitChannels( - channels?.filter( - (channel) => - (channel as UnitChannel).unit_detail.unit.professional === false, - ), + const academicUnits = sortUnits( + units?.filter((unit) => unit.professional === false), courseCounts, programCounts, ) - const professionalUnits = sortUnitChannels( - channels?.filter( - (channel) => - (channel as UnitChannel).unit_detail.unit.professional === true, - ), + const professionalUnits = sortUnits( + units?.filter((unit) => unit.professional === true), courseCounts, programCounts, ) - const sections = [ + const unitData = [ { id: "academic", icon: , title: "Academic Units", description: "MIT's Academic courses, programs, and materials mirror MIT curriculum and residential programs, making these available to a global audience. Approved by faculty committees, Academic content furnishes a comprehensive foundation of knowledge, skills, and abilities for students pursuing their academic objectives. Renowned for their rigor and challenge, MIT's Academic offerings deliver an experience on par with the campus environment.", - channels: academicUnits as UnitChannel[], + units: academicUnits, }, { id: "professional", @@ -239,7 +234,7 @@ const UnitsListingPage: React.FC = () => { title: "Professional Units", description: "MIT's Professional courses and programs are tailored for working professionals seeking essential practical skills across various industries. Led by MIT faculty and maintaining challenging standards, Professional courses and programs prioritize real-world applications, emphasize practical skills and are directly relevant to today's workforce.", - channels: professionalUnits as UnitChannel[], + units: professionalUnits, }, ] @@ -272,17 +267,17 @@ const UnitsListingPage: React.FC = () => { - {sections.map((section) => ( + {unitData.map((unit) => ( ))} diff --git a/frontends/main/src/app/about/page.tsx b/frontends/main/src/app/about/page.tsx index 813a8a3311..f95679b170 100644 --- a/frontends/main/src/app/about/page.tsx +++ b/frontends/main/src/app/about/page.tsx @@ -1,5 +1,6 @@ import React from "react" import { Metadata } from "next" + import { AboutPage } from "@/app-pages/AboutPage/AboutPage" import { standardizeMetadata } from "@/common/metadata" diff --git a/frontends/main/src/app/c/[channelType]/[name]/page.tsx b/frontends/main/src/app/c/[channelType]/[name]/page.tsx index d696be97ca..5cc73220e1 100644 --- a/frontends/main/src/app/c/[channelType]/[name]/page.tsx +++ b/frontends/main/src/app/c/[channelType]/[name]/page.tsx @@ -4,7 +4,10 @@ import { channelsApi } from "api/clients" import { ChannelTypeEnum } from "api/v0" import { getMetadataAsync } from "@/common/metadata" import handleNotFound from "@/common/handleNotFound" -import type { PageParams } from "@/app/types" + +type SearchParams = { + [key: string]: string | string[] | undefined +} type RouteParams = { channelType: ChannelTypeEnum @@ -14,7 +17,10 @@ type RouteParams = { export async function generateMetadata({ searchParams, params, -}: PageParams) { +}: { + searchParams: Promise + params: Promise +}) { const { channelType, name } = await params const { data } = await handleNotFound( diff --git a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx index 47a9c88930..082710c443 100644 --- a/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx +++ b/frontends/main/src/app/dashboard/[tab]/[id]/page.tsx @@ -1,5 +1,6 @@ import React from "react" import DashboardPage from "@/app-pages/DashboardPage/DashboardPage" + import { Metadata } from "next" import { standardizeMetadata } from "@/common/metadata" import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" diff --git a/frontends/main/src/app/departments/page.tsx b/frontends/main/src/app/departments/page.tsx index bfc54b2811..a9b5133e9f 100644 --- a/frontends/main/src/app/departments/page.tsx +++ b/frontends/main/src/app/departments/page.tsx @@ -1,20 +1,20 @@ import React from "react" import { Metadata } from "next" -import { Hydrate } from "@tanstack/react-query" +import DepartmentListingPage from "@/app-pages/DepartmentListingPage/DepartmentListingPage" import { standardizeMetadata } from "@/common/metadata" -import { learningResources } from "api/hooks/learningResources" -import { channels } from "api/hooks/channels" +import { Hydrate } from "@tanstack/react-query" +import { learningResourcesKeyFactory } from "api/hooks/learningResources" +import { channelsKeyFactory } from "api/hooks/channels" import { prefetch } from "api/ssr/prefetch" -import DepartmentListingPage from "@/app-pages/DepartmentListingPage/DepartmentListingPage" export const metadata: Metadata = standardizeMetadata({ title: "Departments", }) const Page: React.FC = async () => { - const { dehydratedState } = await prefetch([ - channels.countsByType("department"), - learningResources.schools(), + const dehydratedState = await prefetch([ + channelsKeyFactory.countsByType("department"), + learningResourcesKeyFactory.schools(), ]) return ( diff --git a/frontends/main/src/app/learningpaths/[id]/page.tsx b/frontends/main/src/app/learningpaths/[id]/page.tsx index 3ffd0ba826..2d6cfc35b0 100644 --- a/frontends/main/src/app/learningpaths/[id]/page.tsx +++ b/frontends/main/src/app/learningpaths/[id]/page.tsx @@ -1,7 +1,7 @@ import React from "react" -import { Permissions } from "@/common/permissions" -import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" import LearningPathDetailsPage from "@/app-pages/LearningPathDetailsPage/LearningPathDetailsPage" +import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" +import { Permissions } from "@/common/permissions" const Page: React.FC = () => { return ( diff --git a/frontends/main/src/app/learningpaths/page.tsx b/frontends/main/src/app/learningpaths/page.tsx index f8dcb046b5..b48a847c31 100644 --- a/frontends/main/src/app/learningpaths/page.tsx +++ b/frontends/main/src/app/learningpaths/page.tsx @@ -1,9 +1,10 @@ import React from "react" +import LearningPathListingPage from "@/app-pages/LearningPathListingPage/LearningPathListingPage" + import { Metadata } from "next" import { standardizeMetadata } from "@/common/metadata" -import { Permissions } from "@/common/permissions" import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" -import LearningPathListingPage from "@/app-pages/LearningPathListingPage/LearningPathListingPage" +import { Permissions } from "@/common/permissions" export const metadata: Metadata = standardizeMetadata({ title: "Learning Paths", diff --git a/frontends/main/src/app/onboarding/page.tsx b/frontends/main/src/app/onboarding/page.tsx index 8d94e352c5..34a51559db 100644 --- a/frontends/main/src/app/onboarding/page.tsx +++ b/frontends/main/src/app/onboarding/page.tsx @@ -1,9 +1,9 @@ import React from "react" import { Metadata } from "next" +import OnboardingPage from "@/app-pages/OnboardingPage/OnboardingPage" import { standardizeMetadata } from "@/common/metadata" -import { Permissions } from "@/common/permissions" import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" -import OnboardingPage from "@/app-pages/OnboardingPage/OnboardingPage" +import { Permissions } from "@/common/permissions" export const metadata: Metadata = standardizeMetadata({ title: "Onboarding", diff --git a/frontends/main/src/app/page.tsx b/frontends/main/src/app/page.tsx index 1fadbb491e..ae920e6784 100644 --- a/frontends/main/src/app/page.tsx +++ b/frontends/main/src/app/page.tsx @@ -3,9 +3,11 @@ import type { Metadata } from "next" import HomePage from "@/app-pages/HomePage/HomePage" import { getMetadataAsync } from "@/common/metadata" import { Hydrate } from "@tanstack/react-query" -import { learningResources } from "api/hooks/learningResources" -import { testimonials } from "api/hooks/testimonials" -import { NewsEventsListFeedTypeEnum, newsEvents } from "api/hooks/newsEvents" +import { testimonialsKeyFactory } from "api/hooks/testimonials" +import { + NewsEventsListFeedTypeEnum, + newsEventsKeyFactory, +} from "api/hooks/newsEvents" import { prefetch } from "api/ssr/prefetch" type SearchParams = { @@ -24,50 +26,14 @@ export async function generateMetadata({ } const Page: React.FC = async () => { - const { dehydratedState } = await prefetch([ - // Featured Courses carousel "All" - learningResources.featured({ - limit: 12, - }), - // Featured Courses carousel "Free" - learningResources.featured({ - limit: 12, - free: true, - }), - // Featured Courses carousel "With Certificate" - learningResources.featured({ - limit: 12, - certification: true, - professional: false, - }), - // Featured Courses carousel "Professional & Executive Learning" - learningResources.featured({ - limit: 12, - professional: true, - }), - // Media carousel "All" - learningResources.list({ - resource_type: ["video", "podcast_episode"], - limit: 12, - sortby: "new", - }), - // Media carousel "Videos" - learningResources.list({ - resource_type: ["video"], - limit: 12, - sortby: "new", - }), - // Media carousel "Podcasts" - learningResources.list({ - resource_type: ["podcast_episode"], - limit: 12, - sortby: "new", - }), - // Browse by Topic - learningResources.topics({ is_toplevel: true }), - - testimonials.list({ position: 1 }), - newsEvents.list({ + const dehydratedState = await prefetch([ + testimonialsKeyFactory.list({ position: 1 }), + newsEventsKeyFactory.list({ + feed_type: [NewsEventsListFeedTypeEnum.News], + limit: 6, + sortby: "-news_date", + }), + newsEventsKeyFactory.list({ feed_type: [NewsEventsListFeedTypeEnum.Events], limit: 5, sortby: "event_date", diff --git a/frontends/main/src/app/privacy/page.tsx b/frontends/main/src/app/privacy/page.tsx index b24728f354..bea7709610 100644 --- a/frontends/main/src/app/privacy/page.tsx +++ b/frontends/main/src/app/privacy/page.tsx @@ -1,8 +1,8 @@ import React from "react" import { Metadata } from "next" -import { standardizeMetadata } from "@/common/metadata" -import PrivacyPage from "@/app-pages/PrivacyPage/PrivacyPage" +import PrivacyPage from "@/app-pages/PrivacyPage/PrivacyPage" +import { standardizeMetadata } from "@/common/metadata" export const metadata: Metadata = standardizeMetadata({ title: "Privacy Policy", }) diff --git a/frontends/main/src/app/search/page.tsx b/frontends/main/src/app/search/page.tsx index 239623d7fb..71c7723373 100644 --- a/frontends/main/src/app/search/page.tsx +++ b/frontends/main/src/app/search/page.tsx @@ -1,9 +1,16 @@ import React from "react" import { getMetadataAsync } from "@/common/metadata" import SearchPage from "@/app-pages/SearchPage/SearchPage" -import type { PageParams } from "@/app/types" -export async function generateMetadata({ searchParams }: PageParams) { +type SearchParams = { + [key: string]: string | string[] | undefined +} + +export async function generateMetadata({ + searchParams, +}: { + searchParams: Promise +}) { return await getMetadataAsync({ title: "Search", searchParams, diff --git a/frontends/main/src/app/terms/page.tsx b/frontends/main/src/app/terms/page.tsx index 57d82d21bc..67c45a73be 100644 --- a/frontends/main/src/app/terms/page.tsx +++ b/frontends/main/src/app/terms/page.tsx @@ -1,8 +1,8 @@ import React from "react" import { Metadata } from "next" -import { standardizeMetadata } from "@/common/metadata" -import TermsPage from "@/app-pages/TermsPage/TermsPage" +import TermsPage from "@/app-pages/TermsPage/TermsPage" +import { standardizeMetadata } from "@/common/metadata" export const metadata: Metadata = standardizeMetadata({ title: "Terms of Service", }) diff --git a/frontends/main/src/app/topics/page.tsx b/frontends/main/src/app/topics/page.tsx index 0d742ce794..abbbfc7a66 100644 --- a/frontends/main/src/app/topics/page.tsx +++ b/frontends/main/src/app/topics/page.tsx @@ -1,27 +1,15 @@ import React from "react" import { Metadata } from "next" -import { Hydrate } from "@tanstack/react-query" -import { prefetch } from "api/ssr/prefetch" -import { learningResources } from "api/hooks/learningResources" -import { channels } from "api/hooks/channels" -import TopicsListingPage from "@/app-pages/TopicsListingPage/TopicsListingPage" import { standardizeMetadata } from "@/common/metadata" export const metadata: Metadata = standardizeMetadata({ title: "Topics", }) -const Page: React.FC = async () => { - const { dehydratedState } = await prefetch([ - learningResources.topics({}), - channels.countsByType("topic"), - ]) +import TopicsListingPage from "@/app-pages/TopicsListingPage/TopicsListingPage" - return ( - - - - ) +const Page: React.FC = () => { + return } export default Page diff --git a/frontends/main/src/app/types.d.ts b/frontends/main/src/app/types.d.ts deleted file mode 100644 index 77335d0f0a..0000000000 --- a/frontends/main/src/app/types.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type SearchParams = { - [key: string]: string | string[] | undefined -} - -type PageParamsWithRouteParams = { - params: Promise - searchParams?: Promise -} - -type PageParamsWithoutRouteParams = { - searchParams?: Promise -} - -export type PageParams> = - RouteParams extends Record - ? PageParamsWithoutRoute - : PageParamsWithRoute diff --git a/frontends/main/src/app/units/page.tsx b/frontends/main/src/app/units/page.tsx index 52cf658a24..1f1a535933 100644 --- a/frontends/main/src/app/units/page.tsx +++ b/frontends/main/src/app/units/page.tsx @@ -1,26 +1,14 @@ import React from "react" import { Metadata } from "next" -import { Hydrate } from "@tanstack/react-query" -import { prefetch } from "api/ssr/prefetch" -import { standardizeMetadata } from "@/common/metadata" -import { channels } from "api/hooks/channels" -import UnitsListingPage from "@/app-pages/UnitsListingPage/UnitsListingPage" +import UnitsListingPage from "@/app-pages/UnitsListingPage/UnitsListingPage" +import { standardizeMetadata } from "@/common/metadata" export const metadata: Metadata = standardizeMetadata({ title: "Units", }) -const Page: React.FC = async () => { - const { dehydratedState } = await prefetch([ - channels.countsByType("unit"), - channels.list({ channel_type: "unit" }), - ]) - - return ( - - - - ) +const Page: React.FC = () => { + return } export default Page diff --git a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx index 18c8764dec..5eee0c4a99 100644 --- a/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx +++ b/frontends/main/src/page-components/LearningResourceDrawer/LearningResourceDrawer.tsx @@ -1,5 +1,3 @@ -"use client" - import React, { useCallback } from "react" import { RESOURCE_DRAWER_QUERY_PARAM } from "@/common/urls" import { ReadonlyURLSearchParams, useSearchParams } from "next/navigation" @@ -27,7 +25,7 @@ const useResourceDrawerHref = () => { return useCallback( (resourceId: number) => { - const hash = typeof window !== "undefined" && window?.location.hash + const hash = window?.location.hash return `?${getOpenDrawerSearchParams(searchParams, resourceId)}${hash || ""}` }, [searchParams], diff --git a/frontends/main/src/page-components/ResourceCarousel/ResourceCarousel.tsx b/frontends/main/src/page-components/ResourceCarousel/ResourceCarousel.tsx index 857d5caf7e..125b98ecaf 100644 --- a/frontends/main/src/page-components/ResourceCarousel/ResourceCarousel.tsx +++ b/frontends/main/src/page-components/ResourceCarousel/ResourceCarousel.tsx @@ -1,7 +1,7 @@ "use client" import React from "react" -import { learningResources } from "api/hooks/learningResources" +import { learningResourcesKeyFactory } from "api/hooks/learningResources" import { Carousel, TabButton, @@ -200,11 +200,11 @@ const ResourceCarousel: React.FC = ({ > => { switch (tab.data.type) { case "resources": - return learningResources.list(tab.data.params) + return learningResourcesKeyFactory.list(tab.data.params) case "lr_search": - return learningResources.search(tab.data.params) + return learningResourcesKeyFactory.search(tab.data.params) case "lr_featured": - return learningResources.featured(tab.data.params) + return learningResourcesKeyFactory.featured(tab.data.params) } }, ),