dictionary-modal-content.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { useCallback, useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import useAsync from '../../../shared/hooks/use-async'
  4. import { postJSON } from '../../../infrastructure/fetch-json'
  5. import ignoredWords from '../ignored-words'
  6. import { debugConsole } from '@/utils/debugging'
  7. import {
  8. OLModalBody,
  9. OLModalFooter,
  10. OLModalHeader,
  11. OLModalTitle,
  12. } from '@/features/ui/components/ol/ol-modal'
  13. import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
  14. import OLNotification from '@/features/ui/components/ol/ol-notification'
  15. import OLButton from '@/features/ui/components/ol/ol-button'
  16. import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
  17. import { bsVersion } from '@/features/utils/bootstrap-5'
  18. type DictionaryModalContentProps = {
  19. handleHide: () => void
  20. }
  21. const wordsSortFunction = (a: string, b: string) => a.localeCompare(b)
  22. export default function DictionaryModalContent({
  23. handleHide,
  24. }: DictionaryModalContentProps) {
  25. const { t } = useTranslation()
  26. const [learnedWords, setLearnedWords] = useState(ignoredWords.learnedWords)
  27. const { isError, runAsync } = useAsync()
  28. const handleRemove = useCallback(
  29. word => {
  30. runAsync(
  31. postJSON('/spelling/unlearn', {
  32. body: {
  33. word,
  34. },
  35. })
  36. )
  37. .then(() => {
  38. ignoredWords.remove(word)
  39. setLearnedWords(new Set(ignoredWords.learnedWords))
  40. })
  41. .catch(debugConsole.error)
  42. },
  43. [runAsync]
  44. )
  45. return (
  46. <>
  47. <OLModalHeader closeButton>
  48. <OLModalTitle>{t('edit_dictionary')}</OLModalTitle>
  49. </OLModalHeader>
  50. <OLModalBody>
  51. {isError ? (
  52. <OLNotification
  53. type="error"
  54. content={t('generic_something_went_wrong')}
  55. />
  56. ) : null}
  57. {learnedWords?.size > 0 ? (
  58. <ul className="list-unstyled dictionary-entries-list">
  59. {[...learnedWords].sort(wordsSortFunction).map(learnedWord => (
  60. <li key={learnedWord} className="dictionary-entry">
  61. <span className="dictionary-entry-name">{learnedWord}</span>
  62. <OLTooltip
  63. id={`tooltip-remove-learned-word-${learnedWord}`}
  64. description={t('edit_dictionary_remove')}
  65. overlayProps={{ delay: 0 }}
  66. >
  67. <OLIconButton
  68. variant="danger"
  69. size="sm"
  70. onClick={() => handleRemove(learnedWord)}
  71. bs3Props={{ bsSize: 'xsmall' }}
  72. icon={
  73. bsVersion({
  74. bs5: 'delete',
  75. bs3: 'trash-o',
  76. }) as string
  77. }
  78. accessibilityLabel={t('edit_dictionary_remove')}
  79. />
  80. </OLTooltip>
  81. </li>
  82. ))}
  83. </ul>
  84. ) : (
  85. <p className="dictionary-empty-body text-center">
  86. <i>{t('edit_dictionary_empty')}</i>
  87. </p>
  88. )}
  89. </OLModalBody>
  90. <OLModalFooter>
  91. <OLButton variant="secondary" onClick={handleHide}>
  92. {t('close')}
  93. </OLButton>
  94. </OLModalFooter>
  95. </>
  96. )
  97. }