@material-ui/core#Radio TypeScript Examples

The following examples show how to use @material-ui/core#Radio. 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: LabeledRadio.tsx    From UsTaxes with GNU Affero General Public License v3.0 6 votes vote down vote up
export function LabeledRadio<A>(props: LabeledRadioProps<A>): ReactElement {
  const { label, name, values, useGrid = true, sizes = { xs: 12 } } = props

  const classes = useStyles()
  const { control } = useFormContext<A>()

  return (
    <ConditionallyWrap
      condition={useGrid}
      wrapper={(children) => (
        <Grid item {...sizes}>
          {children}
        </Grid>
      )}
    >
      <Controller
        name={name}
        render={({ field: { value, onChange } }) => (
          <div className={classes.root}>
            <FormControl component="fieldset">
              <FormLabel>{label}</FormLabel>
              <RadioGroup name={name} value={value} onChange={onChange}>
                {values.map(([rowLabel, rowValue], i) => (
                  <FormControlLabel
                    key={i}
                    value={rowValue}
                    control={<Radio color="primary" />}
                    label={rowLabel}
                  />
                ))}
              </RadioGroup>
            </FormControl>
          </div>
        )}
        control={control}
      />
    </ConditionallyWrap>
  )
}
Example #2
Source File: Language.tsx    From back-home-safe with GNU General Public License v3.0 6 votes vote down vote up
Language = () => {
  const { t } = useTranslation("tutorial");
  const { language, setLanguage } = useI18n();

  return (
    <Wrapper>
      <h2>{t("language.name")}</h2>
      <StyledRadioGroup
        aria-label="language"
        name="language"
        value={language}
        onChange={(event) => {
          setLanguage(event.target.value as languageType);
        }}
      >
        <FormControlLabel
          value={languageType["ZH-HK"]}
          control={<Radio />}
          label="繁體中文"
        />
        <FormControlLabel
          value={languageType.EN}
          control={<Radio />}
          label="English"
        />
      </StyledRadioGroup>
    </Wrapper>
  );
}
Example #3
Source File: TemplateDemoControls.tsx    From clearflask with Apache License 2.0 6 votes vote down vote up
render() {
    return (
      <RadioGroup
        className={this.props.classes.extraControls}
        value={this.props.value}
        onChange={(e, val) => this.props.onChange(val)}
      >
        {Object.keys(demoOptions).map(option => (
          <FormControlLabel key={option} value={option} control={<Radio color='primary' />}
            label={<FormHelperText component='span'>{option}</FormHelperText>} />
        ))}
      </RadioGroup>
    );
  }
Example #4
Source File: RoadmapControls.tsx    From clearflask with Apache License 2.0 6 votes vote down vote up
render() {
    return (
      <RadioGroup
        className={this.props.classes.extraControls}
        value={this.state.type}
        onChange={(e, val) => {
          switch (val) {
            case 'development':
              this.setState({ type: val });
              this.props.templater.demoBoardPreset('development');
              break;
            case 'funding':
              this.setState({ type: val });
              this.props.templater.demoBoardPreset('funding');
              break;
            case 'design':
              this.setState({ type: val });
              this.props.templater.demoBoardPreset('design');
              break;
          }
        }}
      >
        <FormControlLabel value='development' control={<Radio color='primary' />} label='Development' />
        <FormControlLabel value='funding' control={<Radio color='primary' />} label='Custom' />
        {/* <FormControlLabel value='design' control={<Radio color='primary' />} label="Design" /> */}
      </RadioGroup>
    );
  }
Example #5
Source File: PrioritizationControlsCredits.tsx    From clearflask with Apache License 2.0 6 votes vote down vote up
render() {
    return (
      <RadioGroup
        className={this.props.classes.extraControls}
        value={this.state.fundingType}
        onChange={this.handleChangeFundingType.bind(this)}
      >
        <FormControlLabel value='currency' control={<Radio color='primary' />}
          label={<FormHelperText component='span'>Currency</FormHelperText>} />
        <FormControlLabel value='time' control={<Radio color='primary' />}
          label={<FormHelperText component='span'>{this.props.forContentCreator ? 'Time' : 'Development time'}</FormHelperText>} />
        <FormControlLabel value={this.props.forContentCreator ? 'heart' : 'beer'} control={<Radio color='primary' />}
          label={<FormHelperText component='span'>Customize</FormHelperText>} />
      </RadioGroup>
    );
  }
Example #6
Source File: Settings.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
Settings = () => {
  const { type, handleChangeType } = useRandomJoke();
  const JOKE_TYPES: JokeType[] = ['any' as JokeType, 'programming' as JokeType];
  return (
    <FormControl component="fieldset">
      <FormLabel component="legend">Joke Type</FormLabel>
      <RadioGroup
        aria-label="joke type"
        value={type}
        onChange={e => handleChangeType(e.target.value)}
      >
        {JOKE_TYPES.map(t => (
          <FormControlLabel
            key={t}
            value={t}
            control={<Radio />}
            label={upperFirst(t)}
          />
        ))}
      </RadioGroup>
    </FormControl>
  );
}
Example #7
Source File: SQFormRadioButtonGroupItem.tsx    From SQForm with MIT License 6 votes vote down vote up
function SQFormRadioButtonGroupItem({
  value,
  label,
  isDisabled = false,
  isRowDisplay = false,
  InputProps = {},
}: SQFormRadioButtonGroupItemProps): JSX.Element {
  const classes = useStyles();

  return (
    <FormControlLabel
      className={`
        ${classes.radioButton}
        ${isRowDisplay ? classes.rowDisplay : ''}
      `}
      value={value}
      label={label}
      control={<Radio disabled={isDisabled} {...InputProps} />}
    />
  );
}
Example #8
Source File: Checkbox.tsx    From panvala with Apache License 2.0 6 votes vote down vote up
Checkbox = (props: any) => {
  return (
    <>
      <Wrapper>
        <Field name={props.name} required>
          {({ field, form }: any) => (
            <>
              <Radio
                checked={field.value.includes(props.value)}
                onChange={() => form.setFieldValue(props.name, props.value)}
                value={props.value}
                name={props.name}
                aria-label="D"
                classes={{
                  root: props.classes.root,
                  checked: props.classes.checked,
                }}
              />
              <ToggleLabel
                onClick={() => form.setFieldValue(props.name, props.value)}
                htmlFor={props.name}
              >
                {props.label}
              </ToggleLabel>
            </>
          )}
        </Field>
      </Wrapper>
    </>
  );
}
Example #9
Source File: BooleanFacet.tsx    From cognitive-search-static-web-apps-sample-ui with MIT License 6 votes vote down vote up
render(): JSX.Element {
        const state = this.props.state;
        return (
            <FacetValuesList component="div" disablePadding>

                <FacetValueListItem dense disableGutters>
                    <Radio edge="start" disableRipple
                        disabled={this.props.inProgress}
                        checked={!state.isApplied}
                        onChange={(evt) => state.value = null}
                    />
                    <ListItemText primary="[ANY]" />
                </FacetValueListItem>
                <FacetValueListItem dense disableGutters>
                    <Radio edge="start" disableRipple
                        disabled={this.props.inProgress}
                        checked={state.value === true}
                        onChange={(evt) => state.value = true}
                    />
                    <ListItemText primary={`TRUE(${state.trueCount})`} />
                </FacetValueListItem>
                <FacetValueListItem dense disableGutters>
                    <Radio edge="start" disableRipple
                        disabled={this.props.inProgress}
                        checked={state.value === false}
                        onChange={(evt) => state.value = false}
                    />
                    <ListItemText primary={`FALSE(${state.falseCount})`} />
                </FacetValueListItem>

            </FacetValuesList>
        );
    }
