react#ReactText TypeScript Examples

The following examples show how to use react#ReactText. 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: ColumnsHider.tsx    From ke with MIT License 6 votes vote down vote up
export function ColumnsHider<T>({ children, onChange, columns, visibleColumns }: ColumnHiderProps<T>): JSX.Element {
  const handleChange = useCallback(
    (values: ReactText[]) => {
      const newVisibleColumns = columns.filter(({ name }) => values.includes(String(name)))

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

  return (
    <div>
      <Popover placement="right-start">
        <PopoverTrigger>
          <Button margin="10px 0">Отображаемые колонки</Button>
        </PopoverTrigger>
        <Portal>
          <PopoverContent>
            <PopoverArrow />
            <PopoverHeader>Выберите отображаемые колонки</PopoverHeader>
            <PopoverCloseButton />
            <PopoverBody maxHeight="400px" overflow="scroll">
              <CheckboxGroup value={visibleColumns.map(({ name }) => name)} onChange={handleChange}>
                {columns.map(({ name, header }) => (
                  <Checkbox value={name} display="block">
                    {header}
                  </Checkbox>
                ))}
              </CheckboxGroup>
            </PopoverBody>
          </PopoverContent>
        </Portal>
      </Popover>
      {children}
    </div>
  )
}
Example #2
Source File: cellDescToProps.ts    From ke with MIT License 6 votes vote down vote up
export function cellDescToProps<T, CProps, Extra>(
  cellDesc: CellDesc<CProps, T, Extra>,
  item: T,
  rowIndex: number,
  columnIndex: number,
  extraGenerator: (item: unknown, rowIndex: number, cellIndex: number) => Extra
): CellProps<CProps> | PropsWithChildren<{}> {
  const configOrNode = isCellGenerator(cellDesc)
    ? cellDesc(item, rowIndex, columnIndex, extraGenerator(item, rowIndex, columnIndex))
    : cellDesc

  if (typeof configOrNode === 'string' && typeof item === 'object' && configOrNode in item) {
    return {
      children: (item as Record<string, unknown>)[configOrNode] as ReactText,
    }
  }

  const { value, ...restProps } = isCellConfig(configOrNode) ? configOrNode : { value: configOrNode }

  return {
    ...restProps,
    children: isCellNodeGenerator(value)
      ? value(item, rowIndex, columnIndex, extraGenerator(item, rowIndex, columnIndex))
      : value,
  }
}
Example #3
Source File: helpers.ts    From glide-frontend with GNU General Public License v3.0 6 votes vote down vote up
useCompetitionCakeRewards = (userCakeReward: ReactText) => {
  const cakeAsBigNumber = new BigNumber(userCakeReward as string)
  const cakeBalance = getBalanceNumber(cakeAsBigNumber)
  const cakePriceUsdc = usePriceCakeUsdc()
  return {
    cakeReward: cakeBalance,
    dollarValueOfCakeReward: cakePriceUsdc.gt(0) ? cakeBalance * cakePriceUsdc.toNumber() : null,
  }
}
Example #4
Source File: helpers.ts    From vvs-ui with GNU General Public License v3.0 6 votes vote down vote up
useCompetitionCakeRewards = (userCakeReward: ReactText) => {
  const cakeAsBigNumber = new BigNumber(userCakeReward as string)
  const cakeBalance = getBalanceNumber(cakeAsBigNumber)
  const croPriceUsdc = usePriceVvsUsdc()
  return {
    cakeReward: cakeBalance,
    dollarValueOfCakeReward: croPriceUsdc.gt(0) ? cakeBalance * croPriceUsdc.toNumber() : null,
  }
}
Example #5
Source File: utility.ts    From save-food with MIT License 6 votes vote down vote up
replaceComma = (value: ReactText): string => `${value}`.replace(/,/g, '.')
Example #6
Source File: DataTable.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
onRowSelectionColumnClicked = (selectedRowKeys: ReactText[]): void => {
    if (this.isRowSelectionEnabled) {
      this.selectedRowKeys = selectedRowKeys as string[];
    }
  };
Example #7
Source File: DataTableHelpers.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
/**
 *
 * @param tableFilters
 * @param onFilterChange
 * @param entityName
 * @param fields
 * @param metadata
 * @param apiFilters
 */
export function setFilters(
  tableFilters: Record<string, Array<ReactText | boolean> | null>,
  onFilterChange: FilterChangeCallback,
  entityName: string,
  fields: string[],
  metadata: Metadata,
  apiFilters?: JmixEntityFilter[],
) {
  let nextApiFilters: JmixEntityFilter[] = [];

  if (apiFilters != null && apiFilters.length > 0) {

    // We check which of the current API filter conditions needs to be preserved regardless of table filters state.
    // Particularly we preserve filters on columns that are not displayed.
    const preservedConditions: JmixEntityFilter[] = getPreservedConditions(apiFilters, fields);

    if (preservedConditions.length > 0) {
      nextApiFilters = [
        ...nextApiFilters,
        ...preservedConditions
      ];
    }
  }

  // Now we modify API filters based on the state of table filters
  if (tableFilters) {
    fields.forEach((propertyName: string) => {
      if (Object.prototype.hasOwnProperty.call(tableFilters, propertyName)
          && tableFilters[propertyName] != null
          && tableFilters[propertyName]!.length > 0) {

        const propertyInfoNN = getPropertyInfoNN(propertyName as string, entityName, metadata.entities);

        // Enum
        if (propertyInfoNN.attributeType === 'ENUM') {
          addFilter(nextApiFilters, propertyName, '_in', tableFilters[propertyName]);
          return;
        }

        const {operator, value} = JSON.parse(String(tableFilters[propertyName]![0]));

        // Temporal interval
        if (operator === '__inInterval') {
          const {minDate, maxDate} = value;
          addFilter(nextApiFilters, propertyName, '_gte', minDate);
          addFilter(nextApiFilters, propertyName, '_lte', maxDate);
          return;
        }

        // Association
        if (isRelationProperty(propertyInfoNN)) {
          nextApiFilters.push({
            [propertyName]: {
              id: {
                [operator]: value
              }
            }
          });
          return;
        }

        // Everything else
        addFilter(nextApiFilters, propertyName, operator, value);
      }
    });
  }

  onFilterChange(nextApiFilters);
}
Example #8
Source File: BadgePage.tsx    From nuzlocke with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
function BadgePage(): JSX.Element {
  const navigate = useNavigate();
  const { badge, game } = useParams();
  const { t } = useTranslation('badges');
  const selectedGame = useStore(useCallback((state) => state.selectedGame, []));
  const [tab, setTab] = useState(0);

  const selectedDetail =
    !!game && DETAILS[game] && !!badge && typeof Number(badge) === 'number'
      ? DETAILS[game][Number(badge)]
      : null;

  useEffect(() => {
    if (selectedGame?.value !== game) {
      navigate('/');
    }
  }, [game, navigate, selectedGame]);

  useEffect(() => {
    if (!selectedDetail) {
      navigate('/');
    }
  }, [game, navigate, selectedDetail]);

  const panes = selectedDetail
    ? selectedDetail.map((gameDetail) => {
        return {
          menuItem: gameDetail.game,
          render: () => (
            <Tab.Pane>
              <BadgeDetail selectedDetail={selectedDetail[tab]} />
            </Tab.Pane>
          ),
        };
      })
    : null;

  const handleTabChange = (newIndex: ReactText) => {
    setTab(Number(newIndex));
  };

  return (
    <Page header={t('details')}>
      <Tab
        activeIndex={tab}
        className={styles.tabs}
        data-testid="badge-details-tabs"
        menu={{ attached: false, tabular: false }}
        onTabChange={(e, data) => handleTabChange(data.activeIndex)}
        panes={panes}
      />
    </Page>
  );
}
Example #9
Source File: validation.ts    From save-food with MIT License 5 votes vote down vote up
checkValidation = (control: InputControl, value: ReactText) =>
	!!(!control.error && value && `${value}`.trim() !== '')
Example #10
Source File: AddRule.tsx    From nuzlocke with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
function AddRule(): JSX.Element {
  const { t } = useTranslation('rules');
  const addRule = useStore(useCallback((state) => state.addRule, []));
  const rules = useStore(useCallback((state) => state.rules, []));
  const selectedRuleset = useStore(useCallback((state) => state.selectedRuleset, []));
  const darkMode = useStore(useCallback((state) => state.darkMode, []));
  const [open, setOpen] = useState(false);
  const [ruleText, setRuleText] = useState('');
  const [level, setLevel] = useState('');
  const [types, setTypes] = useState([]);
  const [gens, setGens] = useState([]);
  const [tab, setTab] = useState(0);
  const containsType = rules[selectedRuleset]?.some((rule) => rule.type === 'TYPE');
  const containsGen = rules[selectedRuleset]?.some((rule) => rule.type === 'GENERATION');
  const containsLevel = rules[selectedRuleset]?.some((rule) => rule.type === 'LEVEL');

  const panes = [
    {
      menuItem: t('text'),
      render: () => (
        <Tab.Pane>
          {t('rule_description')}:
          <Input
            data-testid="add-rule-input"
            maxLength={500}
            fluid
            onChange={(e, data) => setRuleText(data.value)}
            placeholder={t('please_rule')}
            value={ruleText}
          />
        </Tab.Pane>
      ),
    },
    {
      menuItem: t('type'),
      render: () => (
        <Tab.Pane>
          {t('allow_only_types')}:
          <Dropdown
            data-testid="add-rule-type"
            disabled={!!containsType}
            fluid
            multiple
            onChange={(e, data) => setTypes([...(data.value as string[])])}
            options={Object.keys(TYPE_COUNT).map((key) => {
              return { key, text: key, value: key };
            })}
            placeholder={t('please_type')}
            selection
            value={types}
          />
          {!!containsType && (
            <span style={{ color: 'red' }}>{t('already_exists', { rule: t('type') })}</span>
          )}
        </Tab.Pane>
      ),
    },
    {
      menuItem: t('generation'),
      render: () => (
        <Tab.Pane>
          {t('allow_only_generations')}:
          <Dropdown
            data-testid="add-rule-generation"
            fluid
            disabled={!!containsGen}
            multiple
            onChange={(e, data) => setGens([...(data.value as number[])])}
            options={GENERATIONS.map((gen) => {
              return { key: gen, text: gen, value: gen };
            })}
            placeholder={t('please_generation')}
            selection
            value={gens}
          />
          {!!containsGen && (
            <span style={{ color: 'red' }}>{t('already_exists', { rule: t('generation') })}</span>
          )}
        </Tab.Pane>
      ),
    },
    {
      menuItem: t('level'),
      render: () => (
        <Tab.Pane>
          {t('max_level_allowed')}:
          <Input
            data-testid="add-rule-level-input"
            disabled={!!containsLevel}
            fluid
            max={100}
            onChange={(e, data) => setLevel(data.value)}
            placeholder={t('please_max')}
            type="number"
            value={level}
          />
          {!!containsLevel && (
            <span style={{ color: 'red' }}>{t('already_exists', { rule: t('level') })}</span>
          )}
        </Tab.Pane>
      ),
    },
  ];

  const handleClose = () => {
    setOpen(false);
    setRuleText('');
  };

  const handleAdd = () => {
    switch (tab) {
      case 1:
        addRule({ content: types, default: false, type: 'TYPE' });
        break;
      case 2:
        addRule({ content: gens, default: false, type: 'GENERATION' });
        break;
      case 3:
        addRule({ content: level, default: false, type: 'LEVEL' });
        break;
      case 0:
      default:
        addRule({ content: ruleText, default: false, type: 'TEXT' });
        break;
    }
    setOpen(false);
    setRuleText('');
    setLevel('');
    setTypes([]);
    setGens([]);
  };

  const handleTabChange = (newIndex: ReactText) => {
    setTab(Number(newIndex));
  };

  const getDisabled = () => {
    switch (tab) {
      case 1:
        return types?.length === 0 || containsType;
      case 2:
        return gens?.length === 0 || containsGen;
      case 3:
        return !level || containsLevel;
      case 0:
      default:
        return ruleText?.length === 0;
    }
  };

  return (
    <Modal
      className={styles.addRule}
      open={open}
      trigger={
        <Button
          color="green"
          data-testid="add-rule"
          disabled={!selectedRuleset}
          inverted={darkMode}
          onClick={() => setOpen(true)}
          type="button"
        >
          {t('add_rule')}
          <Icon name="plus" />
        </Button>
      }
    >
      <Modal.Content className={modalStyles.modal}>
        <Tab
          activeIndex={tab}
          className={styles.tabs}
          onTabChange={(e, data) => handleTabChange(data.activeIndex)}
          panes={panes}
        />
      </Modal.Content>
      <Modal.Actions>
        <Button onClick={handleClose}>{t('cancel', { ns: 'common' })}</Button>
        <Button disabled={getDisabled()} onClick={handleAdd} primary>
          {t('save', { ns: 'common' })}
        </Button>
      </Modal.Actions>
    </Modal>
  );
}
Example #11
Source File: CardUserInfo.tsx    From glide-frontend with GNU General Public License v3.0 4 votes vote down vote up
CardUserInfo: React.FC<YourScoreProps> = ({
  hasRegistered,
  account,
  profile,
  userLeaderboardInformation,
  currentPhase,
}) => {
  const { t } = useTranslation()
  const [onPresentShareModal] = useModal(
    <ShareImageModal profile={profile} userLeaderboardInformation={userLeaderboardInformation} />,
    false,
  )
  const { global, team, volume, next_rank: nextRank } = userLeaderboardInformation
  const shouldShowUserRanks = account && hasRegistered

  const getMedal = (currentRank: ReactText) => {
    if (currentRank === 1) {
      return {
        current: <MedalGoldIcon />,
        next: null,
      }
    }
    if (currentRank <= 10) {
      return {
        current: <MedalSilverIcon />,
        next: <MedalGoldIcon />,
      }
    }
    if (currentRank <= 100) {
      return {
        current: <MedalBronzeIcon />,
        next: <MedalSilverIcon />,
      }
    }
    if (currentRank <= 500) {
      return {
        current: <MedalPurpleIcon />,
        next: <MedalBronzeIcon />,
      }
    }
    if (currentRank > 500) {
      return {
        current: <MedalTealIcon />,
        next: <MedalPurpleIcon />,
      }
    }
    return {
      current: <BlockIcon />,
      next: <MedalTealIcon />,
    }
  }

  const getNextTier = (currentRank: ReactText) => {
    if (currentRank === 1) {
      return {
        color: null,
        rank: null,
      }
    }
    if (currentRank <= 10) {
      return {
        color: 'GOLD',
        rank: 1,
      }
    }
    if (currentRank <= 100) {
      return {
        color: 'SILVER',
        rank: 10,
      }
    }
    if (currentRank <= 500) {
      return {
        color: 'BRONZE',
        rank: 100,
      }
    }
    if (currentRank > 500) {
      return {
        color: 'PURPLE',
        rank: 500,
      }
    }
    return {
      color: '',
      rank: 500,
    }
  }

  const getHeadingText = () => {
    if (!account) {
      return t('Check your Rank')
    }
    if (!hasRegistered) {
      return t('You’re not participating this time.')
    }
    return `@${profile.username}`
  }

  const getSubHeadingText = () => {
    if (!account) {
      return t('Connect wallet to view')
    }
    if (!hasRegistered) {
      return t('Sorry, you needed to register during the “entry” period!')
    }
    return `${profile.team.name}`
  }

  const headingText = getHeadingText()
  const subHeadingText = getSubHeadingText()
  const nextTier = userLeaderboardInformation && getNextTier(team)
  const medal = userLeaderboardInformation && getMedal(team)

  return (
    <Flex flexDirection="column" alignItems="center" mt="16px">
      <Heading scale="lg" textAlign="center">
        {headingText}
      </Heading>
      <Text textAlign="center" fontSize="14px" color="textSubtle" mt="4px">
        {subHeadingText}
      </Text>
      {shouldShowUserRanks && (
        <>
          {profile.nft && volume > 0 && (
            <Button mt="12px" variant="secondary" scale="sm" onClick={onPresentShareModal}>
              {t('Share Score')}
            </Button>
          )}
          <RanksWrapper>
            <Flex width="100%" flexDirection={['column', 'row']}>
              {volume > 0 && (
                <UserRankBox
                  flex="1"
                  title={t('Rank in team').toUpperCase()}
                  footer={userLeaderboardInformation ? t('#%global% Overall', { global: global.toLocaleString() }) : ''}
                  mr={[0, '8px']}
                  mb={['8px', 0]}
                >
                  {!userLeaderboardInformation ? (
                    <Skeleton height="26px" width="110px" />
                  ) : (
                    <TeamRankTextWrapper>
                      <Heading textAlign="center" scale="lg" mr="8px">
                        #{team}
                      </Heading>
                      {medal.current}
                    </TeamRankTextWrapper>
                  )}
                </UserRankBox>
              )}
              <UserRankBox
                flex="1"
                title={t('Your volume').toUpperCase()}
                footer={t('Since start')}
                // Add responsive mr if competition is LIVE
                mr={currentPhase.state === LIVE ? [0, null, '8px'] : 0}
              >
                {!userLeaderboardInformation ? (
                  <Skeleton height="26px" width="110px" />
                ) : (
                  <Heading textAlign="center" scale="lg">
                    ${userLeaderboardInformation && localiseTradingVolume(volume)}
                  </Heading>
                )}
              </UserRankBox>
            </Flex>
            {/* Show next ranks if competition is LIVE */}
            {currentPhase.state === LIVE &&
              (team === 1 ? (
                // If user is first
                <NextRankBox
                  flex="2"
                  title={t('Your tier: gold').toUpperCase()}
                  footer={t('Love, The Chefs x')}
                  currentMedal={medal.current}
                  hideArrow
                >
                  <Heading scale="lg">{t('HECK YEAH!')}</Heading>
                </NextRankBox>
              ) : (
                <NextRankBox
                  flex="2"
                  title={`${t('Next tier').toUpperCase()}: ${nextTier.color}`}
                  footer={t('to become #%rank% in team', { rank: nextTier.rank })}
                  currentMedal={medal.current}
                  nextMedal={medal.next}
                >
                  <Heading scale="lg">+${userLeaderboardInformation && localiseTradingVolume(nextRank)}</Heading>
                </NextRankBox>
              ))}
          </RanksWrapper>
        </>
      )}
    </Flex>
  )
}
Example #12
Source File: ClientConnectionInterruption.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
ClientConnectionInterruption: FC = observer(() => {
  const [error, setError] = useState<string | null>(null);
  const [isSubmitting, setSubmitting] = useState<boolean>(false);
  const [selection, setSelection] = useState<ReactText>('retry');
  const clientConnectionSettingsRef = useRef<ClientConnectionSettings | null>(null);

  return (
    <Panel spacing="large">
      <Form
        onSubmit={async () => {
          setSubmitting(true);

          if (selection === 'config') {
            const currentUsername = AuthStore.currentUser.username;
            const connectionSettings = clientConnectionSettingsRef.current;

            if (currentUsername == null || connectionSettings == null) {
              setError('connection.settings.error.empty');
              setSubmitting(false);
              return;
            }

            try {
              await AuthActions.updateUser(currentUsername, {
                client: connectionSettings,
              })
                .then(() => {
                  // do nothing.
                })
                .catch((e) => {
                  setError('general.error.unknown');
                  throw e;
                });
            } catch {
              setSubmitting(false);
              return;
            }
          }

          await ClientActions.testConnection()
            .then(() => {
              FloodActions.restartActivityStream();
            })
            .catch(() => {
              setError('connection-interruption.verification-error');
            });

          setSubmitting(false);
        }}
      >
        <PanelHeader>
          <h1>
            <Trans id="connection-interruption.heading" />
          </h1>
        </PanelHeader>
        <PanelContent>
          {error && (
            <FormRow>
              <FormError>
                <Trans id={error} />
              </FormError>
            </FormRow>
          )}
          {AuthStore.currentUser.isAdmin ? (
            <FormRow>
              <Select id="action" onSelect={setSelection} defaultID="retry">
                <SelectItem key="retry" id="retry">
                  <Trans id="connection-interruption.action.selection.retry" />
                </SelectItem>
                <SelectItem key="config" id="config">
                  <Trans id="connection-interruption.action.selection.config" />
                </SelectItem>
              </Select>
            </FormRow>
          ) : (
            <p className="copy--lead">
              <Trans id="connection-interruption.not.admin" />
            </p>
          )}
          {selection === 'config' && (
            <ClientConnectionSettingsForm
              onSettingsChange={(settings) => {
                clientConnectionSettingsRef.current = settings;
              }}
            />
          )}
        </PanelContent>
        <PanelFooter hasBorder>
          <FormRow justify="end">
            {selection === 'retry' && (
              <Button type="submit" isLoading={isSubmitting}>
                <Trans id="button.retry" />
              </Button>
            )}
            {selection === 'config' && (
              <Button type="submit" isLoading={isSubmitting}>
                <Trans id="button.save" />
              </Button>
            )}
          </FormRow>
        </PanelFooter>
      </Form>
    </Panel>
  );
})
Example #13
Source File: DirectoryFileList.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
DirectoryFiles: FC<DirectoryFilesProps> = ({depth, items, hash, path, onItemSelect}: DirectoryFilesProps) => {
  const [copiedToClipboard, setCopiedToClipboard] = useState<number | null>(null);
  const contentPermalinks = useRef<Record<number, string | null>>({});

  if (items == null) {
    return null;
  }

  const files = Object.values(items)
    .sort((a, b) => a.filename.localeCompare(b.filename))
    .map((file) => {
      const isSelected = (items && items[file.filename] && items[file.filename].isSelected) || false;
      const classes = classnames(
        'directory-tree__node file',
        'directory-tree__node--file directory-tree__node--selectable',
        {
          'directory-tree__node--selected': isSelected,
        },
      );

      return (
        <div className={classes} key={file.filename} title={file.filename}>
          <div className="file__label file__detail">
            <div className="file__checkbox directory-tree__checkbox">
              <div className="directory-tree__checkbox__item directory-tree__checkbox__item--checkbox">
                <Checkbox
                  checked={isSelected}
                  id={`${file.index}`}
                  onClick={() =>
                    onItemSelect({
                      type: 'file',
                      depth,
                      path: [...path, file.filename],
                      select: !isSelected,
                    })
                  }
                />
              </div>
              <div className="directory-tree__checkbox__item directory-tree__checkbox__item--icon">
                <FileIcon />
              </div>
            </div>
            <div className="file__name">
              {/* TODO: Add a WebAssembly decoding player if the feature is popular */}
              <a
                href={`${ConfigStore.baseURI}api/torrents/${hash}/contents/${file.index}/data`}
                style={{textDecoration: 'none'}}
                target="_blank"
                rel="noreferrer"
              >
                {file.filename}
              </a>
            </div>
          </div>
          <div className="file__detail file__detail--secondary">
            <Size value={file.sizeBytes} precision={1} />
          </div>
          <div className="file__detail file__detail--secondary">{Math.trunc(file.percentComplete)}%</div>
          <div
            className="file__detail file__detail--secondary
            file__detail--priority"
          >
            <PriorityMeter
              key={`${file.index}-${file.filename}`}
              level={file.priority}
              id={file.index}
              maxLevel={2}
              onChange={(fileIndex: ReactText, priorityLevel: number) =>
                TorrentActions.setFilePriority(hash, {
                  indices: [Number(fileIndex)],
                  priority: priorityLevel,
                })
              }
              priorityType="file"
            />
          </div>
          {typeof navigator.clipboard?.writeText === 'function' && (
            <button
              className="file__detail file__detail--secondary file__detail--clipboard"
              type="button"
              onClick={() => {
                const copy = (link: string): void => {
                  if (link !== '') {
                    if (typeof navigator.share === 'function') {
                      navigator
                        .share({
                          title: file.filename,
                          url: link,
                        })
                        .then(() => setCopiedToClipboard(file.index));
                    } else {
                      navigator.clipboard.writeText(link).then(() => setCopiedToClipboard(file.index));
                    }
                  }
                };
                // Safari does not support async operations inside "user gesture" handler.
                // Otherwise the write to clipboard will be rejected for "security reasons".
                // As such, we cache the token, so next click can be synchronous. Incompatible
                // morons make everyone's life hard.
                const link = contentPermalinks.current[file.index];
                if (link != null) {
                  copy(link);
                } else {
                  contentPermalinks.current[file.index] = '';
                  TorrentActions.getTorrentContentsDataPermalink(hash, [file.index]).then(
                    (url) => {
                      contentPermalinks.current[file.index] = url;
                      copy(url);
                    },
                    () => {
                      contentPermalinks.current[file.index] = null;
                    },
                  );
                }
              }}
            >
              {copiedToClipboard === file.index ? <Checkmark /> : <Clipboard />}
            </button>
          )}
        </div>
      );
    });

  return <div className="directory-tree__node directory-tree__node--file-list">{files}</div>;
}
Example #14
Source File: useSelection.tsx    From amiya with MIT License 4 votes vote down vote up
export default function useSelection(_props: UseSelectionProps): UseSelectionReturns {
  const { rowKey, selectionType, onSelectionChange, selectShowKey, rowSelection } = _props
  const [selectionKeys, setSelectionKeys] = useState<Array<ReactText>>([])
  const [selection, setSelection] = useState<Array<Row>>([])

  let tableRowSelection: AnyKeyProps | undefined

  if (selectionType) {
    tableRowSelection = {
      ...rowSelection,
      type: selectionType,
      selectedRowKeys: selectionKeys,
      onSelect: (record: Row, selected: boolean) => {
        if (selectionType === 'radio') {
          changeRadioSelection(record)
        } else {
          selected ? addSelection(record) : removeSelection(null, record)
        }
      },
      onSelectAll: (selected: boolean, selectedRows: Array<Row>, changeRows: Array<Row>) => {
        selected ? addSelectionArray(selectedRows) : removeSelectionArray(changeRows)
      }
    }
  }

  /**
   * 清空所有选项
   */
  const clearSelection = () => {
    setSelectionKeys([])
    setSelection([])
  }

  /**
   * 设置选中的行
   */
  const setDefaultSelection = (selection: AnyKeyProps[]) => {
    setSelection(selection)
    setSelectionKeys(selection.map(row => getKey(row, rowKey)))
  }

  /**
   * 添加选项
   */
  const addDefaultSelection = (addSelection: AnyKeyProps[]) => {
    // @ts-ignore
    let newSelection = [...selection]
    addSelection.forEach(row => {
      if (!selectionKeys.includes(getKey(row, rowKey))) {
        newSelection.push(row)
      }
    })

    setSelection(newSelection)
    setSelectionKeys(newSelection.map(row => getKey(row, rowKey)))
  }

  const changeRadioSelection = (row: AnyKeyProps) => {
    let newKeys = []
    let newSelection = []

    newKeys.push(getKey(row, rowKey))
    newSelection.push(row)

    setSelectionKeys(newKeys)
    setSelection(newSelection)
  }

  /**
   * 添加选项(单个)
   * @param row 某一条选项
   */
  const addSelection = (row: AnyKeyProps) => {
    // @ts-ignore
    let newKeys = [...selectionKeys]
    let newSelection = [...selection]

    newKeys.push(getKey(row, rowKey))
    newSelection.push(row)

    setSelectionKeys(newKeys)
    setSelection(newSelection)
  }

  /**
   * 添加选项(数组)
   * @param rows 项目列表
   */
  const addSelectionArray = (rows: Array<AnyKeyProps>) => {
    let newKeys = [...selectionKeys]
    let newSelection = [...selection]

    rows.forEach(row => {
      if (!row) {
        return
      }
      let key = getKey(row, rowKey)
      if (!newKeys.includes(key)) {
        newKeys.push(key)
        newSelection.push(row)
      }
    })

    setSelectionKeys(newKeys)
    setSelection(newSelection)
  }

  /**
   * 移除某个选项
   * @param i 移除选项的 index
   */
  const removeSelection = (i: number | null, record?: AnyKeyProps) => {
    let newKeys = [...selectionKeys]
    let newSelection = [...selection]

    if (i === null && record) {
      i = newKeys.findIndex(key => key === getKey(record, rowKey))
    }

    if (typeof i === 'number') {
      newKeys.splice(i, 1)
      newSelection.splice(i, 1)
    }

    setSelectionKeys(newKeys)
    setSelection(newSelection)
  }

  /**
   * 移除一组选项
   * @param rows 移除选项
   */
  const removeSelectionArray = (rows: Array<Row>) => {
    let newKeys = [...selectionKeys]
    let newSelection = [...selection]

    rows.forEach(row => {
      let index = newKeys.findIndex(item => item === getKey(row, rowKey))
      if (index >= 0) {
        newKeys.splice(index, 1)
        newSelection.splice(index, 1)
      }
    })

    setSelectionKeys(newKeys)
    setSelection(newSelection)
  }

  /** Popover 弹窗的提示 */
  const popContent = (
    <div className="ay-search-poper">
      {selection.map((row, i) => {
        return (
          <Tag key={getKey(row, rowKey)} closable className="mb" onClose={() => removeSelection(i)}>
            {row[selectShowKey || 'name']}
          </Tag>
        )
      })}
    </div>
  )

  const message = (
    <div>
      <span>
        {locale.table.selectedBefore}
        <Popover title={locale.table.selectedTitle} content={popContent}>
          <a>{selection.length}</a>
        </Popover>
        &nbsp;{locale.table.selectedAfter}
      </span>
      <AyAction className="ml" type="link" size="small" onClick={clearSelection}>
        {locale.table.selectedClear}
      </AyAction>
    </div>
  )

  /** 头部已选中的提示 */
  const header = selectionKeys.length ? <Alert className="ay-search-table-alert" message={message} showIcon /> : ''

  useEffect(() => {
    if (onSelectionChange) {
      onSelectionChange(selection, selectionKeys)
    }
  }, [onSelectionChange, selection])

  return {
    header,
    message,
    tableRowSelection,
    selection,
    clearSelection,
    removeSelection,
    setSelection: setDefaultSelection,
    addSelection: addDefaultSelection
  }
}
Example #15
Source File: CardUserInfo.tsx    From vvs-ui with GNU General Public License v3.0 4 votes vote down vote up
CardUserInfo: React.FC<YourScoreProps> = ({
  hasRegistered,
  account,
  profile,
  userLeaderboardInformation,
  currentPhase,
}) => {
  const { t } = useTranslation()
  const [onPresentShareModal] = useModal(
    <ShareImageModal profile={profile} userLeaderboardInformation={userLeaderboardInformation} />,
    false,
  )
  const { global, team, volume, next_rank: nextRank } = userLeaderboardInformation
  const shouldShowUserRanks = account && hasRegistered

  const getMedal = (currentRank: ReactText) => {
    if (currentRank === 1) {
      return {
        current: <MedalGoldIcon />,
        next: null,
      }
    }
    if (currentRank <= 10) {
      return {
        current: <MedalSilverIcon />,
        next: <MedalGoldIcon />,
      }
    }
    if (currentRank <= 100) {
      return {
        current: <MedalBronzeIcon />,
        next: <MedalSilverIcon />,
      }
    }
    if (currentRank <= 500) {
      return {
        current: <MedalPurpleIcon />,
        next: <MedalBronzeIcon />,
      }
    }
    if (currentRank > 500) {
      return {
        current: <MedalTealIcon />,
        next: <MedalPurpleIcon />,
      }
    }
    return {
      current: <BlockIcon />,
      next: <MedalTealIcon />,
    }
  }

  const getNextTier = (currentRank: ReactText) => {
    if (currentRank === 1) {
      return {
        color: null,
        rank: null,
      }
    }
    if (currentRank <= 10) {
      return {
        color: 'GOLD',
        rank: 1,
      }
    }
    if (currentRank <= 100) {
      return {
        color: 'SILVER',
        rank: 10,
      }
    }
    if (currentRank <= 500) {
      return {
        color: 'BRONZE',
        rank: 100,
      }
    }
    if (currentRank > 500) {
      return {
        color: 'PURPLE',
        rank: 500,
      }
    }
    return {
      color: '',
      rank: 500,
    }
  }

  const getHeadingText = () => {
    if (!account) {
      return t('Check your Rank')
    }
    if (!hasRegistered) {
      return t('You’re not participating this time.')
    }
    return `@${profile.username}`
  }

  const getSubHeadingText = () => {
    if (!account) {
      return t('Connect wallet to view')
    }
    if (!hasRegistered) {
      return t('Sorry, you needed to register during the “entry” period!')
    }
    return `${profile.team.name}`
  }

  const headingText = getHeadingText()
  const subHeadingText = getSubHeadingText()
  const nextTier = userLeaderboardInformation && getNextTier(team)
  const medal = userLeaderboardInformation && getMedal(team)

  return (
    <Flex flexDirection="column" alignItems="center" mt="16px">
      <Heading scale="lg" textAlign="center">
        {headingText}
      </Heading>
      <Text textAlign="center" fontSize="14px" color="textSubtle" mt="4px">
        {subHeadingText}
      </Text>
      {shouldShowUserRanks && (
        <>
          {profile.nft && volume > 0 && (
            <Button mt="12px" variant="secondary" scale="sm" onClick={onPresentShareModal}>
              {t('Share Score')}
            </Button>
          )}
          <RanksWrapper>
            <Flex width="100%" flexDirection={['column', 'row']}>
              {volume > 0 && (
                <UserRankBox
                  flex="1"
                  title={t('Rank in team').toUpperCase()}
                  footer={userLeaderboardInformation ? t('#%global% Overall', { global: global.toLocaleString() }) : ''}
                  mr={[0, '8px']}
                  mb={['8px', 0]}
                >
                  {!userLeaderboardInformation ? (
                    <Skeleton height="26px" width="110px" />
                  ) : (
                    <TeamRankTextWrapper>
                      <Heading textAlign="center" scale="lg" mr="8px">
                        #{team}
                      </Heading>
                      {medal.current}
                    </TeamRankTextWrapper>
                  )}
                </UserRankBox>
              )}
              <UserRankBox
                flex="1"
                title={t('Your volume').toUpperCase()}
                footer={t('Since start')}
                // Add responsive mr if competition is LIVE
                mr={currentPhase.state === LIVE ? [0, null, '8px'] : 0}
              >
                {!userLeaderboardInformation ? (
                  <Skeleton height="26px" width="110px" />
                ) : (
                  <Heading textAlign="center" scale="lg">
                    ${userLeaderboardInformation && localiseTradingVolume(volume)}
                  </Heading>
                )}
              </UserRankBox>
            </Flex>
            {/* Show next ranks if competition is LIVE */}
            {currentPhase.state === LIVE &&
              (team === 1 ? (
                // If user is first
                <NextRankBox
                  flex="2"
                  title={t('Your tier: gold').toUpperCase()}
                  footer={t('Love, The Chefs x')}
                  currentMedal={medal.current}
                  hideArrow
                >
                  <Heading scale="lg">{t('HECK YEAH!')}</Heading>
                </NextRankBox>
              ) : (
                <NextRankBox
                  flex="2"
                  title={`${t('Next tier').toUpperCase()}: ${nextTier.color}`}
                  footer={t('to become #%rank% in team', { rank: nextTier.rank })}
                  currentMedal={medal.current}
                  nextMedal={medal.next}
                >
                  <Heading scale="lg">+${userLeaderboardInformation && localiseTradingVolume(nextRank)}</Heading>
                </NextRankBox>
              ))}
          </RanksWrapper>
        </>
      )}
    </Flex>
  )
}
Example #16
Source File: Payment.tsx    From save-food with MIT License 4 votes vote down vote up
Payment = ({ navigation }: Props) => {
	const { useSubscribe, setSettings } = useSettingsContext()
	const settings = useSubscribe((s) => s.settings)
	const translations = useSubscribe((s) => ({
		...s.translations.Payment,
		...s.translations.common,
	}))

	const [loading, setLoading] = useState(false)
	const [showModal, setShowModal] = useState(false)
	const [amount, setAmount] = useState<number>()
	const [email, setEmail] = useState<ReactText>(settings.email)
	const [controls, setControls] = useState<InputsControl>({
		email: {
			label: translations.emailLabel,
			characterRestriction: 70,
			keyboardType: 'email-address',
			email: true,
		},
	})

	const payForFoodHandler = async () => {
		setLoading(true)
		if (email && !controls.email.error) {
			await fetch(`${config.SAVE_FOOD_API}/send-email`, {
				method: 'POST',
				body: JSON.stringify({ email, lang: settings.lang }),
				headers: {
					Accept: 'application/json',
					'Content-Type': 'application/json',
				},
			})
				.then(async (res) => {
					if (res.status !== 200) {
						throw new Error(`Response status: ${res.status}`)
					}

					await logEvent('sendEmail', {
						component: 'Payment',
					})
				})
				.catch((err) => {
					// eslint-disable-next-line no-console
					console.warn(err)
					sentryError(err)
				})

			setSettings(await changeEmail(`${email}`))
		}

		const ids = navigation.getParam('ids', undefined)

		if (!ids) {
			// eslint-disable-next-line no-console
			console.warn('Missing food ids for payment')
			sentryError('Missing food ids for payment')
		}

		navigation.navigate('List', { ids })
	}

	const itemOnPressHandler = async (item: Organization) => {
		await logEvent('itemOnPress', {
			component: 'Payment',
			item,
		})

		await WebBrowser.openBrowserAsync(item.url)
	}

	const renderItem = ({ item }: { item: Organization }) => (
		<TouchableOpacity
			activeOpacity={1}
			style={[styles.imageContainer, shadow]}
			onPress={() => itemOnPressHandler(item)}
		>
			<Image style={styles.image} source={item.image} />
		</TouchableOpacity>
	)

	useEffect(() => {
		const amount = navigation.getParam('amount', 0)
		setAmount(amount)
	}, [])

	useAsyncEffect(async () => {
		const paidFoods = await getPaidWastedFoods()

		if (paidFoods.length === 0) {
			setShowModal(true)
		}
	}, [])

	return (
		<View style={styles.flex}>
			<StatusBar barStyle='dark-content' translucent backgroundColor='transparent' />
			<Header
				leftComponent={
					<Icon color={blackColor} onPress={() => navigation.goBack()} variant='backIcon' />
				}
				centerComponent={
					<Text numberOfLines={1} style={styles.header}>
						{translations.amount} {amount} {settings.currency}
					</Text>
				}
				rightComponent={
					<Icon
						color={blackColor}
						style={styles.infoIcon}
						onPress={() => setShowModal(true)}
						type='material'
						name='info-outline'
					/>
				}
			/>

			<Modal
				visible={showModal}
				toggleModal={() => setShowModal(!showModal)}
				title={translations.paymentInfoTitle}
				buttons={[{ text: 'Ok', onPress: () => setShowModal(false) }]}
			>
				<View>
					<Text style={styles.infoText}>{translations.paymentInfo1}</Text>
					<Text style={styles.infoText}>{translations.paymentInfo2}</Text>
					<Text style={styles.infoText}>{translations.paymentInfo3}</Text>
				</View>
			</Modal>

			<ScrollView scrollEventThrottle={200} directionalLockEnabled>
				<View style={styles.inputWrapper}>
					<Input
						inputConfig={controls.email}
						translations={translations}
						focus={false}
						value={email}
						changed={(value, control) => {
							setEmail(value)
							setControls({ email: control })
						}}
					/>
				</View>

				<View style={styles.contentWrapper}>
					<Text style={styles.contentTextWrapper}>
						<Text style={styles.lightText}>{translations.paymentHeaderText1}&nbsp;</Text>
						<Text style={styles.boldText}>{translations.paymentHeaderText2}&nbsp;</Text>
						<Text style={styles.lightText}>{translations.paymentHeaderText3}&nbsp;</Text>
						<Text style={styles.boldText}>{translations.paymentHeaderText4}&nbsp;</Text>
						<Text style={styles.lightText}>:</Text>
					</Text>

					<Carousel
						layout='default'
						removeClippedSubviews={false}
						data={charityOrganizations}
						sliderWidth={200}
						itemWidth={200}
						renderItem={renderItem}
						activeSlideAlignment='center'
						containerCustomStyle={styles.slider}
						loop
					/>

					<Text style={styles.contentTextWrapper}>
						<Text style={styles.lightText}>{translations.paymentFooterText1}&nbsp;</Text>
						<Text style={styles.boldText}>{translations.paymentFooterText2}&nbsp;</Text>
						<Text style={styles.lightText}>{translations.paymentFooterText3}</Text>
					</Text>
				</View>
			</ScrollView>

			<View style={[styles.paymentButtonContainer, shadow]}>
				<View style={styles.paymentButtonWrapper}>
					<Button
						loading={loading}
						buttonStyle={styles.paymentButton}
						titleStyle={styles.paymentButtonTitle}
						onPress={payForFoodHandler}
						title={translations.donationSent}
					/>
				</View>
			</View>
		</View>
	)
}