The Node.js® Website
1'use client';
2
3import { useTranslations } from 'next-intl';
4import { useContext, useEffect, useMemo } from 'react';
5import type { FC } from 'react';
6
7import Select from '@/components/Common/Select';
8import Apple from '@/components/Icons/Platform/Apple';
9import Linux from '@/components/Icons/Platform/Linux';
10import Microsoft from '@/components/Icons/Platform/Microsoft';
11import { useDetectOS } from '@/hooks/react-client';
12import { ReleaseContext } from '@/providers/releaseProvider';
13import type { UserOS } from '@/types/userOS';
14import {
15 formatDropdownItems,
16 operatingSystemItems,
17} from '@/util/downloadUtils';
18
19type OperatingSystemDropdownProps = { exclude?: Array<UserOS> };
20
21const OperatingSystemDropdown: FC<OperatingSystemDropdownProps> = ({
22 exclude = [],
23}) => {
24 const { os: userOS } = useDetectOS();
25 const { platform, os, setOS } = useContext(ReleaseContext);
26 const t = useTranslations();
27
28 // we shouldn't react when "actions" change
29 // eslint-disable-next-line react-hooks/exhaustive-deps
30 useEffect(() => setOS(userOS), [userOS]);
31
32 // @TODO: We should have a proper utility that gives
33 // disabled OSs, Platforms, based on specific criteria
34 // this can be an optimisation for the future
35 // to remove this logic from this component
36 const disabledItems = useMemo(() => {
37 const disabledItems = exclude;
38
39 if (platform === 'BREW') {
40 disabledItems.push('WIN');
41 }
42
43 if (platform === 'DOCKER') {
44 disabledItems.push('LINUX');
45 }
46
47 return disabledItems;
48 }, [exclude, platform]);
49
50 // @TODO: We should have a proper utility that gives
51 // disabled OSs, Platforms, based on specific criteria
52 // this can be an optimisation for the future
53 // to remove this logic from this component
54 useEffect(() => {
55 const currentOSExcluded = disabledItems.includes(os);
56
57 const nonExcludedOS = operatingSystemItems
58 .map(({ value }) => value)
59 .find(os => !disabledItems.includes(os));
60
61 if (currentOSExcluded && nonExcludedOS) {
62 setOS(nonExcludedOS);
63 }
64 // we shouldn't react when "actions" change
65 // eslint-disable-next-line react-hooks/exhaustive-deps
66 }, [os, disabledItems]);
67
68 return (
69 <Select
70 label={t('layouts.download.dropdown.os')}
71 values={formatDropdownItems({
72 items: operatingSystemItems,
73 disabledItems,
74 icons: {
75 WIN: <Microsoft width={16} height={16} />,
76 MAC: <Apple width={16} height={16} />,
77 LINUX: <Linux width={16} height={16} />,
78 },
79 })}
80 defaultValue={os}
81 onChange={value => setOS(value as UserOS)}
82 className="w-[8.5rem]"
83 inline={true}
84 />
85 );
86};
87
88export default OperatingSystemDropdown;