Skip to content

Commit

Permalink
Channel Search (#740)
Browse files Browse the repository at this point in the history
  • Loading branch information
abeglova authored Apr 9, 2024
1 parent b2d180a commit 8c451de
Show file tree
Hide file tree
Showing 13 changed files with 658 additions and 5 deletions.
4 changes: 4 additions & 0 deletions frontends/api/src/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ArticlesApi,
ProgramLettersApi,
LearningResourcesSearchApi,
PlatformsApi,
} from "./generated/v1/api"

import { ChannelsApi, WidgetListsApi } from "./generated/v0/api"
Expand Down Expand Up @@ -36,6 +37,8 @@ const userListsApi = new UserlistsApi(undefined, BASE_PATH, axiosInstance)

const offerorsApi = new OfferorsApi(undefined, BASE_PATH, axiosInstance)

const platformsApi = new PlatformsApi(undefined, BASE_PATH, axiosInstance)

const topicsApi = new TopicsApi(undefined, BASE_PATH, axiosInstance)

const articlesApi = new ArticlesApi(undefined, BASE_PATH, axiosInstance)
Expand All @@ -60,4 +63,5 @@ export {
learningResourcesSearchApi,
channelsApi,
widgetListsApi,
platformsApi,
}
12 changes: 12 additions & 0 deletions frontends/api/src/hooks/learningResources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
UserList,
UserListRelationshipRequest,
MicroUserListRelationship,
PlatformsApiPlatformsListRequest,
} from "../../generated/v1"
import learningResources, {
invalidateResourceQueries,
Expand Down Expand Up @@ -413,6 +414,16 @@ const useListItemMove = () => {
})
}

const usePlatformsList = (
params: PlatformsApiPlatformsListRequest = {},
opts: Pick<UseQueryOptions, "enabled"> = {},
) => {
return useQuery({
...learningResources.platforms(params),
...opts,
})
}

export {
useLearningResourcesList,
useLearningResourcesUpcoming,
Expand All @@ -439,4 +450,5 @@ export {
useInfiniteUserListItems,
useOfferorsList,
useListItemMove,
usePlatformsList,
}
8 changes: 8 additions & 0 deletions frontends/api/src/hooks/learningResources/keyFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
topicsApi,
userListsApi,
offerorsApi,
platformsApi,
} from "../../clients"
import axiosInstance from "../../axios"
import type {
Expand All @@ -23,6 +24,7 @@ import type {
PaginatedUserListRelationshipList,
UserList,
OfferorsApiOfferorsListRequest,
PlatformsApiPlatformsListRequest,
} from "../../generated/v1"
import { createQueryKeys } from "@lukemorales/query-key-factory"

Expand Down Expand Up @@ -129,6 +131,12 @@ const learningResources = createQueryKeys("learningResources", {
queryFn: () => offerorsApi.offerorsList(params).then((res) => res.data),
}
},
platforms: (params: PlatformsApiPlatformsListRequest) => {
return {
queryKey: [params],
queryFn: () => platformsApi.platformsList(params).then((res) => res.data),
}
},
})

const learningPathHasResource =
Expand Down
2 changes: 2 additions & 0 deletions frontends/api/src/test-utils/factories/learningResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const learningResourceOfferor: Factory<LearningResourceOfferor> = (
}
}
const learningResourceOfferors = makePaginatedFactory(learningResourceOfferor)
const learningResourcePlatforms = makePaginatedFactory(learningResourcePlatform)

