Skip to content

Commit d0abfbf

Browse files
fix: use camel case response
1 parent a79ab26 commit d0abfbf

File tree

5 files changed

+20
-17
lines changed

5 files changed

+20
-17
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"*.scss"
1919
],
2020
"scripts": {
21-
"dev": "PORT=8081 PUBLIC_PATH=/instructor openedx dev",
21+
"dev": "PORT=8080 PUBLIC_PATH=/instructor openedx dev",
2222
"i18n_extract": "openedx formatjs extract",
2323
"lint": "openedx lint .",
2424
"lint:fix": "openedx lint --fix .",

src/data/api.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { getCourseInfo } from './api';
2-
import { getAppConfig, getAuthenticatedHttpClient } from '@openedx/frontend-base';
2+
import { getAppConfig, getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';
33

44
jest.mock('@openedx/frontend-base');
55

66
const mockGetAppConfig = getAppConfig as jest.MockedFunction<typeof getAppConfig>;
7+
const mockCamelCaseObject = camelCaseObject as jest.MockedFunction<typeof camelCaseObject>;
78
const mockGetAuthenticatedHttpClient = getAuthenticatedHttpClient as jest.MockedFunction<typeof getAuthenticatedHttpClient>;
89

910
describe('getCourseInfo', () => {
1011
const mockHttpClient = {
1112
get: jest.fn(),
1213
};
1314
const mockCourseData = { course_name: 'Test Course', tabs: [{ tab_id: 'course_info', title: 'Course Information', url: 'https://test-lms.com/courses/test-course-123/info' }] };
15+
const mockCamelCasedCourseData = { courseName: 'Test Course', tabs: [{ tabId: 'course_info', title: 'Course Information', url: 'https://test-lms.com/courses/test-course-123/info' }] };
1416

1517
beforeEach(() => {
1618
jest.clearAllMocks();
1719
mockGetAppConfig.mockReturnValue({ LMS_BASE_URL: 'https://test-lms.com' });
1820
mockGetAuthenticatedHttpClient.mockReturnValue(mockHttpClient as any);
21+
mockCamelCaseObject.mockReturnValue(mockCamelCasedCourseData);
1922
mockHttpClient.get.mockResolvedValue({ data: mockCourseData });
2023
});
2124

@@ -25,7 +28,7 @@ describe('getCourseInfo', () => {
2528
expect(mockGetAppConfig).toHaveBeenCalledWith('org.openedx.frontend.app.instructor');
2629
expect(mockGetAuthenticatedHttpClient).toHaveBeenCalled();
2730
expect(mockHttpClient.get).toHaveBeenCalledWith('https://test-lms.com/api/instructor/v2/courses/test-course-123');
28-
expect(result).toBe(mockCourseData);
31+
expect(result).toBe(mockCamelCasedCourseData);
2932
});
3033

3134
it('throws error when API call fails', async () => {

src/data/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getAppConfig, getAuthenticatedHttpClient } from '@openedx/frontend-base';
1+
import { getAppConfig, getAuthenticatedHttpClient, camelCaseObject } from '@openedx/frontend-base';
22
import { appId } from '../constants';
33

44
const getApiBaseUrl = () => getAppConfig(appId).LMS_BASE_URL;
@@ -11,5 +11,5 @@ const getApiBaseUrl = () => getAppConfig(appId).LMS_BASE_URL;
1111
export const getCourseInfo = async (courseId) => {
1212
const { data } = await getAuthenticatedHttpClient()
1313
.get(`${getApiBaseUrl()}/api/instructor/v2/courses/${courseId}`);
14-
return data;
14+
return camelCaseObject(data);
1515
};

src/instructorTabs/InstructorTabs.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import { SlotContext, useWidgetsForId } from '@openedx/frontend-base';
55
import { useCourseInfo } from '../data/apiHook';
66

77
export interface TabProps {
8-
tab_id: string,
8+
tabId: string,
99
url: string,
1010
title: string,
1111
}
1212

1313
const extractWidgetProps = (widget: React.ReactNode): TabProps | null => {
1414
if (widget && typeof widget === 'object' && 'props' in widget) {
1515
const props = widget.props.children.props as TabProps;
16-
if (props?.tab_id && props?.url && props?.title) {
16+
if (props?.tabId && props?.url && props?.title) {
1717
return props;
1818
}
1919
}
@@ -36,10 +36,10 @@ const InstructorTabs = () => {
3636
const allTabs = [...apiTabs];
3737

3838
widgetPropsArray.forEach(slotTab => {
39-
if (!apiTabs.find(apiTab => apiTab.tab_id === slotTab.tab_id)) {
39+
if (!apiTabs.find(apiTab => apiTab.tabId === slotTab.tabId)) {
4040
allTabs.push(slotTab);
4141
} else {
42-
const indexToRemove = allTabs.findIndex(({ tab_id }) => tab_id === slotTab.tab_id);
42+
const indexToRemove = allTabs.findIndex(({ tabId }) => tabId === slotTab.tabId);
4343
if (indexToRemove !== -1) {
4444
allTabs.splice(indexToRemove, 1);
4545
}
@@ -50,7 +50,7 @@ const InstructorTabs = () => {
5050
const activeKey = tabId ?? 'course_info';
5151
const handleSelect = (eventKey: string | null) => {
5252
if (eventKey && courseId) {
53-
const selectedTab = allTabs.find(({ tab_id }) => tab_id === eventKey);
53+
const selectedTab = allTabs.find(({ tabId }) => tabId === eventKey);
5454
if (selectedTab) {
5555
navigate(`/${courseId}/${eventKey}`);
5656
}
@@ -65,8 +65,8 @@ const InstructorTabs = () => {
6565

6666
return (
6767
<Tabs id="instructor-tabs" activeKey={activeKey} onSelect={handleSelect}>
68-
{allTabs.map(({ tab_id, title }) => (
69-
<Tab key={tab_id} eventKey={tab_id} title={title} />
68+
{allTabs.map(({ tabId, title }) => (
69+
<Tab key={tabId} eventKey={tabId} title={title} />
7070
))}
7171
</Tabs>
7272
);

src/slots/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ import { SlotOperation, WidgetOperationTypes } from '@openedx/frontend-base';
2121
import { InstructorTab } from 'src/slots/instructorTabsSlot/InstructorTabsSlot';
2222

2323
// Tab configuration data
24-
const tabData = { tab_id: 'course_info', url: 'course_info', title: 'Course Info' };
24+
const tabData = { tabId: 'course_info', url: 'course_info', title: 'Course Info' };
2525

2626
// Create slot operations
2727
export const tabSlots: SlotOperation[] = [{
2828
slotId: `org.openedx.frontend.slot.instructor.tabs.v1`,
29-
id: `org.openedx.frontend.widget.instructor.tab.${tab_id}`,
29+
id: `org.openedx.frontend.widget.instructor.tab.${tabId}`,
3030
op: WidgetOperationTypes.APPEND,
31-
element: <InstructorTab tab_id={tabData.tab_id} title={tabData.title} url={tabData.url} />,
31+
element: <InstructorTab tabId={tabData.tabId} title={tabData.title} url={tabData.url} />,
3232
}];
3333
```
3434

@@ -60,8 +60,8 @@ const InstructorTabs = () => {
6060
return (
6161
<Tabs>
6262
{widgets.map((widget, index) => {
63-
const { tab_id, title } = widget.element.props;
64-
return <Tab key={tab_id} eventKey={tab_id} title={title} />;
63+
const { tabId, title } = widget.element.props;
64+
return <Tab key={tabId} eventKey={tabId} title={title} />;
6565
})}
6666
</Tabs>
6767
);

0 commit comments

Comments
 (0)