@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 vote down vote up
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 vote down vote up
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 vote down vote up
// ----------------------------------------------------------------------

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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
 * @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 vote down vote up
/**
 * @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 vote down vote up
/**
 * @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 vote down vote up
/**
 * @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 vote down vote up
/**
 * @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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}