dictionary-modal-content.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { useCallback, useMemo } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { Alert, Button, Modal } from 'react-bootstrap'
  4. import Icon from '../../../shared/components/icon'
  5. import Tooltip from '../../../shared/components/tooltip'
  6. import useAsync from '../../../shared/hooks/use-async'
  7. import { postJSON } from '../../../infrastructure/fetch-json'
  8. import ignoredWords from '../ignored-words'
  9. import BetaBadge from '../../../shared/components/beta-badge'
  10. type DictionaryModalContentProps = {
  11. handleHide: () => void
  12. }
  13. const wordsSortFunction = (a: string, b: string) => a.localeCompare(b)
  14. export default function DictionaryModalContent({
  15. handleHide,
  16. }: DictionaryModalContentProps) {
  17. const { t } = useTranslation()
  18. const { isError, runAsync } = useAsync()
  19. const handleRemove = useCallback(
  20. word => {
  21. ignoredWords.remove(word)
  22. runAsync(
  23. postJSON('/spelling/unlearn', {
  24. body: {
  25. word,
  26. },
  27. })
  28. ).catch(console.error)
  29. },
  30. [runAsync]
  31. )
  32. const betaBadgeTooltipProps = useMemo(() => {
  33. return {
  34. id: 'dictionary-modal-tooltip',
  35. placement: 'bottom',
  36. className: 'tooltip-wide',
  37. text: (
  38. <>
  39. We are testing the dictionary manager.
  40. <br />
  41. Click to give feedback
  42. </>
  43. ),
  44. }
  45. }, [])
  46. return (
  47. <>
  48. <Modal.Header closeButton>
  49. <Modal.Title>
  50. {t('edit_dictionary')}{' '}
  51. <BetaBadge
  52. tooltip={betaBadgeTooltipProps}
  53. url="https://forms.gle/8cLBEW6HU9mDKBPX9"
  54. phase="release"
  55. />
  56. </Modal.Title>
  57. </Modal.Header>
  58. <Modal.Body>
  59. {isError ? (
  60. <Alert bsStyle="danger">{t('generic_something_went_wrong')}</Alert>
  61. ) : null}
  62. {ignoredWords.learnedWords?.size > 0 ? (
  63. <ul className="list-unstyled dictionary-entries-list">
  64. {[...ignoredWords.learnedWords]
  65. .sort(wordsSortFunction)
  66. .map(learnedWord => (
  67. <li key={learnedWord} className="dictionary-entry">
  68. <span className="dictionary-entry-name">{learnedWord}</span>
  69. <Tooltip
  70. id={`tooltip-remove-learned-word-${learnedWord}`}
  71. description={t('edit_dictionary_remove')}
  72. overlayProps={{ delay: 0 }}
  73. >
  74. <Button
  75. bsStyle="danger"
  76. bsSize="xs"
  77. onClick={() => handleRemove(learnedWord)}
  78. >
  79. <Icon
  80. type="trash-o"
  81. accessibilityLabel={t('edit_dictionary_remove')}
  82. />
  83. </Button>
  84. </Tooltip>
  85. </li>
  86. ))}
  87. </ul>
  88. ) : (
  89. <p className="dictionary-empty-body text-center">
  90. <i>{t('edit_dictionary_empty')}</i>
  91. </p>
  92. )}
  93. </Modal.Body>
  94. <Modal.Footer>
  95. <Button onClick={handleHide}>{t('done')}</Button>
  96. </Modal.Footer>
  97. </>
  98. )
  99. }