@chakra-ui/react#Checkbox TypeScript Examples

The following examples show how to use @chakra-ui/react#Checkbox. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: AutoInstallUpdatesField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
AutoInstallUpdatesField = ({ helpText }: AutoInstallUpdatesFieldProps): JSX.Element => {
    const autoInstall: boolean = (useAppSelector(state => state.config.auto_install_updates) ?? false);

    return (
        <FormControl>
            <Checkbox id='auto_install_updates' isChecked={autoInstall} onChange={onCheckboxToggle}>Auto Install / Apply Updates</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        When enabled, BlueBubbles will auto-install the latest available version when an update is detected
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #2
Source File: Content.tsx    From calories-in with MIT License 6 votes vote down vote up
function Content({ selectRef }: Props) {
  const filter = useFoodsFilter()
  const foodsFilterActions = useFoodsFilterActions()

  function onSelectChange(event: ChangeEvent<HTMLSelectElement>) {
    const { value } = event.target
    foodsFilterActions.updateFilter({ categoryId: Number(value) })
  }

  function onCheckboxChange(event: ChangeEvent<HTMLInputElement>) {
    const { checked } = event.target
    foodsFilterActions.updateFilter({ onlyFoodsAddedByUser: checked })
  }

  return (
    <VStack spacing={5} p={1} alignItems="flex-start">
      <FoodCategoriesSelect
        ref={selectRef}
        flex={3}
        onChange={onSelectChange}
        value={filter.categoryId}
      >
        <option value={0}>All categories</option>
      </FoodCategoriesSelect>

      <Checkbox
        onChange={onCheckboxChange}
        colorScheme="teal"
        isChecked={Boolean(filter.onlyFoodsAddedByUser)}
      >
        Only items added by me
      </Checkbox>
    </VStack>
  )
}
Example #3
Source File: checkbox-single.tsx    From formik-chakra-ui with MIT License 6 votes vote down vote up
CheckboxSingleControl: FC<CheckboxSingleProps> = React.forwardRef(
  (props: CheckboxSingleProps, ref: React.ForwardedRef<HTMLInputElement>) => {
    const { name, label, children, checkBoxProps, ...rest } = props;
    const [field, { error, touched }] = useField(name);
    const isChecked = field.value;

    return (
      <FormControl name={name} {...rest}>
        <Checkbox
          {...field}
          id={name}
          isInvalid={!!error && touched}
          isChecked={isChecked}
          ref={ref}
          {...checkBoxProps}
        >
          {label}
          {children}
        </Checkbox>
      </FormControl>
    );
  }
)
Example #4
Source File: checkbox-control.tsx    From formik-chakra-ui with MIT License 6 votes vote down vote up
CheckboxControl: FC<CheckboxControlProps> = React.forwardRef(
  (props: CheckboxControlProps, ref: React.ForwardedRef<HTMLInputElement>) => {
    const { name, label, children, ...rest } = props;
    const [field, { error, touched }] = useField(name);
    let isChecked;
    if (field.value instanceof Array) {
      isChecked = field.value.includes(props.value) ?? false;
    }

    return (
      <Checkbox
        {...field}
        isInvalid={!!error && touched}
        isChecked={isChecked}
        ref={ref}
        {...rest}
      >
        {label}
        {children}
      </Checkbox>
    );
  }
)
Example #5
Source File: CheckBoxGroup.tsx    From ke with MIT License 6 votes vote down vote up
CheckBoxGroupInner = <T extends object>(
  props: CheckBoxGroupProps<T>,
  ref?: React.ForwardedRef<HTMLInputElement>
): JSX.Element => {
  const { value, onChange, getKey, getValue, getLabel, defaultValue } = props

  const handleChange = useCallback(
    (changeValues: (string | number)[]): void => {
      onChange(value.filter((v) => changeValues.includes(getValue(v))))
    },
    [onChange, getValue, value]
  )

  return (
    <div ref={ref}>
      <CheckboxGroup colorScheme="brand" defaultValue={defaultValue} onChange={(values) => handleChange(values)}>
        {value.map((v: T) => (
          <Checkbox spacing={8} key={getKey(v)} value={getValue(v)} mr={4}>
            {getLabel(v)}
          </Checkbox>
        ))}
      </CheckboxGroup>
    </div>
  )
}
Example #6
Source File: ColumnsHider.tsx    From ke with MIT License 6 votes vote down vote up
export function ColumnsHider<T>({ children, onChange, columns, visibleColumns }: ColumnHiderProps<T>): JSX.Element {
  const handleChange = useCallback(
    (values: ReactText[]) => {
      const newVisibleColumns = columns.filter(({ name }) => values.includes(String(name)))

      onChange(newVisibleColumns)
    },
    [onChange, columns]
  )

  return (
    <div>
      <Popover placement="right-start">
        <PopoverTrigger>
          <Button margin="10px 0">Отображаемые колонки</Button>
        </PopoverTrigger>
        <Portal>
          <PopoverContent>
            <PopoverArrow />
            <PopoverHeader>Выберите отображаемые колонки</PopoverHeader>
            <PopoverCloseButton />
            <PopoverBody maxHeight="400px" overflow="scroll">
              <CheckboxGroup value={visibleColumns.map(({ name }) => name)} onChange={handleChange}>
                {columns.map(({ name, header }) => (
                  <Checkbox value={name} display="block">
                    {header}
                  </Checkbox>
                ))}
              </CheckboxGroup>
            </PopoverBody>
          </PopoverContent>
        </Portal>
      </Popover>
      {children}
    </div>
  )
}
Example #7
Source File: UseHttpsField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
UseHttpsField = ({ helpText }: UseHttpsFieldProps): JSX.Element => {
    const useHttps: boolean = (useAppSelector(state => state.config.use_custom_certificate) ?? false);

    return (
        <FormControl>
            <Checkbox id='use_custom_certificate' isChecked={useHttps} onChange={onCheckboxToggle}>Use Custom Certificate</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        This will install a self-signed certificate at: <Code>~/Library/Application Support/bluebubbles-server/Certs</Code>
                        <br />
                        Note: Only use this this option if you have your own certificate! Replace the certificates in the <Code>Certs</Code> directory
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #8
Source File: OledDarkThemeField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
UseOledDarkModeField = ({ helpText }: UseOledDarkModeFieldProps): JSX.Element => {
    const oledDark: boolean = (useAppSelector(state => state.config.use_oled_dark_mode) ?? false);

    return (
        <FormControl>
            <Checkbox id='use_oled_dark_mode' isChecked={oledDark} onChange={onCheckboxToggle}>Use OLED Black Dark Mode</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        Enabling this will set the dark mode theme to OLED black
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #9
Source File: AutoCaffeinateField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
AutoCaffeinateField = ({ helpText }: AutoCaffeinateFieldProps): JSX.Element => {
    const keepAwake: boolean = (useAppSelector(state => state.config.auto_caffeinate) ?? false);

    return (
        <FormControl>
            <Checkbox id='auto_caffeinate' isChecked={keepAwake}  onChange={onCheckboxToggle}>Keep macOS Awake</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        When enabled, you mac will not fall asleep due to inactivity or a screen screen saver.
                        However, your computer lid's close action may override this.
                        Make sure your computer does not go to sleep when the lid is closed.
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #10
Source File: AutoStartField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
AutoStartField = ({ helpText }: AutoStartFieldProps): JSX.Element => {
    const autoStart: boolean = (useAppSelector(state => state.config.auto_start) ?? false);

    return (
        <FormControl>
            <Checkbox id='auto_start' isChecked={autoStart}  onChange={onCheckboxToggle}>Startup with macOS</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        When enabled, BlueBubbles will start automatically when you login.
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #11
Source File: CheckForUpdatesField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
CheckForUpdatesField = ({ helpText }: CheckForUpdatesFieldProps): JSX.Element => {
    const checkForUpdates: boolean = (useAppSelector(state => state.config.check_for_updates) ?? false);

    return (
        <FormControl>
            <Checkbox id='check_for_updates' isChecked={checkForUpdates} onChange={onCheckboxToggle}>Check for Updates on Startup</Checkbox>
            <FormHelperText>
                {helpText ?? (
                    <Text>
                        When enabled, BlueBubbles will automatically check for updates on startup
                    </Text>
                )}
            </FormHelperText>
        </FormControl>
    );
}
Example #12
Source File: EncryptCommunicationsField.tsx    From bluebubbles-server with Apache License 2.0 6 votes vote down vote up
EncryptCommunicationsField = ({ helpText }: EncryptCommunicationsFieldProps): JSX.Element => {
    const encryption: boolean = (useAppSelector(state => state.config.encrypt_coms) ?? false);

    return (
        <FormControl>
            <Checkbox id='encrypt_coms' isChecked={encryption} onChange={onCheckboxToggle}>Encrypt Messages</Checkbox>
            <FormHelperText>
                {helpText ?? 'Enabling this will add an additional layer of security to the app communications by encrypting messages with a password-based AES-256-bit algorithm'}
            </FormHelperText>
        </FormControl>
    );
}
Example #13
Source File: PrivateApiField.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
PrivateApiField = ({ helpText }: PrivateApiFieldProps): JSX.Element => {
    const privateApi: boolean = (useAppSelector(state => state.config.enable_private_api) ?? false);
    const alertRef = useRef(null);
    const [requiresConfirmation, confirm] = useState((): string | null => {
        return null;
    });

    return (
        <Box mt={1}>
            <PrivateApiRequirements />

            <FormControl mt={5}>
                <Stack direction='row'>
                    <Checkbox
                        id='enable_private_api'
                        isChecked={privateApi}
                        onChange={onCheckboxToggle}
                    >
                        Private API
                    </Checkbox>
                    <Button
                        size='xs'
                        onClick={() => confirm('reinstall')}
                    >
                        Re-install Helper
                    </Button>
                </Stack>
                <FormHelperText>
                    {helpText ?? (
                        <Text>
                            If you have set up the Private API features (via MacForge or MySIMBL),
                            enable this option to allow the server to communicate with the iMessage Private API.
                        </Text>
                    )}
                </FormHelperText>
            </FormControl>

            <ConfirmationDialog
                modalRef={alertRef}
                onClose={() => confirm(null)}
                body={confirmationActions[requiresConfirmation as string]?.message}
                onAccept={() => {
                    confirmationActions[requiresConfirmation as string].func();
                }}
                isOpen={requiresConfirmation !== null}
            />
        </Box>
    );
}
Example #14
Source File: FeatureSettings.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
FeatureSettings = (): JSX.Element => {
    const hideDockIcon = (useAppSelector(state => state.config.hide_dock_icon) ?? false);
    const useTerminal = (useAppSelector(state => state.config.start_via_terminal) ?? false);
    return (
        <section>
            <Stack direction='column' p={5}>
                <Text fontSize='2xl'>Features</Text>
                <Divider orientation='horizontal' />
                <Spacer />
                <PrivateApiField />
                <Spacer />
                <AutoCaffeinateField />
                <Spacer />
                <AutoStartField />
                <Spacer />

                <FormControl>
                    <Checkbox id='hide_dock_icon' isChecked={hideDockIcon} onChange={onCheckboxToggle}>Hide Dock Icon</Checkbox>
                    <FormHelperText>
                        Hiding the dock icon will not close the app. You can open the app again via the status bar icon.
                    </FormHelperText>
                </FormControl>

                <Spacer />
                <Accordion allowMultiple>
                    <AccordionItem>
                        <AccordionButton>
                            <Box flex='1' textAlign='left' width="15em">
                                Advanced Feature Settings
                            </Box>
                            <AccordionIcon />
                        </AccordionButton>
                        <AccordionPanel pb={4}>
                            <FormControl>
                                <Checkbox id='start_via_terminal' isChecked={useTerminal} onChange={onCheckboxToggle}>Always Start via Terminal</Checkbox>
                                <FormHelperText>
                                    When BlueBubbles starts up, it will auto-reload itself in terminal mode.
                                    When in terminal, type "help" for command information.
                                </FormHelperText>
                            </FormControl>
                        </AccordionPanel>
                    </AccordionItem>
                </Accordion>
            </Stack>
        </section>
    );
}
Example #15
Source File: ControlAttendeeEdit.tsx    From takeout-app with MIT License 5 votes vote down vote up
ControlAttendeeEdit: React.FC<Props> = () => {
  const match = useRouteMatch<{ id: string }>();
  const id = parseInt(match.params.id, 10);
  const { data } = ControlApi.useAttendee(id);
  const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
  const [isRequesting, setIsRequesting] = React.useState<boolean>(false);
  const { register, handleSubmit, reset } = useForm<ControlUpdateAttendeeRequestAttendee>({
    defaultValues: {
      name: React.useMemo(() => data?.attendee?.name, [data]),
      is_staff: React.useMemo(() => data?.attendee?.is_staff, [data]),
      is_speaker: React.useMemo(() => data?.attendee?.is_speaker, [data]),
      is_committer: React.useMemo(() => data?.attendee?.is_committer, [data]),
      presentation_slugs: React.useMemo(() => data?.attendee?.presentation_slugs || [], [data]),
    },
  });

  const onSubmit = handleSubmit(async (data) => {
    if (isRequesting) return;
    setIsRequesting(true);
    try {
      await ControlApi.updateAttendee(id, data);
      setErrorAlert(null);
    } catch (e) {
      setErrorAlert(
        <Box my={2}>
          <ErrorAlert error={e} />
        </Box>,
      );
    }
    setIsRequesting(false);
  });

  React.useEffect(() => {
    if (data) reset(data.attendee);
  }, [data]);

  if (!data) return <p>Loading</p>;

  // TODO: link to registration page and support email
  return (
    <>
      {errorAlert}
      <Container mt="20px">
        <form onSubmit={onSubmit}>
          <Text>
            <Link href={data.ticket.admin_url} isExternal textDecoration="underline">
              {data.ticket.reference}
            </Link>
          </Text>
          <FormControl mt={4} id="attendee__name" isRequired>
            <FormLabel>Name</FormLabel>
            <Input {...register("name")} />
          </FormControl>
          <FormControl mt={4} id="attendee__staff" isRequired>
            <FormLabel>Staff</FormLabel>
            <Checkbox {...register("is_staff")} />
          </FormControl>
          <FormControl mt={4} id="attendee__speaker" isRequired>
            <FormLabel>Speaker</FormLabel>
            <Checkbox {...register("is_speaker")} />
          </FormControl>
          <FormControl mt={4} id="attendee__committer" isRequired>
            <FormLabel>Committer</FormLabel>
            <Checkbox {...register("is_committer")} />
          </FormControl>
          <FormControl mt={4} id="attendee__presentation_slugs">
            <FormLabel>Presentation Slugs</FormLabel>
            <Input {...register("presentation_slugs.0")} />
          </FormControl>

          <Button mt={4} size="lg" type="submit" isLoading={isRequesting}>
            Save
          </Button>
        </form>
      </Container>
    </>
  );
}
Example #16
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaArray: React.FunctionComponent<SchemaArrayProps> = (
	props: React.PropsWithChildren<SchemaArrayProps>
) => {
	const { schemaState, isReadOnly } = props;

	const state = useState(schemaState.items as JSONSchema7);
	const isReadOnlyState = useState(isReadOnly);

	const { length } = state.path.filter((name) => name !== "properties");
	const tagPaddingLeftStyle = {
		paddingLeft: `${20 * (length + 1)}px`,
	};

	const onCloseAdvanced = (): void => {
		localState.isAdvancedOpen.set(false);
	};

	const showadvanced = (): void => {
		localState.isAdvancedOpen.set(true);
	};

	const focusRef = React.createRef<HTMLElement>();

	const localState = useState({
		isAdvancedOpen: false,
	});

	return (
		<>
			<Flex
				direction="row"
				wrap="nowrap"
				className="array-item"
				mt={2}
				mr={5}
				style={tagPaddingLeftStyle}
			>
				<Input
					key="Items"
					isDisabled
					value="Items"
					size="sm"
					flexShrink={1}
					margin={2}
					variant="outline"
				/>
				<Checkbox isDisabled margin={2} colorScheme="blue" />
				<Select
					variant="outline"
					isDisabled={isReadOnlyState.value}
					value={state.type.value as JSONSchema7TypeName}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						state.set(newSchema as JSONSchema7);
					}}
				>
					{SchemaTypes.map((item, index) => {
						return (
							<option key={String(index)} value={item}>
								{item}
							</option>
						);
					})}
				</Select>
				<Input
					value={state.title.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.title.set(evt.target.value);
					}}
				/>
				<Input
					value={state.description.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.description.set(evt.target.value);
					}}
				/>
				<Tooltip
					hasArrow
					aria-label="Advanced Settings"
					label="Advanced Settings"
					placement="top"
				>
					<IconButton
						isRound
						isDisabled={isReadOnlyState.value}
						size="sm"
						mt={2}
						mb={2}
						ml={1}
						variant="link"
						colorScheme="blue"
						fontSize="16px"
						icon={<FiSettings />}
						aria-label="Advanced Settings"
						onClick={() => {
							showadvanced();
						}}
					/>
				</Tooltip>

				{state.type.value === "object" && (
					<Tooltip
						hasArrow
						aria-label="Add Child Node"
						label="Add Child Node"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							mr={2}
							variant="link"
							colorScheme="green"
							fontSize="16px"
							icon={<IoIosAddCircleOutline />}
							aria-label="Add Child Node"
							onClick={() => {
								const fieldName = `field_${random()}`;
								(state.properties as State<{
									[key: string]: JSONSchema7;
								}>)[fieldName].set(getDefaultSchema(DataType.string));
							}}
						/>
					</Tooltip>
				)}
			</Flex>
			{state.type?.value === "object" && (
				<SchemaObject isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			{state.type?.value === "array" && (
				<SchemaArray isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			<Modal
				isOpen={localState.isAdvancedOpen.get()}
				finalFocusRef={focusRef}
				size="lg"
				onClose={onCloseAdvanced}
			>
				<ModalOverlay />
				<ModalContent>
					<ModalHeader textAlign="center">Advanced Schema Settings</ModalHeader>

					<ModalBody>
						<AdvancedSettings itemStateProp={state} />
					</ModalBody>

					<ModalFooter>
						<Button
							colorScheme="blue"
							variant="ghost"
							mr={3}
							onClick={onCloseAdvanced}
						>
							Close
						</Button>
					</ModalFooter>
				</ModalContent>
			</Modal>
		</>
	);
}
Example #17
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaItem: React.FunctionComponent<SchemaItemProps> = (
	props: React.PropsWithChildren<SchemaItemProps>
) => {
	const {
		name,
		itemStateProp,
		showadvanced,
		required,
		parentStateProp,
		isReadOnly,
	} = props;

	// const itemState = useState(itemStateProp);
	const parentState = useState(parentStateProp);
	const parentStateOrNull: State<JSONSchema7> | undefined = parentState.ornull;
	const propertiesOrNull:
		| State<{
				[key: string]: JSONSchema7Definition;
		  }>
		| undefined = parentStateOrNull.properties.ornull;

	const nameState = useState(name);
	const isReadOnlyState = useState(isReadOnly);

	const itemState = useState(
		(parentStateProp.properties as State<{
			[key: string]: JSONSchema7;
		}>).nested(nameState.value)
	);

	const { length } = parentState.path.filter((name) => name !== "properties");
	const tagPaddingLeftStyle = {
		paddingLeft: `${20 * (length + 1)}px`,
	};

	const isRequired = required
		? required.length > 0 && required.includes(name)
		: false;
	const toast = useToast();

	// Debounce callback
	const debounced = useDebouncedCallback(
		// function
		(newValue: string) => {
			// Todo: make toast for duplicate properties
			if (propertiesOrNull && propertiesOrNull[newValue].value) {
				toast({
					title: "Duplicate Property",
					description: "Property already exists!",
					status: "error",
					duration: 1000,
					isClosable: true,
					position: "top",
				});
			} else {
				const oldName = name;
				const proptoupdate = newValue;

				const newobj = renameKeys(
					{ [oldName]: proptoupdate },
					parentState.properties.value
				);
				parentStateOrNull.properties.set(JSON.parse(JSON.stringify(newobj)));
			}
		},
		// delay in ms
		1000
	);

	if (!itemState.value) {
		return <></>;
	}

	return (
		<div>
			<Flex
				alignContent="space-evenly"
				direction="row"
				wrap="nowrap"
				className="schema-item"
				style={tagPaddingLeftStyle}
			>
				<Input
					isDisabled={isReadOnlyState.value}
					defaultValue={nameState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Enter property name"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						debounced(evt.target.value);
					}}
				/>
				<Checkbox
					isDisabled={isReadOnlyState.value}
					isChecked={isRequired}
					margin={2}
					colorScheme="blue"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						if (!evt.target.checked && required.includes(name)) {
							(parentState.required as State<string[]>)[
								required.indexOf(name)
							].set(none);
						} else {
							parentState.required.merge([name]);
						}
					}}
				/>
				<Select
					isDisabled={false}
					variant="outline"
					value={itemState.type.value}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						itemState.set(newSchema as JSONSchema7);
					}}
				>
					{SchemaTypes.map((item, index) => {
						return (
							<option key={String(index)} value={item}>
								{item}
							</option>
						);
					})}
				</Select>
				<Input
					isDisabled={isReadOnlyState.value}
					value={itemState.title.value || ""}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.title.set(evt.target.value);
					}}
				/>
				<Input
					isDisabled={isReadOnlyState.value}
					value={itemState.description.value || ""}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.description.set(evt.target.value);
					}}
				/>

				{itemState.type.value !== "object" && itemState.type.value !== "array" && (
					<Tooltip
						hasArrow
						aria-label="Advanced Settings"
						label="Advanced Settings"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							ml={1}
							variant="link"
							colorScheme="blue"
							fontSize="16px"
							icon={<FiSettings />}
							aria-label="Advanced Settings"
							onClick={() => {
								showadvanced(name);
							}}
						/>
					</Tooltip>
				)}

				<Tooltip
					hasArrow
					aria-label="Remove Node"
					label="Remove Node"
					placement="top"
				>
					<IconButton
						isRound
						isDisabled={isReadOnlyState.value}
						size="sm"
						mt={2}
						mb={2}
						ml={1}
						variant="link"
						colorScheme="red"
						fontSize="16px"
						icon={<AiOutlineDelete />}
						aria-label="Remove Node"
						onClick={() => {
							const updatedState = deleteKey(
								nameState.value,
								JSON.parse(JSON.stringify(parentState.properties.value))
							);
							parentState.properties.set(updatedState);
						}}
					/>
				</Tooltip>

				{itemState.type?.value === "object" ? (
					<DropPlus
						isDisabled={isReadOnlyState.value}
						parentStateProp={parentState}
						itemStateProp={itemStateProp}
					/>
				) : (
					<Tooltip
						hasArrow
						aria-label="Add Sibling Node"
						label="Add Sibling Node"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							mr={2}
							variant="link"
							colorScheme="green"
							fontSize="16px"
							icon={<IoIosAddCircleOutline />}
							aria-label="Add Sibling Node"
							onClick={() => {
								if (propertiesOrNull) {
									const fieldName = `field_${random()}`;
									propertiesOrNull
										?.nested(fieldName)
										.set(getDefaultSchema(DataType.string) as JSONSchema7);
								}
							}}
						/>
					</Tooltip>
				)}
			</Flex>
			{itemState.type?.value === "object" && (
				<SchemaObject isReadOnly={isReadOnlyState} schemaState={itemState} />
			)}
			{itemState.type?.value === "array" && (
				<SchemaArray isReadOnly={isReadOnlyState} schemaState={itemState} />
			)}
		</div>
	);
}
Example #18
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaRoot: React.FunctionComponent<SchemaArrayProps> = (
	props: React.PropsWithChildren<SchemaArrayProps>
) => {
	const state = useState(props.schemaState);
	const isReadOnlyState = useState(props.isReadOnly);

	return (
		<>
			{props.onSchemaChange(JSON.stringify(state.value))}
			<Flex
				data-testid="jsonschema-editor"
				direction="row"
				wrap="nowrap"
				size="sm"
				mt={2}
				mr={5}
			>
				<Input isDisabled placeholder="root" margin={2} variant="outline" />
				<Tooltip
					hasArrow
					aria-label="All Required"
					label="All Required"
					placement="top"
				>
					<Checkbox
						isDisabled={isReadOnlyState.value}
						margin={2}
						width={20}
						colorScheme="blue"
					/>
				</Tooltip>

				<Select
					variant="outline"
					isDisabled={isReadOnlyState.value}
					value={state.type.value ?? ""}
					size="sm"
					margin={2}
					placeholder="Choose root data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						state.set(newSchema as JSONSchema7);
					}}
				>
					<option key="object" value="object">
						object
					</option>
					<option key="array" value="array">
						array
					</option>
				</Select>
				<Input
					value={state.value?.title ?? ""}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.title.set(evt.target.value);
					}}
				/>
				<Input
					value={state.value?.description ?? ""}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.description.set(evt.target.value);
					}}
				/>

				{state.value?.type === "object" && (
					<>
						<Tooltip
							hasArrow
							aria-label="Add Child Node"
							label="Add Child Node"
							placement="top"
						>
							<IconButton
								isRound
								isDisabled={isReadOnlyState.value}
								size="sm"
								mt={2}
								mb={2}
								mr={2}
								variant="link"
								colorScheme="green"
								fontSize="16px"
								icon={<IoIosAddCircleOutline />}
								aria-label="Add Child Node"
								onClick={() => {
									const fieldName = `field_${random()}`;
									(state.properties as State<{
										[key: string]: JSONSchema7;
									}>)[fieldName].set(getDefaultSchema(DataType.string));
								}}
							/>
						</Tooltip>
					</>
				)}
			</Flex>
		</>
	);
}
Example #19
Source File: FusePoolCreatePage.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
PoolConfiguration = () => {
  const { t } = useTranslation();
  const toast = useToast();
  const { fuse, address } = useRari();
  const navigate = useNavigate();

  const { isOpen, onOpen, onClose } = useDisclosure();

  const [name, setName] = useState("");
  const [isWhitelisted, setIsWhitelisted] = useState(false);
  const [whitelist, setWhitelist] = useState<string[]>([]);

  const [closeFactor, setCloseFactor] = useState(50);
  const [liquidationIncentive, setLiquidationIncentive] = useState(8);

  const [isUsingMPO, setIsUsingMPO] = useState(true)
  const [customOracleAddress, setCustomOracleAddress] = useState('')

  const [isCreating, setIsCreating] = useState(false);

  const [activeStep, setActiveStep] = useState<number>(0);

  const increaseActiveStep = (step: string) => {
    setActiveStep(steps.indexOf(step));
  };

  const [needsRetry, setNeedsRetry] = useState<boolean>(false);
  const [retryFlag, setRetryFlag] = useState<number>(1);

  const [deployedPriceOracle, setDeployedPriceOracle] = useState<string>("");

  const postDeploymentHandle = (priceOracle: string) => {
    setDeployedPriceOracle(priceOracle);
  };

  const deployPool = async (
    bigCloseFactor: string,
    bigLiquidationIncentive: string,
    options: any,
    priceOracle: string
  ) => {
    const [poolAddress] = await fuse.deployPool(
      name,
      isWhitelisted,
      bigCloseFactor,
      
      bigLiquidationIncentive,
      priceOracle,
      {},
      options,
      isWhitelisted ? whitelist : null
    );

    return poolAddress;
  };

  const onDeploy = async () => {
    let priceOracle = deployedPriceOracle;

    if (name === "") {
      toast({
        title: "Error!",
        description: "You must specify a name for your Fuse pool!",
        status: "error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      });

      return;
    }

    if (isWhitelisted && whitelist.length < 2 ) {
      toast({
        title: "Error!",
        description: "You must add an address to your whitelist!",
        status:"error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      })

      return
    }

    if (!isUsingMPO && !fuse.web3.utils.isAddress(customOracleAddress)) {
      
      toast({
        title: "Error!",
        description: "You must add an address for your oracle or use the default oracle.",
        status:"error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      })

      return
  }


    setIsCreating(true);
    onOpen();

    // 50% -> 0.5 * 1e18
    const bigCloseFactor = new BigNumber(closeFactor)
      .dividedBy(100)
      .multipliedBy(1e18)
      .toFixed(0);

    // 8% -> 1.08 * 1e8
    const bigLiquidationIncentive = new BigNumber(liquidationIncentive)
      .dividedBy(100)
      .plus(1)
      .multipliedBy(1e18)
      .toFixed(0);

    let _retryFlag = retryFlag;

    try {
      const options = { from: address };

      setNeedsRetry(false);

      if (!isUsingMPO && _retryFlag === 1) {
        _retryFlag = 2;
        priceOracle = customOracleAddress
      }

      if (_retryFlag === 1) {
        priceOracle = await fuse.deployPriceOracle(
          "MasterPriceOracle",
          {
            underlyings: [],
            oracles: [],
            canAdminOverwrite: true,
            defaultOracle:
              Fuse.PUBLIC_PRICE_ORACLE_CONTRACT_ADDRESSES.MasterPriceOracle, // We give the MasterPriceOracle a default "fallback" oracle of the Rari MasterPriceOracle
          },
          options
        );
        postDeploymentHandle(priceOracle);
        increaseActiveStep("Deploying Pool!");
        _retryFlag = 2;
      }

      let poolAddress: string;

      if (_retryFlag === 2) {
        poolAddress = await deployPool(
          bigCloseFactor,
          bigLiquidationIncentive,
          options,
          priceOracle
        );

        const event = (
          await fuse.contracts.FusePoolDirectory.getPastEvents(
            "PoolRegistered",
            {
              fromBlock: (await fuse.web3.eth.getBlockNumber()) - 10,
              toBlock: "latest",
            }
          )
        ).filter(
          (event) =>
            event.returnValues.pool.comptroller.toLowerCase() ===
            poolAddress.toLowerCase()
        )[0];

        LogRocket.track("Fuse-CreatePool");

        toast({
          title: "Your pool has been deployed!",
          description: "You may now add assets to it.",
          status: "success",
          duration: 2000,
          isClosable: true,
          position: "top-right",
        });

        let id = event.returnValues.index;
        onClose();
        navigate(`/fuse/pool/${id}/edit`);
      }
    } catch (e) {
      handleGenericError(e, toast);
      setRetryFlag(_retryFlag);
      setNeedsRetry(true);
    }
  };

  return (
    <>
      <TransactionStepperModal
        handleRetry={onDeploy}
        needsRetry={needsRetry}
        activeStep={activeStep}
        isOpen={isOpen}
        onClose={onClose}
      />
      <DashboardBox width="100%" mt={4}>
        <Column mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
          <Heading size="sm" px={4} py={4}>
            {t("Create Pool")}
          </Heading>

          <ModalDivider />

          <OptionRow>
            <Text fontWeight="bold" mr={4}>
              {t("Name")}
            </Text>
            <Input
              width="20%"
              value={name}
              onChange={(event) => setName(event.target.value)}
            />
          </OptionRow>

          <ModalDivider />

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "If enabled you will be able to limit the ability to supply to the pool to a select group of addresses. The pool will not show up on the 'all pools' list."
              )}
            >
              <Text fontWeight="bold">
                {t("Whitelisted")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <Switch
              h="20px"
              isChecked={isWhitelisted}
              onChange={() => {
                setIsWhitelisted((past) => !past);
                // Add the user to the whitelist by default
                if (whitelist.length === 0) {
                  setWhitelist([address]);
                }
              }}
              className="black-switch"
              colorScheme="#121212"
            />
          </OptionRow>

          {isWhitelisted ? (
            <WhitelistInfo
              whitelist={whitelist}
              addToWhitelist={(user) => {
                setWhitelist((past) => [...past, user]);
              }}
              removeFromWhitelist={(user) => {
                setWhitelist((past) =>
                  past.filter(function (item) {
                    return item !== user;
                  })
                );
              }}
            />
          ) : null}

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing. Compound's close factor is 50%."
              )}
            >
              <Text fontWeight="bold">
                {t("Close Factor")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <SliderWithLabel
              value={closeFactor}
              setValue={setCloseFactor}
              formatValue={formatPercentage}
              min={5}
              max={90}
            />
          </OptionRow>

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. For example, if the liquidation incentive is 10%, liquidators receive an extra 10% of the borrowers collateral for every unit they close. Compound's liquidation incentive is 8%."
              )}
            >
              <Text fontWeight="bold">
                {t("Liquidation Incentive")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <SliderWithLabel
              value={liquidationIncentive}
              setValue={setLiquidationIncentive}
              formatValue={formatPercentage}
              min={0}
              max={50}
            />
          </OptionRow>

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "We will deploy a price oracle for your pool. This price oracle will contain price feeds for popular ERC20 tokens."
              )}
            >
              <Text fontWeight="bold">
                {isUsingMPO ? t("Default Price Oracle") : t("Custom Price Oracle")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <Box display="flex" alignItems='flex-end' flexDirection="column"> 
              <Checkbox
                isChecked={isUsingMPO}
                onChange={(e) => setIsUsingMPO(!isUsingMPO)}
                marginBottom={3}
              />
              {
                !isUsingMPO ? (
                  <>
                  <Input 
                    value={customOracleAddress}
                    onChange={(e) => setCustomOracleAddress(e.target.value)}
                  />
                  <Text mt={3} opacity="0.6" fontSize="sm">
                    Please make sure you know what you're doing.
                  </Text>
                  </>
                ) 
                : null
              }
              
            </Box>
          </OptionRow>
        </Column>
      </DashboardBox>

      <DashboardBox
        width="100%"
        height="60px"
        mt={4}
        py={3}
        fontSize="xl"
        as="button"
        onClick={useAuthedCallback(onDeploy)}
      >
        <Center expand fontWeight="bold">
          {isCreating ? <Spinner /> : t("Create")}
        </Center>
      </DashboardBox>
    </>
  );
}
Example #20
Source File: UniswapV2OrSushiPriceOracleConfigurator.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
UniswapV2OrSushiPriceOracleConfigurator = ({
  type,
}: {
  // Asset's Address. i.e DAI, USDC

  // Either SushiSwap or Uniswap V2
  type: string;
}) => {
  const { t } = useTranslation();

  // This will be used to index whitelistPools array (fetched from the graph.)
  // It also helps us know if user has selected anything or not. If they have, detail fields are shown.
  const [activePool, setActivePair] = useState<string>("");

  // Checks if user has started the TWAP bot.
  const [checked, setChecked] = useState<boolean>(false);

  // Will store oracle response. This helps us know if its safe to add it to Master Price Oracle
  const [checkedStepTwo, setCheckedStepTwo] = useState<boolean>(false);

  const { tokenAddress, setOracleAddress, setUniV3BaseTokenAddress } =
    useAddAssetContext();

  // Get pair options from sushiswap and uniswap
  const { SushiPairs, SushiError, UniV2Pairs, univ2Error } =
    useSushiOrUniswapV2Pairs(tokenAddress);

  // This is where we conditionally store data depending on type.
  // Uniswap V2 or SushiSwap
  const Pairs = type === "UniswapV2" ? UniV2Pairs : SushiPairs;
  const Error = type === "UniswapV2" ? univ2Error : SushiError;

  // Will update active pair, set oracle address and base token.
  const updateInfo = (value: string) => {
    const pair = Pairs[value];
    setActivePair(value);
    setOracleAddress(pair.id);
    setUniV3BaseTokenAddress(
      pair.token1.id === tokenAddress ? pair.token0.id : pair.token1.id
    );
  };

  // If pairs are still being fetched, if theres and error or if there are none, return nothing.
  if (Pairs === undefined || Error || Pairs === null) return null;

  return (
    <>
      <Row
        crossAxisAlignment="center"
        mainAxisAlignment="space-between"
        width="260px"
        my={3}
      >
        <Checkbox isChecked={checked} onChange={() => setChecked(!checked)}>
          <Text fontSize="xs" align="center">
            Using this type of oracle requires you to run a TWAP bot.
          </Text>
        </Checkbox>
      </Row>

      {checked ? (
        <Row
          crossAxisAlignment="center"
          mainAxisAlignment="space-between"
          width="260px"
          my={3}
        >
          <Button colorScheme="teal">Check</Button>

          <Text fontSize="xs" align="center">
            After deploying your oracle, you have to wait about 15 - 25 minutes
            for the oracle to be set.
          </Text>
        </Row>
      ) : null}

      {true ? (
        <Row
          crossAxisAlignment="center"
          mainAxisAlignment="space-between"
          width="260px"
          my={2}
        >
          <SimpleTooltip
            label={t(
              "This field will determine which pool your oracle reads from. Its safer with more liquidity."
            )}
          >
            <Text fontWeight="bold">
              {t("Pool:")} <QuestionIcon ml={1} mb="4px" />
            </Text>
          </SimpleTooltip>
          <Select
            {...DASHBOARD_BOX_PROPS}
            ml={2}
            mb={2}
            borderRadius="7px"
            _focus={{ outline: "none" }}
            width="180px"
            placeholder={
              activePool.length === 0 ? t("Choose Pool") : activePool
            }
            value={activePool}
            disabled={!checked}
            onChange={(event) => {
              updateInfo(event.target.value);
            }}
          >
            {typeof Pairs !== undefined
              ? Object.entries(Pairs).map(([key, value]: any[]) =>
                  value.totalSupply !== null &&
                  value.totalSupply !== undefined &&
                  value.totalSupply >= 100 ? (
                    <option
                      className="black-bg-option"
                      value={key}
                      key={value.id}
                    >
                      {`${value.token0.symbol} / ${
                        value.token1.symbol
                      } (${shortUsdFormatter(value.totalSupply)})`}
                    </option>
                  ) : null
                )
              : null}
          </Select>
        </Row>
      ) : null}

      {activePool.length > 0 ? (
        <Row
          crossAxisAlignment="center"
          mainAxisAlignment="space-between"
          width="260px"
          my={2}
        >
          <SimpleTooltip label={t("TVL in pool as of this moment.")}>
            <Text fontWeight="bold">
              {t("Liquidity:")} <QuestionIcon ml={1} mb="4px" />
            </Text>
          </SimpleTooltip>
          <h1>
            {activePool !== ""
              ? smallUsdFormatter(Pairs[activePool].totalSupply)
              : null}
          </h1>
        </Row>
      ) : null}
    </>
  );
}
Example #21
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
AdvancedString: React.FunctionComponent<AdvancedItemStateProps> = (
	props: React.PropsWithChildren<AdvancedItemStateProps>
) => {
	const { itemStateProp } = props;

	const changeEnumOtherValue = (value: string): string[] | null => {
		const array = value.split("\n");
		if (array.length === 0 || (array.length === 1 && !array[0])) {
			return null;
		}

		return array;
	};

	const itemState = useState(itemStateProp);

	const isEnumChecked = (itemState.value as JSONSchema7).enum !== undefined;
	const enumData = (itemState.value as JSONSchema7).enum
		? (itemState.enum.value as string[])
		: [];
	const enumValue = enumData?.join("\n");

	return (
		<Flex direction="column" wrap="nowrap">
			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Default: </FormLabel>
				<Input
					id="default"
					placeholder="Default value"
					value={(itemState.default.value as string) ?? ""}
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.default.set(evt.target.value);
					}}
				/>
			</Stack>

			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Min Length: </FormLabel>
				<NumberInput
					size="sm"
					defaultValue={Number(itemState.minLength.value)}
					onChange={(value: number | string) => {
						itemState.minLength.set(Number(value));
					}}
				>
					<NumberInputField value={Number(itemState.minLength.value)} />
					<NumberInputStepper>
						<NumberIncrementStepper />
						<NumberDecrementStepper />
					</NumberInputStepper>
				</NumberInput>
				<FormLabel mr={2}>Max Length: </FormLabel>
				<NumberInput
					size="sm"
					defaultValue={Number(itemState.maxLength.value)}
					onChange={(value: number | string) => {
						itemState.maxLength.set(Number(value));
					}}
				>
					<NumberInputField value={Number(itemState.maxLength.value)} />
					<NumberInputStepper>
						<NumberIncrementStepper />
						<NumberDecrementStepper />
					</NumberInputStepper>
				</NumberInput>
			</Stack>
			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2} htmlFor="pattern">
					Pattern:{" "}
				</FormLabel>
				<Input
					id="pattern"
					placeholder="MUST be a valid regular expression."
					value={itemState.pattern.value ?? ""}
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						itemState.pattern.set(evt.target.value);
					}}
				/>
			</Stack>

			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Enum: </FormLabel>
				<Checkbox
					isChecked={isEnumChecked}
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						if (!evt.target.checked) {
							itemState.enum.set(none);
						} else {
							itemState.enum.set(Array<string>());
						}
					}}
				/>
				<Textarea
					value={enumValue || ""}
					isDisabled={!isEnumChecked}
					placeholder="ENUM Values - One Entry Per Line"
					onChange={(evt: React.ChangeEvent<HTMLTextAreaElement>) => {
						const update = changeEnumOtherValue(evt.target.value);
						if (update === null) {
							itemState.enum.set(none);
						} else {
							itemState.enum.set(update as string[]);
						}
					}}
				/>
			</Stack>
			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2} htmlFor="format">
					Format:{" "}
				</FormLabel>
				<Select
					variant="outline"
					value={itemState.format.value ?? ""}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						if (evt.target.value === "") {
							itemState.format.set(none);
						} else {
							itemState.format.set(evt.target.value);
						}
					}}
				>
					{StringFormat.map((item, index) => {
						return (
							<option key={String(index)} value={item.name}>
								{item.name}
							</option>
						);
					})}
				</Select>
			</Stack>
		</Flex>
	);
}
Example #22
Source File: NameControls.tsx    From dope-monorepo with GNU General Public License v3.0 4 votes vote down vote up
NameControls = ({
  config,
  setHustlerConfig,
  enableNameVisible = false,
}: ConfigureHustlerProps & { enableNameVisible?: boolean }) => {
  const [errorName, setErrorName] = useState<string | undefined>(undefined);
  const [hustlerName, setHustlerName] = useState(config.name ?? '');
  const [nameFieldDirty, setNameFieldDirty] = useState(false);
  const debouncedHustlerName = useDebounce<string>(hustlerName, 250);

  const validateName = (value: string) => {
    if (!value) {
      setErrorName('Name is required');
    } else if (value.length > NAME_MAX_LENGTH) {
      setErrorName('Name too long');
    }
  };

  useEffect(() => {
    // Set from typing
    if (nameFieldDirty && config.name !== debouncedHustlerName) {
      setHustlerConfig({ ...config, name: debouncedHustlerName });
      setNameFieldDirty(false);
      // Set from randomize or external change
    } else if (!nameFieldDirty && config.name !== debouncedHustlerName) {
      setHustlerName(config.name ?? '');
    }
  }, [debouncedHustlerName, config, nameFieldDirty, setHustlerConfig]);

  return (
    <div>
      <Stack spacing={FIELD_SPACING} borderBottom="1px solid #EFEFEF" paddingBottom="16px">
        <FormLabel htmlFor="name" color="#000" padding="0" fontSize="14px">
          Name
        </FormLabel>
        <HStack
          display="flex"
          alignItems="center"
          css={css`
            margin-top: unset !important;
          `}
        >
          <FormControl width="70%" mr="27px">
            <Input
              id="name"
              placeholder="name"
              maxLength={NAME_MAX_LENGTH}
              value={hustlerName}
              border="2px"
              fontSize="14px"
              paddingX="14px"
              paddingY="10px"
              rounded="unset"
              onChange={e => {
                setNameFieldDirty(true);
                validateName(e.target.value);
                setHustlerName(e.currentTarget.value);
              }}
            />
            {errorName && <FormErrorMessage>{errorName}</FormErrorMessage>}
          </FormControl>
          <FormControl display="flex" alignItems="center" width="30%">
            {enableNameVisible && (
              <>
                <Checkbox
                  id="render-name"
                  isChecked={config.renderName ?? false}
                  onChange={e => setHustlerConfig({ ...config, renderName: e.target.checked })}
                  colorScheme="whiteAlpha"
                  iconColor="black"
                  borderRadius="10px"
                  sx={{
                    borderColor: '#000',
                    '[data-checked][data-hover]': {
                      borderColor: '#000',
                    },
                    '[data-checked]': {
                      borderColor: '#000 !important',
                    },
                  }}
                />
                <FormLabel htmlFor="render-name" ml="2" mt="2" color="#000">
                  Visible
                </FormLabel>
              </>
            )}
          </FormControl>
        </HStack>
      </Stack>
    </div>
  );
}
Example #23
Source File: index.tsx    From dope-monorepo with GNU General Public License v3.0 4 votes vote down vote up
HustlersPanel = (props: { hustlers: Hustler[] }) => {
    const hustlers = props.hustlers;

    return (
        <Accordion allowToggle>
            {hustlers.map((hustler, i) => 
                <AccordionItem key={i}>
                    <h2>
                        <AccordionButton>
                            <Box flex='1' textAlign='left'>
                                {hustler.name}: {hustler.hustlerId ?? 'No Hustler'}
                                <br/>
                                Citizen: {hustler instanceof Citizen ? '✅' : '❌'}
                            </Box>
                            <AccordionIcon />
                        </AccordionButton>
                    </h2>
                    <AccordionPanel pb={4}>
                        <InputGroup size="sm">
                            <InputLeftAddon children='Name' />
                            <Input onChange={(e) => hustler.name = e.target.value} placeholder={hustler.name} />
                        </InputGroup>
                        <div>
                        <Position object={hustler} />
                        </div>
                        <br />
                        <Accordion allowToggle>
                            {hustler instanceof Citizen ? <div>
                                <AccordionItem>
                                <h2>
                                    <AccordionButton>
                                        <Box flex='1' textAlign='left'>
                                            Path
                                        </Box>
                                        <AccordionIcon />
                                    </AccordionButton>
                                </h2>
                                <AccordionPanel pb={4}>
                                        Repeat path:
                                        <Checkbox defaultChecked={hustler.repeatPath} onChange={(e) => hustler.repeatPath = e.target.checked} />
                                        <br />
                                        Follow path:
                                        <Checkbox defaultChecked={hustler.shouldFollowPath} onChange={(e) => hustler.shouldFollowPath = e.target.checked} />
                                        <br />
                                        <br />
                                        {
                                            hustler.path.map((p, i) => 
                                                <div key={i}>
                                                    PathPoint #{i}
                                                    <Position object={p.position} />
                                                    <br />
                                                </div>
                                            )
                                        }
                                </AccordionPanel>
                            </AccordionItem>
                            <AccordionItem>
                                <h2>
                                    <AccordionButton>
                                        <Box flex='1' textAlign='left'>
                                            Conversations
                                        </Box>
                                        <AccordionIcon />
                                    </AccordionButton>
                                </h2>
                                <AccordionPanel pb={4}>
                                        {
                                            hustler.conversations.map((c, i) => 
                                                <div key={i}>
                                                    <Accordion>
                                                        {
                                                            c.texts.map((t, i) =>
                                                                <AccordionItem key={i}>
                                                                    <h2>
                                                                        <AccordionButton>
                                                                            <Box flex='1' textAlign='left'>
                                                                                {t.text}
                                                                            </Box>
                                                                            <AccordionIcon />
                                                                        </AccordionButton>
                                                                    </h2>
                                                                    <AccordionPanel pb={4}>
                                                                        <InputGroup size="sm">
                                                                            <InputLeftAddon children='Text' />
                                                                            <Input onChange={(e) => t.text = e.target.value} placeholder={t.text} />
                                                                        </InputGroup>
                                                                        <Text>
                                                                            Choices
                                                                        </Text>
                                                                        {
                                                                            t.choices ? t.choices.map((c, i) =>
                                                                                <div key={i}>
                                                                                    <InputGroup size="sm">
                                                                                        <InputLeftAddon children='Text' />
                                                                                        <Input onChange={(e) => (t.choices!)[i] = e.target.value} placeholder={c} />
                                                                                    </InputGroup>
                                                                                </div>
                                                                            ) : undefined
                                                                        }
                                                                    </AccordionPanel>
                                                                </AccordionItem>
                                                            )
                                                        }
                                                    </Accordion>
                                                </div>
                                            )
                                        }
                                </AccordionPanel>
                            </AccordionItem>
                            </div> : undefined}
                        </Accordion>
                    </AccordionPanel>
                </AccordionItem>
            )}
        </Accordion>
        
    )
}
Example #24
Source File: index.tsx    From dope-monorepo with GNU General Public License v3.0 4 votes vote down vote up
LightsPanel = (props: { player: Player, lights: Phaser.GameObjects.LightsManager }) => {
    const [, forceUpdate] = useReducer(x => x + 1, 0);
    
    const player = props.player;
    const lights = props.lights;

    return (
        <>
            <div style={{
                paddingLeft: '1rem',
            }}>
                Enabled: <Checkbox onChange={(e) => lights.active = e.target.checked} defaultChecked={lights.active}/>
                <br/>
                Number of lights: {lights.getLightCount()}
                <br/>
                Ambient color:
                <input 
                    type="color" 
                    onChange={(e) => {
                        const value = e.target.value;
                        const color = value.substring(1);
                        const r = parseInt(color.substring(0, 2), 16) / 255;
                        const g = parseInt(color.substring(2, 4), 16) / 255;
                        const b = parseInt(color.substring(4, 6), 16) / 255;
                        lights.ambientColor.set(r, g, b);
                    }}
                    defaultValue={'#' + 
                        (lights.ambientColor.r * 255).toString(16) + 
                        (lights.ambientColor.g * 255).toString(16) + 
                        (lights.ambientColor.b * 255).toString(16)}
                />
                <br/>
                <br />
                <Button onClick={(e) => {
                    lights.addLight(player.x, player.y);
                    forceUpdate();
                }}>
                    Add light
                </Button>
                <br />
                <Button onClick={(e) => {
                    let layer: Phaser.GameObjects.Layer;
                    if (!(layer = (lights as any).pointLightLayer))
                        layer = (lights as any).pointLightLayer = player.scene.add.layer();
                    layer.add(lights.addPointLight(player.x, player.y));
                    forceUpdate();
                }}>
                    Add pointlight
                </Button>
            </div>
            <br/>
            <Accordion defaultIndex={0}>
                {
                    // getLights doesnt actually return an array of the lights... it returns an object with the dist and light
                    lights.getLights(player.scene.cameras.main).map((light, i) => {
                        const distance = (light as any).distance;
                        light = (light as any).light;
                        return <AccordionItem key={i}>
                            <h2>
                                <AccordionButton>
                                    <Box flex='1' textAlign='left'>
                                        Light: {light.x} {light.y}
                                        <br />
                                        PointLight: {light instanceof Phaser.GameObjects.PointLight ? '✅' : '❌'}
                                    </Box>
                                    <AccordionIcon />
                                </AccordionButton>
                            </h2>
                            <AccordionPanel pb={4}>
                                <Position object={light}/>
                                <InputGroup size="sm">
                                    <InputLeftAddon children='Radius' />
                                    <Input onChange={(e) => light.radius = Number.parseFloat(e.target.value) ?? 0} placeholder={light.radius.toString()} />
                                </InputGroup>
                                <InputGroup size="sm">
                                    <InputLeftAddon children='Intensity' />
                                    <Input onChange={(e) => light.intensity = Number.parseFloat(e.target.value) ?? 0} placeholder={light.intensity.toString()} />
                                </InputGroup>
                                <br/>
                                Visible: <Checkbox onChange={(e) => light.visible = e.target.checked} defaultChecked={light.visible}/>
                                <div>
                                    Color:
                                    <input 
                                        type="color" 
                                        onChange={(e) => {
                                            const value = e.target.value;
                                            const color = value.substring(1);
                                            const r = parseInt(color.substring(0, 2), 16) / 255;
                                            const g = parseInt(color.substring(2, 4), 16) / 255;
                                            const b = parseInt(color.substring(4, 6), 16) / 255;
                                            light.color.set(r, g, b);
                                        }}
                                        defaultValue={'#' + 
                                            ((light.color as any).r * 255).toString(16).padStart(2, '0') + 
                                            ((light.color as any).g * 255).toString(16).padStart(2, '0') + 
                                            ((light.color as any).b * 255).toString(16).padStart(2, '0')}
                                    />
                                </div>
                                <br/>
                                <Button variant="cny" onClick={(e) => {
                                    if (light instanceof Phaser.GameObjects.PointLight)
                                        (light as any).layer.remove(light);
                                    else
                                        lights.removeLight(light);
                                    forceUpdate();
                                }}>
                                    Remove light
                                </Button>
                            </AccordionPanel>
                        </AccordionItem>
                    })
                }
            </Accordion>
        </>
    )
}
Example #25
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
AdvancedNumber: React.FunctionComponent<AdvancedItemStateProps> = (
	props: React.PropsWithChildren<AdvancedItemStateProps>
) => {
	const { itemStateProp } = props;

	const changeEnumOtherValue = (value: string): string[] | null => {
		const array = value.split("\n");
		if (array.length === 0 || (array.length === 1 && !array[0])) {
			return null;
		}

		return array;
	};

	const itemState = useState(itemStateProp);

	const isEnumChecked = (itemState.value as JSONSchema7).enum !== undefined;
	const enumData = (itemState.value as JSONSchema7).enum
		? (itemState.enum.value as string[])
		: [];
	const enumValue = enumData?.join("\n");

	return (
		<Flex direction="column" wrap="nowrap">
			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Default: </FormLabel>

				<NumberInput
					size="sm"
					defaultValue={Number(itemState.default.value)}
					placeholder="Default value"
					onChange={(value: number | string) => {
						itemState.default.set(Number(value));
					}}
				>
					<NumberInputField value={Number(itemState.default.value)} />
					<NumberInputStepper>
						<NumberIncrementStepper />
						<NumberDecrementStepper />
					</NumberInputStepper>
				</NumberInput>
			</Stack>

			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Min Value: </FormLabel>
				<NumberInput
					size="sm"
					defaultValue={Number(itemState.minimum.value)}
					onChange={(value: number | string) => {
						itemState.minimum.set(Number(value));
					}}
				>
					<NumberInputField value={Number(itemState.minimum.value)} />
					<NumberInputStepper>
						<NumberIncrementStepper />
						<NumberDecrementStepper />
					</NumberInputStepper>
				</NumberInput>
				<FormLabel mr={2}>Max Value: </FormLabel>
				<NumberInput
					size="sm"
					defaultValue={Number(itemState.maximum.value)}
					onChange={(value: number | string) => {
						itemState.maximum.set(Number(value));
					}}
				>
					<NumberInputField value={Number(itemState.maximum.value)} />
					<NumberInputStepper>
						<NumberIncrementStepper />
						<NumberDecrementStepper />
					</NumberInputStepper>
				</NumberInput>
			</Stack>
			<Stack
				isInline
				alignItems="center"
				justifyContent="center"
				alignContent="center"
				m={1}
			>
				<FormLabel mr={2}>Enum: </FormLabel>
				<Checkbox
					isChecked={isEnumChecked}
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						if (!evt.target.checked) {
							itemState.enum.set(none);
						} else {
							itemState.enum.set(Array<string>());
						}
					}}
				/>
				<Textarea
					value={enumValue}
					isDisabled={!isEnumChecked}
					placeholder="ENUM Values - One Entry Per Line"
					type={"number"}
					onChange={(evt: React.ChangeEvent<HTMLTextAreaElement>) => {
						const re = /^[0-9\n]+$/;
						if (evt.target.value === "" || re.test(evt.target.value)) {
							const update = changeEnumOtherValue(evt.target.value);
							if (update === null) {
								itemState.enum.set(none);
							} else {
								itemState.enum.set(update as string[]);
							}
						}
					}}
				/>
			</Stack>
		</Flex>
	);
}
Example #26
Source File: PaymentMethodsInput.tsx    From coindrop with GNU General Public License v3.0 4 votes vote down vote up
PaymentMethodsInput: FC<Props> = ({ fieldArrayName, fields, control, register, remove, append }) => {
    const { colors } = useTheme();
    const paymentMethodsDataWatch: PaymentMethod[] = useWatch({
        control,
        name: fieldArrayName,
    });
    const [openAccordionItemIndex, setOpenAccordionItemIndex] = useState(-1);
    useEffect(() => {
        if (
            paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.paymentMethodId === "default-blank"
            || paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.address === ""
        ) {
            setOpenAccordionItemIndex(paymentMethodsDataWatch.length - 1);
        }
    }, [paymentMethodsDataWatch]);
    const containsInvalidAddress = paymentMethodsDataWatch.some(paymentMethod => !paymentMethod.address);
    const { isAddressTouched, setIsAddressTouched } = useContext(AdditionalValidation);
    // optgroup not compatible with Chakra dark mode: https://github.com/chakra-ui/chakra-ui/issues/2853
        // const optionsGroup = (category: Category) => {
        //     const optgroupLabels: Record<Category, string> = {
        //         "digital-wallet": 'Digital Wallets',
        //         "digital-asset": "Digital Assets",
        //         "subscription-platform": "Subscription Platforms",
        //     };
        //     return (
        //         <optgroup label={optgroupLabels[category]}>
        //             {paymentMethods
        //             .filter(paymentMethod => paymentMethod.category === category)
        //             .sort((a, b) => (a.id < b.id ? -1 : 1))
        //             .map(({ id, displayName }) => (
        //                 <option
        //                     key={id}
        //                     value={id}
        //                     style={{display: paymentMethodsDataWatch.map(paymentMethodDataWatch => paymentMethodDataWatch.paymentMethodId).includes(id) ? "none" : undefined }}
        //                 >
        //                     {displayName}
        //                 </option>
        //             ))}
        //         </optgroup>
        //     );
        // };
    return (
        <>
        {fields.length < 1
            ? 'No payment methods defined yet.'
        : (
            <Accordion
                allowToggle
                defaultIndex={-1}
                index={openAccordionItemIndex}
            >
                {
                fields
                    .map((item, index) => {
                    const watchedData = paymentMethodsDataWatch.find(watchedPaymentMethod => watchedPaymentMethod.id === item.id);
                    const PaymentMethodIcon = paymentMethodIcons[watchedData?.paymentMethodId];
                    return (
                        <AccordionItem
                            key={item.id}
                        >
                            <AccordionButton
                                onClick={() => {
                                    setIsAddressTouched(true);
                                    if (openAccordionItemIndex !== index && !paymentMethodsDataWatch.find(paymentMethod => paymentMethod.address === "")) {
                                        setOpenAccordionItemIndex(index);
                                    } else {
                                        setOpenAccordionItemIndex(undefined);
                                    }
                                }}
                            >
                                <Flex flex="1" textAlign="left" align="center">
                                    <Flex mr={1} align="center">
                                        {PaymentMethodIcon ? <PaymentMethodIcon mr={2} /> : <QuestionOutlineIcon mr={2} />}
                                        {paymentMethodNames[watchedData?.paymentMethodId] ?? 'Add payment method'}
                                    </Flex>
                                    {watchedData?.isPreferred && (
                                        <Flex>
                                            <StarIcon
                                                ml={2}
                                                size="16px"
                                                color={colors.yellow['400']}
                                            />
                                            <Text
                                                as="span"
                                                fontSize="xs"
                                                ml={1}
                                            >
                                                <i>Preferred</i>
                                            </Text>
                                        </Flex>
                                    )}
                                </Flex>
                                <AccordionIcon />
                            </AccordionButton>
                            <AccordionPanel pb={4} id={`accordion-panel-${watchedData.paymentMethodId}`}>
                                <input
                                    ref={register()}
                                    name={`${fieldArrayName}[${index}].id`}
                                    defaultValue={item.id}
                                    style={{display: 'none'}}
                                />
                                <Box
                                    display={paymentMethodNames[watchedData?.paymentMethodId] ? "none" : "block"}
                                    data-cy={`select-payment-method-container-${watchedData.paymentMethodId}`}
                                >
                                    <Select
                                        name={`${fieldArrayName}[${index}].paymentMethodId`}
                                        ref={register()}
                                        defaultValue={paymentMethodNames[item.paymentMethodId] ? item.paymentMethodId : 'default-blank'}
                                        isInvalid={containsInvalidAddress && isAddressTouched}
                                        onChange={() => setIsAddressTouched(false)}
                                    >
                                        <option hidden disabled value="default-blank">Select...</option>
                                        {/* optgroup not compatible with Chakra dark mode: https://github.com/chakra-ui/chakra-ui/issues/2853 */}
                                        {Object.entries(paymentMethodNames)
                                            .sort((a, b) => {
                                                const [aId] = a;
                                                const [bId] = b;
                                                return aId < bId ? -1 : 1;
                                            })
                                            .map(([paymentMethodId, paymentMethodDisplayName]) => (
                                                <option
                                                    key={paymentMethodId}
                                                    value={paymentMethodId}
                                                    style={{display: paymentMethodsDataWatch.map(paymentMethod => paymentMethod.paymentMethodId).includes(paymentMethodId) ? "none" : undefined }}
                                                >
                                                    {paymentMethodDisplayName}
                                                </option>
                                            ))}
                                    </Select>
                                </Box>
                                <Box
                                    mx={3}
                                    display={paymentMethodNames[watchedData?.paymentMethodId] ? "block" : "none"}
                                >
                                    <FormControl isRequired>
                                        <FormLabel htmlFor={`${fieldArrayName}[${index}].address`}>Address</FormLabel>
                                        <Input
                                            id={`address-input-${watchedData.paymentMethodId}`}
                                            name={`${fieldArrayName}[${index}].address`}
                                            ref={register()}
                                            defaultValue={item.address}
                                            isInvalid={containsInvalidAddress && isAddressTouched}
                                        />
                                        <Box>
                                            <Checkbox
                                                name={`${fieldArrayName}[${index}].isPreferred`}
                                                ref={register()}
                                                defaultValue={item?.isPreferred ? 1 : 0}
                                                defaultIsChecked={item?.isPreferred}
                                                mt={1}
                                                colorScheme="yellow"
                                            >
                                                Preferred
                                            </Checkbox>
                                        </Box>
                                    </FormControl>
                                </Box>
                                <Flex
                                    justify={watchedData?.paymentMethodId === 'default-blank' ? 'space-between' : 'flex-end'}
                                    mt={3}
                                    wrap="wrap"
                                    align="center"
                                >
                                    {watchedData?.paymentMethodId === 'default-blank' && (
                                        <Text fontSize="xs" ml={1}>
                                            <Link href="/blog/payment-method-request" isExternal>
                                                Payment method not listed?
                                            </Link>
                                        </Text>
                                    )}
                                    <Button
                                        onClick={() => {
                                            remove(index);
                                            setIsAddressTouched(false);
                                        }}
                                        leftIcon={<MinusIcon />}
                                        size="sm"
                                    >
                                        {'Remove '}
                                        {/* {paymentMethodNames[watchedData?.paymentMethodId]} */}
                                    </Button>
                                </Flex>
                            </AccordionPanel>
                        </AccordionItem>
                    );
                })
}
            </Accordion>
        )}
        <Flex
            justify="center"
            mt={2}
        >
            <Button
                id="add-payment-method-button"
                onClick={() => {
                    append({});
                    setIsAddressTouched(false);
                }}
                leftIcon={<AddIcon />}
                variant="ghost"
                size="sm"
                isDisabled={
                    (
                        fields.length > 0
                        && !paymentMethodNames[paymentMethodsDataWatch[paymentMethodsDataWatch.length - 1]?.paymentMethodId]
                    )
                    || containsInvalidAddress
                }
            >
                Add payment method
            </Button>
        </Flex>
        </>
    );
}
Example #27
Source File: index.tsx    From coindrop with GNU General Public License v3.0 4 votes vote down vote up
UserDataForm: FC<UserDataFormProps> = ({ userData, mutate, userId }) => {
    const [isSubmitting, setIsSubmitting] = useState(false);
    const toast = useToast();
    const { register, handleSubmit, formState: { isDirty }, reset } = useForm();
    const email_lists = userData?.email_lists;
    const onSubmit = async (rawFormData) => {
        setIsSubmitting(true);
        const userDataForDb = {
            email_lists: [],
        };
        Object.keys(optionalEmailLists).forEach(emailListId => {
            if (rawFormData.email_lists[emailListId]) {
                userDataForDb.email_lists.push(emailListId);
            }
        });
        try {
            await updateUserData({ data: userDataForDb, userId });
            mutate(userDataForDb);
            reset();
            toast({
                title: "Account updated",
                status: "success",
                duration: 6000,
                isClosable: true,
            });
        } catch (err) {
            toast({
                title: "Error updating account",
                description: "Please try again or contact support",
                status: "error",
                duration: 9000,
                isClosable: true,
            });
        } finally {
            setIsSubmitting(false);
        }
    };
    return (
        <SectionContainer>
            <form onSubmit={handleSubmit(onSubmit)} data-testid="settings-form">
                <SectionHeading size="md">
                    E-mail
                </SectionHeading>
                <Box
                    id="email-preferences-content"
                    m={4}
                >
                    <FormLabel>Newsletters</FormLabel>
                    <Flex wrap="wrap">
                        {Object.entries(optionalEmailLists).map(([emailListId, emailListDisplayName]: [EmailListIds, string]) => {
                            return (
                                <Checkbox
                                    key={emailListId}
                                    mr={6}
                                    name={`email_lists.${emailListId}`}
                                    colorScheme="orange"
                                    defaultChecked={email_lists?.includes(emailListId)}
                                    ref={register()}
                                >
                                    {emailListDisplayName}
                                </Checkbox>
                            );
                        })}
                        {alwaysEnabledEmailLists.map(listName => (
                            <Checkbox
                                key={listName}
                                mr={6}
                                colorScheme="orange"
                                defaultChecked
                                isDisabled
                            >
                                {listName}
                            </Checkbox>
                        ))}
                    </Flex>
                </Box>
                <Box>
                    <Button
                        colorScheme="green"
                        type="submit"
                        isDisabled={!isDirty || isSubmitting}
                        leftIcon={isSubmitting ? <Spinner size="sm" /> : undefined}
                    >
                        {isSubmitting ? 'Saving' : 'Save'}
                    </Button>
                </Box>
            </form>
        </SectionContainer>
    );
}
Example #28
Source File: LogsLayout.tsx    From bluebubbles-server with Apache License 2.0 4 votes vote down vote up
LogsLayout = (): JSX.Element => {
    const dispatch = useAppDispatch();
    const [requiresConfirmation, confirm] = useState((): string | null => {
        return null;
    });
    const alertRef = useRef(null);
    let logs = useAppSelector(state => state.logStore.logs);
    const showDebug = useAppSelector(state => state.logStore.debug);

    // If we don't want to show debug logs, filter them out
    if (!showDebug) {
        logs = logs.filter(e => e.type !== 'debug');
    }

    const toggleDebugMode = (e: React.ChangeEvent<HTMLInputElement>) => {
        dispatch(setDebug(e.target.checked));
    };

    return (
        <Box p={3} borderRadius={10}>
            <Flex flexDirection="column">
                <Stack direction='column' p={5}>
                    <Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
                        <Text fontSize='2xl'>Controls</Text>
                        <Popover trigger='hover'>
                            <PopoverTrigger>
                                <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                    <AiOutlineInfoCircle />
                                </Box>
                            </PopoverTrigger>
                            <PopoverContent>
                                <PopoverArrow />
                                <PopoverCloseButton />
                                <PopoverHeader>Information</PopoverHeader>
                                <PopoverBody>
                                    <Text>
                                        This page will allow you to perform debugging actions on your BlueBubbles server.
                                        As many of you know, software is not perfect, and there will always be edge cases
                                        depending on the environment. These controls allow us to get the information needed, or
                                        take the required actions to solve an issue. It also allows you to "see" into what
                                        the server is doing in the background.
                                    </Text>
                                </PopoverBody>
                            </PopoverContent>
                        </Popover>
                    </Flex>
                    <Divider orientation='horizontal' />
                    <Flex flexDirection="row" justifyContent="flex-start">
                        <Menu>
                            <MenuButton
                                as={Button}
                                rightIcon={<BsChevronDown />}
                                width="12em"
                                mr={5}
                            >
                                Manage
                            </MenuButton>
                            <MenuList>
                                <MenuItem icon={<VscDebugRestart />} onClick={() => confirm('restartServices')}>
                                    Restart Services
                                </MenuItem>
                                <MenuItem icon={<BsBootstrapReboot />} onClick={() => confirm('fullRestart')}>
                                    Full Restart
                                </MenuItem>
                                <MenuItem icon={<FiExternalLink />} onClick={() => openLogLocation()}>
                                    Open Log Location
                                </MenuItem>
                                <MenuItem icon={<GoFileSubmodule />} onClick={() => openAppLocation()}>
                                    Open App Location
                                </MenuItem>
                                <MenuItem icon={<AiOutlineClear />} onClick={() => clearLogs()}>
                                    Clear Logs
                                </MenuItem>
                            </MenuList>
                        </Menu>
                        <Menu>
                            <MenuButton
                                as={Button}
                                rightIcon={<BsChevronDown />}
                                width="12em"
                                mr={5}
                            >
                                Debug Actions
                            </MenuButton>
                            <MenuList>
                                <MenuItem icon={<BsTerminal />} onClick={() => confirm('restartViaTerminal')}>
                                    Restart via Terminal
                                </MenuItem>
                                <MenuItem icon={<AiOutlineClear />} onClick={() => confirm('clearEventCache')}>
                                    Clear Event Cache
                                </MenuItem>
                            </MenuList>
                        </Menu>
                        
                    </Flex>
                </Stack>
                <Stack direction='column' p={5}>
                    <Text fontSize='2xl'>Debug Logs</Text>
                    <Divider orientation='horizontal' />
                    <Spacer />
                    <Flex flexDirection='row' justifyContent='flex-start' alignItems='center'>
                        <Checkbox onChange={(e) => toggleDebugMode(e)} isChecked={showDebug}>Show Debug Logs</Checkbox>
                        <Popover trigger='hover'>
                            <PopoverTrigger>
                                <Box ml={2} _hover={{ color: 'brand.primary', cursor: 'pointer' }}>
                                    <AiOutlineInfoCircle />
                                </Box>
                            </PopoverTrigger>
                            <PopoverContent>
                                <PopoverArrow />
                                <PopoverCloseButton />
                                <PopoverHeader>Inforamation</PopoverHeader>
                                <PopoverBody>
                                    <Text>
                                        Enabling this option will show DEBUG level logs. Leaving
                                        this disabled will only INFO, WARN, and ERROR level logs.
                                    </Text>
                                </PopoverBody>
                            </PopoverContent>
                        </Popover>
                    </Flex>
                    <Spacer />
                    <LogsTable logs={logs} />
                </Stack>
            </Flex>

            <ConfirmationDialog
                modalRef={alertRef}
                onClose={() => confirm(null)}
                body={confirmationActions[requiresConfirmation as string]?.message}
                onAccept={() => {
                    if (hasKey(confirmationActions, requiresConfirmation as string)) {
                        if (confirmationActions[requiresConfirmation as string].shouldDispatch ?? false) {
                            dispatch(confirmationActions[requiresConfirmation as string].func() as AnyAction);
                        } else {
                            confirmationActions[requiresConfirmation as string].func();
                        }
                    }
                }}
                isOpen={requiresConfirmation !== null}
            />
        </Box>
    );
}