Example #10
Source File: radio_input.tsx    From jupyter-extensions with Apache License 2.0 6 votes vote down vote up
/** Funtional Component for Radio input fields */
export function RadioInput(props: RadioInputProps) {
  const { options, ...groupProps } = props;
  return (
    <ThemeProvider theme={theme}>
      <RadioGroup {...groupProps}>
        {options &&
          options.map((o, i) => (
            <FormControlLabel
              key={i}
              value={o.value}
              control={<Radio />}
              label={o.text}
              className={css.primaryTextColor}
            />
          ))}
      </RadioGroup>
    </ThemeProvider>
  );
}
Example #11
Source File: RiskCriteria.tsx    From listo with MIT License 5 votes vote down vote up
RiskCriteria = ({
  text,
  options,
  handleRiskOption,
  description,
}: Props) => {
  const classes = useStyles({});

  if (!options) {
    // TODO: this should be moved to pre-validation
    return null;
  }

  const selectedOption = options.find(o => o.selected);
  const value = selectedOption ? selectedOption.text : UNSELECTED_KEY;

  const ExpansionPanelDetails = withStyles(theme => ({
    root: {
      padding: theme.spacing(2),
      backgroundColor: '#f5f9fe',
    },
  }))(MuiExpansionPanelDetails);

  return (
    <React.Fragment>
      <Paper className={classes.root}>
        <Grid container spacing={2}>
          <Grid item xs={12}>
            <ExpansionPanel>
              <ExpansionPanelSummary
                expandIcon={<ExpandMoreIcon />}
                aria-controls="panel1a-content"
              >
                <Typography>{text}</Typography>
              </ExpansionPanelSummary>
              <ExpansionPanelDetails>
                <Typography>{description}</Typography>
              </ExpansionPanelDetails>
            </ExpansionPanel>
          </Grid>
          <Grid item xs={12}>
            <FormControl>
              <RadioGroup onChange={handleRiskOption} value={value}>
                {options.map(option => (
                  <FormControlLabel
                    key={option.text}
                    value={option.text}
                    control={<Radio />}
                    label={option.text}
                  />
                ))}
                <FormControlLabel
                  value={UNSELECTED_KEY}
                  control={<Radio />}
                  style={{ display: 'none' }}
                  label="Hidden"
                />
              </RadioGroup>
            </FormControl>
          </Grid>
        </Grid>
      </Paper>
    </React.Fragment>
  );
}
Example #12
Source File: ShippingMethods.tsx    From storefront with MIT License 5 votes vote down vote up
ShippingMethods: React.VFC<Props> = ({
  availableShippingMethods,
  chosenShippingMethods,
  onSubmit,
}) => {
  const [updateShippingMethod, { loading }] = useUpdateShippingMethodMutation({
    refetchQueries: ['Cart'],
  });

  const handleChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
    updateShippingMethod({ variables: { shippingMethods: [ev.target.value] } });
  };

  return (
    <>
      <RadioGroup
        name="shippingMethod"
        value={chosenShippingMethods?.[0] ?? undefined}
        onChange={handleChange}
      >
        <Grid container spacing={2}>
          {availableShippingMethods?.[0]?.rates?.map(
            (rate) =>
              rate != null && (
                <Grid key={rate.id} item xs={12} lg={6}>
                  <Box
                    component="label"
                    htmlFor={`shippingMethod-${rate.id}`}
                    sx={{
                      alignItems: 'center',
                      backgroundColor: 'background.paper',
                      cursor: 'pointer',
                      display: 'flex',
                      flexDirection: 'row',
                      p: 2,
                    }}
                  >
                    <div>
                      <Radio value={rate.id} id={`shippingMethod-${rate.id}`} disabled={loading} />
                    </div>
                    <Box sx={{ flexGrow: 1, ml: 2 }}>
                      <Typography>{rate.label}</Typography>
                      <Price>{rate.cost}</Price>
                    </Box>
                  </Box>
                </Grid>
              ),
          )}
        </Grid>
      </RadioGroup>
      <Box sx={{ mt: 2 }}>
        <Button
          type="submit"
          color="primary"
          disabled={chosenShippingMethods == null}
          loading={loading}
          onClick={onSubmit}
        >
          Continue to Payment Method
        </Button>
      </Box>
    </>
  );
}
Example #13
Source File: StringCollectionFacet.tsx    From cognitive-search-static-web-apps-sample-ui with MIT License 5 votes vote down vote up
render(): JSX.Element {
        const state = this.props.state;
        return (<FacetValuesList component="div" disablePadding>

            <FacetValueListItem key={state.fieldName} dense disableGutters>
                <Radio edge="start" disableRipple
                    disabled={this.props.inProgress}
                    checked={state.allSelected}
                    onChange={(evt) => state.allSelected = evt.target.checked}
                />
                <ListItemText primary="[ALL]" />
            </FacetValueListItem>

            <FacetValueListItem key={state.fieldName + "-or-and"} dense disableGutters>
                <Radio edge="start" disableRipple
                    disabled={this.props.inProgress || state.allSelected}
                    checked={!state.allSelected && !state.useAndOperator}
                    onChange={(evt) => state.useAndOperator = false}
                />
                <ListItemText primary="[ANY OF]" />

                <Radio edge="start" disableRipple
                    disabled={this.props.inProgress || state.allSelected}
                    checked={!state.allSelected && state.useAndOperator}
                    onChange={(evt) => state.useAndOperator = true}
                />
                <ListItemText primary="[ALL OF]" />
            </FacetValueListItem>

            {state.values.map(facetValue => {
                return (

                    <FacetValueListItem key={facetValue.value} dense disableGutters>
                        <Checkbox edge="start" disableRipple
                            disabled={this.props.inProgress}
                            checked={facetValue.isSelected}
                            onChange={(evt) => facetValue.isSelected = evt.target.checked}
                        />
                        <ListItemText primary={`${facetValue.value} (${facetValue.count})`} />
                    </FacetValueListItem>

                );
            })}

        </FacetValuesList>);
    }
Example #14
Source File: AlertSnoozeForm.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
AlertSnoozeForm = forwardRef<
  HTMLFormElement,
  AlertSnoozeFormProps
