@material-ui/core#OutlinedInput TypeScript Examples

The following examples show how to use @material-ui/core#OutlinedInput. 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: path_setup.tsx    From jupyter-extensions with Apache License 2.0 6 votes vote down vote up
render(): React.ReactElement {
    return (
      <FormControl
        className={classes(setupItemClass)}
        disabled
        variant="outlined"
      >
        <FormHelperText className={setupHelperTextClass}>
          Repository
        </FormHelperText>
        <OutlinedInput
          className={classes(setupItemInnerClass)}
          value={this.state.path}
          style={{ color: 'var(--jp-ui-font-color0)' }}
        />
      </FormControl>
    );
  }
Example #2
Source File: FilterInput.tsx    From ow-mod-manager with MIT License 6 votes vote down vote up
FilterInput: React.FunctionComponent<Props> = ({
  value,
  onChange,
  label,
}) => {
  const [filterText, setFilterText] = useState(value);
  const debouncedFilterText = useDebounce(filterText, 200);

  useEffect(() => {
    onChange(debouncedFilterText);
  }, [debouncedFilterText, onChange]);

  return (
    <OutlinedInput
      margin="dense"
      onChange={({ currentTarget }) => {
        setFilterText(currentTarget.value);
      }}
      value={filterText}
      placeholder={label}
      color="secondary"
      startAdornment={
        <InputAdornment position="start">
          <SearchIcon />
        </InputAdornment>
      }
      endAdornment={
        filterText !== '' && (
          <InputAdornment position="end">
            <IconButton onClick={() => setFilterText('')} size="small">
              <CloseIcon fontSize="small" />
            </IconButton>
          </InputAdornment>
        )
      }
    />
  );
}
Example #3
Source File: AdvancedSettings.tsx    From lobis-frontend with MIT License 5 votes vote down vote up
function AdvancedSettings({ open, handleClose, slippage, recipientAddress, onRecipientAddressChange, onSlippageChange }: IAdvancedSettingsProps) {
    return (
        <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
            <Paper className="ohm-card ohm-popover">
                <div className="cross-wrap">
                    <IconButton onClick={handleClose}>
                        <SvgIcon color="primary" component={XIcon} />
                    </IconButton>
                </div>

                <Box className="card-content">
                    <InputLabel htmlFor="slippage">
                        <p className="input-lable">Slippage</p>
                    </InputLabel>
                    <FormControl variant="outlined" color="primary" fullWidth>
                        <OutlinedInput
                            id="slippage"
                            value={slippage}
                            onChange={onSlippageChange}
                            fullWidth
                            type="number"
                            //@ts-ignore
                            max="100"
                            min="100"
                            className="bond-input"
                            endAdornment={
                                <InputAdornment position="end">
                                    <p className="percent">%</p>
                                </InputAdornment>
                            }
                        />
                        <div className="help-text">
                            <p className="text-bond-desc">Transaction may revert if price changes by more than slippage %</p>
                        </div>
                    </FormControl>
                </Box>
            </Paper>
        </Modal>
    );
}
Example #4
Source File: AdvancedSettings.tsx    From rugenerous-frontend with MIT License 5 votes vote down vote up
function AdvancedSettings({
  open,
  handleClose,
  slippage,
  recipientAddress,
  onRecipientAddressChange,
  onSlippageChange,
}: IAdvancedSettingsProps) {
  const [value, setValue] = useState(slippage);

  useEffect(() => {
    let timeount: any = null;
    clearTimeout(timeount);

    timeount = setTimeout(() => onSlippageChange(value), 1000);
    return () => clearTimeout(timeount);
  }, [value]);

  return (
    <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
      <Paper className="ohm-card ohm-popover">
        <div className="cross-wrap">
          <IconButton onClick={handleClose}>
            <SvgIcon color="primary" component={XIcon} />
          </IconButton>
        </div>

        <p className="hades-title">Settings</p>

        <Box className="card-content">
          <InputLabel htmlFor="slippage">
            <p className="input-lable">Slippage</p>
          </InputLabel>
          <FormControl variant="outlined" color="primary" fullWidth>
            <OutlinedInput
              id="slippage"
              value={value}
              onChange={(e: any) => setValue(e.target.value)}
              fullWidth
              type="number"
              className="bond-input"
              endAdornment={
                <InputAdornment position="end">
                  <p className="percent">%</p>
                </InputAdornment>
              }
            />
            <div className="help-text">
              <p className="text-bond-desc">Transaction may revert if price changes by more than slippage %</p>
            </div>
          </FormControl>

          <InputLabel htmlFor="recipient">
            <p className="input-lable">Recipient Address</p>
          </InputLabel>
          <FormControl variant="outlined" color="primary" fullWidth>
            <OutlinedInput
              className="bond-input"
              id="recipient"
              value={recipientAddress}
              onChange={onRecipientAddressChange}
              type="text"
            />
            <div className="help-text">
              <p className="text-bond-desc">
                Choose recipient address. By default, this is your currently connected address
              </p>
            </div>
          </FormControl>
        </Box>
      </Paper>
    </Modal>
  );
}
Example #5
Source File: index.tsx    From rugenerous-frontend with MIT License 5 votes vote down vote up
function ChooseToken({ open, handleClose, handleSelect, bond }: IChooseTokenProps) {
  const { tokens, loading } = useTokens();

  const [quantity, setQuantity] = useState("");

  const filtredTokens = tokens.filter(({ name, address, isAvax }) => {
    let addressTest = true;

    if (quantity && quantity.length === 42) {
      addressTest = address.toLocaleLowerCase() === quantity.toLowerCase();
    }

    let nameTest = true;

    if (quantity && quantity.length < 10) {
      nameTest = name.toLowerCase().includes(quantity.toLowerCase());
    }

    let lpFilter = true;

    if (bond.name === mim.name) {
      lpFilter = mimToken.address !== address;
    }

    // if (bond.name === wavax.name) {
    //   lpFilter = isAvax ? false : wavaxToken.address !== address;
    // }

    return nameTest && addressTest && lpFilter;
  });

  return (
    <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
      <Paper className="ohm-card ohm-popover choose-token-poper">
        <div className="cross-wrap">
          <IconButton onClick={handleClose}>
            <SvgIcon color="primary" component={XIcon} />
          </IconButton>
        </div>
        <Box>
          <div className="choose-token-poper-header">
            <p className="choose-token-poper-header-title">Choose token</p>
            <OutlinedInput
              placeholder="Search name or paste address"
              className="choose-token-poper-header-input"
              value={quantity}
              onChange={e => setQuantity(e.target.value)}
              labelWidth={0}
              startAdornment={
                <InputAdornment position="start">
                  <Box display="flex" alignItems="center" justifyContent="center" width={"24px"}>
                    <img src={IconsSearch} style={{ height: "24px", width: "24px" }} />
                  </Box>
                </InputAdornment>
              }
            />
          </div>

          <div className="choose-token-poper-body">
            {filtredTokens.map(token => (
              <div onClick={() => handleSelect(token)} key={token.address} className="choose-token-poper-body-item">
                <img className="choose-token-poper-body-item-img" src={token.img} alt="" />
                <div className="choose-token-poper-body-item-desc">
                  <p className="choose-token-poper-body-item-name">{token.name}</p>
                  <div className="choose-token-poper-body-item-balance">
                    {loading ? <Skeleton width="50px" /> : <p>{trim(token.balance, 6)}</p>}
                  </div>
                </div>
              </div>
            ))}
          </div>
        </Box>
      </Paper>
    </Modal>
  );
}
Example #6
Source File: MaxDepthFilter.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
MaxDepthFilter = ({ value, onChange }: Props) => {
  const classes = useStyles();

  const handleChange = useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const v = Number(event.target.value);
      onChange(v <= 0 ? Number.POSITIVE_INFINITY : v);
    },
    [onChange],
  );

  const reset = useCallback(() => {
    onChange(Number.POSITIVE_INFINITY);
  }, [onChange]);

  return (
    <Box pb={1} pt={1}>
      <FormControl variant="outlined" className={classes.formControl}>
        <Typography variant="button">Max Depth</Typography>
        <OutlinedInput
          type="number"
          placeholder="∞ Infinite"
          value={isFinite(value) ? value : ''}
          onChange={handleChange}
          endAdornment={
            <InputAdornment position="end">
              <IconButton
                aria-label="clear max depth"
                onClick={reset}
                edge="end"
              >
                <ClearIcon />
              </IconButton>
            </InputAdornment>
          }
          inputProps={{
            'aria-label': 'maxp',
          }}
          labelWidth={0}
        />
      </FormControl>
    </Box>
  );
}
Example #7
Source File: index.tsx    From wonderland-frontend with MIT License 5 votes vote down vote up
function ChooseToken({ open, handleClose, handleSelect, bond }: IChooseTokenProps) {
    const { tokens, loading } = useTokens();

    const [quantity, setQuantity] = useState("");

    const filtredTokens = tokens.filter(({ name, address, isAvax }) => {
        let addressTest = true;

        if (quantity && quantity.length === 42) {
            addressTest = address.toLocaleLowerCase() === quantity.toLowerCase();
        }

        let nameTest = true;

        if (quantity && quantity.length < 10) {
            nameTest = name.toLowerCase().includes(quantity.toLowerCase());
        }

        let lpFilter = true;

        if (bond.name === mim.name) {
            lpFilter = mimToken.address !== address;
        }

        if (bond.name === wavax.name) {
            lpFilter = isAvax ? false : wavaxToken.address !== address;
        }

        return nameTest && addressTest && lpFilter;
    });

    return (
        <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
            <Paper className="ohm-card ohm-popover choose-token-poper">
                <div className="cross-wrap">
                    <IconButton onClick={handleClose}>
                        <SvgIcon color="primary" component={XIcon} />
                    </IconButton>
                </div>
                <Box>
                    <div className="choose-token-poper-header">
                        <p className="choose-token-poper-header-title">Choose token</p>
                        <OutlinedInput
                            placeholder="Search name or paste address"
                            className="choose-token-poper-header-input"
                            value={quantity}
                            onChange={e => setQuantity(e.target.value)}
                            labelWidth={0}
                            startAdornment={
                                <InputAdornment position="start">
                                    <Box display="flex" alignItems="center" justifyContent="center" width={"24px"}>
                                        <img src={IconsSearch} style={{ height: "24px", width: "24px" }} />
                                    </Box>
                                </InputAdornment>
                            }
                        />
                    </div>

                    <div className="choose-token-poper-body">
                        {filtredTokens.map(token => (
                            <div onClick={() => handleSelect(token)} key={token.address} className="choose-token-poper-body-item">
                                <img className="choose-token-poper-body-item-img" src={token.img} alt="" />
                                <div className="choose-token-poper-body-item-desc">
                                    <p className="choose-token-poper-body-item-name">{token.name}</p>
                                    <div className="choose-token-poper-body-item-balance">{loading ? <Skeleton width="50px" /> : <p>{trim(token.balance, 6)}</p>}</div>
                                </div>
                            </div>
                        ))}
                    </div>
                </Box>
            </Paper>
        </Modal>
    );
}
Example #8
Source File: AdvancedSettings.tsx    From wonderland-frontend with MIT License 5 votes vote down vote up
function AdvancedSettings({ open, handleClose, slippage, onSlippageChange }: IAdvancedSettingsProps) {
    const [value, setValue] = useState(slippage);

    useEffect(() => {
        let timeount: any = null;
        clearTimeout(timeount);

        timeount = setTimeout(() => onSlippageChange(value), 1000);
        return () => clearTimeout(timeount);
    }, [value]);

    return (
        <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
            <Paper className="ohm-card ohm-popover">
                <div className="cross-wrap">
                    <IconButton onClick={handleClose}>
                        <SvgIcon color="primary" component={XIcon} />
                    </IconButton>
                </div>

                <p className="hades-title">Settings</p>

                <Box className="card-content">
                    <InputLabel htmlFor="slippage">
                        <p className="input-lable">Slippage</p>
                    </InputLabel>
                    <FormControl variant="outlined" color="primary" fullWidth>
                        <OutlinedInput
                            id="slippage"
                            value={value}
                            onChange={(e: any) => setValue(e.target.value)}
                            fullWidth
                            type="number"
                            className="bond-input"
                            endAdornment={
                                <InputAdornment position="end">
                                    <p className="percent">%</p>
                                </InputAdornment>
                            }
                        />
                        <div className="help-text">
                            <p className="text-bond-desc">Transaction may revert if price changes by more than slippage %</p>
                        </div>
                    </FormControl>
                </Box>
            </Paper>
        </Modal>
    );
}
Example #9
Source File: App.tsx    From isitworththecost with MIT License 4 votes vote down vote up
function App() {
    const classes = useStyles()

    const [values, setValues] = React.useState({
        timeCost: { value: 25, unit: 'dollars', period: 'hour' },
        serviceCost: { value: 125, unit: 'dollars', period: 'month' },
        trainingTime: { value: 2, unit: 'hour', period: null },
        timeSavings: { value: 60, unit: 'min', period: 'day' },
        peopleCount: { value: 1, unit: null, period: null },

        savingPeriodCost: 'year',
        savingPeriodPeople: 'day',
        paybackPeriod: 'day',
    })

    const [costs, setCosts] = React.useState({
        employeePerYear: 0,
        servicePerYear: 0,
        trainingPerYear: 0,
        savingsPerYear: 0,
        freeTimePerYear: 0,
        paybackTimePerYear: 0,
    })

    const handleChange = (prop: string, key: string | null = null) => (
        event: ChangeEvent<HTMLInputElement | { value: unknown }>,
    ): void => {
        let val: any = event.target.value
        if (key === null) {
            setValues({
                ...values,
                [prop]: val,
            })
        } else {
            if (key === 'value' && (val < 0 || isNaN(val))) {
                val = 0
            }
            setValues({
                ...values,
                [prop]: {
                    //@ts-ignore
                    value: values[prop].value,
                    //@ts-ignore
                    unit: values[prop].unit,
                    //@ts-ignore
                    period: values[prop].period,
                    //@ts-ignore
                    [key]: val,
                },
            })
        }
    }

    useEffect(() => {
        // save this to state for now for ease of visibility
        const employeePerYear =
            values.timeCost.value * periodToYear(values.timeCost.period, 1)
        const servicePerYear =
            values.serviceCost.value *
            periodToYear(values.serviceCost.period, 1)

        // assumes amortisation period of 1 year
        const trainingPerYear =
            unitToYear(values.trainingTime.unit, values.trainingTime.value) *
            employeePerYear *
            values.peopleCount.value

        const freeTimePerYear =
            periodToYear(
                values.timeSavings.period,
                unitToYear(values.timeSavings.unit, values.timeSavings.value),
            ) * values.peopleCount.value

        const savingsPerYear =
            employeePerYear * freeTimePerYear - servicePerYear - trainingPerYear

        const paybackTimePerYear =
            (trainingPerYear + servicePerYear) / employeePerYear

        setCosts({
            employeePerYear,
            servicePerYear,
            trainingPerYear,
            savingsPerYear,
            freeTimePerYear,
            paybackTimePerYear,
        })
    }, [values])

    return (
        <Container maxWidth={'md'}>
            <Paper className={classes.root} variant={'outlined'}>
                <div className={classes.heading}>
                    <TopControls />
                    <Typography variant="h2" component="h1">
                        Is it worth the cost?
                    </Typography>
                    <Typography variant="h5" component="p" gutterBottom>
                        A simple check on whether purchasing a service is worth
                        the cost.
                    </Typography>
                </div>
                <Grid container>
                    <Grid item xs={12} md={6}>
                        <h2>Basics</h2>
                        <p>1. Cost of your time or an employees time.</p>
                        <FormControl
                            className={clsx(classes.margin, classes.textField)}
                            variant="outlined"
                        >
                            <InputLabel htmlFor="time-cost">
                                Time Cost
                            </InputLabel>
                            <OutlinedInput
                                id="time-cost"
                                value={values.timeCost.value}
                                type="number"
                                onChange={handleChange('timeCost', 'value')}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <AttachMoneyIcon />
                                    </InputAdornment>
                                }
                                labelWidth={80}
                            />
                        </FormControl>
                        <FormControl
                            variant="outlined"
                            className={classes.margin}
                        >
                            <InputLabel htmlFor="time-cost-unit">
                                per
                            </InputLabel>
                            <Select
                                native
                                value={values.timeCost.period}
                                onChange={handleChange('timeCost', 'period')}
                                labelWidth={40}
                                inputProps={{
                                    name: 'per',
                                    id: 'time-cost-unit',
                                }}
                            >
                                <option value={'hour'}>hour</option>
                                <option value={'day'}>day</option>
                                <option value={'week'}>week</option>
                                <option value={'month'}>month</option>
                                <option value={'year'}>year</option>
                            </Select>
                        </FormControl>
                        <p>2. Cost of the service under consideration.</p>
                        <FormControl
                            className={clsx(classes.margin, classes.textField)}
                            variant="outlined"
                        >
                            <InputLabel htmlFor="service-cost">
                                Service Cost
                            </InputLabel>
                            <OutlinedInput
                                id="service-cost"
                                value={values.serviceCost.value}
                                type="number"
                                onChange={handleChange('serviceCost', 'value')}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <AttachMoneyIcon />
                                    </InputAdornment>
                                }
                                labelWidth={95}
                            />
                        </FormControl>
                        <FormControl
                            variant="outlined"
                            className={classes.margin}
                        >
                            <InputLabel htmlFor="service-cost-period">
                                per
                            </InputLabel>
                            <Select
                                native
                                value={values.serviceCost.period}
                                onChange={handleChange('serviceCost', 'period')}
                                labelWidth={40}
                                inputProps={{
                                    name: 'per',
                                    id: 'service-cost-period',
                                }}
                            >
                                {/*<option value={'hour'}>hour</option>*/}
                                <option value={'day'}>day</option>
                                <option value={'week'}>week</option>
                                <option value={'month'}>month</option>
                                <option value={'year'}>year</option>
                            </Select>
                        </FormControl>
                        <p>
                            3. Estimate the training time required (one person).
                        </p>
                        <FormControl
                            fullWidth
                            className={clsx(classes.margin, classes.textField)}
                            variant="outlined"
                        >
                            <InputLabel htmlFor="training-time">
                                Training Time
                            </InputLabel>
                            <OutlinedInput
                                id="training-time"
                                value={values.trainingTime.value}
                                type="number"
                                onChange={handleChange('trainingTime', 'value')}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <AccessTimeIcon />
                                    </InputAdornment>
                                }
                                labelWidth={105}
                            />
                        </FormControl>
                        <FormControl
                            variant="outlined"
                            className={classes.margin}
                        >
                            <Select
                                native
                                value={values.trainingTime.unit}
                                onChange={handleChange('trainingTime', 'unit')}
                                inputProps={{
                                    name: 'per',
                                    id: 'training-time-unit',
                                }}
                            >
                                <option value={'hour'}>hours</option>
                                <option value={'day'}>days</option>
                                <option value={'week'}>weeks</option>
                                <option value={'month'}>months</option>
                                {/*<option value={'year'}>years</option>*/}
                            </Select>
                        </FormControl>
                        <p>
                            4. Estimate the time this service will save (one
                            person).
                        </p>
                        <FormControl
                            className={clsx(classes.margin, classes.textField)}
                            variant="outlined"
                        >
                            <InputLabel htmlFor="time-savings">
                                Time Saved
                            </InputLabel>
                            <OutlinedInput
                                id="time-savings"
                                type="number"
                                value={values.timeSavings.value}
                                onChange={handleChange('timeSavings', 'value')}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <AccessTimeIcon />
                                    </InputAdornment>
                                }
                                labelWidth={80}
                            />
                        </FormControl>
                        <FormControl
                            variant="outlined"
                            className={classes.margin}
                        >
                            <Select
                                native
                                value={values.timeSavings.unit}
                                onChange={handleChange('timeSavings', 'unit')}
                            >
                                <option value={'minute'}>minutes</option>
                                <option value={'hour'}>hours</option>
                                <option value={'day'}>days</option>
                                <option value={'week'}>weeks</option>
                                <option value={'month'}>months</option>
                            </Select>
                        </FormControl>
                        <FormControl
                            variant="outlined"
                            className={classes.margin}
                        >
                            <InputLabel htmlFor="time-savings-period">
                                per
                            </InputLabel>
                            <Select
                                id={'time-savings-period'}
                                native
                                value={values.timeSavings.period}
                                onChange={handleChange('timeSavings', 'period')}
                                labelWidth={40}
                            >
                                <option value={'hour'}>hour</option>
                                <option value={'day'}>day</option>
                                <option value={'week'}>week</option>
                                <option value={'month'}>month</option>
                                <option value={'year'}>year</option>
                            </Select>
                        </FormControl>
                        <p>5. Number of people using the service.</p>
                        <FormControl
                            className={clsx(classes.margin, classes.textField)}
                            variant="outlined"
                        >
                            <InputLabel htmlFor="people-count">
                                People
                            </InputLabel>
                            <OutlinedInput
                                id="people-count"
                                type="number"
                                value={values.peopleCount.value}
                                onChange={handleChange('peopleCount', 'value')}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <EmojiPeopleIcon />
                                    </InputAdornment>
                                }
                                labelWidth={50}
                            />
                        </FormControl>
                    </Grid>
                    <Grid item xs={12} md={6}>
                        <Breakdown
                            values={values}
                            costs={costs}
                            handleChange={handleChange}
                        />
                    </Grid>
                </Grid>
            </Paper>
        </Container>
    )
}
Example #10
Source File: OrganizationList.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
OrganizationList: React.SFC<OrganizationListProps> = ({
  match,
  openExtensionModal,
  openCustomerModal,
}) => {
  const { t } = useTranslation();

  const [orgName, setOrgName] = useState('');
  const history = useHistory();

  const columnNames = ['NAME', 'STATUS', 'ACTIONS'];

  const getName = (label: string, insertedAt: any) => (
    <div className={styles.LabelContainer}>
      <p className={styles.LabelText}>
        {label}
        <br />
        <span className={styles.SubLabelText}>{moment(insertedAt).format('DD MMM YYYY')}</span>
      </p>
    </div>
  );

  const [updateOrganizationStatus] = useMutation(UPDATE_ORGANIZATION_STATUS, {
    onCompleted: () => {
      setNotification('Organization updated successfully');
    },
  });

  const getStatus = (id: any, status: string) => {
    const options = [
      { id: 'INACTIVE', label: <div className={styles.Inactive}>Inactive</div> },
      { id: 'APPROVED', label: 'Approved' },
      { id: 'ACTIVE', label: 'Active' },
      { id: 'SUSPENDED', label: 'Suspended' },
      { id: 'READY_TO_DELETE', label: <div className={styles.Delete}>Ready to delete</div> },
    ];

    const statusField = {
      onChange: (event: any) => {
        updateOrganizationStatus({
          variables: {
            updateOrganizationId: id,
            status: event.target.value,
          },
        });
      },
      value: status,
      style: { width: '187px' },
    };
    return <Dropdown options={options} placeholder="" field={statusField} />;
  };

  const columnStyles: any = [styles.Label, styles.Status, styles.Actions];

  const getColumns = ({ id, name, insertedAt, status }: any) => ({
    name: getName(name, insertedAt),
    isApproves: getStatus(id, status),
  });

  const columnAttributes = {
    columnNames,
    columns: getColumns,
    columnStyles,
  };

  const listIcon = <OrganisationIcon className={styles.OrgIcon} />;
  const extensionIcon = <ExtensionIcon className={styles.ExtensionIcon} />;

  const customerDetailsIcon = <CustomerDetailsIcon />;

  const [deleteInActiveOrg] = useMutation(DELETE_INACTIVE_ORGANIZATIONS);

  const handleDeleteInActiveOrg = ({ payload, refetch, setDeleteItemID }: any) => {
    deleteInActiveOrg({ variables: payload, refetchQueries: refetch });
    // Setting delete item id to null to prevent showing dialogue again
    setDeleteItemID(null);
    setNotification('Organization deleted successfully');
  };

  const deleteDialogue = (id: any, name: any) => {
    const component = (
      <div>
        <p className={styles.DialogSubText}>
          This action cannot be undone. Please enter the name of organization to proceed
        </p>
        <OutlinedInput
          fullWidth
          placeholder="Organization name"
          onChange={(event: any) => setOrgName(event.target.value)}
          className={styles.DialogSubInput}
        />
      </div>
    );

    const isConfirmed = orgName === name;
    const payload = {
      isConfirmed,
      deleteOrganizationID: id,
    };
    return {
      component,
      handleOkCallback: (val: any) => handleDeleteInActiveOrg({ payload, ...val }),
      isConfirmed,
    };
  };

  const addExtension = (id: any) => {
    history.push({ pathname: `/organizations/${id}/extensions` });
  };

  const addCustomer = (id: any) => {
    history.push({ pathname: `/organizations/${id}/customer` });
  };

  const dialogMessage = deleteDialogue;

  const additionalActions = [
    {
      icon: extensionIcon,
      parameter: 'id',
      label: t('Extension code'),
      dialog: addExtension,
    },
    {
      icon: customerDetailsIcon,
      parameter: 'id',
      label: t('Add/View Customer'),
      dialog: addCustomer,
    },
  ];
  const addNewButton = { show: false, label: 'Add New' };
  const restrictedAction = (listItem: any) => {
    if (listItem.status === 'READY_TO_DELETE') {
      return { delete: true, edit: false };
    }
    return { delete: false, edit: false };
  };

  return (
    <>
      <List
        title={t('Organizations')}
        listItem="organizations"
        listItemName="organization"
        pageLink="organization"
        listIcon={listIcon}
        dialogMessage={dialogMessage}
        additionalAction={additionalActions}
        button={addNewButton}
        restrictedAction={restrictedAction}
        searchParameter={['name']}
        editSupport={false}
        {...queries}
        {...columnAttributes}
      />
      <Extensions openDialog={!!openExtensionModal} match={match} />
      <OrganizationCustomer openDialog={!!openCustomerModal} match={match} />
    </>
  );
}
Example #11
Source File: AddToMessageTemplate.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
AddToMessageTemplate: React.SFC<AddToMessageTemplateProps> = ({
  id,
  message,
  changeDisplay,
}) => {
  const [messageTemplate, setMessageTemplate] = useState<string | null>('');
  const [required, setRequired] = useState(false);
  const { t } = useTranslation();

  const [saveTemplate] = useMutation(SAVE_MESSAGE_TEMPLATE_MUTATION, {
    onCompleted: () => {
      setNotification(t('Message has been successfully added to speed sends.'));
    },
    refetchQueries: [
      {
        query: FILTER_TEMPLATES,
        variables: setVariables({ term: '' }),
      },
    ],
  });

  const onChange = (event: any) => {
    setMessageTemplate(event.target.value);
    if (required) {
      setRequired(false);
    }
  };

  const textField = (
    <div className={styles.DialogContainer} data-testid="templateContainer">
      <FormControl fullWidth error={required}>
        <InputLabel variant="outlined">Enter title</InputLabel>
        <OutlinedInput
          error={required}
          classes={{
            notchedOutline: styles.InputBorder,
          }}
          className={styles.Label}
          label={t('Enter title')}
          fullWidth
          data-testid="templateInput"
          onChange={onChange}
        />
        {required ? <FormHelperText>{t('Required')}</FormHelperText> : null}
      </FormControl>
      <div className={styles.Message}>{WhatsAppToJsx(message)}</div>
    </div>
  );

  const handleCloseButton = () => {
    changeDisplay(false);
    setMessageTemplate(null);
  };

  const handleOKButton = () => {
    if (messageTemplate === '') {
      setRequired(true);
    } else {
      saveTemplate({
        variables: {
          messageId: id,
          templateInput: {
            label: messageTemplate,
            shortcode: messageTemplate,
            languageId: '2',
          },
        },
      });
      changeDisplay(false);
      setMessageTemplate(null);
    }
  };

  return (
    <div>
      <DialogBox
        handleCancel={handleCloseButton}
        handleOk={handleOKButton}
        title={t('Add message to speed sends')}
        buttonOk={t('Save')}
      >
        {textField}
      </DialogBox>
    </div>
  );
}
Example #12
Source File: Input.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
Input: React.SFC<InputProps> = ({ textArea = false, disabled = false, ...props }) => {
  const {
    field,
    form,
    helperText,
    type,
    togglePassword,
    endAdornmentCallback,
    emojiPicker,
    placeholder,
    editor,
    rows,
    endAdornment,
    inputProp,
    translation,
  } = props;

  let fieldType = type;
  let fieldEndAdorment = null;
  if (type === 'password') {
    // we should change the type to text if user has clicked on show password
    if (togglePassword) {
      fieldType = 'text';
    }
    fieldEndAdorment = (
      <InputAdornment position="end">
        <IconButton
          aria-label="toggle password visibility"
          data-testid="passwordToggle"
          onClick={endAdornmentCallback}
          edge="end"
        >
          {togglePassword ? (
            <Visibility classes={{ root: styles.Visibility }} />
          ) : (
            <VisibilityOff classes={{ root: styles.Visibility }} />
          )}
        </IconButton>
      </InputAdornment>
    );
  } else if (emojiPicker) {
    fieldEndAdorment = emojiPicker;
  } else if (type === 'otp') {
    fieldType = 'text';
    fieldEndAdorment = (
      <InputAdornment position="end">
        <IconButton
          aria-label="resend otp"
          data-testid="resendOtp"
          onClick={endAdornmentCallback}
          edge="end"
        >
          <p className={styles.Resend}>resend</p>{' '}
          <RefreshIcon classes={{ root: styles.ResendButton }} />
        </IconButton>
      </InputAdornment>
    );
  }

  let showError = false;
  if (form && form.errors[field.name] && form.touched[field.name]) {
    showError = true;
  }

  return (
    <>
      {translation && <div className={styles.Translation}>{translation}</div>}
      <div className={styles.Input} data-testid="input">
        <FormControl fullWidth error={showError}>
          <InputLabel variant="outlined" className={styles.Label} data-testid="inputLabel">
            {placeholder}
          </InputLabel>
          <OutlinedInput
            data-testid="outlinedInput"
            inputComponent={editor ? editor.inputComponent : undefined}
            inputProps={editor ? editor.inputProps : inputProp}
            type={fieldType}
            classes={{ multiline: styles.Multiline }}
            disabled={disabled}
            error={showError}
            multiline={textArea}
            rows={rows}
            className={styles.OutlineInput}
            label={placeholder}
            fullWidth
            {...field}
            endAdornment={endAdornment || fieldEndAdorment}
          />
          {form && form.errors[field.name] && form.touched[field.name] ? (
            <FormHelperText className={styles.DangerText}>{form.errors[field.name]}</FormHelperText>
          ) : null}
          {helperText && (
            <div id="helper-text" className={styles.HelperText}>
              {helperText}
            </div>
          )}
        </FormControl>
      </div>
    </>
  );
}
Example #13
Source File: index.tsx    From wonderland-frontend with MIT License 4 votes vote down vote up
function Stake() {
    const dispatch = useDispatch();
    const { provider, address, connect, chainID, checkWrongNetwork } = useWeb3Context();

    const [view, setView] = useState(0);
    const [quantity, setQuantity] = useState<string>("");

    const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
    const currentIndex = useSelector<IReduxState, string>(state => {
        return state.app.currentIndex;
    });
    const fiveDayRate = useSelector<IReduxState, number>(state => {
        return state.app.fiveDayRate;
    });
    const timeBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.time;
    });
    const memoBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.memo;
    });
    const stakeAllowance = useSelector<IReduxState, number>(state => {
        return state.account.staking && state.account.staking.time;
    });
    const unstakeAllowance = useSelector<IReduxState, number>(state => {
        return state.account.staking && state.account.staking.memo;
    });
    const stakingRebase = useSelector<IReduxState, number>(state => {
        return state.app.stakingRebase;
    });
    const stakingAPY = useSelector<IReduxState, number>(state => {
        return state.app.stakingAPY;
    });
    const stakingTVL = useSelector<IReduxState, number>(state => {
        return state.app.stakingTVL;
    });

    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    const setMax = () => {
        if (view === 0) {
            setQuantity(timeBalance);
        } else {
            setQuantity(memoBalance);
        }
    };

    const onSeekApproval = async (token: string) => {
        if (await checkWrongNetwork()) return;

        await dispatch(changeApproval({ address, token, provider, networkID: chainID }));
    };

    const onChangeStake = async (action: string) => {
        if (await checkWrongNetwork()) return;
        if (quantity === "" || parseFloat(quantity) === 0) {
            dispatch(warning({ text: action === "stake" ? messages.before_stake : messages.before_unstake }));
        } else {
            await dispatch(changeStake({ address, action, value: String(quantity), provider, networkID: chainID }));
            setQuantity("");
        }
    };

    const hasAllowance = useCallback(
        token => {
            if (token === "time") return stakeAllowance > 0;
            if (token === "memo") return unstakeAllowance > 0;
            return 0;
        },
        [stakeAllowance],
    );

    const changeView = (newView: number) => () => {
        setView(newView);
        setQuantity("");
    };

    const trimmedMemoBalance = trim(Number(memoBalance), 6);
    const trimmedStakingAPY = trim(stakingAPY * 100, 1);
    const stakingRebasePercentage = trim(stakingRebase * 100, 4);
    const nextRewardValue = trim((Number(stakingRebasePercentage) / 100) * Number(trimmedMemoBalance), 6);

    return (
        <div className="stake-view">
            <Zoom in={true}>
                <div className="stake-card">
                    <Grid className="stake-card-grid" container direction="column" spacing={2}>
                        <Grid item>
                            <div className="stake-card-header">
                                <p className="stake-card-header-title">TIME Staking (?, ?)</p>
                                <RebaseTimer />
                            </div>
                        </Grid>

                        <Grid item>
                            <div className="stake-card-metrics">
                                <Grid container spacing={2}>
                                    <Grid item xs={12} sm={4} md={4} lg={4}>
                                        <div className="stake-card-apy">
                                            <p className="stake-card-metrics-title">APY</p>
                                            <p className="stake-card-metrics-value">
                                                {stakingAPY ? <>{new Intl.NumberFormat("en-US").format(Number(trimmedStakingAPY))}%</> : <Skeleton width="150px" />}
                                            </p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="stake-card-tvl">
                                            <p className="stake-card-metrics-title">TVL</p>
                                            <p className="stake-card-metrics-value">
                                                {stakingTVL ? (
                                                    new Intl.NumberFormat("en-US", {
                                                        style: "currency",
                                                        currency: "USD",
                                                        maximumFractionDigits: 0,
                                                        minimumFractionDigits: 0,
                                                    }).format(stakingTVL)
                                                ) : (
                                                    <Skeleton width="150px" />
                                                )}
                                            </p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="stake-card-index">
                                            <p className="stake-card-metrics-title">Current Index</p>
                                            <p className="stake-card-metrics-value">{currentIndex ? <>{trim(Number(currentIndex), 2)} TIME</> : <Skeleton width="150px" />}</p>
                                        </div>
                                    </Grid>
                                </Grid>
                            </div>
                        </Grid>

                        <div className="stake-card-area">
                            {!address && (
                                <div className="stake-card-wallet-notification">
                                    <div className="stake-card-wallet-connect-btn" onClick={connect}>
                                        <p>Connect Wallet</p>
                                    </div>
                                    <p className="stake-card-wallet-desc-text">Connect your wallet to stake TIME tokens!</p>
                                </div>
                            )}
                            {address && (
                                <div>
                                    <div className="stake-card-action-area">
                                        <div className="stake-card-action-stage-btns-wrap">
                                            <div onClick={changeView(0)} className={classnames("stake-card-action-stage-btn", { active: !view })}>
                                                <p>Stake</p>
                                            </div>
                                            <div onClick={changeView(1)} className={classnames("stake-card-action-stage-btn", { active: view })}>
                                                <p>Unstake</p>
                                            </div>
                                        </div>

                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder="Amount"
                                                className="stake-card-action-input"
                                                value={quantity}
                                                onChange={e => setQuantity(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={setMax} className="stake-card-action-input-btn">
                                                            <p>Max</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />

                                            {view === 0 && (
                                                <div className="stake-card-tab-panel">
                                                    {address && hasAllowance("time") ? (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "staking")) return;
                                                                onChangeStake("stake");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "staking", "Stake TIME")}</p>
                                                        </div>
                                                    ) : (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "approve_staking")) return;
                                                                onSeekApproval("time");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "approve_staking", "Approve")}</p>
                                                        </div>
                                                    )}
                                                </div>
                                            )}

                                            {view === 1 && (
                                                <div className="stake-card-tab-panel">
                                                    {address && hasAllowance("memo") ? (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "unstaking")) return;
                                                                onChangeStake("unstake");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "unstaking", "Unstake TIME")}</p>
                                                        </div>
                                                    ) : (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "approve_unstaking")) return;
                                                                onSeekApproval("memo");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "approve_unstaking", "Approve")}</p>
                                                        </div>
                                                    )}
                                                </div>
                                            )}
                                        </div>

                                        <div className="stake-card-action-help-text">
                                            {address && ((!hasAllowance("time") && view === 0) || (!hasAllowance("memo") && view === 1)) && (
                                                <p>
                                                    Note: The "Approve" transaction is only needed when staking/unstaking for the first time; subsequent staking/unstaking only
                                                    requires you to perform the "Stake" or "Unstake" transaction.
                                                </p>
                                            )}
                                        </div>
                                    </div>

                                    <div className="stake-user-data">
                                        <div className="data-row">
                                            <p className="data-row-name">Your Balance</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(timeBalance), 4)} TIME</>}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Your Staked Balance</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{trimmedMemoBalance} MEMO</>}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Next Reward Amount</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{nextRewardValue} MEMO</>}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Next Reward Yield</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{stakingRebasePercentage}%</>}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">ROI (5-Day Rate)</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(fiveDayRate) * 100, 4)}%</>}</p>
                                        </div>
                                    </div>
                                </div>
                            )}
                        </div>
                    </Grid>
                </div>
            </Zoom>
        </div>
    );
}
Example #14
Source File: index.tsx    From wonderland-frontend with MIT License 4 votes vote down vote up
function Calculator() {
    const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
    const marketPrice = useSelector<IReduxState, number>(state => {
        return state.app.marketPrice;
    });
    const stakingAPY = useSelector<IReduxState, number>(state => {
        return state.app.stakingAPY;
    });
    const memoBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.memo;
    });

    const trimmedStakingAPY = trim(stakingAPY * 100, 1);
    const trimmedMemoBalance = trim(Number(memoBalance), 6);
    const trimeMarketPrice = trim(marketPrice, 2);

    const [memoAmount, setMemoAmount] = useState(trimmedMemoBalance);
    const [rewardYield, setRewardYield] = useState(trimmedStakingAPY);
    const [priceAtPurchase, setPriceAtPurchase] = useState(trimeMarketPrice);
    const [futureMarketPrice, setFutureMarketPrice] = useState(trimeMarketPrice);
    const [days, setDays] = useState(30);

    const [rewardsEstimation, setRewardsEstimation] = useState("0");
    const [potentialReturn, setPotentialReturn] = useState("0");

    const calcInitialInvestment = () => {
        const memo = Number(memoAmount) || 0;
        const price = parseFloat(priceAtPurchase) || 0;
        const amount = memo * price;
        return trim(amount, 2);
    };

    const calcCurrentWealth = () => {
        const memo = Number(memoAmount) || 0;
        const price = parseFloat(trimeMarketPrice);
        const amount = memo * price;
        return trim(amount, 2);
    };

    const [initialInvestment, setInitialInvestment] = useState(calcInitialInvestment());

    useEffect(() => {
        const newInitialInvestment = calcInitialInvestment();
        setInitialInvestment(newInitialInvestment);
    }, [memoAmount, priceAtPurchase]);

    const calcNewBalance = () => {
        let value = parseFloat(rewardYield) / 100;
        value = Math.pow(value - 1, 1 / (365 * 3)) - 1 || 0;
        let balance = Number(memoAmount);
        for (let i = 0; i < days * 3; i++) {
            balance += balance * value;
        }
        return balance;
    };

    useEffect(() => {
        const newBalance = calcNewBalance();
        setRewardsEstimation(trim(newBalance, 6));
        const newPotentialReturn = newBalance * (parseFloat(futureMarketPrice) || 0);
        setPotentialReturn(trim(newPotentialReturn, 2));
    }, [days, rewardYield, futureMarketPrice, memoAmount]);

    return (
        <div className="calculator-view">
            <Zoom in={true}>
                <div className="calculator-card">
                    <Grid className="calculator-card-grid" container direction="column" spacing={2}>
                        <Grid item>
                            <div className="calculator-card-header">
                                <p className="calculator-card-header-title">Calculator</p>
                                <p className="calculator-card-header-subtitle">Estimate your returns</p>
                            </div>
                        </Grid>
                        <Grid item>
                            <div className="calculator-card-metrics">
                                <Grid container spacing={2}>
                                    <Grid item xs={12} sm={4} md={4} lg={4}>
                                        <div className="calculator-card-apy">
                                            <p className="calculator-card-metrics-title">TIME Price</p>
                                            <p className="calculator-card-metrics-value">{isAppLoading ? <Skeleton width="100px" /> : `$${trimeMarketPrice}`}</p>
                                        </div>
                                    </Grid>
                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="calculator-card-tvl">
                                            <p className="calculator-card-metrics-title">Current APY</p>
                                            <p className="calculator-card-metrics-value">
                                                {isAppLoading ? <Skeleton width="100px" /> : <>{new Intl.NumberFormat("en-US").format(Number(trimmedStakingAPY))}%</>}
                                            </p>
                                        </div>
                                    </Grid>
                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="calculator-card-index">
                                            <p className="calculator-card-metrics-title">Your MEMO Balance</p>
                                            <p className="calculator-card-metrics-value">{isAppLoading ? <Skeleton width="100px" /> : <>{trimmedMemoBalance} MEMO</>}</p>
                                        </div>
                                    </Grid>
                                </Grid>
                            </div>
                        </Grid>

                        <div className="calculator-card-area">
                            <div>
                                <div className="calculator-card-action-area">
                                    <Grid container spacing={3}>
                                        <Grid item xs={12} sm={6}>
                                            <div className="calculator-card-action-area-inp-wrap">
                                                <p className="calculator-card-action-area-inp-wrap-title">MEMO Amount</p>
                                                <OutlinedInput
                                                    type="number"
                                                    placeholder="Amount"
                                                    className="calculator-card-action-input"
                                                    value={memoAmount}
                                                    onChange={e => setMemoAmount(e.target.value)}
                                                    labelWidth={0}
                                                    endAdornment={
                                                        <InputAdornment position="end">
                                                            <div onClick={() => setMemoAmount(trimmedMemoBalance)} className="stake-card-action-input-btn">
                                                                <p>Max</p>
                                                            </div>
                                                        </InputAdornment>
                                                    }
                                                />
                                            </div>
                                        </Grid>
                                        <Grid item xs={12} sm={6}>
                                            <div className="calculator-card-action-area-inp-wrap">
                                                <p className="calculator-card-action-area-inp-wrap-title">APY (%)</p>
                                                <OutlinedInput
                                                    type="number"
                                                    placeholder="Amount"
                                                    className="calculator-card-action-input"
                                                    value={rewardYield}
                                                    onChange={e => setRewardYield(e.target.value)}
                                                    labelWidth={0}
                                                    endAdornment={
                                                        <InputAdornment position="end">
                                                            <div onClick={() => setRewardYield(trimmedStakingAPY)} className="stake-card-action-input-btn">
                                                                <p>Current</p>
                                                            </div>
                                                        </InputAdornment>
                                                    }
                                                />
                                            </div>
                                        </Grid>
                                        <Grid item xs={12} sm={6}>
                                            <div className="calculator-card-action-area-inp-wrap">
                                                <p className="calculator-card-action-area-inp-wrap-title">TIME price at purchase ($)</p>
                                                <OutlinedInput
                                                    type="number"
                                                    placeholder="Amount"
                                                    className="calculator-card-action-input"
                                                    value={priceAtPurchase}
                                                    onChange={e => setPriceAtPurchase(e.target.value)}
                                                    labelWidth={0}
                                                    endAdornment={
                                                        <InputAdornment position="end">
                                                            <div onClick={() => setPriceAtPurchase(trimeMarketPrice)} className="stake-card-action-input-btn">
                                                                <p>Current</p>
                                                            </div>
                                                        </InputAdornment>
                                                    }
                                                />
                                            </div>
                                        </Grid>
                                        <Grid item xs={12} sm={6}>
                                            <div className="calculator-card-action-area-inp-wrap">
                                                <p className="calculator-card-action-area-inp-wrap-title">Future TIME market price ($)</p>
                                                <OutlinedInput
                                                    type="number"
                                                    placeholder="Amount"
                                                    className="calculator-card-action-input"
                                                    value={futureMarketPrice}
                                                    onChange={e => setFutureMarketPrice(e.target.value)}
                                                    labelWidth={0}
                                                    endAdornment={
                                                        <InputAdornment position="end">
                                                            <div onClick={() => setFutureMarketPrice(trimeMarketPrice)} className="stake-card-action-input-btn">
                                                                <p>Current</p>
                                                            </div>
                                                        </InputAdornment>
                                                    }
                                                />
                                            </div>
                                        </Grid>
                                    </Grid>
                                </div>
                                <div className="calculator-days-slider-wrap">
                                    <p className="calculator-days-slider-wrap-title">{`${days} day${days > 1 ? "s" : ""}`}</p>
                                    <Slider className="calculator-days-slider" min={1} max={365} value={days} onChange={(e, newValue: any) => setDays(newValue)} />
                                </div>
                                <div className="calculator-user-data">
                                    <div className="data-row">
                                        <p className="data-row-name">Your initial investment</p>
                                        <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>${initialInvestment}</>}</p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">Current wealth</p>
                                        <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>${calcCurrentWealth()}</>}</p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">TIME rewards estimation</p>
                                        <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{rewardsEstimation} TIME</>}</p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">Potential return</p>
                                        <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>${potentialReturn}</>}</p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">Potential number of lambos</p>
                                        <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{Math.floor(Number(potentialReturn) / 220000)}</>}</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </Grid>
                </div>
            </Zoom>
        </div>
    );
}
Example #15
Source File: index.tsx    From wonderland-frontend with MIT License 4 votes vote down vote up
function Zapin({ open, handleClose, bond }: IZapinProps) {
    const { tokens } = useTokens();
    const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();
    const dispatch = useDispatch();

    const isBondLoading = useSelector<IReduxState, boolean>(state => state.bonding.loading ?? true);
    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    let defaultToken = tokens.find(token => token.name === avax.name);

    if (bond.name === wavax.name) {
        defaultToken = tokens.find(token => token.name === mim.name);
    }

    const [quantity, setQuantity] = useState<string>("");
    //@ts-ignore
    const [token, setToken] = useState<IAllTokenData>(defaultToken);
    const [chooseTokenOpen, setChooseTokenOpen] = useState(false);
    const [settingsOpen, setSettingsOpen] = useState(false);
    const [slippage, setSlippage] = useState(2);
    const [swapInfo, setSwapInfo] = useState<ITokenZapinResponse>({ swapData: "", swapTarget: "", amount: "", value: "0" });
    const [priceToken, setPriceToken] = useState<number>(0);

    const [loading, setLoading] = useState(false);

    const hasAllowance = useCallback(() => {
        return token.allowance > 0;
    }, [token.allowance]);

    const onSeekApproval = async () => {
        if (await checkWrongNetwork()) return;

        dispatch(changeApproval({ address, token, provider, networkID: chainID }));
    };

    const onMint = async () => {
        if (await checkWrongNetwork()) return;

        if (!swapInfo.amount || !swapInfo.swapData || !swapInfo.swapTarget || swapInfo.value !== quantity) {
            return dispatch(warning({ text: messages.something_wrong }));
        }

        dispatch(
            zapinMint({
                provider,
                networkID: chainID,
                bond,
                token,
                value: quantity,
                minReturnAmount: swapInfo.amount,
                swapTarget: swapInfo.swapTarget,
                swapData: swapInfo.swapData,
                slippage,
                address,
            }),
        );
    };

    const onSlippageChange = (value: any) => {
        return setSlippage(value);
    };

    const setMax = () => {
        const maxBondPriceToken = bond.maxBondPriceToken / priceToken;
        let amount: any = Math.min(maxBondPriceToken, token.isAvax ? token.balance * 0.99 : token.balance);

        if (amount) {
            amount = trim(amount);
        }

        setQuantity((amount || "").toString());
    };

    useEffect(() => {
        let timeount: any = null;

        clearTimeout(timeount);

        if (Number(quantity) > 0) {
            setSwapInfo({ swapData: "", swapTarget: "", amount: "", value: "0" });
            setLoading(true);
            timeount = setTimeout(async () => {
                const info = await calcZapinDetails({ token, provider, networkID: chainID, bond, value: quantity, slippage, dispatch });
                if (info.amount) {
                    const amount = utils.formatEther(info.amount);
                    dispatch(calcBondDetails({ bond, value: amount, provider, networkID: chainID }));
                } else {
                    dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
                }
                setSwapInfo(info);
                setLoading(false);
            }, 1000);
        } else {
            setSwapInfo({ swapData: "", swapTarget: "", amount: "", value: "0" });
            dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
            setLoading(false);
        }
        return () => clearTimeout(timeount);
    }, [quantity, slippage]);

    useEffect(() => {
        setTimeout(async () => {
            const { amount } = await calcZapinDetails({ token, provider, networkID: chainID, bond, value: "1", slippage, dispatch });
            if (amount) {
                const amountValue = utils.formatEther(amount);
                setPriceToken(Number(amountValue));
            }
        }, 500);
    }, [token, slippage]);

    let minimumReceivedAmount = "0";

    if (swapInfo.amount) {
        const minimumReceivedAmountValue = utils.formatEther(swapInfo.amount);
        minimumReceivedAmount = trim(Number(minimumReceivedAmountValue), 6);
    }

    const handleChooseTokenOpen = () => {
        setChooseTokenOpen(true);
    };

    const handleChooseTokenClose = () => {
        setChooseTokenOpen(false);
    };

    const handleChooseTokenSelect = (token: IAllTokenData) => {
        setQuantity("");
        setToken(token);
        setChooseTokenOpen(false);
        setSwapInfo({ swapData: "", swapTarget: "", amount: "", value: "0" });
    };

    const handleSettingsOpen = () => {
        setSettingsOpen(true);
    };

    const handleSettingsClose = () => {
        setSettingsOpen(false);
    };

    const isLoading = isBondLoading || loading;

    return (
        <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
            <Paper className="ohm-card ohm-popover zapin-poper">
                <div className="cross-wrap">
                    <IconButton onClick={handleClose}>
                        <SvgIcon color="primary" component={XIcon} />
                    </IconButton>
                    <IconButton style={{ marginLeft: "auto" }} onClick={handleSettingsOpen}>
                        <SvgIcon color="primary" component={SettingsIcon} />
                    </IconButton>
                </div>
                <Box className="card-content">
                    <div className="zapin-header">
                        <div className="zapin-header-token-select-wrap">
                            <p className="zapin-header-token-select-title">Zapin & Mint</p>
                            <OutlinedInput
                                type="number"
                                placeholder="Amount"
                                className="zapin-header-token-select-input"
                                value={quantity}
                                onChange={e => setQuantity(e.target.value)}
                                labelWidth={0}
                                startAdornment={
                                    <InputAdornment position="start">
                                        <div onClick={handleChooseTokenOpen} className="zapin-header-token-select-input-token-select">
                                            <img className="zapin-header-token-select-input-token-select-logo" src={token.img} alt="" />
                                            <p>{token.name}</p>
                                            <Box display="flex" alignItems="center" justifyContent="center" width={"16px"}>
                                                <img src={ArrowUpImg} style={{ height: "16px", width: "16px" }} />
                                            </Box>
                                        </div>
                                    </InputAdornment>
                                }
                                endAdornment={
                                    <InputAdornment position="end">
                                        <div className="zapin-header-token-select-input-btn" onClick={setMax}>
                                            <p>Max</p>
                                        </div>
                                    </InputAdornment>
                                }
                            />
                            {hasAllowance() || token.isAvax ? (
                                <div
                                    className="zapin-header-token-select-btn"
                                    onClick={async () => {
                                        if (isPendingTxn(pendingTransactions, "zapin_" + token.name + "_" + bond.name)) return;
                                        await onMint();
                                    }}
                                >
                                    <p>{txnButtonText(pendingTransactions, "zapin_" + token.name + "_" + bond.name, "Mint")}</p>
                                </div>
                            ) : (
                                <div
                                    className="zapin-header-token-select-btn"
                                    onClick={async () => {
                                        if (isPendingTxn(pendingTransactions, "approve_" + token.address)) return;
                                        await onSeekApproval();
                                    }}
                                >
                                    <p>{txnButtonText(pendingTransactions, "approve_" + token.address, "Approve")}</p>
                                </div>
                            )}
                        </div>
                        {!hasAllowance() && !token.isAvax && (
                            <div className="zapin-header-help-text">
                                <p>Note: The "Approve" transaction is only needed when bonding for the first time</p>
                                <p>for each token; subsequent bonding only requires you to perform the</p>
                                <p>"zapin&mint" transaction.</p>
                            </div>
                        )}
                    </div>
                    <div className="zapin-body">
                        <div className="zapin-body-header">
                            <BondLogo bond={bond} />
                            <div className="zapin-body-header-name">
                                <p>TX settings</p>
                            </div>
                        </div>
                        <div className="zapin-body-params">
                            <div className="data-row">
                                <p className="data-row-name">Destination token </p>
                                <p className="data-row-value">{bond.displayName}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Slippage Tolerance</p>
                                <p className="data-row-value">{trim(slippage)}%</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Your Balance</p>
                                <p className="data-row-value">{`${trim(token.balance, 6)} ${token.name}`}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Minimum Received Amount</p>
                                <p className="data-row-value">{isLoading ? <Skeleton width="100px" /> : `${minimumReceivedAmount} ${bond.displayUnits}`}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Approximately you will get</p>
                                <p className="data-row-value">{isLoading ? <Skeleton width="100px" /> : `~ ${trim(bond.bondQuote, 4)} TIME`}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Max You Can Buy</p>
                                <p className="data-row-value">{isLoading ? <Skeleton width="100px" /> : `${trim(bond.maxBondPrice, 4)} TIME`}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">ROI</p>
                                <p className="data-row-value">{isLoading ? <Skeleton width="100px" /> : `${trim(bond.bondDiscount * 100, 2)}%`}</p>
                            </div>
                            <div className="data-row">
                                <p className="data-row-name">Minimum purchase</p>
                                <p className="data-row-value">0.01 TIME</p>
                            </div>
                        </div>
                    </div>
                    <ChooseToken open={chooseTokenOpen} handleClose={handleChooseTokenClose} handleSelect={handleChooseTokenSelect} bond={bond} />
                    <AdvancedSettings open={settingsOpen} handleClose={handleSettingsClose} slippage={slippage} onSlippageChange={onSlippageChange} />
                </Box>
            </Paper>
        </Modal>
    );
}
Example #16
Source File: BondPurchase.tsx    From wonderland-frontend with MIT License 4 votes vote down vote up
function BondPurchase({ bond, slippage }: IBondPurchaseProps) {
    const dispatch = useDispatch();
    const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();

    const [quantity, setQuantity] = useState("");
    const [useAvax, setUseAvax] = useState(false);

    const isBondLoading = useSelector<IReduxState, boolean>(state => state.bonding.loading ?? true);
    const [zapinOpen, setZapinOpen] = useState(false);

    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    const vestingPeriod = () => {
        return prettifySeconds(bond.vestingTerm, "day");
    };

    async function onBond() {
        if (await checkWrongNetwork()) return;

        if (quantity === "") {
            dispatch(warning({ text: messages.before_minting }));
            //@ts-ignore
        } else if (isNaN(quantity)) {
            dispatch(warning({ text: messages.before_minting }));
        } else if (bond.interestDue > 0 || bond.pendingPayout > 0) {
            const shouldProceed = window.confirm(messages.existing_mint);
            if (shouldProceed) {
                const trimBalance = trim(Number(quantity), 10);

                await dispatch(
                    bondAsset({
                        value: trimBalance,
                        slippage,
                        bond,
                        networkID: chainID,
                        provider,
                        address,
                        useAvax,
                    }),
                );
                clearInput();
            }
        } else {
            const trimBalance = trim(Number(quantity), 10);
            await dispatch(
                //@ts-ignore
                bondAsset({
                    value: trimBalance,
                    slippage,
                    bond,
                    networkID: chainID,
                    provider,
                    address,
                    useAvax,
                }),
            );
            clearInput();
        }
    }

    const clearInput = () => {
        setQuantity("");
    };

    const hasAllowance = useCallback(() => {
        return bond.allowance > 0;
    }, [bond.allowance]);

    const setMax = () => {
        let amount: any = Math.min(bond.maxBondPriceToken * 0.9999, useAvax ? bond.avaxBalance * 0.99 : bond.balance);

        if (amount) {
            amount = trim(amount);
        }

        setQuantity((amount || "").toString());
    };

    const bondDetailsDebounce = useDebounce(quantity, 1000);

    useEffect(() => {
        dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
    }, [bondDetailsDebounce]);

    const onSeekApproval = async () => {
        if (await checkWrongNetwork()) return;

        dispatch(changeApproval({ address, bond, provider, networkID: chainID }));
    };

    const handleZapinOpen = () => {
        dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
        setZapinOpen(true);
    };

    const handleZapinClose = () => {
        dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
        setZapinOpen(false);
    };

    const displayUnits = useAvax ? "AVAX" : bond.displayUnits;

    return (
        <Box display="flex" flexDirection="column">
            <Box display="flex" justifyContent="space-around" flexWrap="wrap">
                {bond.name === "wavax" && (
                    <FormControl className="ohm-input" variant="outlined" color="primary" fullWidth>
                        <div className="avax-checkbox">
                            <input type="checkbox" checked={useAvax} onClick={() => setUseAvax(!useAvax)} />
                            <p>Use AVAX</p>
                        </div>
                    </FormControl>
                )}
                <FormControl className="bond-input-wrap" variant="outlined" color="primary" fullWidth>
                    <OutlinedInput
                        placeholder="Amount"
                        type="number"
                        value={quantity}
                        onChange={e => setQuantity(e.target.value)}
                        labelWidth={0}
                        className="bond-input"
                        endAdornment={
                            <InputAdornment position="end">
                                <div className="stake-input-btn" onClick={setMax}>
                                    <p>Max</p>
                                </div>
                            </InputAdornment>
                        }
                    />
                </FormControl>
                {hasAllowance() || useAvax ? (
                    <div
                        className="transaction-button bond-approve-btn"
                        onClick={async () => {
                            if (isPendingTxn(pendingTransactions, "bond_" + bond.name)) return;
                            await onBond();
                        }}
                    >
                        <p>{txnButtonText(pendingTransactions, "bond_" + bond.name, "Mint")}</p>
                    </div>
                ) : (
                    <div
                        className="transaction-button bond-approve-btn"
                        onClick={async () => {
                            if (isPendingTxn(pendingTransactions, "approve_" + bond.name)) return;
                            await onSeekApproval();
                        }}
                    >
                        <p>{txnButtonText(pendingTransactions, "approve_" + bond.name, "Approve")}</p>
                    </div>
                )}

                <div className="transaction-button bond-approve-btn" onClick={handleZapinOpen}>
                    <p>Zap</p>
                </div>

                {!hasAllowance() && !useAvax && (
                    <div className="help-text">
                        <p className="help-text-desc">
                            Note: The "Approve" transaction is only needed when minting for the first time; subsequent minting only requires you to perform the "Mint" transaction.
                        </p>
                    </div>
                )}
            </Box>

            <Slide direction="left" in={true} mountOnEnter unmountOnExit {...{ timeout: 533 }}>
                <Box className="bond-data">
                    <div className="data-row">
                        <p className="bond-balance-title">Your Balance</p>
                        <p className="bond-balance-title">
                            {isBondLoading ? (
                                <Skeleton width="100px" />
                            ) : (
                                <>
                                    {trim(useAvax ? bond.avaxBalance : bond.balance, 4)} {displayUnits}
                                </>
                            )}
                        </p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">You Will Get</p>
                        <p className="price-data bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondQuote, 4)} TIME`}</p>
                    </div>

                    <div className={`data-row`}>
                        <p className="bond-balance-title">Max You Can Buy</p>
                        <p className="price-data bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.maxBondPrice, 4)} TIME`}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">ROI</p>
                        <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondDiscount * 100, 2)}%`}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">Vesting Term</p>
                        <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : vestingPeriod()}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">Minimum purchase</p>
                        <p className="bond-balance-title">0.01 TIME</p>
                    </div>
                </Box>
            </Slide>
            <Zapin open={zapinOpen} handleClose={handleZapinClose} bond={bond} />
        </Box>
    );
}
Example #17
Source File: index.tsx    From wonderland-frontend with MIT License 4 votes vote down vote up
function Wrap({ open, handleClose }: IAdvancedSettingsProps) {
    const dispatch = useDispatch();
    const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();

    const [value, setValue] = useState("");

    const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);

    const memoBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.memo;
    });
    const wmemoBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.wmemo;
    });

    const wrapValue = useSelector<IReduxState, string>(state => {
        return state.wrapping && state.wrapping.wrapValue;
    });

    const wrapPrice = useSelector<IReduxState, number>(state => {
        return state.wrapping && state.wrapping.wrapPrice;
    });

    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    const memoAllowance = useSelector<IReduxState, number>(state => {
        return state.account.wrapping && state.account.wrapping.memo;
    });

    const [isWrap, setIsWrap] = useState(true);
    const [isWrapPrice, setIsWrapPrice] = useState(true);

    const setMax = () => {
        if (isWrap) {
            setValue(memoBalance);
        } else {
            setValue(wmemoBalance);
        }
    };

    const handleSwap = () => {
        setValue("");
        const value = !isWrap;
        setIsWrap(value);
        setIsWrapPrice(value);
    };

    const handleValueChange = (e: any) => {
        const value = e.target.value;
        setValue(value);
    };

    useEffect(() => {
        dispatch(calcWrapDetails({ isWrap, provider, value, networkID: chainID }));
    }, [value]);

    useEffect(() => {
        dispatch(calcWrapPrice({ isWrap: isWrapPrice, provider, networkID: chainID }));
    }, [isWrapPrice]);

    const onClose = () => {
        setValue("");
        setIsWrap(true);
        setIsWrapPrice(true);
        dispatch(calcWrapDetails({ isWrap, provider, value: "", networkID: chainID }));
        handleClose();
    };

    const hasAllowance = useCallback(() => memoAllowance > 0, [memoAllowance]);

    const trimmedMemoBalance = trim(Number(memoBalance), 6);
    const trimmedWmemoBalance = trim(Number(wmemoBalance), 6);

    const getBalance = () => (isWrap ? `${trimmedMemoBalance} MEMO` : `${trimmedWmemoBalance} wMEMO`);

    const handleOnWrap = async () => {
        if (await checkWrongNetwork()) return;

        if (value === "" || parseFloat(value) === 0) {
            dispatch(warning({ text: isWrap ? messages.before_wrap : messages.before_unwrap }));
        } else {
            await dispatch(changeWrap({ isWrap, value, provider, networkID: chainID, address }));
            setValue("");
        }
    };

    const onSeekApproval = async () => {
        if (await checkWrongNetwork()) return;

        await dispatch(changeApproval({ address, provider, networkID: chainID }));
    };

    return (
        <Modal id="hades" open={open} onClose={onClose} hideBackdrop>
            <Paper className="ohm-card ohm-popover wrap-token-poper">
                <div className="cross-wrap wrap-cros-wrap">
                    <IconButton onClick={onClose}>
                        <SvgIcon color="primary" component={XIcon} />
                    </IconButton>
                    <div className="wrap-price" onClick={() => setIsWrapPrice(!isWrapPrice)}>
                        <p>
                            1 {isWrapPrice ? "MEMO" : "wMEMO"} = {`${trim(wrapPrice, 4)} ${isWrapPrice ? "wMEMO" : "MEMO"}`}
                        </p>
                    </div>
                </div>

                <div className="wrap-header-conteiner">
                    <p className="wrap-header-title">{isWrap ? "Wrap" : "Unwrap"}</p>
                    <p className="wrap-header-balance">Balance: {isAppLoading ? <Skeleton width="80px" /> : <>{getBalance()}</>}</p>
                </div>

                <div className="wrap-container">
                    <OutlinedInput
                        placeholder="Amount"
                        value={value}
                        onChange={handleValueChange}
                        fullWidth
                        type="number"
                        className="bond-input wrap-input"
                        startAdornment={
                            <InputAdornment position="start">
                                <div className="wrap-action-input-text">
                                    <p>{isWrap ? "MEMO" : "wMEMO"}</p>
                                </div>
                            </InputAdornment>
                        }
                        endAdornment={
                            <InputAdornment position="end">
                                <div onClick={setMax} className="wrap-action-input-btn">
                                    <p>Max</p>
                                </div>
                            </InputAdornment>
                        }
                    />
                    <div className="wrap-toggle">
                        <IconButton onClick={handleSwap}>
                            <SvgIcon color="primary" component={ArrowsIcon} />
                        </IconButton>
                    </div>
                    <OutlinedInput
                        placeholder="Amount"
                        value={wrapValue}
                        disabled
                        fullWidth
                        type="number"
                        className="bond-input wrap-input"
                        startAdornment={
                            <InputAdornment position="start">
                                <div className="wrap-action-input-text">
                                    <p>{isWrap ? "wMEMO" : "MEMO"}</p>
                                </div>
                            </InputAdornment>
                        }
                    />
                    {hasAllowance() ? (
                        <div
                            className="wrap-btn"
                            onClick={() => {
                                const inPending = isWrap ? isPendingTxn(pendingTransactions, "wrapping") : isPendingTxn(pendingTransactions, "unwrapping");
                                if (inPending) return;
                                handleOnWrap();
                            }}
                        >
                            <p>{isWrap ? txnButtonText(pendingTransactions, "wrapping", "Wrap") : txnButtonText(pendingTransactions, "unwrapping", "Unwrap")}</p>
                        </div>
                    ) : (
                        <div
                            className="wrap-btn"
                            onClick={() => {
                                if (isPendingTxn(pendingTransactions, "approve_wrapping")) return;
                                onSeekApproval();
                            }}
                        >
                            <p>{txnButtonText(pendingTransactions, "approve_wrapping", "Approve")}</p>
                        </div>
                    )}
                    {!hasAllowance() && (
                        <div className="wrap-help-text">
                            <p>Note: The "Approve" transaction is only needed when</p>
                            <p>wrapping for the first time; subsequent wrapping only</p>
                            <p>requires you to perform the "Wrap" transaction.</p>
                        </div>
                    )}
                </div>
            </Paper>
        </Modal>
    );
}
Example #18
Source File: index.tsx    From rugenerous-frontend with MIT License 4 votes vote down vote up
function Stake() {
  const [anchorEl, setAnchorEl] = useState(null);

  const dispatch = useDispatch();
  const { provider, address, connect, chainID, checkWrongNetwork } = useWeb3Context();

  const [view, setView] = useState(0);
  const [quantity, setQuantity] = useState<string>("");

  const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
  const app = useSelector<IReduxState, IAppSlice>(state => state.app);
  const currentIndex = useSelector<IReduxState, string>(state => {
    return state.app.currentIndex;
  });
  const fiveDayRate = useSelector<IReduxState, number>(state => {
    return state.app.fiveDayRate;
  });
  const timeBalance = useSelector<IReduxState, string>(state => {
    return state.account.balances && state.account.balances.rug;
  });
  const warmupBalance = useSelector<IReduxState, string>(state => {
    return state.account.warmupInfo && state.account.warmupInfo.deposit;
  });
  const gonsBalance = useSelector<IReduxState, string>(state => {
    return state.account.warmupInfo && state.account.warmupInfo.gonsBalance;
  });
  const warmupExpiry = useSelector<IReduxState, string>(state => {
    return state.account.warmupInfo && state.account.warmupInfo.expiry;
  });
  const currentEpoch = useSelector<IReduxState, string>(state => {
    return state.account.warmupInfo && state.account.warmupInfo.epoch;
  });
  const memoBalance = useSelector<IReduxState, string>(state => {
    return state.account.balances && state.account.balances.srug;
  });
  //Adding Durag - KM
  const duragBalance = useSelector<IReduxState, string>(state => {
    return state.account.balances && state.account.balances.durag;
  });
  const stakeAllowance = useSelector<IReduxState, number>(state => {
    return state.account.staking && state.account.staking.rug;
  });
  const unstakeAllowance = useSelector<IReduxState, number>(state => {
    return state.account.staking && state.account.staking.srug;
  });
  const stakingRebase = useSelector<IReduxState, number>(state => {
    return state.app.stakingRebase;
  });
  const stakingAPY = useSelector<IReduxState, number>(state => {
    return state.app.stakingAPY;
  });
  const stakingTVL = useSelector<IReduxState, number>(state => {
    return state.app.stakingTVL;
  });

  const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
    return state.pendingTransactions;
  });

  const setMax = () => {
    if (view === 0) {
      const fullBalance = Number(timeBalance);
      setQuantity(trim(fullBalance, 4));
      console.log(quantity);
    } else {
      setQuantity(memoBalance);
    }
  };

  const onSeekApproval = async (token: string) => {
    if (await checkWrongNetwork()) return;

    await dispatch(changeApproval({ address, token, provider, networkID: chainID }));
  };

  const onChangeStake = async (action: string) => {
    if (await checkWrongNetwork()) return;
    if (quantity === "" || parseFloat(quantity) === 0) {
      dispatch(warning({ text: action === "stake" ? messages.before_stake : messages.before_unstake }));
    } else {
      await dispatch(
        changeStake({
          address,
          action,
          value: String(quantity),
          provider,
          networkID: chainID,
          warmUpBalance: Number(warmupBalance),
        }),
      );
      setQuantity("");
    }
  };

  const onChangeWarmup = async (action: string) => {
    if (await checkWrongNetwork()) return;
    await dispatch(
      forfeitOrClaim({
        address,
        action,
        provider,
        networkID: chainID,
      }),
    );
  };

  const hasAllowance = useCallback(
    token => {
      if (token === "rug") return stakeAllowance > 0;
      if (token === "srug") return unstakeAllowance > 0;
      return 0;
    },
    [stakeAllowance],
  );

  const changeView = (newView: number) => () => {
    setView(newView);
    setQuantity("");
  };

  const trimmedMemoBalance = trim(Number(memoBalance), 6);
  const trimmedMemoBalanceInUSD = trim(Number(memoBalance) * app.marketPrice, 2);
  const trimmedStakingAPY = trim(stakingAPY * 100, 1);
  const stakingRebasePercentage = trim(stakingRebase * 100, 4);
  const nextRewardValue = trim((Number(stakingRebasePercentage) / 100) * Number(trimmedMemoBalance), 6);
  const nextRewardInUSD = Number(nextRewardValue) * app.marketPrice;
  const trimmedEarningsPerDay = trim(nextRewardInUSD * 3, 2);

  const handleClick = (event: any) => {
    setAnchorEl(anchorEl ? null : event.currentTarget);
  };

  const open = Boolean(anchorEl);

  return (
    <div className="stake-view">
      <Zoom in={true}>
        <div className="stake-card">
          <Grid className="stake-card-grid" container direction="column" spacing={2}>
            <Grid item>
              <div className="stake-card-header">
                <p className="stake-card-header-title">RUG Staking (?, ?)</p>
                <RebaseTimer />
              </div>
            </Grid>

            <Grid item>
              <div className="stake-card-metrics">
                <Grid container spacing={2}>
                  <Grid item xs={12} sm={4} md={4} lg={4}>
                    <div className="stake-card-apy">
                      <p className="stake-card-metrics-title">APY</p>
                      <>
                        {stakingAPY ? (
                          <div>
                            <p
                              className="stake-card-metrics-value"
                              onMouseEnter={e => handleClick(e)}
                              onMouseLeave={e => handleClick(e)}
                            >
                              `'Big' - trust me bro...`
                            </p>

                            <Popper className="rug-menu-popper tooltip" open={open} anchorEl={anchorEl} transition>
                              {({ TransitionProps }) => (
                                <Fade {...TransitionProps} timeout={200}>
                                  <p className="tooltip-item">
                                    {new Intl.NumberFormat("en-US").format(Number(trimmedStakingAPY))}%
                                  </p>
                                </Fade>
                              )}
                            </Popper>
                          </div>
                        ) : (
                          <p className="stake-card-metrics-value">
                            <Skeleton width="150px" />
                          </p>
                        )}
                      </>
                    </div>
                  </Grid>

                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="stake-card-index">
                      <p className="stake-card-metrics-title">Current Index</p>
                      <p className="stake-card-metrics-value">
                        {currentIndex ? <>{trim(Number(currentIndex), 2)} RUG</> : <Skeleton width="150px" />}
                      </p>
                    </div>
                  </Grid>

                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="stake-card-index">
                      <p className="stake-card-metrics-title">Earnings per Day</p>
                      <p className="stake-card-metrics-value">
                        {currentIndex ? <>${trimmedEarningsPerDay}</> : <Skeleton width="150px" />}
                      </p>
                    </div>
                  </Grid>
                </Grid>
              </div>
            </Grid>

            <div className="stake-card-area">
              {!address && (
                <div className="stake-card-wallet-notification">
                  <div className="stake-card-wallet-connect-btn" onClick={connect}>
                    <p>Connect Wallet</p>
                  </div>
                  <p className="stake-card-wallet-desc-text">Connect your wallet to stake RUG tokens!</p>
                </div>
              )}
              {address && (
                <div>
                  <div className="stake-card-action-area">
                    <div className="stake-card-action-stage-btns-wrap">
                      <div
                        onClick={changeView(0)}
                        className={classnames("stake-card-action-stage-btn", { active: !view })}
                      >
                        <p>Stake</p>
                      </div>
                      <div
                        onClick={changeView(1)}
                        className={classnames("stake-card-action-stage-btn", { active: view })}
                      >
                        <p>Unstake</p>
                      </div>
                    </div>

                    <div className="stake-card-action-row">
                      <OutlinedInput
                        type="number"
                        placeholder="Amount"
                        className="stake-card-action-input"
                        value={quantity}
                        onChange={e => setQuantity(e.target.value)}
                        labelWidth={0}
                        endAdornment={
                          <InputAdornment position="end">
                            <div onClick={setMax} className="stake-card-action-input-btn">
                              <p>Max</p>
                            </div>
                          </InputAdornment>
                        }
                      />

                      {view === 0 && (
                        <div className="stake-card-tab-panel">
                          {address && hasAllowance("rug") ? (
                            <div
                              className="stake-card-tab-panel-btn"
                              onClick={() => {
                                if (isPendingTxn(pendingTransactions, "staking")) return;
                                onChangeStake("stake");
                              }}
                            >
                              <p>{txnButtonText(pendingTransactions, "staking", "Stake RUG")}</p>
                            </div>
                          ) : (
                            <div
                              className="stake-card-tab-panel-btn"
                              onClick={() => {
                                if (isPendingTxn(pendingTransactions, "approve_staking")) return;
                                onSeekApproval("rug");
                              }}
                            >
                              <p>{txnButtonText(pendingTransactions, "approve_staking", "Approve")}</p>
                            </div>
                          )}
                        </div>
                      )}

                      {view === 1 && (
                        <div className="stake-card-tab-panel">
                          {address && hasAllowance("srug") ? (
                            <div
                              className="stake-card-tab-panel-btn"
                              onClick={() => {
                                if (isPendingTxn(pendingTransactions, "unstaking")) return;
                                onChangeStake("unstake");
                              }}
                            >
                              <p>{txnButtonText(pendingTransactions, "unstaking", "Unstake RUG")}</p>
                            </div>
                          ) : (
                            <div
                              className="stake-card-tab-panel-btn"
                              onClick={() => {
                                if (isPendingTxn(pendingTransactions, "approve_unstaking")) return;
                                onSeekApproval("srug");
                              }}
                            >
                              <p>{txnButtonText(pendingTransactions, "approve_unstaking", "Approve")}</p>
                            </div>
                          )}
                        </div>
                      )}
                    </div>

                    <div className="stake-card-action-help-text">
                      {address && ((!hasAllowance("rug") && view === 0) || (!hasAllowance("srug") && view === 1)) && (
                        <p>
                          Note: The "Approve" transaction is only needed when staking/unstaking for the first rug;
                          subsequent staking/unstaking only requires you to perform the "Stake" or "Unstake"
                          transaction.
                        </p>
                      )}
                    </div>
                  </div>

                  <div className="stake-user-data">
                    <div className="data-row">
                      <p className="data-row-name">Your Balance</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(timeBalance), 4)} RUG</>}
                      </p>
                    </div>

                    <div className="data-row">
                      <p className="data-row-name">Your Durag Balance</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(duragBalance), 4)} DURAG</>}
                      </p>
                    </div>

                    {Number(warmupBalance) > 0 && (
                      <>
                        <br />
                        <div className="data-row">
                          <p className="data-row-name">Your Warm Up Balance</p>
                          <p className="data-row-value">
                            {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(warmupBalance), 4)} RUG</>}
                          </p>
                        </div>

                        {Number(warmupBalance) < Number(gonsBalance) && (
                          <>
                            <div className="data-row">
                              <p className="data-row-name">Warm Up Balance with Rebase Rewards</p>
                              <p className="data-row-value">
                                {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(gonsBalance), 4)} RUG</>}
                              </p>
                            </div>
                          </>
                        )}

                        <div className="data-row">
                          <p className="data-row-name">Pending Warm Up Till Release</p>
                          <p className="data-row-value">
                            {isAppLoading ? (
                              <Skeleton width="80px" />
                            ) : Number(warmupExpiry) <= Number(currentEpoch) ? (
                              <>
                                <div
                                  className="claim-btn"
                                  onClick={() => {
                                    if (isPendingTxn(pendingTransactions, "claim")) return;
                                    onChangeWarmup("claim");
                                  }}
                                >
                                  <p>{txnButtonText(pendingTransactions, "claim", "Claim SRUG")}</p>
                                </div>
                                <br />
                              </>
                            ) : (
                              <div className="warmup-text">
                                {" "}
                                {Number(warmupExpiry) - Number(currentEpoch)} Rebase(s) left till claimable
                                <div className="forfeit-btn">{BasicModal(onChangeWarmup)}</div>
                              </div>
                            )}
                          </p>
                        </div>
                      </>
                    )}

                    <div className="data-row">
                      <p className="data-row-name">Your Staked Balance</p>
                      <p className="data-row-value">
                        {isAppLoading ? (
                          <Skeleton width="80px" />
                        ) : (
                          <>
                            {trimmedMemoBalance} sRUG (${trimmedMemoBalanceInUSD})
                          </>
                        )}
                      </p>
                    </div>

                    <div className="data-row">
                      <p className="data-row-name">Next Reward Amount</p>
                      <p className="data-row-value">
                        {isAppLoading ? (
                          <Skeleton width="80px" />
                        ) : (
                          <>
                            {nextRewardValue} sRUG (${trim(nextRewardInUSD, 2)})
                          </>
                        )}
                      </p>
                    </div>

                    <div className="data-row">
                      <p className="data-row-name">Next Reward Yield</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>{stakingRebasePercentage}%</>}
                      </p>
                    </div>

                    <div className="data-row">
                      <p className="data-row-name">ROI (5-Day Rate)</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(fiveDayRate) * 100, 4)}%</>}
                      </p>
                    </div>

                    <div className="stake-card-action-help-text">
                      <br />
                      <p>
                        Please Note: there is a two-epoch warm-up period when staking. One epoch is eight hours (one
                        rebase window). During warm-up, your staked tokens are held by the warm-up contract. Exiting the
                        warm-up early will return your original deposit to your wallet.
                        <br />
                        <br />
                        Your staked tokens and their accrued rebase rewards will be available to claim at the start of
                        the third epoch after you originally staked. Once claimed, the tokens move to your staked token
                        balance, where they will continue to earn rebase rewards and can be unstaked at any time without
                        penalty.
                      </p>
                    </div>
                  </div>
                </div>
              )}
            </div>
          </Grid>
        </div>
      </Zoom>
    </div>
  );
}
Example #19
Source File: index.tsx    From rugenerous-frontend with MIT License 4 votes vote down vote up
function Redemption() {
  const [anchorEl, setAnchorEl] = useState(null);

  const dispatch = useDispatch();
  const { provider, address, connect, chainID, checkWrongNetwork } = useWeb3Context();

  const [view, setView] = useState(0);
  const [quantity, setQuantity] = useState<string>("");

  const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
  const app = useSelector<IReduxState, IAppSlice>(state => state.app);
  const currentIndex = useSelector<IReduxState, number>(state => {
    return state.app.rfv;
  });
  const setRFV = useSelector<IReduxState, number>(state => {
    return state.app.setRFV;
  });
  const timeBalance = useSelector<IReduxState, string>(state => {
    return state.account.balances && state.account.balances.rug;
  });
  const timeBalanceValue = (Number(timeBalance) * setRFV) / 100;
  //Adding Durag - KM
  const redeemAllowance = useSelector<IReduxState, number>(state => {
    return state.account.redeem && state.account.redeem.rug;
  });

  const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
    return state.pendingTransactions;
  });

  const setMax = () => {
    const fullBalance = Number(timeBalance);
    setQuantity(trim(fullBalance, 4));
    console.log(quantity);
  };

  const onSeekApproval = async (token: string) => {
    if (await checkWrongNetwork()) return;

    await dispatch(changeApproval({ address, token, provider, networkID: chainID }));
  };

  const onRedeem = async (action: string) => {
    if (await checkWrongNetwork()) return;
    if (quantity === "" || parseFloat(quantity) === 0) {
      dispatch(warning({ text: action === "redeem" ? messages.before_redeem : "" }));
    } else {
      await dispatch(
        redeemFromRUG({
          address,
          action,
          value: String(quantity),
          provider,
          networkID: chainID,
        }),
      );
      setQuantity("");
    }
  };

  const hasAllowance = useCallback(
    token => {
      if (token === "rug") return redeemAllowance > 0;
      return 0;
    },
    [redeemAllowance],
  );

  const changeView = (newView: number) => () => {
    setView(newView);
    setQuantity("");
  };

  const handleClick = (event: any) => {
    setAnchorEl(anchorEl ? null : event.currentTarget);
  };

  return (
    <div className="redeem-view">
      <Zoom in={true}>
        <div className="redeem-card">
          <Grid className="redeem-card-grid" container direction="column" spacing={2}>
            <Grid item>
              <div className="redeem-card-header">
                <p className="redeem-card-header-title">The RUG Redemption (?, ?)</p>
              </div>
            </Grid>

            <Grid item>
              <div className="redeem-card-metrics">
                <Grid container spacing={2}>
                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="redeem-card-index">
                      <p className="redeem-card-metrics-title">Approximate RFV</p>
                      <p className="redeem-card-metrics-value">
                        {currentIndex ? <>${trim(Number(currentIndex), 2)}</> : <Skeleton width="150px" />}
                      </p>
                    </div>
                  </Grid>
                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="redeem-card-index">
                      <p className="redeem-card-metrics-title">Applied Risk Free Value</p>
                      <p className="redeem-card-metrics-value">
                        {currentIndex ? <>${trim(Number(setRFV / 100), 2)}</> : <Skeleton width="150px" />}
                      </p>
                    </div>
                  </Grid>
                </Grid>
              </div>
            </Grid>

            <div className="redeem-card-area">
              {!address && (
                <div className="redeem-card-wallet-notification">
                  <div className="redeem-card-wallet-connect-btn" onClick={connect}>
                    <p>Connect Wallet</p>
                  </div>
                  <p className="redeem-card-wallet-desc-text">
                    Connect your wallet to Redeem USDC for your RUG tokens!
                  </p>
                </div>
              )}
              {address && (
                <div>
                  <div className="redeem-card-action-area">
                    <div className="redeem-card-action-stage-btns-wrap">
                      <div
                        onClick={changeView(0)}
                        className={classnames("redeem-card-action-stage-btn", { active: !view })}
                      >
                        <p>Redeem</p>
                      </div>
                    </div>

                    <div className="redeem-card-action-row">
                      <OutlinedInput
                        type="number"
                        placeholder="Amount"
                        className="redeem-card-action-input"
                        value={quantity}
                        onChange={e => setQuantity(e.target.value)}
                        labelWidth={0}
                        endAdornment={
                          <InputAdornment position="end">
                            <div onClick={setMax} className="redeem-card-action-input-btn">
                              <p>Max</p>
                            </div>
                          </InputAdornment>
                        }
                      />

                      <div className="redeem-card-tab-panel">
                        {address && hasAllowance("rug") ? (
                          <div
                            className="redeem-card-tab-panel-btn"
                            onClick={() => {
                              if (isPendingTxn(pendingTransactions, "redeem")) return;
                              onRedeem("redeem");
                            }}
                          >
                            <p>{txnButtonText(pendingTransactions, "redeem", "Redeem USDC")}</p>
                          </div>
                        ) : (
                          <div
                            className="redeem-card-tab-panel-btn"
                            onClick={() => {
                              if (isPendingTxn(pendingTransactions, "approve_redeem")) return;
                              onSeekApproval("rug");
                            }}
                          >
                            <p>{txnButtonText(pendingTransactions, "approve_redeem", "Approve")}</p>
                          </div>
                        )}
                      </div>
                    </div>

                    <div className="redeem-card-action-help-text">
                      {address && !hasAllowance("rug") && view === 0 && (
                        <p>
                          Note: The "Approve" transaction is only needed when redeeming for the first time, subsequent
                          redemptions only requires you to perform the "Redeem" transaction.
                        </p>
                      )}
                    </div>
                  </div>

                  <div className="redeem-user-data">
                    <div className="data-row">
                      <p className="data-row-name">Your Balance</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(timeBalance), 4)} RUG</>}
                      </p>
                    </div>
                    <div className="data-row">
                      <p className="data-row-name">Your Balance Value</p>
                      <p className="data-row-value">
                        {isAppLoading ? <Skeleton width="80px" /> : <>${trim(timeBalanceValue, 4)}</>}
                      </p>
                    </div>
                  </div>
                </div>
              )}
            </div>
          </Grid>
        </div>
      </Zoom>
    </div>
  );
}
Example #20
Source File: index.tsx    From rugenerous-frontend with MIT License 4 votes vote down vote up
function Calculator() {
  const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
  const marketPrice = useSelector<IReduxState, number>(state => {
    return state.app.marketPrice;
  });
  const stakingAPY = useSelector<IReduxState, number>(state => {
    return state.app.stakingAPY;
  });
  const memoBalance = useSelector<IReduxState, string>(state => {
    return state.account.balances && state.account.balances.srug;
  });

  const trimmedStakingAPY = trim(stakingAPY * 100, 1);
  const trimmedMemoBalance = trim(Number(memoBalance), 6);
  const trimeMarketPrice = trim(marketPrice, 2);

  const [memoAmount, setMemoAmount] = useState(trimmedMemoBalance);
  const [rewardYield, setRewardYield] = useState(trimmedStakingAPY);
  const [priceAtPurchase, setPriceAtPurchase] = useState(trimeMarketPrice);
  const [futureMarketPrice, setFutureMarketPrice] = useState(trimeMarketPrice);
  const [days, setDays] = useState(30);

  const [rewardsEstimation, setRewardsEstimation] = useState("0");
  const [potentialReturn, setPotentialReturn] = useState("0");

  const calcInitialInvestment = () => {
    const srug = Number(memoAmount) || 0;
    const price = parseFloat(priceAtPurchase) || 0;
    const amount = srug * price;
    return trim(amount, 2);
  };

  const calcCurrentWealth = () => {
    const srug = Number(memoAmount) || 0;
    const price = parseFloat(trimeMarketPrice);
    const amount = srug * price;
    return trim(amount, 2);
  };

  const [initialInvestment, setInitialInvestment] = useState(calcInitialInvestment());

  useEffect(() => {
    const newInitialInvestment = calcInitialInvestment();
    setInitialInvestment(newInitialInvestment);
  }, [memoAmount, priceAtPurchase]);

  const calcNewBalance = () => {
    let value = parseFloat(rewardYield) / 100;
    value = Math.pow(value - 1, 1 / (365 * 3)) - 1 || 0;
    let balance = Number(memoAmount);
    for (let i = 0; i < days * 3; i++) {
      balance += balance * value;
    }
    return balance;
  };

  useEffect(() => {
    const newBalance = calcNewBalance();
    setRewardsEstimation(trim(newBalance, 6));
    const newPotentialReturn = newBalance * (parseFloat(futureMarketPrice) || 0);
    setPotentialReturn(trim(newPotentialReturn, 2));
  }, [days, rewardYield, futureMarketPrice, memoAmount]);

  return (
    <div className="calculator-view">
      <Zoom in={true}>
        <div className="calculator-card">
          <Grid className="calculator-card-grid" container direction="column" spacing={2}>
            <Grid item>
              <div className="calculator-card-header">
                <p className="calculator-card-header-title">Super Accurate Calculator</p>
                <p className="calculator-card-header-subtitle">Estimate how much you get rugged...</p>
              </div>
            </Grid>
            <Grid item>
              <div className="calculator-card-metrics">
                <Grid container spacing={2}>
                  <Grid item xs={12} sm={4} md={4} lg={4}>
                    <div className="calculator-card-apy">
                      <p className="calculator-card-metrics-title">RUG Price</p>
                      <p className="calculator-card-metrics-value">
                        {isAppLoading ? <Skeleton width="100px" /> : `$${trimeMarketPrice}`}
                      </p>
                    </div>
                  </Grid>
                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="calculator-card-tvl">
                      <p className="calculator-card-metrics-title">Current APY</p>
                      <p className="calculator-card-metrics-value">
                        {isAppLoading ? (
                          <Skeleton width="100px" />
                        ) : (
                          <>{new Intl.NumberFormat("en-US").format(Number(trimmedStakingAPY))}%</>
                        )}
                      </p>
                    </div>
                  </Grid>
                  <Grid item xs={6} sm={4} md={4} lg={4}>
                    <div className="calculator-card-index">
                      <p className="calculator-card-metrics-title">Your RUGGED Balance</p>
                      <p className="calculator-card-metrics-value">
                        {isAppLoading ? <Skeleton width="100px" /> : <>{trimmedMemoBalance} RUGGED</>}
                      </p>
                    </div>
                  </Grid>
                </Grid>
              </div>
            </Grid>

            <div className="calculator-card-area">
              <div>
                <div className="calculator-card-action-area">
                  <Grid container spacing={3}>
                    <Grid item xs={12} sm={6}>
                      <div className="calculator-card-action-area-inp-wrap">
                        <p className="calculator-card-action-area-inp-wrap-title">RUGGED Amount</p>
                        <OutlinedInput
                          type="number"
                          placeholder="Amount"
                          className="calculator-card-action-input"
                          value={memoAmount}
                          onChange={e => setMemoAmount(e.target.value)}
                          labelWidth={0}
                          endAdornment={
                            <InputAdornment position="end">
                              <div
                                onClick={() => setMemoAmount(trimmedMemoBalance)}
                                className="stake-card-action-input-btn"
                              >
                                <p>Max</p>
                              </div>
                            </InputAdornment>
                          }
                        />
                      </div>
                    </Grid>
                    <Grid item xs={12} sm={6}>
                      <div className="calculator-card-action-area-inp-wrap">
                        <p className="calculator-card-action-area-inp-wrap-title">APY (%)</p>
                        <OutlinedInput
                          type="number"
                          placeholder="Amount"
                          className="calculator-card-action-input"
                          value={rewardYield}
                          onChange={e => setRewardYield(e.target.value)}
                          labelWidth={0}
                          endAdornment={
                            <InputAdornment position="end">
                              <div
                                onClick={() => setRewardYield(trimmedStakingAPY)}
                                className="stake-card-action-input-btn"
                              >
                                <p>Current</p>
                              </div>
                            </InputAdornment>
                          }
                        />
                      </div>
                    </Grid>
                    <Grid item xs={12} sm={6}>
                      <div className="calculator-card-action-area-inp-wrap">
                        <p className="calculator-card-action-area-inp-wrap-title">RUG price at purchase ($)</p>
                        <OutlinedInput
                          type="number"
                          placeholder="Amount"
                          className="calculator-card-action-input"
                          value={priceAtPurchase}
                          onChange={e => setPriceAtPurchase(e.target.value)}
                          labelWidth={0}
                          endAdornment={
                            <InputAdornment position="end">
                              <div
                                onClick={() => setPriceAtPurchase(trimeMarketPrice)}
                                className="stake-card-action-input-btn"
                              >
                                <p>Current</p>
                              </div>
                            </InputAdornment>
                          }
                        />
                      </div>
                    </Grid>
                    <Grid item xs={12} sm={6}>
                      <div className="calculator-card-action-area-inp-wrap">
                        <p className="calculator-card-action-area-inp-wrap-title">Future RUG market price ($)</p>
                        <OutlinedInput
                          type="number"
                          placeholder="Amount"
                          className="calculator-card-action-input"
                          value={futureMarketPrice}
                          onChange={e => setFutureMarketPrice(e.target.value)}
                          labelWidth={0}
                          endAdornment={
                            <InputAdornment position="end">
                              <div
                                onClick={() => setFutureMarketPrice(trimeMarketPrice)}
                                className="stake-card-action-input-btn"
                              >
                                <p>Current</p>
                              </div>
                            </InputAdornment>
                          }
                        />
                      </div>
                    </Grid>
                  </Grid>
                </div>
                <div className="calculator-days-slider-wrap">
                  <p className="calculator-days-slider-wrap-title">{`${days} day${days > 1 ? "s" : ""}`}</p>
                  <Slider
                    className="calculator-days-slider"
                    min={1}
                    max={365}
                    value={days}
                    onChange={(e, newValue: any) => setDays(newValue)}
                  />
                </div>
                <div className="calculator-user-data">
                  <div className="data-row">
                    <p className="data-row-name">Your initial investment</p>
                    <p className="data-row-value">
                      {isAppLoading ? <Skeleton width="80px" /> : <>${initialInvestment}</>}
                    </p>
                  </div>
                  <div className="data-row">
                    <p className="data-row-name">Current wealth</p>
                    <p className="data-row-value">
                      {isAppLoading ? <Skeleton width="80px" /> : <>${calcCurrentWealth()}</>}
                    </p>
                  </div>
                  <div className="data-row">
                    <p className="data-row-name">RUG rewards estimation</p>
                    <p className="data-row-value">
                      {isAppLoading ? <Skeleton width="80px" /> : <>{rewardsEstimation} RUG</>}
                    </p>
                  </div>
                  <div className="data-row">
                    <p className="data-row-name">Potential return</p>
                    <p className="data-row-value">
                      {isAppLoading ? <Skeleton width="80px" /> : <>${potentialReturn}</>}
                    </p>
                  </div>
                  <div className="data-row">
                    <p className="data-row-name">Potential number of lambos</p>
                    <p className="data-row-value">
                      {isAppLoading ? <Skeleton width="80px" /> : <>{Math.floor(Number(potentialReturn) / 220000)}</>}
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </Grid>
        </div>
      </Zoom>
    </div>
  );
}
Example #21
Source File: index.tsx    From rugenerous-frontend with MIT License 4 votes vote down vote up
function Zapin({ open, handleClose, bond }: IZapinProps) {
  const { tokens } = useTokens();
  const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();
  const dispatch = useDispatch();

  const isBondLoading = useSelector<IReduxState, boolean>(state => state.bonding.loading ?? true);
  const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
    return state.pendingTransactions;
  });

  let defaultToken = tokens.find(token => token.name === avax.name);

  // if (bond.name === wavax.name) {
  //   defaultToken = tokens.find(token => token.name === mim.name);
  // }

  const [quantity, setQuantity] = useState<string>("");
  //@ts-ignore
  const [token, setToken] = useState<IAllTokenData>(defaultToken);
  const [chooseTokenOpen, setChooseTokenOpen] = useState(false);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [slippage, setSlippage] = useState(2);
  const [recipientAddress, setRecipientAddress] = useState(address);
  const [swapInfo, setSwapInfo] = useState<ITokenZapinResponse>({ swapData: "", swapTarget: "", amount: "" });
  const [priceToken, setPriceToken] = useState<number>(0);

  const [loading, setLoading] = useState(false);

  const hasAllowance = useCallback(() => {
    return token.allowance > 0;
  }, [token.allowance]);

  const onSeekApproval = async () => {
    if (await checkWrongNetwork()) return;

    dispatch(changeApproval({ address, token, provider, networkID: chainID }));
  };

  const onMint = async () => {
    if (await checkWrongNetwork()) return;

    if (!swapInfo.amount || !swapInfo.swapData || !swapInfo.swapTarget) {
      return dispatch(warning({ text: messages.something_wrong }));
    }

    dispatch(
      zapinMint({
        provider,
        networkID: chainID,
        bond,
        token,
        value: quantity,
        minReturnAmount: swapInfo.amount,
        swapTarget: swapInfo.swapTarget,
        swapData: swapInfo.swapData,
        slippage,
        address,
      }),
    );
  };

  const onRecipientAddressChange = (value: any) => {
    return setRecipientAddress(value);
  };

  const onSlippageChange = (value: any) => {
    return setSlippage(value);
  };

  const setMax = () => {
    const maxBondPriceToken = bond.maxBondPriceToken / priceToken;
    let amount: any = Math.min(maxBondPriceToken, token.isAvax ? token.balance * 0.99 : token.balance);

    if (amount) {
      amount = trim(amount);
    }

    setQuantity((amount || "").toString());
  };

  useEffect(() => {
    if (address) setRecipientAddress(address);
  }, [provider, address]);

  useEffect(() => {
    let timeount: any = null;

    clearTimeout(timeount);

    if (Number(quantity) > 0) {
      setLoading(true);
      timeount = setTimeout(async () => {
        const info = await calcZapinDetails({
          token,
          provider,
          networkID: chainID,
          bond,
          value: quantity,
          slippage,
          dispatch,
        });
        if (info.amount) {
          const amount = utils.formatEther(info.amount);
          dispatch(calcBondDetails({ bond, value: amount, provider, networkID: chainID }));
        } else {
          dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
        }
        setSwapInfo(info);
        setLoading(false);
      }, 1000);
    } else {
      setSwapInfo({ swapData: "", swapTarget: "", amount: "" });
      dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
      setLoading(false);
    }
    return () => clearTimeout(timeount);
  }, [quantity, slippage]);

  useEffect(() => {
    setTimeout(async () => {
      const { amount } = await calcZapinDetails({
        token,
        provider,
        networkID: chainID,
        bond,
        value: "1",
        slippage,
        dispatch,
      });
      if (amount) {
        const amountValue = utils.formatEther(amount);
        setPriceToken(Number(amountValue));
      }
    }, 500);
  }, [token, slippage]);

  let minimumReceivedAmount = "0";

  if (swapInfo.amount) {
    const minimumReceivedAmountValue = utils.formatEther(swapInfo.amount);
    minimumReceivedAmount = trim(Number(minimumReceivedAmountValue), 6);
  }

  const handleChooseTokenOpen = () => {
    setChooseTokenOpen(true);
  };

  const handleChooseTokenClose = () => {
    setChooseTokenOpen(false);
  };

  const handleChooseTokenSelect = (token: IAllTokenData) => {
    setQuantity("");
    setToken(token);
    setChooseTokenOpen(false);
  };

  const handleSettingsOpen = () => {
    setSettingsOpen(true);
  };

  const handleSettingsClose = () => {
    setSettingsOpen(false);
  };

  const isLoading = isBondLoading || loading;

  return (
    <Modal id="hades" open={open} onClose={handleClose} hideBackdrop>
      <Paper className="ohm-card ohm-popover zapin-poper">
        <div className="cross-wrap">
          <IconButton onClick={handleClose}>
            <SvgIcon color="primary" component={XIcon} />
          </IconButton>
          <IconButton style={{ marginLeft: "auto" }} onClick={handleSettingsOpen}>
            <SvgIcon color="primary" component={SettingsIcon} />
          </IconButton>
        </div>
        <Box className="card-content">
          <div className="zapin-header">
            <div className="zapin-header-token-select-wrap">
              <p className="zapin-header-token-select-title">Zapin & Mint</p>
              <OutlinedInput
                type="number"
                placeholder="Amount"
                className="zapin-header-token-select-input"
                value={quantity}
                onChange={e => setQuantity(e.target.value)}
                labelWidth={0}
                startAdornment={
                  <InputAdornment position="start">
                    <div onClick={handleChooseTokenOpen} className="zapin-header-token-select-input-token-select">
                      <img className="zapin-header-token-select-input-token-select-logo" src={token.img} alt="" />
                      <p>{token.name}</p>
                      <Box display="flex" alignItems="center" justifyContent="center" width={"16px"}>
                        <img src={ArrowUpImg} style={{ height: "16px", width: "16px" }} />
                      </Box>
                    </div>
                  </InputAdornment>
                }
                endAdornment={
                  <InputAdornment position="end">
                    <div className="zapin-header-token-select-input-btn" onClick={setMax}>
                      <p>Max</p>
                    </div>
                  </InputAdornment>
                }
              />
              {hasAllowance() || token.isAvax ? (
                <div
                  className="zapin-header-token-select-btn"
                  onClick={async () => {
                    if (isPendingTxn(pendingTransactions, "zapin_" + token.name + "_" + bond.name)) return;
                    await onMint();
                  }}
                >
                  <p>{txnButtonText(pendingTransactions, "zapin_" + token.name + "_" + bond.name, "Mint")}</p>
                </div>
              ) : (
                <div
                  className="zapin-header-token-select-btn"
                  onClick={async () => {
                    if (isPendingTxn(pendingTransactions, "approve_" + token.address)) return;
                    await onSeekApproval();
                  }}
                >
                  <p>{txnButtonText(pendingTransactions, "approve_" + token.address, "Approve")}</p>
                </div>
              )}
            </div>
            {!hasAllowance() && !token.isAvax && (
              <div className="zapin-header-help-text">
                <p>Note: The "Approve" transaction is only needed when bonding for the first rug</p>
                <p>for each token; subsequent bonding only requires you to perform the</p>
                <p>"zapin&mint" transaction.</p>
              </div>
            )}
          </div>
          <div className="zapin-body">
            <div className="zapin-body-header">
              <BondLogo bond={bond} />
              <div className="zapin-body-header-name">
                <p>TX settings</p>
              </div>
            </div>
            <div className="zapin-body-params">
              <div className="data-row">
                <p className="data-row-name">Destination token </p>
                <p className="data-row-value">{bond.displayName}</p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Slippage Tolerance</p>
                <p className="data-row-value">{trim(slippage)}%</p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Your Balance</p>
                <p className="data-row-value">{`${trim(token.balance, 6)} ${token.name}`}</p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Minimum Received Amount</p>
                <p className="data-row-value">
                  {isLoading ? <Skeleton width="100px" /> : `${minimumReceivedAmount} ${bond.displayUnits}`}
                </p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Approximately you will get</p>
                <p className="data-row-value">
                  {isLoading ? <Skeleton width="100px" /> : `~ ${trim(bond.bondQuote, 4)} RUG`}
                </p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Max You Can Buy</p>
                <p className="data-row-value">
                  {isLoading ? <Skeleton width="100px" /> : `${trim(bond.maxBondPrice, 4)} RUG`}
                </p>
              </div>
              <div className="data-row">
                <p className="data-row-name">ROI</p>
                <p className="data-row-value">
                  {isLoading ? <Skeleton width="100px" /> : `${trim(bond.bondDiscount * 100, 2)}%`}
                </p>
              </div>
              <div className="data-row">
                <p className="data-row-name">Minimum purchase</p>
                <p className="data-row-value">0.01 RUG</p>
              </div>
              {recipientAddress !== address && (
                <div className="data-row">
                  <p className="data-row-name">Recipient</p>
                  <p className="data-row-value">{shorten(recipientAddress)}</p>
                </div>
              )}
            </div>
          </div>
          <ChooseToken
            open={chooseTokenOpen}
            handleClose={handleChooseTokenClose}
            handleSelect={handleChooseTokenSelect}
            bond={bond}
          />
          <AdvancedSettings
            open={settingsOpen}
            handleClose={handleSettingsClose}
            slippage={slippage}
            recipientAddress={recipientAddress}
            onRecipientAddressChange={onRecipientAddressChange}
            onSlippageChange={onSlippageChange}
          />
        </Box>
      </Paper>
    </Modal>
  );
}
Example #22
Source File: BondPurchase.tsx    From rugenerous-frontend with MIT License 4 votes vote down vote up
function BondPurchase({ bond, slippage, recipientAddress }: IBondPurchaseProps) {
  const dispatch = useDispatch();
  const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();

  const [quantity, setQuantity] = useState("");
  const [useAvax, setUseAvax] = useState(false);

  const isBondLoading = useSelector<IReduxState, boolean>(state => state.bonding.loading ?? true);
  const [zapinOpen, setZapinOpen] = useState(false);

  const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
    return state.pendingTransactions;
  });

  const vestingPeriod = () => {
    return prettifySeconds(bond.vestingTerm, "day");
  };

  async function onBond() {
    if (await checkWrongNetwork()) return;

    if (quantity === "") {
      dispatch(warning({ text: messages.before_minting }));
      //@ts-ignore
    } else if (isNaN(quantity)) {
      dispatch(warning({ text: messages.before_minting }));
    } else if (bond.interestDue > 0 || bond.pendingPayout > 0) {
      const shouldProceed = window.confirm(messages.existing_mint);
      if (shouldProceed) {
        const trimBalance = trim(Number(quantity), 10);

        await dispatch(
          bondAsset({
            value: trimBalance,
            slippage,
            bond,
            networkID: chainID,
            provider,
            address: recipientAddress || address,
            useAvax,
          }),
        );
        clearInput();
      }
    } else {
      const trimBalance = trim(Number(quantity), 10);
      await dispatch(
        //@ts-ignore
        bondAsset({
          value: trimBalance,
          slippage,
          bond,
          networkID: chainID,
          provider,
          address: recipientAddress || address,
          useAvax,
        }),
      );
      clearInput();
    }
  }

  const clearInput = () => {
    setQuantity("");
  };

  const hasAllowance = useCallback(() => {
    return bond.allowance > 0;
  }, [bond.allowance]);

  const setMax = () => {
    let amount: any = Math.min(bond.maxBondPriceToken * 0.9999, useAvax ? bond.avaxBalance * 0.99 : bond.balance);

    if (amount) {
      amount = trim(amount);
    }

    setQuantity((amount || "").toString());
  };

  const bondDetailsDebounce = useDebounce(quantity, 1000);

  useEffect(() => {
    dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
  }, [bondDetailsDebounce]);

  const onSeekApproval = async () => {
    if (await checkWrongNetwork()) return;

    dispatch(changeApproval({ address, bond, provider, networkID: chainID }));
  };

  const handleZapinOpen = () => {
    dispatch(calcBondDetails({ bond, value: "0", provider, networkID: chainID }));
    setZapinOpen(true);
  };

  const handleZapinClose = () => {
    dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
    setZapinOpen(false);
  };

  const displayUnits = useAvax ? "AVAX" : bond.displayUnits;

  return (
    <Box display="flex" flexDirection="column">
      <Box display="flex" justifyContent="space-around" flexWrap="wrap">
        {bond.name === "wavax" && (
          <FormControl className="ohm-input" variant="outlined" color="primary" fullWidth>
            <div className="avax-checkbox">
              <input type="checkbox" checked={useAvax} onClick={() => setUseAvax(!useAvax)} />
              <p>Use AVAX</p>
            </div>
          </FormControl>
        )}
        <FormControl className="bond-input-wrap" variant="outlined" color="primary" fullWidth>
          <OutlinedInput
            placeholder="Amount"
            type="number"
            value={quantity}
            onChange={e => setQuantity(e.target.value)}
            labelWidth={0}
            className="bond-input"
            endAdornment={
              <InputAdornment position="end">
                <div className="stake-input-btn" onClick={setMax}>
                  <p>Max</p>
                </div>
              </InputAdornment>
            }
          />
        </FormControl>
        {hasAllowance() || useAvax ? (
          <div
            className="transaction-button bond-approve-btn"
            onClick={async () => {
              if (isPendingTxn(pendingTransactions, "bond_" + bond.name)) return;
              await onBond();
            }}
          >
            <p>{txnButtonText(pendingTransactions, "bond_" + bond.name, "Rug Me")}</p>
          </div>
        ) : (
          <div
            className="transaction-button bond-approve-btn"
            onClick={async () => {
              if (isPendingTxn(pendingTransactions, "approve_" + bond.name)) return;
              await onSeekApproval();
            }}
          >
            <p>{txnButtonText(pendingTransactions, "approve_" + bond.name, "Approve")}</p>
          </div>
        )}

        {/* <div className="transaction-button bond-approve-btn" onClick={handleZapinOpen}>
          <p>Zap</p>
        </div> */}

        {!hasAllowance() && !useAvax && (
          <div className="help-text">
            <p className="help-text-desc">
              Note: The "Approve" transaction is only needed when rugging yourself for the first rug; subsequent rugs
              only requires you to perform the "Rug Me" transaction.
            </p>
          </div>
        )}
      </Box>

      <Slide direction="left" in={true} mountOnEnter unmountOnExit {...{ timeout: 533 }}>
        <Box className="bond-data">
          <div className="data-row">
            <p className="bond-balance-title">Your Balance</p>
            <p className="bond-balance-title">
              {isBondLoading ? (
                <Skeleton width="100px" />
              ) : (
                <>
                  {trim(useAvax ? bond.avaxBalance : bond.balance, 4)} {displayUnits}
                </>
              )}
            </p>
          </div>

          <div className="data-row">
            <p className="bond-balance-title">You Will Get</p>
            <p className="price-data bond-balance-title">
              {isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondQuote, 4)} RUG`}
            </p>
          </div>

          <div className={`data-row`}>
            <p className="bond-balance-title">Max You Can Buy</p>
            <p className="price-data bond-balance-title">
              {isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.maxBondPrice, 4)} RUG`}
            </p>
          </div>

          <div className="data-row">
            <p className="bond-balance-title">ROI</p>
            <p className="bond-balance-title">
              {isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondDiscount * 100, 2)}%`}
            </p>
          </div>

          <div className="data-row">
            <p className="bond-balance-title">Vesting Term</p>
            <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : vestingPeriod()}</p>
          </div>

          <div className="data-row">
            <p className="bond-balance-title">Minimum purchase</p>
            <p className="bond-balance-title">0.01 RUG</p>
          </div>

          {recipientAddress !== address && (
            <div className="data-row">
              <p className="bond-balance-title">Recipient</p>
              <p className="bond-balance-title">
                {isBondLoading ? <Skeleton width="100px" /> : shorten(recipientAddress)}
              </p>
            </div>
          )}
        </Box>
      </Slide>
      {/* <Zapin open={zapinOpen} handleClose={handleZapinClose} bond={bond} /> */}
    </Box>
  );
}
Example #23
Source File: index.tsx    From lobis-frontend with MIT License 4 votes vote down vote up
function Stake() {
    const dispatch = useDispatch();
    const { provider, address, connect, chainID, checkWrongNetwork } = useWeb3Context();

    const [view, setView] = useState(0);
    const [quantity, setQuantity] = useState<string>("");

    const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);
    const currentIndex = useSelector<IReduxState, string>(state => {
        return state.app.currentIndex;
    });
    const fiveDayRate = useSelector<IReduxState, number>(state => {
        return state.app.fiveDayRate;
    });
    const lobiBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.lobi;
    });
    const sTokenBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.sLobi;
    });
    const stakeAllowance = useSelector<IReduxState, number>(state => {
        return state.account.staking && state.account.staking.lobi;
    });
    const unstakeAllowance = useSelector<IReduxState, number>(state => {
        return state.account.staking && state.account.staking.sLobi;
    });
    const stakingRebase = useSelector<IReduxState, number>(state => {
        return state.app.stakingRebase;
    });
    const stakingAPY = useSelector<IReduxState, number>(state => {
        return state.app.stakingAPY;
    });
    const stakingTVL = useSelector<IReduxState, number>(state => {
        return state.app.stakingTVL;
    });
    const lobiPrice = useSelector<IReduxState, number>(state => {
        return state.app.marketPrice;
    });

    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    const setMax = () => {
        if (view === 0) {
            setQuantity(lobiBalance);
        } else {
            setQuantity(sTokenBalance);
        }
    };

    const onSeekApproval = async (token: string) => {
        if (await checkWrongNetwork()) return;

        await dispatch(changeApproval({ address, token, provider, networkID: chainID }));
    };

    const onChangeStake = async (action: string) => {
        if (await checkWrongNetwork()) return;
        if (quantity === "" || parseFloat(quantity) === 0) {
            dispatch(warning({ text: action === "stake" ? messages.before_stake : messages.before_unstake }));
        } else {
            await dispatch(changeStake({ address, action, value: String(quantity), provider, networkID: chainID }));
            setQuantity("");
        }
    };

    const hasAllowance = useCallback(
        token => {
            if (token === "lobi") {
                return stakeAllowance > 0;
            } else if (token === "sLobi") {
                return unstakeAllowance > 0;
            }
            return 0;
        },
        [stakeAllowance, unstakeAllowance],
    );

    const changeView = (newView: number) => () => {
        setView(newView);
        setQuantity("");
    };

    const trimmedSLobiBalance = trim(Number(sTokenBalance), 6);
    const trimmedStakingAPY = trim(stakingAPY * 100, 1);
    const stakingRebasePercentage = trim(stakingRebase * 100, 4);
    const nextRewardValue = trim((Number(stakingRebasePercentage) / 100) * Number(trimmedSLobiBalance), 6);
    const stakingAmountInUSD = Number(sTokenBalance) * lobiPrice;
    const nextRewardValueInUSD = (Number(stakingRebasePercentage) / 100) * Number(trimmedSLobiBalance) * lobiPrice;

    return (
        <div className="stake-view">
            <Zoom in={true}>
                <div className="stake-card">
                    <Grid className="stake-card-grid" container direction="column" spacing={2}>
                        <Grid item>
                            <div className="stake-card-header">
                                <p className="stake-card-header-title">{TOKEN_NAME} Staking ( III , III )</p>
                                <RebaseTimer />
                            </div>
                        </Grid>

                        <Grid item>
                            <div className="stake-card-metrics">
                                <Grid container spacing={2}>
                                    <Grid item xs={12} sm={4} md={4} lg={4}>
                                        <div className="stake-card-apy">
                                            <p className="stake-card-metrics-title">APY</p>

                                            <p className="stake-card-metrics-value">
                                                {stakingAPY ? (
                                                    <>
                                                        {parseFloat(trimmedStakingAPY) > 1000000000
                                                            ? "100,000,000% +"
                                                            : `${new Intl.NumberFormat("en-US").format(Number(trimmedStakingAPY))}%`}
                                                    </>
                                                ) : (
                                                    <Skeleton width="150px" />
                                                )}
                                            </p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="stake-card-tvl">
                                            <p className="stake-card-metrics-title">TVL</p>
                                            <p className="stake-card-metrics-value">
                                                {stakingTVL ? (
                                                    new Intl.NumberFormat("en-US", {
                                                        style: "currency",
                                                        currency: "USD",
                                                        maximumFractionDigits: 0,
                                                        minimumFractionDigits: 0,
                                                    }).format(stakingTVL)
                                                ) : (
                                                    <Skeleton width="150px" />
                                                )}
                                            </p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={6} sm={4} md={4} lg={4}>
                                        <div className="stake-card-index">
                                            <p className="stake-card-metrics-title">Current Index</p>
                                            <p className="stake-card-metrics-value">
                                                {currentIndex ? (
                                                    <>
                                                        {trim(Number(currentIndex), 4)} {TOKEN_NAME}
                                                    </>
                                                ) : (
                                                    <Skeleton width="150px" />
                                                )}
                                            </p>
                                        </div>
                                    </Grid>
                                </Grid>
                            </div>
                        </Grid>

                        <div className="stake-card-area">
                            {!address && (
                                <div className="stake-card-wallet-notification">
                                    <div className="stake-card-wallet-connect-btn" onClick={connect}>
                                        <p>Connect Wallet</p>
                                    </div>
                                    <p className="stake-card-wallet-desc-text">Connect your wallet to stake {TOKEN_NAME} tokens!</p>
                                </div>
                            )}
                            {address && (
                                <div>
                                    <div className="stake-card-action-area">
                                        <div className="stake-card-action-stage-btns-wrap">
                                            <div onClick={changeView(0)} className={classnames("stake-card-action-stage-btn", { active: !view })}>
                                                <p>Stake</p>
                                            </div>
                                            <div onClick={changeView(1)} className={classnames("stake-card-action-stage-btn", { active: view })}>
                                                <p>Unstake</p>
                                            </div>
                                        </div>

                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder="Amount"
                                                className="stake-card-action-input"
                                                value={quantity}
                                                onChange={e => setQuantity(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={setMax} className="stake-card-action-input-btn">
                                                            <p>Max</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />

                                            {view === 0 && (
                                                <div className="stake-card-tab-panel">
                                                    {address && hasAllowance("lobi") ? (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "staking")) return;
                                                                onChangeStake("stake");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "staking", `Stake ${TOKEN_NAME}`)}</p>
                                                        </div>
                                                    ) : (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "approve_staking")) return;
                                                                onSeekApproval("lobi");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "approve_staking", "Approve")}</p>
                                                        </div>
                                                    )}
                                                </div>
                                            )}

                                            {view === 1 && (
                                                <div className="stake-card-tab-panel">
                                                    {address && hasAllowance("sLobi") ? (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "unstaking")) return;
                                                                onChangeStake("unstake");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "unstaking", `Unstake ${TOKEN_NAME}`)}</p>
                                                        </div>
                                                    ) : (
                                                        <div
                                                            className="stake-card-tab-panel-btn"
                                                            onClick={() => {
                                                                if (isPendingTxn(pendingTransactions, "approve_unstaking")) return;
                                                                onSeekApproval("sLobi");
                                                            }}
                                                        >
                                                            <p>{txnButtonText(pendingTransactions, "approve_unstaking", "Approve")}</p>
                                                        </div>
                                                    )}
                                                </div>
                                            )}
                                        </div>

                                        <div className="stake-card-action-help-text">
                                            {address && ((!hasAllowance("lobi") && view === 0) || (!hasAllowance("sLobi") && view === 1)) && (
                                                <p>
                                                    Note: The "Approve" transaction is only needed when staking/unstaking for the first lobi; subsequent staking/unstaking only
                                                    requires you to perform the "Stake" or "Unstake" transaction.
                                                </p>
                                            )}
                                        </div>
                                    </div>

                                    <div className="stake-user-data">
                                        <div className="data-row">
                                            <p className="data-row-name">Your Balance</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {trim(Number(lobiBalance), 4)} {TOKEN_NAME}
                                                    </>
                                                )}
                                            </p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Your Staked Balance</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {trimmedSLobiBalance} {STAKING_TOKEN_NAME}
                                                    </>
                                                )}
                                            </p>
                                        </div>
                                        <div className="data-row">
                                            <p className="data-row-name">$ Amount</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {new Intl.NumberFormat("en-US", {
                                                            style: "currency",
                                                            currency: "USD",
                                                            maximumFractionDigits: 0,
                                                            minimumFractionDigits: 0,
                                                        }).format(stakingAmountInUSD)}
                                                    </>
                                                )}
                                            </p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Next Reward Amount</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {nextRewardValue} {STAKING_TOKEN_NAME}
                                                    </>
                                                )}
                                            </p>
                                        </div>
                                        <div className="data-row">
                                            <p className="data-row-name">Next Reward Amount in $</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {new Intl.NumberFormat("en-US", {
                                                            style: "currency",
                                                            currency: "USD",
                                                            maximumFractionDigits: 0,
                                                            minimumFractionDigits: 0,
                                                        }).format(nextRewardValueInUSD)}
                                                    </>
                                                )}
                                            </p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Next Reward Yield</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{stakingRebasePercentage}%</>}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">ROI (5-Day Rate)</p>
                                            <p className="data-row-value">{isAppLoading ? <Skeleton width="80px" /> : <>{trim(Number(fiveDayRate) * 100, 4)}%</>}</p>
                                        </div>
                                    </div>
                                </div>
                            )}
                        </div>
                    </Grid>
                </div>
            </Zoom>
        </div>
    );
}
Example #24
Source File: index.tsx    From lobis-frontend with MIT License 4 votes vote down vote up
function LobisMeter() {
    const dispatch = useDispatch();
    const { provider, address, connect, chainID, checkWrongNetwork } = useWeb3Context();

    const [view, setView] = useState(0);
    const [quantity, setQuantity] = useState<string>("");
    const [rewardYield, setRewardYield] = useState<string>("");
    const [lobiPrice, setLobiPrice] = useState<string>("");
    const [days, setDays] = useState<number>(30);
    const [futureLobiPrice, setFutureLobiPrice] = useState<string>("");
    const [apy, setApy] = useState<string>("");
    const isAppLoading = useSelector<IReduxState, boolean>(state => state.app.loading);

    const sLobiBalance = useSelector<IReduxState, string>(state => {
        return state.account.balances && state.account.balances.sLobi;
    });

    const stakingRebase = useSelector<IReduxState, number>(state => {
        return state.app.stakingRebase;
    });
    const stakingAPY = useSelector<IReduxState, number>(state => {
        return state.app.stakingAPY;
    });

    const marketPrice = useSelector<IReduxState, number>(state => {
        return state.app.marketPrice;
    });
    const epoch = useSelector<IReduxState, any[]>(state => {
        return state.app.epoch;
    });

    const handleDays = (newValue: number | number[]) => {
        setDays(newValue as number);
    };
    const setMax = () => {
        setQuantity(sLobiBalance);
    };
    const handleAPY = (value: string) => {
        setApy(value);
        const newRewardYield = (Math.pow(Number(value) / 100, 1 / (365 * dailyRebaseAmounts)) - 1) * 100;
        setRewardYield(trim(newRewardYield, 4).toString());
        if (value === "") {
            setRewardYield("");
        }
    };
    const handleRewardYield = (value: string) => {
        setRewardYield(value);
        const newAPY = (Math.pow(1 + Number(value) / 100, 365 * dailyRebaseAmounts) - 1) * 100;
        setApy(trim(newAPY, 4).toString());
        if (value === "") {
            setApy("");
        }
    };
    const setCurrent = (type: string) => {
        switch (type) {
            case "rewardYield":
                setRewardYield(stakingRebasePercentage);
                const newAPY = (Math.pow(1 + Number(stakingRebasePercentage) / 100, 365 * dailyRebaseAmounts) - 1) * 100;
                setApy(trim(newAPY, 4).toString());
                break;
            case "setPrice":
                setLobiPrice(marketPrice.toString());
                break;
            case "futurePrice":
                setFutureLobiPrice(marketPrice.toString());
                break;
        }
    };

    const trimmedSLobiBalance = trim(Number(sLobiBalance), 6);
    const stakingRebasePercentage = trim(stakingRebase * 100, 4);
    const blockSecondLength = 13;
    const rebaseTimeInSeconds = epoch ? epoch[0] * blockSecondLength : 28800;
    const dailyRebaseAmounts = 86400 / rebaseTimeInSeconds;
    const totalReturn = (Math.pow(1 + Number(rewardYield) / 100, days * dailyRebaseAmounts) - 1) * Number(quantity);
    const initialInvestment = parseFloat(lobiPrice) * parseFloat(quantity);
    const potentialReturn = parseFloat(futureLobiPrice) * (totalReturn + Number(quantity)) - initialInvestment;
    const daysUntilTwoTimes = Math.log(2) / Math.log(1 + Number(rewardYield) / 100) / dailyRebaseAmounts;
    const daysUntilFiveTimes = Math.log(5) / Math.log(1 + Number(rewardYield) / 100) / dailyRebaseAmounts;
    const daysUntilTenTimes = Math.log(10) / Math.log(1 + Number(rewardYield) / 100) / dailyRebaseAmounts;
    return (
        <div className="stake-view">
            <Zoom in={true}>
                <div className="stake-card">
                    <Grid className="stake-card-grid" container direction="column" spacing={2}>
                        <Grid item>
                            <div className="stake-card-header">
                                <p className="stake-card-header-title">Calculator</p>
                                <p className="stake-card-header-description">Please fill the inputs to simulate your rewards</p>
                            </div>
                        </Grid>

                        <Grid item>
                            <div className="stake-card-metrics">
                                <Grid container spacing={2}>
                                    <Grid item lg={4} md={4} sm={4} xs={12}>
                                        <div className="stake-card-apy">
                                            <p className="stake-card-metrics-title">{TOKEN_NAME} Price</p>
                                            <p className="stake-card-metrics-value">{isAppLoading ? <Skeleton width="100px" /> : `$${trim(marketPrice, 2)}`}</p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={12} sm={4} md={4} lg={4}>
                                        <div className="stake-card-tvl">
                                            <p className="stake-card-metrics-title">Current Reward Yield</p>
                                            <p className="stake-card-metrics-value">{isAppLoading ? <Skeleton width="80px" /> : <>{stakingRebasePercentage}%</>}</p>
                                        </div>
                                    </Grid>

                                    <Grid item xs={12} sm={4} md={4} lg={4}>
                                        <div className="stake-card-index">
                                            <p className="stake-card-metrics-title">Your {STAKING_TOKEN_NAME} Balance</p>
                                            <p className="stake-card-metrics-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {trimmedSLobiBalance} {STAKING_TOKEN_NAME}
                                                    </>
                                                )}
                                            </p>
                                        </div>
                                    </Grid>
                                </Grid>
                            </div>
                        </Grid>

                        <div className="stake-card-area">
                            {address && (
                                <div>
                                    <div className="stake-card-action-area">
                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder={`${STAKING_TOKEN_NAME} amount`}
                                                className="stake-card-action-input"
                                                value={quantity}
                                                onChange={e => setQuantity(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={setMax} className="stake-card-action-input-btn">
                                                            <p>Max</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />
                                        </div>
                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder={`APY (%)`}
                                                className="stake-card-action-input"
                                                value={apy}
                                                onChange={e => handleAPY(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={<InputAdornment position="end"></InputAdornment>}
                                            />
                                        </div>
                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder={`Reward yield each rebase (%)`}
                                                className="stake-card-action-input"
                                                value={rewardYield}
                                                onChange={e => handleRewardYield(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={() => setCurrent("rewardYield")} className="stake-card-action-input-btn">
                                                            <p>Current</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />
                                        </div>
                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder={`${TOKEN_NAME} price at purchase ($) `}
                                                className="stake-card-action-input"
                                                value={lobiPrice}
                                                onChange={e => setLobiPrice(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={() => setCurrent("setPrice")} className="stake-card-action-input-btn">
                                                            <p>Current</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />
                                        </div>
                                        <div className="stake-card-action-row">
                                            <OutlinedInput
                                                type="number"
                                                placeholder={`Future ${TOKEN_NAME} market price ($)`}
                                                className="stake-card-action-input"
                                                value={futureLobiPrice}
                                                onChange={e => setFutureLobiPrice(e.target.value)}
                                                labelWidth={0}
                                                endAdornment={
                                                    <InputAdornment position="end">
                                                        <div onClick={() => setCurrent("futurePrice")} className="stake-card-action-input-btn">
                                                            <p>Current</p>
                                                        </div>
                                                    </InputAdornment>
                                                }
                                            />
                                        </div>
                                        <div className="stake-card-action-row">
                                            <Slider className="slider" min={1} max={365} onChange={(e, val) => handleDays(val)} value={days} />{" "}
                                            <p className="days-text">
                                                {days} {days === 1 ? "Day" : "Days"}
                                            </p>
                                        </div>
                                    </div>

                                    <div className="stake-user-data">
                                        <div className="data-row">
                                            <p className="data-row-name">Your Initial Investment</p>
                                            <p className="data-row-value">
                                                {isAppLoading ? (
                                                    <Skeleton width="80px" />
                                                ) : (
                                                    <>
                                                        {initialInvestment > 0
                                                            ? new Intl.NumberFormat("en-US", {
                                                                  style: "currency",
                                                                  currency: "USD",
                                                                  maximumFractionDigits: 5,
                                                                  minimumFractionDigits: 0,
                                                              }).format(initialInvestment)
                                                            : new Intl.NumberFormat("en-US", {
                                                                  style: "currency",
                                                                  currency: "USD",
                                                                  maximumFractionDigits: 0,
                                                                  minimumFractionDigits: 0,
                                                              }).format(0)}
                                                    </>
                                                )}
                                            </p>
                                        </div>

                                        {/*<div className="data-row">
                                            <p className="data-row-name">Current Wealth</p>
                                            <p className="data-row-value">
                                                {
                                                    <>
                                                        {marketPrice * parseFloat(trimmedSLobiBalance) > 0
                                                            ? new Intl.NumberFormat("en-US", {
                                                                  style: "currency",
                                                                  currency: "USD",
                                                                  maximumFractionDigits: 5,
                                                                  minimumFractionDigits: 0,
                                                              }).format(marketPrice * parseFloat(trimmedSLobiBalance))
                                                            : new Intl.NumberFormat("en-US", {
                                                                  style: "currency",
                                                                  currency: "USD",
                                                                  maximumFractionDigits: 0,
                                                                  minimumFractionDigits: 0,
                                                              }).format(0)}
                                                    </>
                                                }
                                            </p>
                                            </div>*/}

                                        <div className="data-row">
                                            <p className="data-row-name">{`${TOKEN_NAME} rewards estimation`}</p>
                                            <p className="data-row-value">{totalReturn > 0 ? `${trim(totalReturn, 4)} ${TOKEN_NAME}` : `0 ${TOKEN_NAME}`}</p>
                                        </div>

                                        <div className="data-row">
                                            <p className="data-row-name">Total return</p>
                                            <p className="data-row-value">
                                                {!isNaN(potentialReturn)
                                                    ? new Intl.NumberFormat("en-US", {
                                                          style: "currency",
                                                          currency: "USD",
                                                          maximumFractionDigits: 5,
                                                          minimumFractionDigits: 0,
                                                      }).format(potentialReturn)
                                                    : "--"}
                                            </p>
                                        </div>
                                        {rewardYield !== "" && (
                                            <div style={{ width: "100%" }}>
                                                <Divider style={{ backgroundColor: " rgba(255, 255, 255, 0.2)" }} />
                                            </div>
                                        )}
                                    </div>
                                </div>
                            )}
                            {rewardYield !== "" && (
                                <div className="stake-user-data">
                                    <div className="data-row">
                                        <p className="data-row-name">Amount of days Until...</p>
                                        <p className="data-row-value"></p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">2x {STAKING_TOKEN_NAME}</p>
                                        <p className="data-row-value">
                                            {daysUntilTwoTimes.toFixed(1)} {daysUntilTwoTimes > 1 ? "Days" : "Day"}
                                        </p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">5x {STAKING_TOKEN_NAME}</p>
                                        <p className="data-row-value">
                                            {daysUntilFiveTimes.toFixed(1)} {daysUntilTwoTimes > 1 ? "Days" : "Day"}
                                        </p>
                                    </div>
                                    <div className="data-row">
                                        <p className="data-row-name">10x {STAKING_TOKEN_NAME}</p>
                                        <p className="data-row-value">
                                            {daysUntilTenTimes.toFixed(1)} {daysUntilTwoTimes > 1 ? "Days" : "Day"}
                                        </p>
                                    </div>
                                </div>
                            )}
                        </div>
                    </Grid>
                </div>
            </Zoom>
        </div>
    );
}
Example #25
Source File: BondPurchase.tsx    From lobis-frontend with MIT License 4 votes vote down vote up
function BondPurchase({ bond, slippage, recipientAddress }: IBondPurchaseProps) {
    const SECONDS_TO_REFRESH = 60;
    const dispatch = useDispatch();
    const { provider, address, chainID, checkWrongNetwork } = useWeb3Context();

    const [quantity, setQuantity] = useState("");
    const [secondsToRefresh, setSecondsToRefresh] = useState(SECONDS_TO_REFRESH);

    const isBondLoading = useSelector<IReduxState, boolean>(state => state.bonding.loading ?? true);

    const pendingTransactions = useSelector<IReduxState, IPendingTxn[]>(state => {
        return state.pendingTransactions;
    });

    const vestingPeriod = () => {
        return prettifySeconds(bond.vestingTerm * 13.01, "day");
    };

    async function onBond() {
        if (await checkWrongNetwork()) return;

        if (quantity === "") {
            dispatch(warning({ text: messages.before_minting }));
            //@ts-ignore
        } else if (isNaN(quantity)) {
            dispatch(warning({ text: messages.before_minting }));
        } else if (bond.interestDue > 0 || bond.pendingPayout > 0) {
            const shouldProceed = window.confirm(messages.existing_mint);
            if (shouldProceed) {
                await dispatch(
                    bondAsset({
                        value: quantity,
                        slippage,
                        bond,
                        networkID: chainID,
                        provider,
                        address: recipientAddress || address,
                    }),
                );
                clearInput();
            }
        } else {
            await dispatch(
                //@ts-ignore
                bondAsset({
                    value: quantity,
                    slippage,
                    bond,
                    networkID: chainID,
                    provider,
                    address: recipientAddress || address,
                }),
            );
            clearInput();
        }
    }

    const clearInput = () => {
        setQuantity("");
    };

    const hasAllowance = useCallback(() => {
        return bond.allowance > 0;
    }, [bond.allowance]);

    const setMax = () => {
        const amount = Math.min(bond.maxBondPriceToken, bond.balance);
        const am = fromExponential(amount);
        setQuantity((am || "").toString());
    };

    const bondDetailsDebounce = useDebounce(quantity, 1000);

    useEffect(() => {
        dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
    }, [bondDetailsDebounce]);

    useEffect(() => {
        let interval: any = null;
        if (secondsToRefresh > 0) {
            interval = setInterval(() => {
                setSecondsToRefresh(secondsToRefresh => secondsToRefresh - 1);
            }, 1000);
        } else {
            clearInterval(interval);
            dispatch(calcBondDetails({ bond, value: quantity, provider, networkID: chainID }));
            setSecondsToRefresh(SECONDS_TO_REFRESH);
        }
        return () => clearInterval(interval);
    }, [secondsToRefresh, quantity]);

    const onSeekApproval = async () => {
        if (await checkWrongNetwork()) return;

        dispatch(changeApproval({ address, bond, provider, networkID: chainID }));
    };

    const displayUnits = bond.displayUnits;

    return (
        <Box display="flex" flexDirection="column">
            <Box display="flex" justifyContent="space-around" flexWrap="wrap">
                <FormControl className="bond-input-wrap" variant="outlined" color="primary" fullWidth>
                    <OutlinedInput
                        placeholder="Amount"
                        type="number"
                        value={quantity}
                        onChange={e => setQuantity(e.target.value)}
                        labelWidth={0}
                        className="bond-input"
                        disabled={bond.name === lobiOHMBond.name}
                        endAdornment={
                            <InputAdornment position="end">
                                <div className="stake-input-btn" onClick={setMax}>
                                    <p>Max</p>
                                </div>
                            </InputAdornment>
                        }
                    />
                </FormControl>
                {bond.name === lobiOHMBond.name ? (
                    <div className="transaction-button bond-disabled-btn">
                        <p>{txnButtonText(pendingTransactions, "bond_" + bond.name, "Disabled Bond")}</p>
                    </div>
                ) : hasAllowance() ? (
                    Number(quantity) > bond.balance ? (
                        <div className="transaction-button bond-disabled-btn">
                            <p>{txnButtonText(pendingTransactions, "bond_" + bond.name, "Not Enough Balance")}</p>
                        </div>
                    ) : (
                        <div
                            className="transaction-button bond-approve-btn"
                            onClick={async () => {
                                if (isPendingTxn(pendingTransactions, "bond_" + bond.name)) return;
                                await onBond();
                            }}
                        >
                            <p>{txnButtonText(pendingTransactions, "bond_" + bond.name, "Mint")}</p>
                        </div>
                    )
                ) : (
                    <div
                        className="transaction-button bond-approve-btn"
                        onClick={async () => {
                            if (isPendingTxn(pendingTransactions, "approve_" + bond.name)) return;
                            await onSeekApproval();
                        }}
                    >
                        <p>{txnButtonText(pendingTransactions, "approve_" + bond.name, "Approve")}</p>
                    </div>
                )}

                {!hasAllowance() && (
                    <div className="help-text">
                        <p className="help-text-desc">
                            Note: The "Approve" transaction is only needed when minting for the first time; subsequent minting only requires you to perform the "Mint" transaction.
                        </p>
                    </div>
                )}
            </Box>

            <Slide direction="left" in={true} mountOnEnter unmountOnExit {...{ timeout: 0 }}>
                <Box className="bond-data">
                    <div className="data-row">
                        <p className="bond-balance-title">Your Balance</p>
                        <p className="bond-balance-title">
                            {isBondLoading ? (
                                <Skeleton width="100px" />
                            ) : (
                                <>
                                    {trim(bond.balance, 10)} {displayUnits}
                                </>
                            )}
                        </p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">You Will Get</p>
                        <p className="price-data bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondQuote, 4)} ${TOKEN_NAME}`}</p>
                    </div>

                    <div className={`data-row`}>
                        <p className="bond-balance-title">Max You Can Buy</p>
                        <p className="price-data bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.maxBondPrice, 4)} ${TOKEN_NAME}`}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">ROI</p>
                        <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : `${trim(bond.bondDiscount * 100, 2)}%`}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">Vesting Term</p>
                        <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : vestingPeriod()}</p>
                    </div>

                    <div className="data-row">
                        <p className="bond-balance-title">Minimum purchase</p>
                        <p className="bond-balance-title">0.01 {TOKEN_NAME}</p>
                    </div>

                    {recipientAddress !== address && (
                        <div className="data-row">
                            <p className="bond-balance-title">Recipient</p>
                            <p className="bond-balance-title">{isBondLoading ? <Skeleton width="100px" /> : shorten(recipientAddress)}</p>
                        </div>
                    )}
                </Box>
            </Slide>
        </Box>
    );
}