22
33import Select from '@node-core/ui-components/Common/Select' ;
44import { useTranslations } from 'next-intl' ;
5- import { useEffect , use , useMemo } from 'react' ;
5+ import { useEffect , use , useMemo , useState } from 'react' ;
66
77import useClientContext from '#site/hooks/useClientContext' ;
88import { ReleaseContext } from '#site/providers/releaseProvider' ;
@@ -16,14 +16,25 @@ const PlatformDropdown: FC = () => {
1616 const { architecture, bitness } = useClientContext ( ) ;
1717
1818 const release = use ( ReleaseContext ) ;
19+
1920 const t = useTranslations ( ) ;
2021
22+ // Compute the platform during render so it's available to both `useEffect` calls below in the same cycle
23+ // (avoiding race conditions when architecture detection and OS detection arrive in the same batch)
24+ const currentPlatform =
25+ architecture && bitness ? getUserPlatform ( architecture , bitness ) : null ;
26+
27+ // Track whether the user has manually selected a platform via the dropdown.
28+ // When true the OS/version effect will respect their choice instead of
29+ // resetting to the auto-detected value.
30+ const [ userHasSelectedPlatform , setUserHasSelectedPlatform ] = useState ( false ) ;
31+
2132 useEffect (
2233 ( ) => {
23- if ( architecture && bitness ) {
24- const autoDetectedPlatform = getUserPlatform ( architecture , bitness ) ;
25-
26- release . setPlatform ( autoDetectedPlatform ) ;
34+ if ( currentPlatform ) {
35+ // eslint-disable-next-line @eslint-react/set-state-in-effect
36+ setUserHasSelectedPlatform ( false ) ;
37+ release . setPlatform ( currentPlatform ) ;
2738 }
2839 } ,
2940 // Only react on the change of the Client Context Architecture and Bitness
@@ -49,12 +60,19 @@ const PlatformDropdown: FC = () => {
4960 useEffect (
5061 ( ) => {
5162 if ( release . os !== 'LOADING' && release . platform !== '' ) {
52- release . setPlatform ( nextItem ( release . platform , parsedPlatforms ) ) ;
63+ // If the user has not manually selected a platform and there is a currently
64+ // auto-detected one then use it otherwise fallback to the current release platform
65+ const basePlatform =
66+ ! userHasSelectedPlatform && currentPlatform
67+ ? currentPlatform
68+ : release . platform ;
69+
70+ release . setPlatform ( nextItem ( basePlatform , parsedPlatforms ) ) ;
5371 }
5472 } ,
5573 // We only want to react on the change of the OS and Version
5674 // eslint-disable-next-line @eslint-react/exhaustive-deps
57- [ release . os , release . version , release . platform ]
75+ [ release . os , release . version ]
5876 ) ;
5977
6078 return (
@@ -64,7 +82,10 @@ const PlatformDropdown: FC = () => {
6482 loading = { release . os === 'LOADING' || release . platform === '' }
6583 placeholder = { t ( 'layouts.download.dropdown.unknown' ) }
6684 ariaLabel = { t ( 'layouts.download.dropdown.platform' ) }
67- onChange = { platform => platform && release . setPlatform ( platform ) }
85+ onChange = { platform => {
86+ setUserHasSelectedPlatform ( true ) ;
87+ release . setPlatform ( platform ) ;
88+ } }
6889 className = "min-w-28"
6990 inline = { true }
7091 />
0 commit comments