|
1 | 1 | import type {ReactNode} from 'react'; |
2 | 2 | import {Fragment, useEffect, useMemo, useState} from 'react'; |
3 | 3 | import styled from '@emotion/styled'; |
| 4 | +import {parseAsStringLiteral, useQueryState} from 'nuqs'; |
4 | 5 | import {PlatformIcon} from 'platformicons'; |
5 | 6 |
|
6 | 7 | import HighlightTopRightPattern from 'sentry-images/pattern/highlight-top-right.svg'; |
7 | 8 |
|
8 | 9 | import {LinkButton} from '@sentry/scraps/button'; |
9 | 10 | import {CompactSelect} from '@sentry/scraps/compactSelect'; |
10 | | -import {Flex} from '@sentry/scraps/layout'; |
| 11 | +import {Container, Flex} from '@sentry/scraps/layout'; |
11 | 12 | import {OverlayTrigger} from '@sentry/scraps/overlayTrigger'; |
12 | 13 |
|
13 | 14 | import {FeedbackOnboardingLayout} from 'sentry/components/feedback/feedbackOnboarding/feedbackOnboardingLayout'; |
@@ -42,7 +43,6 @@ import {useLegacyStore} from 'sentry/stores/useLegacyStore'; |
42 | 43 | import type {SelectValue} from 'sentry/types/core'; |
43 | 44 | import type {PlatformKey, Project} from 'sentry/types/project'; |
44 | 45 | import {trackAnalytics} from 'sentry/utils/analytics'; |
45 | | -import {useUrlParams} from 'sentry/utils/url/useUrlParams'; |
46 | 46 | import {useLocation} from 'sentry/utils/useLocation'; |
47 | 47 | import {useOrganization} from 'sentry/utils/useOrganization'; |
48 | 48 |
|
@@ -197,21 +197,20 @@ function OnboardingContent({currentProject}: {currentProject: Project}) { |
197 | 197 | textValue?: string; |
198 | 198 | }>(jsFrameworkSelectOptions[0]!); |
199 | 199 |
|
200 | | - const defaultTab = 'npm'; |
201 | 200 | const location = useLocation(); |
202 | 201 | const crashReportOnboarding = location.hash === CRASH_REPORT_HASH; |
203 | 202 |
|
204 | | - const {getParamValue: setupMode, setParamValue: setSetupMode} = useUrlParams( |
| 203 | + const [setupMode, setSetupMode] = useQueryState( |
205 | 204 | 'mode', |
206 | | - defaultTab |
| 205 | + parseAsStringLiteral(['npm', 'jsLoader'] as const).withDefault('npm') |
207 | 206 | ); |
208 | 207 |
|
209 | 208 | const currentPlatform = currentProject.platform |
210 | 209 | ? (platforms.find(p => p.id === currentProject.platform) ?? otherPlatform) |
211 | 210 | : otherPlatform; |
212 | 211 |
|
213 | 212 | const webBackendPlatform = replayBackendPlatforms.includes(currentPlatform.id); |
214 | | - const showJsFrameworkInstructions = webBackendPlatform && setupMode() === 'npm'; |
| 213 | + const showJsFrameworkInstructions = webBackendPlatform && setupMode === 'npm'; |
215 | 214 |
|
216 | 215 | const crashApiPlatform = feedbackCrashApiPlatforms.includes(currentPlatform.id); |
217 | 216 | const widgetPlatform = feedbackWidgetPlatforms.includes(currentPlatform.id); |
@@ -261,48 +260,50 @@ function OnboardingContent({currentProject}: {currentProject: Project}) { |
261 | 260 | const radioButtons = ( |
262 | 261 | <Header> |
263 | 262 | {showRadioButtons ? ( |
264 | | - <StyledRadioGroup |
265 | | - label="mode" |
266 | | - choices={[ |
267 | | - [ |
268 | | - 'npm', |
269 | | - webBackendPlatform ? ( |
270 | | - <Flex align="center" wrap="wrap" gap="md" key="platform-select"> |
271 | | - {tct('I use [platformSelect]', { |
272 | | - platformSelect: ( |
273 | | - <CompactSelect |
274 | | - size="xs" |
275 | | - trigger={triggerProps => ( |
276 | | - <OverlayTrigger.Button {...triggerProps}> |
277 | | - {jsFramework.label ?? triggerProps.children} |
278 | | - </OverlayTrigger.Button> |
279 | | - )} |
280 | | - value={jsFramework.value} |
281 | | - onChange={setJsFramework} |
282 | | - options={jsFrameworkSelectOptions} |
283 | | - position="bottom-end" |
284 | | - key={jsFramework.textValue} |
285 | | - disabled={setupMode() === 'jsLoader'} |
| 263 | + <Container padding="md 0"> |
| 264 | + <RadioGroup<typeof setupMode> |
| 265 | + label="mode" |
| 266 | + choices={[ |
| 267 | + [ |
| 268 | + 'npm', |
| 269 | + webBackendPlatform ? ( |
| 270 | + <Flex align="center" wrap="wrap" gap="md" key="platform-select"> |
| 271 | + {tct('I use [platformSelect]', { |
| 272 | + platformSelect: ( |
| 273 | + <CompactSelect |
| 274 | + size="xs" |
| 275 | + trigger={triggerProps => ( |
| 276 | + <OverlayTrigger.Button {...triggerProps}> |
| 277 | + {jsFramework.label ?? triggerProps.children} |
| 278 | + </OverlayTrigger.Button> |
| 279 | + )} |
| 280 | + value={jsFramework.value} |
| 281 | + onChange={setJsFramework} |
| 282 | + options={jsFrameworkSelectOptions} |
| 283 | + position="bottom-end" |
| 284 | + key={jsFramework.textValue} |
| 285 | + disabled={setupMode === 'jsLoader'} |
| 286 | + /> |
| 287 | + ), |
| 288 | + })} |
| 289 | + {jsFrameworkDocs?.platformOptions && ( |
| 290 | + <PlatformOptionDropdown |
| 291 | + platformOptions={jsFrameworkDocs?.platformOptions} |
| 292 | + disabled={setupMode === 'jsLoader'} |
286 | 293 | /> |
287 | | - ), |
288 | | - })} |
289 | | - {jsFrameworkDocs?.platformOptions && ( |
290 | | - <PlatformOptionDropdown |
291 | | - platformOptions={jsFrameworkDocs?.platformOptions} |
292 | | - disabled={setupMode() === 'jsLoader'} |
293 | | - /> |
294 | | - )} |
295 | | - </Flex> |
296 | | - ) : ( |
297 | | - t('I use NPM or Yarn') |
298 | | - ), |
299 | | - ], |
300 | | - ['jsLoader', t('I use HTML templates (Loader Script)')], |
301 | | - ]} |
302 | | - value={setupMode()} |
303 | | - onChange={setSetupMode} |
304 | | - tooltipPosition="top-start" |
305 | | - /> |
| 294 | + )} |
| 295 | + </Flex> |
| 296 | + ) : ( |
| 297 | + t('I use NPM or Yarn') |
| 298 | + ), |
| 299 | + ], |
| 300 | + ['jsLoader', t('I use HTML templates (Loader Script)')], |
| 301 | + ]} |
| 302 | + value={setupMode} |
| 303 | + onChange={value => setSetupMode(value)} |
| 304 | + tooltipPosition="top-start" |
| 305 | + /> |
| 306 | + </Container> |
306 | 307 | ) : ( |
307 | 308 | (newDocs?.platformOptions?.siblingOption || |
308 | 309 | newDocs?.platformOptions?.packageManager) && |
@@ -370,9 +371,8 @@ function OnboardingContent({currentProject}: {currentProject: Project}) { |
370 | 371 | return 'feedbackOnboardingCrashApi'; |
371 | 372 | } |
372 | 373 | if ( |
373 | | - setupMode() === 'npm' || // switched to NPM option |
374 | | - (!setupMode() && defaultTab === 'npm' && widgetPlatform) || // default value for FE frameworks when ?mode={...} in URL is not set yet |
375 | | - npmOnlyFramework // even if '?mode=jsLoader', only show npm instructions for FE frameworks) |
| 374 | + setupMode === 'npm' || // switched to NPM option |
| 375 | + npmOnlyFramework // even if '?mode=jsLoader', only show npm instructions for FE frameworks |
376 | 376 | ) { |
377 | 377 | return 'feedbackOnboardingNpm'; |
378 | 378 | } |
@@ -431,7 +431,3 @@ const StyledIdBadge = styled(IdBadge)` |
431 | 431 | white-space: nowrap; |
432 | 432 | flex-shrink: 1; |
433 | 433 | `; |
434 | | - |
435 | | -const StyledRadioGroup = styled(RadioGroup)` |
436 | | - padding: ${p => p.theme.space.md} 0; |
437 | | -`; |
0 commit comments