>(({ onSubmit, disableSubmit }, ref) => {
  const classes = useStyles();
  const [duration, setDuration] = useState<Maybe<Duration>>(Duration.P7D);

  useEffect(() => disableSubmit(false), [disableSubmit]);

  const onFormSubmit: FormEventHandler = e => {
    e.preventDefault();
    if (duration) {
      const repeatInterval = 1;
      const today = DateTime.now().toFormat(DEFAULT_DATE_FORMAT);
      onSubmit({
        intervals: intervalsOf(duration, today, repeatInterval),
      });
    }
  };

  const onSnoozeDurationChange = (
    _: ChangeEvent<HTMLInputElement>,
    value: string,
  ) => {
    setDuration(value as Duration);
  };

  return (
    <form ref={ref} onSubmit={onFormSubmit}>
      <FormControl component="fieldset" fullWidth>
        <Typography color="textPrimary">
          <b>For how long?</b>
        </Typography>
        <Box mb={1}>
          <RadioGroup
            name="snooze-alert-options"
            value={duration}
            onChange={onSnoozeDurationChange}
          >
            {AlertSnoozeOptions.map(option => (
              <FormControlLabel
                key={`snooze-alert-option-${option.duration}`}
                label={option.label}
                value={option.duration}
                control={<Radio className={classes.radio} />}
              />
            ))}
          </RadioGroup>
        </Box>
      </FormControl>
    </form>
  );
})
Example #15
Source File: VersioningStrategy.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
export function VersioningStrategy() {
  const navigate = useNavigate();
  const { project } = useProjectContext();
  const { getParsedQuery, getQueryParamsWithUpdates } = useQueryHandler();

  useEffect(() => {
    const { parsedQuery } = getParsedQuery();

    if (!parsedQuery.versioningStrategy && !project.isProvidedViaProps) {
      const { queryParams } = getQueryParamsWithUpdates({
        updates: [
          { key: 'versioningStrategy', value: project.versioningStrategy },
        ],
      });

      navigate(`?${queryParams}`, { replace: true });
    }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <FormControl
      component="fieldset"
      required
      disabled={project.isProvidedViaProps}
    >
      <FormLabel component="legend">Versioning strategy</FormLabel>

      <RadioGroup
        data-testid={TEST_IDS.form.versioningStrategy.radioGroup}
        aria-label="calendar-strategy"
        name="calendar-strategy"
        value={project.versioningStrategy}
        onChange={event => {
          const { queryParams } = getQueryParamsWithUpdates({
            updates: [{ key: 'versioningStrategy', value: event.target.value }],
          });

          navigate(`?${queryParams}`, { replace: true });
        }}
      >
        <FormControlLabel
          value={VERSIONING_STRATEGIES.semver}
          control={<Radio />}
          label="Semantic versioning"
        />

        <FormControlLabel
          value={VERSIONING_STRATEGIES.calver}
          control={<Radio />}
          label="Calendar versioning"
        />
      </RadioGroup>
    </FormControl>
  );
}
Example #16
Source File: ListReplyTemplate.tsx    From glific-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
ChatTemplate: React.SFC<TemplateProps> = (props) => {
  const [showDialog, setShowDialog] = useState(false);
  const [checkedItem, setCheckedItem] = useState<any>(null);
  const { title, body, globalButtonTitle, items } = props;

  let dialog;

  if (showDialog) {
    const list = items.map((item: any) => {
      const { options, title: listItemTitle } = item;
      return (
        <div className={styles.ListItemContainer} key={listItemTitle}>
          <div className={styles.ListItemTitle}>{listItemTitle}</div>
          {options.map((option: any) => (
            <Button
              key={option.title}
              className={styles.ListItemChat}
              onClick={() => setCheckedItem(option.title)}
            >
              <div>
                <div>{option.title}</div>
                <div>{option.description}</div>
              </div>
              <div>
                <Radio
                  value={option.title}
                  name="radio-list-item"
                  size="small"
                  checked={option.title === checkedItem}
                  color="primary"
                />
              </div>
            </Button>
          ))}
        </div>
      );
    });
    dialog = (
      <DialogBox
        title={globalButtonTitle}
        titleAlign="left"
        handleOk={() => setShowDialog(false)}
        buttonOk="Done"
        skipCancel
        alwaysOntop
      >
        <div className={styles.DialogContent}> {list}</div>
      </DialogBox>
    );
  }

  return (
    <div>
      <div className={styles.ChatTemplateBody}>
        <p>{title}</p>
        <p>{body}</p>
      </div>
      <div className={styles.ChatTemplateButton}>
        <Button
          variant="contained"
          color="default"
          startIcon={<MenuIcon />}
          onClick={() => setShowDialog(true)}
          className={styles.GlobalButton}
        >
          {globalButtonTitle}
        </Button>
      </div>
      {dialog}
    </div>
  );
}
Example #17
Source File: RadioInput.tsx    From glific-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
RadioInput: React.SFC<RadioInputProps> = ({
  labelYes = 'Yes',
  labelNo = 'No',
  row = true,
  field,
  form: { touched, errors, setFieldValue, values },
  radioTitle,
  handleChange,
}) => {
  const selectedValue = values[field.name];

  const isChecked = (value: any) => selectedValue === value;

  const handleRadioChange = (value: boolean) => {
    setFieldValue(field.name, value);
    if (handleChange) {
      handleChange(value);
    }
  };

  let radioGroupLabel: any;
  if (radioTitle) {
    radioGroupLabel = <FormLabel component="legend">{radioTitle}</FormLabel>;
  }

  return (
    <FormControl component="fieldset">
      {radioGroupLabel}
      <RadioGroup row={row} name="radio-buttons">
        <FormControlLabel
          value={1}
          control={
            <Radio
              color="primary"
              onClick={() => handleRadioChange(true)}
              checked={isChecked(true)}
            />
          }
          label={labelYes}
          className={styles.Label}
        />
        <FormControlLabel
          value={0}
          control={
            <Radio
              color="primary"
              onClick={() => handleRadioChange(false)}
              checked={isChecked(false)}
            />
          }
          label={labelNo}
          className={styles.Label}
        />
      </RadioGroup>
      {errors[field.name] && touched[field.name] ? (
        <FormHelperText className={styles.DangerText}>{errors[field.name]}</FormHelperText>
      ) : null}
    </FormControl>
  );
}
Example #18
Source File: FilterControls.tsx    From clearflask with Apache License 2.0 5 votes vote down vote up
FilterControlSelect = (props: {
  type: 'radio' | 'check';
  name?: string;
  labels: Array<Label>;
  selected?: Set<String> | string;
  onToggle: (value: string) => void;
}) => {
  const classes = useStyles();
  const Control = props.type === 'check' ? Checkbox : Radio;
  return (
    <div
      key={`group-${props.name || 'noname'}-${props.type}`}
      className={classes.group}
    >
      <FilterControlTitle name={props.name} />
      {props.labels.map(label => (
        <FormControlLabel
          key={`label-${label.label}-${label.value}`}
          style={{ color: label.color }}
          label={(
            <Typography
              variant='body2'
              component='div'
              className={classes.label}>
              {label.label}
            </Typography>
          )}
          control={(
            <Control
              size='small'
              color='primary'
              checked={typeof props.selected === 'string'
                ? label.value === props.selected
                : !!props.selected?.has(label.value)}
              onChange={e => props.onToggle(label.value)}
            />
          )}
        />
      ))}
    </div>
  );
}
Example #19
Source File: PricingPlan.tsx    From clearflask with Apache License 2.0 5 votes vote down vote up
render() {
    return (
      <Card elevation={0} className={classNames(this.props.className, this.props.classes.box, this.props.selected && this.props.classes.boxSelected)}>
        <CardHeader
          title={(
            <div className={this.props.classes.title}>
              {this.props.plan.title}
              {this.props.plan.beta && (
                <div className={this.props.classes.beta}>
                  EARLY<br />ACCESS
                </div>
              )}
            </div>
          )}
          titleTypographyProps={{ align: 'center' }}
        />
        <CardContent>
          {this.renderPriceTag()}
          {(this.props.overridePerks || this.props.plan.perks).map(perk => (
            <div key={perk.desc} style={{ display: 'flex', alignItems: 'baseline' }}>
              <CheckIcon fontSize='inherit' />
              &nbsp;
              <Typography variant='subtitle1'>
                {perk.desc}
                {!!perk.terms && (<>
                  &nbsp;
                  <HelpPopper description={perk.terms} />
                </>)}
              </Typography>
            </div>
          ))}
        </CardContent>
        {
          !!this.props.actionTitle && (
            <CardActions className={this.props.classes.actions}>
              {this.props.actionType === 'radio' ? (
                <FormControlLabel
                  label={this.props.actionTitle}
                  control={(
                    <Radio
                      checked={this.props.selected}
                      color='primary'
                      onChange={e => this.props.actionOnClick && this.props.actionOnClick()}
                      disabled={!this.props.actionOnClick}
                    />
                  )}
                />
              ) : (
                <Button
                  color='primary'
                  variant='contained'
                  disableElevation
                  style={{ fontWeight: 900 }}
                  onClick={this.props.actionOnClick}
                  disabled={!this.props.actionOnClick}
                  {...(this.props.actionTo ? {
                    component: Link,
                    to: this.props.actionTo,
                  } : {})}
                  {...(this.props.actionToExt ? {
                    component: 'a',
                    href: this.props.actionToExt,
                  } : {})}
                >
                  {this.props.actionTitle}
                </Button>
              )}
            </CardActions>
          )
        }
        {this.props.remark && (
          <div className={this.props.classes.remark}>
            <Typography variant='caption' component='div' color='textSecondary'>{this.props.remark}</Typography>
          </div>
        )}
      </Card >
    );
  }
Example #20
Source File: Users.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
Users: React.FC = () => {
  const { apiGet, apiPost, apiDelete } = useAuthContext();
  const [showModal, setShowModal] = useState<Boolean>(false);
  const [selectedRow, setSelectedRow] = useState<number>(0);
  const [users, setUsers] = useState<User[]>([]);

  const columns: Column<User>[] = [
    {
      Header: 'Name',
      accessor: 'fullName',
      width: 200,
      disableFilters: true,
      id: 'name'
    },
    {
      Header: 'Email',
      accessor: 'email',
      width: 150,
      minWidth: 150,
      id: 'email',
      disableFilters: true
    },
    {
      Header: 'Organizations',
      accessor: ({ roles }) =>
        roles &&
        roles
          .filter((role) => role.approved)
          .map((role) => role.organization.name)
          .join(', '),
      id: 'organizations',
      width: 200,
      disableFilters: true
    },
    {
      Header: 'User type',
      accessor: ({ userType }) =>
        userType === 'standard'
          ? 'Standard'
          : userType === 'globalView'
          ? 'Global View'
          : 'Global Admin',
      width: 50,
      minWidth: 50,
      id: 'userType',
      disableFilters: true
    },
    {
      Header: 'Date ToU Signed',
      accessor: ({ dateAcceptedTerms }) =>
        dateAcceptedTerms
          ? `${formatDistanceToNow(parseISO(dateAcceptedTerms))} ago`
          : 'None',
      width: 50,
      minWidth: 50,
      id: 'dateAcceptedTerms',
      disableFilters: true
    },
    {
      Header: 'ToU Version',
      accessor: 'acceptedTermsVersion',
      width: 50,
      minWidth: 50,
      id: 'acceptedTermsVersion',
      disableFilters: true
    },
    {
      Header: 'Last Logged In',
      accessor: ({ lastLoggedIn }) =>
        lastLoggedIn
          ? `${formatDistanceToNow(parseISO(lastLoggedIn))} ago`
          : 'None',
      width: 50,
      minWidth: 50,
      id: 'lastLoggedIn',
      disableFilters: true
    },
    {
      Header: 'Delete',
      id: 'delete',
      Cell: ({ row }: { row: { index: number } }) => (
        <span
          onClick={() => {
            setShowModal(true);
            setSelectedRow(row.index);
          }}
        >
          <FaTimes />
        </span>
      ),
      disableFilters: true
    }
  ];
  const [errors, setErrors] = useState<Errors>({});

  const [values, setValues] = useState<{
    firstName: string;
    lastName: string;
    email: string;
    organization?: Organization;
    userType: string;
  }>({
    firstName: '',
    lastName: '',
    email: '',
    userType: ''
  });

  const fetchUsers = useCallback(async () => {
    try {
      const rows = await apiGet<User[]>('/users/');
      setUsers(rows);
    } catch (e) {
      console.error(e);
    }
  }, [apiGet]);

  const deleteRow = async (index: number) => {
    try {
      const row = users[index];
      await apiDelete(`/users/${row.id}`, { body: {} });
      setUsers(users.filter((user) => user.id !== row.id));
    } catch (e) {
      setErrors({
        global:
          e.status === 422 ? 'Unable to delete user' : e.message ?? e.toString()
      });
      console.log(e);
    }
  };

  const onSubmit: React.FormEventHandler = async (e) => {
    e.preventDefault();
    try {
      const body = {
        firstName: values.firstName,
        lastName: values.lastName,
        email: values.email,
        userType: values.userType
      };
      const user = await apiPost('/users/', {
        body
      });
      setUsers(users.concat(user));
    } catch (e) {
      setErrors({
        global:
          e.status === 422
            ? 'Error when submitting user entry.'
            : e.message ?? e.toString()
      });
      console.log(e);
    }
  };

  const onTextChange: React.ChangeEventHandler<
    HTMLInputElement | HTMLSelectElement
  > = (e) => onChange(e.target.name, e.target.value);

  const onChange = (name: string, value: any) => {
    setValues((values) => ({
      ...values,
      [name]: value
    }));
  };

  React.useEffect(() => {
    document.addEventListener('keyup', (e) => {
      //Escape
      if (e.keyCode === 27) {
        setShowModal(false);
      }
    });
  }, [apiGet]);

  return (
    <div className={classes.root}>
      <h1>Users</h1>
      <Table<User> columns={columns} data={users} fetchData={fetchUsers} />
      <h2>Invite a user</h2>
      <form onSubmit={onSubmit} className={classes.form}>
        {errors.global && <p className={classes.error}>{errors.global}</p>}
        <Label htmlFor="firstName">First Name</Label>
        <TextInput
          required
          id="firstName"
          name="firstName"
          className={classes.textField}
          type="text"
          value={values.firstName}
          onChange={onTextChange}
        />
        <Label htmlFor="lastName">Last Name</Label>
        <TextInput
          required
          id="lastName"
          name="lastName"
          className={classes.textField}
          type="text"
          value={values.lastName}
          onChange={onTextChange}
        />
        <Label htmlFor="email">Email</Label>
        <TextInput
          required
          id="email"
          name="email"
          className={classes.textField}
          type="text"
          value={values.email}
          onChange={onTextChange}
        />
        <Label htmlFor="userType">User Type</Label>
        <RadioGroup
          aria-label="User Type"
          name="userType"
          value={values.userType}
          onChange={onTextChange}
        >
          <FormControlLabel
            value="standard"
            control={<Radio color="primary" />}
            label="Standard"
          />
          <FormControlLabel
            value="globalView"
            control={<Radio color="primary" />}
            label="Global View"
          />
          <FormControlLabel
            value="globalAdmin"
            control={<Radio color="primary" />}
            label="Global Administrator"
          />
        </RadioGroup>
        <br></br>
        <Button type="submit">Invite User</Button>
      </form>
      <ImportExport<
        | User
        | {
            roles: string;
          }
      >
        name="users"
        fieldsToExport={['firstName', 'lastName', 'email', 'roles', 'userType']}
        onImport={async (results) => {
          // TODO: use a batch call here instead.
          const createdUsers = [];
          for (const result of results) {
            const parsedRoles: {
              organization: string;
              role: string;
            }[] = JSON.parse(result.roles as string);
            const body: any = result;
            // For now, just create role with the first organization
            if (parsedRoles.length > 0) {
              body.organization = parsedRoles[0].organization;
              body.organizationAdmin = parsedRoles[0].role === 'admin';
            }
            try {
              createdUsers.push(
                await apiPost('/users/', {
                  body
                })
              );
            } catch (e) {
              // Just continue when an error occurs
              console.error(e);
            }
          }
          setUsers(users.concat(...createdUsers));
        }}
        getDataToExport={() =>
          users.map((user) => ({
            ...user,
            roles: JSON.stringify(
              user.roles.map((role) => ({
                organization: role.organization.id,
                role: role.role
              }))
            )
          }))
        }
      />

      {showModal && (
        <div>
          <Overlay />
          <ModalContainer>
            <Modal
              actions={
                <>
                  <Button
                    outline
                    type="button"
                    onClick={() => {
                      setShowModal(false);
                    }}
                  >
                    Cancel
                  </Button>
                  <Button
                    type="button"
                    onClick={() => {
                      deleteRow(selectedRow);
                      setShowModal(false);
                    }}
                  >
                    Delete
                  </Button>
                </>
              }
              title={<h2>Delete user?</h2>}
            >
              <p>
                Are you sure you would like to delete{' '}
                <code>{users[selectedRow].fullName}</code>?
              </p>
            </Modal>
          </ModalContainer>
        </div>
      )}
    </div>
  );
}
Example #21
Source File: ListReplyTemplate.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
ListReplyTemplateDrawer: React.SFC<ListTemplate> = (props) => {
  const { items, drawerTitle, onItemClick, onDrawerClose, disableSend = false } = props;
  const [checkedItem, setCheckedItem] = useState<any>(null);

  const handleItemClick = () => {
    onItemClick(checkedItem);
  };

  const list =
    items.items &&
    items.items.map((item: any, index: number) => {
      const { options, title: sectionTitle } = item;

      if (!sectionTitle) {
        return null;
      }

      return (
        <div key={uuidv4()}>
          <div className={styles.SectionTitle}>{sectionTitle}</div>
          <div className={styles.Options}>
            {options
              .map((option: any) => {
                const payloadObject = {
                  payload: {
                    type: 'list_reply',
                    title: option.title,
                    id: '',
                    reply: `${option.title} ${index + 1} `,
                    postbackText: '',
                    description: option.description,
                  },
                  context: {
                    id: '',
                    gsId: items.bspMessageId,
                  },
                };

                if (option.title) {
                  return (
                    <Button
                      key={uuidv4()}
                      className={styles.ListItem}
                      onClick={() => setCheckedItem(payloadObject)}
                    >
                      <div>
                        <div>{option.title}</div>
                        <div>{option.description}</div>
                      </div>
                      <div>
                        <Radio
                          value={option.title}
                          name="radio-list-item"
                          size="small"
                          checked={checkedItem && option.title === checkedItem.payload.title}
                          color="primary"
                        />
                      </div>
                    </Button>
                  );
                }
                return null;
              })
              .filter((a: any) => a)}
          </div>
        </div>
      );
    });

  return (
    <div className={styles.Drawer}>
      <div className={styles.DrawerHeading}>
        <h3>{drawerTitle}</h3>
        <ClearIcon onClick={onDrawerClose} className={styles.DrawerCloseIcon} />
      </div>
      <div className={styles.List}>{list}</div>
      <div className={styles.SendButton}>
        <Button
          variant="contained"
          color="primary"
          disabled={!checkedItem || disableSend}
          onClick={handleItemClick}
        >
          Send
        </Button>
      </div>
    </div>
  );
}
Example #22
Source File: InteractiveOptions.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
InteractiveOptions: React.SFC<InteractiveOptionsProps> = ({
  isAddButtonChecked,
  templateType,
  inputFields,
  form,
  onAddClick,
  onRemoveClick,
  onTemplateTypeChange,
  onInputChange,
  onGlobalButtonInputChange,
  onListItemAddClick,
  onListItemRemoveClick,
  disabled = false,
  translation,
  disabledType,
}) => {
  const { values, errors, touched, setFieldValue } = form;

  const handleAddClick = (helper: any, type: string) => {
    const obj = type === LIST ? { title: '', options: [] } : { value: '' };
    helper.push(obj);
    onAddClick(true, type);
  };

  const handleRemoveClick = (helper: any, idx: number) => {
    helper.remove(idx);
    onRemoveClick(idx);
  };

  const getButtons = (index: number, arrayHelpers: any) => {
    let template: any = null;
    if (templateType === LIST) {
      template = (
        <ListReplyTemplate
          translation={translation && translation.items[index]}
          key={index}
          index={index}
          inputFields={inputFields}
          form={form}
          onListAddClick={() => handleAddClick(arrayHelpers, LIST)}
          onListRemoveClick={() => handleRemoveClick(arrayHelpers, index)}
          onListItemAddClick={(options: Array<any>) => onListItemAddClick(index, options)}
          onListItemRemoveClick={(itemIndex: number) => onListItemRemoveClick(index, itemIndex)}
          onInputChange={(value: string, payload: any) =>
            onInputChange(LIST, index, value, payload, setFieldValue)
          }
        />
      );
    }

    if (templateType === QUICK_REPLY) {
      template = (
        <QuickReplyTemplate
          translation={translation && translation[index]}
          key={index}
          index={index}
          inputFields={inputFields}
          form={form}
          onInputChange={(value: string, payload: any) =>
            onInputChange(QUICK_REPLY, index, value, payload, setFieldValue)
          }
          onAddClick={() => handleAddClick(arrayHelpers, QUICK_REPLY)}
          onRemoveClick={() => handleRemoveClick(arrayHelpers, index)}
        />
      );
    }
    return template;
  };

  const radioTemplateType = (
    <div>
      <RadioGroup
        aria-label="template-type"
        name="template-type"
        row
        value={templateType}
        onChange={(event) => onTemplateTypeChange(event.target.value)}
      >
        <div className={styles.RadioLabelWrapper}>
          <FormControlLabel
            value={QUICK_REPLY}
            control={
              <Radio
                disabled={disabledType}
                color="primary"
                checkedIcon={<ApprovedIcon className={styles.CheckedIcon} />}
                size="small"
              />
            }
            className={templateType === QUICK_REPLY ? styles.SelectedLabel : ''}
            classes={{ root: styles.RadioLabel }}
            label="Reply buttons"
          />
        </div>
        <div className={styles.RadioLabelWrapper}>
          <FormControlLabel
            value={LIST}
            control={
              <Radio
                disabled={disabledType}
                color="primary"
                checkedIcon={<ApprovedIcon className={styles.CheckedIcon} />}
                size="small"
              />
            }
            className={templateType === LIST ? styles.SelectedLabel : ''}
            classes={{ root: styles.RadioLabel }}
            label="List message"
          />
        </div>
      </RadioGroup>
      {templateType && templateType === LIST && (
        <div className={styles.GlobalButton}>
          {translation && <div className={styles.Translation}>{translation.globalButton}</div>}
          <FormControl
            fullWidth
            error={!!(errors.globalButton && touched.globalButton)}
            className={styles.FormControl}
          >
            <TextField
              placeholder="List header"
              variant="outlined"
              label="List header*"
              className={styles.TextField}
              onChange={(e: any) => {
                setFieldValue('globalButton', e.target.value);
                onGlobalButtonInputChange(e.target.value);
              }}
              value={values.globalButton}
              error={!!errors.globalButton && touched.globalButton}
            />
            {errors.globalButton && touched.globalButton && (
              <FormHelperText>{errors.globalButton}</FormHelperText>
            )}
          </FormControl>
        </div>
      )}

      {templateType && (
        <div className={templateType === QUICK_REPLY ? styles.TemplateFields : ''}>
          <FieldArray
            name="templateButtons"
            render={(arrayHelpers) =>
              values.templateButtons.map((row: any, index: any) => getButtons(index, arrayHelpers))
            }
          />
        </div>
      )}
    </div>
  );

  return <div>{isAddButtonChecked && !disabled && radioTemplateType}</div>;
}
Example #23
Source File: TemplateOptions.tsx    From glific-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
TemplateOptions: React.SFC<TemplateOptionsProps> = ({
  isAddButtonChecked,
  templateType,
  inputFields,
  form: { touched, errors, values },
  onAddClick,
  onRemoveClick,
  onTemplateTypeChange,
  onInputChange,
  disabled = false,
}) => {
  const buttonTitle = 'Button Title';
  const buttonValue = 'Button Value';
  const buttonTitles: any = {
    CALL_TO_ACTION: 'Call to action',
    QUICK_REPLY: 'Quick Reply',
  };

  const handleAddClick = (helper: any, type: boolean) => {
    const obj = type ? { type: '', value: '', title: '' } : { value: '' };
    helper.push(obj);
    onAddClick();
  };

  const handleRemoveClick = (helper: any, idx: number) => {
    helper.remove(idx);
    onRemoveClick(idx);
  };

  const addButton = (helper: any, type: boolean = false) => {
    const title = templateType ? buttonTitles[templateType] : '';
    const buttonClass =
      templateType === QUICK_REPLY ? styles.QuickReplyAddButton : styles.CallToActionAddButton;
    return (
      <Button
        className={buttonClass}
        variant="outlined"
        color="primary"
        onClick={() => handleAddClick(helper, type)}
      >
        Add {title}
      </Button>
    );
  };

  const getButtons = (row: any, index: number, arrayHelpers: any) => {
    const { type, title, value }: any = row;
    let template: any = null;

    const isError = (key: string) =>
      !!(
        errors.templateButtons &&
        touched.templateButtons &&
        errors.templateButtons[index] &&
        errors.templateButtons[index][key]
      );

    if (templateType === CALL_TO_ACTION) {
      template = (
        <div className={styles.CallToActionContainer} key={index.toString()}>
          <div className={styles.CallToActionWrapper}>
            <div>
              <div className={styles.RadioStyles}>
                <FormControl fullWidth error={isError('type')} className={styles.FormControl}>
                  <RadioGroup
                    aria-label="action-radio-buttons"
                    name="action-radio-buttons"
                    row
                    value={type}
                    onChange={(e: any) => onInputChange(e, row, index, 'type')}
                    className={styles.RadioGroup}
                  >
                    <FormControlLabel
                      value="phone_number"
                      control={
                        <Radio
                          color="primary"
                          disabled={
                            disabled ||
                            (index === 0 &&
                              inputFields.length > 1 &&
                              inputFields[0].type !== 'phone_number') ||
                            (index > 0 &&
                              inputFields[0].type &&
                              inputFields[0].type === 'phone_number')
                          }
                        />
                      }
                      label="Phone number"
                    />
                    <FormControlLabel
                      value="url"
                      control={
                        <Radio
                          color="primary"
                          disabled={
                            disabled ||
                            (index === 0 &&
                              inputFields.length > 1 &&
                              inputFields[0].type !== 'url') ||
                            (index > 0 && inputFields[0].type && inputFields[0].type === 'url')
                          }
                        />
                      }
                      label="URL"
                    />
                  </RadioGroup>
                  {errors.templateButtons &&
                  touched.templateButtons &&
                  touched.templateButtons[index] ? (
                    <FormHelperText>{errors.templateButtons[index]?.type}</FormHelperText>
                  ) : null}
                </FormControl>
              </div>
              <div>
                {inputFields.length > 1 ? (
                  <DeleteIcon onClick={() => handleRemoveClick(arrayHelpers, index)} />
                ) : null}
              </div>
            </div>
            <div className={styles.TextFieldWrapper}>
              <FormControl fullWidth error={isError('title')} className={styles.FormControl}>
                <TextField
                  disabled={disabled}
                  title={title}
                  defaultValue={value}
                  placeholder={buttonTitle}
                  variant="outlined"
                  label={buttonTitle}
                  onBlur={(e: any) => onInputChange(e, row, index, 'title')}
                  className={styles.TextField}
                  error={isError('title')}
                />
                {errors.templateButtons &&
                touched.templateButtons &&
                touched.templateButtons[index] ? (
                  <FormHelperText>{errors.templateButtons[index]?.title}</FormHelperText>
                ) : null}
              </FormControl>
            </div>
            <div className={styles.TextFieldWrapper}>
              <FormControl fullWidth error={isError('value')} className={styles.FormControl}>
                <TextField
                  title={value}
                  defaultValue={value}
                  disabled={disabled}
                  placeholder={buttonValue}
                  variant="outlined"
                  label={buttonValue}
                  onBlur={(e: any) => onInputChange(e, row, index, 'value')}
                  className={styles.TextField}
                  error={isError('value')}
                />
                {errors.templateButtons &&
                touched.templateButtons &&
                touched.templateButtons[index] ? (
                  <FormHelperText>{errors.templateButtons[index]?.value}</FormHelperText>
                ) : null}
              </FormControl>
            </div>
          </div>
          <div>
            {inputFields.length === index + 1 && inputFields.length !== 2
              ? addButton(arrayHelpers, true)
              : null}
          </div>
        </div>
      );
    }

    if (templateType === QUICK_REPLY) {
      template = (
        <div className={styles.QuickReplyContainer} key={index.toString()}>
          <div className={styles.QuickReplyWrapper}>
            <FormControl fullWidth error={isError('value')} className={styles.FormControl}>
              <TextField
                disabled={disabled}
                defaultValue={value}
                title={title}
                placeholder={`Quick reply ${index + 1} title`}
                label={`Quick reply ${index + 1} title`}
                variant="outlined"
                onBlur={(e: any) => onInputChange(e, row, index, 'value')}
                className={styles.TextField}
                error={isError('value')}
                InputProps={{
                  endAdornment: inputFields.length > 1 && !disabled && (
                    <CrossIcon
                      className={styles.RemoveIcon}
                      title="Remove"
                      onClick={() => handleRemoveClick(arrayHelpers, index)}
                    />
                  ),
                }}
              />
              {errors.templateButtons &&
              touched.templateButtons &&
              touched.templateButtons[index] ? (
                <FormHelperText>{errors.templateButtons[index]?.value}</FormHelperText>
              ) : null}
            </FormControl>
          </div>
          <div>
            {inputFields.length === index + 1 && inputFields.length !== 3
              ? addButton(arrayHelpers)
              : null}
          </div>
        </div>
      );
    }
    return template;
  };

  const radioTemplateType = (
    <div>
      <RadioGroup
        aria-label="template-type"
        name="template-type"
        row
        value={templateType}
        onChange={(event) => onTemplateTypeChange(event.target.value)}
      >
        <div className={styles.RadioLabelWrapper}>
          <FormControlLabel
            value={CALL_TO_ACTION}
            control={<Radio color="primary" disabled={disabled} />}
            label="Call to actions"
            classes={{ root: styles.RadioLabel }}
          />
          <Tooltip title={GUPSHUP_CALL_TO_ACTION} placement="right" tooltipClass={styles.Tooltip}>
            <InfoIcon />
          </Tooltip>
        </div>
        <div className={styles.RadioLabelWrapper}>
          <FormControlLabel
            value={QUICK_REPLY}
            control={<Radio color="primary" disabled={disabled} />}
            label="Quick replies"
            className={styles.RadioLabel}
          />
          <Tooltip title={GUPSHUP_QUICK_REPLY} placement="right" tooltipClass={styles.Tooltip}>
            <InfoIcon />
          </Tooltip>
        </div>
      </RadioGroup>

      {templateType ? (
        <div
          className={
            templateType === QUICK_REPLY
              ? styles.QuickTemplateFields
              : styles.CallToActionTemplateFields
          }
        >
          <FieldArray
            name="templateButtons"
            render={(arrayHelpers) =>
              values.templateButtons.map((row: any, index: any) =>
                getButtons(row, index, arrayHelpers)
              )
            }
          />
        </div>
      ) : null}
    </div>
  );

  return <div>{isAddButtonChecked && radioTemplateType}</div>;
}
Example #24
Source File: CreateGame.tsx    From planning-poker with MIT License 4 votes vote down vote up
CreateGame = () => {
  const history = useHistory();
  const [gameName, setGameName] = useState('Avengers');
  const [createdBy, setCreatedBy] = useState('SuperHero');
  const [gameType, setGameType] = useState(GameType.Fibonacci);

  const handleSubmit = async (event: FormEvent) => {
    event.preventDefault();
    const game: NewGame = {
      name: gameName,
      createdBy: createdBy,
      gameType: gameType,
      createdAt: new Date(),
    };
    const newGameId = await addNewGame(game);
    history.push(`/game/${newGameId}`);
  };

  return (
    <Grow in={true} timeout={1000}>
      <form onSubmit={handleSubmit}>
        <Card variant='outlined' className='CreateGameCard'>
          <CardHeader
            className='CreateGameCardHeader'
            title='Create New Session'
            titleTypographyProps={{ variant: 'h4' }}
          />
          <CardContent className='CreateGameCardContent'>
            <TextField
              className='CreateGameTextField'
              required
              id='filled-required'
              label='Session Name'
              placeholder='Enter a session name'
              defaultValue={gameName}
              variant='outlined'
              onChange={(event: ChangeEvent<HTMLInputElement>) => setGameName(event.target.value)}
            />
            <TextField
              className='CreateGameTextField'
              required
              id='filled-required'
              label='Your Name'
              placeholder='Enter your name'
              defaultValue={createdBy}
              variant='outlined'
              onChange={(event: ChangeEvent<HTMLInputElement>) => setCreatedBy(event.target.value)}
            />
            <RadioGroup
              aria-label='gender'
              name='gender1'
              value={gameType}
              onChange={(
                event: ChangeEvent<{
                  name?: string | undefined;
                  value: any;
                }>
              ) => setGameType(event.target.value)}
            >
              <FormControlLabel
                value={GameType.Fibonacci}
                control={<Radio color='primary' size='small' />}
                label='Fibonacci (0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89)'
              />
              <FormControlLabel
                value={GameType.ShortFibonacci}
                control={<Radio color='primary' size='small' />}
                label='Short Fibonacci (0, ½, 1, 2, 3, 5, 8, 13, 20, 40, 100)'
              />
              <FormControlLabel
                value={GameType.TShirt}
                control={<Radio color='primary' size='small' />}
                label='T-Shirt (XXS, XS, S, M, L, XL, XXL)'
              />
            </RadioGroup>
          </CardContent>
          <CardActions className='CreateGameCardAction'>
            <Button type='submit' variant='contained' color='primary' className='CreateGameButton'>
              Create
            </Button>
          </CardActions>
        </Card>
      </form>
    </Grow>
  );
}
Example #25
Source File: Settings.tsx    From back-home-safe with GNU General Public License v3.0 4 votes vote down vote up
Settings = () => {
  const { t } = useTranslation("main_screen");
  const { hasCameraSupport } = useCamera();
  const { autoRemoveRecordDay, setAutoRemoveRecordDay } = useTravelRecord();
  const { incognito, setIncognito, value } = useData();
  const [languageOpen, setLanguageOpen] = useState(false);
  const { language, setLanguage } = useI18n();

  const handleLanguageClick = () => {
    setLanguageOpen(!languageOpen);
  };

  const handleExportData = () => {
    const dataStr =
      "data:text/json;charset=utf-8," +
      encodeURIComponent(JSON.stringify(value));
    const downloadAnchorNode = document.createElement("a");
    downloadAnchorNode.setAttribute("href", dataStr);
    downloadAnchorNode.setAttribute("download", "export.json");
    document.body.appendChild(downloadAnchorNode); // required for firefox
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
  };

  return (
    <PageWrapper>
      <Header name={t("setting.name")} />
      <ContentWrapper>
        <StyledList
          subheader={
            <ListSubheader>{t("setting.section.common")}</ListSubheader>
          }
        >
          {hasCameraSupport ? (
            <StyledLink to="/cameraSetting">
              <ListItem button>
                <ListItemText primary={t("setting.item.camera_setting")} />
              </ListItem>
            </StyledLink>
          ) : (
            <ListItem button disabled>
              <ListItemText primary={t("setting.item.camera_setting")} />
            </ListItem>
          )}
          <StyledLink to="/confirmPageSetting">
            <ListItem button>
              <ListItemText primary={t("setting.item.confirm_page_setting")} />
            </ListItem>
          </StyledLink>
          <ListItem>
            <ListItemText primary={t("setting.item.auto_delete_record")} />
            <ListItemSecondaryAction>
              <Select
                labelId="cameraId"
                id="demo-simple-select"
                value={autoRemoveRecordDay}
                onChange={(e) => {
                  setAutoRemoveRecordDay(e.target.value as number);
                }}
              >
                {range(1, 100).map((day) => (
                  <MenuItem value={day} key={day}>
                    {day}{" "}
                    {day === 1 ? t("setting.form.day") : t("setting.form.days")}
                  </MenuItem>
                ))}
              </Select>
            </ListItemSecondaryAction>
          </ListItem>
          <ListItem>
            <ListItemText
              primary={t("setting.item.incognito_mode.name")}
              secondary={t("setting.item.incognito_mode.explanation")}
            />
            <ListItemSecondaryAction>
              <Switch
                checked={incognito}
                onChange={(e) => {
                  setIncognito(e.target.checked);
                }}
                color="primary"
              />
            </ListItemSecondaryAction>
          </ListItem>
          <ListItem button onClick={handleLanguageClick}>
            <ListItemText primary={t("setting.item.language")} />
            {languageOpen ? <ExpandLess /> : <ExpandMore />}
          </ListItem>
          <Collapse in={languageOpen} timeout="auto" unmountOnExit>
            <ListItem>
              <RadioGroup
                aria-label="language"
                name="language"
                value={language}
                onChange={(event) => {
                  setLanguage(event.target.value as languageType);
                }}
              >
                <FormControlLabel
                  value={languageType["ZH-HK"]}
                  control={<Radio />}
                  label="繁體中文"
                />
                <FormControlLabel
                  value={languageType.EN}
                  control={<Radio />}
                  label="English"
                />
              </RadioGroup>
            </ListItem>
          </Collapse>
        </StyledList>
        <Divider />
        <StyledList
          subheader={<ListSubheader>{t("setting.section.lab")}</ListSubheader>}
        >
          <StyledLink to="/qrGenerator">
            <ListItem button>
              <ListItemText primary={t("setting.item.qr_generator")} />
            </ListItem>
          </StyledLink>
          <StyledLink to="/vaccinationQRReader">
            <ListItem button>
              <ListItemText primary={t("setting.item.vaccinationQRReader")} />
            </ListItem>
          </StyledLink>
          <ListItem onClick={handleExportData}>
            <ListItemText primary={t("setting.item.export_data")} />
          </ListItem>
          <ListItem button>
            <ListItemText
              primary={t("setting.item.reset")}
              onClick={clearAllData}
            />
          </ListItem>
        </StyledList>
        <Divider />
        <StyledList
          subheader={
            <ListSubheader>
              {t("setting.section.version")}: {__APP_VERSION__}
            </ListSubheader>
          }
        >
          <StyledExternalLink
            href="https://gitlab.com/codogo-b/back-home-safe"
            target="_blank"
          >
            <ListItem button>
              <ListItemText primary={t("setting.item.about_us")} />
            </ListItem>
          </StyledExternalLink>
          <StyledLink to="/disclaimer">
            <ListItem button>
              <ListItemText primary={t("setting.item.disclaimer")} />
            </ListItem>
          </StyledLink>
          <StyledExternalLink
            href="https://gitlab.com/codogo-b/back-home-safe/-/blob/master/CHANGELOG.md"
            target="_blank"
          >
            <ListItem button>
              <ListItemText primary={t("setting.item.change_log")} />
            </ListItem>
          </StyledExternalLink>
          <StyledExternalLink
            href="https://gitlab.com/codogo-b/back-home-safe/-/issues"
            target="_blank"
          >
            <ListItem button>
              <ListItemText primary={t("setting.item.report_issue")} />
            </ListItem>
          </StyledExternalLink>
        </StyledList>
      </ContentWrapper>
    </PageWrapper>
  );
}
Example #26
Source File: PopupContents.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
// TODO: Implement infinite scroll here
export default function PopupContents({
  value = [],
  onChange,
  config,
  row,
  docRef,
}: IPopupContentsProps) {
  const url = config.url;
  const titleKey = config.titleKey ?? config.primaryKey;
  const subtitleKey = config.subtitleKey;
  const resultsKey = config.resultsKey;
  const primaryKey = config.primaryKey;
  const multiple = Boolean(config.multiple);

  const classes = useStyles();

  // Webservice search query
  const [query, setQuery] = useState("");
  // Webservice response
  const [response, setResponse] = useState<any | null>(null);

  const [docData, setDocData] = useState<any | null>(null);
  useEffect(() => {
    docRef.get().then((d) => setDocData(d.data()));
  }, []);

  const hits: any["hits"] = _get(response, resultsKey) ?? [];
  const [search] = useDebouncedCallback(
    async (query: string) => {
      if (!docData) return;
      if (!url) return;
      const uri = new URL(url),
        params = { q: query };
      Object.keys(params).forEach((key) =>
        uri.searchParams.append(key, params[key])
      );

      const resp = await fetch(uri.toString(), {
        method: "POST",
        body: JSON.stringify(docData),
        headers: { "content-type": "application/json" },
      });

      const jsonBody = await resp.json();
      setResponse(jsonBody);
    },
    1000,
    { leading: true }
  );

  useEffect(() => {
    search(query);
  }, [query, docData]);

  if (!response) return <Loading />;

  const select = (hit: any) => () => {
    if (multiple) onChange([...value, hit]);
    else onChange([hit]);
  };
  const deselect = (hit: any) => () => {
    if (multiple)
      onChange(value.filter((v) => v[primaryKey] !== hit[primaryKey]));
    else onChange([]);
  };

  const selectedValues = value?.map((item) => _get(item, primaryKey));

  const clearSelection = () => onChange([]);

  return (
    <Grid container direction="column" className={classes.grid}>
      <Grid item className={classes.searchRow}>
        <TextField
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          fullWidth
          variant="filled"
          margin="dense"
          label="Search items"
          className={classes.noMargins}
          InputProps={{
            endAdornment: (
              <InputAdornment position="end">
                <SearchIcon />
              </InputAdornment>
            ),
          }}
          onClick={(e) => e.stopPropagation()}
          onKeyDown={(e) => e.stopPropagation()}
        />
      </Grid>

      <Grid item xs className={classes.listRow}>
        <List className={classes.list}>
          {hits.map((hit) => {
            const isSelected =
              selectedValues.indexOf(_get(hit, primaryKey)) !== -1;
            console.log(`Selected Values: ${selectedValues}`);
            return (
              <React.Fragment key={_get(hit, primaryKey)}>
                <MenuItem
                  dense
                  onClick={isSelected ? deselect(hit) : select(hit)}
                >
                  <ListItemIcon className={classes.checkboxContainer}>
                    {multiple ? (
                      <Checkbox
                        edge="start"
                        checked={isSelected}
                        tabIndex={-1}
                        color="secondary"
                        className={classes.checkbox}
                        disableRipple
                        inputProps={{
                          "aria-labelledby": `label-${_get(hit, primaryKey)}`,
                        }}
                      />
                    ) : (
                      <Radio
                        edge="start"
                        checked={isSelected}
                        tabIndex={-1}
                        color="secondary"
                        className={classes.checkbox}
                        disableRipple
                        inputProps={{
                          "aria-labelledby": `label-${_get(hit, primaryKey)}`,
                        }}
                      />
                    )}
                  </ListItemIcon>
                  <ListItemText
                    id={`label-${_get(hit, primaryKey)}`}
                    primary={_get(hit, titleKey)}
                    secondary={!subtitleKey ? "" : _get(hit, subtitleKey)}
                  />
                </MenuItem>
                <Divider className={classes.divider} />
              </React.Fragment>
            );
          })}
        </List>
      </Grid>

      {multiple && (
        <Grid item className={clsx(classes.footerRow, classes.selectedRow)}>
          <Grid
            container
            direction="row"
            justify="space-between"
            alignItems="center"
          >
            <Typography
              variant="button"
              color="textSecondary"
              className={classes.selectedNum}
            >
              {value?.length} of {hits?.length}
            </Typography>

            <Button
              disabled={!value || value.length === 0}
              onClick={clearSelection}
              color="primary"
              className={classes.selectAllButton}
            >
              Clear Selection
            </Button>
          </Grid>
        </Grid>
      )}
    </Grid>
  );
}
Example #27
Source File: Organization.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
Organization: React.FC = () => {
  const {
    apiGet,
    apiPut,
    apiPost,
    user,
    setFeedbackMessage
  } = useAuthContext();
  const { organizationId } = useParams<{ organizationId: string }>();
  const [organization, setOrganization] = useState<OrganizationType>();
  const [tags, setTags] = useState<AutocompleteType[]>([]);
  const [userRoles, setUserRoles] = useState<Role[]>([]);
  const [scanTasks, setScanTasks] = useState<ScanTask[]>([]);
  const [scans, setScans] = useState<Scan[]>([]);
  const [scanSchema, setScanSchema] = useState<ScanSchema>({});
  const [newUserValues, setNewUserValues] = useState<{
    firstName: string;
    lastName: string;
    email: string;
    organization?: OrganizationType;
    role: string;
  }>({
    firstName: '',
    lastName: '',
    email: '',
    role: ''
  });
  const classes = useStyles();
  const [tagValue, setTagValue] = React.useState<AutocompleteType | null>(null);
  const [inputValue, setInputValue] = React.useState('');
  const [dialog, setDialog] = React.useState<{
    open: boolean;
    type?: 'rootDomains' | 'ipBlocks' | 'tags';
    label?: string;
  }>({ open: false });

  const dateAccessor = (date?: string) => {
    return !date || new Date(date).getTime() === new Date(0).getTime()
      ? 'None'
      : `${formatDistanceToNow(parseISO(date))} ago`;
  };

  const userRoleColumns: Column<Role>[] = [
    {
      Header: 'Name',
      accessor: ({ user }) => user.fullName,
      width: 200,
      disableFilters: true,
      id: 'name'
    },
    {
      Header: 'Email',
      accessor: ({ user }) => user.email,
      width: 150,
      minWidth: 150,
      id: 'email',
      disableFilters: true
    },
    {
      Header: 'Role',
      accessor: ({ approved, role, user }) => {
        if (approved) {
          if (user.invitePending) {
            return 'Invite pending';
          } else if (role === 'admin') {
            return 'Administrator';
          } else {
            return 'Member';
          }
        }
        return 'Pending approval';
      },
      width: 50,
      minWidth: 50,
      id: 'approved',
      disableFilters: true
    },
    {
      Header: () => {
        return (
          <div style={{ justifyContent: 'flex-center' }}>
            <Button color="secondary" onClick={() => setDialog({ open: true })}>
              <ControlPoint style={{ marginRight: '10px' }}></ControlPoint>
              Add member
            </Button>
          </div>
        );
      },
      id: 'action',
      Cell: ({ row }: { row: { index: number } }) => {
        const isApproved =
          !organization?.userRoles[row.index] ||
          organization?.userRoles[row.index].approved;
        return (
          <>
            {isApproved ? (
              <Button
                onClick={() => {
                  removeUser(row.index);
                }}
                color="secondary"
              >
                <p>Remove</p>
              </Button>
            ) : (
              <Button
                onClick={() => {
                  approveUser(row.index);
                }}
                color="secondary"
              >
                <p>Approve</p>
              </Button>
            )}
          </>
        );
      },
      disableFilters: true
    }
  ];

  const scanColumns: Column<Scan>[] = [
    {
      Header: 'Name',
      accessor: 'name',
      width: 150,
      id: 'name',
      disableFilters: true
    },
    {
      Header: 'Description',
      accessor: ({ name }) => scanSchema[name] && scanSchema[name].description,
      width: 200,
      minWidth: 200,
      id: 'description',
      disableFilters: true
    },
    {
      Header: 'Mode',
      accessor: ({ name }) =>
        scanSchema[name] && scanSchema[name].isPassive ? 'Passive' : 'Active',
      width: 150,
      minWidth: 150,
      id: 'mode',
      disableFilters: true
    },
    {
      Header: 'Action',
      id: 'action',
      maxWidth: 100,
      Cell: ({ row }: { row: { index: number } }) => {
        if (!organization) return;
        const enabled = organization.granularScans.find(
          (scan) => scan.id === scans[row.index].id
        );
        return (
          <Button
            type="button"
            onClick={() => {
              updateScan(scans[row.index], !enabled);
            }}
          >
            {enabled ? 'Disable' : 'Enable'}
          </Button>
        );
      },
      disableFilters: true
    }
  ];

  const scanTaskColumns: Column<ScanTask>[] = [
    {
      Header: 'ID',
      accessor: 'id',
      disableFilters: true
    },
    {
      Header: 'Status',
      accessor: 'status',
      disableFilters: true
    },
    {
      Header: 'Type',
      accessor: 'type',
      disableFilters: true
    },
    {
      Header: 'Name',
      accessor: ({ scan }) => scan?.name,
      disableFilters: true
    },
    {
      Header: 'Created At',
      accessor: ({ createdAt }) => dateAccessor(createdAt),
      disableFilters: true,
      disableSortBy: true
    },
    {
      Header: 'Requested At',
      accessor: ({ requestedAt }) => dateAccessor(requestedAt),
      disableFilters: true,
      disableSortBy: true
    },
    {
      Header: 'Started At',
      accessor: ({ startedAt }) => dateAccessor(startedAt),
      disableFilters: true,
      disableSortBy: true
    },
    {
      Header: 'Finished At',
      accessor: ({ finishedAt }) => dateAccessor(finishedAt),
      disableFilters: true,
      disableSortBy: true
    },
    {
      Header: 'Output',
      accessor: 'output',
      disableFilters: true
    }
  ];

  const fetchOrganization = useCallback(async () => {
    try {
      const organization = await apiGet<OrganizationType>(
        `/organizations/${organizationId}`
      );
      organization.scanTasks.sort(
        (a, b) =>
          new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
      );
      setOrganization(organization);
      setUserRoles(organization.userRoles);
      setScanTasks(organization.scanTasks);
      const tags = await apiGet<OrganizationTag[]>(`/organizations/tags`);
      setTags(tags);
    } catch (e) {
      console.error(e);
    }
  }, [apiGet, setOrganization, organizationId]);

  const fetchScans = useCallback(async () => {
    try {
      const response = await apiGet<{
        scans: Scan[];
        schema: ScanSchema;
      }>('/granularScans/');
      let { scans } = response;
      const { schema } = response;

      if (user?.userType !== 'globalAdmin')
        scans = scans.filter(
          (scan) =>
            scan.name !== 'censysIpv4' && scan.name !== 'censysCertificates'
        );

      setScans(scans);
      setScanSchema(schema);
    } catch (e) {
      console.error(e);
    }
  }, [apiGet, user]);

  const approveUser = async (user: number) => {
    try {
      await apiPost(
        `/organizations/${organization?.id}/roles/${organization?.userRoles[user].id}/approve`,
        { body: {} }
      );
      const copy = userRoles.map((role, id) =>
        id === user ? { ...role, approved: true } : role
      );
      setUserRoles(copy);
    } catch (e) {
      console.error(e);
    }
  };

  const removeUser = async (user: number) => {
    try {
      await apiPost(
        `/organizations/${organization?.id}/roles/${userRoles[user].id}/remove`,
        { body: {} }
      );
      const copy = userRoles.filter((_, ind) => ind !== user);
      setUserRoles(copy);
    } catch (e) {
      console.error(e);
    }
  };

  const updateOrganization = async (body: any) => {
    try {
      const org = await apiPut('/organizations/' + organization?.id, {
        body: organization
      });
      setOrganization(org);
      setFeedbackMessage({
        message: 'Organization successfully updated',
        type: 'success'
      });
    } catch (e) {
      setFeedbackMessage({
        message:
          e.status === 422
            ? 'Error updating organization'
            : e.message ?? e.toString(),
        type: 'error'
      });
      console.error(e);
    }
  };

  const updateScan = async (scan: Scan, enabled: boolean) => {
    try {
      if (!organization) return;
      await apiPost(
        `/organizations/${organization?.id}/granularScans/${scan.id}/update`,
        {
          body: {
            enabled
          }
        }
      );
      setOrganization({
        ...organization,
        granularScans: enabled
          ? organization.granularScans.concat([scan])
          : organization.granularScans.filter(
              (granularScan) => granularScan.id !== scan.id
            )
      });
    } catch (e) {
      setFeedbackMessage({
        message:
          e.status === 422 ? 'Error updating scan' : e.message ?? e.toString(),
        type: 'error'
      });
      console.error(e);
    }
  };

  useEffect(() => {
    fetchOrganization();
  }, [fetchOrganization]);

  const onInviteUserSubmit = async () => {
    try {
      const body = {
        firstName: newUserValues.firstName,
        lastName: newUserValues.lastName,
        email: newUserValues.email,
        organization: organization?.id,
        organizationAdmin: newUserValues.role === 'admin'
      };
      const user: User = await apiPost('/users/', {
        body
      });
      const newRole = user.roles[user.roles.length - 1];
      newRole.user = user;
      if (userRoles.find((role) => role.user.id === user.id)) {
        setUserRoles(
          userRoles.map((role) => (role.user.id === user.id ? newRole : role))
        );
      } else {
        setUserRoles(userRoles.concat([newRole]));
      }
    } catch (e) {
      setFeedbackMessage({
        message:
          e.status === 422 ? 'Error inviting user' : e.message ?? e.toString(),
        type: 'error'
      });
      console.log(e);
    }
  };

  const onInviteUserTextChange: React.ChangeEventHandler<
    HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
  > = (e) => onInviteUserChange(e.target.name, e.target.value);

  const onInviteUserChange = (name: string, value: any) => {
    setNewUserValues((values) => ({
      ...values,
      [name]: value
    }));
  };
  const filter = createFilterOptions<AutocompleteType>();

  const ListInput = (props: {
    type: 'rootDomains' | 'ipBlocks' | 'tags';
    label: string;
  }) => {
    if (!organization) return null;
    const elements: (string | OrganizationTag)[] = organization[props.type];
    return (
      <div className={classes.headerRow}>
        <label>{props.label}</label>
        <span>
          {elements &&
            elements.map((value: string | OrganizationTag, index: number) => (
              <Chip
                className={classes.chip}
                key={index}
                label={typeof value === 'string' ? value : value.name}
                onDelete={() => {
                  organization[props.type].splice(index, 1);
                  setOrganization({ ...organization });
                }}
              ></Chip>
            ))}
          <Chip
            label="ADD"
            variant="outlined"
            color="secondary"
            onClick={() => {
              setDialog({
                open: true,
                type: props.type,
                label: props.label
              });
            }}
          />
        </span>
      </div>
    );
  };

  if (!organization) return null;

  const views = [
    <Paper className={classes.settingsWrapper} key={0}>
      <Dialog
        open={dialog.open}
        onClose={() => setDialog({ open: false })}
        aria-labelledby="form-dialog-title"
        maxWidth="xs"
        fullWidth
      >
        <DialogTitle id="form-dialog-title">
          Add {dialog.label && dialog.label.slice(0, -1)}
        </DialogTitle>
        <DialogContent>
          {dialog.type === 'tags' ? (
            <>
              <DialogContentText>
                Select an existing tag or add a new one.
              </DialogContentText>
              <Autocomplete
                value={tagValue}
                onChange={(event, newValue) => {
                  if (typeof newValue === 'string') {
                    setTagValue({
                      name: newValue
                    });
                  } else {
                    setTagValue(newValue);
                  }
                }}
                filterOptions={(options, params) => {
                  const filtered = filter(options, params);
                  // Suggest the creation of a new value
                  if (
                    params.inputValue !== '' &&
                    !filtered.find(
                      (tag) =>
                        tag.name?.toLowerCase() ===
                        params.inputValue.toLowerCase()
                    )
                  ) {
                    filtered.push({
                      name: params.inputValue,
                      title: `Add "${params.inputValue}"`
                    });
                  }
                  return filtered;
                }}
                selectOnFocus
                clearOnBlur
                handleHomeEndKeys
                options={tags}
                getOptionLabel={(option) => {
                  return option.name ?? '';
                }}
                renderOption={(option) => {
                  if (option.title) return option.title;
                  return option.name ?? '';
                }}
                fullWidth
                freeSolo
                renderInput={(params) => (
                  <TextField {...params} variant="outlined" />
                )}
              />
            </>
          ) : (
            <TextField
              autoFocus
              margin="dense"
              id="name"
              label={dialog.label && dialog.label.slice(0, -1)}
              type="text"
              fullWidth
              onChange={(e) => setInputValue(e.target.value)}
            />
          )}
        </DialogContent>
        <DialogActions>
          <Button variant="outlined" onClick={() => setDialog({ open: false })}>
            Cancel
          </Button>
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              if (dialog.type && dialog.type !== 'tags') {
                if (inputValue) {
                  organization[dialog.type].push(inputValue);
                  setOrganization({ ...organization });
                }
              } else {
                if (tagValue) {
                  if (!organization.tags) organization.tags = [];
                  organization.tags.push(tagValue as any);
                  setOrganization({ ...organization });
                }
              }
              setDialog({ open: false });
              setInputValue('');
              setTagValue(null);
            }}
          >
            Add
          </Button>
        </DialogActions>
      </Dialog>
      <TextField
        value={organization.name}
        disabled
        variant="filled"
        InputProps={{
          className: classes.orgName
        }}
      ></TextField>
      <ListInput label="Root Domains" type="rootDomains"></ListInput>
      <ListInput label="IP Blocks" type="ipBlocks"></ListInput>
      <ListInput label="Tags" type="tags"></ListInput>
      <div className={classes.headerRow}>
        <label>Passive Mode</label>
        <span>
          <SwitchInput
            checked={organization.isPassive}
            onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
              setOrganization({
                ...organization,
                isPassive: event.target.checked
              });
            }}
            color="primary"
          />
        </span>
      </div>
      <div className={classes.buttons}>
        <Link to={`/organizations`}>
          <Button
            variant="outlined"
            style={{ marginRight: '10px', color: '#565C65' }}
          >
            Cancel
          </Button>
        </Link>
        <Button
          variant="contained"
          onClick={updateOrganization}
          style={{ background: '#565C65', color: 'white' }}
        >
          Save
        </Button>
      </div>
    </Paper>,
    <React.Fragment key={1}>
      <Table<Role> columns={userRoleColumns} data={userRoles} />
      <Dialog
        open={dialog.open}
        onClose={() => setDialog({ open: false })}
        aria-labelledby="form-dialog-title"
        maxWidth="xs"
        fullWidth
      >
        <DialogTitle id="form-dialog-title">Add Member</DialogTitle>
        <DialogContent>
          <p style={{ color: '#3D4551' }}>
            Organization members can view Organization-specific vulnerabilities,
            domains, and notes. Organization administrators can additionally
            manage members and update the organization.
          </p>
          <TextField
            margin="dense"
            id="firstName"
            name="firstName"
            label="First Name"
            type="text"
            fullWidth
            value={newUserValues.firstName}
            onChange={onInviteUserTextChange}
            variant="filled"
            InputProps={{
              className: classes.textField
            }}
          />
          <TextField
            margin="dense"
            id="lastName"
            name="lastName"
            label="Last Name"
            type="text"
            fullWidth
            value={newUserValues.lastName}
            onChange={onInviteUserTextChange}
            variant="filled"
            InputProps={{
              className: classes.textField
            }}
          />
          <TextField
            margin="dense"
            id="email"
            name="email"
            label="Email"
            type="text"
            fullWidth
            value={newUserValues.email}
            onChange={onInviteUserTextChange}
            variant="filled"
            InputProps={{
              className: classes.textField
            }}
          />
          <br></br>
          <br></br>
          <FormLabel component="legend">Role</FormLabel>
          <RadioGroup
            aria-label="role"
            name="role"
            value={newUserValues.role}
            onChange={onInviteUserTextChange}
          >
            <FormControlLabel
              value="standard"
              control={<Radio color="primary" />}
              label="Standard"
            />
            <FormControlLabel
              value="admin"
              control={<Radio color="primary" />}
              label="Administrator"
            />
          </RadioGroup>
        </DialogContent>
        <DialogActions>
          <Button variant="outlined" onClick={() => setDialog({ open: false })}>
            Cancel
          </Button>
          <Button
            variant="contained"
            color="primary"
            onClick={async () => {
              onInviteUserSubmit();
              setDialog({ open: false });
            }}
          >
            Add
          </Button>
        </DialogActions>
      </Dialog>
    </React.Fragment>,
    <React.Fragment key={2}>
      <OrganizationList parent={organization}></OrganizationList>
    </React.Fragment>,
    <React.Fragment key={3}>
      <Table<Scan> columns={scanColumns} data={scans} fetchData={fetchScans} />
      <h2>Organization Scan History</h2>
      <Table<ScanTask> columns={scanTaskColumns} data={scanTasks} />
    </React.Fragment>
  ];

  let navItems = [
    {
      title: 'Settings',
      path: `/organizations/${organizationId}`,
      exact: true
    },
    {
      title: 'Members',
      path: `/organizations/${organizationId}/members`
    }
  ];

  if (!organization.parent) {
    navItems = navItems.concat([
      // { title: 'Teams', path: `/organizations/${organizationId}/teams` },
      { title: 'Scans', path: `/organizations/${organizationId}/scans` }
    ]);
  }

  return (
    <div>
      <div className={classes.header}>
        <h1 className={classes.headerLabel}>
          <Link to="/organizations">Organizations</Link>
          {organization.parent && (
            <>
              <ChevronRight></ChevronRight>
              <Link to={'/organizations/' + organization.parent.id}>
                {organization.parent.name}
              </Link>
            </>
          )}
          <ChevronRight
            style={{
              verticalAlign: 'middle',
              lineHeight: '100%',
              fontSize: '26px'
            }}
          ></ChevronRight>
          <span style={{ color: '#07648D' }}>{organization.name}</span>
        </h1>
        <Subnav
          items={navItems}
          styles={{
            background: '#F9F9F9'
          }}
        ></Subnav>
      </div>
      <div className={classes.root}>
        <Switch>
          <Route
            path="/organizations/:organizationId"
            exact
            render={() => views[0]}
          />
          <Route
            path="/organizations/:organizationId/members"
            render={() => views[1]}
          />
          <Route
            path="/organizations/:organizationId/teams"
            render={() => views[2]}
          />
          <Route
            path="/organizations/:organizationId/scans"
            render={() => views[3]}
          />
        </Switch>
      </div>
    </div>
  );
}
Example #28
Source File: AlertDismissForm.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
AlertDismissForm = forwardRef<
  HTMLFormElement,
  AlertDismissFormProps
