You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UploadImageButton.tsx 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { Theme } from '@mui/material';
  2. import React, { useCallback, useRef } from 'react';
  3. import { WithTranslation } from 'react-i18next';
  4. import { makeStyles } from 'tss-react/mui';
  5. import { v4 as uuidv4 } from 'uuid';
  6. import { translate } from '../../base/i18n/functions';
  7. import Icon from '../../base/icons/components/Icon';
  8. import { IconPlusCircle } from '../../base/icons/svg';
  9. import { type Image, VIRTUAL_BACKGROUND_TYPE } from '../constants';
  10. import { resizeImage } from '../functions';
  11. import logger from '../logger';
  12. interface IProps extends WithTranslation {
  13. /**
  14. * Callback used to set the 'loading' state of the parent component.
  15. */
  16. setLoading: Function;
  17. /**
  18. * Callback used to set the options.
  19. */
  20. setOptions: Function;
  21. /**
  22. * Callback used to set the storedImages array.
  23. */
  24. setStoredImages: Function;
  25. /**
  26. * If a label should be displayed alongside the button.
  27. */
  28. showLabel: boolean;
  29. /**
  30. * A list of images locally stored.
  31. */
  32. storedImages: Array<Image>;
  33. }
  34. // @ts-ignore
  35. const useStyles = makeStyles()((theme: Theme) => {
  36. return {
  37. addBackground: {
  38. marginRight: theme.spacing(2)
  39. },
  40. button: {
  41. display: 'none'
  42. },
  43. label: {
  44. fontSize: '14px',
  45. fontWeight: '600',
  46. lineHeight: '20px',
  47. marginTop: theme.spacing(3),
  48. marginBottom: theme.spacing(2),
  49. color: '#669aec',
  50. display: 'inline-flex',
  51. cursor: 'pointer'
  52. }
  53. };
  54. });
  55. /**
  56. * Component used to upload an image.
  57. *
  58. * @param {Object} Props - The props of the component.
  59. * @returns {React$Node}
  60. */
  61. function UploadImageButton({
  62. setLoading,
  63. setOptions,
  64. setStoredImages,
  65. showLabel,
  66. storedImages,
  67. t
  68. }: IProps) {
  69. const { classes } = useStyles();
  70. const uploadImageButton = useRef<HTMLInputElement>(null);
  71. const uploadImageKeyPress = useCallback(e => {
  72. if (uploadImageButton.current && (e.key === ' ' || e.key === 'Enter')) {
  73. e.preventDefault();
  74. uploadImageButton.current.click();
  75. }
  76. }, [ uploadImageButton.current ]);
  77. const uploadImage = useCallback(async e => {
  78. const reader = new FileReader();
  79. const imageFile = e.target.files;
  80. reader.readAsDataURL(imageFile[0]);
  81. reader.onload = async () => {
  82. const url = await resizeImage(reader.result);
  83. const uuId = uuidv4();
  84. setStoredImages([
  85. ...storedImages,
  86. {
  87. id: uuId,
  88. src: url
  89. }
  90. ]);
  91. setOptions({
  92. backgroundType: VIRTUAL_BACKGROUND_TYPE.IMAGE,
  93. enabled: true,
  94. url,
  95. selectedThumbnail: uuId
  96. });
  97. };
  98. logger.info('New virtual background image uploaded!');
  99. reader.onerror = () => {
  100. setLoading(false);
  101. logger.error('Failed to upload virtual image!');
  102. };
  103. }, [ storedImages ]);
  104. return (
  105. <>
  106. {showLabel && <label
  107. aria-label = { t('virtualBackground.uploadImage') }
  108. className = { classes.label }
  109. htmlFor = 'file-upload'
  110. onKeyPress = { uploadImageKeyPress }
  111. tabIndex = { 0 } >
  112. <Icon
  113. className = { classes.addBackground }
  114. size = { 20 }
  115. src = { IconPlusCircle } />
  116. {t('virtualBackground.addBackground')}
  117. </label>}
  118. <input
  119. accept = 'image/*'
  120. className = { classes.button }
  121. id = 'file-upload'
  122. onChange = { uploadImage }
  123. ref = { uploadImageButton }
  124. type = 'file' />
  125. </>
  126. );
  127. }
  128. export default translate(UploadImageButton);