@material-ui/core#RadioGroup TypeScript Examples
The following examples show how to use
@material-ui/core#RadioGroup.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: radio_input.tsx From jupyter-extensions with Apache License 2.0 | 6 votes |
/** 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 #2
Source File: LabeledRadio.tsx From UsTaxes with GNU Affero General Public License v3.0 | 6 votes |
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 #3
Source File: TemplateDemoControls.tsx From clearflask with Apache License 2.0 | 6 votes |
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 |
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 |
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 |
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: SQFormRadioButtonGroup.tsx From SQForm with MIT License | 5 votes |
function SQFormRadioButtonGroup({
name,
onChange,
shouldDisplayInRow = false,
size = 'auto',
groupLabel,
children,
}: SQFormRadioButtonGroupProps): React.ReactElement {
const {
fieldState: {isFieldError, isFieldRequired},
formikField: {field},
fieldHelpers: {handleChange, handleBlur, HelperTextComponent},
} = useForm<
RadioButtonInputItemProps['value'],
React.ChangeEvent<HTMLInputElement>
>({
name,
onChange,
});
const childrenToRadioGroupItems = () => {
return children.map((radioOption) => {
const {label, value, isDisabled, InputProps} = radioOption;
return (
<SQFormRadioButtonGroupItem
label={label}
value={value}
isDisabled={isDisabled}
isRowDisplay={shouldDisplayInRow}
InputProps={InputProps}
key={`SQFormRadioButtonGroupItem_${value}`}
/>
);
});
};
return (
<Grid item sm={size}>
<FormControl
component="fieldset"
required={isFieldRequired}
error={isFieldError}
onBlur={handleBlur}
>
<FormLabel
component="legend"
classes={{
root: 'MuiInputLabel-root',
asterisk: 'MuiInputLabel-asterisk',
}}
>
{groupLabel}
</FormLabel>
<RadioGroup
value={field.value}
row={shouldDisplayInRow}
aria-label={`SQFormRadioButtonGroup_${name}`}
name={name}
onChange={handleChange}
>
{childrenToRadioGroupItems()}
</RadioGroup>
<FormHelperText>{HelperTextComponent}</FormHelperText>
</FormControl>
</Grid>
);
}
Example #8
Source File: RiskCriteria.tsx From listo with MIT License | 5 votes |
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 #9
Source File: RadioInput.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
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 #10
Source File: Language.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
StyledRadioGroup = styled(RadioGroup)`
&.MuiFormGroup-root {
display: block;
}
`
Example #11
Source File: VersioningStrategy.tsx From backstage with Apache License 2.0 | 5 votes |
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 #12
Source File: AlertSnoozeForm.tsx From backstage with Apache License 2.0 | 5 votes |
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 #13
Source File: ShippingMethods.tsx From storefront with MIT License | 5 votes |
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 #14
Source File: Organization.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
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 #15
Source File: Users.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
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 #16
Source File: AlertDismissForm.tsx From backstage with Apache License 2.0 | 4 votes |
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 #17
Source File: Settings.tsx From back-home-safe with GNU General Public License v3.0 | 4 votes |
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 #18
Source File: CardSettings.tsx From fishbowl with MIT License | 4 votes |
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>
)}
</>
)
}
Example #19
Source File: InteractiveOptions.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
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 #20
Source File: TemplateOptions.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
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 #21
Source File: CreateGame.tsx From planning-poker with MIT License | 4 votes |
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 #22
Source File: PaymentMethods.tsx From storefront with MIT License | 4 votes |
PaymentMethods: React.VFC<Props> = ({
customer,
onSubmit,
paymentMethod: initialPaymentMethod,
}) => {
const creditCardFormRef = useRef<HTMLFormElement>(null);
const [paymentMethod, setPaymentMethod] = useState(initialPaymentMethod);
const [loading, setLoading] = useState(false);
const { data: { paymentGateways } = { data: undefined }, loading: paymentGatewaysLoading } =
usePaymentGatewaysQuery();
const handleSubmitCreditCard = async (values: CreditCardFormData) => {
setLoading(true);
const data = await makePayment(process.env.BRAINTREE_TOKENIZATION_KEY, {
billingAddress: {
postalCode: customer.billing?.postcode ?? undefined,
},
cvv: values.ccCsc,
expirationDate: values.ccExp,
number: values.ccNumber,
});
setLoading(false);
onSubmit({
creditCard: {
cardType: data.cardType,
lastFour: data.lastFour,
},
paymentMethod,
paymentNonce: data.nonce,
});
};
const handleSubmit = () => {
if (creditCardFormRef.current != null) {
if (creditCardFormRef.current.checkValidity()) {
// The following line is not working anymore for some reason:
// creditCardFormRef.current.dispatchEvent(new Event('submit', { cancelable: true }));
// So I have overridden the `submit` method, see in `CreditCardForm`
creditCardFormRef.current.submit();
} else {
creditCardFormRef.current.reportValidity();
}
}
if (paymentMethod === 'braintree_paypal') {
onSubmit({ paymentMethod });
}
};
const handleChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
setPaymentMethod(ev.target.value);
};
return (
<>
<RadioGroup name="paymentMode" value={paymentMethod} onChange={handleChange}>
{paymentGateways?.nodes?.map(
(paymentGateway) =>
paymentGateway != null && (
<Box
key={paymentGateway.id}
component="label"
htmlFor={`paymentMode-${paymentGateway.id}`}
sx={{
alignItems: 'center',
backgroundColor: 'background.paper',
cursor: 'pointer',
display: 'flex',
mb: 2,
p: 2,
}}
>
<div>
<Radio value={paymentGateway.id} id={`paymentMode-${paymentGateway.id}`} />
</div>
<Box sx={{ flexGrow: 1, ml: 2 }}>
<Typography variant="h5">{paymentGateway.title}</Typography>
{paymentGateway.icon != null ? (
<img src={paymentGateway.icon} alt="" height="24" />
) : (
paymentGateway.id === 'braintree_cc' && (
<>
<SvgIcon component={AmexSvg} viewBox="0 0 30 30" fontSize="large" />{' '}
<SvgIcon component={VisaSvg} viewBox="0 0 30 30" fontSize="large" />
</>
)
)}
{!isBlank(paymentGateway.description) && (
<Typography variant="body2">{paymentGateway.description}</Typography>
)}
{paymentGateway.id === 'braintree_cc' && paymentMethod === paymentGateway.id && (
<CreditCardForm ref={creditCardFormRef} onSubmit={handleSubmitCreditCard} />
)}
</Box>
</Box>
),
)}
</RadioGroup>
<Box sx={{ mt: 2 }}>
<Button
type="submit"
color="primary"
loading={paymentGatewaysLoading || loading}
onClick={handleSubmit}
>
Continue to Review Your Order
</Button>
</Box>
</>
);
}
Example #23
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function Analyser({ extent, classes }: AnalyserProps) {
const dispatch = useDispatch();
const map = useSelector(mapSelector);
const selectedLayers = useSelector(layersSelector);
const {
updateHistory,
removeKeyFromUrl,
resetAnalysisParams,
updateAnalysisParams,
getAnalysisParams,
} = useUrlHistory();
const availableDates = useSelector(availableDatesSelector);
const analysisResult = useSelector(analysisResultSelector);
const isAnalysisLoading = useSelector(isAnalysisLoadingSelector);
const isMapLayerActive = useSelector(isAnalysisLayerActiveSelector);
const {
analysisHazardLayerId: hazardLayerIdFromUrl,
analysisBaselineLayerId: baselineLayerIdFromUrl,
analysisDate: selectedDateFromUrl,
analysisStatistic: selectedStatisticFromUrl,
analysisThresholdAbove: aboveThresholdFromUrl,
analysisThresholdBelow: belowThresholdFromUrl,
analysisAdminLevel: adminLevelFromUrl,
analysisStartDate: selectedStartDateFromUrl,
analysisEndDate: selectedEndDateFromUrl,
} = getAnalysisParams();
// form elements
const [hazardLayerId, setHazardLayerId] = useState<LayerKey | undefined>(
hazardLayerIdFromUrl,
);
const [statistic, setStatistic] = useState(
(selectedStatisticFromUrl as AggregationOperations) ||
AggregationOperations.Mean,
);
const [baselineLayerId, setBaselineLayerId] = useState<LayerKey | undefined>(
baselineLayerIdFromUrl,
);
const [selectedDate, setSelectedDate] = useState<number | null>(null);
const [belowThreshold, setBelowThreshold] = useState(
belowThresholdFromUrl || '',
);
const [aboveThreshold, setAboveThreshold] = useState(
aboveThresholdFromUrl || '',
);
const [thresholdError, setThresholdError] = useState<string | null>(null);
const [isAnalyserFormOpen, setIsAnalyserFormOpen] = useState<boolean>(
hazardLayerIdFromUrl !== undefined,
);
const [isTableViewOpen, setIsTableViewOpen] = useState(true);
// for polygon intersection analysis
const [adminLevel, setAdminLevel] = useState<AdminLevelType>(
Number(adminLevelFromUrl || '1') as AdminLevelType,
);
const [startDate, setStartDate] = useState<number | null>(null);
const [endDate, setEndDate] = useState<number | null>(null);
// find layer for the given adminLevel
const adminLevelLayer = getAdminLevelLayer(adminLevel);
const adminLevelLayerData = useSelector(
// if we couldn't find an admin layer, just return undefined
adminLevelLayer ? layerDataSelector(adminLevelLayer.id) : () => undefined,
) as LayerData<BoundaryLayerProps> | undefined;
// get variables derived from state
const selectedHazardLayer = hazardLayerId
? (LayerDefinitions[hazardLayerId] as WMSLayerProps)
: null;
const hazardDataType: HazardDataType | null = selectedHazardLayer
? selectedHazardLayer.geometry || RasterType.Raster
: null;
const availableHazardDates = selectedHazardLayer
? getPossibleDatesForLayer(selectedHazardLayer, availableDates)?.map(
d => new Date(d),
) || []
: undefined;
const BASELINE_URL_LAYER_KEY = 'baselineLayerId';
const preSelectedBaselineLayer = selectedLayers.find(
l => l.type === 'admin_level_data',
);
const [previousBaselineId, setPreviousBaselineId] = useState<
LayerKey | undefined
>(preSelectedBaselineLayer?.id);
const { t } = useSafeTranslation();
// check if there is any available date from the url, otherwise use last available date for the selected hazard layer
const lastAvailableHazardDate = availableHazardDates
? getDateFromList(
selectedDateFromUrl ? new Date(selectedDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const lastAvailableHazardStartDate = availableHazardDates
? getDateFromList(
selectedStartDateFromUrl ? new Date(selectedStartDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const lastAvailableHazardEndDate = availableHazardDates
? getDateFromList(
selectedEndDateFromUrl ? new Date(selectedEndDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const { translatedColumns } = useAnalysisTableColumns(analysisResult);
// set default date after dates finish loading and when hazard layer changes
useEffect(() => {
if (isNil(lastAvailableHazardDate)) {
setSelectedDate(null);
} else {
setSelectedDate(lastAvailableHazardDate);
}
if (isNil(lastAvailableHazardStartDate)) {
setStartDate(null);
} else {
setStartDate(lastAvailableHazardStartDate);
}
if (isNil(lastAvailableHazardEndDate)) {
setEndDate(null);
} else {
setEndDate(lastAvailableHazardEndDate);
}
}, [
availableDates,
hazardLayerId,
lastAvailableHazardDate,
lastAvailableHazardStartDate,
lastAvailableHazardEndDate,
]);
const onOptionChange = <T extends string>(
setterFunc: Dispatch<SetStateAction<T>>,
) => (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value as T;
setterFunc(value);
return value;
};
// specially for threshold values, also does error checking
const onThresholdOptionChange = (thresholdType: 'above' | 'below') => (
event: React.ChangeEvent<HTMLInputElement>,
) => {
const setterFunc =
thresholdType === 'above' ? setAboveThreshold : setBelowThreshold;
const changedOption = onOptionChange(setterFunc)(event);
// setting a value doesn't update the existing value until next render, therefore we must decide whether to access the old one or the newly change one here.
const aboveThresholdValue = parseFloat(
thresholdType === 'above' ? changedOption : aboveThreshold,
);
const belowThresholdValue = parseFloat(
thresholdType === 'below' ? changedOption : belowThreshold,
);
if (belowThresholdValue > aboveThresholdValue) {
setThresholdError('Below threshold is larger than above threshold!');
} else {
setThresholdError(null);
}
};
const statisticOptions = Object.entries(AggregationOperations)
.filter(([, value]) => value !== AggregationOperations.Sum) // sum is used only for exposure analysis.
.map(([key, value]) => (
<FormControlLabel
key={key}
value={value}
control={
<Radio
className={classes.radioOptions}
color="default"
size="small"
/>
}
label={t(key)}
/>
));
const activateUniqueBoundary = (forceAdminLevel?: BoundaryLayerProps) => {
if (forceAdminLevel) {
// remove displayed boundaries
getDisplayBoundaryLayers().forEach(l => {
if (l.id !== forceAdminLevel.id) {
safeDispatchRemoveLayer(map, l, dispatch);
}
});
safeDispatchAddLayer(
map,
{ ...forceAdminLevel, isPrimary: true },
dispatch,
);
return;
}
if (!baselineLayerId) {
throw new Error('Layer should be selected to run analysis');
}
const baselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
if (baselineLayer.boundary) {
const boundaryLayer = LayerDefinitions[
baselineLayer.boundary
] as BoundaryLayerProps;
// remove displayed boundaries
getDisplayBoundaryLayers().forEach(l => {
if (l.id !== boundaryLayer.id) {
safeDispatchRemoveLayer(map, l, dispatch);
}
});
safeDispatchAddLayer(
map,
{ ...boundaryLayer, isPrimary: true },
dispatch,
);
} else {
getDisplayBoundaryLayers().forEach(l => {
safeDispatchAddLayer(map, l, dispatch);
});
}
};
const deactivateUniqueBoundary = () => {
if (!baselineLayerId) {
throw new Error('Layer should be selected to run analysis');
}
const baselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
if (baselineLayer.boundary) {
const boundaryLayer = LayerDefinitions[
baselineLayer.boundary
] as BoundaryLayerProps;
if (!getDisplayBoundaryLayers().includes(boundaryLayer)) {
safeDispatchRemoveLayer(map, boundaryLayer, dispatch);
}
}
getDisplayBoundaryLayers().forEach(l => {
safeDispatchAddLayer(map, l, dispatch);
});
};
const clearAnalysis = () => {
dispatch(clearAnalysisResult());
resetAnalysisParams();
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
updateHistory(BASELINE_URL_LAYER_KEY, previousBaselineId);
safeDispatchAddLayer(map, previousBaseline, dispatch);
// check isMapLayerActive on analysis clear
// to avoid miss behaviour on boundary layers
dispatch(setIsMapLayerActive(true));
}
};
const shareAnalysis = () => {
copyTextToClipboard(window.location.href).then(() => {
dispatch(
addNotification({
message: 'Link to this analysis copied to clipboard!',
type: 'success',
}),
);
});
};
const onMapSwitchChange = (e: ChangeEvent<HTMLInputElement>) => {
dispatch(setIsMapLayerActive(e.target.checked));
// hazard layer doesn't needs a display boundary
// because it is already a vector
if (hazardDataType === GeometryType.Polygon) {
return;
}
if (isMapLayerActive) {
deactivateUniqueBoundary();
// check for previous baseline and bring it back
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
updateHistory(BASELINE_URL_LAYER_KEY, previousBaselineId);
safeDispatchAddLayer(map, previousBaseline, dispatch);
}
} else {
// check for previous baseline and remove it before...
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
removeKeyFromUrl(BASELINE_URL_LAYER_KEY);
safeDispatchRemoveLayer(map, previousBaseline, dispatch);
}
// activating the unique boundary layer
activateUniqueBoundary();
}
};
const runAnalyser = async () => {
if (preSelectedBaselineLayer) {
setPreviousBaselineId(preSelectedBaselineLayer.id);
removeKeyFromUrl(BASELINE_URL_LAYER_KEY);
// no need to safely dispatch remove we are sure
dispatch(removeLayer(preSelectedBaselineLayer));
}
if (analysisResult) {
clearAnalysis();
}
if (!extent) {
return;
} // hasn't been calculated yet
if (!selectedHazardLayer) {
throw new Error('Hazard layer should be selected to run analysis');
}
if (hazardDataType === GeometryType.Polygon) {
if (!startDate) {
throw new Error('Date Range must be given to run analysis');
}
if (!endDate) {
throw new Error('Date Range must be given to run analysis');
}
if (!adminLevelLayer || !adminLevelLayerData) {
// technically we can't get here because the run analaysis button
// is disabled while the admin level data loads
// but we have to put this in so the typescript compiler
// doesn't throw an error when we try to access the data
// property of adminLevelLayerData
throw new Error('Admin level data is still loading');
}
const params: PolygonAnalysisDispatchParams = {
hazardLayer: selectedHazardLayer,
adminLevel,
adminLevelLayer,
adminLevelData: adminLevelLayerData.data,
startDate,
endDate,
extent,
};
activateUniqueBoundary(adminLevelLayer);
// update history
updateAnalysisParams({
analysisHazardLayerId: hazardLayerId,
analysisAdminLevel: adminLevel.toString(),
analysisStartDate: moment(startDate).format(DEFAULT_DATE_FORMAT),
analysisEndDate: moment(endDate).format(DEFAULT_DATE_FORMAT),
analysisStatistic: statistic,
});
dispatch(requestAndStorePolygonAnalysis(params));
} else {
if (!selectedDate) {
throw new Error('Date must be given to run analysis');
}
if (!baselineLayerId) {
throw new Error('Baseline layer should be selected to run analysis');
}
const selectedBaselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
activateUniqueBoundary();
const params: AnalysisDispatchParams = {
hazardLayer: selectedHazardLayer,
baselineLayer: selectedBaselineLayer,
date: selectedDate,
statistic,
extent,
threshold: {
above: parseFloat(aboveThreshold) || undefined,
below: parseFloat(belowThreshold) || undefined,
},
};
// update history
updateAnalysisParams({
analysisHazardLayerId: hazardLayerId,
analysisBaselineLayerId: baselineLayerId,
analysisDate: moment(selectedDate).format(DEFAULT_DATE_FORMAT),
analysisStatistic: statistic,
analysisThresholdAbove: aboveThreshold || undefined,
analysisThresholdBelow: belowThreshold || undefined,
});
dispatch(requestAndStoreAnalysis(params));
}
};
return (
<div className={classes.analyser}>
<Button
variant="contained"
color="primary"
onClick={() => {
setIsAnalyserFormOpen(!isAnalyserFormOpen);
}}
>
<BarChart fontSize="small" />
<Typography variant="body2" className={classes.analyserLabel}>
{t('Run Analysis')}
</Typography>
<ArrowDropDown fontSize="small" />
</Button>
<Box
className={classes.analyserMenu}
width={isAnalyserFormOpen ? 'min-content' : 0}
padding={isAnalyserFormOpen ? '10px' : 0}
>
{isAnalyserFormOpen ? (
<div>
<div className={classes.newAnalyserContainer}>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Hazard Layer')}</Typography>
<LayerDropdown
type="wms"
value={hazardLayerId}
setValue={setHazardLayerId}
className={classes.selector}
placeholder="Choose hazard layer"
/>
</div>
{hazardDataType === GeometryType.Polygon && (
<>
<div className={classes.analyserOptions}>
<Typography variant="body2">Admin Level</Typography>
<SimpleDropdown
value={adminLevel}
options={range(getAdminLevelCount()).map(i => [
(i + 1) as AdminLevelType,
`Admin ${i + 1}`,
])}
onChange={setAdminLevel}
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Date Range')}</Typography>
<div className={classes.dateRangePicker}>
<Typography variant="body2">{t('Start')}</Typography>
<DatePicker
selected={startDate ? new Date(startDate) : null}
onChange={date =>
setStartDate(date?.getTime() || startDate)
}
maxDate={new Date()}
todayButton="Today"
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
<div className={classes.dateRangePicker}>
<Typography variant="body2">{t('End')}</Typography>
<DatePicker
selected={endDate ? new Date(endDate) : null}
onChange={date =>
setEndDate(date?.getTime() || endDate)
}
maxDate={new Date()}
todayButton="Today"
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
</div>
</>
)}
{hazardDataType === RasterType.Raster && (
<>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Statistic')}</Typography>
<FormControl component="div">
<RadioGroup
name="statistics"
value={statistic}
onChange={onOptionChange(setStatistic)}
row
>
{statisticOptions}
</RadioGroup>
</FormControl>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">
{t('Baseline Layer')}
</Typography>
<LayerDropdown
type="admin_level_data"
value={baselineLayerId || undefined}
setValue={setBaselineLayerId}
className={classes.selector}
placeholder="Choose baseline layer"
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Threshold')}</Typography>
<TextField
id="filled-number"
error={!!thresholdError}
helperText={thresholdError}
className={classes.numberField}
label={t('Below')}
type="number"
value={belowThreshold}
onChange={onThresholdOptionChange('below')}
variant="filled"
/>
<TextField
id="filled-number"
label={t('Above')}
className={classes.numberField}
value={aboveThreshold}
onChange={onThresholdOptionChange('above')}
type="number"
variant="filled"
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Date')}</Typography>
<DatePicker
locale={t('date_locale')}
dateFormat="PP"
selected={selectedDate ? new Date(selectedDate) : null}
onChange={date =>
setSelectedDate(date?.getTime() || selectedDate)
}
maxDate={new Date()}
todayButton={t('Today')}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
</>
)}
</div>
{!isAnalysisLoading &&
analysisResult &&
(analysisResult instanceof BaselineLayerResult ||
analysisResult instanceof PolygonAnalysisResult) && (
<>
<FormGroup>
<FormControlLabel
control={
<Switch
color="default"
checked={isMapLayerActive}
onChange={onMapSwitchChange}
/>
}
label={t('Map View')}
/>
<FormControlLabel
control={
<Switch
color="default"
checked={isTableViewOpen}
onChange={e => setIsTableViewOpen(e.target.checked)}
/>
}
label={t('Table View')}
/>
</FormGroup>
{isTableViewOpen && (
<AnalysisTable
tableData={analysisResult.tableData}
columns={translatedColumns}
/>
)}
<Button
className={classes.innerAnalysisButton}
onClick={() =>
downloadCSVFromTableData(
analysisResult,
translatedColumns,
selectedDate,
)
}
>
<Typography variant="body2">{t('Download')}</Typography>
</Button>
<Button
className={classes.innerAnalysisButton}
onClick={clearAnalysis}
>
<Typography variant="body2">
{t('Clear Analysis')}
</Typography>
</Button>
<Button
className={classes.innerAnalysisButton}
onClick={shareAnalysis}
>
<Typography variant="body2">
{t('Share Analysis')}
</Typography>
</Button>
</>
)}
{(!analysisResult ||
analysisResult instanceof ExposedPopulationResult) && (
<Button
className={classes.innerAnalysisButton}
onClick={runAnalyser}
disabled={
!!thresholdError || // if there is a threshold error
isAnalysisLoading || // or analysis is currently loading
!hazardLayerId || // or hazard layer hasn't been selected
(hazardDataType === GeometryType.Polygon
? !startDate || !endDate || !adminLevelLayerData
: !selectedDate || !baselineLayerId) // or date hasn't been selected // or baseline layer hasn't been selected
}
>
<Typography variant="body2">{t('Run Analysis')}</Typography>
</Button>
)}
{isAnalysisLoading ? <LinearProgress /> : null}
</div>
) : null}
</Box>
</div>
);
}