Skip to content

Commit aeeecd5

Browse files
committed
update api client and use the new attach function, also update interstitial page to use it and the nextjs redirect function instead of setting window.location directly
1 parent 2f3284d commit aeeecd5

File tree

7 files changed

+67
-59
lines changed

7 files changed

+67
-59
lines changed

frontends/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"ol-test-utilities": "0.0.0"
3131
},
3232
"dependencies": {
33-
"@mitodl/mitxonline-api-axios": "2025.8.6",
33+
"@mitodl/mitxonline-api-axios": "2025.8.12",
3434
"@tanstack/react-query": "^5.66.0",
3535
"axios": "^1.6.3"
3636
}

frontends/api/src/mitxonline/clients.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
ProgramCertificatesApi,
99
UsersApi,
1010
} from "@mitodl/mitxonline-api-axios/v2"
11-
import axios, { AxiosInstance } from "axios"
11+
import axios from "axios"
1212

1313
const axiosInstance = axios.create({
1414
baseURL: process.env.NEXT_PUBLIC_MITX_ONLINE_BASE_URL,
@@ -22,25 +22,6 @@ const axiosInstance = axios.create({
2222
const BASE_PATH =
2323
process.env.NEXT_PUBLIC_MITX_ONLINE_BASE_URL?.replace(/\/+$/, "") ?? ""
2424

25-
class B2BAttachApi {
26-
private axiosInstance: AxiosInstance
27-
private basePath: string
28-
29-
constructor(
30-
_config: unknown = undefined,
31-
basePath: string,
32-
axiosInstance: AxiosInstance,
33-
) {
34-
this.basePath = basePath
35-
this.axiosInstance = axiosInstance
36-
}
37-
38-
async attach(code: string, data?: unknown, options?: unknown) {
39-
const url = `${this.basePath}/api/v0/b2b/attach/${encodeURIComponent(code)}/`
40-
return this.axiosInstance.post(url, data, options || undefined)
41-
}
42-
}
43-
4425
const usersApi = new UsersApi(undefined, BASE_PATH, axiosInstance)
4526
const b2bApi = new B2bApi(undefined, BASE_PATH, axiosInstance)
4627
const programsApi = new ProgramsApi(undefined, BASE_PATH, axiosInstance)
@@ -57,7 +38,6 @@ const programCertificatesApi = new ProgramCertificatesApi(
5738
)
5839

5940
const coursesApi = new CoursesApi(undefined, BASE_PATH, axiosInstance)
60-
const b2bAttachApi = new B2BAttachApi(undefined, BASE_PATH, axiosInstance)
6141

6242
const courseCertificatesApi = new CourseCertificatesApi(
6343
undefined,
@@ -75,7 +55,6 @@ export {
7555
usersApi,
7656
b2bApi,
7757
courseRunEnrollmentsApi,
78-
b2bAttachApi,
7958
programsApi,
8059
programCollectionsApi,
8160
coursesApi,

frontends/api/src/mitxonline/hooks/organizations/queries.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import { B2bApiB2bOrganizationsRetrieveRequest } from "@mitodl/mitxonline-api-axios/v0"
2-
import { OrganizationPage } from "@mitodl/mitxonline-api-axios/v1"
3-
import { queryOptions, useMutation } from "@tanstack/react-query"
4-
import { b2bApi, b2bAttachApi } from "../../clients"
1+
import {
2+
queryOptions,
3+
useMutation,
4+
useQueryClient,
5+
} from "@tanstack/react-query"
6+
import { b2bApi } from "../../clients"
7+
import {
8+
OrganizationPage,
9+
B2bApiB2bAttachCreateRequest,
10+
B2bApiB2bOrganizationsRetrieveRequest,
11+
} from "@mitodl/mitxonline-api-axios/v2"
512

613
const organizationKeys = {
714
root: ["mitxonline", "organizations"],
@@ -22,10 +29,14 @@ const organizationQueries = {
2229
}),
2330
}
2431

25-
const useB2BAttachMutation = (code: string) => {
32+
const useB2BAttachMutation = (opts: B2bApiB2bAttachCreateRequest) => {
33+
const queryClient = useQueryClient()
2634
return useMutation({
27-
mutationFn: (data?: unknown) => {
28-
return b2bAttachApi.attach(code, data).then((res) => res.data)
35+
mutationFn: () => b2bApi.b2bAttachCreate(opts),
36+
onSuccess: () => {
37+
queryClient.invalidateQueries({
38+
queryKey: organizationKeys.organizationsRetrieve(),
39+
})
2940
},
3041
})
3142
}

frontends/main/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"@emotion/cache": "^11.13.1",
1515
"@emotion/styled": "^11.11.0",
1616
"@mitodl/course-search-utils": "3.3.2",
17-
"@mitodl/mitxonline-api-axios": "2025.8.6",
17+
"@mitodl/mitxonline-api-axios": "2025.8.12",
1818
"@mitodl/smoot-design": "^6.10.0",
1919
"@next/bundle-analyzer": "^14.2.15",
2020
"@remixicon/react": "^4.2.0",
Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,24 @@
11
import React from "react"
2-
import { renderWithProviders, setMockResponse } from "@/test-utils"
2+
import { renderWithProviders, setMockResponse, waitFor } from "@/test-utils"
33
import { urls } from "api/test-utils"
44
import { urls as b2bUrls } from "api/mitxonline-test-utils"
55
import * as commonUrls from "@/common/urls"
66
import { Permission } from "api/hooks/user"
77
import B2BAttachPage from "./B2BAttachPage"
8+
import { redirect } from "next/navigation"
89

9-
const oldWindowLocation = window.location
10+
// Mock Next.js redirect function
11+
jest.mock("next/navigation", () => ({
12+
redirect: jest.fn(),
13+
}))
1014

11-
beforeAll(() => {
12-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
13-
delete (window as any).location
15+
const mockRedirect = jest.mocked(redirect)
1416

15-
window.location = Object.defineProperties({} as Location, {
16-
...Object.getOwnPropertyDescriptors(oldWindowLocation),
17-
assign: {
18-
configurable: true,
19-
value: jest.fn(),
20-
},
17+
describe("B2BAttachPage", () => {
18+
beforeEach(() => {
19+
jest.clearAllMocks()
2120
})
22-
})
2321

24-
afterAll(() => {
25-
window.location = oldWindowLocation
26-
})
27-
28-
describe("B2BAttachPage", () => {
2922
test("Renders when logged in", async () => {
3023
setMockResponse.get(urls.userMe.get(), {
3124
[Permission.Authenticated]: true,
@@ -37,4 +30,21 @@ describe("B2BAttachPage", () => {
3730
url: commonUrls.B2B_ATTACH_VIEW,
3831
})
3932
})
33+
34+
test("Redirects to dashboard on successful attachment", async () => {
35+
setMockResponse.get(urls.userMe.get(), {
36+
[Permission.Authenticated]: true,
37+
})
38+
39+
setMockResponse.post(b2bUrls.b2bAttach.b2bAttachView("test-code"), [])
40+
41+
renderWithProviders(<B2BAttachPage code="test-code" />, {
42+
url: commonUrls.B2B_ATTACH_VIEW,
43+
})
44+
45+
// Wait for the mutation to complete and verify redirect was called
46+
await waitFor(() => {
47+
expect(mockRedirect).toHaveBeenCalledWith(commonUrls.DASHBOARD_HOME)
48+
})
49+
})
4050
})

frontends/main/src/app-pages/B2BAttachPage/B2BAttachPage.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client"
22
import React from "react"
3+
import { redirect } from "next/navigation"
34
import { styled, Breadcrumbs, Container, Typography } from "ol-components"
45
import * as urls from "@/common/urls"
56
import { useB2BAttachMutation } from "api/mitxonline-hooks/organizations"
@@ -14,12 +15,18 @@ const InterstitialMessage = styled(Typography)(({ theme }) => ({
1415
}))
1516

1617
const B2BAttachPage: React.FC<B2BAttachPageProps> = ({ code }) => {
17-
const { mutate: attach, isSuccess } = useB2BAttachMutation(code)
18+
const {
19+
mutate: attach,
20+
isSuccess,
21+
isPending,
22+
} = useB2BAttachMutation({
23+
enrollment_code: code,
24+
})
1825

19-
React.useEffect(() => attach(code), [attach, code])
26+
React.useEffect(() => attach(), [attach])
2027

2128
if (isSuccess) {
22-
window.history.replaceState(null, "", urls.DASHBOARD_HOME)
29+
redirect(urls.DASHBOARD_HOME)
2330
}
2431

2532
return (
@@ -29,8 +36,9 @@ const B2BAttachPage: React.FC<B2BAttachPageProps> = ({ code }) => {
2936
ancestors={[{ href: urls.HOME, label: "Home" }]}
3037
current="Use Enrollment Code"
3138
/>
32-
33-
<InterstitialMessage>Validating code "{code}"...</InterstitialMessage>
39+
{isPending && (
40+
<InterstitialMessage>Validating code "{code}"...</InterstitialMessage>
41+
)}
3442
</Container>
3543
)
3644
}

yarn.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)