react-bootstrap#FormControl TypeScript Examples
The following examples show how to use
react-bootstrap#FormControl.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CustomMenu.tsx From 3Speak-app with GNU General Public License v3.0 | 6 votes |
CustomPinsViewMenu = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }: any, ref: any) => {
const [value, setValue] = useState('')
return (
<div ref={ref} style={style} className={className} aria-labelledby={labeledBy}>
<FormControl
autoFocus
className="mx-3 my-2 w-auto"
placeholder="Type to filter..."
onChange={(e) => setValue(e.target.value)}
value={value}
/>
<ul className="list-unstyled">
{React.Children.toArray(children).filter(
(child: any) => !value || child.props.children.toLowerCase().startsWith(value),
)}
</ul>
</div>
)
},
)
Example #2
Source File: MysticCodePicker.tsx From apps with MIT License | 6 votes |
render() {
return (
<div>
Jump to:
<FormControl
as={"select"}
custom
onChange={(ev: Event) => {
this.changeMysticCode(parseInt(ev.target.value));
}}
value={this.props.id}
>
{this.props.mysticCodes.map((mysticCode) => {
return (
<option key={mysticCode.id} value={mysticCode.id}>
{mysticCode.name}
</option>
);
})}
</FormControl>
</div>
);
}
Example #3
Source File: CommandCodePicker.tsx From apps with MIT License | 6 votes |
render() {
return (
<div>
Jump to:
<FormControl
as={"select"}
custom
onChange={(ev: Event) => {
this.changeCommandCode(parseInt(ev.target.value));
}}
value={this.props.id}
>
{this.props.commandCodes
.slice()
.reverse()
.map((commandCode) => {
return (
<option key={commandCode.id} value={commandCode.id}>
{commandCode.name}
</option>
);
})}
</FormControl>
</div>
);
}
Example #4
Source File: Login.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 6 votes |
onEmailChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
email: target.value,
emailValid: emailRegex.test(target.value.toLowerCase())
? "success"
: "error",
});
};
Example #5
Source File: Signup.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 6 votes |
onEmailChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
email: target.value,
emailValid: emailRegex.test(target.value.toLowerCase())
? "success"
: "error",
});
};
Example #6
Source File: Signup.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
onConfirmationCodeChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
confirmationCode: target.value,
confirmationCodeValid: target.value.length > 0 ? "error" : "success",
});
};
Example #7
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 5 votes |
ProposalEditor = ({
title,
body,
onTitleInput,
onBodyInput,
}: {
title: string;
body: string;
onTitleInput: (title: string) => void;
onBodyInput: (body: string) => void;
}) => {
const bodyPlaceholder = `## Summary\n\nInsert your summary here\n\n## Methodology\n\nInsert your methodology here\n\n## Conclusion\n\nInsert your conclusion here`;
const [proposalText, setProposalText] = useState('');
const onBodyChange = (body: string) => {
setProposalText(body);
onBodyInput(body);
};
return (
<div>
<InputGroup className={`${classes.proposalEditor} d-flex flex-column`}>
<FormText>
<Trans>Proposal</Trans>
</FormText>
<FormControl
className={classes.titleInput}
value={title}
onChange={e => onTitleInput(e.target.value)}
placeholder="Proposal Title"
/>
<hr className={classes.divider} />
<FormControl
className={classes.bodyInput}
value={body}
onChange={e => onBodyChange(e.target.value)}
as="textarea"
placeholder={bodyPlaceholder}
/>
</InputGroup>
{proposalText !== '' && (
<div className={classes.previewArea}>
<h3>
<Trans>Preview:</Trans>
</h3>
<ReactMarkdown
className={classes.markdown}
children={proposalText}
remarkPlugins={[remarkBreaks]}
/>
</div>
)}
</div>
);
}
Example #8
Source File: PhotoSwipe.tsx From bada-frame with GNU General Public License v3.0 | 5 votes |
FileNameEditForm = ({ filename, saveEdits, discardEdits, extension }) => {
const [loading, setLoading] = useState(false);
const onSubmit = async (values: formValues) => {
try {
setLoading(true);
await saveEdits(values.filename);
} finally {
setLoading(false);
}
};
return (
<Formik<formValues>
initialValues={{ filename }}
validationSchema={Yup.object().shape({
filename: Yup.string()
.required(constants.REQUIRED)
.max(
MAX_EDITED_FILE_NAME_LENGTH,
constants.FILE_NAME_CHARACTER_LIMIT
),
})}
validateOnBlur={false}
onSubmit={onSubmit}>
{({ values, errors, handleChange, handleSubmit }) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Row>
<Form.Group
bsPrefix="ente-form-group"
as={Col}
xs={extension ? 7 : 8}>
<Form.Control
as="textarea"
placeholder={constants.FILE_NAME}
value={values.filename}
onChange={handleChange('filename')}
isInvalid={Boolean(errors.filename)}
autoFocus
disabled={loading}
/>
<FormControl.Feedback
type="invalid"
style={{ textAlign: 'center' }}>
{errors.filename}
</FormControl.Feedback>
</Form.Group>
{extension && (
<Form.Group
bsPrefix="ente-form-group"
as={Col}
xs={1}
controlId="formHorizontalFileName">
<FlexWrapper style={{ padding: '5px' }}>
{`.${extension}`}
</FlexWrapper>
</Form.Group>
)}
<Form.Group bsPrefix="ente-form-group" as={Col} xs={2}>
<Value width={'16.67%'}>
<IconButton type="submit" disabled={loading}>
{loading ? (
<SmallLoadingSpinner />
) : (
<TickIcon />
)}
</IconButton>
<IconButton
onClick={discardEdits}
disabled={loading}>
<CloseIcon />
</IconButton>
</Value>
</Form.Group>
</Form.Row>
</Form>
)}
</Formik>
);
}
Example #9
Source File: Signup.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
showSignupForm = () => {
return (
<form onSubmit={this.onSignup}>
<FormGroup controlId="email" validationState={this.state.emailValid}>
<ControlLabel>Email</ControlLabel>
<FormControl
name="email"
type="email"
bsSize="large"
value={this.state.email}
onChange={this.onEmailChange}
/>
<FormControl.Feedback />
</FormGroup>
<FormGroup
controlId="password"
validationState={this.state.passwordValid}
>
<ControlLabel>Password</ControlLabel>
<FormControl
name="password"
type="password"
bsSize="large"
value={this.state.password}
onChange={this.onPasswordChange}
/>
<FormControl.Feedback />
<HelpBlock>Must be at least 8 characters</HelpBlock>
</FormGroup>
<FormGroup
controlId="confirmPassword"
validationState={this.state.confirmPasswordValid}
>
<ControlLabel>Confirm Password</ControlLabel>
<FormControl
name="confirmPassword"
type="password"
bsSize="large"
value={this.state.confirmPassword}
onChange={this.onConfirmPasswordChange}
/>
<FormControl.Feedback />
</FormGroup>
<Button
block
bsSize="large"
type="submit"
disabled={
this.state.passwordValid !== "success" ||
this.state.confirmPasswordValid !== "success" ||
this.state.emailValid !== "success"
}
>
{this.state.loading && (
<Glyphicon glyph="refresh" className="spinning" />
)}
Log in
</Button>
</form>
);
};
Example #10
Source File: Signup.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
onConfirmPasswordChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
confirmPassword: target.value,
confirmPasswordValid:
target.value !== this.state.password ? "error" : "success",
});
};
Example #11
Source File: Signup.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
onPasswordChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
password: target.value,
passwordValid: target.value.length < 8 ? "error" : "success",
});
};
Example #12
Source File: Login.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
onPasswordChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement;
this.setState({
password: target.value,
passwordValid: target.value.length < 8 ? "error" : "success",
});
};
Example #13
Source File: Login.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
render() {
if (this.state.redirect) return <Redirect to="/" />;
return (
<div className="Login">
<form onSubmit={this.onLogin}>
<FormGroup controlId="email" validationState={this.state.emailValid}>
<ControlLabel>Email</ControlLabel>
<FormControl
name="email"
type="email"
bsSize="large"
value={this.state.email}
onChange={this.onEmailChange}
/>
<FormControl.Feedback />
</FormGroup>
<FormGroup
controlId="password"
validationState={this.state.passwordValid}
>
<ControlLabel>Password</ControlLabel>
<FormControl
name="password"
type="password"
bsSize="large"
value={this.state.password}
onChange={this.onPasswordChange}
/>
<FormControl.Feedback />
</FormGroup>
<Button
block
bsSize="large"
type="submit"
disabled={
this.state.passwordValid !== "success" ||
this.state.emailValid !== "success"
}
>
{this.state.loading && (
<Glyphicon glyph="refresh" className="spinning" />
)}
Log in
</Button>
</form>
</div>
);
}
Example #14
Source File: CheckoutForm.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
handleChange = (event: React.FormEvent<FormControl>) => {
const target = event.target as HTMLInputElement
this.setState({
...this.state,
[target.name as any]: target.value
});
}
Example #15
Source File: CheckoutForm.tsx From tutorial-cloudflare-bookstore with Apache License 2.0 | 5 votes |
render() {
if (this.state.toConfirm) return <Redirect to='/checkout-confirm' />
if (this.state.isLoading) return null;
return (
<div className="well-bs col-md-12 full-page no-padding-top">
<div className="white-box no-margin-top">
<div className="checkout ">
<img src={supportedCards} alt="Supported cards" />
<Form>
<FormGroup
controlId="card"
validationState={this.getCardNumberValidationState()}>
<ControlLabel>Card number</ControlLabel>
<FormControl
name="card"
type="text"
value={this.state.card}
onChange={this.handleChange} />
<FormControl.Feedback />
</FormGroup>
<div className="form-row">
<FormGroup
controlId="expDate">
<ControlLabel>Expiration date</ControlLabel>
<FormControl
name="expDate"
type="date"
value={this.state.expDate}
onChange={this.handleChange} />
<FormControl.Feedback />
</FormGroup>
<FormGroup
className="ccv"
controlId="ccv">
<ControlLabel>CCV</ControlLabel>
<FormControl
name="ccv"
type="text"
value={this.state.ccv}
onChange={this.handleChange} />
<FormControl.Feedback />
</FormGroup>
</div>
</Form>
</div>
</div>
<div className="pull-right">
<button className="btn btn-black" type="button" onClick={this.onCheckout}>{`Pay ($${this.getOrderTotal()})`}</button>
</div>
</div>
);
}
Example #16
Source File: TopNavbar.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function TopNavbar() {
const [inEdit, setInEdit] = useState(false)
const urlForm = useRef<any>()
const [urlSplit, setUrlSplit] = useState([])
const startEdit = () => {
setInEdit(true)
}
useEffect(() => {
if (inEdit) {
urlForm.current?.focus()
}
}, [inEdit])
const exitEdit = () => {
setInEdit(false)
}
const finishEdit = (e) => {
if (e.keyCode === 13) {
if (location.hash !== `#${e.target.value}`) {
location.replace(`#${e.target.value}`)
location.reload()
}
setInEdit(false)
} else if (e.keyCode === 27) {
exitEdit()
}
}
const updateUrlSplit = () => {
const hash = window.location.hash
const theUrlSplit = hash.split('/')
theUrlSplit.splice(0, 1)
if (theUrlSplit[0] === 'watch') {
const pagePerm = theUrlSplit[1]
const pagePermSpliced = pagePerm.split(':')
pagePermSpliced.splice(0, 1)
theUrlSplit.pop()
pagePermSpliced.forEach((onePagePerm) => {
theUrlSplit.push(onePagePerm)
})
setUrlSplit(theUrlSplit)
} else {
setUrlSplit(theUrlSplit)
}
}
useEffect(() => {
updateUrlSplit()
}, [])
useEffect(() => {
window.addEventListener('hashchange', function (event) {
updateUrlSplit()
})
}, [])
const userProfileUrl = useMemo(() => {
const windowLocationHash = window.location.hash
const windowLocationSearch = windowLocationHash.search('#')
const windowLocationHref = windowLocationHash.slice(windowLocationSearch)
const hrefSegments = windowLocationHref.split('/')
hrefSegments.splice(0, 1)
let userProfileUrl = '#/user/'
if (hrefSegments[0] === 'watch') {
const userProfileUrlInit = hrefSegments[1]
const userProfileUrlSpliced = userProfileUrlInit.split(':')
userProfileUrlSpliced.pop()
userProfileUrlSpliced.forEach((one) => {
if (one === userProfileUrlSpliced[0]) {
userProfileUrl = userProfileUrl + one + ':'
} else {
userProfileUrl = userProfileUrl + one
}
})
}
return userProfileUrl
}, [])
return (
<div>
<Navbar bg="light" expand="lg">
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
{!inEdit ? (
<>
<Breadcrumb>
<Breadcrumb.Item href="#/">Home</Breadcrumb.Item>
{urlSplit.map((el) =>
el === updateUrlSplit[1] && updateUrlSplit[0] === 'watch' ? (
<Breadcrumb.Item href={userProfileUrl} key={el} id={el}>
{el}
</Breadcrumb.Item>
) : (
<Breadcrumb.Item href={'#'} key={el} id={el}>
{el}
</Breadcrumb.Item>
),
)}
</Breadcrumb>
<Button
className="btn btn-light btn-sm"
style={{
marginLeft: '5px',
width: '40px',
height: '40px',
padding: '3.5%',
verticalAlign: 'baseline',
}}
onClick={startEdit}
>
<FaEdit style={{ textAlign: 'center', verticalAlign: 'initial' }} />
</Button>
</>
) : (
<FormControl
ref={urlForm}
defaultValue={(() => {
return location.hash.slice(1)
})()}
onKeyDown={finishEdit}
onBlur={exitEdit}
/>
)}
</Nav>
<Dropdown>
<Dropdown.Toggle variant="secondary" size="lg">
Options
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={() => copyToClip(window.location.hash)}>
Copy Current URL{' '}
<FaCopy size={28} onClick={() => copyToClip(window.location.hash)} />
</Dropdown.Item>
<Dropdown.Item onClick={goToClip}>
Go to Copied URL <FaArrowRight size={28} />
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Nav>
<Nav.Link>
<FaAngleLeft size={28} onClick={goBack} />
</Nav.Link>
<Nav.Link>
<FaAngleRight size={28} onClick={goForth} />
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
</div>
)
}
Example #17
Source File: ChangeEmail.tsx From bada-frame with GNU General Public License v3.0 | 4 votes |
function ChangeEmailForm(props: Props) {
const [loading, setLoading] = useState(false);
const [ottInputVisible, setShowOttInputVisibility] = useState(false);
const emailInputElement = useRef(null);
const ottInputRef = useRef(null);
const appContext = useContext(AppContext);
useEffect(() => {
setTimeout(() => {
emailInputElement.current?.focus();
}, 250);
}, []);
useEffect(() => {
if (!ottInputVisible) {
props.showMessage(false);
}
}, [ottInputVisible]);
const requestOTT = async (
{ email }: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
try {
setLoading(true);
await getOTTForEmailChange(email);
props.setEmail(email);
setShowOttInputVisibility(true);
props.showMessage(true);
setTimeout(() => {
ottInputRef.current?.focus();
}, 250);
} catch (e) {
setFieldError('email', `${constants.EMAIl_ALREADY_OWNED}`);
}
setLoading(false);
};
const requestEmailChange = async (
{ email, ott }: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
try {
setLoading(true);
await changeEmail(email, ott);
setData(LS_KEYS.USER, { ...getData(LS_KEYS.USER), email });
appContext.setDisappearingFlashMessage({
message: constants.EMAIL_UDPATE_SUCCESSFUL,
type: FLASH_MESSAGE_TYPE.SUCCESS,
});
router.push(PAGES.GALLERY);
} catch (e) {
setFieldError('ott', `${constants.INCORRECT_CODE}`);
}
setLoading(false);
};
return (
<Formik<formValues>
initialValues={{ email: '' }}
validationSchema={Yup.object().shape({
email: Yup.string()
.email(constants.EMAIL_ERROR)
.required(constants.REQUIRED),
})}
validateOnChange={false}
validateOnBlur={false}
onSubmit={!ottInputVisible ? requestOTT : requestEmailChange}>
{({ values, errors, touched, handleChange, handleSubmit }) => (
<Form noValidate onSubmit={handleSubmit}>
{!ottInputVisible ? (
<Form.Group controlId="formBasicEmail">
<Form.Control
ref={emailInputElement}
type="email"
placeholder={constants.ENTER_EMAIL}
value={values.email}
onChange={handleChange('email')}
isInvalid={Boolean(
touched.email && errors.email
)}
autoFocus
disabled={loading}
/>
<FormControl.Feedback type="invalid">
{errors.email}
</FormControl.Feedback>
</Form.Group>
) : (
<>
<EmailRow>
<Col xs="8">{values.email}</Col>
<Col xs="4">
<Button
variant="link"
onClick={() =>
setShowOttInputVisibility(false)
}>
{constants.CHANGE}
</Button>
</Col>
</EmailRow>
<Form.Group controlId="formBasicEmail">
<Form.Control
ref={ottInputRef}
type="text"
placeholder={constants.ENTER_OTT}
value={values.ott}
onChange={handleChange('ott')}
isInvalid={Boolean(
touched.ott && errors.ott
)}
disabled={loading}
/>
<FormControl.Feedback type="invalid">
{errors.ott}
</FormControl.Feedback>
</Form.Group>
</>
)}
<SubmitButton
buttonText={
!ottInputVisible
? constants.SEND_OTT
: constants.VERIFY
}
loading={loading}
/>
<br />
<Button
block
variant="link"
className="text-center"
onClick={router.back}>
{constants.GO_BACK}
</Button>
</Form>
)}
</Formik>
);
}
Example #18
Source File: AbuseReportForm.tsx From bada-frame with GNU General Public License v3.0 | 4 votes |
export function AbuseReportForm({ show, close, url }: Iprops) {
const [loading, setLoading] = useState(false);
const appContext = useContext(AppContext);
const publicCollectionGalleryContent = useContext(
PublicCollectionGalleryContext
);
const submitReport = async (
// eslint-disable-next-line @typescript-eslint/no-unused-vars
{ url, reason, terms, ...details }: FormValues,
{ setFieldError }: FormikHelpers<FormValues>
) => {
try {
setLoading(true);
if (reason === REPORT_REASON.MALICIOUS_CONTENT) {
details.address = undefined;
details.onBehalfOf = undefined;
details.jobTitle = undefined;
}
if (!details.comment) {
details.comment = undefined;
}
await reportAbuse(
publicCollectionGalleryContent.token,
url,
reason,
details
);
close();
appContext.setDialogMessage({
title: constants.REPORT_SUBMIT_SUCCESS_TITLE,
content: constants.REPORT_SUBMIT_SUCCESS_CONTENT,
close: { text: constants.OK },
});
} catch (e) {
setFieldError('signature', constants.REPORT_SUBMIT_FAILED);
} finally {
setLoading(false);
}
};
return (
<MessageDialog
show={show}
size="lg"
onHide={close}
attributes={{
title: constants.ABUSE_REPORT,
staticBackdrop: true,
}}>
<Wrapper>
<h6>{constants.ABUSE_REPORT_DESCRIPTION}</h6>
<Formik<FormValues>
initialValues={{
...defaultInitialValues,
url,
}}
validationSchema={Yup.object().shape({
reason: Yup.mixed<keyof typeof REPORT_REASON>()
.oneOf(Object.values(REPORT_REASON))
.required(constants.REQUIRED),
url: Yup.string().required(constants.REQUIRED),
fullName: Yup.string().required(constants.REQUIRED),
email: Yup.string()
.email()
.required(constants.REQUIRED),
comment: Yup.string(),
signature: Yup.string().required(constants.REQUIRED),
onBehalfOf: Yup.string().when('reason', {
is: REPORT_REASON.COPYRIGHT,
then: Yup.string().required(constants.REQUIRED),
}),
jobTitle: Yup.string().when('reason', {
is: REPORT_REASON.COPYRIGHT,
then: Yup.string().required(constants.REQUIRED),
}),
address: Yup.object().when('reason', {
is: REPORT_REASON.COPYRIGHT,
then: Yup.object().shape({
city: Yup.string().required(constants.REQUIRED),
state: Yup.string().required(
constants.REQUIRED
),
country: Yup.string().required(
constants.REQUIRED
),
postalCode: Yup.string().required(
constants.REQUIRED
),
phone: Yup.string().required(
constants.REQUIRED
),
}),
}),
terms: Yup.object().when('reason', {
is: REPORT_REASON.COPYRIGHT,
then: Yup.object().shape({
1: Yup.boolean(),
2: Yup.boolean(),
3: Yup.boolean(),
}),
}),
})}
validateOnChange={false}
validateOnBlur={false}
onSubmit={submitReport}>
{({
values,
errors,
touched,
handleChange,
handleSubmit,
}): JSX.Element => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group controlId="reportForm.url">
<Form.Label>{constants.ALBUM_URL}</Form.Label>
<Form.Control
type="text"
disabled
value={url}
/>
</Form.Group>
<Form.Group controlId="reportForm.reason">
<Form.Control
as="select"
value={values.reason}
onChange={handleChange('reason')}
isInvalid={Boolean(
touched.reason && errors.reason
)}
autoFocus
disabled={loading}>
<option disabled selected>
select reason
</option>
{Object.values(REPORT_REASON).map(
(reason) => (
<option key={reason} value={reason}>
{constants[reason]}
</option>
)
)}
</Form.Control>
<FormControl.Feedback type="invalid">
{constants.SELECT_REASON}
</FormControl.Feedback>
</Form.Group>
<Row>
<Col md={6}>
<Form.Group controlId="reportForm.fullName">
<Form.Control
type="text"
placeholder={
constants.ENTER_FULL_NAME
}
value={values.fullName}
onChange={handleChange('fullName')}
isInvalid={Boolean(
touched.fullName &&
errors.fullName
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.fullName}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={6}>
<Form.Group controlId="reportForm.email">
<Form.Control
type="text"
placeholder={
constants.ENTER_EMAIL_ADDRESS
}
value={values.email}
onChange={handleChange('email')}
isInvalid={Boolean(
touched.email && errors.email
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.email}
</Form.Control.Feedback>
</Form.Group>
</Col>
</Row>
{values.reason === REPORT_REASON.COPYRIGHT && (
<>
<Row>
<Col md={6}>
{' '}
<Form.Group controlId="reportForm.onBehalfOf">
<Form.Control
type="text"
placeholder={
constants.ENTER_ON_BEHALF_OF
}
value={values.onBehalfOf}
onChange={handleChange(
'onBehalfOf'
)}
isInvalid={Boolean(
touched.onBehalfOf &&
errors.onBehalfOf
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.onBehalfOf}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={6}>
<Form.Group controlId="reportForm.jobTitle">
<Form.Control
type="text"
placeholder={
constants.ENTER_JOB_TITLE
}
value={values.jobTitle}
onChange={handleChange(
'jobTitle'
)}
isInvalid={Boolean(
touched.jobTitle &&
errors.jobTitle
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.jobTitle}
</Form.Control.Feedback>
</Form.Group>
</Col>
</Row>
<Row>
<Col md={6}>
<Form.Group controlId="reportForm.address">
<Form.Control
type="text"
placeholder={
constants.ENTER_ADDRESS
}
value={
values.address.street
}
onChange={handleChange(
'address.street'
)}
isInvalid={Boolean(
touched.address
?.street &&
errors.address
?.street
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.street}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={6}>
<Form.Group controlId="reportForm.address.city">
<Form.Control
type="text"
placeholder={
constants.ENTER_CITY
}
value={values.address.city}
onChange={handleChange(
'address.city'
)}
isInvalid={Boolean(
touched.address?.city &&
errors.address?.city
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.city}
</Form.Control.Feedback>
</Form.Group>
</Col>
</Row>
<Row>
<Col md={6}>
{' '}
<Form.Group controlId="reportForm.address.phone">
<Form.Control
type="text"
placeholder={
constants.ENTER_PHONE
}
value={values.address.phone}
onChange={handleChange(
'address.phone'
)}
isInvalid={Boolean(
touched.address
?.phone &&
errors.address
?.phone
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.phone}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={6}>
{' '}
<Form.Group controlId="reportForm.address.state">
<Form.Control
type="text"
placeholder={
constants.ENTER_STATE
}
value={values.address.state}
onChange={handleChange(
'address.state'
)}
isInvalid={Boolean(
touched.address
?.state &&
errors.address
?.state
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.state}
</Form.Control.Feedback>
</Form.Group>
</Col>
</Row>
<Row>
<Col md={6}>
{' '}
<Form.Group controlId="reportForm.address.postalCode">
<Form.Control
type="text"
placeholder={
constants.ENTER_POSTAL_CODE
}
value={
values.address
.postalCode
}
onChange={handleChange(
'address.postalCode'
)}
isInvalid={Boolean(
touched.address
?.postalCode &&
errors.address
?.postalCode
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.postalCode}
</Form.Control.Feedback>
</Form.Group>
</Col>
<Col md={6}>
{' '}
<Form.Group controlId="reportForm.address.country">
<Form.Control
type="text"
placeholder={
constants.ENTER_COUNTRY
}
value={
values.address.country
}
onChange={handleChange(
'address.country'
)}
isInvalid={Boolean(
touched.address
?.country &&
errors.address
?.country
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.address?.country}
</Form.Control.Feedback>
</Form.Group>
</Col>
</Row>
</>
)}
<Form.Group controlId="reportForm.comment">
<Form.Control
type="text-area"
placeholder={constants.COMMENT}
as="textarea"
value={values.comment}
onChange={handleChange('comment')}
isInvalid={Boolean(
touched.comment && errors.comment
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.comment}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="reportForm.signature">
<Form.Control
type="text"
placeholder={
constants.ENTER_DIGITAL_SIGNATURE
}
value={values.signature}
onChange={handleChange('signature')}
isInvalid={Boolean(
touched.signature && errors.signature
)}
disabled={loading}
/>
<Form.Control.Feedback type="invalid">
{errors.signature}
</Form.Control.Feedback>
</Form.Group>
<Wrapper>
{values.reason === REPORT_REASON.COPYRIGHT && (
<>
<h6>
{constants.JUDICIAL_DESCRIPTION()}
</h6>
<Form.Group controlId="formBasicCheckbox-1">
<Form.Check
checked={values.terms[1]}
onChange={handleChange(
'terms[1]'
)}
isInvalid={Boolean(
touched.terms?.[1] &&
errors.terms?.[1]
)}
disabled={loading}
type="checkbox"
label={constants.TERM_1}
/>
</Form.Group>
<Form.Group controlId="formBasicCheckbox-2">
<Form.Check
checked={values.terms[2]}
onChange={handleChange(
'terms[2]'
)}
isInvalid={Boolean(
touched.terms?.[2] &&
errors.terms?.[2]
)}
disabled={loading}
type="checkbox"
label={constants.TERM_2}
/>
</Form.Group>
<Form.Group controlId="formBasicCheckbox-3">
<Form.Check
checked={values.terms[3]}
onChange={handleChange(
'terms[3]'
)}
isInvalid={Boolean(
touched.terms?.[3] &&
errors.terms?.[3]
)}
disabled={loading}
type="checkbox"
label={constants.TERM_3}
/>
</Form.Group>
</>
)}
</Wrapper>
<SubmitButton
buttonText={constants.SUBMIT}
loading={loading}
disabled={
values.reason === REPORT_REASON.COPYRIGHT &&
(!values.terms[1] ||
!values.terms[2] ||
!values.terms[3])
}
/>
</Form>
)}
</Formik>
</Wrapper>
</MessageDialog>
);
}
Example #19
Source File: index.tsx From react-bootstrap-country-select with MIT License | 4 votes |
CountrySelect = ({
value,
onChange = () => {},
onTextChange,
countries = [ ...COUNTRIES ],
exclusions,
additions,
valueAs = 'object',
flags = true,
flush = true,
disabled = false,
placeholder = 'Type or select country...',
noMatchesText = 'No matches',
size,
sort, // e.g. (c1, c2) => c1.name < c2.name ? -1 : (c1.name > c2.name ? 1 : 0),
matchNameFromStart = true,
matchAbbreviations = false,
countryLabelFormatter = ({ name }) => name,
throwInvalidValueError = false,
listMaxHeight,
closeOnSelect = true,
formControlProps = {},
overlayProps = {},
classPrefix = DEFAULT_CLASS_PREFIX,
className,
}: CountrySelectProps) => {
const inputGroupRef = useRef(null);
const formControlRef = useRef(null);
const hasInitRef = useRef(false);
const [ width, setWidth ] = useState(-1);
const [ {
focused,
inputText,
list,
activeListItemIndex,
combinedCountries,
}, dispatch ] = useReducer(reducer, INITIAL_STATE);
const handleFocus = focus(dispatch);
const handleBlur = blur(dispatch);
const handleTextChange = textChange(dispatch);
const handleListActiveItemChange = activeListItemChange(dispatch);
const handleCountrySelect = countrySelect(dispatch);
const handleClear = clear(dispatch);
const getCountryId = (value: ICountry | string): string => (typeof value === 'string' ? value : value.id);
const selectedCountry = value ? (combinedCountries || []).find(country => country.id === getCountryId(value)) : null;
if (throwInvalidValueError && value && !selectedCountry)
throw new Error(`No matching country for value: ${JSON.stringify(value)}`);
useEffect(() => {
if (hasInitRef.current) return;
const combinedCountries = applyExclusionsAndAdditions(countries, exclusions, additions);
const sorted = getInitialList(combinedCountries, sort);
init(dispatch)(sorted);
hasInitRef.current = true;
}, [ countries, exclusions, additions, sort ]);
useEffect(() => {
setWidth(inputGroupRef.current.offsetWidth);
}, [ inputGroupRef ]);
const select = listItemIndex => {
const country = list[listItemIndex];
handleCountrySelect();
onChange(valueAs === 'id' ? country.id : country);
};
const escape = () => {
handleClear();
onChange(null);
};
const inputChange = (text, ev) => {
if (selectedCountry && flags) {
text = removeEmojiFlag(text);
}
const [ updatedList, updatedActiveListItemIndex ]
= getUpdatedList(text, list, activeListItemIndex, combinedCountries, sort, matchNameFromStart, matchAbbreviations);
handleTextChange(text, updatedList, updatedActiveListItemIndex);
if (onTextChange) onTextChange(text, ev);
if (value) onChange(null);
};
const handleKey = ev => {
if (ev.key === 'ArrowUp') {
ev.preventDefault();
const newIndex = activeListItemIndex <= 0 ? list.length - 1 : activeListItemIndex - 1;
handleListActiveItemChange(newIndex);
} else if (ev.key === 'ArrowDown') {
const newIndex = activeListItemIndex >= list.length - 1 ? 0 : activeListItemIndex + 1;
handleListActiveItemChange(newIndex);
} else if (ev.key === 'Enter') {
if (activeListItemIndex >= 0) select(activeListItemIndex)
} else if (ev.key === 'Escape') {
escape();
}
};
const classes = classNames([
className,
classPrefix,
flush && `${classPrefix}--flush`,
]);
return (
<div className={classes}>
<InputGroup
ref={inputGroupRef}
className={`${classPrefix}__input-group`}
size={size}
>
{ (!flush && flags) &&
<InputGroup.Prepend>
<InputGroup.Text
className={`${classPrefix}__input-group__flag`}
>
{selectedCountry ? selectedCountry.flag : ''}
</InputGroup.Text>
</InputGroup.Prepend>
}
<FormControl
ref={formControlRef}
className={`${classPrefix}__form-control`}
value={selectedCountry ? `${flush && flags ? selectedCountry.flag + ' ' : ''}${selectedCountry.name}` : inputText}
onKeyDown={handleKey}
onChange={ev => inputChange(ev.target.value, ev)}
onFocus={handleFocus}
onBlur={handleBlur}
placeholder={placeholder}
disabled={disabled}
spellCheck={false}
autoComplete='new-value'
{...formControlProps}
/>
</InputGroup>
<Overlay
target={inputGroupRef.current}
rootClose
placement='bottom-start'
show={focused && (!selectedCountry || !closeOnSelect)} // experimental; not documented
onHide={() => {}}
transition
{...overlayProps}
>
{({ placement, arrowProps, show: _show, popper, ...props }) => (
<div
{...props}
style={{
width: (width > 0) ? `${width}px` : 'calc(100% - 10px)',
...props.style,
}}
>
<OverlayContent
classPrefix={classPrefix}
list={list}
activeListItemIndex={activeListItemIndex}
countryLabelFormatter={countryLabelFormatter}
flags={flags}
noMatchesText={noMatchesText}
maxHeight={listMaxHeight}
onListItemClick={select}
/>
</div>
)}
</Overlay>
</div>
);
}
Example #20
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
Bid: React.FC<{
auction: Auction;
auctionEnded: boolean;
}> = props => {
const activeAccount = useAppSelector(state => state.account.activeAccount);
const { library } = useEthers();
let { auction, auctionEnded } = props;
const activeLocale = useActiveLocale();
const nounsAuctionHouseContract = new NounsAuctionHouseFactory().attach(
config.addresses.nounsAuctionHouseProxy,
);
const account = useAppSelector(state => state.account.activeAccount);
const bidInputRef = useRef<HTMLInputElement>(null);
const [bidInput, setBidInput] = useState('');
const [bidButtonContent, setBidButtonContent] = useState({
loading: false,
content: auctionEnded ? <Trans>Settle</Trans> : <Trans>Place bid</Trans>,
});
const [showConnectModal, setShowConnectModal] = useState(false);
const hideModalHandler = () => {
setShowConnectModal(false);
};
const dispatch = useAppDispatch();
const setModal = useCallback((modal: AlertModal) => dispatch(setAlertModal(modal)), [dispatch]);
const minBidIncPercentage = useAuctionMinBidIncPercentage();
const minBid = computeMinimumNextBid(
auction && new BigNumber(auction.amount.toString()),
minBidIncPercentage,
);
const { send: placeBid, state: placeBidState } = useContractFunction(
nounsAuctionHouseContract,
AuctionHouseContractFunction.createBid,
);
const { send: settleAuction, state: settleAuctionState } = useContractFunction(
nounsAuctionHouseContract,
AuctionHouseContractFunction.settleCurrentAndCreateNewAuction,
);
const bidInputHandler = (event: ChangeEvent<HTMLInputElement>) => {
const input = event.target.value;
// disable more than 2 digits after decimal point
if (input.includes('.') && event.target.value.split('.')[1].length > 2) {
return;
}
setBidInput(event.target.value);
};
const placeBidHandler = async () => {
if (!auction || !bidInputRef.current || !bidInputRef.current.value) {
return;
}
if (currentBid(bidInputRef).isLessThan(minBid)) {
setModal({
show: true,
title: <Trans>Insufficient bid amount ?</Trans>,
message: (
<Trans>
Please place a bid higher than or equal to the minimum bid amount of {minBidEth(minBid)}{' '}
ETH
</Trans>
),
});
setBidInput(minBidEth(minBid));
return;
}
const value = utils.parseEther(bidInputRef.current.value.toString());
const contract = connectContractToSigner(nounsAuctionHouseContract, undefined, library);
const gasLimit = await contract.estimateGas.createBid(auction.nounId, {
value,
});
placeBid(auction.nounId, {
value,
gasLimit: gasLimit.add(10_000), // A 10,000 gas pad is used to avoid 'Out of gas' errors
});
};
const settleAuctionHandler = () => {
settleAuction();
};
const clearBidInput = () => {
if (bidInputRef.current) {
bidInputRef.current.value = '';
}
};
// successful bid using redux store state
useEffect(() => {
if (!account) return;
// tx state is mining
const isMiningUserTx = placeBidState.status === 'Mining';
// allows user to rebid against themselves so long as it is not the same tx
const isCorrectTx = currentBid(bidInputRef).isEqualTo(new BigNumber(auction.amount.toString()));
if (isMiningUserTx && auction.bidder === account && isCorrectTx) {
placeBidState.status = 'Success';
setModal({
title: <Trans>Success</Trans>,
message: <Trans>Bid was placed successfully!</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Place bid</Trans> });
clearBidInput();
}
}, [auction, placeBidState, account, setModal]);
// placing bid transaction state hook
useEffect(() => {
switch (!auctionEnded && placeBidState.status) {
case 'None':
setBidButtonContent({
loading: false,
content: <Trans>Place bid</Trans>,
});
break;
case 'Mining':
setBidButtonContent({ loading: true, content: <></> });
break;
case 'Fail':
setModal({
title: <Trans>Transaction Failed</Trans>,
message: placeBidState?.errorMessage || <Trans>Please try again.</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Bid</Trans> });
break;
case 'Exception':
setModal({
title: <Trans>Error</Trans>,
message: placeBidState?.errorMessage || <Trans>Please try again.</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Bid</Trans> });
break;
}
}, [placeBidState, auctionEnded, setModal]);
// settle auction transaction state hook
useEffect(() => {
switch (auctionEnded && settleAuctionState.status) {
case 'None':
setBidButtonContent({
loading: false,
content: <Trans>Settle Auction</Trans>,
});
break;
case 'Mining':
setBidButtonContent({ loading: true, content: <></> });
break;
case 'Success':
setModal({
title: <Trans>Success</Trans>,
message: <Trans>Settled auction successfully!</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Settle Auction</Trans> });
break;
case 'Fail':
setModal({
title: <Trans>Transaction Failed</Trans>,
message: settleAuctionState?.errorMessage || <Trans>Please try again.</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Settle Auction</Trans> });
break;
case 'Exception':
setModal({
title: <Trans>Error</Trans>,
message: settleAuctionState?.errorMessage || <Trans>Please try again.</Trans>,
show: true,
});
setBidButtonContent({ loading: false, content: <Trans>Settle Auction</Trans> });
break;
}
}, [settleAuctionState, auctionEnded, setModal]);
if (!auction) return null;
const isDisabled =
placeBidState.status === 'Mining' || settleAuctionState.status === 'Mining' || !activeAccount;
const fomoNounsBtnOnClickHandler = () => {
// Open Fomo Nouns in a new tab
window.open('https://fomonouns.wtf', '_blank')?.focus();
};
const isWalletConnected = activeAccount !== undefined;
return (
<>
{showConnectModal && activeAccount === undefined && (
<WalletConnectModal onDismiss={hideModalHandler} />
)}
<InputGroup>
{!auctionEnded && (
<>
<span className={classes.customPlaceholderBidAmt}>
{!auctionEnded && !bidInput ? (
<>
Ξ {minBidEth(minBid)}{' '}
<span
className={
activeLocale === 'ja-JP' ? responsiveUiUtilsClasses.disableSmallScreens : ''
}
>
<Trans>or more</Trans>
</span>
</>
) : (
''
)}
</span>
<FormControl
className={classes.bidInput}
type="number"
min="0"
onChange={bidInputHandler}
ref={bidInputRef}
value={bidInput}
/>
</>
)}
{!auctionEnded ? (
<Button
className={auctionEnded ? classes.bidBtnAuctionEnded : classes.bidBtn}
onClick={auctionEnded ? settleAuctionHandler : placeBidHandler}
disabled={isDisabled}
>
{bidButtonContent.loading ? <Spinner animation="border" /> : bidButtonContent.content}
</Button>
) : (
<>
<Col lg={12} className={classes.voteForNextNounBtnWrapper}>
<Button className={classes.bidBtnAuctionEnded} onClick={fomoNounsBtnOnClickHandler}>
<Trans>Vote for the next Noun</Trans> ⌐◧-◧
</Button>
</Col>
{/* Only show force settle button if wallet connected */}
{isWalletConnected && (
<Col lg={12}>
<SettleManuallyBtn settleAuctionHandler={settleAuctionHandler} auction={auction} />
</Col>
)}
</>
)}
</InputGroup>
</>
);
}
Example #21
Source File: PinsView.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
export function PinsView() {
const [pinList, setPinList] = useState([])
const [newVideos, setNewVideos] = useState([])
const [trendingVideos, setTrendingVideos] = useState([])
const [showExplorer, setShowExplorer] = useState(false)
const pid = useRef<any>()
const updateSearchTables = (community = null, creator = null) => {
const ids = pinList.map((x) => {
return x._id
})
console.log(ids)
const params = '?limit=10&ipfsOnly=true'
let newUrl = `https://3speak.tv/apiv2/feeds/new${params}`
let trendingUrl = `https://3speak.tv/apiv2/feeds/trending${params}`
if (community) {
newUrl = `https://3speak.tv/apiv2/feeds/community/${community}/new${params}`
trendingUrl = `https://3speak.tv/apiv2/feeds/community/${community}/trending${params}`
} else if (creator && creator.length > 2) {
newUrl = `https://3speak.tv/apiv2/feeds/@${creator}`
trendingUrl = null
}
fetch(newUrl)
.then((r) => r.json())
.then((r) => {
for (const video of r) {
const id = `hive:${video.author}:${video.permlink}`
video.isPinned = ids.includes(id)
video.id = id
}
console.log(r)
setNewVideos(r)
})
if (!trendingUrl) {
setTrendingVideos([])
} else {
fetch(trendingUrl)
.then((r) => r.json())
.then((r) => {
for (const video of r) {
const id = `hive:${video.author}:${video.permlink}`
video.isPinned = ids.includes(id)
video.id = id
}
setTrendingVideos(r)
})
}
}
const generate = async () => {
// type error - 2 arguments expected
setPinList(await PromiseIpc.send('pins.ls', undefined as any))
}
const PinLocally = async (cids, title, _id) => {
debug(`CIDs to store ${JSON.stringify(cids)}`)
if (cids.length !== 0) {
NotificationManager.info('Pinning in progress')
await PromiseIpc.send('pins.add', {
_id,
source: 'Pins page',
cids,
expire: null,
meta: {
title,
},
} as any)
NotificationManager.success(
`Video with title of ${title} has been successfully pinned! Thank you for contributing!`,
'Pin Successful',
)
} else {
NotificationManager.warning('This video is not available on IPFS')
}
await generate()
}
const actionSelect = async (key) => {
console.log(key)
switch (key) {
case '1': {
const func = () =>
new Promise(async (resolve, reject) => {
const ref = React.createRef() as any
Popup.create({
content: (
<div>
<Form ref={ref}>
<Form.Label>Reflink</Form.Label>
<FormControl
name="reflink"
placeholder="hive:username:123permlink"
></FormControl>
</Form>
</div>
),
buttons: {
left: [
{
text: 'Cancel',
className: 'secondary',
action: function () {
Popup.close()
},
},
],
right: [
{
text: 'Done',
className: 'success',
action: function () {
resolve(FormUtils.formToObj(new FormData(ref.current)))
Popup.close()
},
},
],
},
})
})
const ret = (await func()) as any
const video_info = await AccountService.permalinkToVideoInfo(ret.reflink)
const cids = []
for (const source of video_info.sources) {
const url = new (require('url').URL)(source.url)
try {
new CID(url.host)
cids.push(url.host)
} catch (ex) {
console.error(ex)
}
}
if (cids.length !== 0) {
NotificationManager.info('Pinning in progress')
await PromiseIpc.send('pins.add', {
_id: ret.reflink,
source: 'Manual Add',
cids,
expire: null,
meta: {
title: video_info.title,
},
} as any)
NotificationManager.success(
`Video with reflink of ${ret.reflink} has been successfully pinned! Thank you for contributing!`,
'Pin Successful',
)
} else {
NotificationManager.warning('This video is not available on IPFS')
}
break
}
case '2': {
NotificationManager.info('GC has started')
const { ipfs } = await IpfsHandler.getIpfs()
ipfs.repo.gc()
break
}
default: {
}
}
}
const removePin = async (reflink) => {
try {
await PromiseIpc.send('pins.rm', reflink)
NotificationManager.success('IPFS pin removal complete')
await generate()
} catch (ex) {
NotificationManager.error('IPFS pin removal resulted in error')
console.error(ex)
}
}
useEffect(() => {
document.title = '3Speak - Tokenised video communities'
void generate()
pid.current = setInterval(generate, 1500)
updateSearchTables()
return () => {
clearInterval(pid.current)
}
}, [])
const pinRows = useMemo(() => {
const rows = []
for (const pin of pinList) {
const sizeBest = bytesAsString(pin.size)
rows.push(
<tr key={pin._id}>
<td>
<a href={`#/watch/${pin._id}`}>{pin._id}</a>
<br />(<strong>{RefLink.parse(pin._id).root}</strong>)
</td>
<td>
<a href={`#/watch/${pin._id}`}>{pin.meta ? pin.meta.title : null} </a>
</td>
<td>
{pin.cids.length > 1 ? (
<a
onClick={() => {
Popup.create({
title: 'CIDs',
content: (
<div>
<Editor value={pin.cids} ace={ace} theme="ace/theme/github"></Editor>
</div>
),
buttons: {
left: [],
right: [
{
text: 'close',
key: '⌘+s',
className: 'success',
action: function () {
Popup.close()
},
},
],
},
})
}}
>
View ({pin.cids.length})
</a>
) : (
pin.cids
)}
</td>
<td>{pin.source}</td>
<td>
{pin.expire
? (() => {
console.log(pin.expire)
return 'In ' + millisecondsAsString((pin.expire = new Date().getTime()))
})()
: 'Permanent'}
</td>
<td>
{pin.meta.pin_date
? (() => {
console.log(pin.meta.pin_date)
return new Date(pin.meta.pin_date).toLocaleString()
})()
: null}
</td>
<td>{pin.size === 0 ? <strong>Pinning In Progress</strong> : sizeBest}</td>
<td>
<Button variant="danger" onClick={() => removePin(pin._id)}>
X
</Button>
</td>
</tr>,
)
}
return rows
}, [pinList])
return (
<div>
<Row>
<Col style={{ textAlign: 'right' }}>
<Dropdown onSelect={actionSelect}>
<Dropdown.Toggle as={CustomPinsViewToggle} id="dropdown-custom-components">
<Button>Actions</Button>
</Dropdown.Toggle>
<Dropdown.Menu as={CustomPinsViewMenu}>
<Dropdown.Item eventKey="1">Manual Pin</Dropdown.Item>
<Dropdown.Item eventKey="2">Manual GC</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Col>
</Row>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Reflink</th>
<th>Title</th>
<th>CID(s)</th>
<th>Source</th>
<th>Expiration</th>
<th>Pin Date</th>
<th>Size/Status</th>
<th>Remove?</th>
</tr>
</thead>
<tbody>{pinRows}</tbody>
</Table>
<Button
onClick={() => {
setShowExplorer(!showExplorer)
}}
>
Toggle pin explorer
</Button>
{showExplorer && (
<>
<h6>Select to pin and help secure the network by backing up videos</h6>
<input
type="text"
placeholder="Enter community ID..."
onChange={(event) => {
if (event.target.value.match(/\bhive-\d{6}\b/g)) {
updateSearchTables(event.target.value, null)
}
}}
/>
<input
type="text"
placeholder="Enter a username"
onChange={(event) => {
updateSearchTables(null, event.target.value)
}}
/>
<Row>
{['new', 'trending'].map((type: 'new' | 'trending') => (
<Col key={type}>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>{type} videos</th>
<th>Title</th>
<th>Creator</th>
<th>pinned</th>
</tr>
</thead>
<tbody>
{/* {this.state[`${type}Videos`].map((video) => ( */}
{(type === 'new' ? newVideos : trendingVideos).map((video) => (
<tr key={`${type}-${video.author}-${video.permlink}`}>
<td>
<div className="teaser_holder video-card-image">
<div className="card-label">
{(() => {
const pattern = DateTime.compile('mm:ss')
return DateTime.format(new Date(video.duration * 1000), pattern)
})()}
</div>
<a href={`#/watch/hive:${video.author}:${video.permlink}`}>
<img
className="img-fluid bg-dark"
src={video.images.thumbnail}
alt=""
/>
</a>
</div>
</td>
<td>{video.title}</td>
<td>{video.author}</td>
<td>
{video.isPinned ? (
<Button
variant="danger"
onClick={async () => {
await removePin(video.id)
updateSearchTables()
}}
>
X
</Button>
) : (
<Button
variant="success"
onClick={async () => {
await PinLocally([video.ipfs], video.title, video.id)
updateSearchTables()
}}
>
O
</Button>
)}
</td>
</tr>
))}
</tbody>
</Table>
</Col>
))}
</Row>
</>
)}
</div>
)
}
Example #22
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
ProposalTransactionFormModal = ({
show,
onHide,
onProposalTransactionAdded,
}: ProposalTransactionFormModalProps) => {
const [address, setAddress] = useState('');
const [abi, setABI] = useState<Interface>();
const [value, setValue] = useState('');
const [func, setFunction] = useState('');
const [args, setArguments] = useState<string[]>([]);
const [isABIUploadValid, setABIUploadValid] = useState<boolean>();
const [abiFileName, setABIFileName] = useState<string | undefined>('');
const addressValidator = (s: string) => {
if (!utils.isAddress(s)) {
return false;
}
// To avoid blocking stepper progress, do not `await`
populateABIIfExists(s);
return true;
};
const valueValidator = (v: string) => !v || !new BigNumber(v).isNaN();
const argumentsValidator = (a: string[]) => {
if (!func) {
return true;
}
try {
return !!abi?._encodeParams(abi?.functions[func]?.inputs, args);
} catch {
return false;
}
};
const setArgument = (index: number, value: string) => {
const values = [...args];
values[index] = value;
setArguments(values);
};
let abiErrorTimeout: NodeJS.Timeout;
const setABIInvalid = () => {
setABIUploadValid(false);
setABIFileName(undefined);
abiErrorTimeout = setTimeout(() => {
setABIUploadValid(undefined);
}, 5_000);
};
const validateAndSetABI = (file: File | undefined) => {
if (abiErrorTimeout) {
clearTimeout(abiErrorTimeout);
}
if (!file) {
return;
}
const reader = new FileReader();
reader.onload = async e => {
try {
const abi = e?.target?.result?.toString() ?? '';
setABI(new Interface(JSON.parse(abi)));
setABIUploadValid(true);
setABIFileName(file.name);
} catch {
setABIInvalid();
}
};
reader.readAsText(file);
};
const getContractInformation = async (address: string) => {
const response = await fetch(buildEtherscanApiQuery(address));
const json = await response.json();
return json?.result?.[0];
};
const getABI = async (address: string) => {
let info = await getContractInformation(address);
if (info?.Proxy === '1' && utils.isAddress(info?.Implementation)) {
info = await getContractInformation(info.Implementation);
}
return info.ABI;
};
const populateABIIfExists = async (address: string) => {
if (abiErrorTimeout) {
clearTimeout(abiErrorTimeout);
}
try {
const result = await getABI(address);
setABI(new Interface(JSON.parse(result)));
setABIUploadValid(true);
setABIFileName('etherscan-abi-download.json');
} catch {
setABIUploadValid(undefined);
setABIFileName(undefined);
}
};
const stepForwardOrCallback = () => {
if (currentStep !== steps.length - 1) {
return stepForward();
}
onProposalTransactionAdded({
address,
value: value ? utils.parseEther(value).toString() : '0',
signature: func,
calldata: (func && abi?._encodeParams(abi?.functions[func]?.inputs, args)) || '0x',
});
clearState();
};
const steps = [
{
label: 'Address',
name: 'address',
validator: () => addressValidator(address),
},
{
label: 'Value',
name: 'value',
validator: () => valueValidator(value),
},
{
label: 'Function',
name: 'function',
},
{
label: 'Arguments',
name: 'arguments',
validator: () => argumentsValidator(args),
},
{
label: 'Summary',
name: 'summary',
},
];
const { stepForward, stepBackwards, currentStep } = useStepProgress({
steps,
startingStep: 0,
});
const clearState = () => {
setAddress('');
setABI(undefined);
setValue('');
setFunction('');
setArguments([]);
setABIUploadValid(undefined);
setABIFileName(undefined);
for (let i = currentStep; i > 0; i--) {
stepBackwards();
}
};
return (
<Modal
show={show}
onHide={() => {
onHide();
clearState();
}}
dialogClassName={classes.transactionFormModal}
centered
>
<Modal.Header closeButton>
<Modal.Title>
<Trans>Add a Proposal Transaction</Trans>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<StepProgressBar className={classes.stepProgressBar} steps={steps} />
<Step step={0}>
<label htmlFor="callee-address">
<Trans>Address (Callee or Recipient)</Trans>
</label>
<FormControl
value={address}
type="text"
id="callee-address"
onChange={e => setAddress(e.target.value)}
/>
</Step>
<Step step={1}>
<label htmlFor="eth-value">
<Trans>Value in ETH (Optional)</Trans>
</label>
<FormControl value={value} id="eth-value" onChange={e => setValue(e.target.value)} />
</Step>
<Step step={2}>
<label htmlFor="function">
<Trans>Function (Optional)</Trans>
</label>
<FormControl
value={func}
as="select"
id="function"
onChange={e => setFunction(e.target.value)}
>
<option className="text-muted">Select Contract Function</option>
{abi && Object.keys(abi.functions).map(func => <option value={func}>{func}</option>)}
</FormControl>
<label style={{ marginTop: '1rem' }} htmlFor="import-abi">
{abiFileName === 'etherscan-abi-download.json' ? abiFileName : 'ABI'}
</label>
<Form.Control
type="file"
id="import-abi"
accept="application/JSON"
isValid={isABIUploadValid}
isInvalid={isABIUploadValid === false}
onChange={(e: ChangeEvent<HTMLInputElement>) => validateAndSetABI(e.target.files?.[0])}
/>
</Step>
<Step step={3}>
{abi?.functions[func]?.inputs?.length ? (
<FormGroup as={Row}>
{abi?.functions[func]?.inputs.map((input, i) => (
<>
<FormLabel column sm="3">
{input.name}
</FormLabel>
<Col sm="9">
<InputGroup className="mb-2">
<InputGroup.Text className={classes.inputGroupText}>
{input.type}
</InputGroup.Text>
<FormControl
value={args[i] ?? ''}
onChange={e => setArgument(i, e.target.value)}
/>
</InputGroup>
</Col>
</>
))}
</FormGroup>
) : (
<Trans>No arguments required </Trans>
)}
</Step>
<Step step={4}>
<Row>
<Col sm="3">
<b>
<Trans>Address</Trans>
</b>
</Col>
<Col sm="9" className="text-break">
<a href={buildEtherscanAddressLink(address)} target="_blank" rel="noreferrer">
{address}
</a>
</Col>
</Row>
<Row>
<Col sm="3">
<b>
<Trans>Value</Trans>
</b>
</Col>
<Col sm="9">{value ? `${value} ETH` : <Trans>None</Trans>}</Col>
</Row>
<Row>
<Col sm="3">
<b>
<Trans>Function</Trans>
</b>
</Col>
<Col sm="9" className="text-break">
{func || <Trans>None</Trans>}
</Col>
</Row>
<Row>
<Col sm="3">
<b>
<Trans>Arguments</Trans>
</b>
</Col>
<Col sm="9">
<hr />
</Col>
<Col sm="9">{abi?.functions[func]?.inputs?.length ? '' : <Trans>None</Trans>}</Col>
</Row>
{abi?.functions[func]?.inputs.map((input, i) => (
<Row key={i}>
<Col sm="3" className={classes.functionName}>
{i + 1}. {input.name}
</Col>
<Col sm="9" className="text-break">
{args[i]}
</Col>
</Row>
))}
</Step>
<div className="d-flex justify-content-between align-items-center pt-3">
<Button
onClick={stepBackwards}
variant="outline-secondary"
size="lg"
disabled={currentStep === 0}
>
<Trans>Back</Trans>
</Button>
<Button onClick={stepForwardOrCallback} variant="primary" size="lg">
{currentStep !== steps.length - 1 ? (
<Trans>Next</Trans>
) : (
<Trans>Add Transaction</Trans>
)}
</Button>
</div>
</Modal.Body>
</Modal>
);
}
Example #23
Source File: index.tsx From nouns-monorepo with GNU General Public License v3.0 | 4 votes |
VoteModal = ({ show, onHide, proposalId, availableVotes }: VoteModalProps) => {
const { castVote, castVoteState } = useCastVote();
const { castVoteWithReason, castVoteWithReasonState } = useCastVoteWithReason();
const [vote, setVote] = useState<Vote>();
const [voteReason, setVoteReason] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isVoteSucessful, setIsVoteSuccessful] = useState(false);
const [isVoteFailed, setIsVoteFailed] = useState(false);
const [failureCopy, setFailureCopy] = useState<ReactNode>('');
const [errorMessage, setErrorMessage] = useState<ReactNode>('');
const getVoteErrorMessage = (error: string | undefined) => {
if (error?.match(/voter already voted/)) {
return <Trans>User Already Voted</Trans>;
}
return error;
};
const handleVoteStateChange = useCallback((state: TransactionStatus) => {
switch (state.status) {
case 'None':
setIsLoading(false);
break;
case 'Mining':
setIsLoading(true);
break;
case 'Success':
setIsLoading(false);
setIsVoteSuccessful(true);
break;
case 'Fail':
setFailureCopy(<Trans>Transaction Failed</Trans>);
setErrorMessage(state?.errorMessage || <Trans>Please try again.</Trans>);
setIsLoading(false);
setIsVoteFailed(true);
break;
case 'Exception':
setFailureCopy(<Trans>Error</Trans>);
setErrorMessage(
getVoteErrorMessage(state?.errorMessage) || <Trans>Please try again.</Trans>,
);
setIsLoading(false);
setIsVoteFailed(true);
break;
}
}, []);
// Cast vote transaction state hook
useEffect(() => {
handleVoteStateChange(castVoteState);
}, [castVoteState, handleVoteStateChange]);
// Cast vote with reason transaction state hook
useEffect(() => {
handleVoteStateChange(castVoteWithReasonState);
}, [castVoteWithReasonState, handleVoteStateChange]);
// Auto close the modal after a transaction completes succesfully
// Leave failed transaction up until user closes manually to allow for debugging
useEffect(() => {
if (isVoteSucessful) {
setTimeout(onHide, POST_SUCESSFUL_VOTE_MODAL_CLOSE_TIME_MS);
}
}, [isVoteSucessful, onHide]);
// If show is false (i.e. on hide) reset failure related state variables
useEffect(() => {
if (show) {
return;
}
setIsVoteFailed(false);
}, [show]);
const voteModalContent = (
<>
{isVoteSucessful && (
<div className={classes.transactionStatus}>
<p>
<Trans>
You've successfully voted on on prop {i18n.number(parseInt(proposalId || '0'))}
</Trans>
</p>
<div className={classes.voteSuccessBody}>
<Trans>Thank you for voting.</Trans>
</div>
</div>
)}
{isVoteFailed && (
<div className={classes.transactionStatus}>
<p className={classes.voteFailureTitle}>
<Trans>There was an error voting for your account.</Trans>
</p>
<div className={classes.voteFailureBody}>
{failureCopy}: <span className={classes.voteFailureErrorMessage}>{errorMessage}</span>
</div>
</div>
)}
{!isVoteFailed && !isVoteSucessful && (
<div className={clsx(classes.votingButtonsWrapper, isLoading ? classes.disabled : '')}>
<div onClick={() => setVote(Vote.FOR)}>
<NavBarButton
buttonText={
availableVotes > 1 ? (
<Trans>
Cast {i18n.number(availableVotes)} votes for Prop{' '}
{i18n.number(parseInt(proposalId || '0'))}
</Trans>
) : (
<Trans>Cast 1 vote for Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>
)
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.FOR
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<div onClick={() => setVote(Vote.AGAINST)}>
<NavBarButton
buttonText={
availableVotes > 1 ? (
<Trans>
Cast {i18n.number(availableVotes)} votes against Prop{' '}
{i18n.number(parseInt(proposalId || '0'))}
</Trans>
) : (
<Trans>Cast 1 vote against Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>
)
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.AGAINST
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<div onClick={() => setVote(Vote.ABSTAIN)}>
<NavBarButton
buttonText={
<Trans>
Abstain from voting on Prop {i18n.number(parseInt(proposalId || '0'))}
</Trans>
}
buttonIcon={<></>}
buttonStyle={
vote === Vote.ABSTAIN
? NavBarButtonStyle.WHITE_ACTIVE_VOTE_SUBMIT
: NavBarButtonStyle.WHITE_INFO
}
/>
</div>
<br />
<FloatingLabel controlId="reasonTextarea" label={<Trans>Reason (Optional)</Trans>}>
<FormControl
as="textarea"
placeholder={
i18n.locale === 'en' ? `Reason for voting ${Vote[vote ?? Vote.FOR]}` : ''
}
value={voteReason}
onChange={e => setVoteReason(e.target.value)}
className={classes.voteReasonTextarea}
/>
</FloatingLabel>
<br />
<Button
onClick={() => {
if (vote === undefined || !proposalId || isLoading) {
return;
}
setIsLoading(true);
if (voteReason.trim() === '') {
castVote(proposalId, vote);
} else {
castVoteWithReason(proposalId, vote, voteReason);
}
}}
className={vote === undefined ? classes.submitBtnDisabled : classes.submitBtn}
>
{isLoading ? <Spinner animation="border" /> : <Trans>Submit Vote</Trans>}
</Button>
</div>
)}
</>
);
// On modal dismiss, reset non-success state
const resetNonSuccessStateAndHideModal = () => {
setIsLoading(false);
setIsVoteFailed(false);
setErrorMessage('');
setFailureCopy('');
onHide();
};
return (
<>
{show && (
<Modal
onDismiss={resetNonSuccessStateAndHideModal}
title={<Trans>Vote on Prop {i18n.number(parseInt(proposalId || '0'))}</Trans>}
content={voteModalContent}
/>
)}
</>
);
}