@material-ui/core#FormGroup TypeScript Examples
The following examples show how to use
@material-ui/core#FormGroup.
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: Settings.tsx From swap-ui with Apache License 2.0 | 6 votes |
function CloseNewAccountsSwitch() {
const styles = useStyles();
const { isClosingNewAccounts, setIsClosingNewAccounts } = useSwapContext();
return (
<FormGroup style={{ display: "none" }} row>
<FormControlLabel
classes={{ label: styles.closeAccountSwitchLabel }}
labelPlacement="start"
style={{
display: "flex",
justifyContent: "space-between",
marginLeft: 0,
width: "100%",
}}
control={
<Switch
checked={isClosingNewAccounts}
onChange={() => setIsClosingNewAccounts(!isClosingNewAccounts)}
color="primary"
/>
}
label="Close new accounts"
/>
</FormGroup>
);
}
Example #2
Source File: SenderFilters.tsx From parity-bridges-ui with GNU General Public License v3.0 | 6 votes |
export default function SenderFilters({
setFilterInput,
setShowEmpty,
setShowCompanion,
showEmpty,
showCompanion
}: Props) {
const classes = useStyles();
const { isBridged } = useGUIContext();
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setFilterInput(event.target.value);
},
[setFilterInput]
);
return (
<div className={classes.filters}>
<SenderFilterInput handleChange={handleChange} />
<Divider />
<FormControl component="fieldset">
<FormGroup aria-label="position" row>
<SenderActionSwitch name="show empty" label="show empty" callback={setShowEmpty} checked={showEmpty} />
{isBridged && (
<SenderActionSwitch
name="show companion"
label="show companion"
callback={setShowCompanion}
checked={showCompanion}
/>
)}
</FormGroup>
</FormControl>
</div>
);
}
Example #3
Source File: index.tsx From aqualink-app with MIT License | 6 votes |
Agreements = ({
agreementsChecked,
handleChange,
classes,
}: AgreementsProps) => {
return (
<div className={classes.agreements}>
<Typography variant="h5">Agree to:</Typography>
<FormGroup>
{agreements.map(({ id, label }) => (
<FormControlLabel
key={label}
className={classes.formControlLabel}
control={
<Checkbox
color="primary"
checked={agreementsChecked[id]}
onChange={() => handleChange(id)}
/>
}
label={label}
/>
))}
</FormGroup>
</div>
);
}
Example #4
Source File: LabeledCheckbox.tsx From UsTaxes with GNU Affero General Public License v3.0 | 5 votes |
export function LabeledCheckbox<TFormValues>(
props: LabeledCheckboxProps<TFormValues>
): ReactElement {
const { label, name, useGrid = true, sizes = { xs: 12 } } = props
const { control } = useFormContext<TFormValues>()
return (
<ConditionallyWrap
condition={useGrid}
wrapper={(children) => (
<Grid item {...sizes}>
{children}
</Grid>
)}
>
<Controller
name={name}
render={({ field: { value, onChange } }) => (
<FormControl component="fieldset">
<FormGroup>
<FormControlLabel
control={
<Checkbox
name={name}
checked={value as boolean}
onChange={(_, checked) => onChange(checked)}
color="primary"
/>
}
label={label}
value={value}
/>
</FormGroup>
</FormControl>
)}
control={control}
/>
</ConditionallyWrap>
)
}
Example #5
Source File: CreateRoom.tsx From cards-against-formality-pwa with BSD 2-Clause "Simplified" License | 5 votes |
function DeckSelector({ decks, onChange }: { decks: any[], onChange: (decks: string[]) => void }) {
const [deckOptions, setDeckOptions] = useState<{ name: string; _id: string, value?: boolean }[]>([]);
const [isExpanded, setIsExpanded] = useState(false);
const [isAllSelected, setIsAllSelected] = useState(false);
const toggleSelectAll = useCallback(() => {
setDeckOptions(prevDeck => {
prevDeck.forEach(deck => deck.value = !isAllSelected);
return [...prevDeck];
});
setIsAllSelected(!isAllSelected);
}, [isAllSelected])
useEffect(() => {
if (decks) {
setDeckOptions(decks.map(deck => {
return { value: deck.name.includes('Base'), ...deck }
}));
}
}, [decks]);
useEffect(() => {
onChange(deckOptions.filter(deck => deck.value).map(deck => deck._id));
}, [deckOptions, onChange]);
function _onChange(e: React.ChangeEvent<HTMLInputElement>) {
setDeckOptions(prevDeck => {
const deck = prevDeck.find(deck => deck._id === e.target.name);
if (deck) {
deck.value = e.target.checked;
}
return [...prevDeck];
});
}
if (!decks?.length) {
return null;
}
return <ExpansionPanel expanded={isExpanded} onChange={() => { setIsExpanded(prev => !prev) }}>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<Typography>Available Decks!</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<FormControl required component="fieldset" error={!deckOptions.some(deck => deck.value)}>
<FormControlLabel
control={<Checkbox checked={isAllSelected} onChange={toggleSelectAll} name="Select all" />}
label="Select all"
/>
<Divider />
<FormLabel component="legend">Select which decks you would like to play with</FormLabel>
<FormGroup className="deck-checkbox-group">
{deckOptions.map(deck => {
return <FormControlLabel
key={deck._id}
control={<Checkbox checked={deck.value} onChange={_onChange} name={deck._id} />}
label={deck.name}
/>
})}
</FormGroup>
<FormHelperText>You must select at least one</FormHelperText>
</FormControl>
</ExpansionPanelDetails>
</ExpansionPanel>
}
Example #6
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
StyledForm = styled(FormGroup)`
padding: 8px 16px;
`
Example #7
Source File: FacetFilter.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 5 votes |
FacetFilter: React.FC<Props> = (props) => {
const classes = useStyles();
const { options, selected, onSelect, onDeselect } = props;
const handleChange = (
e: React.ChangeEvent<HTMLInputElement>,
value: string
) => {
e.persist();
if (e.target.checked) {
onSelect(value);
} else {
onDeselect(value);
}
};
return (
<>
<FormGroup classes={{ root: classes.root }}>
{/* <input className={classes.inp} placeholder="Filter" /> */}
{options.map((opt) => (
<FormControlLabel
classes={{ label: classes.label, root: classes.formControl }}
key={opt.value}
control={
<Checkbox
checked={selected.includes(opt.value)}
onChange={(e) => handleChange(e, opt.value)}
/>
}
label={
<>
<span>{opt.value}</span>
<span className={classes.count}>{opt.count}</span>
</>
}
/>
))}
</FormGroup>
</>
);
}
Example #8
Source File: KubernetesMigrationDismissForm.tsx From backstage with Apache License 2.0 | 5 votes |
KubernetesMigrationDismissForm = forwardRef<
HTMLFormElement,
KubernetesMigrationDismissFormProps
>(({ onSubmit, disableSubmit, alert }, ref) => {
const [services, setServices] = useState<Entity[]>(alert.data.services);
const onFormSubmit: FormEventHandler = e => {
/* Remember to prevent default form behavior */
e.preventDefault();
onSubmit({ services: services });
};
const onCheckboxChange = (
e: ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
if (checked) {
const service = findAlways(
alert.data.services,
s => s.id === e.target.value,
);
setServices(prevServices => prevServices.concat(service));
} else {
setServices(prevServices =>
prevServices.filter(p => p.id !== e.target.value),
);
}
};
/* Submit button is disabled by default. Use props.disableSubmit to toggle disabled state. */
useEffect(() => {
if (services.length) {
disableSubmit(false);
} else {
disableSubmit(true);
}
}, [services, disableSubmit]);
return (
/* All custom forms must accept a ref and implement an onSubmit handler. */
<form ref={ref} onSubmit={onFormSubmit}>
<FormControl component="fieldset" fullWidth>
<Typography color="textPrimary">
<b>Or choose which services to dismiss this alert for.</b>
</Typography>
<FormGroup>
{alert.data.services.map((service, index) => (
<FormControlLabel
key={`example-option-${index}`}
label={service.id}
value={service.id}
control={
<Checkbox
color="primary"
checked={services.some(p => p.id === service.id)}
onChange={onCheckboxChange}
/>
}
/>
))}
</FormGroup>
</FormControl>
</form>
);
})
Example #9
Source File: ContactForm.tsx From storefront with MIT License | 4 votes |
ContactForm: React.VFC = () => {
const { addAlert } = useUI();
const [shouldSend, setShouldSend] = useState(true);
const [contact, { loading }] = useContactMutation();
const { control, formState, handleSubmit, reset } = useForm<ContactFormData>({
defaultValues: {
acceptance: false,
email: '',
name: '',
message: '',
phone: '',
subject: '',
},
mode: 'onChange',
resolver: yupResolver(validationSchema),
});
const onSubmit = handleSubmit(async (values) => {
if (shouldSend) {
try {
const { data } = await contact({ variables: values });
if (data?.contact?.message != null) {
addAlert(data.contact.message);
reset();
}
} catch (error) {
if (isApolloError(error)) {
addAlert(error.message, { severity: 'error' });
}
}
}
});
return (
<form onSubmit={onSubmit}>
<Grid container spacing={2}>
<Grid item xs={6}>
{/* Name */}
<Controller
control={control}
name="name"
render={({ field }) => (
<TextField
required
error={'name' in formState.errors}
helperText={formState.errors.name?.message}
label="Name"
type="text"
{...field}
/>
)}
/>
</Grid>
<Grid item xs={6}>
{/* Email */}
<Controller
control={control}
name="email"
render={({ field }) => (
<TextField
required
error={'email' in formState.errors}
helperText={formState.errors.email?.message}
label="Email"
type="email"
{...field}
/>
)}
/>
</Grid>
</Grid>
<Grid container spacing={2}>
<Grid item xs={6}>
{/* Phone */}
<Controller
control={control}
name="phone"
render={({ field }) => (
<TextField
error={'phone' in formState.errors}
helperText={formState.errors.phone?.message}
label="Phone"
type="text"
{...field}
/>
)}
/>
</Grid>
<Grid item xs={6}>
{/* Subject */}
<Controller
control={control}
name="subject"
render={({ field }) => (
<TextField
error={'subject' in formState.errors}
helperText={formState.errors.subject?.message}
label="Subject"
type="text"
{...field}
/>
)}
/>
</Grid>
</Grid>
{/* Message */}
<Controller
control={control}
name="message"
render={({ field }) => (
<TextField
multiline
required
error={'message' in formState.errors}
helperText={formState.errors.message?.message}
label="Message"
rows={6}
{...field}
/>
)}
/>
{/* Acceptance */}
<FormGroup>
<FormControlLabel
control={
<Controller
control={control}
name="acceptance"
render={({ field }) => (
<Checkbox
checked={field.value}
inputRef={field.ref}
name={field.name}
onBlur={() => field.onBlur()}
onChange={(e) => field.onChange(e.target.checked)}
/>
)}
/>
}
label="I agree that my submitted data is being collected and stored."
/>
</FormGroup>
{/* Acceptance */}
<FormGroup>
<FormControlLabel
control={<Checkbox onChange={(e) => setShouldSend(!e.target.checked)} />}
label="If you are a spambot, you should check this."
/>
</FormGroup>
<Button type="submit" color="primary" disabled={!formState.isValid} loading={loading}>
Submit
</Button>
</form>
);
}
Example #10
Source File: SharePopup.tsx From prompts-ai with MIT License | 4 votes |
export default function SharePopup() {
const classes = useStyles();
const [open, setOpen] = React.useState(true);
const [loading, setLoading] = React.useState(false);
const [link, setLink] = React.useState<string | undefined>(undefined);
const [includeExamples, setIncludeExamples] = React.useState(true);
const completionParameters = useSelector(selectCompletionParameters);
const examples = useSelector(selectExamples);
const handleClose = () => {
setLink(undefined);
setOpen(false);
};
return <Dialog
open={open}
onClose={handleClose}
fullWidth={true}
maxWidth={'sm'}
>
<DialogTitle id="scroll-dialog-title">
Share Prompt
<IconButton aria-label="close" className={classes.closeButton} onClick={handleClose}>
<CloseIcon />
</IconButton>
</DialogTitle>
<DialogContent dividers>
<DialogContent
id="scroll-dialog-description"
tabIndex={-1}
>
<form onSubmit={(event) => {
event.preventDefault();
setLoading(true);
SharedPrompt.create({
engine: completionParameters.engine,
maxTokens: completionParameters.maxTokens,
stop: completionParameters.stop,
prompt: completionParameters.prompt,
temperature: completionParameters.temperature,
topP: completionParameters.topP,
presencePenalty: completionParameters.presencePenalty,
frequencyPenalty: completionParameters.frequencyPenalty,
examples: (includeExamples ? examples : undefined),
}).then(onFulfilled => {
setLoading(false);
setLink(onFulfilled.id)
});
}}>
<Typography>If you edit your prompt after sharing a link, the shared prompt won't change.</Typography>
<Box mt={1}>
{ link && (
<TextField disabled value={link} variant={'outlined'} size={'small'} fullWidth />
)}
{ !link && (
<Box>
<FormGroup row>
<FormControlLabel
control={<Switch checked={includeExamples} onChange={(event: React.ChangeEvent<{}>, value: boolean) => {
setIncludeExamples(value);
}} name="includeExamples" />}
label="Include Examples"
/>
</FormGroup>
<Button disabled={loading} type="submit" variant="contained" color="primary">
{loading && (
<CircularProgress size={24} className={classes.buttonProgress}/>
)}
Create Link
</Button>
</Box>
)}
</Box>
</form>
</DialogContent>
</DialogContent>
</Dialog>;
}
Example #11
Source File: CardSettingsFooter.tsx From neodash with Apache License 2.0 | 4 votes |
NeoCardSettingsFooter = ({ type, fields, reportSettings, reportSettingsOpen, onToggleReportSettings,
onCreateNotification, onReportSettingUpdate }) => {
const [reportSettingsText, setReportSettingsText] = React.useState(reportSettings);
// Variables related to customizing report settings
const [customReportStyleModalOpen, setCustomReportStyleModalOpen] = React.useState(false);
const settingToCustomize = "styleRules";
const debouncedReportSettingUpdate = useCallback(
debounce(onReportSettingUpdate, 250),
[],
);
const updateSpecificReportSetting = (field: string, value: any) => {
const entry = {}
entry[field] = value;
setReportSettingsText(update(reportSettingsText, entry));
debouncedReportSettingUpdate(field, value);
};
useEffect(() => {
// Reset text to the dashboard state when the page gets reorganized.
setReportSettingsText(reportSettings);
}, [JSON.stringify(reportSettings)])
const settings = REPORT_TYPES[type]["settings"];
// If there are no advanced settings, render nothing.
if (Object.keys(settings).length == 0) {
return <div></div>
}
// Else, build the advanced settings view.
const advancedReportSettings = <div style={{ marginLeft: "5px" }}>
{Object.keys(settings).map(setting =>
<NeoSetting key={setting} name={setting}
value={reportSettingsText[setting]}
type={settings[setting]["type"]}
label={settings[setting]["label"]}
defaultValue={settings[setting]["default"]}
choices={settings[setting]["values"]}
onChange={(e) => updateSpecificReportSetting(setting, e)}
/>
)}
</div>
return <div>
<NeoCustomReportStyleModal
settingName={settingToCustomize}
settingValue={reportSettings[settingToCustomize]}
type={type}
fields={fields}
customReportStyleModalOpen={customReportStyleModalOpen}
setCustomReportStyleModalOpen={setCustomReportStyleModalOpen}
onReportSettingUpdate={onReportSettingUpdate}
></NeoCustomReportStyleModal>
<table style={{ borderTop: "1px dashed lightgrey", background: reportSettingsOpen ? "#f6f6f6" : "inherit", width: "100%" }}>
<tbody>
<tr>
<td>
<FormGroup >
<FormControlLabel style={{ marginLeft: "5px", marginBottom: "10px" }}
control={<Switch
checked={reportSettingsOpen} onChange={onToggleReportSettings} color="default" />}
labelPlacement="end"
label={<div style={{ fontSize: "12px", color: "grey" }}>Advanced settings</div>} />
</FormGroup>
</td>
{RULE_BASED_REPORT_CUSTOMIZATIONS[type] ? <td>
<Tooltip title="Set rule-based styling" aria-label="">
<IconButton size="small" style={{ float: "right", marginRight: "10px" }} aria-label="custom styling"
onClick={(e) => {
setCustomReportStyleModalOpen(true); // Open the modal.
}}>
<TuneIcon></TuneIcon>
</IconButton>
</Tooltip>
</td> : <></>}
</tr>
<tr>
<td colSpan={2} style={{ maxWidth: "100%" }}>
{reportSettingsOpen ? advancedReportSettings : <div></div>}
</td>
</tr>
</tbody>
</table>
</div>
}
Example #12
Source File: Dashboard.tsx From crossfeed with Creative Commons Zero v1.0 Universal | 4 votes |
DashboardUI: React.FC<ContextType & { location: any }> = (
props
) => {
const {
current,
setCurrent,
resultsPerPage,
setResultsPerPage,
filters,
addFilter,
removeFilter,
results,
facets,
clearFilters,
sortDirection,
sortField,
setSort,
totalPages,
totalResults,
setSearchTerm,
searchTerm,
noResults
} = props;
const classes = useStyles();
const [selectedDomain, setSelectedDomain] = useState('');
const [resultsScrolled, setResultsScrolled] = useState(false);
const {
apiPost,
apiPut,
setLoading,
showAllOrganizations,
currentOrganization
} = useAuthContext();
const search:
| (SavedSearch & {
editing?: boolean;
})
| undefined = localStorage.getItem('savedSearch')
? JSON.parse(localStorage.getItem('savedSearch')!)
: undefined;
const [showSaveSearch, setShowSaveSearch] = useState<Boolean>(
search && search.editing ? true : false
);
const [savedSearchValues, setSavedSearchValues] = useState<
Partial<SavedSearch> & {
name: string;
vulnerabilityTemplate: Partial<Vulnerability>;
}
>(
search
? search
: {
name: '',
vulnerabilityTemplate: {},
createVulnerabilities: false
}
);
const onTextChange: React.ChangeEventHandler<
HTMLInputElement | HTMLSelectElement
> = (e) => onChange(e.target.name, e.target.value);
const onChange = (name: string, value: any) => {
setSavedSearchValues((values) => ({
...values,
[name]: value
}));
};
const onVulnerabilityTemplateChange = (e: any) => {
(savedSearchValues.vulnerabilityTemplate as any)[e.target.name] =
e.target.value;
setSavedSearchValues(savedSearchValues);
};
const handleResultScroll = (e: React.UIEvent<HTMLElement>) => {
if (e.currentTarget.scrollTop > 0) {
setResultsScrolled(true);
} else {
setResultsScrolled(false);
}
};
useEffect(() => {
if (props.location.search === '') {
// Search on initial load
setSearchTerm('');
}
return () => {
localStorage.removeItem('savedSearch');
};
}, [setSearchTerm, props.location.search]);
useBeforeunload((event) => {
localStorage.removeItem('savedSearch');
});
const fetchDomainsExport = async (): Promise<string> => {
try {
const body: any = {
current,
filters,
resultsPerPage,
searchTerm,
sortDirection,
sortField
};
if (!showAllOrganizations && currentOrganization) {
if ('rootDomains' in currentOrganization)
body.organizationId = currentOrganization.id;
else body.tagId = currentOrganization.id;
}
const { url } = await apiPost('/search/export', {
body
});
return url!;
} catch (e) {
console.error(e);
return '';
}
};
return (
<div className={classes.root}>
<FilterDrawer
addFilter={addFilter}
removeFilter={removeFilter}
filters={filters}
facets={facets}
clearFilters={filters.length > 0 ? () => clearFilters([]) : undefined}
/>
<div className={classes.contentWrapper}>
<Subnav
items={[
{ title: 'Search Results', path: '/inventory', exact: true },
{ title: 'All Domains', path: '/inventory/domains' },
{ title: 'All Vulnerabilities', path: '/inventory/vulnerabilities' }
]}
styles={{
paddingLeft: '0%'
}}
>
<FilterTags filters={filters} removeFilter={removeFilter} />
</Subnav>
<SortBar
sortField={sortField}
sortDirection={sortDirection}
setSort={setSort}
isFixed={resultsScrolled}
saveSearch={
filters.length > 0 || searchTerm
? () => setShowSaveSearch(true)
: undefined
}
existingSavedSearch={search}
/>
{noResults && (
<NoResults
message={"We don't see any results that match your criteria."}
></NoResults>
)}
<div className={classes.content}>
<div className={classes.panel} onScroll={handleResultScroll}>
{results.map((result) => (
<ResultCard
key={result.id.raw}
{...result}
onDomainSelected={(id) => setSelectedDomain(id)}
selected={result.id.raw === selectedDomain}
/>
))}
</div>
<div className={classes.panel}>
{selectedDomain && <DomainDetails domainId={selectedDomain} />}
</div>
</div>
<Paper classes={{ root: classes.pagination }}>
<span>
<strong>
{(totalResults === 0
? 0
: (current - 1) * resultsPerPage + 1
).toLocaleString()}{' '}
-{' '}
{Math.min(
(current - 1) * resultsPerPage + resultsPerPage,
totalResults
).toLocaleString()}
</strong>{' '}
of <strong>{totalResults.toLocaleString()}</strong>
</span>
<Pagination
count={totalPages}
page={current}
onChange={(_, page) => setCurrent(page)}
color="primary"
size="small"
/>
<FormControl
variant="outlined"
className={classes.pageSize}
size="small"
>
<Typography id="results-per-page-label">
Results per page:
</Typography>
<Select
id="teststa"
labelId="results-per-page-label"
value={resultsPerPage}
onChange={(e) => setResultsPerPage(e.target.value as number)}
>
{[15, 45, 90].map((perPage) => (
<MenuItem key={perPage} value={perPage}>
{perPage}
</MenuItem>
))}
</Select>
</FormControl>
<USWDSButton
className={classes.exportButton}
outline
type="button"
onClick={() =>
exportCSV(
{
name: 'domains',
getDataToExport: fetchDomainsExport
},
setLoading
)
}
>
Export Results
</USWDSButton>
</Paper>
</div>
{showSaveSearch && (
<div>
<Overlay />
<ModalContainer>
<Modal
className={classes.saveSearchModal}
actions={
<>
<USWDSButton
outline
type="button"
onClick={() => {
setShowSaveSearch(false);
}}
>
Cancel
</USWDSButton>
<USWDSButton
type="button"
onClick={async () => {
const body = {
body: {
...savedSearchValues,
searchTerm,
filters,
count: totalResults,
searchPath: window.location.search,
sortField,
sortDirection
}
};
if (search) {
await apiPut('/saved-searches/' + search.id, body);
} else {
await apiPost('/saved-searches/', body);
}
setShowSaveSearch(false);
}}
>
Save
</USWDSButton>
</>
}
title={search ? <h2>Update Search</h2> : <h2>Save Search</h2>}
>
<FormGroup>
<Label htmlFor="name">Name Your Search</Label>
<TextInput
required
id="name"
name="name"
type="text"
value={savedSearchValues.name}
onChange={onTextChange}
/>
<p>When a new result is found:</p>
{/* <FormControlLabel
control={
<Checkbox
// checked={gilad}
// onChange={handleChange}
name="email"
/>
}
label="Email me"
/> */}
<FormControlLabel
control={
<Checkbox
checked={savedSearchValues.createVulnerabilities}
onChange={(e) =>
onChange(e.target.name, e.target.checked)
}
id="createVulnerabilities"
name="createVulnerabilities"
/>
}
label="Create a vulnerability"
/>
{savedSearchValues.createVulnerabilities && (
<>
<Label htmlFor="title">Title</Label>
<TextInput
required
id="title"
name="title"
type="text"
value={savedSearchValues.vulnerabilityTemplate.title}
onChange={onVulnerabilityTemplateChange}
/>
<Label htmlFor="description">Description</Label>
<TextareaAutosize
required
id="description"
name="description"
style={{ padding: 10 }}
rowsMin={2}
value={
savedSearchValues.vulnerabilityTemplate.description
}
onChange={onVulnerabilityTemplateChange}
/>
<Label htmlFor="description">Severity</Label>
<Dropdown
id="severity"
name="severity"
onChange={onVulnerabilityTemplateChange}
value={
savedSearchValues.vulnerabilityTemplate
.severity as string
}
style={{ display: 'inline-block', width: '150px' }}
>
<option value="None">None</option>
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
<option value="Critical">Critical</option>
</Dropdown>
</>
)}
{/* <h3>Collaborators</h3>
<p>
Collaborators can view vulnerabilities, and domains within
this search. Adding a team will make all members
collaborators.
</p>
<button className={classes.addButton} >
<AddCircleOutline></AddCircleOutline> ADD
</button> */}
</FormGroup>
</Modal>
</ModalContainer>
</div>
)}
</div>
);
}
Example #13
Source File: chart-filters.tsx From backstage with Apache License 2.0 | 4 votes |
export function ChartFilters(props: ChartFiltersProps) {
const {
analysis,
cicdConfiguration,
initialFetchFilter,
currentFetchFilter,
onChangeFetchFilter,
updateFetchFilter,
initialViewOptions,
onChangeViewOptions,
} = props;
const classes = useStyles();
const [internalRef] = useState<InternalRef>({ first: true });
const [useNowAsToDate, setUseNowAsToDate] = useState(true);
const [toDate, setToDate] = useState(initialFetchFilter.toDate);
const [fromDate, setFromDate] = useState(initialFetchFilter.fromDate);
const [branch, setBranch] = useState(initialFetchFilter.branch);
const statusValues: ReadonlyArray<StatusSelection> =
cicdConfiguration.availableStatuses;
const [selectedStatus, setSelectedStatus] = useState(
initialFetchFilter.status,
);
const [viewOptions, setViewOptions] = useState(initialViewOptions);
const setLowercaseNames = useCallback(
(lowercaseNames: boolean) => {
setViewOptions(old => ({ ...old, lowercaseNames }));
},
[setViewOptions],
);
const setNormalizeTimeRange = useCallback(
(normalizeTimeRange: boolean) => {
setViewOptions(old => ({ ...old, normalizeTimeRange }));
},
[setViewOptions],
);
const setHideLimit = useCallback(
(value: number) => {
setViewOptions(old => ({ ...old, hideLimit: value }));
},
[setViewOptions],
);
const setCollapseLimit = useCallback(
(value: number) => {
setViewOptions(old => ({ ...old, collapsedLimit: value }));
},
[setViewOptions],
);
const setChartType = useCallback(
(statusType: FilterStatusType, chartTypes: ChartTypes) => {
setViewOptions(old => ({
...old,
chartTypes: { ...old.chartTypes, [statusType]: chartTypes },
}));
},
[setViewOptions],
);
const setChartTypeSpecific = useMemo(
() =>
Object.fromEntries(
statusTypes.map(
status =>
[
status,
(chartTypes: ChartTypes) => setChartType(status, chartTypes),
] as const,
),
),
[setChartType],
);
useEffect(() => {
onChangeViewOptions(viewOptions);
}, [onChangeViewOptions, viewOptions]);
useEffect(() => {
if (internalRef.first) {
// Skip calling onChangeFetchFilter first time
internalRef.first = false;
return;
}
onChangeFetchFilter({
toDate,
fromDate,
branch,
status: selectedStatus,
});
}, [
internalRef,
toDate,
fromDate,
branch,
selectedStatus,
onChangeFetchFilter,
]);
const toggleUseNowAsDate = useCallback(() => {
setUseNowAsToDate(!useNowAsToDate);
if (!DateTime.fromJSDate(toDate).hasSame(DateTime.now(), 'day')) {
setToDate(new Date());
}
}, [useNowAsToDate, toDate]);
const hasFetchFilterChanges = useMemo(
() =>
!currentFetchFilter ||
!isSameChartFilter(
{
toDate,
fromDate,
branch,
status: selectedStatus,
},
currentFetchFilter,
),
[toDate, fromDate, branch, selectedStatus, currentFetchFilter],
);
const updateFilter = useCallback(() => {
updateFetchFilter({
toDate,
fromDate,
branch,
status: selectedStatus,
});
}, [toDate, fromDate, branch, selectedStatus, updateFetchFilter]);
const inrefferedStatuses = analysis?.statuses ?? selectedStatus;
return (
<MuiPickersUtilsProvider utils={LuxonUtils}>
<Card className={classes.rootCard}>
<CardHeader
action={
<Button
size="small"
color="secondary"
variant="contained"
onClick={updateFilter}
disabled={!hasFetchFilterChanges}
>
Update
</Button>
}
title={
<Typography variant="subtitle2" className={classes.header}>
Fetching options
</Typography>
}
/>
<CardContent>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Date range
</Typography>
<KeyboardDatePicker
autoOk
variant="inline"
inputVariant="outlined"
label="From date"
format="yyyy-MM-dd"
value={fromDate}
InputAdornmentProps={{ position: 'start' }}
onChange={date => setFromDate(date?.toJSDate() ?? new Date())}
/>
<br />
<FormControl component="fieldset">
<FormGroup>
<FormControlLabel
control={
<Switch
checked={useNowAsToDate}
onChange={toggleUseNowAsDate}
/>
}
label={<Label>To today</Label>}
/>
{useNowAsToDate ? null : (
<KeyboardDatePicker
autoOk
variant="inline"
inputVariant="outlined"
label="To date"
format="yyyy-MM-dd"
value={toDate}
InputAdornmentProps={{ position: 'start' }}
onChange={date => setToDate(date?.toJSDate() ?? new Date())}
/>
)}
</FormGroup>
</FormControl>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Branch
</Typography>
<ButtonSwitch<string>
values={branchValues}
selection={branch}
onChange={setBranch}
/>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Status
</Typography>
<ButtonSwitch<string>
values={statusValues}
multi
vertical
selection={selectedStatus}
onChange={setSelectedStatus}
/>
</CardContent>
</Card>
<Card className={classes.rootCard}>
<CardHeader
title={
<Typography variant="subtitle2" className={classes.header}>
View options
</Typography>
}
/>
<CardContent>
<Toggle
checked={viewOptions.lowercaseNames}
setChecked={setLowercaseNames}
>
<Tooltip
arrow
title={
'Lowercasing names can reduce duplications ' +
'when stage names have changed casing'
}
>
<Label>Lowercase names</Label>
</Tooltip>
</Toggle>
<Toggle
checked={viewOptions.normalizeTimeRange}
setChecked={setNormalizeTimeRange}
>
<Tooltip
arrow
title={
'All charts will use the same x-axis. ' +
'This reduces confusion when stages have been altered over time ' +
'and only appear in a part of the time range.'
}
>
<Label>Normalize time range</Label>
</Tooltip>
</Toggle>
<DurationSlider
header="Hide under peak"
value={viewOptions.hideLimit}
setValue={setHideLimit}
/>
<DurationSlider
header="Collapse under peak"
value={viewOptions.collapsedLimit}
setValue={setCollapseLimit}
/>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Chart styles
</Typography>
{inrefferedStatuses.map(status => (
<Grid key={status} container spacing={0}>
<Grid item>
<ButtonSwitch<ChartType>
values={chartTypeValues}
selection={viewOptions.chartTypes[status as FilterStatusType]}
onChange={setChartTypeSpecific[status]}
multi
/>
</Grid>
<Grid item className={classes.buttonDescription}>
<div>{status}</div>
</Grid>
</Grid>
))}
</CardContent>
</Card>
</MuiPickersUtilsProvider>
);
}
Example #14
Source File: index.tsx From vscode-crossnote with GNU Affero General Public License v3.0 | 4 votes |
function OCRWidget(props: WidgetArgs) {
const classes = useStyles(props);
const { t } = useTranslation();
const [canvas, setCanvas] = useState<HTMLCanvasElement>(null);
// https://github.com/tesseract-ocr/tesseract/wiki/Data-Files#data-files-for-version-400-november-29-2016
const [link, setLink] = useState<string>("");
const [imageDataURL, setImageDataURL] = useState<string>("");
const [ocrDataURL, setOCRDataURL] = useState<string>("");
const [imageDropAreaElement, setImageDropAreaElement] = useState<
HTMLInputElement
>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const [ocrProgresses, setOCRProgresses] = useState<OCRProgress[]>([]);
const [selectedLanguages, setSelectedLanguages] = useState<string[]>(
getInitialLanguages()
);
const [grayscaleChecked, setGrayscaleChecked] = useState<boolean>(true);
useEffect(() => {
if (canvas && imageDataURL) {
const imageObject = new Image();
const context = canvas.getContext("2d");
imageObject.onload = function () {
canvas.width = imageObject.width;
canvas.height = imageObject.height;
context.clearRect(0, 0, canvas.width, canvas.height);
if (grayscaleChecked) {
context.fillStyle = "#FFF";
context.fillRect(0, 0, canvas.width, canvas.height);
context.globalCompositeOperation = "luminosity";
}
context.drawImage(imageObject, 0, 0);
setOCRDataURL(canvas.toDataURL());
};
imageObject.onerror = (error) => {
throw error;
};
imageObject.setAttribute("crossOrigin", "anonymous");
imageObject.src = imageDataURL;
}
}, [canvas, imageDataURL, grayscaleChecked]);
function clickDropArea(e: any) {
e.preventDefault();
e.stopPropagation();
if (!imageDropAreaElement || isProcessing) return;
imageDropAreaElement.onchange = function (event) {
const target = event.target as any;
const files = target.files || [];
if (files.length) {
try {
const file = files[0] as File;
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
setImageDataURL(reader.result as string);
};
reader.onerror = (error) => {
throw error;
};
} catch (error) {}
}
};
imageDropAreaElement.click();
}
function startOCRFromLink() {
try {
setImageDataURL(link);
} catch (error) {}
}
function ocr(input: File | string | HTMLCanvasElement) {
const worker = createWorker({
logger: (m: OCRProgress) => {
setOCRProgresses((ocrProgresses) => {
if (
ocrProgresses.length &&
ocrProgresses[ocrProgresses.length - 1].status === m.status
) {
return [...ocrProgresses.slice(0, ocrProgresses.length - 1), m];
} else {
return [...ocrProgresses, m];
}
});
},
});
(async () => {
setIsProcessing(true);
let languagesArr = selectedLanguages;
if (languagesArr.length === 0) {
languagesArr = ["eng"];
}
await worker.load();
await worker.loadLanguage(languagesArr.join("+"));
await worker.initialize(languagesArr.join("+"));
const {
data: { text },
} = await worker.recognize(input);
props.replaceSelf("\n" + text);
await worker.terminate();
setIsProcessing(false);
})();
}
function toggleLanguage(lang: string) {
setSelectedLanguages((selectedLanguages) => {
const offset = selectedLanguages.indexOf(lang);
if (offset >= 0) {
selectedLanguages.splice(offset, 1);
selectedLanguages = [...selectedLanguages];
} else {
selectedLanguages = [...selectedLanguages, lang];
}
return selectedLanguages;
});
}
if (props.isPreview) {
return <span></span>;
}
if (isProcessing) {
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("general/Processing")}</Typography>
{/*<Typography variant={"body1"}>{t("general/please-wait")}</Typography>*/}
<List>
{ocrProgresses.length > 0 && (
<ListItem>
<ListItemText>
{t(
"tesseract/" + ocrProgresses[ocrProgresses.length - 1].status
)}
</ListItemText>
<ListItemSecondaryAction>
{Math.floor(
ocrProgresses[ocrProgresses.length - 1].progress * 100
).toString() + "%"}
</ListItemSecondaryAction>
</ListItem>
)}
</List>
</Card>
);
}
if (imageDataURL) {
return (
<Card elevation={2} className={clsx(classes.card)}>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/recognize-text-in-languages")}
</Typography>
<FormGroup>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("eng") >= 0}
onChange={() => toggleLanguage("eng")}
value="eng"
/>
}
label="English"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("chi_sim") >= 0}
onChange={() => toggleLanguage("chi_sim")}
value="chi_sim"
/>
}
label="简体中文"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("chi_tra") >= 0}
onChange={() => toggleLanguage("chi_tra")}
value="chi_tra"
/>
}
label="繁體中文"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("jpn") >= 0}
onChange={() => toggleLanguage("jpn")}
value="jpn"
/>
}
label="日本語"
/>
</FormGroup>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/extra-settings")}
</Typography>
<FormControlLabel
control={
<Switch
checked={grayscaleChecked}
onChange={() => {
setGrayscaleChecked(!grayscaleChecked);
}}
color={"primary"}
></Switch>
}
label={t("widget/crossnote.ocr/grayscale")}
></FormControlLabel>
</Box>
<Box className={clsx(classes.canvasWrapper)}>
<canvas
className={clsx(classes.canvas)}
ref={(element) => setCanvas(element)}
></canvas>
</Box>
<ButtonGroup>
<Button
onClick={() => {
setImageDataURL("");
setOCRDataURL("");
}}
>
{t("general/go-back")}
</Button>
<Button
color={"primary"}
onClick={() => ocr(ocrDataURL)}
disabled={!ocrDataURL}
>
{t("widget/crossnote.ocr/start-ocr")}
</Button>
</ButtonGroup>
</Card>
);
}
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("widget/crossnote.ocr/ocr")}</Typography>
<Box className={clsx(classes.actionButtons)}>
<Tooltip title={t("general/Delete")}>
<IconButton onClick={() => props.removeSelf()}>
<TrashCan></TrashCan>
</IconButton>
</Tooltip>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("general/Link")}
</Typography>
<Input
margin={"dense"}
placeholder={t("widget/crossnote.image/image-url-placeholder")}
value={link}
onChange={(event) => {
setLink(event.target.value);
}}
onKeyDown={(event) => {
if (event.which === 13) {
startOCRFromLink();
}
}}
fullWidth={true}
></Input>
</Box>
<Typography
variant={"subtitle1"}
style={{ marginTop: "16px", textAlign: "center" }}
>
{t("widget/crossnote.auth/Or")}
</Typography>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/local-image")}
</Typography>
<Box
className={clsx(
classes.dropArea,
isProcessing ? classes.disabled : null
)}
onClick={clickDropArea}
>
<Typography>
{isProcessing
? t("utils/uploading-image")
: t("widget/crossnote.image/click-here-to-browse-image-file")}
</Typography>
</Box>
</Box>
<input
type="file"
// multiple
style={{ display: "none" }}
ref={(element: HTMLInputElement) => {
setImageDropAreaElement(element);
}}
></input>
</Card>
);
}
Example #15
Source File: ShippingForm.tsx From storefront with MIT License | 4 votes |
ShippingForm = React.forwardRef<HTMLFormElement, Props>(
(
{
defaultValues,
onShippingSameAsBillingChange,
onSubmit: onSubmitProp,
shipToDifferentAddress = false,
},
ref,
) => {
const [updateCustomer, { loading }] = useUpdateCustomerMutation({
refetchQueries: ['Cart', 'Customer'],
});
const [shippingSameAsBilling, setShippingSameAsBilling] = useState(!shipToDifferentAddress);
const { control, formState, handleSubmit, reset } = useForm<CustomerAddressInput>({
defaultValues: {
address1: defaultValues?.address1 ?? '',
address2: defaultValues?.address2 ?? '',
city: defaultValues?.city ?? '',
company: defaultValues?.company ?? '',
country: defaultValues?.country ?? CountriesEnum.DE,
firstName: defaultValues?.firstName ?? '',
lastName: defaultValues?.lastName ?? '',
postcode: defaultValues?.postcode ?? '',
state: defaultValues?.state ?? '',
},
resolver: yupResolver(validationSchema),
});
useEffect(() => {
reset({
address1: defaultValues?.address1 ?? '',
address2: defaultValues?.address2 ?? '',
city: defaultValues?.city ?? '',
company: defaultValues?.company ?? '',
country: defaultValues?.country ?? CountriesEnum.DE,
firstName: defaultValues?.firstName ?? '',
lastName: defaultValues?.lastName ?? '',
postcode: defaultValues?.postcode ?? '',
state: defaultValues?.state ?? '',
});
}, [defaultValues, reset]);
const onSubmit = handleSubmit(async (shipping) => {
await updateCustomer({ variables: { shipping, shippingSameAsBilling } });
onSubmitProp();
});
const handleShippingSameAsBillingChange = async (ev: React.ChangeEvent<HTMLInputElement>) => {
const nextShippingSameAsBilling = ev.target.checked;
await updateCustomer({ variables: { shippingSameAsBilling: nextShippingSameAsBilling } });
setShippingSameAsBilling(nextShippingSameAsBilling);
onShippingSameAsBillingChange(nextShippingSameAsBilling);
reset();
};
const handleChange =
(onChange: (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void) =>
(event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
onChange(event);
if (shippingSameAsBilling) {
setShippingSameAsBilling(false);
onShippingSameAsBillingChange(false);
}
};
return (
<>
<Typography gutterBottom variant="h3">
Shipping Address
</Typography>
<Box sx={{ mb: 4 }}>
<FormGroup>
<FormControlLabel
control={
<Checkbox
name="shippingSameAsBilling"
checked={shippingSameAsBilling}
onChange={handleShippingSameAsBillingChange}
/>
}
label="Same as Billing address"
/>
</FormGroup>
<Divider />
</Box>
<form ref={ref} onSubmit={onSubmit}>
<Grid container spacing={2}>
<Grid item xs={6}>
{/* First Name */}
<Controller
control={control}
name="firstName"
render={({ field }) => (
<TextField
required
autoComplete="given-name"
error={'firstName' in formState.errors}
helperText={formState.errors.firstName?.message}
label="First name"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
</Grid>
<Grid item xs={6}>
{/* Last Name */}
<Controller
control={control}
name="lastName"
render={({ field }) => (
<TextField
required
autoComplete="family-name"
error={'lastName' in formState.errors}
helperText={formState.errors.lastName?.message}
label="Last name"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
</Grid>
</Grid>
{/* Company */}
<Controller
control={control}
name="company"
render={({ field }) => (
<TextField
autoComplete="organization"
error={'company' in formState.errors}
helperText={formState.errors.company?.message}
label="Company"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
{/* Country */}
<Controller
control={control}
name="country"
render={({ field }) => (
<CountrySelect
required
error={'country' in formState.errors}
helperText={formState.errors.country?.message}
label="Country"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
{/* Address */}
<Controller
control={control}
name="address1"
render={({ field }) => (
<TextField
required
autoComplete="address-line1"
error={'address1' in formState.errors}
helperText={formState.errors.address1?.message}
label="Street address"
placeholder="House number and street name"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
<Controller
control={control}
name="address2"
render={({ field }) => (
<TextField
autoComplete="address-line2"
error={'address2' in formState.errors}
helperText={formState.errors.address2?.message}
placeholder="Apartment, suite, unit etc. (optional)"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
<Grid container spacing={2}>
<Grid item xs={3}>
{/* Postcode */}
<Controller
control={control}
name="postcode"
render={({ field }) => (
<TextField
required
autoComplete="postal-code"
error={'postcode' in formState.errors}
helperText={formState.errors.postcode?.message}
label="Postcode"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
</Grid>
<Grid item xs={9}>
{/* City */}
<Controller
control={control}
name="city"
render={({ field }) => (
<TextField
required
autoComplete="address-level2"
error={'city' in formState.errors}
helperText={formState.errors.city?.message}
label="City"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
</Grid>
</Grid>
{/* State */}
<Controller
control={control}
name="state"
render={({ field }) => (
<TextField
autoComplete="address-level1"
error={'state' in formState.errors}
helperText={formState.errors.state?.message}
label="State"
type="text"
{...field}
onChange={handleChange(field.onChange)}
/>
)}
/>
<Box sx={{ mt: 2 }}>
<Button type="submit" color="primary" loading={loading}>
Continue to Shipping Method
</Button>
</Box>
</form>
</>
);
},
)
Example #16
Source File: CheckoutReview.tsx From storefront with MIT License | 4 votes |
CheckoutReview: React.VFC<Props> = ({
cart,
creditCard,
customer,
loading,
onSubmit,
paymentMethod,
paymentNonce,
}) => {
const [customerNote, setCustomerNote] = useState<string>();
const [acceptTerms, setAcceptsTerms] = useState(false);
const [{ loading: paymentLoading }, handlePayment] = useAsyncFn(async (nonce?: string) => {
const response = await fetch('/api/payment', {
method: 'post',
credentials: 'include',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
nonce,
total: cart.total == null ? undefined : parseFloat(cart.total),
}),
});
const data = (await response.json()) as PaymentResponse;
onSubmit({
customerNote,
metaData: [
{
key: '_merchant_account_id',
value: process.env.BRAINTREE_MERCHANT_ID,
},
{
key: '_wc_braintree_environment',
value: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox',
},
{
key: '_transaction_status',
value: data.transaction.status,
},
],
transactionId: data.transaction.id,
});
});
const handleSubmit = () => {
handlePayment(paymentNonce);
};
if (loading || paymentLoading) {
return <Loader />;
}
return (
<>
<Grid container spacing={4}>
<Grid item xs={6}>
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
mb: 1,
}}
>
<Typography variant="h4">Billing Address</Typography>
<IconButton href="/checkout/billing-address" size="small">
<Edit fontSize="inherit" />
</IconButton>
</Box>
<Divider />
<Box sx={{ mt: 2 }}>
<AddressSummary address={customer.billing} />
</Box>
</Grid>
<Grid item xs={6}>
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
mb: 1,
}}
>
<Typography variant="h4">Shipping Address</Typography>
<IconButton href="/checkout/shipping-address" size="small">
<Edit fontSize="inherit" />
</IconButton>
</Box>
<Divider />
<Box sx={{ mt: 2 }}>
<AddressSummary address={customer.shipping} />
</Box>
</Grid>
<Grid item xs={6}>
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
mb: 1,
}}
>
<Typography variant="h4">Shipping Method</Typography>
<IconButton href="/checkout/shipping-options" size="small">
<Edit fontSize="inherit" />
</IconButton>
</Box>
<Divider />
<Box sx={{ mt: 2 }}>
<ShippingSummary
availableShippingMethods={cart.availableShippingMethods}
chosenShippingMethods={cart.chosenShippingMethods}
/>
</Box>
</Grid>
<Grid item xs={6}>
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
mb: 1,
}}
>
<Typography variant="h4">Payment Method</Typography>
<IconButton href="/checkout/payment" size="small">
<Edit fontSize="inherit" />
</IconButton>
</Box>
<Divider />
<Box sx={{ mt: 2 }}>
<PaymentSummary chosenPaymentMethod={paymentMethod} creditCard={creditCard} />
</Box>
</Grid>
</Grid>
<Box sx={{ mt: 6 }}>
<TextField
multiline
label="Note"
placeholder="Please sign my prints"
rows={3}
onChange={(ev) => setCustomerNote(ev.target.value)}
/>
<FormGroup>
<FormControlLabel
control={
<Checkbox
name="acceptTerms"
checked={acceptTerms}
onChange={(ev) => setAcceptsTerms(ev.target.checked)}
/>
}
label={
<>
With your order, you agree to have read and understood our{' '}
<Link href="/terms">Terms & Conditions</Link> your{' '}
<Link href="/revocation">Right of Recission</Link> and our{' '}
<Link href="/privacy-policy">Privacy Policy</Link>.
</>
}
/>
</FormGroup>
</Box>
<Box sx={{ mt: 6 }}>
{paymentMethod === 'braintree_paypal' ? (
<PaypalButton
cart={cart}
disabled={!acceptTerms}
shipping={customer.shipping}
paymentClientToken={process.env.BRAINTREE_TOKENIZATION_KEY}
onAuthorize={(nonce) => handlePayment(nonce)}
/>
) : (
<Button fullWidth color="primary" disabled={!acceptTerms} onClick={handleSubmit}>
Place your order
</Button>
)}
</Box>
</>
);
}
Example #17
Source File: exposedPopulationAnalysis.tsx From prism-frontend with MIT License | 4 votes |
ExposedPopulationAnalysis = ({
result,
id,
extent,
exposure,
}: AnalysisProps) => {
const { startDate: selectedDate } = useSelector(dateRangeSelector);
const isDataTableDrawerActive = useSelector(isDataTableDrawerActiveSelector);
const analysisExposureLoading = useSelector(
isExposureAnalysisLoadingSelector,
);
const data = useSelector(analysisResultSelector);
const { t } = useSafeTranslation();
const dispatch = useDispatch();
const runExposureAnalysis = async () => {
if (data) {
dispatch(clearAnalysisResult());
}
if (!id || !extent || !exposure) {
return;
}
if (!selectedDate) {
throw new Error('Date must be given to run analysis');
}
const params: ExposedPopulationDispatchParams = {
exposure,
date: selectedDate,
statistic: AggregationOperations.Sum,
extent,
wfsLayerId: id as LayerKey,
};
dispatch(requestAndStoreExposedPopulation(params));
};
// Since the exposure analysis doesn't have predefined table in configurations
// and need to have a `TableKey` will use this util function to handle such case
// used timestamp to avoid any potential rare name collision
const generateUniqueTableKey = (activityName: string) => {
return `${activityName}_${Date.now()}`;
};
const ResultSwitches = () => {
const features = data?.featureCollection.features;
const hasNoData = features?.length === 0;
const handleTableViewChange = (e: React.ChangeEvent<HTMLInputElement>) => {
dispatch(setIsDataTableDrawerActive(e.target.checked));
dispatch(
setCurrentDataDefinition({
id: generateUniqueTableKey('exposure_analysis') as TableKey,
title: data?.getTitle(t) || '',
table: '',
legendText: t(data?.legendText || ''),
}),
);
};
return (
<>
<FormGroup>
<AnalysisFormControlLabel
control={
<Switch
color="primary"
disabled={hasNoData}
checked={isDataTableDrawerActive}
onChange={handleTableViewChange}
/>
}
label={t('Table View')}
/>
</FormGroup>
{hasNoData && (
<Grid item>
<Typography align="center" variant="h5">
{t('No population was exposed')}
</Typography>
</Grid>
)}
</>
);
};
if (!result || !(result instanceof ExposedPopulationResult)) {
return (
<>
<AnalysisButton
variant="contained"
color="primary"
size="small"
onClick={runExposureAnalysis}
>
{t('Exposure Analysis')}
</AnalysisButton>
{analysisExposureLoading && <LinearProgress />}
</>
);
}
return (
<>
<AnalysisButton
variant="contained"
color="secondary"
size="small"
onClick={() => dispatch(clearAnalysisResult())}
>
{t('Clear Analysis')}
</AnalysisButton>
<ResultSwitches />
</>
);
}
Example #18
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>
);
}
Example #19
Source File: SQFormCheckboxGroup.tsx From SQForm with MIT License | 4 votes |
function SQFormCheckboxGroup({
name,
groupLabel,
onChange,
shouldDisplayInRow = false,
shouldUseSelectAll = false,
size = 'auto',
children,
}: SQFormCheckboxGroupProps): JSX.Element {
const {
fieldState: {isFieldError, isFieldRequired},
fieldHelpers: {handleChange, handleBlur, HelperTextComponent},
} = useForm<CheckboxOption['value'][], React.ChangeEvent<HTMLInputElement>>({
name,
onChange,
});
const {setFieldValue} = useFormikContext();
const handleSelectAllChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
if (!event.target.checked) {
setFieldValue(name, []);
return;
}
const enabledGroupValues = children.reduce(
(acc: string[], checkboxOption: CheckboxOption) => {
const {value, isDisabled} = checkboxOption;
if (!isDisabled) {
return [...acc, String(value)];
}
return acc;
},
[]
);
setFieldValue(name, enabledGroupValues);
};
const childrenToCheckboxGroupItems = () => {
const providedCheckboxItems = children.map((checkboxOption) => {
const {label, value, isDisabled, inputProps} = checkboxOption;
return (
<SQFormCheckboxGroupItem
groupName={name}
label={label}
value={value}
isRowDisplay={shouldDisplayInRow}
onChange={handleChange}
isDisabled={isDisabled}
inputProps={inputProps}
key={`SQFormCheckboxGroupItem_${value}`}
/>
);
});
if (shouldUseSelectAll) {
return [
<SQFormCheckbox
name={`${name}SelectAll`}
label="All"
onChange={handleSelectAllChange}
key={`${name}_selectAll`}
/>,
...providedCheckboxItems,
];
}
return providedCheckboxItems;
};
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>
<FormGroup row={shouldDisplayInRow}>
{childrenToCheckboxGroupItems()}
</FormGroup>
<FormHelperText>{HelperTextComponent}</FormHelperText>
</FormControl>
</Grid>
);
}
Example #20
Source File: Game.tsx From Lux-Viewer-2021 with Apache License 2.0 | 4 votes |
GameComponent = () => { const [notifWindowOpen, setNotifWindowOpen] = useState(false); const [replayData, setReplayData] = useState(null); const [notifMsg, setNotifMsg] = useState(''); const [running, setRunning] = useState(false); const [useKaggleReplay, setUseKaggleReplay] = useState(true); const [playbackSpeed, _setPlaybackSpeed] = useState(1); const [replayVersion, setReplayVersion] = useState(''); const [warningMessage, setWarningMessage] = useState(''); const setPlaybackSpeed = (speed: number) => { if (speed >= 0.5 && speed <= 32) { _setPlaybackSpeed(speed); main.speed = speed; } }; const url = new URL(window.location.href); const searchlist = url.search.slice(1).split('&'); let scale = searchlist.length > 0 && searchlist[0].split('=')[0] === 'scale' ? parseFloat(searchlist[0].split('=')[1]) : 1.5; if (isNaN(scale)) { scale = 1.5; } let zoom = 1 / scale; let scaleSize = scale / 10; const [visualScale, _setVisualScale] = useState(scale / 4); const setVisualScale = (scale: number) => { if (scale >= scaleSize && scale <= 2) { _setVisualScale(scale); } }; const [isReady, setReady] = useState(false); const [warningsPanelOpen, setWarningsPanelOpen] = useState(false); const [selectedTileData, setTileData] = useState<FrameTileData>(null); const [trackedUnitID, setTrackedUnitID] = useState<string>(null); const [game, setGame] = useState<Phaser.Game>(null); const [main, setMain] = useState<MainScene>(null); const [configs, setConfigs] = useState<LuxMatchConfigs>(null); const [sliderConfigs, setSliderConfigs] = useState({ step: 1, min: 0, max: 1000, }); const [turn, setTurn] = useState(0); const [currentFrame, setFrame] = useState<Frame>(null); const [uploading, setUploading] = useState(false); const fileInput = React.createRef<HTMLInputElement>(); // If the game changes, put a setup callback to set up controller configs useEffect(() => { if (game) { game.events.on('setup', () => { // @ts-ignore const main: MainScene = game.scene.scenes[0]; setMain(main); const configs = main.luxgame.configs; setConfigs(configs as LuxMatchConfigs); setSliderConfigs({ min: 0, max: Math.min(configs.parameters.MAX_DAYS, main.frames.length - 1), step: 1, }); setReady(true); }); } }, [game]); // If play is toggled (running) or playback speed is changed, we update the playback useEffect(() => { if (running && configs) { let currTurn = turn; const interval = setInterval(() => { if ( currTurn >= Math.min(configs.parameters.MAX_DAYS, main.frames.length - 1) ) { setRunning(false); return; } currTurn += 1; moveToTurn(currTurn); setTurn(currTurn); }, 1000 / playbackSpeed); return () => clearInterval(interval); } }, [running, playbackSpeed]); // if game loaded is ready, move to turn 0 and load that turn's frame useEffect(() => { if (isReady) { moveToTurn(0); } }, [isReady]); // whenever the main scene is changed or visualScale is changed, call main to change the visual scale appropriately. useEffect(() => { if (main && visualScale) { main.overallScale = visualScale; if (main.activeImageTile) { // main.activeImageTile.setY(main.originalTileY); // main.activeImageTile.clearTint(); // main.activeImageTile = null; // main.originalTileY } // move to current turn to rerender all objects appropriately moveToTurn(turn); // TODO: do a on scale change instead inside main main.floorImageTiles.forEach((info, hash) => { [info.source, info.overlay, info.roadOverlay].forEach( (tileImage, i) => { const pos = hashToMapPosition(hash); const ps = mapCoordsToIsometricPixels(pos.x, pos.y, { scale: main.overallScale, width: main.mapWidth, height: main.mapHeight, }); tileImage.setScale(main.defaultScales.block * main.overallScale); tileImage.setX(ps[0]); tileImage.setY(ps[1]); if (tileImage == main.activeImageTile) { main.originalTileY = tileImage.y; } if (tileImage == main.hoverImageTile) { main.originalHoverImageTileY = tileImage.y; } } ); }); const ps = mapCoordsToIsometricPixels( main.mapWidth / 2, main.mapWidth / 2, { scale: main.overallScale, width: main.mapWidth, height: main.mapHeight, } ); // [main.islandbaseImage, main.islandbaseNightImage].forEach((tileImage) => { // tileImage.setX(ps[0]); // let f = 32.3; // if (main.mapWidth <= 16) f = 31.7; // tileImage.setY(ps[1] + main.overallScale * main.mapWidth * f); // tileImage.setScale( // main.defaultScales.islandBase * main.overallScale * main.mapWidth // ); // }); } }, [main, visualScale]); /** handle the change of the slider to move turns */ const handleSliderChange = (_event: any, newValue: number) => { setRunning(false); moveToTurn(newValue); }; /** Move to a specific turn and render that turn's frame */ const moveToTurn = (turn: number) => { setTurn(turn); main.renderFrame(turn); setFrame(main.frames[turn]); //render the right bg color const colors = [ '00AFBD', '438D91', '846D68', 'A55D53', '704A60', '4D3D59', '2C2E33', ]; const canvasWrapper = document .getElementById('content') .getElementsByTagName('canvas')[0]; const dayLength = main.luxgame.configs.parameters.DAY_LENGTH; const cycleLength = dayLength + main.luxgame.configs.parameters.NIGHT_LENGTH; let idx = 0; if ( turn % cycleLength >= dayLength - 5 && turn % cycleLength < dayLength + 1 ) { idx = (turn % cycleLength) - (dayLength - 5); } else if ( turn % cycleLength >= dayLength + 1 && turn % cycleLength < cycleLength - 1 ) { idx = 6; } else if (turn % cycleLength >= cycleLength - 1) { idx = 5; } else if (turn % cycleLength < 5 && turn > 5) { idx = 6 - ((turn % cycleLength) + 2); } canvasWrapper.style.transition = `background-color linear ${ 1 / main.speed }s`; canvasWrapper.style.backgroundColor = `#${colors[idx]}`; }; /** track a unit by id */ const trackUnit = (id: string) => { setTrackedUnitID(id); main.untrackUnit(); main.trackUnit(id); }; const untrackUnit = (id: string) => { setTrackedUnitID(null); main.untrackUnit(true); }; /** load game given json replay data */ const loadGame = (jsonReplayData: any) => { let versionMisMatch = false; let versionvals = ['x', 'x']; setReplayVersion(jsonReplayData.version); if (jsonReplayData.version !== undefined) { versionvals = jsonReplayData.version.split('.'); if ( versionvals[0] !== clientConfigs.version[0] || versionvals[1] !== clientConfigs.version[2] ) { versionMisMatch = true; } } if (versionMisMatch) { let warningMessage = `Replay file works on version ${versionvals[0]}.${versionvals[1]}.x but client is on version ${clientConfigs.version}. The visualizer will not be able to parse this replay file. Download an older visualizer with version ${versionvals[0]}.${versionvals[1]}.x here to watch the replay: https://github.com/Lux-AI-Challenge/LuxViewer2021/releases`; setWarningMessage(warningMessage); return; } if (game) { game.destroy(true, false); } setReady(false); setReplayData(jsonReplayData); const newgame = createGame({ replayData: jsonReplayData, handleTileClicked, handleUnitTracked, zoom, }); setGame(newgame); }; /** handle uploaded files */ const handleUpload = () => { setUploading(true); setUseKaggleReplay(false); if (fileInput.current.files.length) { const file = fileInput.current.files[0]; const name = file.name; const meta = name.split('.'); if (meta[meta.length - 1] === 'json') { file .text() .then(JSON.parse) .then((data) => { setUploading(false); data = parseReplayData(data); loadGame(data); }) .catch((err) => { console.error(err); alert(err); }); } } }; useEffect(() => { //@ts-ignore if (window.kaggle) { // check if window.kaggle.environment is valid and usable if ( //@ts-ignore window.kaggle.environment && //@ts-ignore window.kaggle.environment.steps.length > 1 ) { console.log('Embedded kaggle replay detected, parsing it'); //@ts-ignore let replay = window.kaggle.environment; replay = parseReplayData(replay); loadGame(replay); } else { console.log( 'Kaggle detected, but no replay, listening for postMessage' ); // add this listener only once window.addEventListener( 'message', (event) => { // Ensure the environment names match before updating. try { if (event.data.environment.name == 'lux_ai_2021') { // updateContext(event.data); let replay = event.data.environment; console.log('post message:'); console.log(event.data); replay = parseReplayData(replay); loadGame(replay); const el = document.getElementsByTagName('html'); if (window.innerWidth * 0.65 <= 768) { el[0].style.fontSize = '6pt'; } if (window.innerWidth * 0.65 <= 1280) { el[0].style.fontSize = '8pt'; } } } catch (err) { console.error('Could not parse game'); console.error(err); } }, false ); } } // change root font size depending on window size const el = document.getElementsByTagName('html'); if (window.innerWidth <= 768) { // set the font size of root html smaller since this is being viewed on the kaggle page el[0].style.fontSize = '6pt'; } else if (window.innerWidth <= 1280) { el[0].style.fontSize = '8pt'; } // loadGame(parseReplayData(debug_replay)); }, []); useEffect(() => { const handleKeyDown = (event: globalThis.KeyboardEvent) => { switch (event.key) { case 'ArrowUp': setPlaybackSpeed(playbackSpeed * 2); break; case 'ArrowDown': setPlaybackSpeed(playbackSpeed / 2); break; case 'ArrowRight': setRunning(false); if ( turn < Math.min(configs.parameters.MAX_DAYS, main.frames.length - 1) ) { moveToTurn(turn + 1); } break; case 'ArrowLeft': setRunning(false); if (turn > 0) { moveToTurn(turn - 1); } break; } }; document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [turn, playbackSpeed, main, configs]); const handleTileClicked = (data: FrameTileData) => { setTileData(data); // deal with unit tracking, which unfortunately has data fragmented between react and the phaser scene }; const handleUnitTracked = (id: string) => { setTrackedUnitID(id); }; const [debugOn, _setDebug] = useState(true); const setDebug = ( e: React.ChangeEvent<HTMLInputElement>, checked: boolean ) => { _setDebug(checked); main.debug = checked; moveToTurn(turn); }; const renderDebugModeButton = () => { return ( <FormGroup row className="debug-mode-button-wrapper"> <FormControlLabel control={ <Switch checked={debugOn} onChange={setDebug} name="checkedA" /> } label="Debug Mode" /> </FormGroup> ); }; let sidetextAnnotations = []; if (currentFrame && currentFrame.annotations) { sidetextAnnotations = currentFrame.annotations.filter((v) => { return ( v.command.length > 2 && v.command.split(' ')[0] === Game.ACTIONS.DEBUG_ANNOTATE_SIDETEXT ); }); } return ( <div className="Game"> <ThemeProvider theme={theme}> <div id="content"></div> {!isReady && warningMessage === '' && ( <div className="upload-no-replay-wrapper"> <p>Welcome to the Lux AI Season 1 Visualizer</p> <div> <Button className="upload-btn" color="secondary" variant="contained" onClick={() => { fileInput.current.click(); }} > <span className="upload-text">Upload a replay</span> <img className="upload-icon-no-replay" src={UploadSVG} /> </Button> <p></p> <input accept=".json, .luxr" type="file" style={{ display: 'none' }} onChange={handleUpload} ref={fileInput} /> </div> </div> )} {warningMessage !== '' && ( <div className="upload-no-replay-wrapper"> <p>{warningMessage}</p> </div> )} <div id="version-number"> {replayVersion && ( <> <strong>Replay Version: </strong> {replayVersion} <br></br> </> )} <strong>Client Version: </strong> {clientConfigs.version} </div> {isReady && ( <div> <Controller turn={turn} moveToTurn={moveToTurn} handleUpload={handleUpload} running={running} isReady={isReady} setRunning={setRunning} playbackSpeed={playbackSpeed} setPlaybackSpeed={setPlaybackSpeed} fileInput={fileInput} sliderConfigs={sliderConfigs} handleSliderChange={handleSliderChange} /> {debugOn && sidetextAnnotations.length > 0 && ( <div className="debug-sidetext"> <h4>Debug Text</h4> {sidetextAnnotations .sort((v) => v.agentID) .map((v) => { return ( <div className={`sidetext-${v.agentID}`}> {v.command.split(' ').slice(1).join(' ').split("'")[1]} </div> ); })} </div> )} <Button className="warnings-button" onClick={() => { setWarningsPanelOpen(true); }} > Warnings ({currentFrame.errors.length}) </Button> <WarningsPanel panelOpen={warningsPanelOpen} closePanel={() => { setWarningsPanelOpen(false); }} turn={turn} warnings={currentFrame.errors} /> <div className="tile-stats-wrapper"> {selectedTileData && ( <TileStats {...selectedTileData} cities={currentFrame.cityData} trackUnit={trackUnit} untrackUnit={untrackUnit} trackedUnitID={trackedUnitID} /> )} </div> <div className="global-stats-wrapper"> {main && ( <GlobalStats currentFrame={currentFrame} turn={turn} accumulatedStats={main.accumulatedStats} teamDetails={replayData.teamDetails} staticGlobalStats={main.globalStats} /> )} </div> {renderDebugModeButton()} <ZoomInOut className="zoom-in-out" handleZoomIn={() => { setVisualScale(visualScale + scaleSize); }} handleZoomOut={() => { setVisualScale(visualScale - scaleSize); }} /> <div className="map-meta-wrapper"> <p> <strong>Map Size:</strong>{' '} {(main.pseudomatch.state.game as Game).map.width}x {(main.pseudomatch.state.game as Game).map.height} </p> <p> <strong>Map Seed:</strong>{' '} {(main.pseudomatch.state.game as Game).configs.seed} </p> </div> </div> )} </ThemeProvider> </div> ); }
Example #21
Source File: Content.tsx From Demae with MIT License | 4 votes |
Form = ({ provider }: { provider: ProviderDraft }) => {
const classes = useStyles()
const [setProcessing] = useProcessing()
const [setMessage] = useSnackbar()
const [thumbnail, setThumbnail] = useState<File | undefined>()
const [cover, setCover] = useState<File | undefined>()
const [name] = useTextField(provider.name)
const [caption] = useTextField(provider.caption)
const [description] = useTextField(provider.description)
const providerCapabilities = provider.capabilities || []
const [capabilities, setCapabilities] = useState<{ [key in Capability]: boolean }>({
"download": providerCapabilities.includes("download"),
"instore": providerCapabilities.includes("instore"),
"online": providerCapabilities.includes("online"),
"pickup": providerCapabilities.includes("pickup")
})
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setCapabilities({ ...capabilities, [event.target.name]: event.target.checked });
};
const capabilitiesError = Object.values(capabilities).filter((v) => v).length < 1;
const uploadThumbnail = (file: File): Promise<StorageFile | undefined> => {
const ref = firebase.storage().ref(provider.documentReference.path + "/thumbnail.jpg")
return new Promise((resolve, reject) => {
ref.put(file).then(async (snapshot) => {
if (snapshot.state === "success") {
const storageFile = new StorageFile()
if (snapshot.metadata.contentType) {
storageFile.mimeType = snapshot.metadata.contentType
}
storageFile.path = ref.fullPath
resolve(storageFile)
} else {
reject(undefined)
}
})
})
}
const uploadCover = (file: File): Promise<StorageFile | undefined> => {
const ref = firebase.storage().ref(provider.documentReference.path + "/cover.jpg")
return new Promise((resolve, reject) => {
ref.put(file).then(async (snapshot) => {
if (snapshot.state === "success") {
const storageFile = new StorageFile()
if (snapshot.metadata.contentType) {
storageFile.mimeType = snapshot.metadata.contentType
}
storageFile.path = ref.fullPath
resolve(storageFile)
} else {
reject(undefined)
}
})
})
}
const [isEditing, setEdit] = useEdit(async (event) => {
event.preventDefault()
if (!provider) return
setProcessing(true)
if (thumbnail) {
const thumbnailImage = await uploadThumbnail(thumbnail)
if (thumbnailImage) {
provider.thumbnailImage = thumbnailImage
}
}
if (cover) {
const coverImage = await uploadCover(cover)
if (coverImage) {
provider.coverImage = coverImage
}
}
try {
provider.name = name.value as string
provider.caption = caption.value as string
provider.description = description.value as string
provider.capabilities = Object.keys(capabilities).filter(value => capabilities[value]) as Capability[]
await provider.save()
} catch (error) {
console.log(error)
}
setProcessing(false)
setMessage("success", "Change your provider informations.")
setEdit(false)
})
useContentToolbar(() => {
if (!provider) return <></>
if (isEditing) {
return (
<Box display="flex" flexGrow={1} justifyContent="space-between" paddingX={1}>
<Button variant="outlined" color="primary" size="small" onClick={() => setEdit(false)}>Cancel</Button>
<Button variant="contained" color="primary" size="small" type="submit" disabled={capabilitiesError}
>Save</Button>
</Box>
)
}
return (
<Box display="flex" flexGrow={1} justifyContent="space-between" paddingX={1}>
<Box display="flex" flexGrow={1} justifyContent="flex-end">
<Button variant="outlined" color="primary" size="small" onClick={() => setEdit(true)}>Edit</Button>
</Box>
</Box>
)
})
if (isEditing) {
return (
<Container maxWidth="sm">
<Box padding={2}>
<Typography variant="h1" gutterBottom>Shop</Typography>
<Paper>
<Box display="flex" position="relative" flexGrow={1}>
<Box display="flex" flexGrow={1} height={300}>
<DndCard
url={provider?.coverImageURL()}
onDrop={(files) => {
const file = files[0] as File
setCover(file)
}} />
</Box>
<Box display="flex" position="absolute" zIndex={1050} flexGrow={1} width={120} height={120} border={2} borderColor="white" borderRadius="50%" bottom={-16} left={16} style={{ overflow: "hidden" }}>
<DndCard
url={provider?.thumbnailImageURL()}
onDrop={(files) => {
const file = files[0] as File
setThumbnail(file)
}} />
</Box>
</Box>
<Box padding={2} paddingTop={5}>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Name</Typography>
<TextField variant="outlined" margin="dense" required {...name} fullWidth />
</Box>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Caption</Typography>
<TextField variant="outlined" margin="dense" required {...caption} fullWidth />
</Box>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Description</Typography>
<TextField variant="outlined" margin="dense" required fullWidth multiline rows={8} {...description} />
</Box>
</Box>
<Box paddingX={2} paddingBottom={1}>
<Typography variant="subtitle1" gutterBottom>Sales method</Typography>
<FormControl required error={capabilitiesError} component="fieldset">
<FormLabel component="legend">Please select at least one selling method</FormLabel>
<FormGroup>
<FormControlLabel
control={<Checkbox checked={capabilities.download} onChange={handleChange} name="download" />}
label="Download"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.instore} onChange={handleChange} name="instore" />}
label="In-Store Sales"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.online} onChange={handleChange} name="online" />}
label="Online Sales"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.pickup} onChange={handleChange} name="pickup" />}
label="Pickup"
/>
</FormGroup>
<FormHelperText>You can choose multiple sales methods.</FormHelperText>
</FormControl>
</Box>
</Paper>
<Box padding={1}>
<Typography variant="body2" color="textSecondary" gutterBottom>ID: {provider.id}</Typography>
</Box>
</Box>
</Container>
)
}
return (
<Container maxWidth="sm">
<Box padding={2}>
<Typography variant="h1" gutterBottom>Shop</Typography>
<Paper>
<Box display="flex" position="relative" flexGrow={1}>
<Box display="flex" flexGrow={1} height={300}>
<Avatar variant="square" src={provider.coverImageURL()} style={{
minHeight: "300px",
width: "100%"
}}>
<ImageIcon />
</Avatar>
</Box>
<Box display="flex" position="absolute" zIndex={1050} flexGrow={1} width={120} height={120} border={2} borderColor="white" borderRadius="50%" bottom={-16} left={16} style={{ overflow: "hidden" }}>
<Avatar variant="square" src={provider.thumbnailImageURL()} style={{
minHeight: "64px",
height: "100%",
width: "100%"
}}>
<ImageIcon />
</Avatar>
</Box>
</Box>
<Box padding={2} paddingTop={5}>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Name</Typography>
<Typography variant="body1" gutterBottom>{provider.name}</Typography>
</Box>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Caption</Typography>
<Typography variant="body1" gutterBottom>{provider.caption}</Typography>
</Box>
<Box paddingBottom={2}>
<Typography variant="subtitle1" gutterBottom>Description</Typography>
<Typography variant="body1" gutterBottom>{provider.description}</Typography>
</Box>
</Box>
<Box paddingX={2} paddingBottom={1}>
<Typography variant="subtitle1" gutterBottom>Sales method</Typography>
<FormControl disabled component="fieldset">
<FormGroup>
<FormControlLabel
control={<Checkbox checked={capabilities.download} onChange={handleChange} name="download" />}
label="Download"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.instore} onChange={handleChange} name="instore" />}
label="In-Store Sales"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.online} onChange={handleChange} name="online" />}
label="Online Sales"
/>
<FormControlLabel
control={<Checkbox checked={capabilities.pickup} onChange={handleChange} name="pickup" />}
label="Pickup"
/>
</FormGroup>
</FormControl>
</Box>
</Paper>
<Box padding={1}>
<Typography variant="body2" color="textSecondary" gutterBottom>ID: {provider.id}</Typography>
</Box>
</Box>
</Container>
)
}