shareButton.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {openModal} from 'sentry/actionCreators/modal';
  4. import {Button} from 'sentry/components/button';
  5. import RadioGroup from 'sentry/components/forms/controls/radioGroup';
  6. import Input from 'sentry/components/input';
  7. import {useReplayContext} from 'sentry/components/replays/replayContext';
  8. import TextCopyInput from 'sentry/components/textCopyInput';
  9. import {IconUpload} from 'sentry/icons';
  10. import {t} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import {formatSecondsToClock, parseClockToSeconds} from 'sentry/utils/formatters';
  13. import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes';
  14. import {useRoutes} from 'sentry/utils/useRoutes';
  15. function ShareModal({currentTimeSec, Header, Body}) {
  16. const routes = useRoutes();
  17. const [customSeconds, setSeconds] = useState(currentTimeSec);
  18. const [shareMode, setShareMode] = useState<'current' | 'user'>('current');
  19. const url = new URL(window.location.href);
  20. const {searchParams} = url;
  21. searchParams.set('referrer', getRouteStringFromRoutes(routes));
  22. searchParams.set(
  23. 't',
  24. shareMode === 'user' ? String(customSeconds) : String(currentTimeSec)
  25. );
  26. // Use `value` instead of `defaultValue` so the number resets to
  27. // `currentTimeSec` if the user toggles isCustom
  28. const value =
  29. shareMode === 'user'
  30. ? formatSecondsToClock(customSeconds, {padAll: false})
  31. : formatSecondsToClock(currentTimeSec, {padAll: false});
  32. return (
  33. <div>
  34. <Header>
  35. <h3>Share Replay</h3>
  36. </Header>
  37. <Body>
  38. <StyledTextCopyInput aria-label={t('Deeplink to current timestamp')} size="sm">
  39. {url.toString()}
  40. </StyledTextCopyInput>
  41. <ShareAtRadioGroup>
  42. <RadioGroup
  43. value={shareMode}
  44. choices={[
  45. ['current', 'Share at current timestamp'],
  46. [
  47. 'user',
  48. <InputRow key="user">
  49. <div>{t('Share at')}</div>
  50. <Input
  51. name="time"
  52. onFocus={() => setShareMode('user')}
  53. value={value}
  54. onChange={e => {
  55. setSeconds(parseClockToSeconds(e.target.value));
  56. }}
  57. />
  58. </InputRow>,
  59. ],
  60. ]}
  61. label="share at"
  62. onChange={id => setShareMode(id)}
  63. />
  64. </ShareAtRadioGroup>
  65. </Body>
  66. </div>
  67. );
  68. }
  69. function ShareButton() {
  70. // Cannot use this hook inside the modal because context will not be wired up
  71. const {currentTime} = useReplayContext();
  72. // floor() to remove ms level precision. It's a cleaner url by default this way.
  73. const currentTimeSec = Math.floor(currentTime / 1000);
  74. return (
  75. <Button
  76. size="sm"
  77. icon={<IconUpload size="sm" />}
  78. onClick={() =>
  79. openModal(deps => <ShareModal currentTimeSec={currentTimeSec} {...deps} />)
  80. }
  81. >
  82. {t('Share')}
  83. </Button>
  84. );
  85. }
  86. const StyledTextCopyInput = styled(TextCopyInput)`
  87. /* Keep height consistent with the other input in the modal */
  88. input {
  89. height: 38px;
  90. }
  91. `;
  92. const InputRow = styled('div')`
  93. display: flex;
  94. flex-direction: row;
  95. gap: ${space(1)};
  96. align-items: center;
  97. & > div {
  98. min-width: fit-content;
  99. }
  100. & > input {
  101. width: 100px;
  102. }
  103. `;
  104. const ShareAtRadioGroup = styled('div')`
  105. margin-top: ${space(2)};
  106. display: flex;
  107. flex-direction: column;
  108. max-width: fit-content;
  109. `;
  110. export default ShareButton;