seenByList.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import classNames from 'classnames';
  4. import moment from 'moment';
  5. import AvatarList from 'app/components/avatar/avatarList';
  6. import Tooltip from 'app/components/tooltip';
  7. import {IconShow} from 'app/icons';
  8. import {t} from 'app/locale';
  9. import ConfigStore from 'app/stores/configStore';
  10. import space from 'app/styles/space';
  11. import {AvatarUser, User} from 'app/types';
  12. import {userDisplayName} from 'app/utils/formatters';
  13. type Props = {
  14. // Avatar size
  15. avatarSize?: number;
  16. // List of *all* users that have seen something
  17. seenBy?: User[];
  18. // Tooltip message for the "Seen By" icon
  19. iconTooltip?: string;
  20. // Max avatars to display
  21. maxVisibleAvatars?: number;
  22. iconPosition?: 'left' | 'right';
  23. className?: string;
  24. };
  25. const SeenByList = ({
  26. avatarSize = 28,
  27. seenBy = [],
  28. iconTooltip = t('People who have viewed this'),
  29. maxVisibleAvatars = 10,
  30. iconPosition = 'left',
  31. className,
  32. }: Props) => {
  33. const activeUser = ConfigStore.get('user');
  34. const displayUsers = seenBy.filter(user => activeUser.id !== user.id);
  35. if (displayUsers.length === 0) {
  36. return null;
  37. }
  38. // Note className="seen-by" is required for responsive design
  39. return (
  40. <SeenByWrapper
  41. iconPosition={iconPosition}
  42. className={classNames('seen-by', className)}
  43. >
  44. <AvatarList
  45. users={displayUsers}
  46. avatarSize={avatarSize}
  47. maxVisibleAvatars={maxVisibleAvatars}
  48. renderTooltip={user => (
  49. <Fragment>
  50. {userDisplayName(user)}
  51. <br />
  52. {moment((user as AvatarUser).lastSeen).format('LL')}
  53. </Fragment>
  54. )}
  55. />
  56. <IconWrapper iconPosition={iconPosition}>
  57. <Tooltip title={iconTooltip}>
  58. <IconShow size="sm" color="gray200" />
  59. </Tooltip>
  60. </IconWrapper>
  61. </SeenByWrapper>
  62. );
  63. };
  64. const SeenByWrapper = styled('div')<{iconPosition: Props['iconPosition']}>`
  65. display: flex;
  66. margin-top: 15px;
  67. float: right;
  68. ${p => (p.iconPosition === 'left' ? 'flex-direction: row-reverse' : '')};
  69. `;
  70. const IconWrapper = styled('div')<{iconPosition: Props['iconPosition']}>`
  71. background-color: transparent;
  72. color: ${p => p.theme.textColor};
  73. height: 28px;
  74. width: 24px;
  75. line-height: 26px;
  76. text-align: center;
  77. padding-top: ${space(0.5)};
  78. ${p => (p.iconPosition === 'left' ? 'margin-right: 10px' : '')};
  79. `;
  80. export default SeenByList;