reactstrap#Label TypeScript Examples
The following examples show how to use
reactstrap#Label.
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: Select.tsx From opensaas with MIT License | 6 votes |
Select: React.FC<SelectProps> = (props) => {
const { label, name, valid = false, signature, className, options = [] } = props;
return (
<div className={className}>
<Label className='form-check-label mr-sm-2'>{label}</Label>
<select
className={classNames('form-control', 'form-input', 'mb-2', 'mr-sm-2', {
'border-green-500': valid,
'border-red-500': !valid,
})}
name={name}>
{options.map((option: OptionType, i: number) => {
return (
<option value={option.value} key={i}>
{option.label}
</option>
);
})}
</select>
<div
className={classNames('text-xs', 'mr-sm-2', {
'text-green-500': valid,
'text-red-500': !valid,
})}>
{signature}
</div>
</div>
);
}
Example #2
Source File: CheckBox.tsx From opensaas with MIT License | 6 votes |
CheckBox: React.FC<CheckBoxProps> = (props) => {
const { label, name, valid = false, placeholder, signature, className, values } = props;
return (
<div className={className}>
<div>
<Label>{label}</Label>
</div>
{values.map((value: string, i: number) => (
<div className='custom-control custom-control-inline custom-checkbox' key={i}>
<Input
className={classNames('form-input', 'custom-control-input', {
'border-green-500 is-valid': valid,
'border-red-500 is-invalid': !valid,
})}
placeholder={placeholder}
type='checkbox'
name={name}
value={value}
id={name + i + value}
/>
<Label className='form-check-label custom-control-label' htmlFor={name + i + value}>
{value}
</Label>
</div>
))}
<div
className={classNames('text-xs', {
'text-green-500': valid,
'text-red-500': !valid,
})}>
{signature}
</div>
</div>
);
}
Example #3
Source File: Input.tsx From opensaas with MIT License | 6 votes |
Input: React.FC<InputProps> = (props) => {
const { label, name, valid = false, placeholder, className, inline = false, signature, type = 'text' } = props;
const borderClassNames = classNames('form-input', 'mb-2', 'mr-sm-2', {
'border-green-500': valid,
'border-red-500': !valid,
});
const textClassNames = classNames('text-xs', 'mr-sm-2', {
'text-green-500': valid,
'text-red-500': !valid,
});
return (
<div className={classNames('input-field', className)}>
{inline ? (
<div className='form-inline'>
<Label className='form-check-label mr-sm-2'>{label}</Label>
<ReactstrapInput className={borderClassNames} placeholder={placeholder} type={type} name={name} />
<div className={textClassNames}>{signature}</div>
</div>
) : (
<>
<Label className='form-check-label mr-sm-2'>{label}</Label>
<ReactstrapInput className={borderClassNames} placeholder={placeholder} type={type} name={name} />
<div className={textClassNames}>{signature}</div>
</>
)}
</div>
);
}
Example #4
Source File: source_selector.tsx From website with Apache License 2.0 | 5 votes |
/**
* Gets the element for a single source option
*/
function getSourceOptionJsx(
svInfo: SourceSelectorSvInfo,
metahash: string,
modalSelections: Record<string, string>,
setModalSelections: (selections: Record<string, string>) => void
): JSX.Element {
const metadata = svInfo.metadataMap[metahash] || {};
let sourceTitle = getSourceTitle(metadata);
if (svInfo.displayNames && metahash in svInfo.displayNames) {
sourceTitle = svInfo.displayNames[metahash];
}
return (
<FormGroup radio="true" row key={svInfo.dcid + metahash}>
<Label radio="true" className={`${SELECTOR_PREFIX}-option`}>
<div className={`${SELECTOR_PREFIX}-option-title`}>
<Input
type="radio"
name={svInfo.dcid}
defaultChecked={svInfo.metahash === metahash}
onClick={() => {
setModalSelections({
...modalSelections,
[svInfo.dcid]: metahash,
});
}}
/>
<div>{sourceTitle}</div>
</div>
<div className={`${SELECTOR_PREFIX}-option-details`}>
{metadata.importName && <div>importName: {metadata.importName}</div>}
{metadata.measurementMethod && (
<div>measurementMethod: {metadata.measurementMethod}</div>
)}
{metadata.observationPeriod && (
<div>observationPeriod: {metadata.observationPeriod}</div>
)}
{metadata.scalingFactor && (
<div>scalingFactor: {metadata.scalingFactor}</div>
)}
{metadata.unit && <div>unit: {metadata.unit}</div>}
</div>
</Label>
</FormGroup>
);
}
Example #5
Source File: TabPanelUrl.tsx From nextclade with MIT License | 5 votes |
export function TabPanelUrl({ exampleUrl, onConfirm, inputRef }: TabPanelUrlProps) {
const { t } = useTranslationSafe()
const [url, setUrl] = useState<string>('')
const hasUrl = url.length > 0
const change = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { setUrl(e.target.value) }, []) // prettier-ignore
const clear = useCallback(() => { setUrl('') }, []) // prettier-ignore
const confirm = useCallback(() => { onConfirm(url) }, [onConfirm, url]) // prettier-ignore
const placeholder = useMemo(() => t('For example: {{exampleUrl}}', { exampleUrl }), [t, exampleUrl])
const instructions = t('Enter URL to a file to fetch')
return (
<Form>
<Row noGutters className="w-100 h-100">
<Col className="w-100 h-100 d-flex flex-column">
<Label className="w-100 h-100 d-flex flex-column flex-1">
<span className="w-100 flex-grow-0">{instructions}</span>
<TextInputMonospace
className="w-100 flex-grow-1"
type="textarea"
placeholder={placeholder}
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
data-gramm="false"
wrap="hard"
data-gramm_editor="false"
value={url}
onChange={change}
innerRef={inputRef}
/>
</Label>
<Footnote>{t('*Make sure this file is publicly accessible and CORS is enabled on your server')}</Footnote>
<ButtonContainer>
<Button
className="mr-auto"
disabled={!hasUrl}
type="button"
color="link"
title={t('Clear the URL text field')}
onClick={clear}
>
{t('Clear')}
</Button>
<ButtonStyled
className="ml-auto"
disabled={!hasUrl}
type="button"
color="primary"
title={hasUrl ? 'Start downloading this file' : 'Provide a URL before downloading is possible'}
onClick={confirm}
>
{t('OK')}
</ButtonStyled>
</ButtonContainer>
</Col>
</Row>
</Form>
)
}
Example #6
Source File: TabPanelPaste.tsx From nextclade with MIT License | 5 votes |
export function TabPanelPaste({ onConfirm, instructions, inputRef }: TabPanelPasteProps) {
const { t } = useTranslationSafe()
const [seqData, setSeqData] = useState<string>('')
const hasSeqData = seqData.length > 0
const change = useCallback((e: React.ChangeEvent<HTMLInputElement>) => { setSeqData(e.target.value) }, []) // prettier-ignore
const clear = useCallback(() => { setSeqData('') }, []) // prettier-ignore
const confirm = useCallback(() => { onConfirm(seqData) }, [onConfirm, seqData]) // prettier-ignore
return (
<Form>
<Row noGutters className="w-100 h-100">
<Col className="w-100 h-100 d-flex flex-column">
<Label className="w-100 h-100 d-flex flex-column flex-1">
<span className="w-100 flex-grow-0">{instructions}</span>
<TextInputMonospace
className="w-100 flex-grow-1"
type="textarea"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
data-gramm="false"
wrap="hard"
data-gramm_editor="false"
value={seqData}
onChange={change}
innerRef={inputRef}
/>
</Label>
<ButtonContainer>
<Button
className="mr-auto"
disabled={!hasSeqData}
type="button"
color="link"
title={t('Clear the text field')}
onClick={clear}
>
{t('Clear')}
</Button>
<ButtonStyled
className="ml-auto"
disabled={!hasSeqData}
type="button"
color="primary"
title={hasSeqData ? t('Accept the data') : t('Please provide the data first')}
onClick={confirm}
>
{t('OK')}
</ButtonStyled>
</ButtonContainer>
</Col>
</Row>
</Form>
)
}
Example #7
Source File: Radio.tsx From opensaas with MIT License | 5 votes |
Radio: React.FC<RadioProps> = (props) => {
const { label, name, valid = false, placeholder, signature, className, values } = props;
return (
<div className={className}>
<div>
<Label>{label}</Label>
</div>
{values.map((value: string, i: number) => (
<div className='custom-control custom-control-inline custom-radio' key={i}>
<Input
className={classNames('form-check-input', 'custom-control-input', {
'border-green-500': valid,
'border-red-500': !valid,
})}
placeholder={placeholder}
type='radio'
name={name}
value={value}
id={name + i + value}
/>
<Label
className={classNames('form-check-label', 'custom-control-label', {
'text-green-500': valid,
'text-red-500': !valid,
})}
htmlFor={name + i + value}>
{value}
</Label>
</div>
))}
<div
className={classNames('text-xs', {
'text-green-500': valid,
'text-red-500': !valid,
})}>
{signature}
</div>
</div>
);
}
Example #8
Source File: tool_chart_footer.tsx From website with Apache License 2.0 | 5 votes |
export function ToolChartFooter(props: ToolChartFooterPropType): JSX.Element {
const mMethods = !_.isEmpty(props.mMethods)
? Array.from(props.mMethods).join(", ")
: "";
const ratioCheckboxId = props.chartId + "-ratio";
const [chartOptionsOpened, setChartOptionsOpened] = useState(true);
return (
<>
<div
className={`${SELECTOR_PREFIX}-container ${
chartOptionsOpened ? "no-bottom-border" : ""
}`}
>
<div className={`${SELECTOR_PREFIX}-metadata-section`}>
{!_.isEmpty(props.sources) && (
<div className={`${SELECTOR_PREFIX}-metadata`}>
<span>Data from {getSourcesJsx(props.sources)}</span>
</div>
)}
{!_.isEmpty(mMethods) && (
<div className={`${SELECTOR_PREFIX}-metadata`}>
<span>{`Measurement method${
props.mMethods.size > 1 ? "s" : ""
}: ${mMethods}`}</span>
</div>
)}
</div>
<div
onClick={() => setChartOptionsOpened(!chartOptionsOpened)}
className={`${SELECTOR_PREFIX}-options-button`}
>
<span>Chart Options</span>
{chartOptionsOpened ? UP_ARROW_HTML : DOWN_ARROW_HTML}
</div>
</div>
{chartOptionsOpened && (
<div className={`${SELECTOR_PREFIX}-options-section`}>
{!props.hideIsRatio && (
<span className="chart-option">
<FormGroup check>
<Label check>
<Input
id={ratioCheckboxId}
type="checkbox"
checked={props.isPerCapita}
onChange={() =>
props.onIsPerCapitaUpdated(!props.isPerCapita)
}
/>
Per Capita
</Label>
</FormGroup>
</span>
)}
{props.children}
<SourceSelector
svInfoList={props.sourceSelectorSvInfoList}
onSvMetahashUpdated={props.onSvMetahashUpdated}
/>
</div>
)}
<div className="feedback-link">
<a href={FEEDBACK_LINK}>Feedback</a>
</div>
</>
);
}
Example #9
Source File: chart.tsx From website with Apache License 2.0 | 5 votes |
render(): JSX.Element {
const statVars = Object.keys(this.props.statVarInfos);
// TODO(shifucun): investigate on stats var title, now this is updated
// several times.
this.plotParams = computePlotParams(
this.props.placeNames,
statVars,
this.props.statVarInfos
);
// Stats var chip color is independent of places, so pick one place to
// provide a key for style look up.
const placeName = Object.values(this.props.placeNames)[0];
const deltaCheckboxId = `delta-cb-${this.props.mprop}`;
const sourceSelectorSvInfoList = this.getSourceSelectorSvInfo(statVars);
return (
<div className="chart-container">
<div className="card">
<div className="statVarChipRegion">
{statVars.map((statVar) => {
let color: string;
if (statVars.length > 1) {
color = this.plotParams.lines[placeName + statVar].color;
}
return (
<Chip
key={statVar}
id={statVar}
title={this.props.statVarInfos[statVar].title}
color={color}
removeChip={this.props.removeStatVar}
onTextClick={() => window.open(`/tools/statvar#${statVar}`)}
/>
);
})}
</div>
<div ref={this.svgContainer} className="chart-svg"></div>
</div>
<ToolChartFooter
chartId={this.props.mprop}
sources={
this.state.statData ? this.state.statData.sources : new Set()
}
mMethods={
this.state.statData
? this.state.statData.measurementMethods
: new Set()
}
sourceSelectorSvInfoList={sourceSelectorSvInfoList}
onSvMetahashUpdated={(svMetahashMap) => setMetahash(svMetahashMap)}
hideIsRatio={false}
isPerCapita={this.props.pc}
onIsPerCapitaUpdated={(isPerCapita: boolean) =>
setChartOption(this.props.mprop, "pc", isPerCapita)
}
>
<span className="chart-option">
<FormGroup check>
<Label check>
<Input
id={deltaCheckboxId}
className="is-delta-input"
type="checkbox"
checked={this.props.delta}
onChange={() =>
setChartOption(this.props.mprop, "delta", !this.props.delta)
}
/>
Delta
</Label>
</FormGroup>
</span>
</ToolChartFooter>
</div>
);
}
Example #10
Source File: SystemSettings.tsx From nextclade with MIT License | 4 votes |
export function SystemSettings() {
const { t } = useTranslationSafe()
const [numThreads, setNumThreads] = useRecoilState(numThreadsAtom)
const resetNumThreads = useResetRecoilState(numThreadsAtom)
const guess = useGuessNumThreads(numThreads)
const handleValidate = useCallback((values: SettingsFormValues): FormikErrors<SettingsFormValues> => {
const errors: FormikErrors<SettingsFormValues> = {}
const { numThreads } = values
if (!Number.isInteger(numThreads) || numThreads < 0 || numThreads > 1000) {
errors.numThreads = 'Should be a positive integer from 1 to 1000'
}
return errors
}, [])
const setNumThreadsDebounced = useMemo(
() => debounce(setNumThreads, 500, { leading: false, trailing: true }), // prettier-ignore
[setNumThreads],
)
const handleSubmit = useCallback(
(values: SettingsFormValues, { setSubmitting }: FormikHelpers<SettingsFormValues>) => {
setNumThreadsDebounced(values.numThreads)
setSubmitting(false)
},
[setNumThreadsDebounced],
)
const initialValues = useMemo(() => ({ numThreads }), [numThreads])
const onReset = useCallback(() => ({ numThreads }), [numThreads])
const memoryAvailable = useMemo(() => {
return guess.memoryAvailable ? prettyBytes.format(guess.memoryAvailable) : t('unsupported')
}, [guess.memoryAvailable, t])
const memoryAvailablePerThread = useMemo(() => {
return guess.memoryAvailable ? prettyBytes.format(guess.memoryAvailable / numThreads) : t('unsupported')
}, [guess.memoryAvailable, numThreads, t])
return (
<Formik initialValues={initialValues} validate={handleValidate} onSubmit={handleSubmit} onReset={onReset}>
{({ values, errors, touched, handleChange, handleBlur, resetForm }) => (
<Form>
<FormikAutoSubmit />
<FormGroup>
<Label className="d-block w-100">
<NumericInput
id="numThreads"
min={1}
max={1000}
className={classNames('d-inline', errors?.numThreads && 'border-danger')}
type="number"
identifier="settings-num-threads-input"
value={values.numThreads}
onChange={handleChange}
onBlur={handleBlur}
/>
<span className="d-inline">
<span className="mx-3">{t('Number of CPU threads')}</span>
<span className="mx-auto">
<ButtonTransparent
className="my-0"
type="button"
title={t('Reset to default')}
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
onClick={() => {
resetNumThreads()
resetForm()
}}
>
<MdRefresh /> {t('Reset')}
</ButtonTransparent>
</span>
</span>
{touched.numThreads && errors?.numThreads && <p className="text-danger">{errors.numThreads}</p>}
{guess.numThreads && guess.memoryAvailable && (
<Alert className="mt-2 p-1" color="primary" isOpen fade={false}>
<TableSlim borderless className="small mb-1">
<tbody>
<tr>
<td>{t('Memory available*')}</td>
<td>{memoryAvailable}</td>
</tr>
<tr>
<td>{t('Memory per CPU thread')}</td>
<td>{memoryAvailablePerThread}</td>
</tr>
<tr>
<td>{t('Recommended number of CPU threads**')}</td>
<td>{guess.numThreads ?? t('unsupported')}</td>
</tr>
<tr>
<td colSpan={2} className="small">
{t('* Current value. This amount can change depending on load')}
</td>
</tr>
<tr>
<td colSpan={2} className="small">
{t('** {{appName}} requires at least {{memoryRequired}} of memory per thread', {
appName: PROJECT_NAME,
memoryRequired: prettyBytes.format(MEMORY_BYTES_PER_THREAD_MINIMUM),
})}
</td>
</tr>
</tbody>
</TableSlim>
</Alert>
)}
</Label>
</FormGroup>
</Form>
)}
</Formik>
)
}
Example #11
Source File: FeedbackForm.tsx From TutorBase with MIT License | 4 votes |
export default function FeedbackForm({apptTutorId}: IProps) {
const [formOpen, setFormOpen] = useState(false);
const clientData = useSelector(selectClientData);
const [feedbackMessage, setFeedbackMessage] = useState("");
const [rating, setRating] = useState(0);
const submitFeedback = async () => {
let clientId = clientData.clientId;
let tutorId = apptTutorId;
setFormOpen(false)
await api.SubmitFeedback({
clientId: clientId,
tutorId: tutorId,
message: feedbackMessage,
rating: rating
});
// TODO: Show some Toast UI confirming that the rating was submitted
}
return (
<Container>
<Button onClick={(e) => {
setFormOpen(true);
e.stopPropagation();
}}
style={{
minWidth: '60px',
lineHeight: '1',
position: "relative",
}}>
<div style={{
fontSize: "clamp(8px, 1vw, 12px)"
}}>
Rate
<FontAwesomeIcon icon={faStar} style={{marginLeft: '5px'}}/>
</div>
</Button>
<Modal
isOpen={formOpen}
toggle={() => setFormOpen(!formOpen)}
>
<ModalHeader toggle={() => setFormOpen(!formOpen)}>
Please give feedback on your session below.
</ModalHeader>
<StyledBody>
<Label for="exampleText">
What did you think of your session?
</Label>
<Input
id="exampleText"
name="text"
type="textarea"
value={feedbackMessage}
onChange={(element) => setFeedbackMessage(element.target.value)}
/>
<Label style={{marginTop: '1em'}}>
How would you rate your session?
</Label>
<div style={{lineHeight: '0.75'}}>
<ReactStars size={40} value={rating} onChange={new_rating => setRating(new_rating)}/>
</div>
</StyledBody>
<ModalFooter>
<Button
color="primary"
onClick={() => submitFeedback()}
>
Submit
</Button>
{' '}
<Button onClick={() => setFormOpen(false)}>
Cancel
</Button>
</ModalFooter>
</Modal>
</Container>
)
}
Example #12
Source File: SeqViewSettings.tsx From nextclade with MIT License | 4 votes |
export function SeqViewSettings() {
const { t } = useTranslationSafe()
const [maxNucMarkers, setMaxNucMarkers] = useRecoilStateDeferred(maxNucMarkersAtom)
const [seqMarkerMissingHeightState, setSeqMarkerMissingHeightState] = useSeqMarkerState(
seqMarkerMissingHeightStateAtom,
)
const [seqMarkerGapHeightState, setSeqMarkerGapHeightState] = useSeqMarkerState(seqMarkerGapHeightStateAtom)
const [seqMarkerMutationHeightState, setSeqMarkerMutationHeightState] = useSeqMarkerState(
seqMarkerMutationHeightStateAtom,
)
const [seqMarkerUnsequencedHeightState, setSeqMarkerUnsequencedHeightState] = useSeqMarkerState(
seqMarkerUnsequencedHeightStateAtom,
)
return (
<Container fluid>
<Row noGutters>
<Col>
<Form>
<NumericField
identifier="max-nuc-markers"
label={t('Maximum number of nucleotide sequence view markers')}
title={t(
'Sets threshold on maximum number of markers (mutations, deletions etc.) to display in nucleotide views. Reducing this number increases performance. If the threshold is reached, then the nucleotide sequence view will be disabled.',
)}
min={0}
max={1_000_000}
value={maxNucMarkers}
onValueChanged={setMaxNucMarkers}
/>
<FormGroup>
{t('Missing')}
<Multitoggle
values={SEQ_MARKER_HEIGHT_STATES}
value={seqMarkerMissingHeightState}
onChange={setSeqMarkerMissingHeightState}
/>
</FormGroup>
<FormGroup>
<Label>
{t('Gaps')}
<Multitoggle
values={SEQ_MARKER_HEIGHT_STATES}
value={seqMarkerGapHeightState}
onChange={setSeqMarkerGapHeightState}
/>
</Label>
</FormGroup>
<FormGroup>
<Label>
{t('Mutations')}
<Multitoggle
values={SEQ_MARKER_HEIGHT_STATES}
value={seqMarkerMutationHeightState}
onChange={setSeqMarkerMutationHeightState}
/>
</Label>
</FormGroup>
<FormGroup>
<Label>
{t('Unsequenced')}
<Multitoggle
values={SEQ_MARKER_HEIGHT_STATES}
value={seqMarkerUnsequencedHeightState}
onChange={setSeqMarkerUnsequencedHeightState}
/>
</Label>
</FormGroup>
</Form>
</Col>
</Row>
</Container>
)
}
Example #13
Source File: statvar.tsx From website with Apache License 2.0 | 4 votes |
export function StatVarChooser(props: StatVarChooserProps): JSX.Element {
const { x, y, place } = useContext(Context);
// Temporary variable for storing an extra statvar.
const [thirdStatVar, setThirdStatVar] = useState(emptyStatVar);
// Records which two of the three statvars are wanted if a third statvar is selected.
const [modalSelected, setModalSelected] = useState(defaultModalSelected);
const [modalOpen, setModalOpen] = useState(false);
const [samplePlaces, setSamplePlaces] = useState(
getSamplePlaces(
place.value.enclosingPlace.dcid,
place.value.enclosedPlaceType,
place.value.enclosedPlaces
)
);
useEffect(() => {
const samplePlaces = getSamplePlaces(
place.value.enclosingPlace.dcid,
place.value.enclosedPlaceType,
place.value.enclosedPlaces
);
setSamplePlaces(samplePlaces);
}, [place.value.enclosedPlaces]);
const closeModal = () => {
setThirdStatVar(emptyStatVar);
setModalOpen(false);
};
useEffect(() => {
const statVarsToGetInfo = [];
if (!_.isEmpty(x.value.statVarDcid) && _.isNull(x.value.statVarInfo)) {
statVarsToGetInfo.push(x.value.statVarDcid);
}
if (!_.isEmpty(y.value.statVarDcid) && _.isNull(y.value.statVarInfo)) {
statVarsToGetInfo.push(y.value.statVarDcid);
}
if (_.isEmpty(statVarsToGetInfo)) {
return;
}
getStatVarInfo(statVarsToGetInfo)
.then((info) => {
statVarsToGetInfo.forEach((sv) => {
const svInfo = sv in info ? info[sv] : {};
if (sv === x.value.statVarDcid) {
x.setStatVarInfo(svInfo);
} else {
y.setStatVarInfo(svInfo);
}
});
})
.catch(() => {
if (statVarsToGetInfo.indexOf(x.value.statVarDcid) > -1) {
x.setStatVarInfo({});
}
if (statVarsToGetInfo.indexOf(y.value.statVarDcid) > -1) {
y.setStatVarInfo({});
}
});
}, [x.value, y.value]);
let yTitle = y.value.statVarDcid;
if (y.value.statVarInfo && y.value.statVarInfo.title) {
yTitle = y.value.statVarInfo.title;
}
let xTitle = x.value.statVarDcid;
if (x.value.statVarInfo && x.value.statVarInfo.title) {
xTitle = x.value.statVarInfo.title;
}
const selectedSvs = {};
if (!_.isEmpty(x.value.statVarDcid)) {
selectedSvs[x.value.statVarDcid] = x.value.statVarInfo;
}
if (!_.isEmpty(y.value.statVarDcid)) {
selectedSvs[y.value.statVarDcid] = y.value.statVarInfo;
}
if (!_.isEmpty(thirdStatVar.dcid)) {
selectedSvs[thirdStatVar.dcid] = thirdStatVar.info;
}
return (
<>
<StatVarWidget
openSvHierarchyModal={props.openSvHierarchyModal}
openSvHierarchyModalCallback={props.openSvHierarchyModalCallback}
collapsible={true}
svHierarchyType={StatVarHierarchyType.SCATTER}
samplePlaces={samplePlaces}
deselectSVs={(svList: string[]) =>
svList.forEach((sv) => {
removeStatVar(x, y, sv);
})
}
selectedSVs={selectedSvs}
selectSV={(sv) => addStatVar(x, y, sv, setThirdStatVar, setModalOpen)}
/>
{/* Modal for selecting 2 stat vars when a third is selected */}
<Modal isOpen={modalOpen} backdrop="static" id="statvar-modal">
<ModalHeader toggle={closeModal}>
Only Two Statistical Variables Supported
</ModalHeader>
<ModalBody>
<Container>
<div>
You selected:{" "}
<b>{thirdStatVar.info.title || thirdStatVar.dcid}</b>
</div>
<div className="radio-selection-label">
Please choose 1 more statistical variable to keep:
</div>
<div className="radio-selection-section">
<FormGroup radio="true" row>
<Label radio="true">
<Input
id="x-radio-button"
type="radio"
name="statvar"
defaultChecked={modalSelected.x}
onClick={() => setModalSelected({ x: true, y: false })}
/>
{xTitle}
</Label>
</FormGroup>
<FormGroup radio="true" row>
<Label radio="true">
<Input
id="y-radio-button"
type="radio"
name="statvar"
defaultChecked={modalSelected.y}
onClick={() => setModalSelected({ x: false, y: true })}
/>
{yTitle}
</Label>
</FormGroup>
</div>
</Container>
</ModalBody>
<ModalFooter>
<Button
color="primary"
onClick={() =>
confirmStatVars(
x,
y,
thirdStatVar,
setThirdStatVar,
modalSelected,
setModalSelected,
setModalOpen
)
}
>
Confirm
</Button>
</ModalFooter>
</Modal>
</>
);
}
Example #14
Source File: plot_options.tsx From website with Apache License 2.0 | 4 votes |
// TODO: Add a new API that given a statvar, a parent place, and a child type,
// returns the available dates for the statvar. Then, fill the datapicker with
// the dates.
function PlotOptions(): JSX.Element {
const { place, x, y, display } = useContext(Context);
const [lowerBound, setLowerBound] = useState(
place.value.lowerBound.toString()
);
const [upperBound, setUpperBound] = useState(
place.value.upperBound.toString()
);
const [xDenomInput, setXDenomInput] = useState(x.value.denom);
const [yDenomInput, setYDenomInput] = useState(y.value.denom);
const yAxisLabel =
display.chartType === ScatterChartType.SCATTER
? "Y-axis"
: y.value.statVarInfo.title || y.value.statVarDcid;
const xAxisLabel =
display.chartType === ScatterChartType.SCATTER
? "X-axis"
: x.value.statVarInfo.title || x.value.statVarDcid;
const axisLabelStyle = {};
if (
yAxisLabel.length > MIN_WIDTH_LABEL_LENGTH ||
xAxisLabel.length > MIN_WIDTH_LABEL_LENGTH
) {
axisLabelStyle["width"] =
Math.min(
MAX_WIDTH_LABEL_LENGTH,
Math.max(xAxisLabel.length, yAxisLabel.length)
) /
2 +
"rem";
}
return (
<Card id="plot-options">
<Container fluid={true}>
<div className="plot-options-row">
<div className="plot-options-label" style={axisLabelStyle}>
{yAxisLabel}:
</div>
<div className="plot-options-input-section">
<div className="plot-options-input">
<FormGroup check>
<Label check>
<Input
id="per-capita-y"
type="checkbox"
checked={y.value.perCapita}
onChange={(e) => y.setPerCapita(e.target.checked)}
/>
Per Capita
</Label>
</FormGroup>
</div>
<div className="plot-options-input">
<FormGroup check>
<Input
id="log-y"
type="checkbox"
checked={y.value.log}
onChange={(e) => checkLog(y, e)}
/>
<Label check>Log scale</Label>
</FormGroup>
</div>
</div>
</div>
<div className="plot-options-row">
<div className="plot-options-label" style={axisLabelStyle}>
{xAxisLabel}:
</div>
<div className="plot-options-input-section">
<div className="plot-options-input">
<FormGroup check>
<Label check>
<Input
id="per-capita-x"
type="checkbox"
checked={x.value.perCapita}
onChange={(e) => x.setPerCapita(e.target.checked)}
/>
Per Capita
</Label>
</FormGroup>
</div>
<div className="plot-options-input">
<FormGroup check>
<Input
id="log-x"
type="checkbox"
checked={x.value.log}
onChange={(e) => checkLog(x, e)}
/>
<Label check>Log scale</Label>
</FormGroup>
</div>
</div>
</div>
{display.chartType === ScatterChartType.SCATTER && (
<>
<div className="plot-options-row">
<div className="plot-options-label">Display:</div>
<div className="plot-options-input-section">
<div className="plot-options-input">
<Button
id="swap-axes"
size="sm"
color="light"
onClick={() => swapAxes(x, y)}
className="plot-options-swap-button"
>
Swap X and Y axes
</Button>
</div>
<div className="plot-options-input">
<FormGroup check>
<Label check>
<Input
id="quadrants"
type="checkbox"
checked={display.showQuadrants}
onChange={(e) => checkQuadrants(display, e)}
/>
Show quadrants
</Label>
</FormGroup>
</div>
<div className="plot-options-input">
<FormGroup check>
<Label check>
<Input
id="quadrants"
type="checkbox"
checked={display.showLabels}
onChange={(e) => checkLabels(display, e)}
/>
Show labels
</Label>
</FormGroup>
</div>
<div className="plot-options-input">
<FormGroup check>
<Label check>
<Input
id="density"
type="checkbox"
checked={display.showDensity}
onChange={(e) => checkDensity(display, e)}
/>
Show density
</Label>
</FormGroup>
</div>
</div>
</div>
<div className="plot-options-row">
<div className="plot-options-label">Filter by population:</div>
<div className="plot-options-input-section pop-filter">
<div className="plot-options-input">
<FormGroup check>
<Input
className="pop-filter-input"
type="number"
onChange={(e) =>
selectLowerBound(place, e, setLowerBound)
}
value={lowerBound}
onBlur={() =>
setLowerBound(place.value.lowerBound.toString())
}
/>
</FormGroup>
</div>
<span>to</span>
<div className="plot-options-input">
<FormGroup check>
<Input
className="pop-filter-input"
type="number"
onChange={(e) =>
selectUpperBound(place, e, setUpperBound)
}
value={upperBound}
onBlur={() =>
setUpperBound(place.value.upperBound.toString())
}
/>
</FormGroup>
</div>
</div>
</div>
</>
)}
</Container>
</Card>
);
}
Example #15
Source File: chart.tsx From website with Apache License 2.0 | 4 votes |
export function Chart(props: ChartProps): JSX.Element {
const statVar = props.statVar.value;
const [errorMessage, setErrorMessage] = useState("");
const mainSvInfo: StatVarInfo =
statVar.dcid in statVar.info ? statVar.info[statVar.dcid] : {};
const title = getTitle(
Array.from(props.dates),
mainSvInfo.title || statVar.dcid,
statVar.perCapita
);
const placeDcid = props.placeInfo.enclosingPlace.dcid;
const statVarDcid = statVar.dcid;
const [mapPoints, setMapPoints] = useState(null);
const [mapPointsFetched, setMapPointsFetched] = useState(false);
const [zoomTransformation, setZoomTransformation] = useState(
DEFAULT_ZOOM_TRANSFORMATION
);
const chartContainerRef = useRef<HTMLDivElement>();
// load mapPoints in the background.
useEffect(() => {
props.mapPointsPromise
.then((mapPoints) => {
setMapPoints(mapPoints);
setMapPointsFetched(true);
})
.catch(() => setMapPointsFetched(true));
}, []);
function replot() {
draw(
props,
setErrorMessage,
mapPoints,
zoomTransformation,
setZoomTransformation,
props.display.value.color,
props.display.value.domain
);
}
// Replot when data changes.
useEffect(() => {
if (props.display.value.showMapPoints && !mapPointsFetched) {
loadSpinner(SECTION_CONTAINER_ID);
return;
} else {
removeSpinner(SECTION_CONTAINER_ID);
}
replot();
}, [props, mapPointsFetched]);
// Replot when chart width changes on sv widget toggle.
useEffect(() => {
const debouncedHandler = _.debounce(() => {
if (!props.display.value.showMapPoints || mapPointsFetched) {
replot();
}
}, DEBOUNCE_INTERVAL_MS);
const resizeObserver = new ResizeObserver(debouncedHandler);
if (chartContainerRef.current) {
resizeObserver.observe(chartContainerRef.current);
}
return () => {
resizeObserver.unobserve(chartContainerRef.current);
debouncedHandler.cancel();
};
}, [props, chartContainerRef]);
return (
<div className="chart-section-container">
<Card className="chart-section-card">
<Container id={SECTION_CONTAINER_ID} fluid={true}>
<div className="chart-section">
<div className="map-title">
<h3>
{title}
{props.dates.size > 1 && (
<span
onMouseOver={onDateRangeMouseOver}
onMouseOut={onDateRangeMouseOut}
id={DATE_RANGE_INFO_ID}
>
<i className="material-icons-outlined">info</i>
</span>
)}
</h3>
<div id={DATE_RANGE_INFO_TEXT_ID}>
The date range represents the dates of the data shown in this
map.
</div>
</div>
{errorMessage ? (
<div className="error-message">{errorMessage}</div>
) : (
<div className="map-section-container">
<div id={CHART_CONTAINER_ID} ref={chartContainerRef}>
<div id={MAP_CONTAINER_ID}></div>
<div id={LEGEND_CONTAINER_ID}></div>
</div>
<div className="zoom-button-section">
<div id={ZOOM_IN_BUTTON_ID} className="zoom-button">
<i className="material-icons">add</i>
</div>
<div id={ZOOM_OUT_BUTTON_ID} className="zoom-button">
<i className="material-icons">remove</i>
</div>
</div>
</div>
)}
{props.display.value.showTimeSlider &&
props.sampleDates &&
props.sampleDates.length > 1 && (
<TimeSlider
currentDate={_.max(Array.from(props.dates))}
dates={props.sampleDates}
metahash={props.metahash}
onPlay={props.onPlay}
startEnabled={props.dates.size === 1}
updateDate={props.updateDate}
/>
)}
<div className="map-links">
{mainSvInfo.ranked && (
<a className="explore-timeline-link" href={props.rankingLink}>
<span className="explore-timeline-text">
Explore rankings
</span>
<i className="material-icons">keyboard_arrow_right</i>
</a>
)}
{!mainSvInfo.ranked &&
(props.placeInfo.selectedPlace.dcid in props.mapDataValues ||
props.placeInfo.selectedPlace.dcid in
props.breadcrumbDataValues) && (
<a
className="explore-timeline-link"
href={`/tools/timeline#place=${placeDcid}&statsVar=${statVarDcid}`}
>
<span className="explore-timeline-text">
Explore timeline
</span>
<i className="material-icons">keyboard_arrow_right</i>
</a>
)}
</div>
</div>
</Container>
</Card>
<ToolChartFooter
chartId="map"
sources={props.sources}
mMethods={null}
sourceSelectorSvInfoList={[props.sourceSelectorSvInfo]}
onSvMetahashUpdated={(svMetahashMap) =>
props.statVar.setMetahash(svMetahashMap[props.statVar.value.dcid])
}
hideIsRatio={false}
isPerCapita={props.statVar.value.perCapita}
onIsPerCapitaUpdated={(isPerCapita: boolean) =>
props.statVar.setPerCapita(isPerCapita)
}
>
{props.placeInfo.mapPointPlaceType && (
<div className="chart-option">
<FormGroup check>
<Label check>
<Input
id="show-installations"
type="checkbox"
checked={props.display.value.showMapPoints}
onChange={(e) =>
props.display.setShowMapPoints(e.target.checked)
}
/>
Show Installations
</Label>
</FormGroup>
</div>
)}
</ToolChartFooter>
<div id="map-chart-screen" className="screen">
<div id="spinner"></div>
</div>
</div>
);
}
Example #16
Source File: stat_var_chooser.tsx From website with Apache License 2.0 | 4 votes |
export function StatVarChooser(props: StatVarChooserProps): JSX.Element {
const [samplePlaces, setSamplePlaces] = useState([]);
// extraStatVar holds a stat var that is selected after the max number of
// selected stat vars has been reached. This stat var will either be removed
// or used to replace another selected stat var.
const [extraStatVar, setExtraStatVar] = useState(EMPTY_SV_AND_INFO);
const [modalSelection, setModalSelection] = useState("");
const [modalOpen, setModalOpen] = useState(false);
const modalSvOrder = useRef(Object.keys(props.statVars));
useEffect(() => {
modalSvOrder.current = Object.keys(props.statVars);
}, [props.statVars]);
useEffect(() => {
if (!props.placeDcid || !props.enclosedPlaceType) {
setSamplePlaces([]);
return;
}
getEnclosedPlacesPromise(props.placeDcid, props.enclosedPlaceType)
.then((enclosedPlaces) => {
const samplePlaces = getSamplePlaces(
props.placeDcid,
props.enclosedPlaceType,
enclosedPlaces
);
setSamplePlaces(samplePlaces);
})
.catch(() => {
setSamplePlaces([]);
});
}, [props.placeDcid, props.enclosedPlaceType]);
const selectedSVs = { ...props.statVars };
// although we don't propagate the extra stat var selection to the rest of the
// tool, we do need to pass it to the widget because the StatVarHierarchy has
// it showing as selected.
if (!_.isEmpty(extraStatVar.dcid)) {
selectedSVs[extraStatVar.dcid] = extraStatVar.info;
}
return (
<>
<StatVarWidget
openSvHierarchyModal={props.openSvHierarchyModal}
openSvHierarchyModalCallback={props.openSvHierarchyModalCallback}
collapsible={false}
svHierarchyType={StatVarHierarchyType.DOWNLOAD}
samplePlaces={samplePlaces}
deselectSVs={(svList: string[]) =>
svList.forEach((sv) => {
props.onStatVarRemoved(sv);
})
}
selectedSVs={selectedSVs}
selectSV={(sv) => selectSV(sv)}
/>
{/* Modal for selecting stat var to replace when too many are selected */}
<Modal isOpen={modalOpen} backdrop="static" id="statvar-modal">
<ModalHeader toggle={closeModal}>
Only 5 Statistical Variables Supported
</ModalHeader>
<ModalBody>
<Container>
<div>
You selected:{" "}
<b>{extraStatVar.info.title || extraStatVar.dcid}</b>
</div>
<div className="radio-selection-label">
Please choose a statistical variable to replace:
</div>
<div className="radio-selection-section">
{modalSvOrder.current.map((sv, idx) => {
return (
<FormGroup key={sv} radio="true" row>
<Label radio="true">
<Input
type="radio"
name="statvar"
defaultChecked={
(_.isEmpty(modalSelection) && idx === 0) ||
modalSelection === sv
}
onClick={() => setModalSelection(sv)}
/>
{sv in props.statVars
? props.statVars[sv].title || sv
: sv}
</Label>
</FormGroup>
);
})}
</div>
</Container>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => confirmStatVars()}>
Confirm
</Button>
</ModalFooter>
</Modal>
</>
);
/**
* Close the modal
*/
function closeModal(): void {
setExtraStatVar(EMPTY_SV_AND_INFO);
setModalSelection("");
setModalOpen(false);
}
/**
* Confirms the variable to replace in the modal.
*/
function confirmStatVars(): void {
const svToRemove = _.isEmpty(modalSelection)
? modalSvOrder.current[0]
: modalSelection;
props.onStatVarRemoved(svToRemove);
props.onStatVarSelected(extraStatVar.dcid, extraStatVar.info);
closeModal();
}
/**
* Select a variable.
*/
function selectSV(sv: string): void {
getStatVarInfo([sv])
.then((svInfo) => {
const selectedSVInfo = svInfo[sv] || {};
if (Object.keys(props.statVars).length >= MAX_SV) {
setExtraStatVar({ dcid: sv, info: selectedSVInfo });
setModalOpen(true);
} else {
props.onStatVarSelected(sv, selectedSVInfo);
}
})
.catch(() => {
if (Object.keys(props.statVars).length >= MAX_SV) {
setExtraStatVar({ dcid: sv, info: {} });
setModalOpen(true);
} else {
props.onStatVarSelected(sv, {});
}
});
}
}
Example #17
Source File: page.tsx From website with Apache License 2.0 | 4 votes |
export function Page(): JSX.Element {
const [selectedOptions, setSelectedOptions] = useState<DownloadOptions>(null);
const [previewDisabled, setPreviewDisabled] = useState(false);
const [showPreview, setShowPreview] = useState(false);
const [validationErrors, setValidationErrors] = useState<ValidationErrors>({
incompleteSelectionMessage: "",
maxDate: false,
minDate: false,
});
const [isSvModalOpen, updateSvModalOpen] = useState(false);
const toggleSvModalCallback = () => updateSvModalOpen(!isSvModalOpen);
useEffect(() => {
if (showPreview) {
setPreviewDisabled(true);
}
}, [selectedOptions]);
useEffect(() => {
getOptionsFromURL();
}, []);
if (!selectedOptions) {
return <></>;
}
const getDataButtonText = showPreview ? "Update" : "Preview";
const showInfo =
_.isEmpty(validationErrors.incompleteSelectionMessage) && !showPreview;
return (
// TODO: Try to move the options into a separate component.
<>
<StatVarChooser
statVars={selectedOptions.selectedStatVars}
placeDcid={selectedOptions.selectedPlace.dcid}
enclosedPlaceType={selectedOptions.enclosedPlaceType}
onStatVarSelected={selectSV}
onStatVarRemoved={removeSV}
openSvHierarchyModal={isSvModalOpen}
openSvHierarchyModalCallback={toggleSvModalCallback}
/>
<div id="plot-container">
<h1 className="mb-4">Download Tool</h1>
<div className="download-options-container">
<PlaceSelector
selectedPlace={selectedOptions.selectedPlace}
enclosedPlaceType={selectedOptions.enclosedPlaceType}
onPlaceSelected={(place) =>
setSelectedOptions((prev) => {
return { ...prev, selectedPlace: place, enclosedPlaceType: "" };
})
}
onEnclosedPlaceTypeSelected={(enclosedPlaceType) =>
setSelectedOptions((prev) => {
return { ...prev, enclosedPlaceType };
})
}
>
<div className="download-option-section">
<div className="download-option-label">Date</div>
<div className="download-date-options">
<FormGroup radio="true">
<Label radio="true">
<Input
id="latest-date"
type="radio"
name="date"
defaultChecked={!selectedOptions.dateRange}
onClick={() =>
setSelectedOptions((prev) => {
return { ...prev, dateRange: false };
})
}
/>
Latest Date
</Label>
</FormGroup>
<FormGroup radio="true" className="download-date-range-section">
<Label radio="true" className="download-date-range-container">
<Input
id="date-range"
type="radio"
name="date"
defaultChecked={selectedOptions.dateRange}
onClick={() =>
setSelectedOptions((prev) => {
return { ...prev, dateRange: true };
})
}
/>
Date Range:
</Label>
<div className="download-date-range-input-section">
<div className="download-date-range-input-container">
<div>
<FormGroup>
<Input
className={`download-date-range-input${
validationErrors.minDate ? "-error" : ""
}`}
type="text"
onChange={(e) => {
const date = e.target.value;
setSelectedOptions((prev) => {
return { ...prev, minDate: date };
});
}}
disabled={!selectedOptions.dateRange}
value={selectedOptions.minDate}
onBlur={(e) => validateDate(e.target.value, true)}
/>
</FormGroup>
</div>
<span>to</span>
<div>
<FormGroup>
<Input
className={`download-date-range-input${
validationErrors.maxDate ? "-error" : ""
}`}
type="text"
onChange={(e) => {
const date = e.target.value;
setSelectedOptions((prev) => {
return { ...prev, maxDate: date };
});
}}
disabled={!selectedOptions.dateRange}
value={selectedOptions.maxDate}
onBlur={(e) => validateDate(e.target.value, false)}
/>
</FormGroup>
</div>
</div>
<div
className={`download-date-range-hint${
validationErrors.minDate || validationErrors.maxDate
? "-error"
: ""
}`}
>
YYYY or YYYY-MM or YYYY-MM-DD
</div>
</div>
</FormGroup>
</div>
</div>
<div className="download-option-section">
<div className="download-option-label">Variables</div>
{_.isEmpty(selectedOptions.selectedStatVars) ? (
"None selected"
) : (
<div className="download-sv-chips">
{Object.keys(selectedOptions.selectedStatVars).map((sv) => {
return (
<Chip
key={sv}
id={sv}
title={selectedOptions.selectedStatVars[sv].title || sv}
removeChip={removeSV}
/>
);
})}
</div>
)}
</div>
<Row className="d-lg-none">
<Col>
<Button color="primary" onClick={toggleSvModalCallback}>
Select variable
</Button>
</Col>
</Row>
<Button onClick={onGetDataButtonClicked} color="primary">
{getDataButtonText}
</Button>
</PlaceSelector>
</div>
{!_.isEmpty(validationErrors.incompleteSelectionMessage) && (
<div>{validationErrors.incompleteSelectionMessage}</div>
)}
{showPreview && (
<div>{previewDisabled ? "disabled preview" : "preview"}</div>
)}
{showInfo && <div>info text</div>}
</div>
</>
);
function selectSV(sv: string, svInfo: StatVarInfo): void {
setSelectedOptions((prev) => {
const updatedSV = _.cloneDeep(prev.selectedStatVars);
updatedSV[sv] = svInfo;
return { ...prev, selectedStatVars: updatedSV };
});
}
function removeSV(sv: string): void {
setSelectedOptions((prev) => {
const updatedSV = _.cloneDeep(prev.selectedStatVars);
if (sv in updatedSV) {
delete updatedSV[sv];
}
return { ...prev, selectedStatVars: updatedSV };
});
}
function getOptionsFromURL(): void {
const options = {
dateRange: false,
enclosedPlaceType: "",
maxDate: "",
minDate: "",
selectedPlace: { dcid: "", name: "", types: null },
selectedStatVars: {},
};
if (!window.location.hash) {
setSelectedOptions(options);
}
const urlParams = new URLSearchParams(window.location.hash.split("#")[1]);
const place = urlParams.get(URL_PARAM_KEYS.PLACE);
const placePromise = place
? getNamedTypedPlace(place)
: Promise.resolve({ dcid: "", name: "", types: null });
const statVarsParam = urlParams.get(URL_PARAM_KEYS.STAT_VARS);
const statVarsList = statVarsParam ? statVarsParam.split(SEPARATOR) : [];
const svInfoPromise = !_.isEmpty(statVarsList)
? getStatVarInfo(statVarsList)
: Promise.resolve({});
options.enclosedPlaceType = urlParams.get(URL_PARAM_KEYS.PLACE_TYPE) || "";
options.dateRange =
urlParams.get(URL_PARAM_KEYS.DATE_RANGE) === PARAM_VALUE_TRUE;
options.minDate = urlParams.get(URL_PARAM_KEYS.MIN_DATE) || "";
options.maxDate = urlParams.get(URL_PARAM_KEYS.MAX_DATE) || "";
Promise.all([placePromise, svInfoPromise])
.then(([place, svInfo]) => {
setSelectedOptions({
...options,
selectedPlace: place,
selectedStatVars: svInfo,
});
})
.catch(() => {
const emptySvInfo = {};
statVarsList.forEach((sv) => (emptySvInfo[sv] = {}));
setSelectedOptions({
...options,
selectedPlace: { dcid: place, name: place, types: [] },
selectedStatVars: emptySvInfo,
});
});
}
function updateURL(): void {
const urlParams = new URLSearchParams(window.location.hash.split("#")[1]);
const urlParamVals = {
[URL_PARAM_KEYS.PLACE_TYPE]: selectedOptions.enclosedPlaceType,
[URL_PARAM_KEYS.PLACE]: selectedOptions.selectedPlace
? selectedOptions.selectedPlace.dcid
: "",
[URL_PARAM_KEYS.STAT_VARS]: Object.keys(
selectedOptions.selectedStatVars
).join(SEPARATOR),
[URL_PARAM_KEYS.DATE_RANGE]: selectedOptions.dateRange
? PARAM_VALUE_TRUE
: "",
[URL_PARAM_KEYS.MIN_DATE]: selectedOptions.minDate,
[URL_PARAM_KEYS.MAX_DATE]: selectedOptions.maxDate,
};
for (const key of Object.keys(urlParamVals)) {
const val = urlParamVals[key];
if (_.isEmpty(val)) {
urlParams.delete(key);
} else {
urlParams.set(key, val);
}
}
window.location.hash = urlParams.toString();
}
function validateDate(date: string, isMinDate: boolean): void {
const dateError = !_.isEmpty(date) && !isValidDate(date);
setValidationErrors((prev) => {
return {
...prev,
maxDate: !isMinDate ? dateError : prev.maxDate,
minDate: isMinDate ? dateError : prev.minDate,
};
});
}
function onGetDataButtonClicked(): void {
let incompleteSelectionMessage = "";
if (selectedOptions.dateRange) {
if (
(!_.isEmpty(selectedOptions.minDate) &&
!isValidDate(selectedOptions.minDate)) ||
(!_.isEmpty(selectedOptions.maxDate) &&
!isValidDate(selectedOptions.maxDate))
) {
incompleteSelectionMessage = "Invalid dates entered.";
}
}
if (
_.isEmpty(selectedOptions.selectedStatVars) ||
_.isEmpty(selectedOptions.selectedPlace) ||
_.isEmpty(selectedOptions.enclosedPlaceType)
) {
incompleteSelectionMessage =
"Please select a place, place type, and at least one variable.";
}
setValidationErrors((prev) => {
return { ...prev, incompleteSelectionMessage };
});
if (!_.isEmpty(incompleteSelectionMessage)) {
return;
}
setShowPreview(true);
setPreviewDisabled(false);
updateURL();
}
}
Example #18
Source File: SignupPage.tsx From TutorBase with MIT License | 4 votes |
export function SignUpPage() {
const [signUpData, setSignUpData] = useState({
first_name: "",
last_name: "",
email: "",
password: "",
phone_number: "",
visible: false,
passwordValid: false,
emailValid: false,
firstNameValid: false,
lastNameValid: false,
phoneValid: false,
loginValid: true,
emailTaken: false,
});
const history = useHistory();
const HandleChange = (event: any) => {
let name = event.target.name;
let value = event.target.value;
if (name === "first_name")
IsFirstNameValid(value)
else if (name === "last_name")
IsLastNameValid(value)
else if (name === "email")
IsEmailValid(value)
};
const IsFirstNameValid = (value: any) => {
let firstValid = false;
if (value.length > 0)
firstValid = true
setSignUpData({
...signUpData,
first_name: value,
firstNameValid: firstValid,
})
}
const IsLastNameValid = (value: any) => {
let lastValid = false;
if (value.length > 0)
lastValid = true
setSignUpData({
...signUpData,
last_name: value,
lastNameValid: lastValid,
})
}
const IsEmailValid = (value: string) => {
setSignUpData((signUpData: any) => ({
...signUpData,
email: value,
emailValid: isEmail.validate(value),
emailTaken: false,
}));
}
const IsPhoneNumberValid = (value: any) => {
let phoneValid = false;
if (value.length === 0 || (value.length === 10 && value.match(/^[0-9]+$/) != null))
phoneValid = true
setSignUpData({
...signUpData,
phone_number: value,
phoneValid: phoneValid,
})
}
const CreateUser = async () => {
let body = {
"email": signUpData.email,
"first_name": signUpData.first_name,
"last_name": signUpData.last_name,
"phone": signUpData.phone_number,
}
const request = await fetch(ApiBaseAddress + "api/users", {
method: "post",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
credentials: 'include',
});
if (request.ok) {
history.push("home");
} else {
setSignUpData((signUpData) => ({
...signUpData,
emailTaken: true,
emailValid: false,
}));
}
}
const SubmitEvent = (event: any) => {
event.preventDefault();
if (signUpData.firstNameValid && signUpData.lastNameValid) {
CreateUser();
} else {
setSignUpData({
...signUpData,
loginValid: false
});
}
};
return (
<div className="flexBox">
<Container className="signupContainer" fluid="xs" style={{padding: "3%", margin: "10em"}}>
<Row>
<Col xs="1"/>
<Col xs="11">
<Form onSubmit={event => SubmitEvent(event)}>
<Label className="signupText">Sign Up</Label>
<FormGroup row>
<Container>
<Row>
<Col xs="auto">
<Input
type="text"
className="form-control"
name="first_name"
placeholder="First Name"
value={signUpData.first_name}
onChange={event => HandleChange(event)}
autoComplete="off"
/>
</Col>
<Col xs="auto">
<div>
{signUpData.firstNameValid ?
<MdCheck size="30px" color="green"></MdCheck> :
<VscError size="30px" color="red"></VscError>}
</div>
</Col>
</Row>
</Container>
</FormGroup>
<FormGroup row>
<Container>
<Row>
<Col xs="auto">
<Input
type="text"
className="form-control"
name="last_name"
placeholder="Last Name"
value={signUpData.last_name}
onChange={event => HandleChange(event)}
autoComplete="off"
/>
</Col>
<Col xs="auto">
<div>
{signUpData.lastNameValid ?
<MdCheck size="30px" color="green"></MdCheck> :
<VscError size="30px" color="red"></VscError>}
</div>
</Col>
</Row>
</Container>
</FormGroup>
<FormGroup row>
<Container>
<Row>
<Col xs="auto">
<Input
type="email"
className="form-control"
name="email"
placeholder="Email"
value={signUpData.email}
onChange={event => HandleChange(event)}
autoComplete="off"
/>
</Col>
<Col xs="auto">
<div>
{signUpData.emailValid ?
<MdCheck size="30px" color="green"></MdCheck> :
<VscError size="30px" color="red"></VscError>}
</div>
</Col>
</Row>
</Container>
</FormGroup>
<FormGroup row>
<Container fluid>
<Row>
<Col xs="auto">
<Input
type="number"
className="form-control"
name="phone"
placeholder="Cell Number (optional)"
value={signUpData.phone_number}
onChange={event => HandleChange(event)}
autoComplete="off"
/>
</Col>
<Col xs="auto">
<div>
{signUpData.phoneValid ? (
<MdCheck size="30px" color="green"></MdCheck>
) : (
<VscError size="30px" color="red"></VscError>
)}
</div>
</Col>
</Row>
</Container>
</FormGroup>
<div>
{signUpData.loginValid ? '' : 'Invalid Fields'}
</div>
<div>
{signUpData.emailTaken && 'Email already taken'}
</div>
<Button color="danger" type="submit">
Create Account
</Button>
<div>Already have an account? Click <Link to='/login'>here</Link></div>
</Form>
</Col>
</Row>
</Container>
</div>
);
}