userFeedback.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import styled from '@emotion/styled';
  2. import {ActivityAuthor} from 'sentry/components/activity/author';
  3. import {ActivityItem} from 'sentry/components/activity/item';
  4. import {Button} from 'sentry/components/button';
  5. import Link from 'sentry/components/links/link';
  6. import {IconCopy} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {UserReport} from 'sentry/types/group';
  10. import {escape, nl2br} from 'sentry/utils';
  11. import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
  12. type Props = {
  13. issueId: string;
  14. orgSlug: string;
  15. report: UserReport;
  16. className?: string;
  17. showEventLink?: boolean;
  18. };
  19. export function EventUserFeedback({
  20. className,
  21. report,
  22. orgSlug,
  23. issueId,
  24. showEventLink = true,
  25. }: Props) {
  26. const user = report.user || {
  27. name: report.name,
  28. email: report.email,
  29. id: '',
  30. username: '',
  31. ip_address: '',
  32. };
  33. const {onClick, label} = useCopyToClipboard({text: report.email});
  34. return (
  35. <div className={className}>
  36. <StyledActivityItem
  37. date={report.dateCreated}
  38. author={{type: 'user', user}}
  39. header={
  40. <Items>
  41. <ActivityAuthor>{report.name}</ActivityAuthor>
  42. <CopyButton
  43. aria-label={label}
  44. borderless
  45. onClick={onClick}
  46. size="zero"
  47. title={label}
  48. tooltipProps={{delay: 0}}
  49. translucentBorder
  50. icon={<StyledIconCopy size="xs" />}
  51. >
  52. {report.email}
  53. </CopyButton>
  54. {report.eventID && showEventLink && (
  55. <ViewEventLink
  56. to={`/organizations/${orgSlug}/issues/${issueId}/events/${report.eventID}/?referrer=user-feedback`}
  57. >
  58. {t('View event')}
  59. </ViewEventLink>
  60. )}
  61. </Items>
  62. }
  63. >
  64. <p
  65. dangerouslySetInnerHTML={{
  66. __html: nl2br(escape(report.comments)),
  67. }}
  68. />
  69. </StyledActivityItem>
  70. </div>
  71. );
  72. }
  73. const StyledActivityItem = styled(ActivityItem)`
  74. margin-bottom: 0;
  75. `;
  76. const Items = styled('div')`
  77. display: flex;
  78. align-items: center;
  79. gap: ${space(1)};
  80. `;
  81. const CopyButton = styled(Button)`
  82. color: ${p => p.theme.subText};
  83. font-size: ${p => p.theme.fontSizeSmall};
  84. font-weight: ${p => p.theme.fontWeightNormal};
  85. `;
  86. const StyledIconCopy = styled(IconCopy)``;
  87. const ViewEventLink = styled(Link)`
  88. font-weight: ${p => p.theme.fontWeightNormal};
  89. font-size: 0.9em;
  90. `;