-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8335dec
commit 4806dc6
Showing
15 changed files
with
304 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/courseware/course/sequence/Unit/translation-selection/TranslationModal.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { | ||
StandardModal, | ||
ActionRow, | ||
Button, | ||
Icon, | ||
ListBox, | ||
ListBoxOption, | ||
} from '@edx/paragon'; | ||
import { Check } from '@edx/paragon/icons'; | ||
|
||
import useTranslationSelection, { languages } from './useTranslationSelection'; | ||
|
||
import './TranslationModal.scss'; | ||
|
||
const TranslationModal = ({ courseId, isOpen, close }) => { | ||
const { selectedIndex, setSelectedIndex, onSubmit } = useTranslationSelection({ courseId, close }); | ||
|
||
return ( | ||
<StandardModal | ||
title="Translate this course" | ||
isOpen={isOpen} | ||
onClose={close} | ||
footerNode={( | ||
<ActionRow> | ||
<ActionRow.Spacer /> | ||
<Button variant="tertiary" onClick={close}> | ||
Cancel | ||
</Button> | ||
<Button onClick={onSubmit}>Submit</Button> | ||
</ActionRow> | ||
)} | ||
> | ||
<ListBox className="listbox-container"> | ||
{languages.map(([key, value], index) => ( | ||
<ListBoxOption | ||
className="d-flex justify-content-between" | ||
key={key} | ||
selectedOptionIndex={selectedIndex} | ||
onSelect={() => setSelectedIndex(index)} | ||
> | ||
{value} | ||
{selectedIndex === index && <Icon src={Check} />} | ||
</ListBoxOption> | ||
))} | ||
</ListBox> | ||
</StandardModal> | ||
); | ||
}; | ||
|
||
TranslationModal.propTypes = { | ||
isOpen: PropTypes.bool.isRequired, | ||
close: PropTypes.func.isRequired, | ||
courseId: PropTypes.string.isRequired, | ||
}; | ||
|
||
export default TranslationModal; |
7 changes: 7 additions & 0 deletions
7
src/courseware/course/sequence/Unit/translation-selection/TranslationModal.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.listbox-container { | ||
max-height: 400px; | ||
|
||
:last-child { | ||
margin-bottom: 5px; | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
src/courseware/course/sequence/Unit/translation-selection/__snapshots__/index.test.jsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`<TranslationSelection /> renders 1`] = `undefined`; |
36 changes: 36 additions & 0 deletions
36
src/courseware/course/sequence/Unit/translation-selection/index.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { IconButton, Icon, ProductTour } from '@edx/paragon'; | ||
import { Language } from '@edx/paragon/icons'; | ||
import TranslationModal from './TranslationModal'; | ||
import useTranslationTour from './useTranslationTour'; | ||
|
||
const TranslationSelection = ({ courseId }) => { | ||
const { | ||
translationTour, isOpen, open, close, | ||
} = useTranslationTour(); | ||
|
||
return ( | ||
<> | ||
<ProductTour tours={[translationTour]} /> | ||
<IconButton | ||
src={Language} | ||
iconAs={Icon} | ||
alt="change-language" | ||
onClick={open} | ||
variant="primary" | ||
className="mr-2 mb-2 float-right" | ||
id="translation-selection-button" | ||
/> | ||
<TranslationModal isOpen={isOpen} close={close} courseId={courseId} /> | ||
</> | ||
); | ||
}; | ||
|
||
TranslationSelection.propTypes = { | ||
courseId: PropTypes.string.isRequired, | ||
}; | ||
|
||
TranslationSelection.defaultProps = {}; | ||
|
||
export default TranslationSelection; |
27 changes: 27 additions & 0 deletions
27
src/courseware/course/sequence/Unit/translation-selection/index.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { shallow } from '@edx/react-unit-test-utils'; | ||
|
||
import TranslationSelection from './index'; | ||
|
||
jest.mock('@edx/paragon', () => ({ | ||
IconButton: 'IconButton', | ||
Icon: 'Icon', | ||
ProductTour: 'ProductTour', | ||
})); | ||
jest.mock('@edx/paragon/icons', () => ({ | ||
Language: 'Language', | ||
})); | ||
jest.mock('./useTranslationTour', () => ({ | ||
translationTour: { | ||
abitrarily: 'defined', | ||
}, | ||
isOpen: false, | ||
open: jest.fn().mockName('open'), | ||
close: jest.fn().mockName('close'), | ||
})); | ||
|
||
describe('<TranslationSelection />', () => { | ||
it('renders', () => { | ||
const wrapper = shallow(<TranslationSelection courseId="course-v1:edX+DemoX+Demo_Course" />); | ||
expect(wrapper.snapshot).toMatchSnapshot(); | ||
}); | ||
}); |
28 changes: 28 additions & 0 deletions
28
src/courseware/course/sequence/Unit/translation-selection/messages.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { defineMessages } from '@edx/frontend-platform/i18n'; | ||
|
||
// title: 'New translation feature!', | ||
// body: 'Now you can easily translate course content.', | ||
const messages = defineMessages({ | ||
translationModalTitle: { | ||
id: 'translationSelection.translationModalTitle', | ||
defaultMessage: 'This is a standard modal dialog', | ||
description: 'Title for the translation modal.', | ||
}, | ||
translationModalBody: { | ||
id: 'translationSelection.translationModalBody', | ||
defaultMessage: 'Now you can easily translate course content.', | ||
description: 'Body for the translation modal.', | ||
}, | ||
tryItButtonText: { | ||
id: 'translationSelection.tryItButtonText', | ||
defaultMessage: 'Try it', | ||
description: 'Button text for the translation modal.', | ||
}, | ||
dismissButtonText: { | ||
id: 'translationSelection.dismissButtonText', | ||
defaultMessage: 'Dismiss', | ||
description: 'Button text for the translation modal.', | ||
}, | ||
}); | ||
|
||
export default messages; |
52 changes: 52 additions & 0 deletions
52
src/courseware/course/sequence/Unit/translation-selection/useTranslationSelection.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { useCallback } from 'react'; | ||
import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; | ||
import { | ||
getLocalStorage, | ||
setLocalStorage, | ||
} from '../../../../../data/localStorage'; | ||
|
||
export const selectedLanguageKey = 'selectedLanguages'; | ||
|
||
export const languages = Object.entries({ | ||
en: 'English', | ||
es: 'Spanish', | ||
}); | ||
|
||
export const stateKeys = StrictDict({ | ||
selectedIndex: 'selectedIndex', | ||
}); | ||
|
||
// TODO: this should be rewrite in the future decision. Currently it return | ||
// null if the language is English or not set. | ||
export const getTranslateLanguage = (courseId) => { | ||
const selectedLanguageItem = getLocalStorage(selectedLanguageKey) || {}; | ||
return selectedLanguageItem[courseId] !== 'en' | ||
? selectedLanguageItem[courseId] | ||
: null; | ||
}; | ||
|
||
const useTranslationSelection = ({ courseId, close }) => { | ||
const selectedLanguageItem = getLocalStorage(selectedLanguageKey) || {}; | ||
const selectedLanguage = selectedLanguageItem[courseId] || 'en'; | ||
const [selectedIndex, setSelectedIndex] = useKeyedState( | ||
stateKeys.selectedIndex, | ||
languages.findIndex(([key]) => key === selectedLanguage), | ||
); | ||
|
||
const onSubmit = useCallback(() => { | ||
const newSelectedLanguage = languages[selectedIndex][0]; | ||
setLocalStorage(newSelectedLanguage, { | ||
...selectedLanguageItem, | ||
[courseId]: newSelectedLanguage, | ||
}); | ||
close(); | ||
}, [selectedIndex, setSelectedIndex]); | ||
|
||
return { | ||
selectedIndex, | ||
setSelectedIndex, | ||
onSubmit, | ||
}; | ||
}; | ||
|
||
export default useTranslationSelection; |
60 changes: 60 additions & 0 deletions
60
src/courseware/course/sequence/Unit/translation-selection/useTranslationTour.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { useCallback } from 'react'; | ||
|
||
import { useIntl } from '@edx/frontend-platform/i18n'; | ||
import { useToggle } from '@edx/paragon'; | ||
import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils'; | ||
|
||
import messages from './messages'; | ||
|
||
const hasSeenTranslationTourKey = 'hasSeenTranslationTour'; | ||
|
||
export const stateKeys = StrictDict({ | ||
showTranslationTour: 'showTranslationTour', | ||
}); | ||
|
||
const useTranslationTour = () => { | ||
const { formatMessage } = useIntl(); | ||
|
||
const [isTourEnabled, setIsTourEnabled] = useKeyedState( | ||
stateKeys.showTranslationTour, | ||
global.localStorage.getItem(hasSeenTranslationTourKey) !== 'true', | ||
); | ||
const endTour = useCallback(() => { | ||
global.localStorage.setItem(hasSeenTranslationTourKey, 'true'); | ||
setIsTourEnabled(false); | ||
}, [isTourEnabled, setIsTourEnabled]); | ||
|
||
const [isOpen, open, close] = useToggle(false); | ||
|
||
const translationTour = isTourEnabled | ||
? { | ||
tourId: 'translation', | ||
enabled: isTourEnabled, | ||
onDismiss: endTour, | ||
onEnd: () => { | ||
endTour(); | ||
open(); | ||
}, | ||
checkpoints: [ | ||
{ | ||
title: formatMessage(messages.translationModalTitle), | ||
body: formatMessage(messages.translationModalBody), | ||
placement: 'bottom', | ||
target: '#translation-selection-button', | ||
showDismissButton: true, | ||
endButtonText: formatMessage(messages.tryItButtonText), | ||
dismissButtonText: formatMessage(messages.dismissButtonText), | ||
}, | ||
], | ||
} | ||
: {}; | ||
|
||
return { | ||
translationTour, | ||
isOpen, | ||
open, | ||
close, | ||
}; | ||
}; | ||
|
||
export default useTranslationTour; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.