@material-ui/core#ClickAwayListener JavaScript Examples
The following examples show how to use
@material-ui/core#ClickAwayListener.
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: high-risk.js From warsinhk with MIT License | 6 votes |
InfoToolTip = ({ t, title, className, color }) => {
const [open, setOpen] = useState(false)
return (
<ClickAwayListener onClickAway={() => setOpen(false)}>
<StyledToolTip
PopperProps={{
disablePortal: true,
}}
classes={{ popper: className, tooltip: "tooltip" }}
onClose={() => setOpen(false)}
open={open}
disableFocusListener
disableHoverListener
disableTouchListener
placement="top"
title={title}
>
<CaseLabel
color={color}
onClick={e => {
e.stopPropagation()
setOpen(true)
}}
>
{t("high_risk.detail")}
</CaseLabel>
</StyledToolTip>
</ClickAwayListener>
)
}
Example #2
Source File: ShortAddressCopyButton.js From lrc-staking-dapp with MIT License | 6 votes |
ShortAddressCopyButton = React.memo(({
classes, messages, walletAddress,
}) => {
const [isShowCopy, setIsShowCopy] = useState(false);
return (
<ClickAwayListener onClickAway={() => setIsShowCopy(false)}>
<Tooltip
PopperProps={{ disablePortal: true }}
onClose={() => setIsShowCopy(false)}
open={isShowCopy}
disableFocusListener
disableHoverListener
disableTouchListener
arrow
title={messages['Address copied !']}
>
<Button
variant="text"
className={`font-size-sm font-weight-bold my-2 ${classes.btnWalletAddress}`}
onClick={() => { copy(walletAddress); setIsShowCopy(true); }}
>
<span className="btn-wrapper--label">
{`${walletAddress.slice(0, 8).toLowerCase()}...${walletAddress.slice(walletAddress.length - 6).toLowerCase()}`}
</span>
<span className={`btn-wrapper--icon ${classes.iconCopy}`}>
<FontAwesomeIcon
icon={['fas', 'copy']}
className="font-size-xs small"
/>
</span>
</Button>
</Tooltip>
</ClickAwayListener>
);
})
Example #3
Source File: Searchbar.js From course-manager with MIT License | 5 votes |
// ----------------------------------------------------------------------
export default function Searchbar() {
const [isOpen, setOpen] = useState(false);
const handleOpen = () => {
setOpen((prev) => !prev);
};
const handleClose = () => {
setOpen(false);
};
return (
<ClickAwayListener onClickAway={handleClose}>
<div>
{!isOpen && (
<IconButton onClick={handleOpen}>
<Icon icon={searchFill} width={20} height={20} />
</IconButton>
)}
<Slide direction="down" in={isOpen} mountOnEnter unmountOnExit>
<SearchbarStyle>
<Input
autoFocus
fullWidth
disableUnderline
placeholder="Search…"
startAdornment={
<InputAdornment position="start">
<Box
component={Icon}
icon={searchFill}
sx={{ color: 'text.disabled', width: 20, height: 20 }}
/>
</InputAdornment>
}
sx={{ mr: 1, fontWeight: 'fontWeightBold' }}
/>
<Button variant="contained" onClick={handleClose}>
Search
</Button>
</SearchbarStyle>
</Slide>
</div>
</ClickAwayListener>
);
}
Example #4
Source File: JoinDropdown.jsx From frontend with MIT License | 5 votes |
export default function JoinDropdown({ toggleVolunteerModal, toggleOrganizationModal }) {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
const handleCloseAndVolunteerModal = (event) => {
handleClose(event);
toggleVolunteerModal();
}
const handleCloseAndOrganizationModal = (event) => {
handleClose(event);
toggleOrganizationModal();
}
function handleListKeyDown(event) {
if (event.key === 'Tab') {
event.preventDefault();
setOpen(false);
}
}
// Return focus to the button when we transitioned from !open -> open.
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current.focus();
}
prevOpen.current = open;
}, [open]);
return (
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
{plusIcon}
<span className="joinDropdownTitle">{title}</span>
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleCloseAndOrganizationModal}>{options[0]}</MenuItem>
<MenuItem onClick={handleCloseAndVolunteerModal}>{options[1]}</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}
Example #5
Source File: MainMenu.js From dipact with GNU General Public License v3.0 | 4 votes |
render() {
return (
//Below typography is wonky due to limited title classes. I really shouldn't be doing it like this. - Joren
<React.Fragment>
<AppBar position="fixed">
<Toolbar>
<IconButton
edge="start"
onClick={this.openDrawer}
color="secondary"
style={{marginRight:"16px"}}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" style={{ flexGrow: 1 }}>
{this.state.activity == Start
? "My Games"
: this.state.activity == GameMasterStart
? "My Managed Games"
: this.state.activity == GameList
? "Public Games"
: ""}
</Typography>
<IconButton
edge="end"
onClick={(ev) => {
this.setState({
menuAnchorEl: ev.currentTarget,
});
}}
color="secondary"
>
<Avatar
alt="test"
src={Globals.user.Picture}
style={{
width: "32px",
height: "32px",
border: "1px solid #FDE2B5",
}}
/>
</IconButton>
<Menu
anchorEl={this.state.menuAnchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
onClose={(_) => {
this.setState({ menuAnchorEl: null });
}}
open={!!this.state.menuAnchorEl}
>
<MenuItem key="email" style={{ fontWeight: "bold" }}>
{Globals.user.Email}
</MenuItem>
<MenuItem
key="stats"
onClick={(_) => {
this.setState({
menuAnchorEl: null,
statsDialogOpen: true,
});
}}
>
Player stats
</MenuItem>
<MenuItem key="logout" onClick={helpers.logout}>
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<div style={{ marginTop: "60px" }}>{this.renderActivity()}</div>
<Drawer open={this.state.drawerOpen}>
<ClickAwayListener
onClickAway={(_) => {
if (new Date().getTime() > this.drawerOpenedAt + 100) {
this.closeDrawer();
}
}}
>
<div onClick={this.closeDrawer} style={{ width: "220px" }}>
<List component="nav">
<ListItem
style={{
padding: "24px 16px 8px 16px",
height: "40px",
}}
>
<ListItemText
primary="My Diplicity"
disableTypography
style={{
color: "rgba(40, 26, 26, 0.56)",
minHeight: "auto",
minWidth: "auto",
font: "500 14px / 48px Cabin, Roboto, sans-serif",
margin: "0px 0px 2px",
}}
/>
</ListItem>
<ListItem
button
onClick={(_) => {
this.setActivity(Start, {
urls: this.props.urls,
findPrivateGame: this.findGameByID,
findOpenGame: this.renderOpenGames,
renderMyFinishedGames: this.renderMyFinishedGames,
});
}}
>
<ListItemText primary="My games" />
</ListItem>
<ListItem
button
onClick={(_) => {
this.setActivity(GameMasterStart, {
urls: this.props.urls,
findPrivateGame: this.findGameByID,
findOpenGame: this.renderOpenGames,
renderMyFinishedGames: this.renderMyFinishedGames,
});
}}
>
<ListItemText primary="My managed games" />
</ListItem>
<ListItem
button
onClick={(_) => {
this.setState({ menuAnchorEl: null });
this.settingsDialog.setState({
open: true,
});
}}
>
<ListItemText primary="Settings" />
</ListItem>
<Divider />
<ListItem
style={{
padding: "24px 16px 8px 16px",
height: "40px",
}}
>
<ListItemText
primary="Public games"
disableTypography
style={{
color: "rgba(40, 26, 26, 0.56)",
minHeight: "auto",
minWidth: "auto",
font: "500 14px / 48px Cabin, Roboto, sans-serif",
margin: "0px 0px 2px",
}}
/>
</ListItem>
<ListItem
button
urlkey="open-games"
label="Open games"
onClick={this.renderGameList}
>
<ListItemText primary="Open to join" />
</ListItem>
<ListItem
style={{ padding: "4px 16px" }}
button
urlkey="started-games"
label="Started games"
onClick={this.renderGameList}
>
<ListItemText primary="Started" />
</ListItem>
<ListItem
button
urlkey="finished-games"
label="Finished games"
onClick={this.renderGameList}
>
<ListItemText primary="Finished" />
</ListItem>
<Divider />
<ListItem
style={{
padding: "24px 16px 8px 16px",
height: "40px",
}}
>
<ListItemText
primary="Community"
disableTypography
style={{
color: "rgba(40, 26, 26, 0.56)",
minHeight: "auto",
minWidth: "auto",
font: "500 14px / 48px Cabin, Roboto, sans-serif",
margin: "0px 0px 2px",
}}
/>
</ListItem>
<ListItem
button
onClick={(_) => {
open("https://discord.gg/bu3JxYc");
}}
>
<ListItemText primary="Chat" />
</ListItem>
<ListItem
style={{ padding: "4px 16px" }}
button
onClick={(_) => {
open("https://groups.google.com/g/diplicity-talk");
}}
>
<ListItemText primary="Forum" />
</ListItem>
<Divider />
<ListItem
button
onClick={(_) => {
open(
"https://diplicity.notion.site/diplicity/Diplicity-FAQ-7b4e0a119eb54c69b80b411f14d43bb9"
);
}}
>
<ListItemText primary="FAQ" />
</ListItem>
<ListItem
button
onClick={(_) => {
this.setActivity(About);
}}
>
<ListItemText primary="About" />
</ListItem>
</List>
<div
style={{
width: "calc(100% - 16px)",
display: "Flex",
justifyContent: "space-around",
padding: "0px 8px",
}}
>
<div
id="github"
style={{ padding: "8px" }}
onClick={(_) => {
open("https://github.com/zond/dipact");
}}
>
<GitHubIcon />
</div>
<div
id="errorlog"
style={{ padding: "8px" }}
onClick={(_) => {
this.errorsDialog.setState({
open: true,
});
}}
>
<BugReportIcon />
</div>
<div
id="donate"
style={{ padding: "8px" }}
onClick={(_) => {
this.donateDialog.setState({
open: true,
});
}}
>
<DonateIcon />
</div>
</div>
</div>
</ClickAwayListener>
</Drawer>
<FindGameDialog
parentCB={(c) => {
this.findGameDialog = c;
}}
key="find-game-dialog"
/>
<DonateDialog
key="donate-dialog"
parentCB={(c) => {
this.donateDialog = c;
}}
/>
<SettingsDialog
key="settings-dialog"
parentCB={(c) => {
this.settingsDialog = c;
}}
/>
<ErrorsDialog
key="errors-dialog"
parentCB={(c) => {
this.errorsDialog = c;
}}
/>
{this.state.statsDialogOpen ? (
<StatsDialog
open={this.state.statsDialogOpen}
user={Globals.user}
onClose={(_) => {
this.setState({ statsDialogOpen: false });
}}
/>
) : (
""
)}
</React.Fragment>
);
}
Example #6
Source File: Settings.js From akashlytics-deploy with GNU General Public License v3.0 | 4 votes |
export function Settings(props) {
const [isEditing, setIsEditing] = useState(false);
const [isNodesOpen, setIsNodesOpen] = useState(false);
const classes = useStyles();
const { settings, setSettings, refreshNodeStatuses, isRefreshingNodeStatus } = useSettings();
const {
handleSubmit,
control,
reset,
formState: { errors }
} = useForm();
const formRef = useRef();
const { selectedNode, nodes } = settings;
const onIsCustomNodeChange = (event) => {
const isChecked = event.target.checked;
const apiEndpoint = isChecked ? settings.apiEndpoint : selectedNode.api;
const rpcEndpoint = isChecked ? settings.rpcEndpoint : selectedNode.rpc;
reset();
setSettings({ ...settings, isCustomNode: isChecked, apiEndpoint, rpcEndpoint }, (newSettings) => {
refreshNodeStatuses(newSettings);
});
};
const onNodeChange = (event, newNodeId) => {
const newNode = nodes.find((n) => n.id === newNodeId);
const apiEndpoint = newNode.api;
const rpcEndpoint = newNode.rpc;
setSettings({ ...settings, apiEndpoint, rpcEndpoint, selectedNode: newNode });
};
const onRefreshNodeStatus = async () => {
await refreshNodeStatuses();
};
/**
* Update the custom settings
* @param {Object} data {apiEndpoint: string, rpcEndpoint: string}
*/
const onSubmit = (data) => {
const customNodeUrl = new URL(data.apiEndpoint);
setIsEditing(false);
setSettings({ ...settings, ...data, customNode: { ...settings.customNode, id: customNodeUrl.hostname } }, (newSettings) => {
refreshNodeStatuses(newSettings);
});
};
return (
<Box className={classes.root}>
<Helmet title="Settings" />
<Box className={classes.titleContainer}>
<Typography variant="h3" className={classes.title}>
Settings
</Typography>
</Box>
<Box marginTop="1rem">
<FormGroup>
{!settings.isCustomNode && (
<Box display="flex" alignItems="center">
<FormControl>
<Autocomplete
disableClearable
open={isNodesOpen}
options={nodes.map((n) => n.id)}
style={{ width: 300 }}
value={settings.selectedNode.id}
defaultValue={settings.selectedNode.id}
getOptionSelected={(option, value) => option === value}
onChange={onNodeChange}
renderInput={(params) => (
<ClickAwayListener onClickAway={() => setIsNodesOpen(false)}>
<TextField
{...params}
label="Node"
variant="outlined"
onClick={() => setIsNodesOpen((prev) => !prev)}
InputProps={{
...params.InputProps,
classes: { root: clsx(classes.nodeInput, classes.inputClickable), input: classes.inputClickable },
endAdornment: (
<InputAdornment position="end">
<Box marginRight=".5rem" display="inline-flex">
<KeyboardArrowDownIcon fontSize="small" />
</Box>
<NodeStatus latency={Math.floor(selectedNode.latency)} status={selectedNode.status} />
</InputAdornment>
)
}}
/>
</ClickAwayListener>
)}
renderOption={(option) => {
const node = nodes.find((n) => n.id === option);
return (
<Box display="flex" alignItems="center" justifyContent="space-between" width="100%">
<div>{option}</div>
<NodeStatus latency={Math.floor(node.latency)} status={node.status} />
</Box>
);
}}
disabled={settings.isCustomNode}
/>
</FormControl>
<Box marginLeft="1rem">
<IconButton onClick={() => onRefreshNodeStatus()} aria-label="refresh" disabled={isRefreshingNodeStatus}>
{isRefreshingNodeStatus ? <CircularProgress size="1.5rem" /> : <RefreshIcon />}
</IconButton>
</Box>
</Box>
)}
<FormControlLabel
className={classes.switch}
control={<Switch checked={!!settings.isCustomNode} onChange={onIsCustomNodeChange} color="primary" />}
label="Custom node"
/>
</FormGroup>
</Box>
{settings.isCustomNode && (
<form className={classes.form} onSubmit={handleSubmit(onSubmit)} ref={formRef}>
<div className={classes.fieldRow}>
<FormLabel className={classes.formLabel}>Api Endpoint:</FormLabel>
{isEditing ? (
<FormControl error={!errors.apiEndpoint} className={classes.formControl}>
<Controller
control={control}
name="apiEndpoint"
rules={{
required: true,
validate: (v) => isUrl(v)
}}
defaultValue={settings.apiEndpoint}
render={({ fieldState, field }) => {
const helperText = fieldState.error?.type === "validate" ? "Url is invalid." : "Api endpoint is required.";
return (
<TextField
{...field}
type="text"
variant="outlined"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
className={classes.formValue}
/>
);
}}
/>
</FormControl>
) : (
<Typography variant="body1" className={classes.formValue}>
{settings.apiEndpoint}
</Typography>
)}
</div>
<div className={classes.fieldRow}>
<FormLabel className={classes.formLabel}>Rpc Endpoint:</FormLabel>
{isEditing ? (
<FormControl error={!errors.apiEndpoint} className={classes.formControl}>
<Controller
control={control}
name="rpcEndpoint"
rules={{
required: true,
validate: (v) => isUrl(v)
}}
defaultValue={settings.rpcEndpoint}
render={({ fieldState, field }) => {
const helperText = fieldState.error?.type === "validate" ? "Url is invalid." : "Rpc endpoint is required.";
return (
<TextField
{...field}
type="text"
variant="outlined"
error={!!fieldState.invalid}
helperText={fieldState.invalid && helperText}
className={classes.formValue}
/>
);
}}
/>
</FormControl>
) : (
<Typography variant="body1" className={classes.formValue}>
{settings.rpcEndpoint}
</Typography>
)}
</div>
<Box paddingTop="1rem">
{!isEditing && (
<Button variant="contained" color="primary" onClick={() => setIsEditing(!isEditing)}>
Edit
</Button>
)}
{isEditing && (
<>
<Button
variant="contained"
onClick={() => {
reset(null, { keepDefaultValues: true });
setIsEditing(false);
}}
>
Cancel
</Button>
<Button
variant="contained"
color="primary"
type="submit"
className={classes.submitButton}
onClick={() => formRef.current.dispatchEvent(new Event("submit"))}
>
Submit
</Button>
</>
)}
</Box>
</form>
)}
</Box>
);
}
Example #7
Source File: SearchInput.js From covid-19 with MIT License | 4 votes |
SearchInput = (props) => {
const classes = useStyles();
const world = useContext(WorldContext);
const [results, setResults] = React.useState([]);
// Force the search index to lazy load
React.useEffect(() => {
world.get(Path.root(), SearchIndexComponent);
});
const onClose = () => {
setResults([]);
};
const onChange = (e) => {
const search = world.get(SEARCH_INDEX_PATH, SearchIndexComponent);
if (!search) {
return;
}
setResults(search.search(e.target.value));
};
const onChoice = (e, path) => {
e.preventDefault();
setResults([]);
props.onChoice(path);
};
const resultRenderer = ({index, key, style}) => {
const {name, path} = results[index];
return (
<div key={key} style={style} className={classes.result}>
<MaterialLink href="#" onClick={(e) => onChoice(e, path)}>
{name}
</MaterialLink>
</div>
);
};
return (
<ClickAwayListener onClickAway={onClose}>
<div className={`${classes.root} ${props.className || ''}`}>
<SearchIcon className={classes.searchIcon} />
<InputBase
className={classes.input}
onChange={onChange}
placerholder="Search..." />
{props.onGeolocate &&
<Divider className={classes.divider} />
}
{props.onGeolocate &&
<IconButton
size="small"
className={classes.iconButton}
onClick={props.onGeolocate}>
<LocationSearchingIcon />
</IconButton>
}
<Paper
className={
`${classes.resultsContainer} `
+ (results.length === 0 ? 'hide' : '')
}
elevation={3}>
<AutoSizer disableHeight>
{({width}) => (
<List
className={classes.resultsList}
rowCount={results.length}
rowHeight={RESULT_HEIGHT}
rowRenderer={resultRenderer}
width={width}
height={Math.min(RESULTS_MAX_HEIGHT, RESULT_HEIGHT * results.length)}
/>
)}
</AutoSizer>
</Paper>
</div>
</ClickAwayListener>
);
}
Example #8
Source File: Signup.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function Signup View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function Signup(props) {
const classes = useStyles();
const refs = {
phone_el: React.useRef(null),
location_el: React.useRef(null),
date_of_birth_el: React.useRef(null),
};
const [state, setState] = React.useState({
locations: [],
show_password1: false,
show_password2: false,
tool_tip_open: false,
subscribe_box_checked: false,
});
React.useEffect(() => {
handleSetState(getLocations(props));
}, []);
React.useEffect(() => {
initIntlTelInput(props, refs);
}, [refs.phone_el]);
React.useEffect(() => {
setLabelWidthOfStaticFields(refs, document, props);
}, [props.i18n.language]);
React.useEffect(() => {
if (props.touched['email']) {
vars.email_field_touched = true;
} else {
vars.email_field_touched = false;
}
if (props.touched['phone']) {
vars.phone_field_touched = true;
} else {
vars.phone_field_touched = false;
}
}, [props.touched['email'], props.touched['phone']]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const {
locations,
tool_tip_open,
show_password1,
show_password2,
subscribe_box_checked,
} = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="signup"
noValidate="noValidate"
onSubmit={e => signup(e, props)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('signup.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('signup.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['username']) ||
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
{t('signup.inputs.username.label')}
</InputLabel>
<ClickAwayListener
onClickAway={() => handleSetState(handleTooltipClose())}
>
<Tooltip
title={t('signup.tooltips.noRealName')}
placement="top-start"
arrow
onClose={() => handleSetState(handleTooltipClose())}
PopperProps={{
disablePortal: true,
}}
open={tool_tip_open}
disableFocusListener
disableHoverListener
disableTouchListener
>
<OutlinedInput
className={classes.customInputStyle}
id="username"
name="username"
type="text"
onClick={() => handleSetState(handleTooltipOpen())}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.username.label'),
document,
)}
/>
</Tooltip>
</ClickAwayListener>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`signup.inputs.username.errors.${props.errors['username']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'])
}
>
<InputLabel
className={classes.customLabelStyle}
id="user_location"
>
{t('signup.inputs.location.label')}
</InputLabel>
<Select
ref={refs.location_el}
labelId="user_location"
id="user_location"
name="user_location"
className={classes.customInputStyle}
value={
props.values.user_location
? props.values.user_location
: ''
}
onChange={e => handleLocationChange(e, props)}
onBlur={props.handleBlur}
// label="Location"
labelWidth={calculateLabelWidth(
t('signup.inputs.location.label'),
document,
)}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(locations) &&
locations.map(location => (
<MenuItem key={location.name} value={location.name}>
{location.name}
</MenuItem>
))}
</Select>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'] &&
t(
`signup.inputs.location.errors.${props.errors['user_location']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['dateOfBirth']) ||
(props.touched['dateOfBirth'] &&
props.errors['dateOfBirth'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="dateOfBirth"
shrink
>
{t('signup.inputs.dateOfBirth.label')}
</InputLabel>
<OutlinedInput
ref={refs.date_of_birth_el}
className={clsx(classes.customInputStyle)}
id="dateOfBirth"
name="dateOfBirth"
type="date"
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['dateOfBirth']) ||
(props.touched['dateOfBirth'] &&
props.errors['dateOfBirth'] &&
t(
`signup.inputs.dateOfBirth.errors.${props.errors['dateOfBirth']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['phone']) ||
(props.touched['phone'] && props.errors['phone'])
}
>
<InputLabel
className={classes.customLabelStyle}
shrink
htmlFor="phone"
>
{t('signup.inputs.phone.label')}
</InputLabel>
<OutlinedInput
ref={refs.phone_el}
className={clsx(
classes.customInputStyle,
classes.locationInputStyle,
)}
id="phone"
name="phone"
type="phone"
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['phone']) ||
(props.touched['phone'] &&
props.errors['phone'] &&
t(
`signup.inputs.phone.errors.${props.errors['phone']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['email']) ||
(props.touched['email'] && props.errors['email'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="email"
>
{t('signup.inputs.email.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="email"
name="email"
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.email.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['email']) ||
(props.touched['email'] &&
props.errors['email'] &&
t(
`signup.inputs.email.errors.${props.errors['email']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['password1']) ||
(props.touched['password1'] &&
props.errors['password1'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password1"
>
{t('signup.inputs.password1.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="password1"
name="password1"
type={show_password1 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label={t(
'signup.ariaLabel.togglePasswordVisibility',
)}
onClick={() =>
setState({
...state,
show_password1: !show_password1,
})
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password1 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('signup.inputs.password1.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['password1']) ||
(props.touched['password1'] &&
props.errors['password1'] &&
t(
`signup.inputs.password1.errors.${props.errors['password1']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['password2']) ||
(props.touched['password2'] &&
props.errors['password2'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="password2"
>
{t('signup.inputs.password2.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="password2"
name="password2"
type={show_password2 ? 'text' : 'password'}
onChange={props.handleChange}
onBlur={props.handleBlur}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label={t(
'signup.ariaLabel.togglePasswordVisibility',
)}
onClick={() =>
setState({
...state,
show_password2: !show_password2,
})
}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{show_password2 ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
labelWidth={calculateLabelWidth(
t('signup.inputs.password2.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['password2']) ||
(props.touched['password2'] &&
props.errors['password2'] &&
t(
`signup.inputs.password2.errors.${props.errors['password2']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['bio']) ||
(props.touched['bio'] && props.errors['bio'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="bio"
>
{t('signup.inputs.bio.label')}
</InputLabel>
<OutlinedInput
className={classes.customInputStyle}
id="bio"
name="bio"
type="text"
multiline
rows={6}
rowsMax={6}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('signup.inputs.bio.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('signup.inputs.bio.helpText')}
</Typography>
<br />
{(props.status && props.status['bio']) ||
(props.touched['bio'] &&
props.errors['bio'] &&
t(
`signup.inputs.bio.errors.${props.errors['bio']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControlLabel
value={subscribe_box_checked}
onChange={e =>
handleSetState(
handleToggleSubscribeBox(e, props, state),
)
}
control={
<Checkbox
name="subscribe"
id="subscribe"
color="primary"
/>
}
label={
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('signup.unsubscribe')}
</Typography>
}
labelPlacement="end"
/>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
type="submit"
fullWidth
customButtonStyle
>
{t('signup.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{t('signup.alreadyAMember')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/login" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
{t('signup.login')}
</CustomButton>
</Link>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #9
Source File: EditProfile.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function EditProfile View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function EditProfile(props) {
const refs = {
username_el: React.useRef(null),
location_el: React.useRef(null),
email_el: React.useRef(null),
phone_el: React.useRef(null),
bio_el: React.useRef(null),
};
const [state, setState] = React.useState({
locations: [],
tool_tip_open: false,
});
React.useEffect(() => {
getProfile(refs, props);
handleSetState(getLocations(props));
}, []);
const classes = useStyles();
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const { locations, tool_tip_open } = state;
const { t } = props;
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="auth-form"
name="signup"
noValidate="noValidate"
onSubmit={e => editProfile(e, props, toast)}
>
<Typography
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
className={classes.titleStyle}
>
{t('editProfile.welcomeMsg.primary')}
</Typography>
<Typography
className={classes.descStyle}
variant="body2"
color="textSecondary"
component="p"
>
{t('editProfile.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['username']) ||
(props.touched['username'] && props.errors['username'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="username"
>
{t('editProfile.inputs.username.label')}
</InputLabel>
<ClickAwayListener
onClickAway={() => handleSetState(handleTooltipClose())}
>
<Tooltip
title={t('editProfile.tooltips.noRealName')}
placement="top-start"
arrow
onClose={() => handleSetState(handleTooltipClose())}
PopperProps={{
disablePortal: true,
}}
open={tool_tip_open}
disableFocusListener
disableHoverListener
disableTouchListener
>
<OutlinedInput
ref={refs.username_el}
className={clsx(classes.customInputStyle)}
id="username"
name="username"
type="text"
value={
props.values.username ? props.values.username : ''
}
onClick={() => handleSetState(handleTooltipOpen())}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.username.label'),
document,
)}
/>
</Tooltip>
</ClickAwayListener>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['username']) ||
(props.touched['username'] &&
props.errors['username'] &&
t(
`editProfile.inputs.username.errors.${props.errors['username']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
ref={refs.location_el}
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'])
}
>
<InputLabel
className={classes.customLabelStyle}
id="user_location"
>
{t('editProfile.inputs.location.label')}
</InputLabel>
<Select
labelId="user_location"
id="user_location"
name="user_location"
className={clsx(classes.customInputStyle)}
value={
props.values.user_location
? props.values.user_location
: ''
}
onChange={props.handleChange}
onBlur={props.handleBlur}
label="Location"
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(locations) &&
locations.map(location => (
<MenuItem key={location.name} value={location.name}>
{location.name}
</MenuItem>
))}
</Select>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{(props.status && props.status['user_location']) ||
(props.touched['user_location'] &&
props.errors['user_location'] &&
t(
`editProfile.inputs.location.errors.${props.errors['user_location']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['email']) ||
(props.touched['email'] && props.errors['email'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="email"
>
{t('editProfile.inputs.email.label')}
</InputLabel>
<OutlinedInput
ref={refs.email_el}
disabled={
props.status && props.status['init_email']
? true
: false
}
className={clsx(classes.customInputStyle)}
id="email"
name="email"
type="text"
value={props.values.email ? props.values.email : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.email.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{props.status && props.status['init_email'] && (
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.email.disabledHelperText')}
</Typography>
)}
<br />
{(props.status && props.status['email']) ||
(props.touched['email'] &&
props.errors['email'] &&
t(
`editProfile.inputs.email.errors.${props.errors['email']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} sm={6} md={6}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="normal"
error={
(props.status && props.status['phone']) ||
(props.touched['phone'] && props.errors['phone'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="phone"
>
{t('editProfile.inputs.phone.label')}
</InputLabel>
<OutlinedInput
ref={refs.phone_el}
disabled={
props.status && props.status['init_phone']
? true
: false
}
className={clsx(classes.customInputStyle)}
id="phone"
name="phone"
type="phone"
value={props.values.phone ? props.values.phone : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.phone.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
{props.status && props.status['init_phone'] && (
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.phone.disabledHelperText')}
</Typography>
)}
<br />
{(props.status && props.status['phone']) ||
(props.touched['phone'] &&
props.errors['phone'] &&
t(
`editProfile.inputs.phone.errors.${props.errors['phone']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['bio']) ||
(props.touched['bio'] && props.errors['bio'])
}
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="bio"
>
{t('editProfile.inputs.bio.label')}
</InputLabel>
<OutlinedInput
ref={refs.bio_el}
className={clsx(classes.customInputStyle)}
id="bio"
name="bio"
type="text"
multiline
rows={6}
rowsMax={6}
value={props.values.bio ? props.values.bio : ''}
onChange={props.handleChange}
onBlur={props.handleBlur}
labelWidth={calculateLabelWidth(
t('editProfile.inputs.bio.label'),
document,
)}
/>
<FormHelperText
className={classes.fieldHelperTextStyle}
error
>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('editProfile.inputs.bio.helpText')}
</Typography>
<br />
{(props.status && props.status['bio']) ||
(props.touched['bio'] &&
props.errors['bio'] &&
t(
`editProfile.inputs.bio.errors.${props.errors['bio']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
type="submit"
fullWidth
customButtonStyle
>
{t('editProfile.inputs.submit')}
</CustomButton>
</Grid>
</Grid>
</form>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box className={classes.center}>
<Divider className={classes.divider} />
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{t('editProfile.or')}
</Typography>
<Divider className={classes.divider} />
</Box>
</Grid>
<Grid item xs={12}>
<Link to="/profile" className={classes.textDecorationNone}>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
fullWidth
>
{t('editProfile.backToProfile')}
</CustomButton>
</Link>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
Example #10
Source File: CreateProject.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function CreateProject View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function CreateProject(props) {
const [category, setCategory] = React.useState([]);
const classes = useStyles();
const common_classes = useCommonStyles();
const refs = {
title_el: React.useRef(null),
desc_el: React.useRef(null),
image_el: React.useRef(null),
image_upload_button_el: React.useRef(null),
video_upload_button_el: React.useRef(null),
image_count_el: React.useRef(null),
video_el: React.useRef(null),
video_file_el: React.useRef(null),
video_selection_feedback_el: React.useRef(null),
add_materials_used_el: React.useRef(null),
add_tags_el: React.useRef(null),
publish_type_el: React.useRef(null),
publish_visible_to_el: React.useRef(null),
};
const [state, setState] = React.useState({
...JSON.parse(JSON.stringify(vars.default_state)),
});
React.useEffect(() => {
if (props.match.params.id) {
Promise.all([getProject(refs, props, state), getCategories(props)]).then(
result => handleSetState({ ...result[0], ...result[1] }),
);
} else {
handleSetState(getCategories(props));
}
handleSetState(buildPublishTypes(props));
}, []);
React.useEffect(() => {
checkMediaFilesErrorState(refs, props);
}, [
props.errors['project_images'],
props.touched['project_images'],
props.errors['video'],
props.touched['video'],
]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const {
desc_input_is_focused,
video_upload_dialog_open,
media_upload,
categories,
tag_suggestion,
tag_suggestion_open,
select_video_file,
publish_types,
publish_visible_to_suggestion_open,
publish_visible_to_suggestion,
} = state;
const { t } = props;
const id = props.match.params.id;
if (!props.auth.token) {
return <ErrorPage error={t('createProject.errors.notLoggedIn')} />;
} else {
return (
<Box className={classes.root}>
<Container className={classes.containerStyle}>
<Card className={classes.cardStyle}>
<CardActionArea>
<CardContent>
<form
className="project-create-form"
name="create_project"
noValidate="noValidate"
onSubmit={e =>
!vars.upload_in_progress
? initUpload(e, state, props, handleSetState)
: e.preventDefault()
}
>
<Typography
className={classes.titleStyle}
gutterBottom
variant="h5"
component="h2"
color="textPrimary"
>
{!id
? t('createProject.welcomeMsg.primary')
: t('createProject.inputs.edit')}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
className={classes.descStyle}
>
{t('createProject.welcomeMsg.secondary')}
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box
component="p"
className={
props.status &&
props.status['non_field_errors'] &&
classes.errorBox
}
>
{props.status && props.status['non_field_errors'] && (
<Box component="span" className={classes.error}>
{props.status['non_field_errors']}
</Box>
)}
</Box>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['title']) ||
(props.touched['title'] && props.errors['title'])
}
>
<label htmlFor="title">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>1</Box>
{t('createProject.inputs.title.label')}
</Typography>
</label>
<OutlinedInput
ref={refs.title_el}
className={classes.customInputStyle}
id="title"
name="title"
type="text"
onChange={e => handleTextFieldChange(e, props)}
onBlur={e => handleTextFieldBlur(e, props)}
/>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['title']) ||
(props.touched['title'] &&
props.errors['title'] &&
t(
`createProject.inputs.title.errors.${props.errors['title']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
>
<label htmlFor="description">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>2</Box>
{t('createProject.inputs.description.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.description.helperText')}
</Typography>
<ClickAwayListener
onClickAway={() =>
handleSetState({ desc_input_is_focused: false })
}
>
<ReactQuill
ref={refs.desc_el}
className={clsx(
classes.descInputStyle,
{
[classes.descInputFocusStyle]:
desc_input_is_focused,
},
{
[classes.descInputErrorStyle]:
(props.status &&
props.status['description']) ||
(props.touched['description'] &&
props.errors['description']),
},
)}
modules={vars.quill.modules}
formats={vars.quill.formats}
defaultValue={''}
placeholder={t(
'createProject.inputs.description.placeholder',
)}
onChange={value =>
handleDescFieldChange(
value,
props,
handleSetState,
)
}
onFocus={() =>
handleDescFieldFocusChange(
null,
props,
handleSetState,
)
}
/>
</ClickAwayListener>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['description']) ||
(props.touched['description'] &&
props.errors['description'] &&
t(
`createProject.inputs.description.errors.${props.errors['description']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
fullWidth
error={
(props.status && props.status['project_images']) ||
(props.touched['project_images'] &&
props.errors['project_images'])
}
>
<label htmlFor="project_images">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>3</Box>
{t('createProject.inputs.projectImages.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t(
'createProject.inputs.projectImages.topHelperText',
)}
</Typography>
<Grid container spacing={1}>
<Grid item xs={12} sm={6} md={6}>
<CustomButton
ref={refs.image_upload_button_el}
variant="outlined"
size="large"
margin="normal"
id="image_upload_button"
startIcon={<ImageIcon />}
onClick={e =>
handleImageButtonClick(e, props, refs)
}
secondaryButtonStyle
mediaUploadButtonStyle
customButtonStyle
fullWidth
>
{t('createProject.inputs.projectImages.label2')}
</CustomButton>
<Typography
color="textSecondary"
variant="caption"
component="span"
ref={refs.image_count_el}
></Typography>
</Grid>
</Grid>
<input
ref={refs.image_el}
className={classes.displayNone}
aria-hidden="true"
type="file"
accept="image/*"
id="project_images"
name="project_images"
multiple
onChange={_ =>
handleImageFieldChange(
refs,
props,
state,
handleSetState,
)
}
onBlur={props.handleBlur}
/>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['images']) ||
(props.errors['project_images'] &&
t(
`createProject.inputs.projectImages.errors.${props.errors['project_images']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
fullWidth
error={
(props.status && props.status['video']) ||
(props.touched['video'] && props.errors['video'])
}
>
<label htmlFor="video">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>4</Box>
{t('createProject.inputs.video.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.video.topHelperText')}
</Typography>
<Grid container spacing={1}>
<Grid item xs={12} sm={6} md={6}>
<CustomButton
ref={refs.video_upload_button_el}
variant="outlined"
size="large"
margin="normal"
id="video_upload_button"
startIcon={<VideoIcon />}
onClick={e =>
handleSetState(
handleVideoButtonClick(
e,
props,
video_upload_dialog_open,
),
)
}
secondaryButtonStyle
mediaUploadButtonStyle
customButtonStyle
fullWidth
>
{t('createProject.inputs.video.label2')}
</CustomButton>
<Typography
color="textSecondary"
variant="caption"
component="span"
ref={refs.video_selection_feedback_el}
></Typography>
</Grid>
</Grid>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['video']) ||
(props.errors['video'] &&
t(
`createProject.inputs.video.errors.${props.errors['video']}`,
))}
</FormHelperText>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={classes.fieldHelperTextStyle}
>
{t('createProject.inputs.video.bottomHelperText')}
</Typography>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['materials_used']) ||
(props.touched['materials_used'] &&
props.errors['materials_used'])
}
>
<label htmlFor="add_materials_used">
<Typography
color="textSecondary"
className={clsx(
classes.customLabelStyle,
common_classes.marginBottom1em,
)}
>
<Box className={classes.fieldNumberStyle}>5</Box>
{t('createProject.inputs.materialsUsed.label')}
</Typography>
</label>
<Grid container spacing={1} alignItems="flex-end">
<Grid item xs={12} sm={8}>
<Box ref={refs.add_materials_used_el}>
{buildMaterialUsedNodes({
props,
refs,
classes,
common_classes,
})}
</Box>
</Grid>
<Grid item xs={12} sm={4} md={4}>
<CustomButton
variant="outlined"
size="large"
onClick={e => addMaterialsUsedNode(e, props)}
secondaryButtonStyle
customButtonStyle
fullWidth
>
<AddIcon />{' '}
{t('createProject.inputs.materialsUsed.addMore')}
</CustomButton>
</Grid>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['materials_used']) ||
(props.touched['materials_used'] &&
props.errors['materials_used'] &&
t(
`createProject.inputs.materialsUsed.errors.${props.errors['materials_used']}`,
))}
</FormHelperText>
</Grid>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['category']) ||
(props.touched['category'] &&
props.errors['category'])
}
>
<label htmlFor="category">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>6</Box>
{t('createProject.inputs.category.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.category.topHelperText')}
</Typography>
<Select
labelId="category"
id="category"
name="category"
className={classes.customInputStyle}
value={
props.values.category ? props.values.category : ''
}
onChange={props.handleChange}
onBlur={props.handleBlur}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{Array.isArray(categories) &&
categories.map(category => (
<MenuItem key={category.id} value={category.name}>
{category.name}
</MenuItem>
))}
</Select>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['category']) ||
(props.touched['category'] &&
props.errors['category'] &&
t(
`createProject.inputs.category.errors.${props.errors['category']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['tags']) ||
(props.touched['tags'] && props.errors['tags'])
}
>
<label htmlFor="add_tags">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>7</Box>
{t('createProject.inputs.tags.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.tags.topHelperText')}
</Typography>
<Box className={classes.tagsViewStyle}>
{props.values['tags'] &&
JSON.parse(props.values['tags']).map((tag, num) =>
tag && tag.name ? (
<Chip
className={classes.customChipStyle}
key={num}
label={tag.name}
onDelete={e => removeTag(e, props, tag.name)}
color="secondary"
variant="outlined"
/>
) : null,
)}
<input
ref={refs.add_tags_el}
className={classes.tagsInputStyle}
name="tags"
type="text"
autocomplete="off"
placeholder={
props.values['tags'] &&
JSON.parse(props.values['tags']).length >= 5
? t(
'createProject.inputs.tags.errors.limitReached',
)
: `${t('createProject.inputs.tags.addTag')}...`
}
onChange={e => {
handleSuggestTags(
e,
props,
state,
handleSetState,
);
handleSetState(handleAddTags(e, props));
}}
onBlur={e => {
handleAddTags(e, props);
}}
/>
<ClickAwayListener
onClickAway={() =>
handleSetState({
tag_suggestion_open: false,
tag_suggestion: [],
})
}
>
<Box
className={clsx(
classes.tagSuggestionStyle,
!tag_suggestion_open
? common_classes.displayNone
: null,
)}
>
{tag_suggestion && tag_suggestion.length > 0 ? (
tag_suggestion.map((tag, index) => (
<Typography
key={index}
color="textPrimary"
className={classes.tagSuggestionTextStyle}
onClick={() => {
clearTimeout(vars.timer.id);
handleSetState(
handleAddTags(
{
currentTarget: {
value: `${tag.name},`,
},
},
props,
refs.add_tags_el,
),
);
}}
>
{tag.name}
</Typography>
))
) : (
<CircularProgress size={30} thickness={3} />
)}
</Box>
</ClickAwayListener>
</Box>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['tags']) ||
(props.touched['tags'] &&
props.errors['tags'] &&
t(
`createProject.inputs.tags.errors.${props.errors['tags']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} className={common_classes.marginTop1em}>
<FormControl
className={clsx(classes.margin, classes.textField)}
variant="outlined"
size="small"
fullWidth
margin="small"
error={
(props.status && props.status['publish']) ||
(props.touched['publish'] && props.errors['publish'])
}
>
<label htmlFor="publish">
<Typography
color="textSecondary"
className={classes.customLabelStyle}
>
<Box className={classes.fieldNumberStyle}>8</Box>
{t('createProject.inputs.publish.label')}
</Typography>
</label>
<Typography
color="textSecondary"
variant="caption"
component="span"
className={clsx(
classes.fieldHelperTextStyle,
common_classes.marginBottom1em,
)}
>
{t('createProject.inputs.publish.topHelperText')}
</Typography>
<Select
ref={refs.publish_type_el}
labelId="publish"
id="publish"
name="publish"
className={classes.customInputStyle}
value={
props.values.publish
? props.values.publish.type
: publish_types[0]
? publish_types[0].value
: ''
}
onChange={e => handlePublishFieldChange(e, props)}
onBlur={e => handlePublishFieldBlur(e, props)}
>
{publish_types.map(type => (
<MenuItem key={type.name} value={type.value}>
{t(`createProject.inputs.publish.publishTypes.${type.name}`)}
</MenuItem>
))}
</Select>
<Box
className={clsx(
classes.tagsViewStyle,
common_classes.marginTop1em,
{
[common_classes.displayNone]:
props.values.publish?.type !==
publish_type['Preview'],
},
)}
>
{props.values.publish?.visible_to &&
props.values['publish']['visible_to'].map(
(username, num) =>
username ? (
<Chip
className={classes.customChipStyle}
key={num}
label={username}
onDelete={e =>
handleRemovePublishVisibleTo(
e,
props,
username,
)
}
color="secondary"
variant="outlined"
/>
) : null,
)}
<input
ref={refs.publish_visible_to_el}
className={classes.tagsInputStyle}
name="publish_visible_to"
type="text"
autocomplete="off"
placeholder={`${t(
'createProject.inputs.publish.addUsernames',
)}...`}
onChange={e => {
handleSuggestPublishVisibleTo(
e,
props,
state,
handleSetState,
);
handleSetState(
handleAddPublishVisibleTo(e, props),
);
}}
onBlur={e => {
handleAddPublishVisibleTo(e, props);
}}
/>
<ClickAwayListener
onClickAway={() =>
handleSetState({
publish_visible_to_suggestion_open: false,
publish_visible_to_suggestion: [],
})
}
>
<Box
className={clsx(
classes.tagSuggestionStyle,
!publish_visible_to_suggestion_open
? common_classes.displayNone
: null,
)}
>
{publish_visible_to_suggestion &&
publish_visible_to_suggestion.length > 0 ? (
publish_visible_to_suggestion.map(
(username, index) => (
<Typography
key={index}
color="textPrimary"
className={classes.tagSuggestionTextStyle}
onClick={() => {
clearTimeout(vars.timer.id);
handleSetState(
handleAddPublishVisibleTo(
{
currentTarget: {
value: `${username},`,
},
},
props,
refs.publish_visible_to_el,
),
);
}}
>
{username}
</Typography>
),
)
) : (
<CircularProgress size={30} thickness={3} />
)}
</Box>
</ClickAwayListener>
</Box>
<FormHelperText
error
className={classes.fieldHelperTextStyle}
>
{(props.status && props.status['publish']) ||
(props.touched['publish'] &&
props.errors['publish'] &&
t(
`createProject.inputs.publish.errors.${props.errors['publish']}`,
))}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12}>
<CustomButton
variant="contained"
size="large"
type="submit"
primaryButtonStyle
customButtonStyle
fullWidth
>
{!id
? t('createProject.inputs.submit')
: t('createProject.inputs.edit')}
</CustomButton>
</Grid>
</Grid>
<Dialog
PaperProps={{
style: {
backgroundColor: 'transparent',
boxShadow: 'none',
},
}}
open={video_upload_dialog_open}
onClose={async () =>
handleSetState({
...(await handleVideoFieldCancel(refs, props, state)),
video_upload_dialog_open: false,
})
}
aria-labelledby="video upload dialog"
>
<Container
className={clsx(
classes.containerStyle,
classes.videoInputDialogContainerStyle,
)}
>
<Card
className={clsx(
classes.cardStyle,
classes.videoInputDialogCardStyle,
)}
>
<CardActionArea>
<CardContent>
<div
className={
classes.videoInputDialogControlSectionStyle
}
>
<CustomButton
className={
classes.videoInputDialogControlButtonStyle
}
primaryButtonStyle={!select_video_file}
secondaryButtonStyle={select_video_file}
size="medium"
onClick={_ =>
handleSetState({ select_video_file: false })
}
>
<div
className={
classes.videoInputDialogControlButtonUseTextDescStyle
}
>
{t(
'createProject.inputs.video.dialogURLToggle',
)}
</div>
<InsertLinkIcon
className={
classes.videoInputDialogControlButtonUseIconDescStyle
}
/>
</CustomButton>
<CustomButton
className={
classes.videoInputDialogControlButtonStyle
}
primaryButtonStyle={select_video_file}
secondaryButtonStyle={!select_video_file}
size="medium"
onClick={_ =>
handleSetState(
handleSelectVideoFileChecked(
refs.video_file_el.current,
),
)
}
>
<div
className={
classes.videoInputDialogControlButtonUseTextDescStyle
}
>
{t(
'createProject.inputs.video.dialogFileToggle',
)}
</div>
<MovieIcon
className={
classes.videoInputDialogControlButtonUseIconDescStyle
}
/>
</CustomButton>
</div>
<Grid container spacing={1} alignItems="flex-end">
<Grid
item
xs={12}
sm={12}
className={clsx(
common_classes.marginTop1em,
classes.videoInputDialogBodyGridStyle,
)}
>
{!select_video_file ? (
<FormControl
className={clsx(
classes.margin,
classes.textField,
classes.videoInputDialogURLFormControlStyle,
)}
variant="outlined"
size="small"
>
<InputLabel
className={classes.customLabelStyle}
htmlFor="url-input"
>
{t(
'createProject.inputs.video.dialogURLFieldLabel',
)}
</InputLabel>
<OutlinedInput
ref={refs.video_el}
className={classes.customInputStyle}
type="text"
name="url-input"
labelWidth={calculateLabelWidth(
t(
'createProject.inputs.video.dialogURLFieldLabel',
),
document,
)}
placeholder="https://youtube.com/..."
onChange={async e =>
handleSetState(
await handleVideoFieldChange(
e,
refs,
props,
state,
handleSetState,
),
)
}
/>
</FormControl>
) : null}
{select_video_file ? (
<p className={classes.videoFileName}>
{refs.video_file_el.current?.files?.[0]
? refs.video_file_el.current?.files?.[0]
?.name
: t(
'createProject.inputs.video.dialogFileToggle',
)}
</p>
) : null}
<CustomButton
className={
classes.videoInputDialogActionButtonStyle
}
secondaryButtonStyle
variant="outlined"
size="medium"
onClick={async () =>
handleSetState({
...(await handleVideoFieldCancel(
refs,
props,
state,
)),
video_upload_dialog_open: false,
})
}
>
<CloseIcon />
</CustomButton>
<CustomButton
className={
classes.videoInputDialogActionButtonStyle
}
primaryButtonStyle
size="medium"
onClick={async () =>
handleSetState({
...(await handleVideoSelectDone(
refs,
props,
state,
)),
video_upload_dialog_open: false,
})
}
>
<CheckIcon />
</CustomButton>
<input
className={common_classes.displayNone}
ref={refs.video_file_el}
type="file"
accept="video/*"
id="video"
name="video"
onChange={async e => {
handleSetState(
await handleVideoFieldChange(
e,
refs,
props,
state,
handleSetState,
),
);
}}
onBlur={props.handleBlur}
/>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Dialog>
</form>
<Dialog
PaperProps={{
style: {
backgroundColor: 'transparent',
boxShadow: 'none',
},
}}
className={classes.uploadProgressDialogStyle}
open={media_upload.upload_dialog}
aria-labelledby="upload progress dialog"
>
<Box
className={classes.uploadProgressIndicatorContainerStyle}
>
<CircularProgress
className={classes.uploadProgressStyle}
variant="determinate"
size={70}
thickness={6}
value={media_upload.upload_percent}
/>
<Box
top={0}
left={0}
bottom={0}
right={0}
position="absolute"
display="flex"
alignItems="center"
justifyContent="center"
>
<Typography
className={classes.uploadProgressLabelStyle}
variant="caption"
component="div"
>{`${Math.round(
media_upload.upload_percent,
)}%`}</Typography>
</Box>
</Box>
</Dialog>
</CardContent>
</CardActionArea>
</Card>
</Container>
</Box>
);
}
}
Example #11
Source File: PageWrapper.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function PageWrapper View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function PageWrapper(props) {
const backToTopEl = React.useRef(null);
const classes = useStyles();
const common_classes = useCommonStyles();
const trigger = useScrollTrigger();
const [searchType, setSearchType] = useState(
getQueryParams(window.location.href).get('type') || SearchType.PROJECTS,
);
const formRef = useRef();
const token = useSelector(state => state.auth.token);
const [state, setState] = React.useState({
username: null,
anchor_el: null,
loading: false,
open_search_form: false,
});
const [options, setOptions] = useState([]);
const [query, setQuery] = useState('');
const [queryInput, setQueryInput] = useState('');
const throttledFetchOptions = useMemo(
() =>
throttle(async (query, searchType) => {
if (query.length === 0) {
setOptions([]);
return;
}
const api = new API();
let completions = [];
if (searchType === SearchType.TAGS) {
completions = await api.autocompleteTags({ query, token });
completions = completions.map(({ name }) => ({
title: name,
}));
} else if (searchType === SearchType.PROJECTS) {
completions = await api.autocompleteProjects({ query, token });
completions = completions.map(({ id, title, creator, images }) => ({
title,
shortInfo: creator.username,
image: images.length > 0 ? images[0].image_url : null,
link: `/projects/${id}`,
}));
} else {
completions = await api.autocompleteCreators({ query, token });
completions = completions.map(({ username, avatar }) => ({
title: username,
image: avatar,
link: `/creators/${username}`,
}));
}
setOptions(completions);
}, 2),
[],
);
useEffect(() => {
throttledFetchOptions(
query ||
(props.location.search &&
getQueryParams(window.location.href).get('q')),
searchType,
);
}, [query, searchType]);
useEffect(() => {
throttledFetchOptions.cancel();
}, []);
useEffect(() => {
handleSetState({ loading: true });
fetchHero(props)
.then(() => {
if (props.auth.token) {
return props.getAuthUser(props);
}
})
.finally(() => {
handleSetState({ loading: false });
});
}, [props.auth.token]);
React.useEffect(() => {
handleSetState(handleProfileMenuClose());
}, [trigger]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const onSearchOptionClick = async (_, option) => {
if (!option || !option.title) return;
await new Promise(resolve => setTimeout(resolve, 100));
if (option.link) {
window.history.pushState({}, '', option.link);
window.location.reload();
return;
}
const queryParams = new URLSearchParams({
type: searchType,
q: option.title,
});
window.history.pushState({}, '', `/search?${queryParams}`);
window.location.reload();
};
const handleSubmit = e => {
e.preventDefault();
const queryParams = new URLSearchParams({
type: searchType,
q: query,
});
window.history.pushState({}, '', `/search?${queryParams}`);
window.location.reload();
};
const { anchor_el, loading, open_search_form } = state;
const { t } = props;
const { zubhub, hero } = props.projects;
const profileMenuOpen = Boolean(anchor_el);
return (
<>
<ToastContainer />
<CssBaseline />
<AppBar className={classes.navBarStyle}>
<Container className={classes.mainContainerStyle}>
<Toolbar className={classes.toolBarStyle}>
<Box className={classes.logoStyle}>
<Link to="/">
<img
src={zubhub?.header_logo_url ? zubhub.header_logo_url : logo}
alt="logo"
/>
</Link>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.addOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value=""
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.removeOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value={props.i18n.language}
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<form
action="/search"
className={clsx(classes.searchFormStyle, classes.removeOn894)}
role="search"
onSubmit={handleSubmit}
ref={formRef}
>
<FormControl variant="outlined">
<InputLabel
htmlFor="q"
className={classes.searchFormLabelStyle}
>
{t('pageWrapper.inputs.search.label')}
</InputLabel>
<FormGroup row>
<FormControl variant="outlined">
<InputSelect
searchType={searchType}
onSearchTypeChange={setSearchType}
name="type"
>
<MenuItem value={SearchType.PROJECTS}>
Projects
</MenuItem>
<MenuItem value={SearchType.CREATORS}>
Creators
</MenuItem>
<MenuItem value={SearchType.TAGS}>Tags</MenuItem>
</InputSelect>
</FormControl>
<Autocomplete
options={options}
defaultValue={{
title:
props.location.search &&
getQueryParams(window.location.href).get('q'),
}}
renderOption={(option, { inputValue }) => (
<Option
option={option}
inputValue={inputValue}
onOptionClick={onSearchOptionClick}
/>
)}
onChange={onSearchOptionClick}
>
{params => (
<TextField
name="q"
id="q"
type="search"
variant="outlined"
{...params}
InputProps={{
...params.InputProps,
className: clsx(
classes.searchFormInputStyle,
'search-form-input',
),
endAdornment: (
<InputAdornment position="end">
<IconButton
type="submit"
className={classes.searchFormSubmitStyle}
aria-label={t(
'pageWrapper.inputs.search.label',
)}
>
<SearchIcon />
</IconButton>
</InputAdornment>
),
pattern: '(.|s)*S(.|s)*',
defaultValue: {
title:
props.location.search &&
getQueryParams(window.location.href).get('q'),
},
}}
onChange={e => setQuery(e.target.value)}
placeholder={`${t(
'pageWrapper.inputs.search.label',
)}...`}
/>
)}
</Autocomplete>
</FormGroup>
</FormControl>
</form>
</Box>
<div className={classes.navActionStyle}>
{!props.auth.token ? (
<>
<IconButton
className={clsx(
classes.toggleSearchFormStyle,
classes.addOn894,
)}
id="toggle-search"
aria-label="toggle search form"
onClick={() =>
handleSetState(handleToggleSearchForm(state))
}
>
<SearchIcon />
</IconButton>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.removeOnSmallScreen,
)}
to="/login"
>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
>
{t('pageWrapper.navbar.login')}
</CustomButton>
</Link>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.removeOnSmallScreen,
)}
to="/signup"
>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
customButtonStyle
className={common_classes.marginLeft1em}
>
{t('pageWrapper.navbar.signup')}
</CustomButton>
</Link>
<MenuRoundedIcon
className={common_classes.addOnSmallScreen}
aria-label={t('pageWrapper.navbar.menu')}
aria-controls="menu"
aria-haspopup="true"
onClick={e => handleSetState(handleProfileMenuOpen(e))}
/>
<Menu
className={common_classes.addOnSmallScreen}
disableScrollLock={true}
id="menu"
anchorEl={anchor_el}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={profileMenuOpen}
onClose={e => handleSetState(handleProfileMenuClose(e))}
>
<MenuItem>
<Link className={classes.textDecorationNone} to="/login">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.login')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link className={classes.textDecorationNone} to="/signup">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.signup')}
</Typography>
</Link>
</MenuItem>
</Menu>
</>
) : (
<>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.marginRight1em,
common_classes.removeOnSmallScreen,
)}
to="/projects/create"
>
<CustomButton
variant="contained"
primaryButtonStyle
customButtonStyle
size="small"
>
{t('pageWrapper.navbar.createProject')}
</CustomButton>
</Link>
<IconButton
className={clsx(
classes.toggleSearchFormStyle,
classes.addOn894,
)}
id="toggle-search"
aria-label="toggle search form"
onClick={() =>
handleSetState(handleToggleSearchForm(state))
}
>
<SearchIcon />
</IconButton>
<NotificationButton
className={clsx(
common_classes.marginRight1em,
common_classes.removeOnSmallScreen,
)}
/>
<Avatar
className={clsx(
classes.avatarStyle,
common_classes.removeOnSmallScreen,
)}
aria-label={`${props.auth.username}' Avatar`}
aria-controls="profile_menu"
aria-haspopup="true"
onClick={e => handleSetState(handleProfileMenuOpen(e))}
src={props.auth.avatar}
alt={props.auth.username}
/>
<Menu
className={classes.profileMenuStyle}
disableScrollLock={true}
id="profile_menu"
anchorEl={anchor_el}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={profileMenuOpen}
onClose={e => handleSetState(handleProfileMenuClose(e))}
>
<MenuItem>
<Tooltip title={props.auth.username} placement="top">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
className={classes.profileStyle}
>
{props.auth.username }
</Typography>
</Tooltip>
</MenuItem>
<MenuItem>
<a className={classes.textDecorationNone} href="/profile">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.profile')}
</Typography>
</a>
</MenuItem>
<MenuItem className={common_classes.addOnSmallScreen}>
<Link
className={classes.textDecorationNone}
to="/projects/create"
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.createProject')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/projects`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.projects')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/followers`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.followers')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/following`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.following')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to="/projects/saved"
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.savedProjects')}
</Typography>
</Link>
</MenuItem>
<MenuItem className={classes.logOutStyle}>
<Typography
className={common_classes.colorRed}
variant="subtitle2"
component="span"
onClick={e => logout(e, props)}
>
{t('pageWrapper.navbar.logout')}
</Typography>
</MenuItem>
</Menu>
</>
)}
</div>
</Toolbar>
{open_search_form ? (
<ClickAwayListener
onClickAway={e => handleSetState(closeSearchFormOrIgnore(e))}
>
<form
action="/search"
className={clsx(classes.smallSearchFormStyle, classes.addOn894)}
role="search"
ref={formRef}
>
<FormControl variant="outlined" style={{ minWidth: 'unset' }}>
<InputSelect
searchType={searchType}
onSearchTypeChange={setSearchType}
name="type"
>
<MenuItem value={SearchType.PROJECTS}>Projects</MenuItem>
<MenuItem value={SearchType.CREATORS}>Creators</MenuItem>
<MenuItem value={SearchType.TAGS}>Tags</MenuItem>
</InputSelect>
</FormControl>
<FormControl
variant="outlined"
style={{ flex: '1 1 auto', maxWidth: '350px' }}
>
<InputLabel
htmlFor="q"
className={classes.searchFormLabelStyle}
>
{t('pageWrapper.inputs.search.label')}
</InputLabel>
<Autocomplete
options={options}
defaultValue={
props.location.search &&
getQueryParams(window.location.href).get('q')
}
renderOption={(option, { inputValue }) => (
<Option
option={option}
inputValue={inputValue}
onOptionClick={onSearchOptionClick}
/>
)}
onChange={onSearchOptionClick}
>
{params => (
<TextField
name="q"
id="q"
type="search"
variant="outlined"
{...params}
InputProps={{
...params.InputProps,
className: clsx(
classes.smallSearchFormInputStyle,
'search-form-input',
),
endAdornment: (
<InputAdornment position="end">
<IconButton
type="submit"
className={classes.searchFormSubmitStyle}
aria-label={t(
'pageWrapper.inputs.search.label',
)}
>
<SearchIcon />
</IconButton>
</InputAdornment>
),
pattern: '(.|s)*S(.|s)*',
}}
placeholder={`${t(
'pageWrapper.inputs.search.label',
)}...`}
onChange={e => setQuery(e.target.value)}
/>
)}
</Autocomplete>
</FormControl>
</form>
</ClickAwayListener>
) : null}
</Container>
</AppBar>
<Toolbar ref={backToTopEl} />
{loading ? <LoadingPage /> : props.children}
<footer className={clsx('footer-distributed', classes.footerStyle)}>
<Box>
<a href="https://unstructured.studio">
<img
src={
zubhub?.footer_logo_url
? zubhub.footer_logo_url
: unstructuredLogo
}
className={classes.footerLogoStyle}
alt="unstructured-studio-logo"
/>
</a>
<div>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.addOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value=""
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.removeOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value={props.i18n.language}
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
</div>
</Box>
<section className={classes.footerSectionStyle}>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.privacy')}
</Typography>
<Link
to={`/privacy_policy`}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.guidelines')}
</Typography>
</Link>
<Link
to={`/terms_of_use`}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.termsOfUse')}
</Typography>
</Link>
</Box>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.about')}
</Typography>
<Link to="/about" className={common_classes.textDecorationNone}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.zubhub')}
</Typography>
</Link>
</Box>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.help')}
</Typography>
<a
target="__blank"
rel="noreferrer"
href={
hero.tinkering_resource_url
? hero.tinkering_resource_url
: 'https://kriti.unstructured.studio/'
}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.resources')}
</Typography>
</a>
<Link
to={`/faqs`}
className={clsx(
common_classes.textDecorationNone,
common_classes.displayNone,
)}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.faqs')}
</Typography>
</Link>
<a
href="mailto:[email protected]"
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.contactUs')}
</Typography>
</a>
</Box>
</section>
<Zoom in={useScrollTrigger}>
<div
onClick={e => handleScrollTopClick(e, backToTopEl)}
role="presentation"
className={classes.scrollTopButtonStyle}
>
<Fab color="secondary" size="small" aria-label="scroll back to top">
<KeyboardArrowUpIcon />
</Fab>
</div>
</Zoom>
</footer>
</>
);
}
Example #12
Source File: CommentInput.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function CommentInput Component
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function CommentInput(props) {
const refs = {
comment_text: React.useRef(null),
comment_box: React.useRef(null),
comment_author_name: React.useRef(null),
comment_publish_button: React.useRef(null),
};
const classes = useStyles();
const common_classes = useCommonStyles();
const [state, setState] = React.useState({
creator_suggestion: [],
creator_suggestion_open: false,
});
React.useEffect(() => {
const comment_text_el = refs.comment_text.current;
return () => {
try {
comment_text_el.removeEventListener('focus', () =>
handleCommentTextFocus(refs),
);
} catch {}
try {
document.removeEventListener('click', e =>
handleDocumentClick(e, refs),
);
} catch {}
};
}, []);
React.useEffect(() => {
try {
constructCommentBox(refs);
} catch {}
}, [props.context.body]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const { creator_suggestion, creator_suggestion_open } = state;
const { parent_id, t } = props;
return (
<Box
className={clsx(
'comment-box comment-collapsed',
parent_id ? 'sub-comment-box' : null,
)}
ref={refs.comment_box}
>
<Box className="comment-meta">
<Link
className={clsx(common_classes.textDecorationNone)}
to={`/creators/${props.auth.username}`}
>
{props.auth.token ? (
<Avatar
className={classes.commentAvatarStyle}
src={props.auth.avatar}
alt={props.auth.username}
/>
) : null}
</Link>
<Link
ref={refs.comment_author_name}
className={clsx(
common_classes.textDecorationNone,
'comment-meta__a',
'display-none',
)}
to={`/creators/${props.auth.username}`}
>
{props.auth.username}
</Link>
</Box>
<form className="comment-form">
<textarea
ref={refs.comment_text}
className={
!parent_id ? 'comment-text' : 'comment-text sub-comment-text'
}
name="comment"
id="comment"
autoComplete="off"
placeholder={`${t('comments.write')} ...`}
onChange={e => {
handleSuggestCreators(e, props, timer, handleSetState);
}}
></textarea>
<CustomButton
ref={refs.comment_publish_button}
onClick={e => handleAddComment(e, props, refs.comment_text)}
className={clsx('comment-publish-button', 'display-none')}
variant="contained"
size={parent_id ? 'small' : 'medium'}
primaryButtonStyle
>
{t('comments.action')}
</CustomButton>
</form>
<ClickAwayListener
onClickAway={() =>
handleSetState({
creator_suggestion_open: false,
creator_suggestion: [],
})
}
>
<Box
className={clsx(
classes.creatorSuggestionBoxStyle,
!creator_suggestion_open ? common_classes.displayNone : null,
)}
>
{creator_suggestion && creator_suggestion.length > 0 ? (
creator_suggestion.map((creator, index) => (
<Box
className={classes.creatorSuggestionStyle}
key={index}
onClick={() => {
clearTimeout(timer.id);
handleSetState({
creator_suggestion: [],
creator_suggestion_open: false,
});
handleInsertCreatorName(
`@${creator.username}`,
refs.comment_text,
);
}}
>
<Avatar
className={classes.commentAvatarStyle}
src={creator.avatar}
alt={creator.username}
/>
<Typography color="textPrimary">{creator.username}</Typography>
</Box>
))
) : (
<Box className={classes.creatorSuggestionLoadingStyle}>
<CircularProgress size={30} thickness={3} />
</Box>
)}
</Box>
</ClickAwayListener>
</Box>
);
}
Example #13
Source File: NavVidMenuBtn.js From youtube-clone with MIT License | 4 votes |
NavVideoMenuBtn = () => {
const dispatch = useDispatch();
const isModalOpen = useSelector(({ upload }) => upload.isOpen);
const isAuth = useSelector(({ channel }) => channel.isAuth);
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorBtnRef = React.useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorBtnRef.current && anchorBtnRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
const handleUploadClick = () => {
handleToggle();
if (isAuth) {
dispatch(setModal(true));
} else {
window.location.assign(urlJoin(BACKEND_URL, "/api/auth/google"));
}
};
const handleModalClose = (event) => {
dispatch(setModal(false));
// dispatch(resetUpload());
};
function handleListKeyDown(event) {
if (event.key === "Tab") {
event.preventDefault();
setOpen(false);
}
}
return (
<>
<IconButton
ref={anchorBtnRef}
aria-controls={open ? "menu-list-grow" : undefined}
aria-haspopup="true"
className={classes.iconButton}
onClick={handleToggle}
>
<VideoIcon />
</IconButton>
{isModalOpen && (
<UploadModal isOpen={isModalOpen} handleClose={handleModalClose} />
)}
(
<Popper
open={open}
anchorEl={anchorBtnRef.current}
role={undefined}
transition
disablePortal
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="menu-list-grow"
onKeyDown={handleListKeyDown}
>
<List component="nav" aria-labelledby="nested-list-subheader">
<NavItem
title="Upload"
icon={TVIcon}
onClick={handleUploadClick}
/>
<NavItem
to="/live"
title="Go live"
icon={LiveIcon}
onClick={handleClose}
/>
</List>
<Divider />
</MenuList>
</ClickAwayListener>
</Paper>
</Popper>
)}
</>
);
}
Example #14
Source File: NavUserMenuBtn.js From youtube-clone with MIT License | 4 votes |
NavUserMenuBtn = () => {
const dispatch = useDispatch();
const image = useSelector(({ channel }) => channel.image);
const name = useSelector(({ channel }) => channel.name);
const email = useSelector(({ channel }) => channel.email);
const id = useSelector(({ channel }) => channel.id);
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
function handleListKeyDown(event) {
if (event.key === "Tab") {
event.preventDefault();
setOpen(false);
}
}
return (
<>
<IconButton
ref={anchorRef}
aria-controls={open ? "menu-list-grow" : undefined}
aria-haspopup="true"
onClick={handleToggle}
className={classes.iconButton}
>
<Avatar alt="Channel Image" src={image} />
</IconButton>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
style={{ width: "350px" }}
id="menu-list-grow"
onKeyDown={handleListKeyDown}
>
<Grid
container
spacing={1}
alignItems="center"
wrap="nowrap"
style={{ padding: "12px 24px" }}
>
<Grid item>
<Avatar alt="Profile Image" src={image} size="large" />
</Grid>
<Grid item>
<Grid container style={{ overflow: "hidden" }}>
<Grid item xs={12}>
<strong>{name}</strong>
</Grid>{" "}
<Grid item>{email}</Grid>
</Grid>
</Grid>
</Grid>
<Divider />
<List component="nav" aria-labelledby="nested-list-subheader">
<NavItem
to={`/channel/${id}`}
title={"Your Channel"}
icon={ExitToAppIcon}
onClick={handleClose}
/>
<NavItem
title={"Sign Out"}
icon={ExitToAppIcon}
onClick={(e) => {
handleClose(e);
dispatch(logoutChannel());
}}
/>
</List>
<Divider />
</MenuList>
</ClickAwayListener>
</Paper>
</Popper>
</>
);
}
Example #15
Source File: Toolbox.jsx From doc2pen with Creative Commons Zero v1.0 Universal | 4 votes |
function VerticalTabs(props) {
const {
color,
setColor,
fillColor,
setFillColor,
fillOpacity,
setFillOpacity,
setBowing,
setFillStyle,
setFillWeight,
setHachureAngle,
setHachureGap,
bowing,
fillStyle,
fillWeight,
hachureAngle,
hachureGap,
background,
setBackground,
width,
setWidth,
stroke,
setStroke,
roughness,
setRoughness,
type,
setType,
fontSize,
setFontSize,
fontStyle,
setFontStyle,
fontFamily,
setFontFamily,
edge,
setEdge,
clear,
download,
initiateLoadSaved,
loadLastState,
saveInstance,
} = props;
const [displayColorPicker, setDisplayColorPicker] = useState(false);
const ColorPicker = props => {
const { width, name, color, onColorChange } = props;
return (
<div className={styles.root}>
<div className={styles.swatch}>
<div
className={styles.colorIndicator}
style={{
backgroundColor: props.color || "#fff",
}}
onMouseDown={() => {
setDisplayColorPicker(true);
}}
/>
</div>
{displayColorPicker ? (
<ClickAwayListener
onClickAway={() => {
setDisplayColorPicker(false);
}}
>
<div className={styles.popover}>
<ChromePicker
width={width}
name={name}
color={color}
onChangeComplete={color => onColorChange(color.hex)}
/>
</div>
</ClickAwayListener>
) : null}
</div>
);
};
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
};
function Feature({ title, children, classname }) {
return (
<ListItem>
<div className={styles.feature + " " + classname}>
<ListItemText className={styles.title}>{title}</ListItemText>
<div className={styles.body}>{children}</div>
</div>
</ListItem>
);
}
function Shape({ type_, id, label, children }) {
return (
<label style={{ marginTop: "3px" }} htmlFor={id} title={label}>
<div
className={`${styles.feature} ${
type === type_ && styles.active_feature
}`}
onClick={() => setType(type_)}
id={id}
>
{children}
</div>
</label>
);
}
return (
<div className={styles.toolbox_root}>
<div className={styles.canvas_toolbox}>
<div className={classes.root}>
<Tabs
orientation="vertical"
variant="scrollable"
value={value}
onChange={handleChange}
className={classes.tabs}
>
<Tab
onClick={() => setType("pen")}
label={
<label title="Project">
<AccountTree />
</label>
}
{...a11yProps(0)}
/>
<Tab
onClick={() => setType("pen")}
label={
<label title="Canvas Setup">
<RiFileSettingsLine size={25} />
</label>
}
{...a11yProps(1)}
/>
<Tab
onClick={() => setType("pen")}
label={
<label title="Shapes & Tools">
<FaShapes size={25} />
</label>
}
{...a11yProps(2)}
/>
<Tab
onClick={() => setType("text")}
label={
<label title="Text">
<TextFields />
</label>
}
{...a11yProps(3)}
/>
<Tab
onClick={() => {
setType("pen");
}}
label={
<label title="Icon Library">
<Apps />
</label>
}
{...a11yProps(4)}
/>
<Tab
onClick={() => setType("pen")}
label={
<label title="Minimize Sidebar">
<Close />
</label>
}
{...a11yProps(5)}
/>
</Tabs>
<TabPanel value={value} index={0}>
<List component="div">
<ListItem button onClick={clear}>
<ListItemIcon>
<Delete />
</ListItemIcon>
<ListItemText primary="Clear Canvas" />
</ListItem>
<ListItem button onClick={download}>
<ListItemIcon>
<SaveAlt />
</ListItemIcon>
<ListItemText primary="Download PNG" />
</ListItem>
<ListItem
button
onClick={() => initiateLoadSaved("img-file-selector")}
>
<ListItemIcon>
<PhotoLibrary />
<input
type="file"
id="img-file-selector"
style={{ display: "none" }}
accept="image/*"
onChange={event => loadLastState(event)}
/>
</ListItemIcon>
<ListItemText primary="Place Image" />
</ListItem>
<ListItem
button
onClick={() => saveInstance("savedProgress.d2ps")}
>
<ListItemIcon>
<Save />
</ListItemIcon>
<ListItemText primary="Save & download Progress" />
</ListItem>
<ListItem
button
onClick={() => initiateLoadSaved("file-selector")}
>
<ListItemIcon style={{ width: 0 }}>
<D2psIcon
style={{
transform: "scale(0.6) translateX(-30px)",
}}
/>
<input
type="file"
id="file-selector"
style={{ display: "none" }}
accept=".d2ps"
onChange={event => loadLastState(event)}
/>
</ListItemIcon>
<ListItemText primary="Load Previous Progress" />
</ListItem>
</List>
</TabPanel>
<TabPanel value={value} index={1}>
<List component="div">
<Feature title="Canvas Setup">
<div className={styles.colorPicker}>
<ColorPicker
width={200}
name="canvas_bg_color"
color={background}
onColorChange={setBackground}
/>
<input
className={styles.hexInput}
placeholder="#"
type="text"
value={background}
onInput={e => setBackground(e.target.value)}
/>
</div>
</Feature>
</List>
</TabPanel>
<TabPanel value={value} index={2}>
<List component="div">
<Feature title="Shapes and Tools">
<Shape type_="pen" id="sketch-shapes-pen" label="Pen">
<FaPencilAlt size={12} />
</Shape>
<Shape type_="line" id="sketch-shapes-line" label="Line">
<FaSlash size={10} />
</Shape>
<Shape type_="square" id="sketch-shapes-square" label="Square">
<FaRegSquare size={10} />
</Shape>
<Shape type_="circle" id="sketch-shapes-circle" label="Circle">
<FaRegCircle size={10} />
</Shape>
<Shape
type_="triangle"
id="sketch-shapes-triangle"
label="Triangle"
>
<GiTriangleTarget size={12} />
</Shape>
<Shape type_="arrow" id="sketch-shapes-arrow" label="Arrow">
<BsArrowUpRight size={12} />
</Shape>
<Shape
type_="diamond"
id="sketch-shapes-diamond"
label="Diamond"
>
<BsDiamond size={10} />
</Shape>
<Shape
type_="biShapeTriangle"
id="sketch-shapes-biShapeTriangle"
label="Bi Shape Triangle"
>
<BiShapeTriangle size={12} />
</Shape>
</Feature>
<Divider />
{!["text", "pen", "line"].includes(type) && (
<>
<Feature title="Fill Style">
<select
name="shape_fill_style"
value={fillStyle}
onChange={e => setFillStyle(e.target.value)}
>
<option value="none">none</option>
<option value="solid">solid</option>
<option value="hachure">hachure</option>
<option value="zigzag">zigzag</option>
<option value="cross-hatch">cross-hatch</option>
<option value="dots">dots</option>
<option value="dashed">dashed</option>
<option value="zigzag-line">zigzag-line</option>
</select>
</Feature>
{fillStyle !== "none" && (
<>
<Feature title="Fill Color">
<div className={styles.colorPicker}>
<ColorPicker
width={200}
name="canvas_pen_color"
color={fillColor}
onColorChange={setFillColor}
/>
<input
className={styles.hexInput}
placeholder="#"
type="text"
value={fillColor}
onInput={e => setFillColor(e.target.value)}
/>
</div>
</Feature>
<Feature
classname={styles.sliderWrapper}
title={"Fill Opacity"}
>
<input
className={styles.slider}
type="range"
min={0}
max={1}
step={0.1}
value={fillOpacity}
onChange={e => setFillOpacity(e.target.value)}
/>
</Feature>
</>
)}
{!["none", "solid"].includes(fillStyle) && (
<>
<Feature
classname={styles.sliderWrapper}
title={"Fill Weight"}
>
<input
className={styles.slider}
type="range"
min={1}
max={10}
step={0.1}
value={fillWeight}
onChange={e => setFillWeight(e.target.value)}
/>
</Feature>
<Feature
classname={styles.sliderWrapper}
title={"Fill Hachure Angle"}
>
<input
className={styles.slider}
type="range"
min={0}
max={360}
step={1}
value={hachureAngle + 180}
onChange={e => setHachureAngle(e.target.value - 180)}
/>
</Feature>
<Feature
classname={styles.sliderWrapper}
title={"Fill Hachure Gap"}
>
<input
className={styles.slider}
type="range"
min={1}
max={10}
step={0.1}
value={hachureGap}
onChange={e => setHachureGap(e.target.value)}
/>
</Feature>
</>
)}
<Divider />
</>
)}
<Feature title="Stroke">
<div className={styles.colorPicker}>
<ColorPicker
width={200}
name="canvas_pen_color"
color={color}
onColorChange={setColor}
/>
<input
className={styles.hexInput}
placeholder="#"
type="text"
value={color}
onInput={e => setColor(e.target.value)}
/>
</div>
</Feature>
<Feature classname={styles.sliderWrapper} title={"Roughness"}>
<input
className={styles.slider}
type="range"
min={0}
max={5}
step={0.1}
value={roughness}
onChange={e => setRoughness(e.target.value)}
/>
</Feature>
<Feature classname={styles.sliderWrapper} title={"Stroke Bowing"}>
<input
className={styles.slider}
type="range"
min={0}
max={10}
step={0.1}
value={bowing}
onChange={e => setBowing(e.target.value)}
/>
</Feature>
<Feature title="Stroke Width">
<select
name="canvas_pen_width"
value={width}
onChange={e => setWidth(e.target.value)}
>
<option value="1">1px</option>
<option value="2">2px</option>
<option value="3">3px</option>
<option value="4">4px</option>
<option value="5">5px</option>
<option value="6">6px</option>
<option value="7">7px</option>
<option value="8">8px</option>
<option value="9">9px</option>
<option value="10">10px</option>
<option value="11">11px</option>
</select>
</Feature>
<Feature title="Stroke Style">
<div
className={`${styles.feature_box} ${
stroke === "none" && styles.active_feature_box
}`}
onClick={() => setStroke("none")}
>
<AiOutlineLine size={20} />
</div>
<div
className={`${styles.feature_box} ${
stroke === "small" && styles.active_feature_box
}`}
onClick={() => setStroke("small")}
>
<AiOutlineSmallDash size={20} />
</div>
<div
className={`${styles.feature_box} ${
stroke === "big" && styles.active_feature_box
}`}
onClick={() => setStroke("big")}
>
<AiOutlineDash size={20} />
</div>
</Feature>
<Feature title="Edge">
<select value={edge} onChange={e => setEdge(e.target.value)}>
<option value="round">Round</option>
<option value="bevel">Bevel</option>
<option value="miter">Miter</option>
</select>
</Feature>
</List>
</TabPanel>
<TabPanel value={value} index={3}>
<List component="div">
<Feature title="Stroke">
<div className={styles.colorPicker}>
<ColorPicker
width={200}
name="canvas_pen_color"
color={color}
onColorChange={setColor}
/>
<input
className={styles.hexInput}
placeholder="#"
type="text"
value={color}
onInput={e => setColor(e.target.value)}
/>
</div>
</Feature>
<Feature
classname={styles.sliderWrapper}
title={`Font [ ${fontSize} ]`}
>
<input
className={styles.slider}
type="range"
min="10"
max="20"
value={fontSize * 10}
onChange={e => setFontSize(e.target.value / 10)}
/>
</Feature>
<Feature title="Font Style">
<div
className={`${styles.feature_box} ${
fontStyle === "normal" && styles.active_feature_box
}`}
onClick={() => setFontStyle("normal")}
>
<BsFonts size={20} />
</div>
<div
className={`${styles.feature_box} ${
fontStyle === "italic" && styles.active_feature_box
}`}
onClick={() => setFontStyle("italic")}
>
<FaItalic size={15} />
</div>
<div
className={`${styles.feature_box} ${
fontStyle === "bold" && styles.active_feature_box
}`}
onClick={() => setFontStyle("bold")}
>
<FaBold size={15} />
</div>
</Feature>
<Feature title="Font Family">
<select
value={fontFamily}
onChange={e => setFontFamily(e.target.value)}
>
<option value="cursive">Cursive</option>
<option value="Courier New">Courier New</option>
<option value="serif">Serif</option>
</select>
</Feature>
</List>
</TabPanel>
<TabPanel value={value} index={4}>
<List component="div">
<IconsLibrary />
</List>
</TabPanel>
<TabPanel
className={classes.tabPanelClose}
value={value}
index={5}
></TabPanel>
</div>
</div>
</div>
);
}
Example #16
Source File: ActionCardContainer.js From mui-storyblok with MIT License | 4 votes |
ActionCardContainer = ({
rootClass,
menuName,
actionCards,
height,
width,
dataBlokC,
dataBlokUid,
storyblokClass,
}) => {
const [open, setOpen] = useState(false);
const anchorRef = useRef(null);
const defaultStyling = {
padding: '20px 10%',
marginTop: '10px',
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-evenly',
outline: 'none',
};
const styles = StoryBlok.arrayToMuiStyles(rootClass, { ...defaultStyling });
const handleToggle = () => {
setOpen(prevOpen => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
return (
<div
className={`${styles.root} ${storyblokClass}`}
data-blok-c={dataBlokC}
data-blok-uid={dataBlokUid}
>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
data-testid="menuButton"
>
<Typography {...menuName[0]} />
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: 'center top' }}
>
<Paper style={{ minWidth: '100vw', height: '100%' }} id="paper-test">
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="menu-list-grow"
className={styles.root}
>
{actionCards.map((card, index) => (
<MuiActionCard
{...card}
key={index}
height={height}
width={width}
/>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}
Example #17
Source File: OftadehAvatarMenu.jsx From oftadeh-react-admin with MIT License | 4 votes |
OftadehAvatarMenu = props => {
const classes = useStyles(props);
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen(prevOpen => !prevOpen);
};
const handleClose = event => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
return (
<>
<ListItem
button
ref={anchorRef}
aria-controls={open ? "menu-list-grow" : undefined}
aria-haspopup="true"
onClick={handleToggle}
alignItems="flex-start"
className={classes.paddingRightZero}
>
<ListItemAvatar>
<OftadehAvatarBadge
overlap="circle"
anchorOrigin={{
vertical: "bottom",
horizontal: "right"
}}
variant="dot"
>
<Avatar
alt="Mohammad Oftadeh"
src="https://lh5.googleusercontent.com/-WqhFe4eMggE/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdFUa5CK9Wi6g5qd8ZUt6apKFYSwA/photo.jpg?sz=328"
/>
</OftadehAvatarBadge>
</ListItemAvatar>
<Hidden implementation="css" smDown>
<ListItemText
primary={
<React.Fragment>
<Typography component="span" variant="subtitle2">
Mohammad Oftadeh
</Typography>
</React.Fragment>
}
secondary={
<React.Fragment>
<Typography
component="span"
variant="caption"
className={classes.inline}
color="textPrimary"
>
Admin
</Typography>
</React.Fragment>
}
/>
</Hidden>
</ListItem>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom" ? "center top" : "center bottom"
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow">
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<AccountCircle fontSize="small" />
</ListItemIcon>
Profile
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<Settings fontSize="small" />
</ListItemIcon>
settings
</MenuItem>
<MenuItem onClick={handleClose}>
<ListItemIcon className={classes.menuIcon}>
<ExitToApp fontSize="small" />
</ListItemIcon>
Logout
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</>
);
}
Example #18
Source File: ShareQueue.jsx From simplQ-frontend with GNU General Public License v3.0 | 4 votes |
ShareQueue = ({ queueName, tourTag }) => {
const [open, setOpen] = useState(false);
const anchorRef = useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
const link = `${window.location.origin}/j/${queueName}`;
const quote = `Hi! Use ${link} to join my queue and get live updates.`;
return (
<div className={styles['share']}>
<ButtonGroup
reactour-selector={tourTag}
variant="contained"
className={styles['button-background']}
ref={anchorRef}
aria-label="split button"
>
<CopyButton {...{ link }} />
<Button
className={styles['button-background']}
color="primary"
size="small"
onClick={handleToggle}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper
className={styles['popper']}
open={open}
anchorEl={anchorRef.current}
transition
disablePortal
placement="bottom-end"
>
{({ TransitionProps, placement }) => (
<Grow
in={TransitionProps?.in}
onEnter={TransitionProps?.onEnter}
onExited={TransitionProps?.onExited}
style={{
transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList>
<Typography>
<b>Share</b>
</Typography>
<Divider />
<MenuItem>
<FacebookShareButton
url={link}
quote={quote}
className={styles['share-button']}
>
<FacebookIcon size={24} round className={styles['share-icon']} />
<Typography>Facebook</Typography>
</FacebookShareButton>
</MenuItem>
<Divider />
<MenuItem>
<TwitterShareButton url={link} title={quote} className={styles['share-button']}>
<TwitterIcon size={24} round className={styles['share-icon']} />
<Typography>Twitter</Typography>
</TwitterShareButton>
</MenuItem>
<Divider />
<MenuItem>
<WhatsappShareButton
url={link}
title={quote}
className={styles['share-button']}
>
<WhatsappIcon size={24} round className={styles['share-icon']} />
<Typography>Whatsapp</Typography>
</WhatsappShareButton>
</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}