>(({ onSubmit, disableSubmit }, ref) => {
  const classes = useStyles();
  const [other, setOther] = useState<Maybe<string>>(null);
  const [feedback, setFeedback] = useState<Maybe<string>>(null);
  const [reason, setReason] = useState<AlertDismissReason>(
    AlertDismissReason.Resolved,
  );

  const onFormSubmit: FormEventHandler = e => {
    e.preventDefault();
    if (reason) {
      onSubmit({
        other: other,
        reason: reason,
        feedback: feedback,
      });
    }
  };

  const onReasonChange = (_: ChangeEvent<HTMLInputElement>, value: string) => {
    if (other) {
      setOther(null);
    }
    setReason(value as AlertDismissReason);
  };

  const onOtherChange = (e: ChangeEvent<HTMLInputElement>) => {
    return e.target.value
      ? setOther(e.target.value as AlertDismissReason)
      : setOther(null);
  };

  const onFeedbackChange = (e: ChangeEvent<HTMLInputElement>) => {
    return e.target.value
      ? setFeedback(e.target.value as AlertDismissReason)
      : setFeedback(null);
  };

  useEffect(() => {
    function validateDismissForm() {
      if (reason === AlertDismissReason.Other) {
        if (other) {
          disableSubmit(false);
        } else {
          disableSubmit(true);
        }
      } else if (reason) {
        disableSubmit(false);
      } else {
        disableSubmit(true);
      }
    }

    validateDismissForm();
  }, [reason, other, disableSubmit]);

  return (
    <form ref={ref} onSubmit={onFormSubmit}>
      <FormControl component="fieldset" fullWidth>
        <Typography color="textPrimary">
          <b>Reason for dismissing?</b>
        </Typography>
        <Box mb={1}>
          <RadioGroup
            name="dismiss-alert-reasons"
            value={reason}
            onChange={onReasonChange}
          >
            {AlertDismissOptions.map(option => (
              <FormControlLabel
                key={`dismiss-alert-option-${option.reason}`}
                label={option.label}
                value={option.reason}
                control={<Radio className={classes.radio} />}
              />
            ))}
          </RadioGroup>
          <Collapse in={reason === AlertDismissReason.Other}>
            <Box ml={4}>
              <TextField
                id="dismiss-alert-option-other"
                variant="outlined"
                multiline
                fullWidth
                rows={4}
                value={other ?? ''}
                onChange={onOtherChange}
              />
            </Box>
          </Collapse>
        </Box>
        <Typography gutterBottom>
          <b>Any other feedback you can provide?</b>
        </Typography>
        <TextField
          id="dismiss-alert-feedback"
          variant="outlined"
          multiline
          rows={4}
          fullWidth
          value={feedback ?? ''}
          onChange={onFeedbackChange}
        />
      </FormControl>
    </form>
  );
})
Example #29
Source File: CardSettings.tsx    From fishbowl with MIT License 4 votes vote down vote up
function CardSettings(props: {
  cardPlayStyle: GameCardPlayStyleEnum
  setCardPlayStyle?: (cardPlayStyle: GameCardPlayStyleEnum) => void
  debouncedSetWordList?: (wordList: string) => void
}) {
  const { t } = useTranslation()
  const currentPlayer = React.useContext(CurrentPlayerContext)
  const currentGame = React.useContext(CurrentGameContext)
  const [wordList, setWordList] = React.useState("")
  const canConfigureSettings = currentPlayer.role === PlayerRole.Host

  const wordListLength = parseWordList(wordList).length

  return (
    <>
      <Grid item>
        <FormControl component="fieldset" disabled={!canConfigureSettings}>
          <RadioGroup
            value={props.cardPlayStyle}
            onChange={({ target: { value } }) => {
              props.setCardPlayStyle &&
                props.setCardPlayStyle(value as GameCardPlayStyleEnum)
            }}
          >
            <FormControlLabel
              value={GameCardPlayStyleEnum.PlayersSubmitWords}
              control={<Radio color="primary"></Radio>}
              label={t(
                "settings.cards.cardStyle.playersSubmit",
                "Players submit words (default)"
              )}
            ></FormControlLabel>
            <FormControlLabel
              value={GameCardPlayStyleEnum.HostProvidesWords}
              control={<Radio color="primary"></Radio>}
              label={t(
                "settings.cards.cardStyle.hostProvides",
                "Host provides words"
              )}
            ></FormControlLabel>
          </RadioGroup>
        </FormControl>
      </Grid>
      {props.cardPlayStyle === GameCardPlayStyleEnum.PlayersSubmitWords && (
        <>
          <Grid item />
          <Grid item>
            <SubmissionsPerPlayerInput
              value={String(currentGame.num_entries_per_player || "")}
            />
          </Grid>
          <Grid item>
            <LetterInput value={currentGame.starting_letter || ""} />
          </Grid>
          <Grid item>
            <ScreenCardsCheckbox value={Boolean(currentGame.screen_cards)} />
          </Grid>
        </>
      )}
      {props.cardPlayStyle === GameCardPlayStyleEnum.HostProvidesWords &&
        canConfigureSettings && (
          <Grid item>
            <TextField
              autoFocus
              value={wordList}
              onChange={({ target: { value } }) => {
                setWordList(value)
                props.debouncedSetWordList && props.debouncedSetWordList(value)
              }}
              fullWidth
              label={t("settings.cards.words.label", "Words")}
              multiline
              rows={5}
              variant="outlined"
              placeholder={t(
                "settings.cards.words.placeholder",
                "Comma separated list of words here..."
              )}
            ></TextField>
            <Box
              display="flex"
              flexDirection="row-reverse"
              pt={0.5}
              color={grey[600]}
            >
              {t("settings.cards.words.helper", "{{ count }} word detected", {
                count: wordListLength,
                defaultValue_plural: "{{ count }} words detected",
              })}
            </Box>
          </Grid>
        )}
    </>
  )
}