UserPicture.jsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { UncontrolledTooltip } from 'reactstrap';
  4. import { pagePathUtils } from '@growi/core';
  5. const { userPageRoot } = pagePathUtils;
  6. const DEFAULT_IMAGE = '/images/icons/user.svg';
  7. export class UserPicture extends React.Component {
  8. getClassName() {
  9. const className = ['rounded-circle', 'picture'];
  10. // size
  11. if (this.props.size) {
  12. className.push(`picture-${this.props.size}`);
  13. }
  14. return className.join(' ');
  15. }
  16. renderForNull() {
  17. return (
  18. <img
  19. src={DEFAULT_IMAGE}
  20. alt="someone"
  21. className={this.getClassName()}
  22. />
  23. );
  24. }
  25. RootElmWithoutLink = (props) => {
  26. return <span {...props}>{props.children}</span>;
  27. }
  28. RootElmWithLink = (props) => {
  29. const { user } = this.props;
  30. const href = userPageRoot(user);
  31. // Using <span> tag here instead of <a> tag because UserPicture is used in SearchResultList which is essentially a anchor tag.
  32. // Nested anchor tags causes a warning.
  33. // https://stackoverflow.com/questions/13052598/creating-anchor-tag-inside-anchor-taga
  34. return <span onClick={() => { window.location.href = href }} {...props}>{props.children}</span>;
  35. }
  36. withTooltip = (RootElm) => {
  37. const { user } = this.props;
  38. const id = `user-picture-${Math.random().toString(32).substring(2)}`;
  39. return props => (
  40. <>
  41. <RootElm id={id}>{props.children}</RootElm>
  42. <UncontrolledTooltip placement="bottom" target={id} delay={0} fade={false}>
  43. @{user.username}<br />
  44. {user.name}
  45. </UncontrolledTooltip>
  46. </>
  47. );
  48. }
  49. render() {
  50. const user = this.props.user;
  51. if (user == null) {
  52. return this.renderForNull();
  53. }
  54. const { noLink, noTooltip } = this.props;
  55. // determine RootElm
  56. let RootElm = noLink ? this.RootElmWithoutLink : this.RootElmWithLink;
  57. if (!noTooltip) {
  58. RootElm = this.withTooltip(RootElm);
  59. }
  60. const userPictureSrc = user.imageUrlCached || DEFAULT_IMAGE;
  61. return (
  62. <RootElm>
  63. <img
  64. src={userPictureSrc}
  65. alt={user.username}
  66. className={this.getClassName()}
  67. />
  68. </RootElm>
  69. );
  70. }
  71. }
  72. UserPicture.propTypes = {
  73. user: PropTypes.object,
  74. size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
  75. noLink: PropTypes.bool,
  76. noTooltip: PropTypes.bool,
  77. };
  78. UserPicture.defaultProps = {
  79. size: null,
  80. noLink: false,
  81. noTooltip: false,
  82. };