File size: 2,198 Bytes
9b906ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import React from "react";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { cn } from "#/utils/utils";
import { ToggleSwitchVisual } from "#/ui/toggle-switch";

interface SettingsSwitchProps {
  testId?: string;
  name?: string;
  onToggle?: (value: boolean) => void;
  defaultIsToggled?: boolean;
  isToggled?: boolean;
  isBeta?: boolean;
  isDisabled?: boolean;
  /** Whether the toggle sits before or after the label. Defaults to "left". */
  togglePosition?: "left" | "right";
}

export function SettingsSwitch({
  children,
  testId,
  name,
  onToggle,
  defaultIsToggled,
  isToggled: controlledIsToggled,
  isBeta,
  isDisabled,
  togglePosition = "left",
}: React.PropsWithChildren<SettingsSwitchProps>) {
  const { t } = useTranslation("openhands");
  const [isToggled, setIsToggled] = React.useState(defaultIsToggled ?? false);

  const handleToggle = (value: boolean) => {
    if (isDisabled) return;
    setIsToggled(value);
    onToggle?.(value);
  };

  const input = (
    <input
      hidden
      data-testid={testId}
      name={name}
      type="checkbox"
      onChange={(e) => handleToggle(e.target.checked)}
      checked={controlledIsToggled ?? isToggled}
      disabled={isDisabled}
    />
  );

  const toggle = (
    <ToggleSwitchVisual enabled={controlledIsToggled ?? isToggled} />
  );

  const label =
    children || isBeta ? (
      <div className="flex items-center gap-1">
        <span className="text-sm">{children}</span>
        {isBeta && (
          <span className="text-[11px] leading-4 text-base font-[500] tracking-tighter bg-primary px-1 rounded-full">
            {t(I18nKey.BADGE$BETA)}
          </span>
        )}
      </div>
    ) : null;

  return (
    <label
      className={cn(
        "flex items-center gap-2",
        togglePosition === "right" ? "w-full justify-between" : "w-fit",
        isDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
      )}
    >
      {input}
      {togglePosition === "right" ? (
        <>
          {label}
          {toggle}
        </>
      ) : (
        <>
          {toggle}
          {label}
        </>
      )}
    </label>
  );
}