@mui/material#FormControl TypeScript Examples
The following examples show how to use
@mui/material#FormControl.
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: OptionsCheck.tsx From ui-schema with MIT License | 6 votes |
OptionsCheck: React.ComponentType<WidgetProps<MuiWidgetBinding> & OptionsCheckRendererProps> = (
{
schema, storeKeys, showValidity, valid, required, errors,
row, widgets,
}
) => {
const oneOfVal = schema.getIn(['items', 'oneOf'])
if (!oneOfVal) return null
const InfoRenderer = widgets?.InfoRenderer
return <FormControl
required={required} error={!valid && showValidity} component="fieldset" fullWidth
size={schema.getIn(['view', 'dense']) ? 'small' : undefined}
disabled={schema.get('readOnly') as boolean}
>
<FormLabel component="legend" style={{width: '100%'}}>
<TransTitle schema={schema} storeKeys={storeKeys}/>
{InfoRenderer && schema?.get('info') ?
<InfoRenderer
schema={schema} variant={'icon'} openAs={'modal'}
storeKeys={storeKeys} valid={valid} errors={errors}
align={'right'} dense
/> :
undefined}
</FormLabel>
<FormGroup row={row}>
<OptionsCheckValue
oneOfValues={oneOfVal as List<OrderedMap<string, string>>} storeKeys={storeKeys}
required={required} schema={schema}
disabled={schema.get('readOnly') as boolean}
/>
</FormGroup>
<ValidityHelperText errors={errors} showValidity={showValidity} schema={schema}/>
</FormControl>
}
Example #2
Source File: RadioGroup.tsx From Cromwell with MIT License | 6 votes |
/** @internal */
export function RadioGroup(props: TRadioProps) {
return (
<FormControl component="fieldset"
className={props.className}
style={props.style}
id={props.id}
>
<MuiRadioGroup
value={props.value}
onChange={props.onChange}
name={props.name}
>
{props.options?.map(option => {
const value = typeof option === 'object' ? option.value : option;
if (!value) return <></>;
const label = (typeof option === 'object' ? option.label : option) ?? value;
return (
<FormControlLabel
key={value}
value={value}
control={<Radio color="primary" />}
label={label}
/>
)
})}
</MuiRadioGroup>
</FormControl>
)
}
Example #3
Source File: BlockEditor.tsx From NekoMaid with MIT License | 6 votes |
BlockSelector: React.FC<{ worlds: string[] }> = ({ worlds }) => {
const his = useHistory()
const [world, setWorld] = useState(worlds[0])
const [x, setX] = useState('0')
const [y, setY] = useState('0')
const [z, setZ] = useState('0')
return <Grid container>
<Grid item xs={6}>
<FormControl variant='standard' fullWidth>
<InputLabel id='nekomaid-block-editor-world'>{lang.world}</InputLabel>
<Select
labelId='nekomaid-block-editor-world'
value={world}
label={lang.world}
onChange={e => setWorld(e.target.value)}
>
{worlds.map(it => <MenuItem key={it} value={it}>{it}</MenuItem>)}
</Select>
</FormControl>
</Grid>
<Grid item xs={2}><TextField variant='standard' label='X' type='number' fullWidth value={x} onChange={e => setX(e.target.value)} /></Grid>
<Grid item xs={2}><TextField variant='standard' label='Y' type='number' fullWidth value={y} onChange={e => setY(e.target.value)} /></Grid>
<Grid item xs={2}><TextField variant='standard' label='Z' type='number' fullWidth value={z} onChange={e => setZ(e.target.value)} /></Grid>
<Grid item xs={12} sx={{ marginTop: 3, textAlign: 'center' }}>
<Button
variant='contained'
onClick={() => his.push(`/NekoMaid/block/${world}/${parseFloat(x) | 0}/${parseFloat(y) | 0}/${parseFloat(z) | 0}`)}
>{minecraft['gui.done']}</Button>
</Grid>
</Grid>
}
Example #4
Source File: CampaignTypeSelect.tsx From frontend with MIT License | 6 votes |
export default function CampaignTypeSelect({ name = 'campaignTypeId' }) {
const { t } = useTranslation()
const { data } = useCampaignTypesList()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
size="small"
variant="outlined"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<InputLabel>{t('campaigns:campaign.type')}</InputLabel>
<Select fullWidth defaultValue="" label={t('campaigns:campaign.type')} {...field}>
<MenuItem value="" disabled>
{t('campaigns:campaign.type')}
</MenuItem>
{data?.map((campaignType, index) => (
<MenuItem key={index} value={campaignType.id}>
{campaignType.name}
</MenuItem>
))}
</Select>
{helperText && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #5
Source File: Select.tsx From Cromwell with MIT License | 6 votes |
/** @internal */
export function Select(props: TSelectProps & MuiSelectProps<string | number>) {
const { className, style, variant = 'filled' } = props;
return (
<FormControl
fullWidth={props.fullWidth}
style={props.style}
className={props.className}
>
{props.label && (
<InputLabel style={{
marginTop: '8px',
}}>{props.label}</InputLabel>
)}
<MuiSelect
{...props}
variant={variant}
className={className}
style={style}
>
{props.options?.map((option) => {
const label = typeof option === 'object' ? option.label : option;
const value = typeof option === 'object' ? option.value : option;
return (
<MenuItem value={value} key={value + ''}>{label}</MenuItem>
)
})}
</MuiSelect>
</FormControl>
)
}
Example #6
Source File: SelectCoordinator.tsx From frontend with MIT License | 6 votes |
export default function SelectCoordinator({ name = 'coordinatorId' }) {
const { t } = useTranslation()
const [field] = useField(name)
const { data: personList } = usePersonList()
const { data: coordinatorList } = useCoordinatorsList()
return (
<FormControl fullWidth>
<InputLabel>Избери</InputLabel>
<Select fullWidth defaultValue="" label={t('campaigns:campaign.type')} {...field}>
{personList
?.filter((person) => {
return !coordinatorList?.find((c) => c.personId === person.id)
})
?.map((person) => {
return (
<MenuItem key={person.id} value={person.id}>
{person.firstName} {person.lastName}
</MenuItem>
)
})}
</Select>
</FormControl>
)
}
Example #7
Source File: Importer.tsx From your_spotify with GNU General Public License v3.0 | 5 votes |
export default function Importer() {
const dispatch = useAppDispatch();
const imports = useSelector(selectImportStates);
const [importType, setImportType] = useState<ImporterStateTypes>(ImporterStateTypes.privacy);
const fetch = useCallback(
async (force = false) => {
dispatch(getImports(force));
},
[dispatch],
);
useEffect(() => {
fetch();
}, [fetch]);
const running = useMemo(() => imports?.find((st) => st.status === 'progress'), [imports]);
const Component = useMemo(
() => (importType ? ImportTypeToComponent[importType] : null),
[importType],
);
if (!imports) {
return <CircularProgress />;
}
return (
<div>
<div>
{running && (
<div>
<Text>Importing...</Text>
<div className={s.progress}>
<Text>
{running.current} / {running.total}
</Text>
</div>
<LinearProgress
style={{ width: '100%' }}
variant="determinate"
value={(running.current / running.total) * 100}
/>
</div>
)}
</div>
{!running && (
<div>
<FormControl className={s.selectimport}>
<InputLabel id="import-type-select">Import type</InputLabel>
<Select
labelId="import-type-select"
value={importType}
label="Import type"
onChange={(ev) => setImportType(ev.target.value as ImporterStateTypes)}>
{Object.values(ImporterStateTypes).map((typ) => (
<MenuItem value={typ} key={typ}>
{typ}
</MenuItem>
))}
</Select>
</FormControl>
{Component && <Component />}
</div>
)}
{imports.length > 0 && <ImportHistory />}
</div>
);
}
Example #8
Source File: TextFilter.tsx From Tachidesk-WebUI with Mozilla Public License 2.0 | 5 votes |
export default function TextFilter(props: Props) {
const {
state,
name,
position,
group,
updateFilterValue,
update,
} = props;
const [Search, setsearch] = React.useState(state || '');
let typingTimer: NodeJS.Timeout;
function doneTyping(e: React.ChangeEvent<HTMLInputElement>) {
const upd = update.filter((el: {
position: number; group: number | undefined;
}) => !(position === el.position && group === el.group));
updateFilterValue([...upd, { position, state: e.target.value, group }]);
}
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setsearch(e.target.value);
clearTimeout(typingTimer);
typingTimer = setTimeout(() => { doneTyping(e); }, 2500);
}
if (state !== undefined) {
return (
<Box key={`${name}`} sx={{ display: 'flex', flexDirection: 'row', minWidth: 120 }}>
<>
<SearchIcon
sx={{
margin: 'auto',
}}
/>
<FormControl fullWidth>
<InputLabel sx={{ margin: '10px 0 10px 0' }}>
{name}
</InputLabel>
<Input
name={name}
value={Search || ''}
onChange={handleChange}
sx={{ margin: '10px 0 10px 0' }}
/>
</FormControl>
</>
</Box>
);
}
return (<></>);
}
Example #9
Source File: CustomShapedArrayField.tsx From firecms with MIT License | 5 votes |
export default function CustomShapedArrayField({
property,
name,
value,
setValue,
customProps,
touched,
error,
isSubmitting,
showError,
includeDescription,
context,
...props
}: FieldProps<any[], CustomShapedArrayProps>)
: ReactElement {
const properties = customProps.properties;
return (
<FormControl fullWidth error={showError}>
<FormHelperText>{property.title ?? name}</FormHelperText>
<Paper variant={"outlined"}>
<Box m={2}>
{properties.map((property, index) =>
<div key={`array_${index}`}>
{buildPropertyField({
name: `${name}[${index}]`,
property,
context
})}
</div>
)}
</Box>
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
{showError
&& typeof error === "string"
&& <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #10
Source File: CategorySelect.tsx From mojito_pdm with Creative Commons Attribution Share Alike 4.0 International | 5 votes |
CategorySelect: React.FC = () => {
const theme = useTheme()
const [category, setCategory] = useRecoilState(CarState.categorySearch)
const handleChange = (event: SelectChangeEvent) => {
setCategory(event.target.value)
};
return (
<>
<div>
<FormControl variant="outlined" sx={{margin: theme.spacing(1), minWidth: 240}} color="error">
<InputLabel sx={{color: "white"}}>Category</InputLabel>
<Select sx={{color: "white"}}
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={category}
onChange={handleChange}
label="Category"
>
<MenuItem value="">
<em>All</em>
</MenuItem>
<MenuItem value={"Sports"}>Sports</MenuItem>
<MenuItem value={"Compacts"}>Compacts</MenuItem>
<MenuItem value={"Muscle"}>Muscle</MenuItem>
<MenuItem value={"Sedan"}>Sedan</MenuItem>
<MenuItem value={"Coupe"}>Coupé</MenuItem>
<MenuItem value={"Super"}>Super</MenuItem>
<MenuItem value={"SUV"}>SUV</MenuItem>
<MenuItem value={"Vans"}>Vans</MenuItem>
<MenuItem value={"Offroad"}>Offroad</MenuItem>
<MenuItem value={"Sports Classics"}>Sports Classics</MenuItem>
<MenuItem value={"Motorcycles"}>Motorcycles</MenuItem>
</Select>
</FormControl>
</div>
</>
)
}
Example #11
Source File: MultiSelect.tsx From multi-downloader-nx with MIT License | 5 votes |
MultiSelect: React.FC<MultiSelectProps> = (props) => {
const theme = useTheme();
return <div>
<FormControl sx={{ m: 1, width: 300 }}>
<InputLabel id="multi-select-label">{props.title}</InputLabel>
<Select
labelId="multi-select-label"
id="multi-select"
multiple
value={(props.selected ?? [])}
onChange={e => {
const val = typeof e.target.value === "string" ? e.target.value.split(",") : e.target.value;
if (props.allOption && val.includes('all')) {
if (props.values.length === val.length - 1)
props.onChange([]);
else
props.onChange(props.values);
} else {
props.onChange(val);
}
}}
input={<OutlinedInput id="select-multiple-chip" label={props.title} />}
renderValue={(selected) => (
selected.join(', ')
)}
MenuProps={MenuProps}
>
{props.values.concat(props.allOption ? 'all' : []).map((name) => (
<MenuItem
key={`${props.title}_${name}`}
value={name}
style={getStyles(name, props.selected, theme)}
>
{name}
</MenuItem>
))}
</Select>
</FormControl>
</div>
}
Example #12
Source File: CheckboxElement.tsx From react-hook-form-mui with MIT License | 5 votes |
export default function CheckboxElement({
name,
validation = {},
required,
parseError,
label,
control,
...rest
}: CheckboxElementProps): JSX.Element {
if (required) {
validation.required = 'This field is required'
}
return (
<Controller
name={name}
rules={validation}
control={control}
render={({ field: { value, onChange }, fieldState: { invalid, error } }) => {
const helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : rest.helperText
return (
<FormControl required={required} error={invalid}>
<FormGroup row>
<FormControlLabel
label={label || ''}
control={
<Checkbox
color={'primary'}
sx={{
color: invalid ? "error.main" : undefined,
}}
value={value}
checked={!!value}
onChange={() => {
onChange(!value)
//setValue(name, !formValue, { shouldValidate: true })
}}
/>
}
/>
</FormGroup>
{helperText && <FormHelperText error={invalid}>{helperText}</FormHelperText>}
</FormControl>
)
}}
/>
)
}
Example #13
Source File: AutocompleteWrapper.tsx From console with GNU Affero General Public License v3.0 | 5 votes |
AutocompleteWrapper = ({
classes,
id,
name,
onChange,
options,
label,
tooltip = "",
value,
disabled = false,
}: SelectProps) => {
const [internalValue, setInternalValue] = useState<selectorTypes>(options[0]);
const executeOnSelect = (_: any, selectedValue: any) => {
if (selectedValue) {
onChange(selectedValue.value);
setInternalValue(selectedValue);
}
};
return (
<React.Fragment>
<Grid item xs={12} className={classes.fieldContainer}>
{label !== "" && (
<InputLabel htmlFor={id} className={classes.inputLabel}>
<span>{label}</span>
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>
)}
</InputLabel>
)}
<FormControl fullWidth>
<Autocomplete
id={id}
options={options}
getOptionLabel={(option) => option.label}
isOptionEqualToValue={(option) => option.value === value}
disabled={disabled}
renderInput={(params) => <InputField {...params} name={name} />}
value={internalValue}
onChange={executeOnSelect}
autoHighlight
/>
</FormControl>
</Grid>
</React.Fragment>
);
}
Example #14
Source File: CircleCheckboxField.tsx From frontend with MIT License | 5 votes |
export default function CircleCheckboxField({ name, label, labelProps }: CircleCheckboxField) {
const { t } = useTranslation('one-time-donation')
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl required component="fieldset" error={Boolean(meta.error) && Boolean(meta.touched)}>
<FormControlLabel
sx={
field.checked
? {
background: lighten(theme.palette.primary.main, 0.8),
border: `1px solid ${theme.borders.light}`,
}
: undefined
}
label={<Typography sx={{ fontWeight: 'bold', ml: 1 }}>{label}</Typography>}
control={
<Checkbox
icon={
<Icon
sx={(theme) => ({
width: 30,
height: 30,
border: `1px solid ${theme.palette.primary.dark}`,
// @ts-expect-error theme doesn't include overrides
borderRadius: theme.borders.round,
})}
/>
}
checkedIcon={
<CheckIcon
sx={(theme) => ({
width: 30,
height: 30,
border: `1px solid ${theme.palette.primary.main}`,
backgroundColor: theme.palette.primary.main,
// @ts-expect-error theme doesn't include overrides
borderRadius: theme.borders.round,
color: '#fff',
})}
/>
}
checked={Boolean(field.value)}
{...field}
/>
}
{...labelProps}
/>
{Boolean(meta.error) && (
<FormHelperText error>{helperText ? t(helperText) : 'General Error'}</FormHelperText>
)}
</FormControl>
)
}
Example #15
Source File: index.tsx From ExpressLRS-Configurator with GNU General Public License v3.0 | 5 votes |
FlashingMethodOptions: FunctionComponent<FlashingMethodsListProps> = (
props
) => {
const { onChange, currentTarget, currentDevice, firmwareVersionData } = props;
const targetMappingsSorted = useMemo(
() => sortDeviceTargets(currentDevice?.targets ?? []),
[currentDevice?.targets]
);
const onFlashingMethodChange = (
_event: React.ChangeEvent<HTMLInputElement>,
value: string
) => {
const target = targetMappingsSorted?.find((item) => {
return item.id === value;
});
onChange(target ?? null);
};
const flashingMethodRadioOption = useCallback(
(targetMapping: Target) => {
const label = (
<>
{!targetMapping.flashingMethod
? targetMapping.name
: targetMapping.flashingMethod}
{targetMapping.flashingMethod !== null && (
<FlashingMethodDescription
flashingMethod={targetMapping.flashingMethod}
deviceWikiUrl={currentDevice?.wikiUrl ?? null}
firmwareVersionData={firmwareVersionData}
/>
)}
</>
);
return (
<FormControlLabel
key={targetMapping.id}
value={targetMapping.id}
sx={styles.radioControl}
control={<Radio sx={styles.radio} color="primary" />}
label={label}
/>
);
},
[currentDevice?.wikiUrl, firmwareVersionData]
);
return (
<Box sx={styles.root}>
<Typography variant="h6" sx={styles.categoryTitle}>
Flashing Method
</Typography>
<FormControl component="fieldset" sx={styles.flashingMethods}>
<RadioGroup
row
value={currentTarget?.id ?? null}
onChange={onFlashingMethodChange}
defaultValue="top"
>
{targetMappingsSorted?.map((item) => {
return flashingMethodRadioOption(item);
})}
</RadioGroup>
</FormControl>
</Box>
);
}
Example #16
Source File: SubPropertyField.tsx From firecms with MIT License | 5 votes |
CustomField = ({
property,
value,
name,
tableMode,
error,
showError,
includeDescription,
context,
setValue,
}: FieldProps<object>) => {
useEffect(() => {
if (!value) setValue({});
}, [value, setValue]);
return (
<FormControl fullWidth error={showError}>
{!tableMode && (
<FormHelperText filled required={property.validation?.required}>
<LabelWithIcon property={property} />
</FormHelperText>
)}
<Paper elevation={0}>
{buildPropertyField({
name: `${name}.sample`,
property: {
title: "Sample",
dataType: "string",
validation: {
required: true,
},
},
context,
})}
</Paper>
{includeDescription && <FieldDescription property={property} />}
{showError && typeof error === "string" && (
<FormHelperText>{error}</FormHelperText>
)}
</FormControl>
);
}
Example #17
Source File: Sort.tsx From Cromwell with MIT License | 5 votes |
export default function Sort<TEntity>(props: {
options: TSortOption<TEntity>[];
onChange: (key: keyof TEntity, order: 'ASC' | 'DESC') => any;
}) {
const [orderByKey, setOrderByKey] = useState<keyof TEntity | null>(null);
const [order, setOrder] = useState<'ASC' | 'DESC'>('DESC');
const handleChangeOrderByKey = (key: keyof TEntity) => {
setOrderByKey(key);
props.onChange(key, order);
}
const toggleOrder = () => {
setOrder(prev => {
const newOrder = prev === 'ASC' ? 'DESC' : 'ASC';
props.onChange(orderByKey, newOrder);
return newOrder;
});
}
return (
<FormControl className={styles.wrapper}>
<InputLabel>Sort</InputLabel>
<Select
style={{ minWidth: '60px', maxWidth: '100px' }}
size="small"
value={orderByKey ?? 'id'}
label="Sort"
onChange={event => handleChangeOrderByKey(event.target.value as any)}
classes={{
icon: styles.selectIcon,
select: styles.muiSelect,
}}
>
{props.options.map(sort => (
<MenuItem key={sort.key + ''} value={sort.key + ''}>{sort.label}</MenuItem>
))}
</Select>
<div onClick={toggleOrder} className={styles.orderButton}>
<ArrowDropDownIcon
style={{
transform: order === 'ASC' ? 'rotate(180deg)' : undefined,
transition: '0.3s',
}}
/>
</div>
</FormControl>
)
}
Example #18
Source File: ReferenceField.tsx From firecms with MIT License | 4 votes |
/**
* Field that opens a reference selection dialog.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ReferenceField<M extends { [Key: string]: any }>({
name,
value,
setValue,
error,
showError,
disabled,
touched,
autoFocus,
property,
includeDescription,
context,
shouldAlwaysRerender
}: FieldProps<EntityReference>) {
if (typeof property.path !== "string") {
throw Error("Picked the wrong component ReferenceField");
}
useClearRestoreValue({
property,
value,
setValue
});
const classes = useStyles();
const [open, setOpen] = React.useState(autoFocus);
const sideEntityController = useSideEntityController();
const navigationContext = useNavigation();
const collectionResolver: EntityCollectionResolver | undefined = useMemo(() => {
return navigationContext.getCollectionResolver(property.path as string);
}, [property.path, navigationContext]);
if (!collectionResolver) {
throw Error(`Couldn't find the corresponding collection for the path: ${property.path}`);
}
const schemaResolver = collectionResolver.schemaResolver;
const path = property.path;
const validValue = value && value instanceof EntityReference;
const {
entity,
dataLoading,
dataLoadingError
} = useEntityFetch({
path: validValue ? value.path : undefined,
entityId: validValue ? value.id : undefined,
schema: schemaResolver,
useCache: true
});
const handleEntityClick = (entity: Entity<M>) => {
if (disabled)
return;
setValue(entity ? getReferenceFrom(entity) : null);
setOpen(false);
};
const handleClickOpen = () => {
setOpen(true);
};
const clearValue = (e: React.MouseEvent) => {
e.stopPropagation();
setValue(null);
setOpen(false);
};
const seeEntityDetails = (e: React.MouseEvent) => {
e.stopPropagation();
if (entity)
sideEntityController.open({
entityId: entity.id,
path,
overrideSchemaRegistry: false
});
};
const onClose = () => {
setOpen(false);
};
function buildEntityView(schemaResolver?: EntitySchemaResolver) {
const missingEntity = entity && !entity.values;
let body: JSX.Element;
if (!schemaResolver) {
body = (
<ErrorView
error={"The specified collection does not exist. Check console"}/>
);
} else if (missingEntity) {
body = (
<Tooltip title={value && value.path}>
<Box
display={"flex"}
alignItems={"center"}
p={1}
flexGrow={1}>
<ErrorIcon fontSize={"small"} color={"error"}/>
<Box marginLeft={1}>Missing
reference {entity && entity.id}</Box>
</Box>
</Tooltip>
);
} else {
if (validValue) {
const schema = schemaResolver({});
const allProperties = Object.keys(schema.properties);
let listProperties = property.previewProperties?.filter(p => allProperties.includes(p as string));
if (!listProperties || !listProperties.length) {
listProperties = allProperties;
}
listProperties = listProperties.slice(0, 3);
body = (
<Box display={"flex"}
flexDirection={"column"}
flexGrow={1}
ml={1}
mr={1}>
{listProperties && listProperties.map((key, index) => {
const property = schema.properties[key as string];
if (!property) return null;
return (
<Box
key={`reference_previews_${key as string}`}
mt={0.5}
mb={0.5}>
<ErrorBoundary>{
entity
? <PreviewComponent
name={key as string}
value={(entity.values as any)[key]}
property={property as AnyProperty}
size={"tiny"}/>
: <SkeletonComponent
property={property as AnyProperty}
size={"tiny"}/>}
</ErrorBoundary>
</Box>
);
})}
</Box>
);
} else {
body = <Box p={1}
onClick={disabled ? undefined : handleClickOpen}
justifyContent="center"
display="flex">
<Typography variant={"body2"} sx={(theme) => ({
flexGrow: 1,
textAlign: "center",
color: "#838383",
fontWeight: theme.typography.fontWeightMedium
})}>No value set</Typography>
{!disabled && <Button variant="outlined"
color="primary">
Set
</Button>}
</Box>;
}
}
return (
<Box
onClick={disabled ? undefined : handleClickOpen}
display="flex">
<Box display={"flex"}
flexDirection={"column"}
flexGrow={1}>
<Box display={"flex"}
flexDirection={"row"}
flexGrow={1}>
<Box flexGrow={1}>
<FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon
property={property}/>
</FormHelperText>
</Box>
{entity &&
<Box
alignSelf={"center"}
m={1}>
<Tooltip title={value && value.path}>
<Typography variant={"caption"}
className={"mono"}>
{entity.id}
</Typography>
</Tooltip>
</Box>}
{!missingEntity && entity && value && <Box>
<Tooltip title={`See details for ${entity.id}`}>
<span>
<IconButton
onClick={seeEntityDetails}
size="large">
<KeyboardTabIcon/>
</IconButton>
</span>
</Tooltip>
</Box>}
{value && <Box>
<Tooltip title="Clear">
<span>
<IconButton
disabled={disabled}
onClick={disabled ? undefined : clearValue}
size="large">
<ClearIcon/>
</IconButton>
</span>
</Tooltip>
</Box>}
</Box>
{body}
</Box>
</Box>
);
}
return (
<FormControl error={showError} fullWidth>
<div
className={`${classes.root} ${disabled ? classes.disabled : ""}`}>
{schemaResolver && buildEntityView(schemaResolver)}
{collectionResolver && <ReferenceDialog open={open}
collectionResolver={collectionResolver}
multiselect={false}
path={path}
onClose={onClose}
onSingleEntitySelected={handleEntityClick}
/>}
</div>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #19
Source File: SettingsView.tsx From react-flight-tracker with MIT License | 4 votes |
SettingsView: React.FC<Props> = (props) => {
// Fields
const contextName: string = ViewKeys.SettingsView;
// Contexts
const systemContext = useContext(SystemContext);
const appContext = useContext(AppContext);
const getSetting = (key: string, type: string) => {
const value = systemContext.getSetting(key)
if (typeof (value) === type)
return value;
return false;
};
const handleChange = (e: SelectChangeEvent) => {
appContext.changeTheme(e.target.value);
};
const handleSettingsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
systemContext.storeSetting(e.target.name, e.target.checked);
};
const renderAppSettings = () => {
return (
<Card>
<CardContent>
<Typography
variant={'h6'}
gutterBottom={true}>
{'App settings'}
</Typography>
<FormGroup>
<FormControl
color='secondary'
variant="filled"
sx={{ m: 1, minWidth: 120 }}>
<InputLabel
id="demo-simple-select-filled-label">
Theme change
</InputLabel>
<Select
labelId="demo-simple-select-filled-label"
id="demo-simple-select-filled"
value={appContext.activeThemeName}
onChange={handleChange}>
<MenuItem
value={ThemeKeys.DarkTheme}>
{ThemeKeys.DarkTheme}
</MenuItem>
<MenuItem
value={ThemeKeys.LightTheme}>
{ThemeKeys.LightTheme}
</MenuItem>
<MenuItem
value={ThemeKeys.PineappleTheme}>
{ThemeKeys.PineappleTheme}
</MenuItem>
</Select>
</FormControl>
</FormGroup>
</CardContent>
</Card>
);
};
const renderMapSettings = () => {
return (
<Card>
<CardContent>
<Typography
variant={'h6'}
gutterBottom={true}>
{'Map settings'}
</Typography>
<FormGroup>
<FormControlLabel
control={
<Switch
color='secondary'
name={SettingKeys.ShowDataOverlayOnMap}
checked={getSetting(SettingKeys.ShowDataOverlayOnMap, 'boolean')}
onChange={handleSettingsChange} />
}
label="Show data overlay on map"
/>
<FormControlLabel
control={
<Switch
color='secondary'
name={SettingKeys.ShowLogOverlayOnMap}
checked={getSetting(SettingKeys.ShowLogOverlayOnMap, 'boolean')}
onChange={handleSettingsChange} />
}
label="Show log overlay on map"
/>
</FormGroup>
</CardContent>
</Card>
);
};
return (
<ViewContainer
isScrollLocked={true}>
{renderAppSettings()}
<Box sx={{ height: (theme) => theme.spacing(1) }} />
{renderMapSettings()}
</ViewContainer>
);
}
Example #20
Source File: MapField.tsx From firecms with MIT License | 4 votes |
/**
* Field that renders the children property fields
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function MapField<T extends object>({
name,
value,
showError,
disabled,
property,
setValue,
tableMode,
includeDescription,
underlyingValueHasChanged,
context
}: FieldProps<T>) {
const pickOnlySomeKeys = property.config?.pickOnlySomeKeys || false;
if (!property.properties) {
throw Error(`You need to specify a 'properties' prop (or specify a custom field) in your map property ${name}`);
}
let mapProperties: Record<string, Property>;
if (!pickOnlySomeKeys) {
mapProperties = property.properties as Properties;
} else if (value) {
mapProperties = pick(property.properties as Properties,
...Object.keys(value)
.filter(key => key in property.properties!)
);
} else {
mapProperties = {};
}
useClearRestoreValue({
property,
value,
setValue
});
function buildPickKeysSelect() {
const keys = Object.keys(property.properties!)
.filter((key) => !value || !(key in value));
const handleAddProperty = (event: SelectChangeEvent) => {
setValue({
...value,
[event.target.value as string]: null
});
};
if (!keys.length) return <></>;
return <Box m={1}>
<FormControl fullWidth>
<InputLabel>Add property</InputLabel>
<Select
variant={"standard"}
value={""}
disabled={disabled}
onChange={handleAddProperty}>
{keys.map((key) => (
<MenuItem key={key} value={key}>
{(property.properties as Properties)[key].title || key}
</MenuItem>
))}
</Select>
</FormControl>
</Box>;
}
return (
<FormControl fullWidth error={showError}>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<Paper elevation={0} variant={"outlined"} sx={(theme) => ({
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
}
})}>
<Grid container spacing={2}>
{Object.entries(mapProperties)
.filter(([_, property]) => !isHidden(property))
.map(([entryKey, childProperty], index) => {
return (
<Grid item
sm={12}
xs={12}
key={`map-${name}-${index}`}>
{
buildPropertyField<any, T>({
name: `${name}[${entryKey}]`,
disabled,
property: childProperty,
includeDescription,
underlyingValueHasChanged,
context,
tableMode,
partOfArray: false,
autoFocus: false,
shouldAlwaysRerender: false
})
}
</Grid>
);
}
)}
</Grid>
{pickOnlySomeKeys && buildPickKeysSelect()}
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
</FormControl>
);
}
Example #21
Source File: Form.tsx From frontend with MIT License | 4 votes |
export default function EditForm() {
const [type, setType] = useState('donation')
const [status, setStatus] = useState('initial')
const [provider, setProvider] = useState('none')
const [currency, setCurrency] = useState('')
const [vault, setVault] = useState('')
const router = useRouter()
const { t } = useTranslation()
let id = router.query.id
const vaults = useVaultsList().data
let initialValues: DonationInput = {
type: 'donation',
status: 'initial',
provider: 'none',
currency: '',
amount: 0,
targetVaultId: '',
extCustomerId: '',
extPaymentIntentId: '',
extPaymentMethodId: '',
}
if (id) {
id = String(id)
const { data }: UseQueryResult<DonationResponse> = useDonation(id)
if (data) {
initialValues = {
type: data?.type.toString(),
status: data?.status.toString(),
provider: data?.provider.toString(),
currency: data?.currency.toString(),
amount: data?.amount,
targetVaultId: data?.targetVaultId,
extCustomerId: data?.extCustomerId,
extPaymentIntentId: data?.extPaymentIntentId,
extPaymentMethodId: data?.extPaymentMethodId,
}
}
}
const mutationFn = id ? useEditDonation(id) : useCreateDonation()
const mutation = useMutation<
AxiosResponse<DonationResponse>,
AxiosError<ApiErrors>,
DonationInput
>({
mutationFn,
onError: () => AlertStore.show(t('donations:alerts:error'), 'error'),
onSuccess: () => {
AlertStore.show(id ? t('donations:alerts:edit') : t('donations:alerts:create'), 'success')
router.push(routes.admin.donations.index)
},
})
async function onSubmit(data: DonationInput) {
type ? (data.type = type) : ''
status ? (data.status = status) : ''
provider ? (data.provider = provider) : ''
currency ? (data.currency = currency) : ''
vault ? (data.targetVaultId = vault) : ''
mutation.mutate(data)
}
return (
<GenericForm
onSubmit={onSubmit}
initialValues={initialValues}
validationSchema={validationSchema}>
<Box sx={{ marginTop: '5%', height: '62.6vh' }}>
<Typography variant="h5" component="h2" sx={{ marginBottom: 2, textAlign: 'center' }}>
{id ? t('donations:edit-form-heading') : t('donations:form-heading')}
</Typography>
<Grid container spacing={2} sx={{ width: 600, margin: '0 auto' }}>
<Grid item xs={6}>
<FormControl fullWidth size="small">
<InputLabel id="labelType">{t('donations:type')}</InputLabel>
<Select
labelId="labelType"
label={t('donations:type')}
id="type"
name="type"
value={initialValues.type}
onChange={(e) => setType(e.target.value)}
disabled={id ? true : false}>
{validDonationTypes.map((type) => {
return (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth size="small">
<InputLabel id="labelStatus">{t('donations:status')}</InputLabel>
<Select
labelId="labelStatus"
label={t('donations:status')}
id="status"
name="status"
value={initialValues.status}
onChange={(e) => {
setStatus(e.target.value)
console.log(e.target.value)
}}>
{validDonationStatuses.map((stat) => {
return (
<MenuItem key={stat} value={stat}>
{stat}
</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth size="small">
<InputLabel id="labelProvider">{t('donations:provider')}</InputLabel>
<Select
labelId="labelProvider"
label={t('donations:provider')}
id="provider"
name="provider"
value={initialValues.provider}
onChange={(e) => setProvider(e.target.value)}
disabled={id ? true : false}>
{validProviders.map((prov) => {
return (
<MenuItem key={prov} value={prov}>
{prov}
</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth size="small">
<InputLabel id="labelVault">{t('donations:vault')}</InputLabel>
<Select
labelId="labelVault"
label={t('donations:vault')}
id="targetVaultId"
name="targetVaultId"
value={initialValues.targetVaultId}
onChange={(e) => setVault(e.target.value)}
disabled={id ? true : false}>
{vaults?.map((vault) => {
return (
<MenuItem key={vault.id} value={vault.id}>
{vault.name}
</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormTextField
type="text"
label={t('donations:ext-customer-id')}
name="extCustomerId"
disabled={id ? true : false}
/>
</Grid>
<Grid item xs={6}>
<FormTextField
type="text"
label={t('donations:ext-payment-intent-id')}
name="extPaymentIntentId"
disabled={id ? true : false}
/>
</Grid>
<Grid item xs={6}>
<FormTextField
type="text"
label={t('donations:ext-payment-method-id')}
name="extPaymentMethodId"
disabled={id ? true : false}
/>
</Grid>
<Grid item xs={6}>
<FormTextField
type="number"
label={t('donations:amount')}
name="amount"
disabled={id ? true : false}
/>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth size="small">
<InputLabel id="labelCurrency">{t('donations:currency')}</InputLabel>
<Select
labelId="labelCurrency"
label={t('donations:currency')}
id="currency"
name="currency"
value={initialValues.currency}
onChange={(e) => setCurrency(e.target.value)}
disabled={id ? true : false}>
{validCurrencies.map((currency) => {
return (
<MenuItem key={currency} value={currency}>
{currency}
</MenuItem>
)
})}
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<SubmitButton fullWidth label={t('donations:cta:submit')} />
</Grid>
<Grid item xs={6}>
<Link passHref href={routes.admin.donations.index}>
<Button>{t('donations:cta:cancel')}</Button>
</Link>
</Grid>
</Grid>
</Box>
</GenericForm>
)
}
Example #22
Source File: ArrayOneOfField.tsx From firecms with MIT License | 4 votes |
function ArrayOneOfEntry({
name,
index,
value,
typeField,
valueField,
properties,
autoFocus,
context
}: ArrayOneOfEntryProps) {
const type = value && value[typeField];
const [typeInternal, setTypeInternal] = useState<string | undefined>(type ?? undefined);
useEffect(() => {
if (type !== typeInternal) {
setTypeInternal(type);
}
}, [type]);
const property = typeInternal ? properties[typeInternal] : undefined;
const enumValues: EnumValues = Object.entries(properties).map(([key, property]) => ({ [key]: property.title ?? key })).reduce((a, b) => ({ ...a, ...b }));
const typeFieldName = `${name}[${typeField}]`;
const valueFieldName = `${name}[${valueField}]`;
return (
<Paper sx={(theme) => ({
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
}
})} elevation={0}>
<FastField
required={true}
name={typeFieldName}
>
{(fieldProps: FormikFieldProps) =>
(
<FormControl fullWidth>
<InputLabel
id={`${name}_${index}_select_label`}>
<span>Type</span>
</InputLabel>
<Select
fullWidth
sx={{ marginBottom: 2 }}
labelId={`${name}_${index}_select_label`}
value={fieldProps.field.value !== undefined && fieldProps.field.value !== null ? fieldProps.field.value : ""}
onChange={(evt: any) => {
const eventValue = evt.target.value;
fieldProps.form.setFieldTouched(typeFieldName);
setTypeInternal(eventValue);
fieldProps.form.setFieldValue(typeFieldName, eventValue);
fieldProps.form.setFieldValue(valueFieldName, null);
}}
renderValue={(enumKey: any) =>
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
}>
{enumToObjectEntries(enumValues)
.map(([enumKey, labelOrConfig]) => {
return (
<MenuItem
key={`select_${name}_${index}_${enumKey}`}
value={enumKey}>
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
</MenuItem>
);
})}
</Select>
</FormControl>
)
}
</FastField>
{property && (
<FormControl fullWidth
key={`form_control_${name}_${typeInternal}`}>
{buildPropertyField({
name: valueFieldName,
property: property,
context: context,
autoFocus: autoFocus
})}
</FormControl>
)}
</Paper>
);
}
Example #23
Source File: Info.tsx From frontend with MIT License | 4 votes |
export default function Info({ files, setFiles }: Props) {
const { t } = useTranslation('irregularity')
return (
<Grid container spacing={4} justifyContent="center" alignContent="center">
<Subtitle label={t('steps.info.subtitle')} />
<Grid container item>
<Grid item xs={12}>
<Typography sx={{ fontSize: '18px' }}>{t('steps.info.is-donor')}</Typography>
</Grid>
<Grid container item xs={12}>
<FormControl sx={{ width: '40%', marginTop: '20px' }}>
<Grid container item xs={12} direction="row">
<Grid item xs={6}>
<label>
<Field
size="medium"
type="radio"
name="info.notifierType"
value={NotifierTypes.BENEFACTOR}
/>
{t('steps.info.yes')}
</label>
</Grid>
<Grid item xs={6}>
<label>
<Field
size="medium"
type="radio"
name="info.notifierType"
value={NotifierTypes.OTHER}
/>
{t('steps.info.no')}
</label>
</Grid>
</Grid>
</FormControl>
</Grid>
</Grid>
<Grid container item>
<Grid item xs={12}>
<Typography sx={{ fontSize: '18px', marginBottom: '20px' }}>
{t('reason.title')}
</Typography>
</Grid>
<Grid item xs={12}>
<IrregularityReasonSelect />
</Grid>
</Grid>
<Grid container item>
<Grid item xs={12}>
<Typography sx={{ fontSize: '18px' }}>{t('steps.info.content')}</Typography>
</Grid>
<Grid item xs={12}>
<CssTextField label="" type="text" multiline rows={6} name="info.description" />
</Grid>
</Grid>
<Grid container item rowSpacing={2}>
<Grid item xs={12}>
<Typography sx={{ fontSize: '18px' }}>{t('steps.info.files')}</Typography>
</Grid>
<Grid container justifyContent="center">
<FileUpload
onUpload={(newFiles) => {
setFiles((prevFiles: File[]) => [...prevFiles, ...newFiles])
}}
buttonLabel={t('cta.upload-files')}
/>
<FileList
files={files}
onDelete={(deletedFile) =>
setFiles((prevFiles: File[]) =>
prevFiles.filter((file: File) => file.name !== deletedFile.name),
)
}
/>
</Grid>
</Grid>
<Grid item xs={12}>
<Typography sx={{ fontSize: '15px', textAlign: 'justify' }}>
{t('steps.info.priority-message')}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography sx={{ fontSize: '15px', textAlign: 'justify' }}>
{t('steps.info.share-message')}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography sx={{ fontSize: '15px', textAlign: 'justify' }}>
{t('steps.info.thanks-message')}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography sx={{ fontSize: '15px', textAlign: 'justify' }}>
{t('steps.info.sign')}
</Typography>
</Grid>
</Grid>
)
}
Example #24
Source File: ArrayEnumSelect.tsx From firecms with MIT License | 4 votes |
/**
* This fields renders a dropdown with multiple selection.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ArrayEnumSelect({
name,
value,
setValue,
error,
showError,
disabled,
property,
includeDescription,
autoFocus
}: FieldProps<EnumType[]>) {
const classes = formStyles();
if (!property.of) {
throw Error("Using wrong component ArrayEnumSelect");
}
if (property.of.dataType !== "string" && property.of.dataType !== "number") {
throw Error("Field misconfiguration: array field of type string or number");
}
const enumValues = property.of.config?.enumValues;
if (!enumValues) {
console.error(property);
throw Error("Field misconfiguration: array field of type string or number needs to have enumValues");
}
useClearRestoreValue({
property,
value,
setValue
});
const validValue = !!value && Array.isArray(value);
return (
<FormControl
variant="filled"
fullWidth
required={property.validation?.required}
error={showError}
>
<InputLabel id={`${name}-multiselect-label`}
classes={{
root: classes.inputLabel,
shrink: classes.shrinkInputLabel
}}>
<LabelWithIcon property={property}/>
</InputLabel>
<MuiSelect
multiple
sx={{
minHeight: "64px"
}}
variant={"filled"}
labelId={`${name}-multiselect-label`}
value={validValue ? value.map(v => v.toString()) : []}
autoFocus={autoFocus}
disabled={disabled}
onChange={(evt: any) => {
let newValue;
if (property.of?.dataType === "number")
newValue = evt.target.value ? evt.target.value.map((e: any) => parseFloat(e)) : [];
else
newValue = evt.target.value;
return setValue(
newValue
);
}}
renderValue={(selected: any) => (
<ArrayEnumPreview value={selected}
name={name}
enumValues={enumValues}
size={"regular"}/>
)}>
{enumToObjectEntries(enumValues)
.map(([enumKey, labelOrConfig]) => {
const checked = validValue && value.map(v => v.toString()).includes(enumKey.toString());
return (
<MenuItem key={`form-select-${name}-${enumKey}`}
value={enumKey}
disabled={isEnumValueDisabled(labelOrConfig)}
dense={true}>
<Checkbox checked={checked}/>
<ListItemText primary={
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
}/>
</MenuItem>
);
})}
</MuiSelect>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #25
Source File: GeneralInfo.tsx From frontend with MIT License | 4 votes |
export default function GeneralInfo() {
const { t } = useTranslation()
return (
<Grid container spacing={3} justifyContent="center" direction="column" alignContent="center">
<Grid item xs={12}>
<HeaderTypography>{t('support:steps.info.subtitle')}</HeaderTypography>
</Grid>
<Grid item xs={12} sm={8}>
<Grid container spacing={3} justifyContent="center" direction="column">
<Grid item xs={12}>
<Grid container spacing={3} justifyContent="center" direction="row">
<Grid item xs={12} sm={6}>
<FormTextField
autoFocus
type="text"
name="person.firstName"
autoComplete="first-name"
label="support:steps.info.first-name"
/>
</Grid>
<Grid item xs={12} sm={6}>
<FormTextField
type="text"
name="person.lastName"
autoComplete="family-name"
label="support:steps.info.last-name"
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<FormTextField
type="text"
name="person.email"
autoComplete="email"
label="support:steps.info.email"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
type="text"
name="person.phone"
autoComplete="tel"
label="support:steps.info.phone"
/>
</Grid>
<Grid item xs={12}>
<FormTextField
multiline
size="medium"
type="text"
name="person.comment"
autoComplete="comment"
label="support:steps.info.comment"
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sm={8}>
<Grid container direction="column" alignItems="flex-start">
<Grid item xs={12}>
<AcceptTermsField name="person.terms" />
</Grid>
<Grid item xs={12}>
<AcceptPrivacyPolicyField name="person.gdpr" />
</Grid>
<Grid item xs={12}>
<FormControl component="fieldset">
<CheckboxField
name="person.newsletter"
label={
<Typography variant="body2">{t('support:steps.newsletter.label')}</Typography>
}
/>
</FormControl>
</Grid>
</Grid>
</Grid>
</Grid>
)
}
Example #26
Source File: StringNumberFilterField.tsx From firecms with MIT License | 4 votes |
export function StringNumberFilterField({
name,
value,
setValue,
dataType,
isArray,
enumValues,
title
}: StringNumberFilterFieldProps) {
const possibleOperations: (keyof typeof operationLabels) [] = isArray
? ["array-contains"]
: ["==", "!=", ">", "<", ">=", "<="];
if (enumValues)
isArray
? possibleOperations.push("array-contains-any")
: possibleOperations.push("in");
const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
const [operation, setOperation] = useState<TableWhereFilterOp>(fieldOperation);
const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | undefined>(fieldValue);
function updateFilter(op: TableWhereFilterOp, val: string | number | string[] | number[] | undefined) {
let newValue = val;
const prevOpIsArray = multipleSelectOperations.includes(operation);
const newOpIsArray = multipleSelectOperations.includes(op);
if (prevOpIsArray !== newOpIsArray) {
// @ts-ignore
newValue = newOpIsArray ? (typeof val === "string" || typeof val === "number" ? [val] : []) : "";
}
if (typeof newValue === "number" && isNaN(newValue))
newValue = undefined;
setOperation(op);
setInternalValue(newValue);
const hasNewValue = newValue !== null && Array.isArray(newValue)
? newValue.length > 0
: newValue !== undefined;
if (op && hasNewValue) {
setValue(
[op, newValue]
);
} else {
setValue(
undefined
);
}
}
const multiple = multipleSelectOperations.includes(operation);
return (
<Box display={"flex"} width={340} alignItems={"center"}>
<Box width={80}>
<FormControl fullWidth>
<MuiSelect value={operation}
fullWidth
onChange={(evt: any) => {
updateFilter(evt.target.value, internalValue);
}}>
{possibleOperations.map((op) =>
<MenuItem
key={`filter_op_${name}_${op}`}
value={op}>{operationLabels[op]}</MenuItem>
)}
</MuiSelect>
</FormControl>
</Box>
<Box flexGrow={1} ml={1}>
<FormControl fullWidth>
{!enumValues && <OutlinedInput
fullWidth
key={`filter_${name}`}
type={dataType === "number" ? "number" : undefined}
value={internalValue !== undefined ? internalValue : ""}
onChange={(evt) => {
const val = dataType === "number"
? parseFloat(evt.target.value)
: evt.target.value;
updateFilter(operation, val);
}}
/>}
{enumValues &&
<MuiSelect
fullWidth
key={`filter-select-${multiple}-${name}`}
multiple={multiple}
value={internalValue !== undefined ? internalValue : isArray ? [] : ""}
onChange={(evt: any) => updateFilter(operation, dataType === "number" ? parseInt(evt.target.value) : evt.target.value)}
renderValue={multiple
? (selected: any) =>
(
<div>
{selected.map((enumKey: any) => {
return <EnumValuesChip
key={`select_value_${name}_${enumKey}`}
enumKey={enumKey}
enumValues={enumValues}
small={true}/>;
})}
</div>
)
: undefined}>
{Object.entries(enumValues).map(([enumKey, labelOrConfig]) => {
return (
<MenuItem
key={`select_${name}_${enumKey}`}
value={enumKey}>
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
</MenuItem>
);
})}
</MuiSelect>}
</FormControl>
</Box>
{internalValue !== undefined && <Box ml={1}>
<IconButton
onClick={(e) => updateFilter(operation, undefined)}
size={"small"}>
<Tooltip title={`Clear ${title}`}>
<ClearIcon fontSize={"small"}/>
</Tooltip>
</IconButton>
</Box>}
</Box>
);
}
Example #27
Source File: Deposit.tsx From wrap.scrt.network with MIT License | 4 votes |
export default function Deposit({
token,
secretAddress,
onSuccess,
onFailure,
}: {
token: Token;
secretAddress: string;
onSuccess: (txhash: string) => any;
onFailure: (error: any) => any;
}) {
const [sourceAddress, setSourceAddress] = useState<string>("");
const [availableBalance, setAvailableBalance] = useState<string>("");
const [loadingTx, setLoading] = useState<boolean>(false);
const [sourceCosmJs, setSourceCosmJs] =
useState<SigningStargateClient | null>(null);
const [selectedChainIndex, setSelectedChainIndex] = useState<number>(0);
const [fetchBalanceInterval, setFetchBalanceInterval] = useState<any>(null);
const inputRef = useRef<any>();
const maxButtonRef = useRef<any>();
const sourceChain =
chains[token.deposits[selectedChainIndex].source_chain_name];
const targetChain = chains["Secret Network"];
const fetchSourceBalance = async (sourceAddress: string) => {
const url = `${
chains[token.deposits[selectedChainIndex].source_chain_name].lcd
}/bank/balances/${sourceAddress}`;
try {
const response = await fetch(url);
const result: {
height: string;
result: Array<{ denom: string; amount: string }>;
} = await response.json();
const balance =
result.result.find(
(c) => c.denom === token.deposits[selectedChainIndex].from_denom
)?.amount || "0";
setAvailableBalance(balance);
} catch (e) {
console.error(`Error while trying to query ${url}:`, e);
setAvailableBalance("Error");
}
};
useEffect(() => {
setAvailableBalance("");
if (!sourceAddress) {
return;
}
if (fetchBalanceInterval) {
clearInterval(fetchBalanceInterval);
}
fetchSourceBalance(sourceAddress);
const interval = setInterval(
() => fetchSourceBalance(sourceAddress),
10_000
);
setFetchBalanceInterval(interval);
return () => clearInterval(interval);
}, [sourceAddress]);
useEffect(() => {
(async () => {
while (!window.keplr || !window.getOfflineSignerOnlyAmino) {
await sleep(100);
}
if (["LUNA", "UST"].includes(token.name.toUpperCase())) {
await suggestTerraToKeplr(window.keplr);
}
// Initialize cosmjs on the target chain, because it has sendIbcTokens()
const { chain_id, rpc, bech32_prefix } =
chains[token.deposits[selectedChainIndex].source_chain_name];
await window.keplr.enable(chain_id);
const sourceOfflineSigner = window.getOfflineSignerOnlyAmino(chain_id);
const depositFromAccounts = await sourceOfflineSigner.getAccounts();
setSourceAddress(depositFromAccounts[0].address);
const cosmjs = await SigningStargateClient.connectWithSigner(
rpc,
sourceOfflineSigner,
{ prefix: bech32_prefix, broadcastPollIntervalMs: 10_000 }
);
setSourceCosmJs(cosmjs);
})();
}, [selectedChainIndex]);
return (
<>
<div style={{ padding: "1.5em" }}>
<div
style={{
display: "flex",
placeItems: "center",
gap: token.deposits.length === 1 ? "0.3em" : "0.5em",
}}
>
<Typography>
Deposit <strong>{token.name}</strong> from
</Typography>
<If condition={token.deposits.length === 1}>
<Then>
<Typography>
<strong>
{token.deposits[selectedChainIndex].source_chain_name}
</strong>
</Typography>
</Then>
<Else>
<FormControl>
<Select
value={selectedChainIndex}
onChange={(e) =>
setSelectedChainIndex(Number(e.target.value))
}
>
{token.deposits.map((chain, index) => (
<MenuItem value={index} key={index}>
<div
style={{
display: "flex",
gap: "0.5em",
placeItems: "center",
}}
>
<Avatar
src={chains[chain.source_chain_name].chain_image}
sx={{
marginLeft: "0.3em",
width: "1em",
height: "1em",
boxShadow: "rgba(0, 0, 0, 0.15) 0px 6px 10px",
}}
/>
<strong>{chain.source_chain_name}</strong>
</div>
</MenuItem>
))}
</Select>
</FormControl>
</Else>
</If>
<Typography>
to <strong>Secret Network</strong>
</Typography>
</div>
<br />
<div
style={{
display: "flex",
placeContent: "space-between",
placeItems: "center",
gap: "1em",
}}
>
<Typography sx={{ fontWeight: "bold" }}>From:</Typography>
<CopyableAddress
address={sourceAddress}
explorerPrefix={sourceChain.explorer_account}
/>
</div>
<div
style={{
display: "flex",
placeContent: "space-between",
placeItems: "center",
gap: "1em",
}}
>
<Typography sx={{ fontWeight: "bold" }}>To:</Typography>
<CopyableAddress
address={secretAddress}
explorerPrefix={targetChain.explorer_account}
/>
</div>
<br />
<div
style={{
display: "flex",
placeItems: "center",
gap: "0.3em",
marginBottom: "0.8em",
}}
>
<Typography sx={{ fontSize: "0.8em", fontWeight: "bold" }}>
Available to Deposit:
</Typography>
<Typography
sx={{
fontSize: "0.8em",
opacity: 0.8,
cursor: "pointer",
}}
onClick={() => {
maxButtonRef.current.click();
}}
>
{(() => {
if (availableBalance === "") {
return <CircularProgress size="0.6em" />;
}
const prettyBalance = new BigNumber(availableBalance)
.dividedBy(`1e${token.decimals}`)
.toFormat();
if (prettyBalance === "NaN") {
return "Error";
}
return `${prettyBalance} ${token.name}`;
})()}
</Typography>
</div>
<FormControl sx={{ width: "100%" }} variant="standard">
<InputLabel htmlFor="Amount to Deposit">Amount to Deposit</InputLabel>
<Input
autoFocus
id="Amount to Deposit"
fullWidth
type="text"
inputRef={inputRef}
startAdornment={
<InputAdornment position="start">
<Avatar
src={token.image}
sx={{
width: "1em",
height: "1em",
boxShadow: "rgba(0, 0, 0, 0.15) 0px 6px 10px",
}}
/>
</InputAdornment>
}
endAdornment={
<InputAdornment position="end">
<Button
ref={maxButtonRef}
style={{
padding: "0.1em 0.5em",
minWidth: 0,
}}
onClick={() => {
if (availableBalance === "") {
return;
}
const prettyBalance = new BigNumber(availableBalance)
.dividedBy(`1e${token.decimals}`)
.toFormat();
if (prettyBalance === "NaN") {
return;
}
inputRef.current.value = prettyBalance;
}}
>
MAX
</Button>
</InputAdornment>
}
/>
</FormControl>
</div>
<div
style={{
display: "flex",
placeContent: "center",
marginBottom: "0.4em",
}}
>
<LoadingButton
variant="contained"
sx={{
padding: "0.5em 0",
width: "10em",
fontWeight: "bold",
fontSize: "1.2em",
}}
loading={loadingTx}
onClick={async () => {
if (!sourceCosmJs) {
console.error("No cosmjs");
return;
}
if (!inputRef?.current?.value) {
console.error("Empty deposit");
return;
}
const normalizedAmount = (inputRef.current.value as string).replace(
/,/g,
""
);
if (!(Number(normalizedAmount) > 0)) {
console.error(`${normalizedAmount} not bigger than 0`);
return;
}
setLoading(true);
const amount = new BigNumber(normalizedAmount)
.multipliedBy(`1e${token.decimals}`)
.toFixed(0, BigNumber.ROUND_DOWN);
const { deposit_channel_id, deposit_gas } =
chains[token.deposits[selectedChainIndex].source_chain_name];
try {
const { transactionHash } = await sourceCosmJs.sendIbcTokens(
sourceAddress,
secretAddress,
{
amount,
denom: token.deposits[selectedChainIndex].from_denom,
},
"transfer",
deposit_channel_id,
undefined,
Math.floor(Date.now() / 1000) + 15 * 60, // 15 minute timeout
gasToFee(deposit_gas)
);
inputRef.current.value = "";
onSuccess(transactionHash);
} catch (e) {
onFailure(e);
} finally {
setLoading(false);
}
}}
>
Deposit
</LoadingButton>
</div>
</>
);
}
Example #28
Source File: select.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Select: React.FC<SelectProps> = ({
label,
size = 'small',
options,
optionsConfig,
helperText,
error,
inputRef,
...props
}) => {
const theme = createTheme();
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel
id={`mui-select-label-${label}`}
className={css`
&.MuiFormLabel-root {
transform: translate(14px, 9px) scale(1);
}
&.Mui-focused,
&.MuiFormLabel-filled {
transform: translate(14px, -9px) scale(0.75);
}
`}
>
{label}
</InputLabel>
<StyledSelect
{...props}
labelId={`mui-select-label-${label}`}
id={`mui-select-${label}`}
inputRef={inputRef}
label={label}
size={size}
error={error}
onClose={(e) => e.stopPropagation()}
MenuProps={{
sx: {
'& .MuiPaper-root': {
backgroundColor: 'rgba(253, 253, 253, 0.8)',
backdropFilter: 'blur(8px)',
borderRadius: '4px',
marginTop: theme.spacing(1),
minWidth: 140,
color:
theme.palette.mode === 'light'
? 'rgb(55, 65, 81)'
: theme.palette.grey[300],
boxShadow:
'rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px',
'& .MuiMenu-list': {
padding: '0 4px',
},
'& .MuiMenuItem-root': {
borderRadius: '4px',
padding: '4px 8px',
margin: '4px 0',
fontSize: '14px',
transition: 'all 0.3s',
'& .MuiSvgIcon-root': {
fontSize: '14px',
},
'&:active': {
backgroundColor: alpha(
theme.palette.primary.main,
theme.palette.action.selectedOpacity,
),
},
},
},
},
}}
>
{options.map((i) => {
const label =
optionsConfig && optionsConfig.label
? i[optionsConfig.label]
: i.label;
const value =
optionsConfig && optionsConfig.value
? i[optionsConfig.value]
: i.value;
return (
<MenuItem key={value} value={value}>
{label}
</MenuItem>
);
})}
</StyledSelect>
<FormHelperText error={error}>{helperText}</FormHelperText>
</FormControl>
</Box>
);
}
Example #29
Source File: index.tsx From metaplex with Apache License 2.0 | 4 votes |
Settings = ({ narrow }: { narrow: boolean }) => {
const { disconnect, publicKey } = useWallet();
const { setEndpoint, env, endpoint } = useConnectionConfig();
const { setVisible } = useWalletModal();
const open = React.useCallback(() => setVisible(true), [setVisible]);
const { setModal } = useModal();
const theme = useTheme();
const colorModeCtx = useColorMode();
const handleConnect = React.useCallback(() => {
setModal(ModalEnum.WALLET);
setVisible(true);
}, [setModal, setVisible]);
const connectedActions = [
{
click: async () => {
if (publicKey) {
await navigator.clipboard.writeText(publicKey.toBase58());
notify({
message: 'Wallet update',
description: 'Address copied to clipboard',
});
}
},
innerNarrow: () =>
`Copy Address (${publicKey && shortenAddress(publicKey.toBase58())})`,
inner: function ConnectedWalletCopyC() {
return (
<React.Fragment>
<CopyOutlined />
{publicKey && shortenAddress(publicKey.toBase58())}
</React.Fragment>
);
},
},
{
click: open,
inner: () => 'Change\u00A0Wallet',
},
{
click: () => disconnect().catch(),
inner: () => `Disconnect\u00A0(${env})`,
expandedExtra: {
// these are interepreted as props. TODO: specific types
color: 'error' as any,
variant: 'contained' as any,
},
},
];
const [drawerOpen, setDrawerOpen] = React.useState(false);
const [envCollapseOpen, setEnvCollapseOpen] = React.useState(false);
const hackySkipSet = 'hackySkipSet';
const toggleDrawer = open => event => {
if (
event.type === 'keydown' &&
(event.key === 'Tab' || event.key === 'Shift')
) {
return;
}
if (event.target.classList.contains(hackySkipSet)) {
return;
}
setDrawerOpen(open);
};
const drawerC = inner => {
return (
<React.Fragment>
<Button onClick={toggleDrawer(true)}>
<AccountBalanceWalletIcon />
</Button>
<Drawer anchor="right" open={drawerOpen} onClose={toggleDrawer(false)}>
<Box
sx={{ width: 250 }}
role="presentation"
onClick={toggleDrawer(false)}
onKeyDown={toggleDrawer(false)}
>
{inner}
</Box>
</Drawer>
</React.Fragment>
);
};
const themeSwitch = (
<Button
sx={{ ml: 1 }}
onClick={colorModeCtx.toggleColorMode}
color="inherit"
>
{theme.palette.mode === 'dark' ? (
<Brightness7Icon />
) : (
<Brightness4Icon />
)}
</Button>
);
if (narrow) {
const listHead = (
<ListItem>
<ListItemText
primary="Wallet"
primaryTypographyProps={{
fontSize: '1.2rem',
fontWeight: 'medium',
letterSpacing: 0,
}}
/>
</ListItem>
);
return (
<React.Fragment>
{!publicKey &&
drawerC(
<List>
{listHead}
<Divider />
<ListItemButton
onClick={() => setEnvCollapseOpen(!envCollapseOpen)}
className={hackySkipSet}
>
Change Network
{envCollapseOpen ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={envCollapseOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{ENDPOINTS.map(p => (
<ListItemButton
selected={endpoint === p.endpoint}
onClick={() => setEndpoint(p.endpoint)}
key={p.name}
sx={{ pl: 4 }}
className={hackySkipSet}
>
{p.name}
</ListItemButton>
))}
</List>
</Collapse>
<ListItemButton onClick={handleConnect}>Connect</ListItemButton>
</List>,
)}
{publicKey &&
drawerC(
<List>
{listHead}
<Divider />
{connectedActions.map((a, idx) => {
return (
<ListItemButton onClick={a.click} key={idx}>
{(a.innerNarrow && a.innerNarrow()) || a.inner()}
</ListItemButton>
);
})}
</List>,
)}
{themeSwitch}
</React.Fragment>
);
} else {
return (
<Stack
direction="row"
spacing={2}
sx={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
marginRight: '36px',
}}
>
{!publicKey && (
<React.Fragment>
<FormControl variant="standard" style={{ minWidth: '10ch' }}>
<Select
id="connected-env-select"
onChange={e => {
setEndpoint(e.target.value);
}}
value={endpoint}
>
{ENDPOINTS.map(({ name, endpoint }) => (
<MenuItem key={name} value={endpoint}>
{name}
</MenuItem>
))}
</Select>
</FormControl>
<Link underline="none">
<Button variant="contained" onClick={handleConnect}>
Connect
</Button>
</Link>
</React.Fragment>
)}
{publicKey &&
connectedActions.map((a, idx) => {
return (
<Button
key={idx}
variant="outlined"
onClick={a.click}
{...a.expandedExtra}
>
{a.inner()}
</Button>
);
})}
{themeSwitch}
</Stack>
);
}
}