|
1 | | -import { useState, useEffect, useCallback } from 'react'; |
| 1 | +import { useState, useEffect, useCallback, useContext } from 'react'; |
2 | 2 | import { useNavigate, useLocation } from 'react-router-dom'; |
3 | | -import { Tabs, Tab } from '@openedx/paragon'; |
| 3 | +import { Tab, Tabs } from '@openedx/paragon'; |
| 4 | +import { SlotContext, BaseSlotOperation, useSlotOperations } from '@openedx/frontend-base'; |
4 | 5 |
|
5 | | -enum InstructorTabKeys { |
6 | | - COURSE_INFO = 'courseInfo', |
7 | | - ENROLLMENTS = 'enrollments', |
8 | | - COURSE_TEAM = 'courseTeam', |
9 | | - GRADING = 'grading', |
10 | | - DATE_EXTENSIONS = 'dateExtensions', |
11 | | - DATA_DOWNLOADS = 'dataDownloads', |
12 | | - OPEN_RESPONSES = 'openResponses', |
13 | | - CERTIFICATES = 'certificates', |
14 | | - COHORTS = 'cohorts', |
15 | | - SPECIAL_EXAMS = 'specialExams', |
16 | | -} |
17 | | - |
18 | | -interface TabConfig { |
19 | | - tab_id: InstructorTabKeys, |
| 6 | +export interface TabProps { |
| 7 | + tab_id: string, |
20 | 8 | url: string, |
21 | 9 | title: string, |
22 | 10 | } |
23 | 11 |
|
24 | | -// example of tabs response from an API, should be refactored to react query when backend is ready |
25 | | -const tabs: TabConfig[] = [ |
26 | | - { tab_id: InstructorTabKeys.COURSE_INFO, url: 'course_info', title: 'Course Info' }, |
27 | | - { tab_id: InstructorTabKeys.ENROLLMENTS, url: 'enrollments', title: 'Enrollments' }, |
28 | | - { tab_id: InstructorTabKeys.COURSE_TEAM, url: 'course_team', title: 'Course Team' }, |
29 | | - { tab_id: InstructorTabKeys.GRADING, url: 'grading', title: 'Grading' }, |
30 | | - { tab_id: InstructorTabKeys.DATE_EXTENSIONS, url: 'date_extensions', title: 'Date Extensions' }, |
31 | | - { tab_id: InstructorTabKeys.DATA_DOWNLOADS, url: 'data_downloads', title: 'Data Downloads' }, |
32 | | - { tab_id: InstructorTabKeys.OPEN_RESPONSES, url: 'open_responses', title: 'Open Responses' }, |
33 | | - { tab_id: InstructorTabKeys.CERTIFICATES, url: 'certificates', title: 'Certificates' }, |
34 | | - { tab_id: InstructorTabKeys.COHORTS, url: 'cohorts', title: 'Cohorts' }, |
35 | | - { tab_id: InstructorTabKeys.SPECIAL_EXAMS, url: 'special_exams', title: 'Special Exams' }, |
36 | | -]; |
| 12 | +interface SlotWithElementOperation extends BaseSlotOperation { |
| 13 | + element: React.ReactElement, |
| 14 | +} |
37 | 15 |
|
38 | 16 | const InstructorTabs = () => { |
39 | 17 | const navigate = useNavigate(); |
40 | 18 | const location = useLocation(); |
41 | | - const getActiveTabFromUrl = useCallback((): InstructorTabKeys => { |
42 | | - const currentPath = location.pathname.split('/').pop() ?? ''; |
43 | | - const activeTab = tabs.find(({ url }) => url === currentPath); |
44 | | - return (activeTab ? activeTab.tab_id : InstructorTabKeys.COURSE_INFO) as InstructorTabKeys; |
45 | | - }, [location.pathname]); |
| 19 | + const { id: slotId } = useContext(SlotContext); |
| 20 | + const widgets: SlotWithElementOperation[] = useSlotOperations(slotId) as SlotWithElementOperation[]; |
46 | 21 |
|
47 | | - const [tabKey, setTabKey] = useState<InstructorTabKeys>(getActiveTabFromUrl); |
| 22 | + const [tabKey, setTabKey] = useState<string>('courseInfo'); |
| 23 | + |
| 24 | + const getActiveTabFromUrl = useCallback(() => { |
| 25 | + const currentPath = location.pathname.split('/').pop() ?? ''; |
| 26 | + const activeTab = widgets.find((slot) => slot.element.props.url === currentPath)?.element; |
| 27 | + return activeTab ? activeTab.props.tab_id : ''; |
| 28 | + }, [widgets, location.pathname]); |
48 | 29 |
|
49 | 30 | useEffect(() => { |
50 | 31 | setTabKey(getActiveTabFromUrl()); |
51 | 32 | }, [getActiveTabFromUrl]); |
52 | 33 |
|
53 | 34 | const handleSelect = (eventKey: string | null) => { |
54 | 35 | if (eventKey) { |
55 | | - const tabKey = eventKey as InstructorTabKeys; |
56 | | - const selectedUrl = tabs.find(tab => tab.tab_id === tabKey)?.url; |
| 36 | + const tabKey = eventKey; |
| 37 | + const selectedElement = widgets.find((slot) => slot?.element?.props.tab_id === tabKey)?.element; |
| 38 | + const selectedUrl = selectedElement?.props.url; |
57 | 39 | setTabKey(tabKey); |
58 | 40 | if (selectedUrl) { |
59 | 41 | navigate(`/${selectedUrl}`); |
60 | 42 | } |
61 | 43 | } |
62 | 44 | }; |
63 | 45 |
|
| 46 | + if (widgets.length === 0) return null; |
| 47 | + |
64 | 48 | return ( |
65 | 49 | <Tabs id="instructor-tabs" activeKey={tabKey} onSelect={handleSelect}> |
66 | | - {tabs.map(({ tab_id, title }) => ( |
67 | | - <Tab key={tab_id} eventKey={tab_id} title={title} /> |
68 | | - ))} |
| 50 | + {widgets.map((widget: any, index: number) => { |
| 51 | + // We get props from TabSlot to create each Tab |
| 52 | + const element = widget.element; |
| 53 | + const { tab_id, title } = element.props; |
| 54 | + return <Tab key={tab_id ?? index} eventKey={tab_id} title={title} />; |
| 55 | + })} |
69 | 56 | </Tabs> |
70 | 57 | ); |
71 | 58 | }; |
|
0 commit comments