@material-ui/icons#ExpandMore JavaScript Examples

The following examples show how to use @material-ui/icons#ExpandMore. 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: ListExpansion.js    From mui-storyblok with MIT License 6 votes vote down vote up
MuiListExpansion = ({
  rootClass,
  handleClick,
  icon,
  open,
  primaryText,
}) => {
  const styles = StoryBlok.arrayToMuiStyles(rootClass);

  return (
    <>
      <ListItem button onClick={handleClick} className={styles.root}>
        {icon.length ? <ListItemIcon {...icon[0]} /> : null}
        <ListItemText primary={primaryText} />
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
    </>
  );
}
Example #2
Source File: helper.js    From Queen with MIT License 6 votes vote down vote up
Helper = () => {
  const classes = useStyles();
  return (
    <Accordion>
      <AccordionSummary
        expandIcon={<ExpandMore />}
        aria-controls="panel1a-content"
        id="panel1a-header"
      >
        <MarkdownTypo className={classes.heading}>{D.accordionHelperTitle}</MarkdownTypo>
        <MarkdownTypo className={classes.secondaryHeading}>
          {D.accordionHelperSubtitle}
        </MarkdownTypo>
      </AccordionSummary>
      <AccordionDetails className={classes.accordionDetails}>
        <MarkdownTypo>{D.accordionHelperBody}</MarkdownTypo>
      </AccordionDetails>
    </Accordion>
  );
}
Example #3
Source File: LanguageSelector.js    From covid-trials-dashboard with MIT License 6 votes vote down vote up
LanguageSelector = ({ languages, onSelect }) => {
  const { t } = useTranslation('languages')
  const [open, setOpen] = useState(false)
  const classes = useStyles()
  console.log({ languages })
  return (
    <>
      <ListItem button onClick={() => setOpen(!open)}>
        <ListItemIcon>
          <LanguageOutlined />
        </ListItemIcon>
        <ListItemText primary={t('selectorTitle')} />
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
      <Collapse in={open} timeout={300} unmountOnExit>
        <List component='div' disablePadding>
          {languages.map(lan => (
            <ListItem
              key={lan}
              button
              className={classes.nested}
              onClick={() => onSelect(lan)}
            >
              <ListItemText primary={t(lan)} />
            </ListItem>
          ))}
        </List>
      </Collapse>
    </>
  )
}
Example #4
Source File: Filter.jsx    From covid-trials-dashboard with MIT License 6 votes vote down vote up
Filter = ({ name, options, selected, onSelect }) => {
  const [open, setOpen] = useState(false)
  const classes = useStyles()
  const handleClick = useCallback(() => setOpen(!open), [open])
  return (
    <>
      <ListItem button onClick={handleClick}>
        <ListItemText primary={name} />
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
      <Collapse in={open} timeout={300} unmountOnExit>
        <List component='div' disablePadding>
          {options.map(opt => (
            <ListItem
              key={opt}
              button
              className={classes.nested}
              onClick={() => onSelect(opt)}
            >
              <ListItemIcon>
                <Checkbox
                  edge='start'
                  checked={selected.includes(opt)}
                  tabIndex={-1}
                />
              </ListItemIcon>
              <ListItemText primary={opt} />
            </ListItem>
          ))}
        </List>
      </Collapse>
    </>
  )
}
Example #5
Source File: ConnectionsList.js    From spl-token-wallet with Apache License 2.0 5 votes vote down vote up
function ConnectionsListItem({ origin, connectedWallet }) {
  const classes = useStyles();
  const [open, setOpen] = useState(false);
  // TODO better way to get high res icon?
  const appleIconUrl = origin + '/apple-touch-icon.png';
  const faviconUrl = origin + '/favicon.ico';
  const [iconUrl, setIconUrl] = useState(appleIconUrl);
  const { accounts } = useWalletSelector();
  // TODO better way to do this
  const account = accounts.find(
    (account) => account.address.toBase58() === connectedWallet.publicKey,
  );

  const setAutoApprove = (autoApprove) => {
    chrome.storage.local.get('connectedWallets', (result) => {
      result.connectedWallets[origin].autoApprove = autoApprove;
      chrome.storage.local.set({ connectedWallets: result.connectedWallets });
    });
  };

  const disconnectWallet = () => {
    chrome.storage.local.get('connectedWallets', (result) => {
      delete result.connectedWallets[origin];
      chrome.storage.local.set({ connectedWallets: result.connectedWallets });
    });
  };

  return (
    <>
      <ListItem button onClick={() => setOpen((open) => !open)}>
        <ListItemIcon>
          <div className={classes.listItemIcon}>
            <img
              src={iconUrl}
              onError={() => setIconUrl(faviconUrl)}
              className={classes.listItemImage}
              alt=""
            />
          </div>
        </ListItemIcon>
        <div style={{ display: 'flex', flex: 1 }}>
          <ListItemText primary={origin} secondary={account.name} />
        </div>
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
      <Collapse in={open} timeout="auto" unmountOnExit>
        <div class={classes.itemDetails}>
          <div class={classes.buttonContainer}>
            <Button
              variant={connectedWallet.autoApprove ? 'contained' : 'outlined'}
              color="primary"
              size="small"
              startIcon={<DoneAll />}
              onClick={() => setAutoApprove(!connectedWallet.autoApprove)}
            >
              {connectedWallet.autoApprove ? 'Auto-Approved' : 'Auto-Approve'}
            </Button>
            <Button
              variant="outlined"
              color="secondary"
              size="small"
              startIcon={<DeleteIcon />}
              onClick={disconnectWallet}
            >
              Disconnect
            </Button>
          </div>
        </div>
      </Collapse>
    </>
  );
}
Example #6
Source File: CheckoutItem.jsx    From resilience-app with GNU General Public License v3.0 5 votes vote down vote up
Expand = styled(ExpandMore)`
  align-self: center;

  ${(props) => props.open && `transform: rotate(180deg)`}
`
Example #7
Source File: CheckboxFacet.js    From azure-search-react-template with MIT License 5 votes vote down vote up
export default function CheckboxFacet(props) {

    let [isExpanded, setIsExpanded] = useState(false);

    const checkboxes = props.values.map(facetValue => {

        let isSelected = props.selectedFacets.some(facet => facet.value === facetValue.value);
        
        return (
            <FacetValueListItem dense disableGutters id={facetValue.value}>
                <Checkbox 
                    edge="start" 
                    disableRipple 
                    checked={isSelected}
                    onClick= {
                        isSelected ? 
                        () => props.removeFilter({field: props.name, value: facetValue.value}) :
                        () => props.addFilter(props.name, facetValue.value)
                    }
                />
                <ListItemText primary={facetValue.value + " (" + facetValue.count + ")"}/>
            </FacetValueListItem>
        );
    });


    return (
        <div>
            <FacetListItem disableRipple={true} button onClick={() => setIsExpanded(!isExpanded)}>
                <ListItemText 
                    primary={props.mapFacetName(props.name)}
                />
                {isExpanded ? <ExpandLess /> : <ExpandMore />}
            </FacetListItem>
            <Collapse in={isExpanded} component="div">
                <FacetValuesList>
                    {checkboxes}
                </FacetValuesList>
            </Collapse>
        </div>
    );
}
Example #8
Source File: Panel.js    From Queen with MIT License 5 votes vote down vote up
Panel = ({
  index,
  expanded,
  currentPanel,
  handleChangePanel,
  title,
  variables,
  setPage,
  goToSeePage,
}) => {
  const classes = useStyles(currentPanel)();

  const [localExpanded, setLocalExpanded] = useState(currentPanel);

  const localHandleChange = (event, newExpanded) => {
    setLocalExpanded(newExpanded);
    handleChangePanel(index)(event, newExpanded);
  };

  useEffect(() => {
    setLocalExpanded(expanded);
  }, [expanded]);

  useEffect(() => {
    setLocalExpanded(currentPanel);
  }, [currentPanel]);

  const isNothingToDisplay = vars =>
    Object.entries(variables).filter(([key, value]) => !!value).length === 0;

  const emptyData = isNothingToDisplay(variables);

  return (
    <Accordion expanded={localExpanded} onChange={localHandleChange} className={classes.root}>
      <AccordionSummary className={classes.summary} expandIcon={<ExpandMore />}>
        {title}
      </AccordionSummary>
      <AccordionDetails className={classes.details}>
        {emptyData && <div classNam={classes.details}>{Dictionary.noDataCollected}</div>}
        {!emptyData &&
          Object.entries(variables).map(([key, value]) => {
            if (value)
              return (
                <div className={classes.item}>
                  <div className={classes.itemKey}>{`${key}: `}</div>
                  <div>
                    <b>{`${value}`}</b>
                  </div>
                </div>
              );
            return null;
          })}

        {!currentPanel && !emptyData && (
          <div className={classes.action}>
            <Button className={classes.button} onClick={() => setPage(goToSeePage)}>
              {Dictionary.goSeeItButton}
            </Button>
          </div>
        )}
      </AccordionDetails>
    </Accordion>
  );
}
Example #9
Source File: SideAndTopNavBar.js    From medha-STPC with GNU Affero General Public License v3.0 4 votes vote down vote up
function SideAndTopNavBar(props) {
  const { container, className, ...rest } = props;
  const classes = useDrawerStyles();
  const topBarClasses = useTopBarStyles();
  const listClasses = useListStyles();

  const theme = useTheme();

  const [mobileOpen, setMobileOpen] = useState(false);
  const [subListState, setSubListState] = useState({});

  const { index, setIndex } = useContext(SetIndexContext);

  const handleDrawerToggle = () => {
    setMobileOpen(!mobileOpen);
  };

  const handleClick = name => {
    setSubListState({ ...subListState, [name]: !get(subListState, name) });
  };

  const authMenuItems = [
    {
      name: "Auth",
      Icon: <AccountCircleOutlinedIcon />,
      items: [
        {
          name: "Change Password",
          link: routeConstants.CHANGE_PASSWORD,
          Icon: <SwapHorizontalCircleOutlinedIcon />
        },
        {
          name: "Sign Out",
          link: routeConstants.LOGOUT_URL,
          Icon: <InputIcon />
        }
      ]
    }
  ];

  const inputs = get(
    MenuItems(),
    auth.getUserInfo() ? auth.getUserInfo()["role"]["name"] : "",
    []
  );

  const title = () => {
    const userInfo = auth.getUserInfo();
    return userInfo["first_name"]
      ? `${userInfo["first_name"]} ${userInfo["last_name"]}`
      : userInfo.username;
  };

  const role = () => {
    const userInfo = auth.getUserInfo();
    return userInfo["role"]["name"];
  };

  const drawer = (
    <div {...rest} className={clsx(classes.root, className)}>
      <div className={classes.toolbar} />
      {inputs.map((list, id) => {
        return (
          <div key={list.name} className={listClasses.navigationpanel}>
            {list.items != null ? (
              <List
                {...rest}
                className={clsx(
                  listClasses.root,
                  className,
                  listClasses.padding
                )}
              >
                <ListItem
                  className={listClasses.button}
                  disableGutters
                  key={list.name}
                  onClick={e => handleClick(list.name)}
                  selected={index === id}
                >
                  <ListItemIcon>{list.Icon}</ListItemIcon>
                  {list.name}
                  <div className={topBarClasses.flexGrow} />
                  <div className={listClasses.expandPadding}>
                    {get(subListState, list.name) ? (
                      <ExpandLess />
                    ) : (
                      <ExpandMore />
                    )}
                  </div>
                </ListItem>
                <Collapse
                  in={get(subListState, list.name)}
                  timeout="auto"
                  unmountOnExit
                >
                  <List component="div" disablePadding>
                    {list.items.map(subList => {
                      return (
                        <ListItem
                          className={(listClasses.item, listClasses.nested)}
                          disableGutters
                          key={subList.name}
                        >
                          <Button
                            activeClassName={listClasses.active}
                            className={listClasses.button}
                            component={CustomRouterLink}
                            to={subList.link}
                            onClick={() => setIndex(id)}
                          >
                            {subList.name}
                          </Button>
                        </ListItem>
                      );
                    })}
                  </List>
                </Collapse>
              </List>
            ) : (
              <List
                {...rest}
                className={clsx(
                  listClasses.root,
                  className,
                  listClasses.padding
                )}
              >
                <ListItem
                  className={listClasses.button}
                  disableGutters
                  key={list.name}
                  selected={index === id}
                  component={CustomRouterLink}
                  to={list.link}
                  onClick={() => setIndex(id)}
                >
                  <ListItemIcon>{list.Icon}</ListItemIcon>
                  {list.name}
                </ListItem>
              </List>
            )}
          </div>
        );
      })}
      <Hidden lgUp>
        <Divider className={classes.dividerStyle} />
        {authMenuItems.map(list => {
          return (
            <div key={list.name} className={listClasses.navigationpanel}>
              {list.items != null ? (
                <List
                  {...rest}
                  className={clsx(
                    listClasses.root,
                    className,
                    listClasses.padding
                  )}
                >
                  <ListItem
                    className={listClasses.button}
                    disableGutters
                    key={list.name}
                    onClick={e => handleClick(list.name)}
                  >
                    <ListItemIcon>{list.Icon}</ListItemIcon>
                    {list.name}
                    <div className={topBarClasses.flexGrow} />
                    <div className={listClasses.expandPadding}>
                      {get(subListState, list.name) ? (
                        <ExpandLess />
                      ) : (
                        <ExpandMore />
                      )}
                    </div>
                  </ListItem>
                  <Collapse
                    in={get(subListState, list.name)}
                    timeout="auto"
                    unmountOnExit
                  >
                    <List component="div" disablePadding>
                      {list.items.map(subList => {
                        return (
                          <ListItem
                            className={(listClasses.item, listClasses.nested)}
                            disableGutters
                            key={subList.name}
                          >
                            <Button
                              activeClassName={listClasses.active}
                              className={listClasses.button}
                              component={CustomRouterLink}
                              to={subList.link}
                            >
                              {subList.name}
                            </Button>
                          </ListItem>
                        );
                      })}
                    </List>
                  </Collapse>
                </List>
              ) : (
                ""
              )}
            </div>
          );
        })}
      </Hidden>
    </div>
  );

  return (
    <div className={topBarClasses.root}>
      <AppBar position="fixed" className={topBarClasses.root}>
        <Toolbar>
          <Logo />
          {auth.getToken() !== null ? (
            <div className={topBarClasses.loginButtonFlex}>
              <div className={topBarClasses.flexGrow} />
              <Hidden mdDown>
                <div className={topBarClasses.Iconroot}>
                  <AccountCircleOutlinedIcon />
                </div>
                <InputLabel>
                  {"Welcome "}
                  {title()}
                </InputLabel>
                <IconButton
                  className={topBarClasses.changePasswordButton}
                  color="inherit"
                  component={CustomRouterLink}
                  to={routeConstants.CHANGE_PASSWORD}
                >
                  <div className={topBarClasses.Iconroot}>
                    <SwapHorizontalCircleOutlinedIcon />
                  </div>
                  Change Password
                </IconButton>
                <IconButton
                  className={topBarClasses.signOutButton}
                  color="inherit"
                  component={CustomRouterLink}
                  to={routeConstants.LOGOUT_URL}
                >
                  <div className={topBarClasses.Iconroot}>
                    <InputIcon />
                  </div>
                  Sign out
                </IconButton>

                <Drawer
                  classes={{
                    paper: classes.drawer
                  }}
                  anchor="left"
                  variant="permanent"
                  open
                >
                  {auth.getUserInfo().role.name === "Student" ? (
                    <Box className={classes.mainDesktopBox}>
                      {auth.getUserInfo().studentInfo.profile_photo &&
                      auth.getUserInfo().studentInfo.profile_photo.url ? (
                        <Box className={classes.logoStudentBox}>
                          <Avatar
                            alt={title()}
                            src={
                              strapiApiConstants.STRAPI_DB_URL_WITHOUT_HASH +
                              auth.getUserInfo().studentInfo.profile_photo.url
                            }
                            className={classes.avatarLogo}
                          />
                        </Box>
                      ) : (
                        <Box className={classes.logoStudentBox}>
                          <Avatar
                            alt={title()}
                            src=""
                            className={classes.avatarLogo}
                          />
                        </Box>
                      )}

                      <Box className={classes.userContentBox}>
                        <Typography variant="h5" component="h5">
                          {title()}
                        </Typography>
                      </Box>
                    </Box>
                  ) : null}
                  {drawer}
                </Drawer>
              </Hidden>
              <Hidden lgUp>
                <IconButton color="inherit" onClick={handleDrawerToggle}>
                  <MenuIcon />
                </IconButton>
                <Drawer
                  container={container}
                  variant="temporary"
                  anchor={theme.direction === "rtl" ? "right" : "left"}
                  open={mobileOpen}
                  onClose={handleDrawerToggle}
                  classes={{
                    paper: classes.drawerPaper
                  }}
                  ModalProps={{
                    keepMounted: true // Better open performance on mobile.
                  }}
                >
                  {/* <Hidden lgUp> */}
                  <Box className={classes.mainBox}>
                    {auth.getUserInfo().role.name === "Student" &&
                    auth.getUserInfo().studentInfo.profile_photo &&
                    auth.getUserInfo().studentInfo.profile_photo.url ? (
                      <React.Fragment>
                        <Box className={classes.smallLogoBox}>
                          <SmallLogo />
                        </Box>
                        <Box className={classes.logoStudentBox}>
                          <Avatar
                            alt={title()}
                            src={
                              strapiApiConstants.STRAPI_DB_URL_WITHOUT_HASH +
                              auth.getUserInfo().studentInfo.profile_photo.url
                            }
                            className={classes.avatarLogo}
                          />
                        </Box>
                      </React.Fragment>
                    ) : auth.getUserInfo().role.name === "Student" ? (
                      <React.Fragment>
                        <Box className={classes.smallLogoBox}>
                          <SmallLogo />
                        </Box>
                        <Box className={classes.logoStudentBox}>
                          <Avatar
                            alt={title()}
                            src=""
                            className={classes.avatarLogo}
                          />
                        </Box>
                      </React.Fragment>
                    ) : (
                      <Box className={classes.logoBox}>
                        <LargeLogo />
                      </Box>
                    )}

                    <Box className={classes.userContentBox}>
                      <Typography variant="h5" component="h5">
                        {title()}
                      </Typography>
                      <Typography
                        variant="body2"
                        className={classes.body2Style}
                      >
                        {role()}
                      </Typography>
                    </Box>
                  </Box>
                  <Divider />
                  {/* </Hidden> */}

                  {drawer}
                </Drawer>
              </Hidden>
            </div>
          ) : (
            ""
          )}
        </Toolbar>
      </AppBar>
    </div>
  );
}
Example #10
Source File: EditQuiz.js    From Quizzie with MIT License 4 votes vote down vote up
function EditQuiz(props) {
	const quizId = props.match.params.id;

	const [loading, setLoading] = useState(true);
	const [redirect, setRedirect] = useState(false);

	const [quizDetails, setQuizDetails] = useState({});
	const [quizQuestions, setQuizQuestions] = useState([]);

	const [fileError, setFileError] = useState(false);
	const [serverError, setServerError] = useState(false);
	const [popoverAnchor, setPopoverAnchor] = useState(null);
	const popoverOpen = Boolean(popoverAnchor);

	const [questionModal, setQuestionModal] = useState(false);
	const [newQuestion, setNewQuestion] = useState("");
	const [newQuestionError, setNewQuestionError] = useState(false);

	const [option1, setOption1] = useState("");
	const [option1Error, setOption1Error] = useState(false);
	const [option2, setOption2] = useState("");
	const [option2Error, setOption2Error] = useState(false);
	const [option3, setOption3] = useState("");
	const [option3Error, setOption3Error] = useState(false);
	const [option4, setOption4] = useState("");
	const [option4Error, setOption4Error] = useState(false);
	const [correctOption, setCorrectOption] = useState(-1);
	const [correctOptionError, setCorrectOptionError] = useState(false);

	const [update, setUpdate] = useState(false);
	const [updateId, setUpdateId] = useState(null);

	const [deleteModal, setDeleteModal] = useState(false);
	const [deleteQuestionModal, setDeleteQuestionModal] = useState(false);

	const [quizRestartModal, setQuizRestartModal] = useState(false);
	const [closeQuizModal, setCloseQuizModal] = useState(false);

	const [responses, setResponses] = useState([]);

	const [searchData, setSearchData] = useState(responses);
	const [searchText, setSearchText] = useState("");
	const [sortBy, setSortBy] = useState(-1);

	const { executeRecaptcha } = useGoogleReCaptcha();

	const onCloseHandle = () => {
		setQuestionModal(false);
		if (update) {
			setUpdate(false);
			setUpdateId(null);
			clearModal();
		}
	};

	const handlePopover = (event) => {
		setPopoverAnchor(event.currentTarget);
	};

	const handlePopoverClose = () => {
		setPopoverAnchor(null);
	};

	const onQuestionChange = (event) => {
		setNewQuestion(event.target.value);
	};

	const handleOptionChange1 = (event) => {
		setOption1(event.target.value);
	};
	const handleOptionChange2 = (event) => {
		setOption2(event.target.value);
	};
	const handleOptionChange3 = (event) => {
		setOption3(event.target.value);
	};
	const handleOptionChange4 = (event) => {
		setOption4(event.target.value);
	};

	const handleCorrectOption = (event) => {
		setCorrectOption(event.target.value);
	};

	const clearModal = () => {
		setNewQuestion("");
		setNewQuestionError(false);
		setOption1("");
		setOption1Error(false);
		setOption2("");
		setOption2Error(false);
		setOption3("");
		setOption3Error(false);
		setOption4("");
		setOption4Error(false);
		setCorrectOption(-1);
		setCorrectOptionError(false);
	};

	const handleFileDrop = (files) => {
		const reader = new FileReader();

		let questions = [];

		reader.onabort = () => {
			setFileError(true);
			return;
		};
		reader.onerror = () => {
			setFileError(true);
			return;
		};

		reader.onload = () => {
			csv.parse(reader.result, (err, data) => {
				if (data === undefined) {
					setFileError(true);
					return;
				}
				data.map((question) => {
					if (question[0].trim() === "") {
						return null;
					}
					let obj = {
						quizId: quizId,
						description: question[0],
						options: [
							{ text: question[1] },
							{ text: question[2] },
							{ text: question[3] },
							{ text: question[4] },
						],
						correctAnswer: question[5],
					};

					questions.push(obj);
				});
				submitCSV(questions);
			});
		};

		reader.readAsBinaryString(files[0]);
	};

	const submitCSV = async (questions) => {
		setLoading(true);
		let token = localStorage.getItem("authToken");
		let url = "https://quizzie-api.herokuapp.com/question/csv";

		let captcha = await executeRecaptcha("submit_csv");

		let data = {
			questions: questions,
			captcha: captcha,
		};

		try {
			await axios
				.post(url, data, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					console.log(res);
					setLoading(false);
					clearModal();
					onCloseHandle();
					getQuizDetails();
				});
		} catch (error) {
			setServerError(true);
			console.log(error);
		}
	};

	const handleSearchChange = (event) => {
		setSearchText(event.target.value);

		let newRes = responses.filter(
			(response) =>
				response.userId.name
					.toLowerCase()
					.search(event.target.value.trim().toLowerCase()) !== -1 ||
				String(response.marks) ===
					event.target.value.trim().toLowerCase()
		);
		let sorted = sortByFunc(sortBy, newRes);

		setSearchData(sorted);
	};

	const handleSortChange = (event) => {
		setSortBy(event.target.value);

		let newRes = sortByFunc(event.target.value, searchData);

		setSearchData(newRes);
	};

	const sortByFunc = (by, array) => {
		if (by === "score") {
			return array.sort(function (a, b) {
				return b.marks - a.marks;
			});
		} else if (by === "name") {
			return array.sort(function (a, b) {
				return a.userId.name - b.userId.name;
			});
		} else if (by === "recent") {
			return array.sort(function (a, b) {
				return b.timeEnded - a.timeEnded;
			});
		} else {
			return array;
		}
	};

	const handleRestart = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/restart`;

		let captcha = await executeRecaptcha("restart_quiz");

		let data = {
			quizId: quizId,
			captcha: captcha,
		};

		try {
			await axios
				.patch(url, data, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setQuizRestartModal(false);
					getQuizDetails();
				});
		} catch (error) {
			console.log(error);
		}
	};

	const handleQuizClose = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/close`;

		let captcha = await executeRecaptcha("quiz_close");

		let data = {
			quizId: quizId,
			captcha: captcha,
		};

		try {
			await axios
				.patch(url, data, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setCloseQuizModal(false);
					getQuizDetails();
				});
		} catch (error) {
			console.log(error);
		}
	};

	const handleQuestionEditBtn = (question) => {
		setUpdate(true);
		setUpdateId(question._id);
		setNewQuestion(question.description);
		setOption1(question.options[0].text);
		setOption2(question.options[1].text);
		setOption3(question.options[2].text);
		setOption4(question.options[3].text);
		setCorrectOption(question.correctAnswer);
		setQuestionModal(true);
	};

	const handleQuestionDeleteBtn = (question) => {
		setUpdateId(question._id);
		setDeleteQuestionModal(true);
	};

	const handleQuestionModalClose = () => {
		setUpdateId(null);
		setDeleteQuestionModal(false);
	};

	const handleDeleteBtn = () => {
		setDeleteModal(true);
	};

	const handleDeleteQuestion = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/question/${updateId}`;

		// let captcha = executeRecaptcha("delete_quiz");

		try {
			await axios
				.delete(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setUpdateId(null);
					setDeleteQuestionModal(false);
					getQuizDetails();
				});
		} catch (error) {
			console.log(error);
		}
	};

	const handleDelete = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/delete`;

		let data = {
			quizId: quizId,
		};

		try {
			await axios
				.delete(url, {
					headers: {
						"auth-token": token,
					},
					data: data,
				})
				.then((res) => {
					setRedirect(true);
				});
		} catch (error) {
			console.log(error);
		}
	};

	const handleQuestionUpdate = async () => {
		if (!validate()) return;

		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/question/update/${updateId}`;

		let captcha = await executeRecaptcha("question_update");

		let updateOps = [
			{ propName: "description", value: newQuestion },
			{
				propName: "options",
				value: [
					{
						text: option1,
					},
					{
						text: option2,
					},
					{
						text: option3,
					},
					{
						text: option4,
					},
				],
			},
			{ propName: "correctAnswer", value: correctOption },
		];

		let data = {
			updateOps: updateOps,
			captcha: captcha,
		};

		try {
			await axios
				.patch(url, data, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					onCloseHandle();
					getQuizDetails();
				});
		} catch (error) {
			console.log(error);
		}
	};

	const validate = () => {
		if (newQuestion.trim().length === 0) {
			setNewQuestionError(true);
			return false;
		}

		if (option1.trim().length === 0) {
			setOption1Error(true);
			return false;
		}
		if (option2.trim().length === 0) {
			setOption2Error(true);
			return false;
		}
		if (option3.trim().length === 0) {
			setOption3Error(true);
			return false;
		}
		if (option4.trim().length === 0) {
			setOption4Error(true);
			return false;
		}

		if (correctOption === -1) {
			setCorrectOptionError(true);
			return false;
		}

		return true;
	};

	const handleQuestionSubmit = async () => {
		//TODO: Handle Validation

		if (!validate()) return;

		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/question/add`;

		let captcha = await executeRecaptcha("submit_question");

		let options = [
			{ text: option1 },
			{ text: option2 },
			{ text: option3 },
			{ text: option4 },
		];

		let data = {
			quizId: quizId,
			description: newQuestion,
			options: options,
			correctAnswer: correctOption,
			captcha: captcha,
		};

		try {
			await axios
				.post(url, data, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					clearModal();
					getQuizDetails();
					setQuestionModal(false);
				});
		} catch (error) {
			console.log(error);
		}
	};

	const isOwnerOfQuiz = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/checkAdmin/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					return true;
				});
		} catch (error) {
			setRedirect(true);
			return;
		}
	};

	const getQuizDetails = async () => {
		setLoading(true);
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setQuizDetails(res.data.result);
				});
		} catch (error) {
			console.log(error);
		}

		url = `https://quizzie-api.herokuapp.com/question/all/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setQuizQuestions(res.data.result);
				});
		} catch (error) {
			console.log(error);
		}

		url = `https://quizzie-api.herokuapp.com/admin/allStudentsQuizResult/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setResponses(res.data.userResults);
					setSearchData(res.data.userResults);
					setLoading(false);
				});
		} catch (error) {
			console.log(error);
		}
	};

	useEffect(() => {
		let token = localStorage.getItem("authToken");
		if (token === null) {
			setLoading(false);
			setRedirect(true);
			return;
		}

		isOwnerOfQuiz();
		getQuizDetails();
	}, []);

	if (loading) {
		return <Loading />;
	} else if (redirect) {
		return <Redirect to="/dashboard" />;
	} else {
		return (
			<Container className="edit-quiz-page">
				<Typography
					variant="h3"
					className="dash-head p-top edit-quiz-head"
				>
					Edit Quiz
				</Typography>
				<div className="edit-btn-bar">
					<Button
						className="edit-details-btn"
						component={Link}
						to={`/updateQuizDetails/${quizId}`}
					>
						<Create className="edit-icon" />
						Edit Details
					</Button>
					<Button
						className="edit-details-btn delete-btn"
						onClick={handleDeleteBtn}
					>
						<Delete className="edit-icon" />
						Delete Quiz
					</Button>
					{quizDetails.quizStatus === 1 ? (
						<Button
							className="edit-details-btn"
							style={{ marginLeft: "3%" }}
							onClick={() => setCloseQuizModal(true)}
						>
							<Replay className="edit-quiz" />
							Close Quiz
						</Button>
					) : quizDetails.quizStatus === 2 ? (
						<Button
							className="edit-details-btn"
							style={{ marginLeft: "3%" }}
							onClick={() => setQuizRestartModal(true)}
						>
							<Replay className="edit-quiz" />
							Restart Quiz
						</Button>
					) : null}
				</div>
				<div className="quiz-details-sec">
					<Typography variant="h6" className="quiz-detail-param">
						Name:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizName}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Date:{" "}
						<span className="quiz-detail-text">
							{new Date(
								Number(quizDetails.scheduledFor)
							).toDateString()}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Time:{" "}
						<span className="quiz-detail-text">
							{new Date(
								Number(quizDetails.scheduledFor)
							).toLocaleTimeString()}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Duration:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizDuration} minutes
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Type:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizType}
						</span>
					</Typography>
					{quizDetails.quizType === "private" ? (
						<Typography variant="h6" className="quiz-detail-param">
							Quiz Code:{" "}
							<span className="quiz-detail-text">
								{quizDetails.quizCode}
							</span>
						</Typography>
					) : null}
				</div>
				<div className="quiz-questions-sec">
					<Typography variant="h4" className="quiz-questions-head">
						Questions
					</Typography>
					<div className="quiz-questions-display">
						<div className="add-question-bar">
							<Button
								className="add-question-btn"
								onClick={() => setQuestionModal(true)}
							>
								Add a question
							</Button>
						</div>
						{quizQuestions.length === 0 ? (
							<p style={{ textAlign: "center" }}>
								No questions added yet!
							</p>
						) : (
							<div className="questions-list-display">
								{quizQuestions.map((question) => (
									<ExpansionPanel
										elevation={3}
										className="expansion"
										key={question._id}
									>
										<ExpansionPanelSummary
											className="question-summary"
											expandIcon={<ExpandMore />}
											aria-controls="question-content"
											aria-label="Expand"
										>
											<FormControlLabel
												style={{ marginRight: "0" }}
												aria-label="Edit"
												control={
													<IconButton>
														<Create />
													</IconButton>
												}
												// label={question.description}
												onClick={() =>
													handleQuestionEditBtn(
														question
													)
												}
											/>
											<FormControlLabel
												aria-label="Edit"
												control={
													<IconButton>
														<Delete />
													</IconButton>
												}
												// label={question.description}
												onClick={() =>
													handleQuestionDeleteBtn(
														question
													)
												}
											/>
											<Typography className="question-label">
												{question.description}
											</Typography>
										</ExpansionPanelSummary>
										<ExpansionPanelDetails>
											<List
												component="nav"
												className="options-display"
											>
												{question.options.map(
													(option) => (
														<ListItem
															button
															key={option._id}
														>
															<ListItemIcon>
																<Adjust
																	style={{
																		color:
																			question.correctAnswer ===
																			option.text
																				? "green"
																				: "black",
																	}}
																/>
															</ListItemIcon>
															<ListItemText
																style={{
																	color:
																		question.correctAnswer ===
																		option.text
																			? "green"
																			: "black",
																}}
																primary={
																	option.text
																}
															/>
														</ListItem>
													)
												)}
											</List>
										</ExpansionPanelDetails>
									</ExpansionPanel>
								))}
							</div>
						)}
					</div>
					<Typography
						variant="h4"
						className="quiz-questions-head m-top"
					>
						Submissions
					</Typography>
					<div className="quiz-students-list">
						<div className="add-question-bar">
							<Button
								className="add-question-btn stats-btn"
								component={
									responses.length !== 0 ? Link : Button
								}
								to={{
									pathname: "/quizStats",
									state: { responses: responses },
								}}
							>
								<BarChart />
								View Stats
							</Button>
						</div>
						{responses.length === 0 ? (
							<p
								style={{
									textAlign: "center",
									margin: "0",
									paddingTop: "3%",
									paddingBottom: "3%",
								}}
							>
								No responses yet!
							</p>
						) : (
							<>
								<div className="search-bar">
									<TextField
										placeholder="Search by name or score"
										type="text"
										onChange={handleSearchChange}
										className="search-input"
										value={searchText}
									/>
									<div style={{ marginLeft: "3%" }}>
										<InputLabel id="sort-by">
											Sort by
										</InputLabel>
										<Select
											labelId="sort-by"
											id="sort-select"
											value={sortBy}
											onChange={handleSortChange}
										>
											<MenuItem value={-1}>
												<em>None</em>
											</MenuItem>
											<MenuItem value="recent">
												Recent
											</MenuItem>
											<MenuItem value="score">
												Score
											</MenuItem>
											<MenuItem value="name">
												Name
											</MenuItem>
										</Select>
									</div>
								</div>
								<List aria-label="responses list">
									{searchData.map((response) => (
										<ListItem
											button
											key={response._id}
											component={Link}
											to={{
												pathname: `/studentResponse`,
												state: { response: response },
											}}
										>
											<ListItemText
												primary={response.userId.name}
												secondary={`Scored: ${response.marks}`}
											/>
										</ListItem>
									))}
								</List>
							</>
						)}
					</div>
				</div>
				<Dialog
					open={questionModal}
					onClose={onCloseHandle}
					aria-labelledby="add-question-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "#333",
							minWidth: "50%",
						},
					}}
					style={{ width: "100%" }}
				>
					<div className="add-ques-heading">
						<Typography
							variant="h6"
							style={{ textAlign: "center", margin: "2% 5%" }}
						>
							New Question{" "}
						</Typography>
						{!update ? (
							<IconButton onClick={handlePopover}>
								<Info className="add-info-icon" />
							</IconButton>
						) : null}
						<Popover
							id="file-upload-popover"
							open={popoverOpen}
							anchorEl={popoverAnchor}
							onClose={handlePopoverClose}
							anchorOrigin={{
								vertical: "bottom",
								horizontal: "left",
							}}
							disableRestoreFocus
							useLayerForClickAway={false}
							PaperProps={{ style: { maxWidth: "400px" } }}
						>
							<p className="popover-text">
								You can upload a <strong>.csv</strong> file with
								questions. The format should be: the{" "}
								<strong>
									first column should contain the question
									text.
								</strong>{" "}
								The next 4 columns must contain the{" "}
								<strong>four options.</strong> And the sixth
								column should contain{" "}
								<strong>
									the correct answer (it should match one of
									the four options)
								</strong>
								. <br />
								<br />
								<strong>
									NOTE: THE FILE SHOULD EXACTLY MATCH THE
									GIVEN FORMAT.
								</strong>{" "}
								You will be able to see and edit all the
								question though.
							</p>
						</Popover>
					</div>
					{!update ? (
						<>
							<div className="dropzone">
								<Dropzone
									onDrop={(acceptedFiles) =>
										handleFileDrop(acceptedFiles)
									}
								>
									{({ getRootProps, getInputProps }) => (
										<section>
											<div {...getRootProps()}>
												<input {...getInputProps()} />
												<AddCircle className="drop-icon" />
												<p
													style={{
														color:
															"rgb(110, 110, 110)",
													}}
												>
													Drag 'n' drop or click to
													select files
												</p>
											</div>
										</section>
									)}
								</Dropzone>
							</div>
							<p className="manual-head">
								<span>Or manually add the question</span>
							</p>
						</>
					) : null}
					<div className="new-question-form">
						<TextInput
							error={newQuestionError}
							helperText={
								newQuestionError ? "This cannot be empty" : null
							}
							className="new-ques-input"
							variant="outlined"
							label="Question Text"
							value={newQuestion}
							onChange={onQuestionChange}
						/>
						<hr style={{ width: "100%", marginBottom: "3%" }} />
						<Grid container spacing={1}>
							<Grid item xs={12} sm={6}>
								<TextInput
									error={option1Error}
									helperText={
										option1Error
											? "This cannot be empty"
											: null
									}
									className="new-ques-input"
									variant="outlined"
									label="Option 1"
									value={option1}
									onChange={handleOptionChange1}
								/>
							</Grid>
							<Grid item xs={12} sm={6}>
								<TextInput
									error={option2Error}
									helperText={
										option2Error
											? "This cannot be empty"
											: null
									}
									className="new-ques-input"
									variant="outlined"
									label="Option 2"
									value={option2}
									onChange={handleOptionChange2}
								/>
							</Grid>
						</Grid>
						<Grid container spacing={1}>
							<Grid item xs={12} sm={6}>
								<TextInput
									error={option3Error}
									helperText={
										option3Error
											? "This cannot be empty"
											: null
									}
									className="new-ques-input"
									variant="outlined"
									label="Option 3"
									value={option3}
									onChange={handleOptionChange3}
								/>
							</Grid>
							<Grid item xs={12} sm={6}>
								<TextInput
									error={option4Error}
									helperText={
										option4Error
											? "This cannot be empty"
											: null
									}
									className="new-ques-input"
									variant="outlined"
									label="Option 4"
									value={option4}
									onChange={handleOptionChange4}
								/>
							</Grid>
						</Grid>
						<hr style={{ width: "100%", marginBottom: "3%" }} />
						<InputLabel id="correct-option">
							Correct Option
						</InputLabel>
						<Select
							error={correctOptionError}
							className="correct-answer-select"
							style={{ width: "50%" }}
							labelId="correct-option"
							value={correctOption}
							onChange={handleCorrectOption}
						>
							<MenuItem value={-1}>None</MenuItem>
							{option1.trim().length !== 0 ? (
								<MenuItem value={option1}>{option1}</MenuItem>
							) : null}
							{option2.trim().length !== 0 ? (
								<MenuItem value={option2}>{option2}</MenuItem>
							) : null}
							{option3.trim().length !== 0 ? (
								<MenuItem value={option3}>{option3}</MenuItem>
							) : null}
							{option4.trim().length !== 0 ? (
								<MenuItem value={option4}>{option4}</MenuItem>
							) : null}
						</Select>
						{!update ? (
							<Button
								className="add-question-submit"
								onClick={handleQuestionSubmit}
							>
								Add Question
							</Button>
						) : (
							<Button
								className="add-question-submit"
								onClick={handleQuestionUpdate}
							>
								Update Question
							</Button>
						)}
					</div>
				</Dialog>
				<Dialog
					open={deleteModal}
					onClose={() => setDeleteModal(false)}
					aria-labelledby="delete-quiz-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "black",
							minWidth: "10%",
						},
					}}
				>
					<DialogTitle>
						Are you sure you want to delete this quiz?
					</DialogTitle>
					<div className="btn-div">
						<Button
							className="logout-btn m-right bg-red-btn"
							onClick={handleDelete}
						>
							Yes
						</Button>
						<Button
							className="cancel-btn m-left"
							onClick={() => setDeleteModal(false)}
						>
							No
						</Button>
					</div>
				</Dialog>
				<Dialog
					open={deleteQuestionModal}
					onClose={handleQuestionModalClose}
					aria-labelledby="delete-quiz-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "black",
							minWidth: "10%",
						},
					}}
				>
					<DialogTitle>
						Are you sure you want to delete this question?
					</DialogTitle>
					<div className="btn-div">
						<Button
							className="logout-btn m-right bg-red-btn"
							onClick={handleDeleteQuestion}
						>
							Yes
						</Button>
						<Button
							className="cancel-btn m-left"
							onClick={handleQuestionModalClose}
						>
							No
						</Button>
					</div>
				</Dialog>
				<Dialog
					open={quizRestartModal}
					onClose={() => setQuizRestartModal(false)}
					aria-labelledby="restart-quiz-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "black",
							minWidth: "10%",
						},
					}}
				>
					<DialogTitle>
						Are you sure you want to restart this quiz?
					</DialogTitle>
					<div className="btn-div">
						<Button
							className="logout-btn m-right bg-green-btn"
							onClick={handleRestart}
						>
							Yes
						</Button>
						<Button
							className="cancel-btn m-left bg-red-btn"
							onClick={() => setQuizRestartModal(false)}
						>
							No
						</Button>
					</div>
				</Dialog>
				<Dialog
					open={closeQuizModal}
					onClose={() => setCloseQuizModal(false)}
					aria-labelledby="restart-quiz-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "black",
							minWidth: "10%",
						},
					}}
				>
					<DialogTitle>
						Are you sure you want to close this quiz?
					</DialogTitle>
					<div className="btn-div">
						<Button
							className="logout-btn m-right bg-green-btn"
							onClick={handleQuizClose}
						>
							Yes
						</Button>
						<Button
							className="cancel-btn m-left bg-red-btn"
							onClick={() => setCloseQuizModal(false)}
						>
							No
						</Button>
					</div>
				</Dialog>
				<Snackbar
					open={fileError}
					autoHideDuration={3000}
					onClose={() => setFileError(false)}
					anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
				>
					<Alert
						variant="filled"
						severity="error"
						onClose={() => setFileError(false)}
					>
						There was some problem with the file. Try again...
					</Alert>
				</Snackbar>
				<Snackbar
					open={serverError}
					autoHideDuration={3000}
					onClose={() => setServerError(false)}
					anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
				>
					<Alert
						variant="filled"
						severity="error"
						onClose={() => setServerError(false)}
					>
						There was some problem with the server. Try again...
					</Alert>
				</Snackbar>
			</Container>
		);
	}
}
Example #11
Source File: Sidebar.jsx    From Edlib with GNU General Public License v3.0 4 votes vote down vote up
Sidebar = () => {
    const classes = useStyles();
    const history = useHistory();
    const location = useLocation();
    const [currentlyExpandedName, setCurrentlyExpandedName] =
        React.useState(null);

    React.useEffect(() => {
        setCurrentlyExpandedName(null);
    }, [location]);

    const links = [
        { name: 'Dashboard', to: '/dashboard', icon: <Dashboard /> },
        { name: 'Content Author', to: '/content-author', icon: <Settings /> },
        {
            name: 'Settings',
            to: '/settings',
            icon: <Settings />,
            subLinks: [
                {
                    name: 'External applications',
                    to: '/external-applications',
                },
            ],
        },
        {
            name: 'Monitoring',
            to: '/monitoring',
            icon: <LocalOffer />,
            subLinks: [{ name: 'Status of services', to: '/system-status' }],
        },
        {
            name: 'Jobs',
            to: '/jobs',
            icon: <LocalOffer />,
            subLinks: [
                { name: 'Resources', to: '/resources' },
                { name: 'Auth migration', to: '/auth-migration' },
            ],
        },
        {
            name: 'Analytics',
            to: '/analytics',
            icon: <Assessment />,
            subLinks: [{ name: 'Dashboard', to: '/dashboard' }],
        },
    ];

    return (
        <List dense>
            {links.map(({ name, icon, to, subLinks }) => {
                const isInPath = !!matchPath(location.pathname, {
                    path: to,
                    strict: false,
                });

                const isExpanded = isInPath || currentlyExpandedName === name;

                if (subLinks) {
                    return (
                        <React.Fragment key={name}>
                            <ListItem
                                button
                                selected={isInPath}
                                onClick={() => {
                                    setCurrentlyExpandedName(
                                        currentlyExpandedName === name
                                            ? null
                                            : name
                                    );
                                }}
                            >
                                {icon && <ListItemIcon>{icon}</ListItemIcon>}
                                <ListItemText
                                    primary={name}
                                    primaryTypographyProps={{
                                        className: classes.parentItem,
                                    }}
                                    inset={!icon}
                                />
                                {isExpanded ? <ExpandLess /> : <ExpandMore />}
                            </ListItem>
                            <Collapse
                                in={isExpanded}
                                timeout="auto"
                                unmountOnExit
                            >
                                <List component="div" disablePadding dense>
                                    {subLinks.map((subLink) => {
                                        const subTo = to + subLink.to;
                                        const isInSubPath = !!matchPath(
                                            location.pathname,
                                            {
                                                path: subTo,
                                                strict: false,
                                            }
                                        );

                                        return (
                                            <ListItem
                                                key={subLink.name}
                                                button
                                                onClick={() =>
                                                    history.push(subTo)
                                                }
                                                selected={isInSubPath}
                                            >
                                                <ListItemText
                                                    primary={subLink.name}
                                                    inset
                                                />
                                            </ListItem>
                                        );
                                    })}
                                </List>
                            </Collapse>
                        </React.Fragment>
                    );
                }

                return (
                    <ListItem
                        key={name}
                        button
                        selected={isInPath}
                        onClick={() => history.push(to)}
                    >
                        {icon && <ListItemIcon>{icon}</ListItemIcon>}
                        <ListItemText
                            primary={name}
                            primaryTypographyProps={{
                                className: classes.parentItem,
                            }}
                            inset={!icon}
                        />
                    </ListItem>
                );
            })}
        </List>
    );
}
Example #12
Source File: index.js    From whaticket with MIT License 4 votes vote down vote up
MessagesList = ({ ticketId, isGroup }) => {
  const classes = useStyles();

  const [messagesList, dispatch] = useReducer(reducer, []);
  const [pageNumber, setPageNumber] = useState(1);
  const [hasMore, setHasMore] = useState(false);
  const [loading, setLoading] = useState(false);
  const lastMessageRef = useRef();

  const [selectedMessage, setSelectedMessage] = useState({});
  const [anchorEl, setAnchorEl] = useState(null);
  const messageOptionsMenuOpen = Boolean(anchorEl);
  const currentTicketId = useRef(ticketId);

  useEffect(() => {
    dispatch({ type: "RESET" });
    setPageNumber(1);

    currentTicketId.current = ticketId;
  }, [ticketId]);

  useEffect(() => {
    setLoading(true);
    const delayDebounceFn = setTimeout(() => {
      const fetchMessages = async () => {
        try {
          const { data } = await api.get("/messages/" + ticketId, {
            params: { pageNumber },
          });

          if (currentTicketId.current === ticketId) {
            dispatch({ type: "LOAD_MESSAGES", payload: data.messages });
            setHasMore(data.hasMore);
            setLoading(false);
          }

          if (pageNumber === 1 && data.messages.length > 1) {
            scrollToBottom();
          }
        } catch (err) {
          setLoading(false);
          toastError(err);
        }
      };
      fetchMessages();
    }, 500);
    return () => {
      clearTimeout(delayDebounceFn);
    };
  }, [pageNumber, ticketId]);

  useEffect(() => {
    const socket = openSocket();

    socket.on("connect", () => socket.emit("joinChatBox", ticketId));

    socket.on("appMessage", (data) => {
      if (data.action === "create") {
        dispatch({ type: "ADD_MESSAGE", payload: data.message });
        scrollToBottom();
      }

      if (data.action === "update") {
        dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
      }
    });

    return () => {
      socket.disconnect();
    };
  }, [ticketId]);

  const loadMore = () => {
    setPageNumber((prevPageNumber) => prevPageNumber + 1);
  };

  const scrollToBottom = () => {
    if (lastMessageRef.current) {
      lastMessageRef.current.scrollIntoView({});
    }
  };

  const handleScroll = (e) => {
    if (!hasMore) return;
    const { scrollTop } = e.currentTarget;

    if (scrollTop === 0) {
      document.getElementById("messagesList").scrollTop = 1;
    }

    if (loading) {
      return;
    }

    if (scrollTop < 50) {
      loadMore();
    }
  };

  const handleOpenMessageOptionsMenu = (e, message) => {
    setAnchorEl(e.currentTarget);
    setSelectedMessage(message);
  };

  const handleCloseMessageOptionsMenu = (e) => {
    setAnchorEl(null);
  };

  const checkMessageMedia = (message) => {
	if(message.mediaType === "location" && message.body.split('|').length >= 2) {
		let locationParts = message.body.split('|')
		let imageLocation = locationParts[0]		
		let linkLocation = locationParts[1]
		
		let descriptionLocation = null
		
		if(locationParts.length > 2)
			descriptionLocation = message.body.split('|')[2]
		
		return <LocationPreview image={imageLocation} link={linkLocation} description={descriptionLocation} />
	}
	else if (message.mediaType === "vcard") {
		//console.log("vcard")
		//console.log(message)
		let array = message.body.split("\n");
		let obj = [];
		let contact = "";
		for (let index = 0; index < array.length; index++) {
			const v = array[index];
			let values = v.split(":");
			for (let ind = 0; ind < values.length; ind++) {
				if (values[ind].indexOf("+") !== -1) {
					obj.push({ number: values[ind] });
				}
				if (values[ind].indexOf("FN") !== -1) {
					contact = values[ind + 1];
				}
			}
		}
		return <VcardPreview contact={contact} numbers={obj[0].number} />
	} 
  /*else if (message.mediaType === "multi_vcard") {
		console.log("multi_vcard")
		console.log(message)
		
		if(message.body !== null && message.body !== "") {
			let newBody = JSON.parse(message.body)
			return (
				<>
				  {
					newBody.map(v => (
					  <VcardPreview contact={v.name} numbers={v.number} />
					))
				  }
				</>
			)
		} else return (<></>)
	}*/
  else if (message.mediaType === "image") {
      return <ModalImageCors imageUrl={message.mediaUrl} />;
    } else if (message.mediaType === "audio") {
      return (
        <audio controls>
          <source src={message.mediaUrl} type="audio/ogg"></source>
        </audio>
      );
    } else if (message.mediaType === "video") {
      return (
        <video
          className={classes.messageMedia}
          src={message.mediaUrl}
          controls
        />
      );
    } else {
      return (
        <>
          <div className={classes.downloadMedia}>
            <Button
              startIcon={<GetApp />}
              color="primary"
              variant="outlined"
              target="_blank"
              href={message.mediaUrl}
            >
              Download
            </Button>
          </div>
          <Divider />
        </>
      );
    }
  };

  const renderMessageAck = (message) => {
    if (message.ack === 0) {
      return <AccessTime fontSize="small" className={classes.ackIcons} />;
    }
    if (message.ack === 1) {
      return <Done fontSize="small" className={classes.ackIcons} />;
    }
    if (message.ack === 2) {
      return <DoneAll fontSize="small" className={classes.ackIcons} />;
    }
    if (message.ack === 3 || message.ack === 4) {
      return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />;
    }
  };

  const renderDailyTimestamps = (message, index) => {
    if (index === 0) {
      return (
        <span
          className={classes.dailyTimestamp}
          key={`timestamp-${message.id}`}
        >
          <div className={classes.dailyTimestampText}>
            {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
          </div>
        </span>
      );
    }
    if (index < messagesList.length - 1) {
      let messageDay = parseISO(messagesList[index].createdAt);
      let previousMessageDay = parseISO(messagesList[index - 1].createdAt);

      if (!isSameDay(messageDay, previousMessageDay)) {
        return (
          <span
            className={classes.dailyTimestamp}
            key={`timestamp-${message.id}`}
          >
            <div className={classes.dailyTimestampText}>
              {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
            </div>
          </span>
        );
      }
    }
    if (index === messagesList.length - 1) {
      return (
        <div
          key={`ref-${message.createdAt}`}
          ref={lastMessageRef}
          style={{ float: "left", clear: "both" }}
        />
      );
    }
  };

  const renderMessageDivider = (message, index) => {
    if (index < messagesList.length && index > 0) {
      let messageUser = messagesList[index].fromMe;
      let previousMessageUser = messagesList[index - 1].fromMe;

      if (messageUser !== previousMessageUser) {
        return (
          <span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span>
        );
      }
    }
  };

  const renderQuotedMessage = (message) => {
    return (
      <div
        className={clsx(classes.quotedContainerLeft, {
          [classes.quotedContainerRight]: message.fromMe,
        })}
      >
        <span
          className={clsx(classes.quotedSideColorLeft, {
            [classes.quotedSideColorRight]: message.quotedMsg?.fromMe,
          })}
        ></span>
        <div className={classes.quotedMsg}>
          {!message.quotedMsg?.fromMe && (
            <span className={classes.messageContactName}>
              {message.quotedMsg?.contact?.name}
            </span>
          )}
          {message.quotedMsg?.body}
        </div>
      </div>
    );
  };

  const renderMessages = () => {
    if (messagesList.length > 0) {
      const viewMessagesList = messagesList.map((message, index) => {
        if (!message.fromMe) {
          return (
            <React.Fragment key={message.id}>
              {renderDailyTimestamps(message, index)}
              {renderMessageDivider(message, index)}
              <div className={classes.messageLeft}>
                <IconButton
                  variant="contained"
                  size="small"
                  id="messageActionsButton"
                  disabled={message.isDeleted}
                  className={classes.messageActionsButton}
                  onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
                >
                  <ExpandMore />
                </IconButton>
                {isGroup && (
                  <span className={classes.messageContactName}>
                    {message.contact?.name}
                  </span>
                )}
                {(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard" 
                //|| message.mediaType === "multi_vcard" 
                ) && checkMessageMedia(message)}
                <div className={classes.textContentItem}>
                  {message.quotedMsg && renderQuotedMessage(message)}
                  <MarkdownWrapper>{message.body}</MarkdownWrapper>
                  <span className={classes.timestamp}>
                    {format(parseISO(message.createdAt), "HH:mm")}
                  </span>
                </div>
              </div>
            </React.Fragment>
          );
        } else {
          return (
            <React.Fragment key={message.id}>
              {renderDailyTimestamps(message, index)}
              {renderMessageDivider(message, index)}
              <div className={classes.messageRight}>
                <IconButton
                  variant="contained"
                  size="small"
                  id="messageActionsButton"
                  disabled={message.isDeleted}
                  className={classes.messageActionsButton}
                  onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
                >
                  <ExpandMore />
                </IconButton>
                {(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard" 
                //|| message.mediaType === "multi_vcard" 
                ) && checkMessageMedia(message)}
                <div
                  className={clsx(classes.textContentItem, {
                    [classes.textContentItemDeleted]: message.isDeleted,
                  })}
                >
                  {message.isDeleted && (
                    <Block
                      color="disabled"
                      fontSize="small"
                      className={classes.deletedIcon}
                    />
                  )}
                  {message.quotedMsg && renderQuotedMessage(message)}
                  <MarkdownWrapper>{message.body}</MarkdownWrapper>
                  <span className={classes.timestamp}>
                    {format(parseISO(message.createdAt), "HH:mm")}
                    {renderMessageAck(message)}
                  </span>
                </div>
              </div>
            </React.Fragment>
          );
        }
      });
      return viewMessagesList;
    } else {
      return <div>Say hello to your new contact!</div>;
    }
  };

  return (
    <div className={classes.messagesListWrapper}>
      <MessageOptionsMenu
        message={selectedMessage}
        anchorEl={anchorEl}
        menuOpen={messageOptionsMenuOpen}
        handleClose={handleCloseMessageOptionsMenu}
      />
      <div
        id="messagesList"
        className={classes.messagesList}
        onScroll={handleScroll}
      >
        {messagesList.length > 0 ? renderMessages() : []}
      </div>
      {loading && (
        <div>
          <CircularProgress className={classes.circleLoading} />
        </div>
      )}
    </div>
  );
}
Example #13
Source File: index.js    From Artion-Client with GNU General Public License v3.0 4 votes vote down vote up
Header = ({ border }) => {
  const history = useHistory();
  const dispatch = useDispatch();

  const {
    apiUrl,
    storageUrl,
    getAuthToken,
    getAccountDetails,
    getIsModerator,
  } = useApi();
  const { account, chainId, deactivate } = useWeb3React();

  const { user } = useSelector(state => state.Auth);
  let isSearchbarShown = useSelector(state => state.HeaderOptions.isShown);
  const { isModerator } = useSelector(state => state.ConnectWallet);
  const { wftmModalVisible, connectWalletModalVisible } = useSelector(
    state => state.Modal
  );

  const [anchorEl, setAnchorEl] = useState(null);
  const [loading, setLoading] = useState(false);
  const [searchBarActive, setSearchBarActive] = useState(false);
  const [isAdding, setIsAdding] = useState(false);
  const [modModalVisible, setModModalVisible] = useState(false);
  const [isBan, setIsBan] = useState(false);
  const [banCollectionModalVisible, setBanCollectionModalVisible] = useState(
    false
  );
  const [banItemModalVisible, setBanItemModalVisible] = useState(false);
  const [banUserModalVisible, setBanUserModalVisible] = useState(false);
  const [unbanUserModalVisible, setUnbanUserModalVisible] = useState(false);
  const [
    boostCollectionModalVisible,
    setBoostCollectionModalVisible,
  ] = useState(false);

  const [keyword, setKeyword] = useState('');
  const [cancelSource, setCancelSource] = useState(null);
  const [accounts, setAccounts] = useState([]);
  const [collections, setCollections] = useState([]);
  const [tokens, setTokens] = useState([]);
  const [bundles, setBundles] = useState([]);
  const [tokenDetailsLoading, setTokenDetailsLoading] = useState(false);
  const timer = useRef(null);

  const isMenuOpen = Boolean(anchorEl);

  const login = async () => {
    try {
      setLoading(true);
      const token = await getAuthToken(account);
      const isModerator = await getIsModerator(account);

      dispatch(WalletConnectActions.connectWallet(token, isModerator));
      dispatch(AuthActions.fetchStart());
      try {
        const { data } = await getAccountDetails(token);
        dispatch(AuthActions.fetchSuccess(data));
      } catch {
        dispatch(AuthActions.fetchFailed());
      }
      setLoading(false);
    } catch {
      setLoading(false);
    }
  };

  const init = () => {
    login();
  };

  useEffect(() => {
    if (account) {
      init();
    } else {
      handleSignOut();
    }
  }, [account, chainId]);

  const handleConnectWallet = () => {
    dispatch(ModalActions.showConnectWalletModal());
  };

  const resetResults = () => {
    setAccounts([]);
    setCollections([]);
    setTokens([]);
    setBundles([]);
  };

  useEffect(() => {
    resetResults();
  }, [isSearchbarShown]);

  const search = async word => {
    setKeyword(word);

    if (cancelSource) {
      cancelSource.cancel();
    }

    if (word.length === 0) {
      resetResults();

      return;
    }

    try {
      const cancelTokenSource = axios.CancelToken.source();
      setCancelSource(cancelTokenSource);

      const {
        data: {
          data: { accounts, collections, tokens, bundles },
        },
      } = await axios({
        method: 'post',
        url: `${apiUrl}/info/searchNames`,
        data: JSON.stringify({ name: word }),
        headers: {
          'Content-Type': 'application/json',
        },
        cancelToken: cancelTokenSource.token,
      });

      Promise.all(
        tokens.map(async token => {
          if (token.imageURL) {
            token.imageURL = getRandomIPFS(token.imageURL);
          }

          if (token.imageURL === '-') {
            const {
              data: { image },
            } = await axios.get(token.tokenURI);

            if (image) {
              // eslint-disable-next-line require-atomic-updates
              token.imageURL = getRandomIPFS(token.imageURL);
            }
          }
        })
      );

      setAccounts(accounts);
      setCollections(collections);
      setTokenDetailsLoading(true);
      setTokens(tokens);
      setBundles(bundles);
      setTokenDetailsLoading(false);
    } catch (err) {
      console.log(err);
    } finally {
      setCancelSource(null);
    }
  };

  const handleSelectCollection = addr => {
    dispatch(FilterActions.updateCollectionsFilter([addr]));
  };

  const handleSearch = word => {
    if (timer.current) {
      clearTimeout(timer.current);
    }

    timer.current = setTimeout(() => search(word), 500);
  };

  const handleSignOut = () => {
    deactivate();
    dispatch(WalletConnectActions.disconnectWallet());
    dispatch(AuthActions.signOut());
    handleMenuClose();
  };

  const handleProfileMenuOpen = e => {
    setAnchorEl(e.currentTarget);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
  };

  const goToMyProfile = () => {
    history.push(`/account/${account}`);
    handleMenuClose();
  };

  const goToNotificationSettings = () => {
    history.push(`/settings/notification`);
    handleMenuClose();
  };

  // const handleCreateCollection = () => {
  //   history.push('/collection/create');
  //   handleMenuClose();
  // };

  const handleRegisterCollection = () => {
    history.push('/collection/register');
    handleMenuClose();
  };

  const openWrapStation = () => {
    dispatch(ModalActions.showWFTMModal());
    handleMenuClose();
  };

  const addMod = () => {
    setIsAdding(true);
    setModModalVisible(true);
    handleMenuClose();
  };

  const removeMod = () => {
    setIsAdding(false);
    setModModalVisible(true);
    handleMenuClose();
  };

  const reviewCollections = () => {
    history.push('/collection/review');
    handleMenuClose();
  };

  const banCollection = () => {
    setIsBan(true);
    setBanCollectionModalVisible(true);
    handleMenuClose();
  };

  const unbanCollection = () => {
    setIsBan(false);
    setBanCollectionModalVisible(true);
    handleMenuClose();
  };

  const banItems = () => {
    setBanItemModalVisible(true);
    handleMenuClose();
  };

  const banUser = () => {
    setBanUserModalVisible(true);
    handleMenuClose();
  };

  const unbanUser = () => {
    setUnbanUserModalVisible(true);
    handleMenuClose();
  };

  const boostCollection = () => {
    setBoostCollectionModalVisible(true);
    handleMenuClose();
  };

  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMenuOpen}
      onClose={handleMenuClose}
      classes={{
        paper: styles.profilemenu,
        list: styles.menuList,
      }}
    >
      {account && (
        <div
          className={cx(styles.menuItem, styles.topItem)}
          onClick={goToMyProfile}
        >
          <img src={iconUser} className={styles.menuIcon} />
          My Profile
        </div>
      )}
      <div className={styles.menuItem} onClick={goToNotificationSettings}>
        <img src={iconNotification} className={styles.menuIcon} />
        Notification Settings
      </div>
      {/* <div className={styles.menuItem} onClick={handleCreateCollection}>
        <img src={iconAdd} className={styles.menuIcon} />
        Create New Collection
      </div> */}
      <div className={styles.menuItem} onClick={handleRegisterCollection}>
        <img src={iconEdit} className={styles.menuIcon} />
        Register Existing Collection
      </div>
      <div className={styles.menuItem} onClick={openWrapStation}>
        <img src={iconSwap} className={styles.menuIcon} />
        FTM / WFTM Station
      </div>

      <div className={styles.menuSeparator} />
      {account?.toLowerCase() === ADMIN_ADDRESS.toLowerCase()
        ? [
            <div key={0} className={styles.menuItem} onClick={addMod}>
              Add Mod
            </div>,
            <div key={1} className={styles.menuItem} onClick={removeMod}>
              Remove Mod
            </div>,
            <div
              key={2}
              className={styles.menuItem}
              onClick={reviewCollections}
            >
              Review Collections
            </div>,
            <div key={3} className={styles.menuItem} onClick={banCollection}>
              Ban Collection
            </div>,
            <div key={4} className={styles.menuItem} onClick={unbanCollection}>
              Unban Collection
            </div>,
            <div key={5} className={styles.menuItem} onClick={banItems}>
              Ban Items
            </div>,
            <div key={6} className={styles.menuItem} onClick={banUser}>
              Ban a user
            </div>,
            <div key={6} className={styles.menuItem} onClick={unbanUser}>
              Unban a user
            </div>,
            <div key={7} className={styles.menuItem} onClick={boostCollection}>
              Boost Collection
            </div>,
            <div key={8} className={styles.menuSeparator} />,
          ]
        : isModerator
        ? [
            <div key={1} className={styles.menuItem} onClick={banCollection}>
              Ban Collection
            </div>,
            <div key={2} className={styles.menuItem} onClick={banItems}>
              Ban Items
            </div>,
            <div key={3} className={styles.menuItem} onClick={banUser}>
              Ban a user
            </div>,
            <div key={6} className={styles.menuItem} onClick={unbanUser}>
              Unban a user
            </div>,
            <div key={4} className={styles.menuSeparator} />,
          ]
        : null}
      <div className={styles.signOut} onClick={handleSignOut}>
        Sign Out
      </div>
    </Menu>
  );

  const renderSearchBox = () => (
    <div className={cx(styles.searchcont, searchBarActive && styles.active)}>
      <div className={styles.searchcontinner}>
        <div className={styles.searchbar}>
          <SearchIcon className={styles.searchicon} />
          <input
            placeholder="Search items, collections and accounts"
            className={styles.searchinput}
            onChange={e => handleSearch(e.target.value)}
            onFocus={() => setSearchBarActive(true)}
            onBlur={() => setTimeout(() => setSearchBarActive(false), 200)}
          />
        </div>
        {searchBarActive && (
          <div className={styles.resultcont}>
            {collections.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Collections</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {collections.map((collection, idx) => (
                    <div
                      key={idx}
                      className={styles.result}
                      onClick={() =>
                        handleSelectCollection(collection.erc721Address)
                      }
                    >
                      <img
                        className={styles.resultimg}
                        src={`${getRandomIPFS('', true)}${
                          collection.logoImageHash
                        }`}
                      />
                      <div className={styles.resulttitle}>
                        {collection.collectionName}
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            )}
            {accounts.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Accounts</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {accounts.map((account, idx) => (
                    <Link
                      to={`/account/${account.address}`}
                      key={idx}
                      className={styles.result}
                    >
                      {account.imageHash ? (
                        <img
                          className={styles.resultimg}
                          src={`https://cloudflare-ipfs.com/ipfs/${account.imageHash}`}
                        />
                      ) : (
                        <Identicon
                          className={styles.resultimg}
                          account={account.address}
                          size={40}
                        />
                      )}
                      <div className={styles.resulttitle}>{account.alias}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {tokens.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Items</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {tokens.map((tk, idx) => (
                    <Link
                      to={`/explore/${tk.contractAddress}/${tk.tokenID}`}
                      key={idx}
                      className={styles.result}
                    >
                      <div className={styles.resultimg}>
                        {tokenDetailsLoading ? (
                          <Skeleton width={40} height={40} />
                        ) : (
                          tk.thumbnailPath &&
                          (tk.thumbnailPath.length > 10 ? (
                            <img
                              src={`${storageUrl}/image/${tk.thumbnailPath}`}
                            />
                          ) : tk.thumbnailPath === '.' ? (
                            <img src={tk.imageURL} />
                          ) : null)
                        )}
                      </div>
                      <div className={styles.resulttitle}>{tk.name}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {bundles.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Bundles</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {bundles.map((bundle, idx) => (
                    <Link
                      to={`/bundle/${bundle._id}`}
                      key={idx}
                      className={styles.result}
                    >
                      <div className={styles.resultimg}></div>
                      <div className={styles.resulttitle}>{bundle.name}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {keyword.length > 0 &&
              collections.length === 0 &&
              accounts.length === 0 &&
              tokens.length === 0 &&
              bundles.length === 0 && (
                <div className={styles.noResults}>No Results</div>
              )}
          </div>
        )}
      </div>
    </div>
  );

  return (
    <div className={cx(styles.header, border && styles.hasBorder)}>
      <div className={styles.left}>
        <Link to="/" className={styles.logo}>
          <img src={logoSmallBlue} alt="logo" />
        </Link>
        {isSearchbarShown && renderSearchBox()}
        <div className={styles.secondmenu}>
          <NavLink
            to="/explore"
            className={cx(styles.menuLink, styles.link)}
            activeClassName={styles.active}
          >
            Explore
          </NavLink>
          <NavLink
            to="/create"
            className={cx(styles.menuLink, styles.link)}
            activeClassName={styles.active}
          >
            Create
          </NavLink>
        </div>
      </div>
      <div className={styles.menu}>
        {isSearchbarShown && renderSearchBox()}
        <NavLink
          to="/explore"
          className={cx(styles.menuLink, styles.link)}
          activeClassName={styles.active}
          style={{ color: '#fff' }}
        >
          Explore
        </NavLink>
        <NavLink
          to="/create"
          className={cx(styles.menuLink, styles.link)}
          activeClassName={styles.active}
          style={{ color: '#fff' }}
        >
          Create
        </NavLink>
        {account ? (
          <div
            className={cx(styles.account, styles.menuLink)}
            onClick={handleProfileMenuOpen}
          >
            {loading ? (
              <Skeleton className={styles.avatar} />
            ) : user?.imageHash ? (
              <img
                src={`https://cloudflare-ipfs.com/ipfs/${user?.imageHash}`}
                width="24"
                height="24"
                className={styles.avatar}
              />
            ) : (
              <Identicon
                account={account}
                size={36}
                className={styles.avatar}
              />
            )}
            <div className={styles.profile}>
              <div className={styles.address}>
                {loading ? (
                  <Skeleton width={120} />
                ) : (
                  user?.alias || shortenAddress(account)
                )}
              </div>
              <div className={styles.network}>
                {loading ? <Skeleton width={80} /> : NETWORK_LABEL[chainId]}
              </div>
            </div>

            <ExpandMore
              className={cx(styles.expand, isMenuOpen && styles.expanded)}
            />
          </div>
        ) : (
          <div
            className={cx(styles.connect, styles.menuLink)}
            onClick={handleConnectWallet}
          >
            Connect Wallet
          </div>
        )}
      </div>
      {renderMenu}
      <WFTMModal
        visible={wftmModalVisible}
        onClose={() => dispatch(ModalActions.hideWFTMModal())}
      />
      <ModModal
        isAdding={isAdding}
        visible={modModalVisible}
        onClose={() => setModModalVisible(false)}
      />
      <BanCollectionModal
        visible={banCollectionModalVisible}
        isBan={isBan}
        onClose={() => setBanCollectionModalVisible(false)}
      />
      <BanItemModal
        visible={banItemModalVisible}
        onClose={() => setBanItemModalVisible(false)}
      />
      <BanUserModal
        visible={banUserModalVisible}
        onClose={() => setBanUserModalVisible(false)}
        isForBanning={true}
      />
      <BanUserModal
        visible={unbanUserModalVisible}
        onClose={() => setUnbanUserModalVisible(false)}
        isForBanning={false}
      />
      <BoostCollectionModal
        visible={boostCollectionModalVisible}
        onClose={() => setBoostCollectionModalVisible(false)}
      />
      <ConnectWalletModal
        visible={connectWalletModalVisible}
        onClose={() => dispatch(ModalActions.hideConnectWalletModal())}
      />
    </div>
  );
}
Example #14
Source File: index.js    From Artion-Client with GNU General Public License v3.0 4 votes vote down vote up
Header = () => {
  const dispatch = useDispatch();

  const { getAuthToken, getAccountDetails, getIsModerator } = useApi();
  const { account, chainId, deactivate } = useWeb3React();

  const { user } = useSelector(state => state.Auth);

  const [anchorEl, setAnchorEl] = useState(null);
  const [loading, setLoading] = useState(false);
  const [connectWalletModalVisible, setConnectWalletModalVisible] = useState(
    false
  );

  const isMenuOpen = Boolean(anchorEl);

  const login = async () => {
    try {
      setLoading(true);
      const token = await getAuthToken(account);
      const isModerator = await getIsModerator(account);

      dispatch(WalletConnectActions.connectWallet(token, isModerator));
      dispatch(AuthActions.fetchStart());
      try {
        const { data } = await getAccountDetails(token);
        dispatch(AuthActions.fetchSuccess(data));
      } catch {
        dispatch(AuthActions.fetchFailed());
      }
      setLoading(false);
    } catch {
      setLoading(false);
    }
  };

  const init = () => {
    login();
  };

  useEffect(() => {
    if (account) {
      init();
    } else {
      handleSignOut();
    }
  }, [account, chainId]);

  const handleConnectWallet = () => {
    setConnectWalletModalVisible(true);
  };

  const handleSignOut = () => {
    deactivate();
    dispatch(WalletConnectActions.disconnectWallet());
    dispatch(AuthActions.signOut());
    handleMenuClose();
  };

  const handleProfileMenuOpen = e => {
    setAnchorEl(e.currentTarget);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
  };

  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMenuOpen}
      onClose={handleMenuClose}
      classes={{
        paper: styles.profilemenu,
        list: styles.menuList,
      }}
    >
      <div className={styles.signOut} onClick={handleSignOut}>
        Sign Out
      </div>
    </Menu>
  );

  return (
    <div className={styles.header}>
      <div className={styles.left}>
        <Link to="/" className={styles.logo}>
          <img src={logo} alt="logo" />
        </Link>
      </div>
      <div className={styles.menu}>
        {account ? (
          <div
            className={cx(styles.account, styles.menuLink)}
            onClick={handleProfileMenuOpen}
          >
            {loading ? (
              <Skeleton className={styles.avatar} />
            ) : user?.imageHash ? (
              <img
                src={`https://cloudflare-ipfs.com/ipfs/${user?.imageHash}`}
                width="24"
                height="24"
                className={styles.avatar}
              />
            ) : (
              <Identicon
                account={account}
                size={36}
                className={styles.avatar}
              />
            )}
            <div className={styles.profile}>
              <div className={styles.address}>
                {loading ? (
                  <Skeleton width={120} />
                ) : (
                  user?.alias || shortenAddress(account)
                )}
              </div>
              <div className={styles.network}>
                {loading ? <Skeleton width={80} /> : NETWORK_LABEL[chainId]}
              </div>
            </div>

            <ExpandMore
              className={cx(styles.expand, isMenuOpen && styles.expanded)}
            />
          </div>
        ) : (
          <div
            className={cx(styles.connect, styles.menuLink)}
            onClick={handleConnectWallet}
          >
            Connect Wallet
          </div>
        )}
      </div>
      {renderMenu}
      <ConnectWalletModal
        visible={connectWalletModalVisible}
        onClose={() => setConnectWalletModalVisible(false)}
      />
    </div>
  );
}
Example #15
Source File: StudentResponses.js    From Quizzie with MIT License 4 votes vote down vote up
function StudentResponses(props) {
	const [loading, setLoading] = useState(true);

	const [name, setName] = useState("");
	const [marks, setMarks] = useState(null);
	const [responses, setResponses] = useState([]);
	
	const [redirect, setRedirect] = useState(false);

	let state = null;

	const resIcon = (response) => {
		if(response.selected === response.correctAnswer) {
			return <Check style={{color: 'green', marginLeft: '3px'}} />
		} else if(response.selected === null) {
			return <Warning style={{color: 'goldenrod', marginLeft: '3px'}} />
		} 
		else {
			return <Close style={{color: 'red', marginLeft: '3px'}} />
		}
	}

	const setup = () => {
		setName(state.userId.name);
		setMarks(state.marks);
		setResponses(state.responses);
		setLoading(false);
	}

	
	useState(() => {
		if(props.location.state === undefined) {
			setLoading(false);
			setRedirect(true);
			return;
		}

		state = props.location.state.response;
		setup();
	}, [])

	if (loading) {
		return <Loading />
	} else if(redirect) {
		return <Redirect to="/dashboard" />
	}

	return (
		<Container className="result-page">
			<div className="result-head">
				<Typography variant="h4" className="result-title">Results</Typography>
			</div>
			<div className="result-quiz-info">
				<Typography variant="h5"><span className="profile-param">Quiz:</span> <strong>{name}</strong></Typography>
				<Typography variant="h5"><span className="profile-param">Scored:</span> <strong>{marks}</strong> out of <strong>{responses.length}</strong></Typography>
			</div>
			<div className="result-responses">
				<div className="result-response-title">
					<Typography variant="h5">Responses</Typography>
				</div>
				<div className="result-responses-list">
					{responses.map((response) => (
						<ExpansionPanel elevation={3} className="expansion" key={response.quesId}>
							<ExpansionPanelSummary
								className="question-response"
								expandIcon={<ExpandMore />}
								aria-controls="question-content"
								aria-label="Expand"
							>
								<Typography className="question-label">{response.description} {resIcon(response)}</Typography>
							</ExpansionPanelSummary>
							<ExpansionPanelDetails>
								<List component="nav" className="options-display">
									{response.options.map((option) => (
										<ListItem button key={option._id}>
											<ListItemIcon><Adjust style={{ color: response.correctAnswer === option.text ? 'green' : (response.selected === option.text? 'red': 'black') }} /></ListItemIcon>
											<ListItemText style={{ color: response.correctAnswer === option.text ? 'green' : (response.selected === option.text? 'red': 'black') }} primary={option.text} />
										</ListItem>
									))}
								</List>
							</ExpansionPanelDetails>
						</ExpansionPanel>
					))}
				</div>
			</div>
		</Container>
	)
}
Example #16
Source File: ResultPage.js    From Quizzie with MIT License 4 votes vote down vote up
function ResultPage(props) {
	const [quizId, setQuizId] = useState(props.match.params.id);
	const [loading, setLoading] = useState(true);

	const [name, setName] = useState("");
	const [marks, setMarks] = useState(null);
	const [responses, setResponses] = useState([]);


	const resIcon = (response) => {
		if(response.selected === response.correctAnswer) {
			return <Check style={{color: 'green', marginLeft: '3px'}} />
		} else if(response.selected === null) {
			return <Warning style={{color: 'goldenrod', marginLeft: '3px'}} />
		} 
		else {
			return <Close style={{color: 'red', marginLeft: '3px'}} />
		}
	}

	const getDetails = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/${quizId}`;

		try {
			await axios.get(url, {
				headers: {
					"auth-token": token
				}
			}).then(res => {
				setName(res.data.result.quizName);
			})
		} catch (error) {
			console.log(error);
		}
	}

	const getResponses = async () => {
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/user/studentQuizResult/${quizId}`;

		try {
			await axios.get(url, {
				headers: {
					"auth-token": token
				}
			}).then(res => {
				setMarks(res.data.result.marks);
				setResponses(res.data.result.responses);
				setLoading(false);
			})
		} catch (error) {
			console.log(error);
		}
	}

	useState(() => {
		getDetails();
		getResponses();
	}, [])

	if (loading) {
		return <Loading />
	}

	return (
		<Container className="result-page">
			<div className="result-head">
				<Typography variant="h4" className="result-title">Results</Typography>
			</div>
			<div className="result-quiz-info">
				<Typography variant="h5"><span className="profile-param">Quiz:</span> <strong>{name}</strong></Typography>
				<Typography variant="h5"><span className="profile-param">Scored:</span> <strong>{marks}</strong> out of <strong>{responses.length}</strong></Typography>
			</div>
			<div className="result-responses">
				<div className="result-response-title">
					<Typography variant="h5">Responses</Typography>
				</div>
				<div className="result-responses-list">
					{responses.map((response) => (
						<ExpansionPanel elevation={3} className="expansion" key={response.quesId}>
							<ExpansionPanelSummary
								className="question-response"
								expandIcon={<ExpandMore />}
								aria-controls="question-content"
								aria-label="Expand"
							>
								<Typography className="question-label">{response.description} {resIcon(response)}</Typography>
							</ExpansionPanelSummary>
							<ExpansionPanelDetails>
								<List component="nav" className="options-display">
									{response.options.map((option) => (
										<ListItem button key={option._id}>
											<ListItemIcon><Adjust style={{ color: response.correctAnswer === option.text ? 'green' : (response.selected === option.text? 'red': 'black') }} /></ListItemIcon>
											<ListItemText style={{ color: response.correctAnswer === option.text ? 'green' : (response.selected === option.text? 'red': 'black') }} primary={option.text} />
										</ListItem>
									))}
								</List>
							</ExpansionPanelDetails>
						</ExpansionPanel>
					))}
				</div>
			</div>
		</Container>
	)
}
Example #17
Source File: OwnerQuizDetails.js    From Quizzie with MIT License 4 votes vote down vote up
function OwnerQuizDetails(props) {
	const quizId = props.match.params.id;

	const [loading, setLoading] = useState(true);
	const [redirect, setRedirect] = useState(false);
	const [redirectD, setRedirectD] = useState(false);

	const [quizDetails, setQuizDetails] = useState({});
	const [quizQuestions, setQuizQuestions] = useState([]);
	const [responses, setResponses] = useState([]);

	const [deleteModal, setDeleteModal] = useState(false);
	const [deleteSnack, setDeleteSnack] = useState(false);

	const handleDeleteBtn = () => {
		setDeleteModal(true);
	};

	const validate = async () => {
		let token = localStorage.getItem("authToken");
		let url = "https://quizzie-api.herokuapp.com/general/checkUser";

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					if (res.data.result.userType !== "Owner") {
						setRedirectD(true);
						return;
					}
				});
		} catch (error) {
			console.log(error);
		}
	};

	const handleDelete = async () => {
		setDeleteSnack(true);
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/owner/quiz/${quizId}`;

		try {
			await axios
				.delete(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setRedirect(true);
				});
		} catch (error) {
			console.log(error);
		}
	};

	const getQuizDetails = async () => {
		setLoading(true);
		let token = localStorage.getItem("authToken");
		let url = `https://quizzie-api.herokuapp.com/quiz/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setQuizDetails(res.data.result);
				});
		} catch (error) {
			console.log(error);
		}

		url = `https://quizzie-api.herokuapp.com/question/all/${quizId}`;

		try {
			await axios
				.get(url, {
					headers: {
						"auth-token": token,
					},
				})
				.then((res) => {
					setQuizQuestions(res.data.result);
					setLoading(false);
				});
		} catch (error) {
			console.log(error);
		}

		// url = `https://quizzie-api.herokuapp.com/admin/allStudentsQuizResult/${quizId}`;

		// try {
		// 	await axios.get(url, {
		// 		headers: {
		// 			"auth-token": token
		// 		}
		// 	}).then(res => {
		// 		console.log(res);
		// 		setResponses(res.data.userResults);
		// 		setLoading(false);
		// 	})
		// } catch(error) {
		// 	console.log(error);
		// }
	};

	useEffect(() => {
		let token = localStorage.getItem("authToken");
		if (token === null) {
			setLoading(false);
			setRedirect(true);
			return;
		}
		validate();
		getQuizDetails();
	}, []);

	if (loading) {
		return <Loading />;
	} else if (redirect) {
		return <Redirect to="/coronilOP" />;
	} else if (redirectD) {
		return <Redirect to="/dashboard" />;
	} else {
		return (
			<Container className="edit-quiz-page">
				<Typography
					variant="h3"
					className="dash-head p-top edit-quiz-head"
				>
					Quiz Details
				</Typography>
				<div className="edit-btn-bar">
					<Button
						className="edit-details-btn delete-btn"
						onClick={handleDeleteBtn}
					>
						<Delete className="edit-icon" />
						Delete Quiz
					</Button>
				</div>
				<div className="quiz-details-sec">
					<Typography variant="h6" className="quiz-detail-param">
						Name:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizName}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Date:{" "}
						<span className="quiz-detail-text">
							{new Date(
								Number(quizDetails.scheduledFor)
							).toDateString()}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Time:{" "}
						<span className="quiz-detail-text">
							{new Date(
								Number(quizDetails.scheduledFor)
							).toLocaleTimeString()}
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Duration:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizDuration} minutes
						</span>
					</Typography>
					<Typography variant="h6" className="quiz-detail-param">
						Type:{" "}
						<span className="quiz-detail-text">
							{quizDetails.quizType}
						</span>
					</Typography>
					{quizDetails.quizType === "private" ? (
						<Typography variant="h6" className="quiz-detail-param">
							Quiz Code:{" "}
							<span className="quiz-detail-text">
								{quizDetails.quizCode}
							</span>
						</Typography>
					) : null}
				</div>
				<div className="quiz-questions-sec">
					<Typography variant="h4" className="quiz-questions-head">
						Questions
					</Typography>
					<div className="quiz-questions-display">
						{quizQuestions.length === 0 ? (
							<p style={{ textAlign: "center" }}>
								No questions added yet!
							</p>
						) : (
							<div className="questions-list-display">
								{quizQuestions.map((question) => (
									<ExpansionPanel
										elevation={3}
										className="expansion"
										key={question._id}
									>
										<ExpansionPanelSummary
											className="question-summary"
											expandIcon={<ExpandMore />}
											aria-controls="question-content"
											aria-label="Expand"
										>
											<Typography className="question-label">
												{question.description}
											</Typography>
										</ExpansionPanelSummary>
										<ExpansionPanelDetails>
											<List
												component="nav"
												className="options-display"
											>
												{question.options.map(
													(option) => (
														<ListItem
															button
															key={option._id}
														>
															<ListItemIcon>
																<Adjust
																	style={{
																		color:
																			question.correctAnswer ===
																			option.text
																				? "green"
																				: "black",
																	}}
																/>
															</ListItemIcon>
															<ListItemText
																style={{
																	color:
																		question.correctAnswer ===
																		option.text
																			? "green"
																			: "black",
																}}
																primary={
																	option.text
																}
															/>
														</ListItem>
													)
												)}
											</List>
										</ExpansionPanelDetails>
									</ExpansionPanel>
								))}
							</div>
						)}
					</div>
					{/* <Typography variant="h4" className="quiz-questions-head m-top">Submissions</Typography>
					<div className="quiz-students-list">
						{responses.length === 0? <p style={{ textAlign: 'center' }}>No responses yet!</p>
						: 
						<List aria-label="responses list">
							{responses.map((response) => (
								<ListItem button key={response._id}>
									<ListItemText primary={response.userId.name} secondary={`Scored: ${response.marks}`} />
								</ListItem>
							))}
						</List>
						}
					</div> */}
				</div>
				<Dialog
					open={deleteModal}
					onClose={() => setDeleteModal(false)}
					aria-labelledby="delete-quiz-modal"
					PaperProps={{
						style: {
							backgroundColor: "white",
							color: "black",
							minWidth: "10%",
						},
					}}
				>
					<DialogTitle>
						Are you sure you want to delete this quiz?
					</DialogTitle>
					<div className="btn-div">
						<Button
							className="logout-btn m-right bg-red-btn"
							onClick={handleDelete}
						>
							Yes
						</Button>
						<Button
							className="cancel-btn m-left"
							onClick={() => setDeleteModal(false)}
						>
							No
						</Button>
					</div>
				</Dialog>
				<Snackbar
					open={deleteSnack}
					autoHideDuration={5000}
					onClose={() => setDeleteSnack(false)}
				>
					<Alert
						variant="filled"
						severity="info"
						onClose={() => setDeleteSnack(false)}
					>
						Processing... Please Wait!
					</Alert>
				</Snackbar>
			</Container>
		);
	}
}