@chakra-ui/react#RadioGroup JavaScript Examples

The following examples show how to use @chakra-ui/react#RadioGroup. 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: components.js    From idena-web with MIT License 5 votes vote down vote up
export function FlipFilter(props) {
  return <RadioGroup spacing={2} {...props} />
}
Example #2
Source File: components.js    From idena-web with MIT License 5 votes vote down vote up
PresetFormControlOptionList = React.forwardRef((props, ref) => (
  <RadioGroup ref={ref} {...props} />
))
Example #3
Source File: containers.js    From idena-web with MIT License 5 votes vote down vote up
export function NewOraclePresetDialog({onChoosePreset, onCancel, ...props}) {
  const {t} = useTranslation()

  const [preset, setPreset] = React.useState()

  return (
    <Dialog size="lg" onClose={onCancel} {...props}>
      <DialogHeader mb={4}>{t('New Oracle voting')}</DialogHeader>
      <DialogBody>
        <Stack>
          <Text color="muted" fontSize="sm">
            {t('Choose an option to vote')}
          </Text>
          <RadioGroup spacing={0} onChange={value => setPreset(value)}>
            <Stack>
              <Radio
                value="fact"
                alignItems="flex-start"
                borderColor="gray.100"
              >
                <Stack spacing={1}>
                  <Text>{t('Fact certification')}</Text>
                  <Text color="muted">
                    {t(
                      'Oracles who vote against the majority are penalized. Voting will be started in a future date.'
                    )}
                  </Text>
                </Stack>
              </Radio>
              <Radio
                value="poll"
                alignItems="flex-start"
                borderColor="gray.100"
              >
                <Stack spacing={1}>
                  <Text>{t('Poll')}</Text>
                  <Text color="muted">
                    {t(
                      'Oracles can vote for any option. Rewards will be paid to everyone regardless of the outcome of the vote.'
                    )}
                  </Text>
                </Stack>
              </Radio>
              <Radio
                value="decision"
                alignItems="flex-start"
                borderColor="gray.100"
              >
                <Stack spacing={1}>
                  <Text>{t('Making decision')}</Text>
                  <Text color="muted">
                    {t('51% consensus is required to make a decision')}
                  </Text>
                </Stack>
              </Radio>
              <Radio value="custom" borderColor="gray.100">
                {t('Custom')}
              </Radio>
            </Stack>
          </RadioGroup>
        </Stack>
      </DialogBody>
      <DialogFooter>
        <SecondaryButton onClick={onCancel}>{t('Cancel')}</SecondaryButton>
        <PrimaryButton onClick={() => onChoosePreset(preset)}>
          {t('Continue')}
        </PrimaryButton>
      </DialogFooter>
    </Dialog>
  )
}
Example #4
Source File: index.jsx    From UpStats with MIT License 4 votes vote down vote up
export default function Dashboard() {
  const api = create({
    baseURL: "/api",
  });

  const toast = useToast();

  const router = useRouter();
  const [systems, setSystems] = useState([]);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [mailing, setMailing] = useState(false);

  const [currentEditSystem, setCurrentEditSystem] = useState({
    name: "",
    url: "",
  });
  const [subsCount, setSubsCount] = useState(0);
  const loadSystems = async () => {
    try {
      const { data } = await http.get("/systems");
      setSystems(data);
    } catch (e) {
      toast({
        title: "Error",
        description: "Error Loading Systems",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  const loadConfig = async () => {
    try {
      const { data } = await http.get("/config");
      setMailing(data.mailing);
    } catch (e) {
      console.log("Error Loading Config");
    }
  };
  const loadCount = async () => {
    try {
      const { data } = await http.get("/subs");

      setSubsCount(data.length);
    } catch (e) {
      toast({
        title: "Error",
        description: "Error Loading Subs Count",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  useEffect(() => {
    const token = window.localStorage.getItem("token");
    http.setJwt(token);

    if (!token) {
      setIsLoggedIn(false);
      toast({
        title: "Error",
        description: "Redirecting to Login Page",
        status: "warning",
        duration: 9000,
        isClosable: true,
      });
      router.push("/login");
    } else setIsLoggedIn(true);
  }, []);
  useEffect(() => {
    loadSystems();
  }, []);

  useEffect(() => {
    loadCount();
  }, []);
  useEffect(() => {
    loadConfig();
  }, []);
  const handleDelete = async (system) => {
    const originalSystems = systems;
    const newSystems = originalSystems.filter((s) => s._id !== system._id);

    setSystems(newSystems);
    try {
      await http.delete(`/systems/${system._id}`);
    } catch (ex) {
      if (ex.response && ex.response.status === 404)
        toast({
          title: "Error",
          description: "System May be Already Deleted",
          status: "error",
          duration: 9000,
          isClosable: true,
        });
      setSystems(originalSystems);
    }
  };
  const handleAdd = async (system) => {
    try {
      const { data } = await api.post("/systems", system, {
        headers: localStorage.getItem("token"),
      });
      setSystems([...systems, data]);
    } catch (ex) {
      toast({
        title: "Error",
        description: "Submit Unsuccessful",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };

  const formik = useFormik({
    initialValues: {
      name: "",
      url: "",
      type: "web",
    },
    validationSchema: Yup.object({
      name: Yup.string()
        .max(15, "Must be 15 characters or less")
        .required("Required"),
      url: Yup.string().required("Required"),
      type: Yup.string(),
    }),
    onSubmit: (values) => {
      handleAdd(values);
      //alert(JSON.stringify(values, null, 2));
    },
  });
  const handleEdit = async () => {
    const originalSystems = systems;
    let newSystems = [...systems];
    const idx = newSystems.findIndex(
      (sys) => sys._id === currentEditSystem._id
    );
    newSystems[idx] = { ...currentEditSystem };

    setSystems(newSystems);
    try {
      await http.put(`/systems/${currentEditSystem._id}`, {
        name: currentEditSystem.name,
        url: currentEditSystem.url,
        type: currentEditSystem.type,
      });
      setCurrentEditSystem({ name: "", url: "" });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Error Updating The System",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
      setSystems(originalSystems);
      setCurrentEditSystem({ name: "", url: "" });
    }
  };
  const handleChangeConfig = async () => {
    try {
      await http.put(`/config`, {
        mailing: mailing,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Error Updating The Config",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  return (
    <FormikProvider value={formik}>
      <>
        <Layout>
          {isLoggedIn ? (
            <>
              <div className=" mt-12  mx-auto">
                <div>
                  <div className="m-auto p-4 md:w-1/4 sm:w-1/2 w-full">
                    <div className="p-12 py-6 rounded-lg">
                      <svg
                        fill="none"
                        stroke="currentColor"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth={2}
                        className="w-12 h-12 inline-block users-status"
                        viewBox="0 0 24 24"
                      >
                        <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" />
                        <circle cx={9} cy={7} r={4} />
                        <path d="M23 21v-2a4 4 0 00-3-3.87m-4-12a4 4 0 010 7.75" />
                      </svg>
                      <h2 className="title-font font-medium text-3xl">
                        {subsCount}
                      </h2>
                      <p className="leading-relaxed ">Users Subscribed</p>
                    </div>
                  </div>
                </div>
              </div>
              {/* CRUD Status List */}
              <div className="w-full max-w-sm overflow-hidden rounded-lg items-center mx-auto">
                <h3 className="text-2xl font-black text-black">
                  Add New System
                </h3>
                <form onSubmit={formik.handleSubmit} className="p-3">
                  <Stack>
                    <Text>System Title</Text>
                    <Input
                      id="name"
                      name="name"
                      type="text"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.name}
                      placeholder="Enter here"
                      isInvalid={
                        formik.touched.name && formik.errors.name ? true : false
                      }
                    />
                    {formik.touched.name && formik.errors.name ? (
                      <Alert status="error">
                        <AlertIcon />
                        {formik.errors.name}
                      </Alert>
                    ) : null}
                  </Stack>
                  <Stack mt={2}>
                    <Text>System URL</Text>
                    <Input
                      placeholder="Enter here"
                      id="url"
                      name="url"
                      type="text"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.url}
                      isInvalid={
                        formik.touched.url && formik.errors.url ? true : false
                      }
                    />
                    {formik.touched.url && formik.errors.url ? (
                      <Alert status="error">
                        <AlertIcon />
                        {formik.errors.url}
                      </Alert>
                    ) : null}
                  </Stack>
                  {/* Select System Type */}
                  <RadioGroup>
                    <Stack mt={5}>
                      <Field as={Radio} type="radio" name="type" value="web">
                        Web
                      </Field>
                      <Field
                        as={Radio}
                        type="radio"
                        name="type"
                        value="telegram"
                      >
                        Telegram Bot
                      </Field>
                    </Stack>
                  </RadioGroup>
                  {/* Add */}
                  <div className="mt-4">
                    <button
                      style={{ backgroundColor: "#3747D4" }}
                      className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                      type="submit"
                    >
                      Add
                    </button>
                  </div>
                </form>
                {/* Status Page List */}
                {/* Show Sites here */}
                {systems.map((system) => (
                  <div key={system._id} className="status-items-manage">
                    <div className="items">
                      <span className="site-title">{system?.name}</span>
                      <div className="i">
                        <EditIcon
                          mr="2"
                          onClick={() => {
                            setCurrentEditSystem(system);
                          }}
                        />
                        <DeleteIcon
                          color="red"
                          m="2"
                          onClick={() => {
                            handleDelete(system);
                          }}
                        />
                      </div>
                    </div>
                  </div>
                ))}
                {/* End */}
                {currentEditSystem.name ? (
                  <div className="mt-4">
                    <Stack>
                      <h3 className="text-2xl font-black text-black">
                        Edit System
                      </h3>
                      <Stack>
                        <Text>System Title</Text>
                        <Input
                          id="name"
                          name="name"
                          type="text"
                          value={currentEditSystem.name}
                          onChange={(e) => {
                            setCurrentEditSystem({
                              ...currentEditSystem,
                              name: e.target.value,
                            });
                          }}
                          placeholder="Enter here"
                        />
                      </Stack>
                      <Stack mt={2}>
                        <Text>System URL</Text>
                        <Input
                          placeholder="Enter here"
                          id="url"
                          name="url"
                          type="text"
                          value={currentEditSystem.url}
                          onChange={(e) =>
                            setCurrentEditSystem({
                              ...currentEditSystem,
                              url: e.target.value,
                            })
                          }
                        />
                      </Stack>
                    </Stack>
                    {/* Add */}
                    <div className="mt-4">
                      <button
                        onClick={handleEdit}
                        style={{ backgroundColor: "#3747D4" }}
                        className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                      >
                        Done
                      </button>
                    </div>
                  </div>
                ) : (
                  ""
                )}
                <Stack mt={12}>
                  <h3 className="text-xl font-black text-bold">Configs</h3>
                  <p className="text-md font-black text-bold">Mailing</p>
                  <Switch
                    size="lg"
                    isChecked={mailing}
                    onChange={(e) => setMailing(e.target.checked)}
                  />
                  <div className="mt-4">
                    <button
                      onClick={handleChangeConfig}
                      style={{ backgroundColor: "#3747D4" }}
                      className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
                    >
                      Done
                    </button>
                  </div>
                </Stack>
              </div>
            </>
          ) : (
            ""
          )}

          {/* Total No. of Users Subscribed */}
        </Layout>
      </>
    </FormikProvider>
  );
}
Example #5
Source File: offline.js    From idena-web with MIT License 4 votes vote down vote up
export default function Offline() {
  const {t} = useTranslation()
  const {apiKeyState, apiKey, url} = useSettingsState()
  const {saveConnection} = useSettingsDispatch()
  const {coinbase, privateKey} = useAuthState()
  const router = useRouter()

  const {isOpen, onOpen, onClose} = useDisclosure()
  const cancelRef = useRef()

  const [error, setError] = useState({type: errorType.NONE})
  const [state, setState] = useState(options.BUY)
  const [step, setStep] = useState(steps.INITIAL)

  const [savedApiKey, setSavedApiKey] = useState()

  const [submitting, setSubmitting] = useState(false)

  const failToast = useFailToast()

  const {isPurchasing, savePurchase, setRestrictedKey} = useApikeyPurchasing()

  const [isDesktop] = useMediaQuery('(min-width: 481px)')
  const size = useBreakpointValue(['lg', 'md'])
  const variant = useBreakpointValue(['mobile', 'initial'])
  const variantRadio = useBreakpointValue(['mobileDark', 'dark'])
  const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
  const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])

  const {data: identity} = useQuery(
    ['fetch-identity', coinbase],
    () => fetchIdentity(coinbase, true),
    {
      enabled: !!coinbase,
    }
  )

  const getKeyForCandidate = async () => {
    setSubmitting(true)

    try {
      const providers = await getAvailableProviders()
      const signature = signMessage(hexToUint8Array(coinbase), privateKey)
      const result = await getCandidateKey(
        coinbase,
        toHexString(signature, true),
        providers
      )
      savePurchase(result.id, result.provider)
    } catch (e) {
      failToast(
        `Failed to get API key for Candidate: ${
          e.response ? e.response.data : 'unknown error'
        }`
      )
    } finally {
      setSubmitting(false)
    }
  }

  const activateInvite = async () => {
    setSubmitting(true)

    try {
      const from = privateKeyToAddress(privateKey)

      const rawTx = await getRawTx(
        1,
        from,
        coinbase,
        0,
        0,
        privateKeyToPublicKey(privateKey),
        0,
        true
      )

      const tx = new Transaction().fromHex(rawTx)
      tx.sign(privateKey)

      const providers = await getAvailableProviders()

      const result = await activateKey(coinbase, `0x${tx.toHex()}`, providers)
      savePurchase(result.id, result.provider)
      sendActivateInvitation(coinbase)
    } catch (e) {
      failToast(
        `Failed to activate invite: ${
          e.response ? e.response.data : 'invitation is invalid'
        }`
      )
    } finally {
      setSubmitting(false)
    }
  }

  const process = async () => {
    switch (state) {
      case options.ENTER_KEY:
        return router.push('/settings/node')
      case options.BUY:
        return router.push('/node/rent')
      case options.ACTIVATE: {
        if (identity?.state === IdentityStatus.Invite) {
          return activateInvite()
        }
        return router.push('/node/activate')
      }
      case options.CANDIDATE:
        return getKeyForCandidate()
      case options.RESTRICTED: {
        return onOpen()
      }
      case options.RESTORE: {
        return saveConnection(savedApiKey.url, savedApiKey.key, false)
      }
      default:
    }
  }

  useEffect(() => {
    async function checkSaved() {
      try {
        const signature = signMessage(hexToUint8Array(coinbase), privateKey)
        const savedKey = await checkSavedKey(
          coinbase,
          toHexString(signature, true)
        )
        setSavedApiKey(savedKey)
      } catch (e) {}
    }
    checkSaved()
  }, [apiKey, coinbase, privateKey])

  useEffect(() => {
    if (
      apiKeyState === ApiKeyStates.ONLINE ||
      apiKeyState === ApiKeyStates.EXTERNAL
    )
      router.push('/home')
  }, [apiKeyState, router])

  useEffect(() => {
    async function check() {
      try {
        const result = await checkKey(apiKey)
        const res = await getProvider(result.provider)

        if (new URL(url).host !== new URL(res.data.url).host) {
          throw new Error()
        }

        try {
          await promiseTimeout(checkProvider(url), 2000)
          setError({type: errorType.KEY_EXPIRED})
        } catch (e) {
          setError({
            type: errorType.PROVIDER_UNAVAILABLE,
            provider: res.data.ownerName,
          })
        }
      } catch (e) {
        setError({type: errorType.NODE_UNAVAILABLE})
      }
    }

    check()
  }, [apiKey, url])

  useEffect(() => {
    if (identity?.state === IdentityStatus.Candidate) {
      setState(options.CANDIDATE)
    } else if (savedApiKey) {
      setState(options.RESTORE)
    }
  }, [identity, savedApiKey])

  const waiting = submitting || isPurchasing

  return (
    <Layout canRedirect={false}>
      <Flex
        bg={['gray.500', 'graphite.500']}
        alignItems="center"
        justifyContent="center"
        height="100%"
        direction="column"
        justify="center"
        flex="1"
      >
        <Flex
          flexGrow={1}
          align="center"
          justify={['flex-start', 'center']}
          mt="44px"
          mx={[3, 0]}
          direction="column"
        >
          <Flex
            direction="column"
            align={['center', 'initial']}
            maxWidth={['100%', '480px']}
          >
            <Flex
              direction={['column', 'row']}
              align={['center', 'flex-start']}
              textAlign={['center', 'initial']}
              w={['60%', 'auto']}
            >
              <Avatar address={coinbase} />
              <Flex
                direction="column"
                justify="center"
                flex="1"
                ml={[0, 5]}
                mt={[5, 0]}
              >
                <Heading
                  fontSize={['mdx', 'lg']}
                  fontWeight={[400, 500]}
                  color={['muted', 'white']}
                  wordBreak="break-word"
                >
                  {coinbase}
                </Heading>
              </Flex>
            </Flex>
            <Flex
              direction="column"
              mt={6}
              bg="gray.500"
              borderRadius="lg"
              px={[6, 10]}
              py={7}
              w={['100%', 'auto']}
            >
              {step === steps.INITIAL && (
                <Flex direction="column" alignItems="center" mt={6}>
                  <Flex>
                    <Text color="white" fontSize="lg">
                      {t('Offline')}
                    </Text>
                  </Flex>

                  <Flex mt={4}>
                    <Text fontSize="mdx" color="muted" textAlign="center">
                      {t('Please connect to a shared node')}
                    </Text>
                  </Flex>
                  <Flex justifyContent="center" mt={6}>
                    <PrimaryButton onClick={() => setStep(steps.CONNECT)}>
                      {t('New connection')}
                    </PrimaryButton>
                  </Flex>
                </Flex>
              )}
              {step === steps.CONNECT && (
                <>
                  <Flex justify={['center', ' flex-start']}>
                    <Text color="white" fontSize="lg">
                      {t('Connect to Idena node')}
                    </Text>
                  </Flex>

                  <Flex mt={7}>
                    <Text color="white" fontSize="sm" opacity={0.5}>
                      {t('Choose an option')}
                    </Text>
                  </Flex>
                  <Flex mt={[2, 4]}>
                    <RadioGroup w={['100%', 'auto']}>
                      <Stack direction="column" spacing={[1, 3]}>
                        {savedApiKey && savedApiKey.url !== apiKey.url && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.RESTORE}
                            onChange={() => setState(options.RESTORE)}
                            alignItems={['center', 'flex-start']}
                          >
                            <Flex direction="column" mt={['auto', '-2px']}>
                              <Text color="white">
                                {t('Restore connection')}
                              </Text>
                              <Text color="muted" fontSize="sm">
                                {savedApiKey.url}
                              </Text>
                            </Flex>
                          </ChooseItemRadio>
                        )}
                        {identity?.state === IdentityStatus.Candidate && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.CANDIDATE}
                            onChange={() => setState(options.CANDIDATE)}
                          >
                            <Text color="white">{t('Get free access')}</Text>
                          </ChooseItemRadio>
                        )}
                        <ChooseItemRadio
                          variant={variantRadio}
                          px={[4, 0]}
                          isChecked={state === options.BUY}
                          onChange={() => setState(options.BUY)}
                        >
                          <Text color="white">{t('Rent a shared node')}</Text>
                        </ChooseItemRadio>
                        <ChooseItemRadio
                          variant={variantRadio}
                          px={[4, 0]}
                          isChecked={state === options.ENTER_KEY}
                          onChange={() => setState(options.ENTER_KEY)}
                        >
                          <Text color="white">
                            {t('Enter shared node API key')}
                          </Text>
                        </ChooseItemRadio>
                        {[
                          IdentityStatus.Undefined,
                          IdentityStatus.Invite,
                        ].includes(identity?.state) && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.ACTIVATE}
                            onChange={() => setState(options.ACTIVATE)}
                          >
                            <Text color="white">
                              {t('Activate invitation')}
                            </Text>
                          </ChooseItemRadio>
                        )}
                        {identity?.state !== IdentityStatus.Candidate && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.RESTRICTED}
                            onChange={() => setState(options.RESTRICTED)}
                          >
                            <Text
                              lineHeight={['16px', 'initial']}
                              color="white"
                            >
                              {`${t('Get restricted access')}${
                                isDesktop
                                  ? ` (${t(
                                      'Can not be used for validation'
                                    ).toLocaleLowerCase()})`
                                  : ''
                              }`}
                            </Text>
                            <Text
                              display={['inline-block', 'none']}
                              color="xwhite.050"
                              fontSize="sm"
                            >
                              {t('Can not be used for validation')}
                            </Text>
                          </ChooseItemRadio>
                        )}
                      </Stack>
                    </RadioGroup>
                  </Flex>
                  <Flex mt={[4, '30px']} mb={2}>
                    <PrimaryButton
                      size={size}
                      ml="auto"
                      w={['100%', 'auto']}
                      onClick={process}
                      isDisabled={waiting}
                      isLoading={waiting}
                      loadingText="Waiting..."
                    >
                      {t('Continue')}
                    </PrimaryButton>
                  </Flex>
                </>
              )}
            </Flex>
          </Flex>

          {step === steps.INITIAL &&
            error.type === errorType.PROVIDER_UNAVAILABLE && (
              <ProviderOfflineAlert url={url} provider={error.provider} />
            )}
          {step === steps.INITIAL && error.type === errorType.KEY_EXPIRED && (
            <KeyExpiredAlert url={url} apiKey={apiKey} />
          )}
          {step === steps.INITIAL &&
            error.type === errorType.NODE_UNAVAILABLE && (
              <NodeOfflineAlert url={url} />
            )}
        </Flex>
        <Flex
          display={['none', 'flex']}
          justify="center"
          mb={8}
          direction="column"
          justifyContent="center"
        >
          <Text color="white" fontSize="mdx" opacity="0.5" mb={1}>
            {t('You can run your own node at your desktop computer.')}
          </Text>
          <TextLink
            href="https://idena.io/download"
            target="_blank"
            color="white"
            textAlign="center"
          >
            <DownloadIcon boxSize={4} mx={2} />
            {t('Download Idena')}
          </TextLink>
        </Flex>
      </Flex>
      <AlertDialog
        variant={variant}
        motionPreset="slideInBottom"
        leastDestructiveRef={cancelRef}
        onClose={onClose}
        isOpen={isOpen}
        isCentered
      >
        <AlertDialogOverlay />

        <AlertDialogContent mx={[3, 'auto']}>
          <AlertDialogHeader fontSize="lg">
            {t('Are you sure?')}
          </AlertDialogHeader>
          <AlertDialogCloseButton />
          <AlertDialogBody fontSize={['mobile', 'md']}>
            <Trans i18nKey="confirmRestrictedNodeDialog" t={t}>
              Your current API key{' '}
              <Text fontWeight="700" as="span">
                {{apiKey}}
              </Text>{' '}
              for the shared node{' '}
              <Text fontWeight="700" as="span">
                {{url}}
              </Text>{' '}
              will be lost
            </Trans>
          </AlertDialogBody>
          <AlertDialogFooter>
            <Button
              variant={variantSecondary}
              size={size}
              w={['100%', 'auto']}
              onClick={() => {
                setRestrictedKey()
                onClose()
                router.push('/home')
              }}
            >
              {t('Yes')}
            </Button>
            <Divider
              display={['block', 'none']}
              h={10}
              orientation="vertical"
              color="gray.100"
            />
            <Button
              variant={variantPrimary}
              w={['100%', 'auto']}
              size={size}
              ref={cancelRef}
              onClick={onClose}
              ml={2}
            >
              {t('Cancel')}
            </Button>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </Layout>
  )
}
Example #6
Source File: restricted.js    From idena-web with MIT License 4 votes vote down vote up
export default function Restricted() {
  const [{apiKeyState, apiKeyData, apiKey}] = useSettings()
  const {saveConnection} = useSettingsDispatch()
  const {coinbase, privateKey} = useAuthState()
  const [{state: identityState}] = useIdentity()
  const auth = useAuthState()
  const router = useRouter()
  const {t} = useTranslation()

  const [, {updateRestrictedNotNow}] = useAppContext()

  const [step, setStep] = useState(steps.INITIAL)

  const [state, setState] = useState(options.PROLONG)
  const [dontShow, setDontShow] = useState(false)

  const buySharedNodeDisclosure = useDisclosure()

  const [submitting, setSubmitting] = useState(false)

  const failToast = useFailToast()

  const {isPurchasing, savePurchase} = useApikeyPurchasing()

  const [savedApiKey, setSavedApiKey] = useState()

  const size = useBreakpointValue(['lg', 'md'])
  const variantRadio = useBreakpointValue(['mobileDark', 'dark'])
  const variantSecondary = useBreakpointValue(['primaryFlat', 'secondary'])

  const notNow = persist => {
    if (persist) {
      updateRestrictedNotNow(dontShow)
    }
    router.back()
  }

  const getKeyForCandidate = async () => {
    setSubmitting(true)

    try {
      const providers = await getAvailableProviders()
      const signature = signMessage(hexToUint8Array(coinbase), privateKey)
      const result = await getCandidateKey(
        coinbase,
        toHexString(signature, true),
        providers
      )
      savePurchase(result.id, result.provider)
    } catch (e) {
      failToast(
        `Failed to get API key for Candidate: ${
          e.response ? e.response.data : 'unknown error'
        }`
      )
    } finally {
      setSubmitting(false)
    }
  }

  const process = async () => {
    if (state === options.PROLONG) {
      buySharedNodeDisclosure.onOpen()
    } else if (state === options.ENTER_KEY) {
      return router.push('/settings/node')
    } else if (state === options.CANDIDATE) {
      return getKeyForCandidate()
    } else if (state === options.RESTORE) {
      return saveConnection(savedApiKey.url, savedApiKey.key, false)
    } else return router.push('/node/rent')
  }

  const {data: provider, isError} = useQuery(
    ['get-provider-by-id', apiKeyData && apiKeyData.provider],
    () => getProvider(apiKeyData && apiKeyData.provider),
    {
      enabled: !!apiKeyData && !!apiKeyData.provider,
      retry: false,
      refetchOnWindowFocus: false,
    }
  )

  useEffect(() => {
    async function checkSaved() {
      try {
        const signature = signMessage(hexToUint8Array(coinbase), privateKey)
        const savedKey = await checkSavedKey(
          coinbase,
          toHexString(signature, true)
        )
        setSavedApiKey(savedKey)
        // eslint-disable-next-line no-empty
      } catch (e) {}
    }
    checkSaved()
  }, [apiKey, coinbase, privateKey])

  useEffect(() => {
    if (
      apiKeyState === ApiKeyStates.ONLINE ||
      apiKeyState === ApiKeyStates.EXTERNAL
    )
      router.push('/home')
  }, [apiKeyState, router])

  useEffect(() => {
    if (identityState === IdentityStatus.Candidate) {
      setState(options.CANDIDATE)
    } else if (savedApiKey) {
      setState(options.RESTORE)
    } else if ((provider && !provider.slots) || isError) {
      setState(options.BUY)
    }
  }, [identityState, isError, provider, savedApiKey])

  const waiting = submitting || isPurchasing

  const canProlong = provider && provider.slots && !waiting

  return (
    <Layout canRedirect={false}>
      <Flex
        bg={['gray.500', 'graphite.500']}
        alignItems="center"
        justifyContent="center"
        height="100%"
        direction="column"
        justify="center"
        flex="1"
      >
        <Flex
          flexGrow={1}
          align="center"
          justify={['flex-start', 'center']}
          mt="44px"
          mx={[3, 0]}
          direction="column"
        >
          <Flex
            direction="column"
            align={['center', 'initial']}
            maxWidth={['100%', '480px']}
          >
            <Flex
              direction={['column', 'row']}
              align="center"
              textAlign={['center', 'initial']}
              w={['60%', 'auto']}
            >
              <Avatar address={coinbase} />
              <Flex
                direction="column"
                justify="center"
                flex="1"
                ml={[0, 5]}
                mt={[5, 0]}
              >
                <SubHeading
                  fontSize={['mdx', 'lg']}
                  fontWeight={[400, 500]}
                  color={['muted', 'white']}
                  wordBreak="break-word"
                >
                  {auth.coinbase}
                </SubHeading>
              </Flex>
            </Flex>
            <Flex
              direction="column"
              mt={6}
              bg="gray.500"
              borderRadius="lg"
              px={[6, 10]}
              py={7}
              w={['100%', 'auto']}
            >
              {step === steps.INITIAL && (
                <Flex direction="column" alignItems="center" mt={6}>
                  <Flex>
                    <Text color="white" fontSize="lg">
                      {t('Restricted access')}
                    </Text>
                  </Flex>

                  <Flex mt={4}>
                    <Text fontSize="mdx" color="muted" textAlign="center">
                      {t(
                        'You can use all functions of the app except validation. Please connect to a shared node if you want to participate in the upcoming validation using the web app. '
                      )}
                    </Text>
                  </Flex>
                  <Flex justifyContent="center" mt={4}>
                    <PrimaryButton onClick={() => setStep(steps.CONNECT)}>
                      {t('Connect')}
                    </PrimaryButton>
                  </Flex>
                  <Flex
                    mt={10}
                    justifyContent="space-between"
                    alignSelf="normal"
                  >
                    <Flex>
                      <Checkbox
                        textAlign={['left', 'initial']}
                        value={dontShow}
                        isChecked={dontShow}
                        onChange={e => setDontShow(e.target.checked)}
                        color="white"
                      >
                        {t('Don’t show again')}
                      </Checkbox>
                    </Flex>
                    <Flex>
                      <SecondaryButton onClick={() => notNow(true)}>
                        {t('Not now')}
                      </SecondaryButton>
                    </Flex>
                  </Flex>
                </Flex>
              )}
              {step === steps.CONNECT && (
                <>
                  <Flex justify={['center', ' flex-start']}>
                    <Text color="white" fontSize="lg">
                      {t('Connect to a shared node')}
                    </Text>
                  </Flex>

                  <Flex mt={7}>
                    <Text color="muted" fontSize="sm">
                      {t('Choose an option')}
                    </Text>
                  </Flex>
                  <Flex mt={[2, 4]}>
                    <RadioGroup w={['100%', 'auto']}>
                      <Stack direction="column" spacing={[1, 3]}>
                        {savedApiKey && savedApiKey.url !== apiKey.url && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.RESTORE}
                            onChange={() => setState(options.RESTORE)}
                            alignItems={['center', 'flex-start']}
                          >
                            <Flex direction="column" mt={['auto', '-2px']}>
                              <Text color="white">
                                {t('Restore connection')}
                              </Text>
                              <Text color="muted" fontSize="sm">
                                {savedApiKey.url}
                              </Text>
                            </Flex>
                          </ChooseItemRadio>
                        )}
                        {identityState === IdentityStatus.Candidate && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.CANDIDATE}
                            onChange={() => setState(options.CANDIDATE)}
                          >
                            <Text color="white">{t('Get free access')}</Text>
                          </ChooseItemRadio>
                        )}
                        {canProlong && (
                          <ChooseItemRadio
                            variant={variantRadio}
                            px={[4, 0]}
                            isChecked={state === options.PROLONG}
                            onChange={() => setState(options.PROLONG)}
                            alignItems={['center', 'flex-start']}
                          >
                            <Flex direction="column" mt={['auto', '-2px']}>
                              <Text color="white">
                                {t('Prolong node access')}{' '}
                                {`(${GetProviderPrice(
                                  provider.data,
                                  identityState
                                )} iDNA)`}
                              </Text>
                              <Text color="muted" fontSize="sm">
                                {provider.data.url}
                              </Text>
                            </Flex>
                          </ChooseItemRadio>
                        )}
                        <ChooseItemRadio
                          variant={variantRadio}
                          px={[4, 0]}
                          isChecked={state === options.BUY}
                          onChange={() => setState(options.BUY)}
                        >
                          <Text color="white">
                            {canProlong
                              ? t('Rent another shared node')
                              : t('Rent a shared node')}
                          </Text>
                        </ChooseItemRadio>
                        <ChooseItemRadio
                          variant={variantRadio}
                          px={[4, 0]}
                          isChecked={state === options.ENTER_KEY}
                          onChange={() => setState(options.ENTER_KEY)}
                        >
                          <Text color="white">
                            {t('Enter shared node API key')}
                          </Text>
                        </ChooseItemRadio>
                      </Stack>
                    </RadioGroup>
                  </Flex>
                  <Flex mt={[4, 10]} justifyContent="space-between">
                    <Flex
                      direction={['column', 'row']}
                      ml="auto"
                      w={['100%', 'auto']}
                    >
                      <Button
                        variant={variantSecondary}
                        order={[2, 1]}
                        size={size}
                        w={['100%', 'auto']}
                        onClick={() => notNow(false)}
                        mr={[0, 2]}
                        mt={[2, 0]}
                      >
                        {t('Not now')}
                      </Button>
                      <PrimaryButton
                        order={[1, 2]}
                        size={size}
                        w={['100%', 'auto']}
                        onClick={process}
                        isDisabled={waiting}
                        isLoading={waiting}
                        loadingText="Waiting..."
                      >
                        {t('Continue')}
                      </PrimaryButton>
                    </Flex>
                  </Flex>
                </>
              )}
            </Flex>
          </Flex>
        </Flex>
        <Flex
          justify="center"
          mb={8}
          direction="column"
          justifyContent="center"
        >
          <Text color="white" fontSize="mdx" opacity="0.5" mb={1}>
            {t('You can run your own node at your desktop computer.')}
          </Text>
          <TextLink
            href="https://idena.io/download"
            target="_blank"
            color="white"
            textAlign="center"
          >
            <DownloadIcon boxSize={4} mx={2} />
            {t('Download Idena')}
          </TextLink>
        </Flex>
      </Flex>
      {provider && (
        <BuySharedNodeForm
          {...buySharedNodeDisclosure}
          providerId={provider.id}
          url={provider.data.url}
          from={coinbase}
          amount={GetProviderPrice(provider.data, identityState)}
          to={provider.data.address}
        />
      )}
    </Layout>
  )
}
Example #7
Source File: view.js    From idena-web with MIT License 4 votes vote down vote up
export default function ViewVotingPage() {
  const {t, i18n} = useTranslation()

  const [, {addVote}] = useDeferredVotes()

  const toast = useToast()

  const {
    query: {id},
    push: redirect,
  } = useRouter()

  const {epoch} = useEpoch() ?? {epoch: -1}

  const {coinbase, privateKey} = useAuthState()
  const {
    data: {balance: identityBalance},
  } = useBalance()

  const [current, send, service] = useMachine(viewVotingMachine, {
    actions: {
      onError: (context, {data: {message}}) => {
        toast({
          status: 'error',
          // eslint-disable-next-line react/display-name
          render: () => (
            <Toast title={humanError(message, context)} status="error" />
          ),
        })
      },
      addVote: (_, {data: {vote}}) => addVote(vote),
    },
  })

  React.useEffect(() => {
    send('RELOAD', {id, epoch, address: coinbase})
  }, [coinbase, epoch, id, send])

  const toDna = toLocaleDna(i18n.language)

  const {
    title,
    desc,
    contractHash,
    status,
    balance = 0,
    contractBalance = Number(balance),
    votingMinPayment = 0,
    publicVotingDuration = 0,
    quorum = 20,
    committeeSize,
    options = [],
    votes = [],
    voteProofsCount,
    finishDate,
    finishCountingDate,
    selectedOption,
    winnerThreshold = 50,
    balanceUpdates,
    ownerFee,
    totalReward,
    estimatedOracleReward,
    estimatedMaxOracleReward = estimatedOracleReward,
    isOracle,
    minOracleReward,
    estimatedTotalReward,
    pendingVote,
    adCid,
    issuer,
  } = current.context

  const [
    {canProlong, canFinish, canTerminate, isFetching: actionsIsFetching},
    refetchActions,
  ] = useOracleActions(id)

  const isLoaded = !current.matches('loading')

  const sameString = a => b => areSameCaseInsensitive(a, b)

  const eitherIdleState = (...states) =>
    eitherState(current, ...states.map(s => `idle.${s}`.toLowerCase())) ||
    states.some(sameString(status))

  const isClosed = eitherIdleState(
    VotingStatus.Archived,
    VotingStatus.Terminated
  )

  const didDetermineWinner = hasWinner({
    votes,
    votesCount: voteProofsCount,
    winnerThreshold,
    quorum,
    committeeSize,
    finishCountingDate,
  })

  const isMaxWinnerThreshold = winnerThreshold === 100

  const accountableVoteCount = sumAccountableVotes(votes)

  const {data: ad} = useIpfsAd(adCid)

  const adPreviewDisclosure = useDisclosure()

  const isValidAdVoting = React.useMemo(
    () => validateAdVoting({ad, voting: current.context}) === false,
    [ad, current.context]
  )

  const isMaliciousAdVoting = ad && isValidAdVoting

  return (
    <>
      <Layout showHamburger={false}>
        <Page pt={8}>
          <Stack spacing={10}>
            <VotingSkeleton isLoaded={isLoaded} h={6}>
              <Stack isInline spacing={2} align="center">
                <VotingStatusBadge status={status} fontSize="md">
                  {t(mapVotingStatus(status))}
                </VotingStatusBadge>
                <Box
                  as={VotingBadge}
                  bg="gray.100"
                  color="muted"
                  fontSize="md"
                  cursor="pointer"
                  pl="1/2"
                  transition="color 0.2s ease"
                  _hover={{
                    color: 'brandGray.500',
                  }}
                  onClick={() => {
                    openExternalUrl(
                      `https://scan.idena.io/contract/${contractHash}`
                    )
                  }}
                >
                  <Stack isInline spacing={1} align="center">
                    <Avatar size={5} address={contractHash} />
                    <Text>{contractHash}</Text>
                  </Stack>
                </Box>
                <CloseButton
                  sx={{
                    '&': {
                      marginLeft: 'auto!important',
                    },
                  }}
                  onClick={() => redirect('/oracles/list')}
                />
              </Stack>
            </VotingSkeleton>
            <Stack isInline spacing={10} w="full">
              <Box minWidth="lg" maxW="lg">
                <Stack spacing={6}>
                  <VotingSkeleton isLoaded={isLoaded}>
                    <Stack
                      spacing={8}
                      borderRadius="md"
                      bg="gray.50"
                      py={8}
                      px={10}
                    >
                      <Stack spacing={4}>
                        <Heading
                          overflow="hidden"
                          fontSize={21}
                          fontWeight={500}
                          display="-webkit-box"
                          sx={{
                            '&': {
                              WebkitBoxOrient: 'vertical',
                              WebkitLineClamp: '2',
                            },
                          }}
                        >
                          {isMaliciousAdVoting
                            ? t('Please reject malicious ad')
                            : title}
                        </Heading>
                        {ad ? (
                          <>
                            {isMaliciousAdVoting ? (
                              <MaliciousAdOverlay>
                                <OracleAdDescription ad={ad} />
                              </MaliciousAdOverlay>
                            ) : (
                              <OracleAdDescription ad={ad} />
                            )}
                          </>
                        ) : (
                          <Text
                            isTruncated
                            lineHeight="tall"
                            whiteSpace="pre-wrap"
                          >
                            <Linkify
                              onClick={url => {
                                send('FOLLOW_LINK', {url})
                              }}
                            >
                              {desc}
                            </Linkify>
                          </Text>
                        )}
                      </Stack>
                      <Flex>
                        {adCid && (
                          <IconButton
                            icon={<ViewIcon boxSize={4} />}
                            _hover={{background: 'transparent'}}
                            onClick={adPreviewDisclosure.onOpen}
                          >
                            {t('Preview')}
                          </IconButton>
                        )}
                        <GoogleTranslateButton
                          phrases={[
                            title,
                            desc &&
                              encodeURIComponent(desc?.replace(/%/g, '%25')),
                            options.map(({value}) => value).join('\n'),
                          ]}
                          locale={i18n.language}
                          alignSelf="start"
                        />
                      </Flex>
                      <Divider orientation="horizontal" />
                      {isLoaded && <VotingPhase service={service} />}
                    </Stack>
                  </VotingSkeleton>

                  {eitherIdleState(
                    VotingStatus.Pending,
                    VotingStatus.Starting,
                    VotingStatus.Open,
                    VotingStatus.Voting,
                    VotingStatus.Voted,
                    VotingStatus.Prolonging
                  ) && (
                    <VotingSkeleton isLoaded={isLoaded}>
                      {isMaliciousAdVoting ? (
                        <>
                          {eitherIdleState(VotingStatus.Voted) ? (
                            <Box>
                              <Text color="muted" fontSize="sm" mb={3}>
                                {t('Choose an option to vote')}
                              </Text>
                              <Stack spacing={3}>
                                {/* eslint-disable-next-line no-shadow */}
                                {options.map(({id, value}) => {
                                  const isMine = id === selectedOption
                                  return (
                                    <Stack
                                      isInline
                                      spacing={2}
                                      align="center"
                                      bg={isMine ? 'blue.012' : 'gray.50'}
                                      borderRadius="md"
                                      minH={8}
                                      px={3}
                                      py={2}
                                      zIndex={1}
                                    >
                                      <Flex
                                        align="center"
                                        justify="center"
                                        bg={
                                          isMine
                                            ? 'brandBlue.500'
                                            : 'transparent'
                                        }
                                        borderRadius="full"
                                        borderWidth={isMine ? 0 : '4px'}
                                        borderColor="gray.100"
                                        color="white"
                                        w={4}
                                        h={4}
                                      >
                                        {isMine && <OkIcon boxSize={3} />}
                                      </Flex>

                                      <Text
                                        isTruncated
                                        maxW="sm"
                                        title={value.length > 50 ? value : ''}
                                      >
                                        {value}
                                      </Text>
                                    </Stack>
                                  )
                                })}
                              </Stack>
                            </Box>
                          ) : null}
                        </>
                      ) : (
                        <Box>
                          <Text color="muted" fontSize="sm" mb={3}>
                            {t('Choose an option to vote')}
                          </Text>
                          {eitherIdleState(VotingStatus.Voted) ? (
                            <Stack spacing={3}>
                              {/* eslint-disable-next-line no-shadow */}
                              {options.map(({id, value}) => {
                                const isMine = id === selectedOption
                                return (
                                  <Stack
                                    isInline
                                    spacing={2}
                                    align="center"
                                    bg={isMine ? 'blue.012' : 'gray.50'}
                                    borderRadius="md"
                                    minH={8}
                                    px={3}
                                    py={2}
                                    zIndex={1}
                                  >
                                    <Flex
                                      align="center"
                                      justify="center"
                                      bg={
                                        isMine ? 'brandBlue.500' : 'transparent'
                                      }
                                      borderRadius="full"
                                      borderWidth={isMine ? 0 : '4px'}
                                      borderColor="gray.100"
                                      color="white"
                                      w={4}
                                      h={4}
                                    >
                                      {isMine && <OkIcon boxSize={3} />}
                                    </Flex>

                                    <Text
                                      isTruncated
                                      maxW="sm"
                                      title={value.length > 50 ? value : ''}
                                    >
                                      {value}
                                    </Text>
                                  </Stack>
                                )
                              })}
                            </Stack>
                          ) : (
                            <RadioGroup
                              value={String(selectedOption)}
                              onChange={value => {
                                send('SELECT_OPTION', {
                                  option: Number(value),
                                })
                              }}
                            >
                              <Stack spacing={2}>
                                {/* eslint-disable-next-line no-shadow */}
                                {options.map(({id, value}) => (
                                  <VotingOption
                                    key={id}
                                    value={String(id)}
                                    isDisabled={eitherIdleState(
                                      VotingStatus.Pending,
                                      VotingStatus.Starting,
                                      VotingStatus.Voted
                                    )}
                                    annotation={
                                      isMaxWinnerThreshold
                                        ? null
                                        : t('{{count}} min. votes required', {
                                            count: toPercent(
                                              winnerThreshold / 100
                                            ),
                                          })
                                    }
                                  >
                                    {value}
                                  </VotingOption>
                                ))}
                              </Stack>
                            </RadioGroup>
                          )}
                        </Box>
                      )}
                    </VotingSkeleton>
                  )}

                  {eitherIdleState(
                    VotingStatus.Counting,
                    VotingStatus.Finishing,
                    VotingStatus.Archived,
                    VotingStatus.Terminating,
                    VotingStatus.Terminated
                  ) && (
                    <VotingSkeleton isLoaded={isLoaded}>
                      <Stack spacing={3}>
                        <Text color="muted" fontSize="sm">
                          {t('Voting results')}
                        </Text>
                        <VotingResult votingService={service} spacing={3} />
                      </Stack>
                    </VotingSkeleton>
                  )}

                  <VotingSkeleton isLoaded={!actionsIsFetching}>
                    <Flex justify="space-between" align="center">
                      <Stack isInline spacing={2}>
                        {eitherIdleState(VotingStatus.Pending) && (
                          <PrimaryButton
                            loadingText={t('Launching')}
                            onClick={() => {
                              send('REVIEW_START_VOTING', {
                                from: coinbase,
                              })
                            }}
                          >
                            {t('Launch')}
                          </PrimaryButton>
                        )}

                        {eitherIdleState(VotingStatus.Open) &&
                          (isOracle ? (
                            <PrimaryButton
                              onClick={() => {
                                if (isMaliciousAdVoting) {
                                  send('FORCE_REJECT')
                                }
                                send('REVIEW')
                              }}
                            >
                              {isMaliciousAdVoting ? t('Reject') : t('Vote')}
                            </PrimaryButton>
                          ) : (
                            <Box>
                              <Tooltip
                                label={t(
                                  'This vote is not available to you. Only validated identities randomly selected to the committee can vote.'
                                )}
                                placement="top"
                                zIndex="tooltip"
                              >
                                <PrimaryButton isDisabled>
                                  {t('Vote')}
                                </PrimaryButton>
                              </Tooltip>
                            </Box>
                          ))}

                        {eitherIdleState(VotingStatus.Counting) && canFinish && (
                          <PrimaryButton
                            isLoading={current.matches(
                              `mining.${VotingStatus.Finishing}`
                            )}
                            loadingText={t('Finishing')}
                            onClick={() => send('FINISH', {from: coinbase})}
                          >
                            {didDetermineWinner
                              ? t('Finish voting')
                              : t('Claim refunds')}
                          </PrimaryButton>
                        )}

                        {eitherIdleState(
                          VotingStatus.Open,
                          VotingStatus.Voting,
                          VotingStatus.Voted,
                          VotingStatus.Counting
                        ) &&
                          canProlong && (
                            <PrimaryButton
                              onClick={() => send('REVIEW_PROLONG_VOTING')}
                            >
                              {t('Prolong voting')}
                            </PrimaryButton>
                          )}

                        {(eitherIdleState(
                          VotingStatus.Voted,
                          VotingStatus.Voting
                        ) ||
                          (eitherIdleState(VotingStatus.Counting) &&
                            !canProlong &&
                            !canFinish)) && (
                          <PrimaryButton as={Box} isDisabled>
                            {t('Vote')}
                          </PrimaryButton>
                        )}

                        {!eitherIdleState(
                          VotingStatus.Terminated,
                          VotingStatus.Terminating
                        ) &&
                          canTerminate && (
                            <PrimaryButton
                              colorScheme="red"
                              variant="solid"
                              _active={{}}
                              onClick={() => send('TERMINATE')}
                            >
                              {t('Terminate')}
                            </PrimaryButton>
                          )}
                      </Stack>

                      <Stack isInline spacing={3} align="center">
                        {eitherIdleState(
                          VotingStatus.Archived,
                          VotingStatus.Terminated
                        ) &&
                          !didDetermineWinner && (
                            <Text color="red.500">
                              {t('No winner selected')}
                            </Text>
                          )}
                        <VDivider />
                        <Stack isInline spacing={2} align="center">
                          {didDetermineWinner ? (
                            <UserTickIcon color="muted" boxSize={4} />
                          ) : (
                            <UserIcon color="muted" boxSize={4} />
                          )}

                          <Text as="span">
                            {/* eslint-disable-next-line no-nested-ternary */}
                            {eitherIdleState(VotingStatus.Counting) ? (
                              <>
                                {t('{{count}} published votes', {
                                  count: accountableVoteCount,
                                })}{' '}
                                {t('out of {{count}}', {
                                  count: voteProofsCount,
                                })}
                              </>
                            ) : eitherIdleState(
                                VotingStatus.Pending,
                                VotingStatus.Open,
                                VotingStatus.Voting,
                                VotingStatus.Voted
                              ) ? (
                              t('{{count}} votes', {
                                count: voteProofsCount,
                              })
                            ) : (
                              t('{{count}} published votes', {
                                count: accountableVoteCount,
                              })
                            )}
                          </Text>
                        </Stack>
                      </Stack>
                    </Flex>
                  </VotingSkeleton>

                  <VotingSkeleton isLoaded={isLoaded}>
                    <Stack spacing={5}>
                      <Box>
                        <Text fontWeight={500}>{t('Recent transactions')}</Text>
                      </Box>
                      <Table style={{tableLayout: 'fixed', fontWeight: 500}}>
                        <Thead>
                          <Tr>
                            <RoundedTh isLeft>{t('Transaction')}</RoundedTh>
                            <RoundedTh>{t('Date and time')}</RoundedTh>
                            <RoundedTh isRight textAlign="right">
                              {t('Amount')}
                            </RoundedTh>
                          </Tr>
                        </Thead>
                        <Tbody>
                          {balanceUpdates.map(
                            ({
                              hash,
                              type,
                              timestamp,
                              from,
                              amount,
                              fee,
                              tips,
                              balanceChange = 0,
                              contractCallMethod,
                            }) => {
                              const isSender = areSameCaseInsensitive(
                                from,
                                coinbase
                              )

                              const txCost =
                                (isSender ? -amount : 0) + balanceChange
                              const totalTxCost =
                                txCost - ((isSender ? fee : 0) + tips)

                              const isCredit = totalTxCost > 0

                              const color =
                                // eslint-disable-next-line no-nested-ternary
                                totalTxCost === 0
                                  ? 'brandGray.500'
                                  : isCredit
                                  ? 'blue.500'
                                  : 'red.500'

                              return (
                                <Tr key={hash}>
                                  <OraclesTxsValueTd>
                                    <Stack isInline>
                                      <Flex
                                        align="center"
                                        justify="center"
                                        bg={isCredit ? 'blue.012' : 'red.012'}
                                        color={color}
                                        borderRadius="lg"
                                        minH={8}
                                        minW={8}
                                      >
                                        {isSender ? (
                                          <ArrowUpIcon boxSize={5} />
                                        ) : (
                                          <ArrowDownIcon boxSize={5} />
                                        )}
                                      </Flex>
                                      <Box isTruncated>
                                        {contractCallMethod ? (
                                          <Text>
                                            {
                                              ContractCallMethod[
                                                contractCallMethod
                                              ]
                                            }
                                          </Text>
                                        ) : (
                                          <Text>
                                            {ContractTransactionType[type]}
                                          </Text>
                                        )}
                                        <SmallText isTruncated title={from}>
                                          {hash}
                                        </SmallText>
                                      </Box>
                                    </Stack>
                                  </OraclesTxsValueTd>
                                  <OraclesTxsValueTd>
                                    <Text>
                                      {new Date(timestamp).toLocaleString()}
                                    </Text>
                                  </OraclesTxsValueTd>
                                  <OraclesTxsValueTd textAlign="right">
                                    <Text
                                      color={color}
                                      overflowWrap="break-word"
                                    >
                                      {toLocaleDna(i18n.language, {
                                        signDisplay: 'exceptZero',
                                      })(txCost)}
                                    </Text>
                                    {isSender && (
                                      <SmallText>
                                        {t('Fee')} {toDna(fee + tips)}
                                      </SmallText>
                                    )}
                                  </OraclesTxsValueTd>
                                </Tr>
                              )
                            }
                          )}
                          {balanceUpdates.length === 0 && (
                            <Tr>
                              <OraclesTxsValueTd colSpan={3}>
                                <FillCenter py={12}>
                                  <Stack spacing={4} align="center">
                                    <CoinsLgIcon
                                      boxSize={20}
                                      color="gray.100"
                                    />

                                    <Text color="muted">
                                      {t('No transactions')}
                                    </Text>
                                  </Stack>
                                </FillCenter>
                              </OraclesTxsValueTd>
                            </Tr>
                          )}
                        </Tbody>
                      </Table>
                    </Stack>
                  </VotingSkeleton>
                </Stack>
              </Box>
              <VotingSkeleton isLoaded={isLoaded} h={isLoaded ? 'auto' : 'lg'}>
                <Box mt={3}>
                  <Box mt={-2} mb={4}>
                    <IconButton
                      icon={<RefreshIcon boxSize={5} />}
                      px={1}
                      pr={3}
                      _focus={null}
                      onClick={() => {
                        send('REFRESH')
                        refetchActions()
                      }}
                    >
                      {t('Refresh')}
                    </IconButton>
                  </Box>
                  {!isClosed && (
                    <Stat mb={8}>
                      <StatLabel as="div" color="muted" fontSize="md">
                        <Stack isInline spacing={2} align="center">
                          <StarIcon boxSize={4} color="white" />
                          <Text fontWeight={500}>{t('Prize pool')}</Text>
                        </Stack>
                      </StatLabel>
                      <StatNumber fontSize="base" fontWeight={500}>
                        {toDna(estimatedTotalReward)}
                      </StatNumber>
                      <Box mt={1}>
                        <IconButton
                          icon={<AddFundIcon boxSize={5} />}
                          onClick={() => {
                            send('ADD_FUND')
                          }}
                        >
                          {t('Add funds')}
                        </IconButton>
                      </Box>
                    </Stat>
                  )}
                  <Stack spacing={6}>
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          <Tooltip
                            label={
                              // eslint-disable-next-line no-nested-ternary
                              Number(votingMinPayment) > 0
                                ? isMaxWinnerThreshold
                                  ? t('Deposit will be refunded')
                                  : t(
                                      'Deposit will be refunded if your vote matches the majority'
                                    )
                                : t('Free voting')
                            }
                            placement="top"
                          >
                            <Text
                              as="span"
                              borderBottom="dotted 1px"
                              borderBottomColor="muted"
                              cursor="help"
                            >
                              {t('Voting deposit')}
                            </Text>
                          </Tooltip>
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(votingMinPayment)}
                        </StatNumber>
                      </Stat>
                    )}
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          <Tooltip
                            label={t('Including your Voting deposit')}
                            placement="top"
                          >
                            <Text
                              as="span"
                              borderBottom="dotted 1px"
                              borderBottomColor="muted"
                              cursor="help"
                            >
                              {t('Min reward')}
                            </Text>
                          </Tooltip>
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(estimatedOracleReward)}
                        </StatNumber>
                      </Stat>
                    )}
                    {!isClosed && (
                      <Stat>
                        <StatLabel color="muted" fontSize="md">
                          {isMaxWinnerThreshold ? (
                            <Text as="span">{t('Your max reward')}</Text>
                          ) : (
                            <Tooltip
                              label={t(
                                `Including a share of minority voters' deposit`
                              )}
                              placement="top"
                            >
                              <Text
                                as="span"
                                borderBottom="dotted 1px"
                                borderBottomColor="muted"
                                cursor="help"
                              >
                                {t('Max reward')}
                              </Text>
                            </Tooltip>
                          )}
                        </StatLabel>
                        <StatNumber fontSize="base" fontWeight={500}>
                          {toDna(estimatedMaxOracleReward)}
                        </StatNumber>
                      </Stat>
                    )}
                    <AsideStat
                      label={t('Committee size')}
                      value={t('{{committeeSize}} oracles', {committeeSize})}
                    />
                    <AsideStat
                      label={t('Quorum required')}
                      value={t('{{count}} votes', {
                        count: quorumVotesCount({quorum, committeeSize}),
                      })}
                    />
                    <AsideStat
                      label={t('Majority threshold')}
                      value={
                        isMaxWinnerThreshold
                          ? t('N/A')
                          : toPercent(winnerThreshold / 100)
                      }
                    />
                    {isClosed && totalReward && (
                      <AsideStat
                        label={t('Prize paid')}
                        value={toDna(totalReward)}
                      />
                    )}
                  </Stack>
                </Box>
              </VotingSkeleton>
            </Stack>
          </Stack>
        </Page>
      </Layout>

      <VoteDrawer
        isOpen={
          eitherState(current, 'review', `mining.${VotingStatus.Voting}`) &&
          !eitherState(
            current,
            `mining.${VotingStatus.Voting}.reviewPendingVote`
          )
        }
        onClose={() => {
          send('CANCEL')
        }}
        // eslint-disable-next-line no-shadow
        option={options.find(({id}) => id === selectedOption)?.value}
        from={coinbase}
        to={contractHash}
        deposit={votingMinPayment}
        publicVotingDuration={publicVotingDuration}
        finishDate={finishDate}
        finishCountingDate={finishCountingDate}
        isLoading={current.matches(`mining.${VotingStatus.Voting}`)}
        onVote={() => {
          send('VOTE', {privateKey})
        }}
      />

      <AddFundDrawer
        isOpen={eitherState(
          current,
          'funding',
          `mining.${VotingStatus.Funding}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        to={contractHash}
        available={identityBalance}
        ownerFee={ownerFee}
        isLoading={current.matches(`mining.${VotingStatus.Funding}`)}
        onAddFund={({amount}) => {
          send('ADD_FUND', {amount, privateKey})
        }}
      />

      <LaunchDrawer
        isOpen={eitherState(
          current,
          `idle.${VotingStatus.Pending}.review`,
          `mining.${VotingStatus.Starting}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        balance={contractBalance}
        requiredBalance={votingMinBalance(minOracleReward, committeeSize)}
        ownerFee={ownerFee}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Starting}`)}
        onLaunch={({amount}) => {
          send('START_VOTING', {amount, privateKey})
        }}
      />

      <FinishDrawer
        isOpen={eitherState(
          current,
          `idle.${VotingStatus.Counting}.finish`,
          `mining.${VotingStatus.Finishing}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Finishing}`)}
        onFinish={() => {
          send('FINISH', {privateKey})
        }}
        hasWinner={didDetermineWinner}
      />

      <ProlongDrawer
        isOpen={eitherState(
          current,
          'prolong',
          `mining.${VotingStatus.Prolonging}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        from={coinbase}
        available={identityBalance}
        isLoading={current.matches(`mining.${VotingStatus.Prolonging}`)}
        onProlong={() => {
          send('PROLONG_VOTING', {privateKey})
        }}
      />

      <TerminateDrawer
        isOpen={eitherState(
          current,
          `idle.terminating`,
          `mining.${VotingStatus.Terminating}`
        )}
        onClose={() => {
          send('CANCEL')
        }}
        contractAddress={contractHash}
        isLoading={current.matches(`mining.${VotingStatus.Terminating}`)}
        onTerminate={() => {
          send('TERMINATE', {privateKey})
        }}
      />

      {pendingVote && (
        <ReviewNewPendingVoteDialog
          isOpen={eitherState(
            current,
            `mining.${VotingStatus.Voting}.reviewPendingVote`
          )}
          onClose={() => {
            send('GOT_IT')
          }}
          vote={pendingVote}
          startCounting={finishDate}
          finishCounting={finishCountingDate}
        />
      )}

      {adCid && (
        <AdPreview
          ad={{...ad, author: issuer}}
          isMalicious={isMaliciousAdVoting}
          {...adPreviewDisclosure}
        />
      )}

      <Dialog
        isOpen={eitherIdleState('redirecting')}
        onClose={() => send('CANCEL')}
      >
        <DialogHeader>{t('Leaving Idena')}</DialogHeader>
        <DialogBody>
          <Text>{t(`You're about to leave Idena.`)}</Text>
          <Text>{t(`Are you sure?`)}</Text>
        </DialogBody>
        <DialogFooter>
          <SecondaryButton onClick={() => send('CANCEL')}>
            {t('Cancel')}
          </SecondaryButton>
          <PrimaryButton onClick={() => send('CONTINUE')}>
            {t('Continue')}
          </PrimaryButton>
        </DialogFooter>
      </Dialog>
    </>
  )
}
Example #8
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function CommunityTranslations({
  keywords,
  isOpen,
  isPending,
  onVote,
  onSuggest,
  onToggle,
}) {
  const {t} = useTranslation()

  const {privateKey} = useAuthState()

  const [wordIdx, setWordIdx] = React.useState(0)

  const [
    descriptionCharactersCount,
    setDescriptionCharactersCount,
  ] = React.useState(150)

  const translations = keywords.translations[wordIdx]

  const lastTranslationId =
    translations && translations.length
      ? translations[translations.length - 1].id
      : wordIdx

  return (
    <Stack spacing={isOpen ? 8 : 0}>
      <IconButton
        icon={<CommunityIcon boxSize={5} />}
        color="brandGray.500"
        px={0}
        _hover={{background: 'transparent'}}
        onClick={onToggle}
      >
        {t('Community translation')}
        <ChevronDownIcon boxSize={5} color="muted" ml={2} />
      </IconButton>
      <Collapse isOpen={isOpen}>
        <Stack spacing={8}>
          <RadioGroup isInline value={wordIdx} onChange={setWordIdx}>
            {keywords.words.map(({id, name}, i) => (
              <FlipKeywordRadio key={id} value={i}>
                {name && capitalize(name)}
              </FlipKeywordRadio>
            ))}
          </RadioGroup>
          {translations.map(({id, name, desc, score}) => (
            <Flex key={id} justify="space-between">
              <FlipKeyword>
                <FlipKeywordName>{name}</FlipKeywordName>
                <FlipKeywordDescription>{desc}</FlipKeywordDescription>
              </FlipKeyword>
              <Stack isInline spacing={2} align="center">
                <VoteButton
                  icon={<UpvoteIcon />}
                  onClick={() => onVote({id, up: true, pk: privateKey})}
                />
                <Flex
                  align="center"
                  justify="center"
                  bg={score < 0 ? 'red.010' : 'green.010'}
                  color={score < 0 ? 'red.500' : 'green.500'}
                  fontWeight={500}
                  rounded="md"
                  minW={12}
                  minH={8}
                  style={{fontVariantNumeric: 'tabular-nums'}}
                >
                  {score}
                </Flex>
                <VoteButton
                  icon={<UpvoteIcon />}
                  color="muted"
                  transform="rotate(180deg)"
                  onClick={() => onVote({id, up: false, pk: privateKey})}
                />
              </Stack>
            </Flex>
          ))}

          {translations.length && <Divider borderColor="gray.100" />}

          <Box>
            <Text fontWeight={500} mb={3}>
              {t('Suggest translation')}
            </Text>
            <form
              key={lastTranslationId}
              onSubmit={e => {
                e.preventDefault()
                const {
                  nameInput: {value: name},
                  descInput: {value: desc},
                } = e.target.elements
                onSuggest({wordIdx, name, desc: desc.trim(), pk: privateKey})
              }}
            >
              <FormControl>
                <Input
                  id="nameInput"
                  placeholder={
                    keywords.words[wordIdx].name
                      ? capitalize(keywords.words[wordIdx].name)
                      : 'Name'
                  }
                  px={3}
                  pt={1.5}
                  pb={2}
                  borderColor="gray.100"
                  mb={2}
                  _placeholder={{
                    color: 'muted',
                  }}
                />
              </FormControl>
              <FormControl position="relative">
                <Textarea
                  id="descInput"
                  placeholder={
                    keywords.words[wordIdx].desc
                      ? capitalize(keywords.words[wordIdx].desc)
                      : 'Description'
                  }
                  mb={6}
                  onChange={e =>
                    setDescriptionCharactersCount(150 - e.target.value.length)
                  }
                />
                <Box
                  color={descriptionCharactersCount < 0 ? 'red.500' : 'muted'}
                  fontSize="sm"
                  position="absolute"
                  right={2}
                  bottom={2}
                  zIndex="docked"
                >
                  {descriptionCharactersCount}
                </Box>
              </FormControl>
              <PrimaryButton
                type="submit"
                display="flex"
                ml="auto"
                isLoading={isPending}
              >
                {t('Send')}
              </PrimaryButton>
            </form>
          </Box>
        </Stack>
      </Collapse>
    </Stack>
  )
}
Example #9
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function ActivateMiningDrawer({
  mode,
  delegationEpoch,
  pendingUndelegation,
  currentEpoch,
  isLoading,
  onChangeMode,
  onActivate,
  onClose,
  ...props
}) {
  const {t} = useTranslation()

  const [delegatee, setDelegatee] = useState(pendingUndelegation)
  const {onCopy, hasCopied} = useClipboard('https://www.idena.io/download')

  const sizeInput = useBreakpointValue(['lg', 'md'])
  const sizeButton = useBreakpointValue(['mdx', 'md'])
  const variantRadio = useBreakpointValue(['mobile', 'bordered'])
  const variantPrimary = useBreakpointValue(['primaryFlat', 'primary'])
  const variantSecondary = useBreakpointValue(['secondaryFlat', 'secondary'])

  const waitForDelegationEpochs =
    3 - (currentEpoch - delegationEpoch) <= 0
      ? 3
      : 3 - (currentEpoch - delegationEpoch)

  return (
    <AdDrawer isMining={isLoading} onClose={onClose} {...props}>
      <DrawerHeader>
        <Flex
          direction="column"
          textAlign={['center', 'start']}
          justify={['space-between', 'flex-start']}
        >
          <Flex
            order={[2, 1]}
            mt={[6, 0]}
            align="center"
            justify="center"
            bg="blue.012"
            h={12}
            w={12}
            rounded="xl"
          >
            <UserIcon boxSize={6} color="blue.500" />
          </Flex>
          <Heading
            order={[1, 2]}
            color="brandGray.500"
            fontSize={['base', 'lg']}
            fontWeight={[['bold', 500]]}
            lineHeight="base"
            mt={[0, 4]}
          >
            {t('Miner status')}
          </Heading>
        </Flex>
      </DrawerHeader>
      <DrawerBody>
        <Stack spacing={[6]} mt={[0, 30]}>
          <FormControl as={Stack} spacing={[1, 3]}>
            <FormLabel
              fontSize={['11px', '13px']}
              fontWieght={['400!important', '500']}
              color={['muted', 'initial']}
              mb={[0, 2]}
              p={0}
            >
              {t('Type')}
            </FormLabel>
            <RadioGroup
              isInline
              d="flex"
              flexDirection={['column', 'row']}
              value={mode}
              onChange={onChangeMode}
            >
              <Radio
                variant={variantRadio}
                value={NodeType.Miner}
                flex={['0 0 56px', 1]}
                fontSize={['base', 'md']}
                fontWeight={['500', '400']}
                px={[4, 2]}
                py={['18px', 2]}
                mr={2}
              >
                {t('Mining')}
              </Radio>
              <Radio
                variant={variantRadio}
                value={NodeType.Delegator}
                flex={['0 0 56px', 1]}
                fontSize={['base', 'md']}
                fontWeight={['500', '400']}
                px={[4, 2]}
                py={['18px', 2]}
              >
                {t('Delegation')}
              </Radio>
            </RadioGroup>
          </FormControl>
          {mode === NodeType.Delegator ? (
            <Stack spacing={5}>
              <FormControl as={Stack} spacing={[0, 3]}>
                <FormLabel fontSize={['base', 'md']}>
                  {t('Delegation address')}
                </FormLabel>
                <Input
                  size={sizeInput}
                  value={delegatee}
                  isDisabled={Boolean(pendingUndelegation)}
                  onChange={e => setDelegatee(e.target.value)}
                />
              </FormControl>
              {pendingUndelegation ? (
                <ErrorAlert>
                  {t(
                    'You have recently disabled delegation. You need to wait for {{count}} epochs to delegate to a new address.',
                    {count: waitForDelegationEpochs}
                  )}
                </ErrorAlert>
              ) : (
                <ErrorAlert alignItems="start" pb="3">
                  <Stack>
                    <Text>
                      {t(
                        'You can lose your stake, all your mining and validation rewards if you delegate your mining status.'
                      )}
                    </Text>
                    <Text>
                      {t('You can disable delegation at the next epoch only.')}
                    </Text>
                  </Stack>
                </ErrorAlert>
              )}
            </Stack>
          ) : (
            <Stack spacing={[4, 5]}>
              <Text fontSize={['mdx', 'md']} mb={[0, 3]}>
                {t(
                  'To activate mining status please download the desktop version of Idena app'
                )}
              </Text>
              <Flex
                borderY={[0, '1px']}
                h={16}
                alignItems="center"
                justifyContent="space-between"
                sx={{
                  '&': {
                    borderColor: 'gray.100',
                  },
                }}
              >
                <Flex w={['100%', 'auto']}>
                  <Stack
                    w={['100%', 'auto']}
                    spacing={[4, 2]}
                    isInline
                    align="center"
                    color="brand.gray"
                  >
                    <Flex
                      shrink={0}
                      boxSize={[8, 5]}
                      align="center"
                      justify="center"
                      backgroundColor={['brandGray.012', 'initial']}
                      borderRadius="10px"
                    >
                      <LaptopIcon boxSize={5} />
                    </Flex>
                    <Flex
                      direction="row"
                      w={['100%', 'auto']}
                      justify={['space-between', 'flex-start']}
                      borderBottom={['1px', 0]}
                      borderColor="gray.100"
                      lineHeight={['48px', 'auto']}
                    >
                      <Text as="span" fontSize={['base', 14]} fontWeight={500}>
                        {t('Desktop App')}
                      </Text>
                      {hasCopied ? (
                        <Text
                          display={['block', 'none']}
                          as="span"
                          color="green.500"
                          fontSize="base"
                          fontWeight={500}
                        >
                          {t('Copied')}
                        </Text>
                      ) : (
                        <FlatButton
                          display={['block', 'none']}
                          onClick={onCopy}
                          fontWeight="500"
                        >
                          {t('Copy link')}
                        </FlatButton>
                      )}
                    </Flex>
                  </Stack>
                </Flex>
                <Flex display={['none', 'flex']}>
                  <Link
                    href="https://www.idena.io/download"
                    target="_blank"
                    color="brandBlue.500"
                    rounded="md"
                    fontWeight={500}
                    fontSize={13}
                  >
                    {t('Download')}
                  </Link>
                </Flex>
              </Flex>
              <Flex
                rounded="md"
                bg="gray.50"
                borderColor="gray.50"
                borderWidth={1}
                px={6}
                py={4}
              >
                <Text color="muted" fontSize={['mdx', 'md']} lineHeight="20px">
                  {t(
                    'Use your private key backup to migrate your account. You can import your private key backup at the Settings page in Idena Desktop app.'
                  )}
                </Text>
              </Flex>
            </Stack>
          )}
        </Stack>

        <PrimaryButton
          display={['flex', 'none']}
          mt={4}
          w="100%"
          fontSize="mobile"
          size="lg"
          isDisabled={mode === NodeType.Miner}
          isLoading={isLoading}
          onClick={() => {
            onActivate({delegatee})
          }}
          loadingText={t('Waiting...')}
        >
          {t('Submit')}
        </PrimaryButton>
      </DrawerBody>
      <DrawerFooter display={['none', 'flex']} mt={[6, 0]} px={0}>
        <Flex width="100%" justify={['space-evenly', 'flex-end']}>
          <Button
            variant={variantSecondary}
            order={[3, 1]}
            size={sizeButton}
            type="button"
            onClick={onClose}
          >
            {t('Cancel')}
          </Button>
          <Divider
            order="2"
            display={['block', 'none']}
            h={10}
            orientation="vertical"
            color="gray.100"
          />
          <Button
            variant={variantPrimary}
            order={[1, 3]}
            size={sizeButton}
            ml={[0, 2]}
            isDisabled={mode === NodeType.Miner}
            isLoading={isLoading}
            onClick={() => {
              onActivate({delegatee})
            }}
            loadingText={t('Waiting...')}
          >
            {t('Submit')}
          </Button>
        </Flex>
      </DrawerFooter>
    </AdDrawer>
  )
}