Skip to content

Commit 10de6a1

Browse files
authored
Merge pull request #25 from CS428-CT/fix-offerings
Fix offerings
2 parents 5c397d3 + d0ac3c6 commit 10de6a1

File tree

14 files changed

+344
-159
lines changed

14 files changed

+344
-159
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import axios from 'axios'
2+
import React from 'react'
3+
import MockAdapter from 'axios-mock-adapter'
4+
import { render } from '@testing-library/react-native'
5+
import { setUserData } from '../../src/api/auth'
6+
import { ENDPOINTS as UNI_ENDPOINTS } from '../../src/api/universities'
7+
import { ENDPOINTS as OFFER_ENDPOINTS } from '../../src/api/offerings'
8+
import { format } from '../../src/utils/string'
9+
10+
import { HTTP_STATUS_CODES } from '../../src/api'
11+
import { UNIVERSITY_RESPONSE } from '../mock_responses/mock-university-response'
12+
import Home from '../../src/containers/HomeContainer/Home'
13+
import { OFFERINGS_RESPONSE_1 } from '../mock_responses/mock-offerings-response'
14+
15+
// const assertNoButtonsRendered = async () => {
16+
// const { queryAllByA11yRole } = render(<UniversityListContainer />)
17+
// const universityList = await waitFor(() => queryAllByA11yRole('button'))
18+
// expect(universityList.length).toBe(0)
19+
// }
20+
21+
const mock = new MockAdapter(axios)
22+
describe('Check universities rendering', () => {
23+
const USER_DATA = {
24+
authToken: 'A',
25+
universityId: '1001',
26+
userId: 'test user',
27+
emaildId: '[email protected]',
28+
}
29+
30+
const offeringId = 'ac5b1727-629c-443b-8c1a-cc1bd541af6a'
31+
32+
afterEach(() => {
33+
mock.reset()
34+
})
35+
36+
test('Check that components render', async () => {
37+
const mockNavigator = { push: jest.fn() }
38+
39+
mock.onGet(`${UNI_ENDPOINTS.UNIVERSITIES}`).reply(HTTP_STATUS_CODES.OK, UNIVERSITY_RESPONSE)
40+
mock
41+
.onGet(`${OFFER_ENDPOINTS.OFFERINGBYSTUDENT}`)
42+
.reply(HTTP_STATUS_CODES.OK, OFFERINGS_RESPONSE_1)
43+
mock
44+
.onGet(`${format(OFFER_ENDPOINTS.OFFERING, offeringId)}`)
45+
.reply(HTTP_STATUS_CODES.OK, OFFERINGS_RESPONSE_1)
46+
47+
setUserData(USER_DATA)
48+
49+
const { getByTestId } = render(<Home navigation={mockNavigator} />)
50+
51+
const picker = await getByTestId('picker')
52+
expect(picker).not.toBe(null)
53+
54+
const courseList = await getByTestId('courseList')
55+
expect(courseList).not.toBe(null)
56+
})
57+
})

