dictionary-modal-content.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 beta 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. />
  55. </Modal.Title>
  56. </Modal.Header>
  57. <Modal.Body>
  58. {isError ? (
  59. <Alert bsStyle="danger">{t('generic_something_went_wrong')}</Alert>
  60. ) : null}
  61. {ignoredWords.learnedWords?.size > 0 ? (
  62. <ul className="list-unstyled dictionary-entries-list">
  63. {[...ignoredWords.learnedWords]
  64. .sort(wordsSortFunction)
  65. .map(learnedWord => (
  66. <li key={learnedWord} className="dictionary-entry">
  67. <span className="dictionary-entry-name">{learnedWord}</span>
  68. <Tooltip
  69. id={`tooltip-remove-learned-word-${learnedWord}`}
  70. description={t('edit_dictionary_remove')}
  71. overlayProps={{ delay: 0 }}
  72. >
  73. <Button
  74. bsStyle="danger"
  75. bsSize="xs"
  76. onClick={() => handleRemove(learnedWord)}
  77. >
  78. <Icon
  79. type="trash-o"
  80. accessibilityLabel={t('edit_dictionary_remove')}
  81. />
  82. </Button>
  83. </Tooltip>
  84. </li>
  85. ))}
  86. </ul>
  87. ) : (
  88. <p className="dictionary-empty-body text-center">
  89. <i>{t('edit_dictionary_empty')}</i>
  90. </p>
  91. )}
  92. </Modal.Body>
  93. <Modal.Footer>
  94. <Button onClick={handleHide}>{t('done')}</Button>
  95. </Modal.Footer>
  96. </>
  97. )
  98. }