const learningResourceRun: Factory<LearningResourceRun> = (overrides = {}) => {
const start = overrides.start_date
Expand Down Expand Up @@ -391,6 +392,7 @@ export {
learningResourceDepartment as department,
learningResourceTopics as topics,
learningResourceOfferors as offerors,
learningResourcePlatforms as platforms,
learningPath,
learningPaths,
microLearningPathRelationship,
Expand Down
7 changes: 7 additions & 0 deletions frontends/api/src/test-utils/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
ArticlesApi,
UserlistsApi,
OfferorsApi,
PlatformsApi,
} from "../generated/v1"
import type { BaseAPI } from "../generated/v1/base"

Expand Down Expand Up @@ -44,6 +45,11 @@ const offerors = {
`/api/v1/offerors/${query(params)}`,
}

const platforms = {
list: (params?: Params<PlatformsApi, "platformsList">) =>
`/api/v1/platforms/${query(params)}`,
}

const topics = {
list: (params?: Params<TopicsApi, "topicsList">) =>
`/api/v1/topics/${query(params)}`,
Expand Down Expand Up @@ -118,4 +124,5 @@ export {
fields,
widgetLists,
offerors,
platforms,
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import type { FieldChannel } from "api/v0"

const setupApis = (fieldOverrides: Partial<FieldChannel>) => {
const field = factory.field({ is_moderator: true, ...fieldOverrides })
field.search_filter = undefined

setMockResponse.get(
urls.fields.details(field.channel_type, field.name),
field,
Expand Down
63 changes: 59 additions & 4 deletions frontends/mit-open/src/pages/FieldPage/FieldPage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { assertInstanceOf } from "ol-utilities"
import { urls } from "api/test-utils"
import { urls, factories } from "api/test-utils"
import type { FieldChannel } from "api/v0"
import { fields as factory } from "api/test-utils/factories"
import type { LearningResourceSearchResponse } from "api"

import WidgetList from "./WidgetsList"
import {
renderTestApp,
Expand All @@ -13,6 +14,7 @@ import {
} from "../../test-utils"
import { makeWidgetListResponse } from "ol-widgets/src/factories"
import { makeFieldViewPath } from "@/common/urls"
import FieldSearch from "./FieldSearch"

jest.mock("./WidgetsList", () => {
const actual = jest.requireActual("./WidgetsList")
Expand All @@ -23,8 +25,20 @@ jest.mock("./WidgetsList", () => {
})
const mockWidgetList = jest.mocked(WidgetList)

const setupApis = (fieldPatch?: Partial<FieldChannel>) => {
const field = factory.field(fieldPatch)
jest.mock("./FieldSearch", () => {
const actual = jest.requireActual("./FieldSearch")
return {
__esModule: true,
default: jest.fn(actual.default),
}
})
const mockedFieldSearch = jest.mocked(FieldSearch)

const setupApis = (
fieldPatch?: Partial<FieldChannel>,
search?: Partial<LearningResourceSearchResponse>,
) => {
const field = factories.fields.field(fieldPatch)

setMockResponse.get(
urls.fields.details(field.channel_type, field.name),
Expand All @@ -37,6 +51,23 @@ const setupApis = (fieldPatch?: Partial<FieldChannel>) => {
widgetsList,
)

setMockResponse.get(
urls.platforms.list(),
factories.learningResources.platforms({ count: 5 }),
)

setMockResponse.get(expect.stringContaining(urls.search.resources()), {
count: 0,
next: null,
previous: null,
results: [],
metadata: {
aggregations: {},
suggestions: [],
},
...search,
})

return {
field,
widgets: widgetsList.widgets,
Expand Down Expand Up @@ -64,6 +95,30 @@ describe("FieldPage", () => {
])
})

it("Displays the field search if search_filter is not undefined", async () => {
const { field } = setupApis({ search_filter: "platform=ocw" })
renderTestApp({ url: `/c/${field.channel_type}/${field.name}` })
await screen.findByText(field.title)
const expectedProps = expect.objectContaining({
constantSearchParams: { platform: ["ocw"] },
})
const expectedContext = expect.anything()

expect(mockedFieldSearch).toHaveBeenLastCalledWith(
expectedProps,
expectedContext,
)
})

it("Does not display the field search if search_filter is undefined", async () => {
const { field } = setupApis()
field.search_filter = undefined
renderTestApp({ url: `/c/${field.channel_type}/${field.name}` })
await screen.findByText(field.title)

expect(mockedFieldSearch).toHaveBeenCalledTimes(0)
})

it.each([
{
getUrl: (field: FieldChannel) => `/c/${field.channel_type}/${field.name}`,
Expand Down
14 changes: 14 additions & 0 deletions frontends/mit-open/src/pages/FieldPage/FieldPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useChannelDetail } from "api/hooks/fields"
import WidgetsList from "./WidgetsList"
import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout"
import { makeFieldViewPath } from "@/common/urls"
import FieldSearch from "./FieldSearch"
import type { Facets, FacetKey } from "@mitodl/course-search-utils"

type RouteParams = {
channelType: string
Expand Down Expand Up @@ -42,6 +44,15 @@ const FieldPage: React.FC = () => {
navigate(makeFieldViewPath(String(channelType), String(name)))
}, [navigate, channelType, name])

const searchParams: Facets = {}

if (fieldQuery.data?.search_filter) {
const urlParams = new URLSearchParams(fieldQuery.data.search_filter)
for (const [key, value] of urlParams.entries()) {
searchParams[key as FacetKey] = value.split(",")
}
}

return (
<FieldPageSkeleton name={name} channelType={channelType}>
<TabContext value={tabValue}>
Expand All @@ -68,6 +79,9 @@ const FieldPage: React.FC = () => {
<GridColumn variant="main-2-wide-main">
<TabPanel value="home">
<p>{fieldQuery.data?.public_description}</p>
{fieldQuery.data?.search_filter && (
<FieldSearch constantSearchParams={searchParams} />
)}
</TabPanel>
<TabPanel value="about"></TabPanel>
</GridColumn>
Expand Down
Loading

0 comments on commit 8c451de

Please sign in to comment.