__tests__/frontend/PlaylistContainer-test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,23 @@ describe('Check videos rendering', () => {
7676

7777
describe('Check video navigation', () => {
7878
const playlistId = '51519746-aa6c-485c-9894-549959c457b5'
79-
const mockNaivgator = { push: jest.fn() }
79+
const mockNavigator = { push: jest.fn() }
8080

8181
test('when clicking on first item', async () => {
8282
mock
8383
.onGet(`${format(ENDPOINTS.VIDEOS_BY_PLAYLIST, playlistId)}`)
8484
.reply(HTTP_STATUS_CODES.OK, VIDEOS_BY_PLAYLIST_RESPONSE)
8585

8686
const { queryAllByA11yRole } = render(
87-
<PlaylistContainer playlistId={playlistId} navigation={mockNaivgator} />
87+
<PlaylistContainer playlistId={playlistId} navigation={mockNavigator} />
8888
)
8989
const videos = await waitFor(() => queryAllByA11yRole('button'))
9090
expect(videos.length).not.toBe(0)
9191

9292
fireEvent.press(videos[0])
9393

94-
expect(mockNaivgator.push).toHaveBeenCalled()
95-
expect(mockNaivgator.push).toHaveBeenCalledWith(STACK_SCREENS.VIDEO, {
94+
expect(mockNavigator.push).toHaveBeenCalled()
95+
expect(mockNavigator.push).toHaveBeenCalledWith(STACK_SCREENS.VIDEO, {
9696
videos: VIDEOS_BY_PLAYLIST_RESPONSE.medias,
9797
index: 0,
9898
})

__tests__/utils/string-test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ describe('Check formatting', () => {
3131
})
3232

3333
describe('Check truncation', () => {
34+
test('check null string', () => {
35+
expect(truncateString(null, 10)).toBe('')
36+
})
37+
3438
test('already short enough', () => {
3539
expect(truncateString('hello', 10)).toBe('hello')
3640
})

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"dependencies": {
33
"@expo/vector-icons": "^12.0.4",
44
"@react-native-community/masked-view": "0.1.10",
5+
"@react-native-community/picker": "^1.8.1",
56
"@react-native-picker/picker": "1.9.2",
67
"@react-navigation/bottom-tabs": "^5.11.8",
78
"@react-navigation/native": "^5.9.3",
@@ -35,7 +36,7 @@
3536
"react-native-gesture-handler": "^1.10.3",
3637
"react-native-navigation": "^7.11.2",
3738
"react-native-paper": "^4.7.2",
38-
"react-native-picker-select": "^8.0.4",
39+
"react-native-picker-select": "8.0.0",
3940
"react-native-reanimated": "~1.13.0",
4041
"react-native-safe-area-context": "3.1.9",
4142
"react-native-screens": "~2.15.2",
@@ -74,7 +75,7 @@
7475
"build-ios": "expo build:ios",
7576
"ios": "expo start --ios",
7677
"web": "expo start --web",
77-
"eject": "expo eject --non-interactive --eject-method bare",
78+
"eject": "expo eject --non-interactive --ject-method bare",
7879
"lint": "eslint ."
7980
},
8081
"private": true

src/api/auth.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,26 @@ export const getUserMetadata = async () => {
4545
}
4646
}
4747

48+
/**
49+
* Set the authorization token for the current authenticated user
50+
* @param authToken Pass in the auth token so user can watch CT videos
51+
*/
4852
export const setAuthToken = (token) => {
4953
if (!currentAuthenticatedUser) currentAuthenticatedUser = {}
5054
currentAuthenticatedUser.authToken = token
5155
}
5256

57+
/**
58+
* Initialize user's data using the metadata that is passed in during authorization
59+
* @param userData Pass in userData to obtain each user's information
60+
*/
61+
export const setUserData = (userData) => {
62+
if (!currentAuthenticatedUser) currentAuthenticatedUser = {}
63+
currentAuthenticatedUser.userId = userData?.userId
64+
currentAuthenticatedUser.universityId = userData?.universityId
65+
currentAuthenticatedUser.emailId = userData?.emailId
66+
}
67+
5368
/**
5469
* Returns the signed in user's data or null if no one is signed in.
5570
* See @currentAuthenticatedUser for the attributes returned in the object

src/api/offerings.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getCurrentAuthenticatedUser, isUserAuthenticated } from './auth'
66

77
export const ENDPOINTS = {
88
OFFERING: `${API_BASE_URL}Offerings/{0}`,
9+
OFFERINGBYSTUDENT: `${API_BASE_URL}Offerings/ByStudent`,
910
}
1011

1112
/**
@@ -29,6 +30,51 @@ export const getOfferingData = async (offeringId) => {
2930
return null
3031
}
3132

33+
/// //////////////// STUDENT OFFERING FUNCTIONS ////////////////////
34+
35+
/**
36+
* Gets the data for an offering from the CT API if the student is authenticated
37+
* @returns The offering data
38+
*/
39+
export const getOfferingsByStudent = async () => {
40+
if (!isUserAuthenticated()) return null
41+
42+
const url = ENDPOINTS.OFFERINGBYSTUDENT
43+
44+
try {
45+
const resp = await axios.get(url)
46+
if (resp?.status !== HTTP_STATUS_CODES.OK) {
47+
return null
48+
}
49+
return resp.data
50+
} catch (error) {
51+
console.error(error)
52+
}
53+
54+
return null
55+
}
56+
57+
/**
58+
* Returns an array of all the offering data for the current user.
59+
* If no user is signed in, null is returned.
60+
* @returns Array of offerings data
61+
*/
62+
export const getOfferingsData = async () => {
63+
const offerings = []
64+
65+
const studentOfferings = await getOfferingsByStudent()
66+
if (studentOfferings == null) return null
67+
68+
for (const entry of studentOfferings) {
69+
const offeringData = await getOfferingData(entry.offering.id)
70+
if (offeringData != null) offerings.push(offeringData)
71+
}
72+
73+
return offerings
74+
}
75+
76+
/// //////////////// STARRED OFFERING CALLS //////////////////////
77+
3278
/**
3379
* Returns an array of all the starred offering data for the current user.
3480
* If no user is signed in, null is returned.

src/api/video.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import axios from 'axios'
2+
import { HTTP_STATUS_CODES } from '.'
3+
import { API_BASE_URL } from '../constants'
4+
import { format } from '../utils/string'
5+
6+
export const ENDPOINTS = {
7+
TRANSCRIPT: `${API_BASE_URL}Captions/ByTranscription/{0}`,
8+
MEDIA: `${API_BASE_URL}Media/{0}`,
9+
}
10+
11+
export const getVideoTranscription = async (transcriptionId) => {
12+
const url = format(ENDPOINTS.TRANSCRIPT, transcriptionId)
13+
14+
try {
15+
const resp = await axios.get(url)
16+
if (resp?.status !== HTTP_STATUS_CODES.OK) return null
17+
return resp.data
18+
} catch (error) {
19+
console.error(error)
20+
}
21+
22+
return null
23+
}
24+
25+
export const getMedia = async (mediaId) => {
26+
const url = format(ENDPOINTS.MEDIA, mediaId.mediaId)
27+
28+
try {
29+
const resp = await axios.get(url)
30+
if (resp?.status !== HTTP_STATUS_CODES.OK) return null
31+
return resp.data
32+
} catch (error) {
33+
console.error(error)
34+
}
35+
36+
return null
37+
}

src/containers/CTNavigationContainer/CTNavigationContainer.js

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,21 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
55
import { createStackNavigator } from '@react-navigation/stack'
66
import { MaterialCommunityIcons } from '@expo/vector-icons'
77
import { STACK_SCREENS } from './index'
8-
import Home from '../HomeContainers/Home'
8+
import Home from '../HomeContainer/Home'
99
import CoursePlaylistsContainer from '../CoursePlaylistsContainer/CoursePlaylistsContainer'
1010
import VideoContainer from '../VideoContainer/VideoContainer'
11-
import UniversityListContainer from '../UniversityListContainer/UniversityListContainer'
1211
import PlaylistContainer from '../PlaylistContainer/PlaylistContainer'
13-
import DepartmentListContainer from '../DepartmentListContainer/DepartmentListContainer'
14-
import CourseListContainer from '../CourseListContainer/CourseListContainer'
1512

1613
const Tab = createBottomTabNavigator()
1714
const Stack = createStackNavigator()
1815

1916
/**
2017
* The navigator of the home tab. Contains a stack navigator.
2118
*/
22-
const HomeNaivgator = () => {
19+
const HomeNavigator = () => {
2320
return (
2421
<Stack.Navigator initialRouteName={STACK_SCREENS.HOME}>
25-
<Stack.Screen name={STACK_SCREENS.HOME} component={Home} />
22+
<Stack.Screen name={STACK_SCREENS.HOME} component={HomeView} />
2623
<Stack.Screen name={STACK_SCREENS.COURSE_PLAYLISTS} component={CoursePlaylistsView} />
2724
<Stack.Screen name={STACK_SCREENS.PLAYLIST} component={PlaylistView} />
2825
<Stack.Screen name={STACK_SCREENS.VIDEO} component={VideoView} />
@@ -31,35 +28,11 @@ const HomeNaivgator = () => {
3128
}
3229

3330
/**
34-
* Wraps the UniversityListContainer so that it can
31+
* Wraps the Home container so that it can
3532
* receive the proper props
3633
*/
37-
const UniversityListView = ({ navigation }) => {
38-
return <UniversityListContainer navigation={navigation} />
39-
}
40-
41-
/**
42-
* Wraps the DepartmentListContainer so that it can
43-
* receive the proper props
44-
*/
45-
const DepartmentListView = ({ navigation, route }) => {
46-
return (
47-
<DepartmentListContainer universityId={route.params.universityId} navigation={navigation} />
48-
)
49-
}
50-
51-
/**
52-
* Wraps the CourseListContainer so that it can
53-
* receive the proper props
54-
*/
55-
const CourseListView = ({ navigation, route }) => {
56-
return (
57-
<CourseListContainer
58-
departmentId={route.params.departmentId}
59-
acronym={route.params.acronym}
60-
navigation={navigation}
61-
/>
62-
)
34+
const HomeView = ({ navigation }) => {
35+
return <Home navigation={navigation} />
6336
}
6437

6538
/**
@@ -91,11 +64,8 @@ const VideoView = ({ route }) => {
9164
*/
9265
const CourseNavigator = () => {
9366
return (
94-
<Stack.Navigator initialRouteName={STACK_SCREENS.UNIVERSITY_LIST}>
95-
<Stack.Screen name={STACK_SCREENS.UNIVERSITY_LIST} component={UniversityListView} />
96-
<Stack.Screen name={STACK_SCREENS.DEPT_LIST} component={DepartmentListView} />
97-
<Stack.Screen name={STACK_SCREENS.COURSE_LIST} component={CourseListView} />
98-
<Stack.Screen name={STACK_SCREENS.HOME} component={Home} />
67+
<Stack.Navigator initialRouteName={STACK_SCREENS.HOME}>
68+
<Stack.Screen name={STACK_SCREENS.HOME} component={HomeView} />
9969
<Stack.Screen name={STACK_SCREENS.COURSE_PLAYLISTS} component={CoursePlaylistsView} />
10070
<Stack.Screen name={STACK_SCREENS.PLAYLIST} component={PlaylistView} />
10171
<Stack.Screen name={STACK_SCREENS.VIDEO} component={VideoView} />
@@ -124,7 +94,7 @@ const CTNavigationContainer = () => {
12494
/>
12595
<Tab.Screen
12696
name="Home"
127-
component={HomeNaivgator}
97+
component={HomeNavigator}
12898
options={{
12999
tabBarLabel: 'Home',
130100
tabBarIcon: ({ color, size }) => (

0 commit comments

Comments
 (0)