@mui/material#Alert JavaScript Examples

The following examples show how to use @mui/material#Alert. 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: FormResult.js    From fireact with MIT License 6 votes vote down vote up
FormResult = (props) => {
    const {
        severity,
        resultMessage,
        primaryText,
        primaryAction,
        secondaryText,
        secondaryAction
    } = props;

    return (
        <>
            <Alert severity={severity}>{resultMessage}</Alert>
            <ButtonRow>
                <Button variant="contained" color="primary" onClick={primaryAction} >{primaryText}</Button>
                {secondaryText && <Button variant="contained" color="secondary" onClick={secondaryAction}>{secondaryText}</Button>}
            </ButtonRow>
        </>
    );
}
Example #2
Source File: index.js    From fireact with MIT License 5 votes vote down vote up
DataEdit = ({id, schema, validation, handleEdit, success, children}) => {

    const mountedRef = useRef(true);

    const [inSubmit, setInSubmit] = useState(false);
    const [result, setResult] = useState({
        response: null,
        error: null
    });

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <form onSubmit={e => {
            e.preventDefault();
            setInSubmit(true);
            if(validation()){
                let data = {};
                schema.forEach(field => {
                    data[field.name] = e.target.elements[field.name][field.prop]
                });
                handleEdit(id, data).then(res => {
                    if (!mountedRef.current) return null
                    setResult({
                        response: true,
                        error: null
                    });
                    setInSubmit(false);
                }).catch(err => {
                    if (!mountedRef.current) return null
                    setResult({
                        response: false,
                        error: err
                    });
                    setInSubmit(false);
                })
            }else{
                setResult({
                    response: false,
                    error: 'Please fill in the form in the correct format.'
                })
                setInSubmit(false);
            }
            
        }}>
            <Paper>
                <Box p={2}>
                    <Stack spacing={3}>
                    {result.response?(
                        <>{success}</>
                    ):(
                        <>
                        {result.response === false && 
                            <Alert severity="error">{result.error}</Alert>
                        }
                        {children}
                        <Stack direction="row" spacing={1} mt={2}>
                            <Button variant="contained" type="submit" disabled={inSubmit}>{inSubmit && <Loader />} Save</Button>
                        </Stack>
                        </>
                    )}
                    </Stack>
                </Box>
            </Paper>
        </form>
    )
}
Example #3
Source File: CustomizedSnackbar.jsx    From matx-react with MIT License 5 votes vote down vote up
export default function CustomizedSnackbars() {
  const [open, setOpen] = React.useState(false);

  function handleClick() {
    setOpen(true);
  }
  function handleClose(_, reason) {
    if (reason === "clickaway") {
      return;
    }
    setOpen(false);
  }

  return (
    <ContentRoot>
      <Button variant="outlined" className="margin" onClick={handleClick}>
        Open success snackbar
      </Button>

      <Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
        <Alert onClose={handleClose} severity="success" sx={{ width: "100%" }} variant="filled">
          This is a success message!
        </Alert>
      </Snackbar>

      <Alert onClose={handleClose} sx={{ m: 1 }} severity="error" variant="filled">
        This is an error message!
      </Alert>

      <Alert onClose={handleClose} sx={{ m: 1 }} severity="warning" variant="filled">
        This is a warning message!
      </Alert>

      <Alert onClose={handleClose} sx={{ m: 1 }} severity="info" variant="filled">
        This is an information message!
      </Alert>

      <Alert onClose={handleClose} sx={{ m: 1 }} severity="success" variant="filled">
        This is a success message!
      </Alert>
    </ContentRoot>
  );
}
Example #4
Source File: index.js    From fireact with MIT License 5 votes vote down vote up
DataCreate = ({schema, validation, handleCreation, success, children}) => {
    const mountedRef = useRef(true);

    const [inSubmit, setInSubmit] = useState(false);
    const [result, setResult] = useState({
        response: null,
        error: null
    });

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <form onSubmit={e => {
            e.preventDefault();
            setInSubmit(true);
            if(validation()){
                let data = {};
                schema.forEach(field => {
                    data[field.name] = e.target.elements[field.name][field.prop]
                });
                handleCreation(data).then(res => {
                    if (!mountedRef.current) return null
                    setResult({
                        response: true,
                        error: null
                    });
                    setInSubmit(false);
                }).catch(err => {
                    if (!mountedRef.current) return null
                    setResult({
                        response: false,
                        error: err
                    });
                    setInSubmit(false);
                })
            }else{
                setResult({
                    response: false,
                    error: 'Please fill in the form in the correct format.'
                })
                setInSubmit(false);
            }
            
        }}>
            <Paper>
                <Box p={2}>
                    <Stack spacing={3}>
                        {result.response?(
                            <>{success}</>
                        ):(
                            <>
                            {result.response === false && 
                                <Alert severity="error">{result.error}</Alert>
                            }
                            {children}
                            <Stack direction="row" spacing={1} mt={2}>
                                <Button variant="contained" type="submit" disabled={inSubmit}>{inSubmit && <Loader />} Create</Button>
                            </Stack>
                            </>
                        )}
                    </Stack>
                </Box>
            </Paper>
        </form>
    )
}
Example #5
Source File: index.js    From fireact with MIT License 5 votes vote down vote up
DataList = ({handleFetch, schema}) => {
    const mountedRef = useRef(true);
    const [rows, setRows] = useState([]);
    const [total, setTotal] = useState(-1);
    const [page, setPage] = useState(0);
    const [pageSize, setPageSize] = useState(10);
    const [isLoading, setIsLoading] = useState(true);
    
    useEffect(() => {
        setIsLoading(true);
        handleFetch(page, pageSize).then(
            res => {
                if (!mountedRef.current) return null
                setRows(res.data);
                setTotal(res.total);
                setIsLoading(false);
            }
        )
    },[handleFetch, page, pageSize]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            {isLoading?(
                <Paper>
                    <Box p={2}>
                        <Loader text="Loading..." />
                    </Box>
                </Paper>
            ):(
                <Stack spacing={3}>
                {rows.length === 0 &&
                    <Alert severity="error">No data is found.</Alert>
                }
                    <Paper>
                        <Box>
                            <DataTable
                                columns={schema}
                                rows = {rows}
                                totalRows = {total}
                                pageSize = {pageSize}
                                page={page}
                                handlePageChane = {(e, p) => {
                                    setPage(p);
                                }}
                                handlePageSizeChange = {(e) => {
                                    setPage(0);
                                    setPageSize(e.target.value);
                                }}
                            />
                            
                        </Box>
                    </Paper>
                </Stack>
            )}
        </>
    )
}
Example #6
Source File: ImageCreate.js    From fireact with MIT License 4 votes vote down vote up
ImageCreate = () => {

    const listName = 'images'
    const title = 'Create Image';

    const formSchema = imagesJson.formSchema;
    const useStaticData = imagesJson.useStaticData;

    const [formFocused, setFormFocused] = useState(false);
    const [urlError, setUrlError] = useState(null);
    const [titleError, setTitleError] = useState(null);
    const validate = () => {
        return formFocused && !urlError && !titleError;
    }
    const { userData } = useContext(AuthContext);

    const titleCase = (str) => {
        let splitStr = str.toLowerCase().split(' ');
        for (let i = 0; i < splitStr.length; i++) {
            splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);     
        }
        return splitStr.join(' '); 
    }

    const createImageApiFirestore = (data) => {
        const Firestore = FirebaseAuth.firestore();
        const colRef = Firestore.collection('/accounts/'+userData.currentAccount.id+'/images');
        data.createAt = firebase.firestore.FieldValue.serverTimestamp();
        data.lastUpdateAt = firebase.firestore.FieldValue.serverTimestamp();
        return colRef.add(data);
    }


    const { setBreadcrumb } = useContext(BreadcrumbContext);
    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/"+listName,
                text: titleCase(listName),
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    },[setBreadcrumb, title, listName, userData]);

    return (
        <DataCreate
            schema = {formSchema}
            validation = {validate}
            success = {<Alert severity="success">{useStaticData?"Success! No data is saved because the database is a static file. This is just a demo.":"Success! The data is saved."}</Alert>}
            handleCreation = {useStaticData?CreateImageApiStatic:createImageApiFirestore}
        >
            <TextField
                label="Image URL"
                name="url"
                fullWidth
                onFocus={() => setFormFocused(true)}
                onBlur={(e) => {
                    if(!/^(http|https):\/\/[^ "]+$/.test(e.target.value) || e.target.value.length > 500){
                        setUrlError("Image URL must be a valid full URL less than 500 characters long.");
                    }else{
                        setUrlError(null);
                    }
                }}
                error={urlError?true:false}
                helperText={urlError}
            />
            <TextField
                label="Image Title"
                name="title"
                fullWidth
                onFocus={() => setFormFocused(true)}
                onBlur={(e) => {
                    if(e.target.value.trim().length < 1 || e.target.value.trim().length > 100){
                        setTitleError("Image Title must be between 1 to 100 characters.");
                    }else{
                        setTitleError(null);
                    }
                }}
                error={titleError?true:false}
                helperText={titleError}
            />
        </DataCreate>
    )

}
Example #7
Source File: Logs.js    From admin-web with GNU Affero General Public License v3.0 4 votes vote down vote up
render() {
    const { classes, t, logs } = this.props;
    const { snackbar, log, filename, autorefresh, clipboardMessage } = this.state;

    return (
      <TableViewContainer
        headline={t("Logs")}
        subtitle={t("logs_sub")}
        href="https://docs.grommunio.com/admin/administration.html#logs"
        snackbar={snackbar}
        onSnackbarClose={() => this.setState({ snackbar: '' })}
      >
        <div className={classes.logViewer}>
          <List style={{ width: 200 }}>
            <ListItem>
              <ListItemText
                primary={t("Log files")}
                primaryTypographyProps={{ color: "primary", variant: 'h6' }}
              />
            </ListItem>
            {logs.Logs.map((log, idx) =>
              <ListItem
                key={idx}
                onClick={this.handleLog(log)}
                button
                className={classes.li}
                selected={log === filename}
              >
                <ListItemText
                  primary={log}
                  primaryTypographyProps={{ color: "textPrimary" }}
                />
              </ListItem>
            )}
          </List>
          <Paper elevation={1} className={classes.paper}>
            {filename && <Grid container justifyContent="flex-end">
              <IconButton onClick={this.handleRefresh} style={{ marginRight: 8 }} size="large">
                <Refresh />
              </IconButton>
              <FormControlLabel
                control={
                  <Switch
                    checked={autorefresh}
                    onChange={this.handleAutoRefresh}
                    name="autorefresh"
                    color="primary"
                  />
                }
                label="Autorefresh"
              />
            </Grid>}
            {log.length > 0 ? <IconButton onClick={this.handleScroll} size="large">
              <ArrowUp />
            </IconButton> : filename && <Typography>&lt;no logs&gt;</Typography>}
            {log.map((log, idx) =>
              <pre
                key={idx}
                className={log.level < 4 ? classes.errorLog : log.level < 6 ? classes.noticeLog : classes.log}
                onClick={this.handleCopyToClipboard(log.message)}
              >
                {'[' + log.time + ']: ' + log.message}
              </pre>
            )}
          </Paper>
        </div>
        <Portal>
          <Snackbar
            anchorOrigin={{
              vertical: 'bottom',
              horizontal: 'center',
            }}
            open={!!clipboardMessage}
            onClose={this.handleSnackbarClose}
            autoHideDuration={2000}
            transitionDuration={{ in: 0, appear: 250, enter: 250, exit: 0 }}
          >
            <Alert
              onClose={this.handleSnackbarClose}
              severity={"success"}
              elevation={6}
              variant="filled"
            >
              {clipboardMessage}
            </Alert>
          </Snackbar>
        </Portal>
      </TableViewContainer>
    );
  }
Example #8
Source File: RegisterForm.js    From Django-REST-Framework-React-BoilerPlate with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function RegisterForm() {
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const userLogin = useSelector((state) => state.userLogin);
  const { userInfo } = userLogin;

  const userRgister = useSelector((state) => state.userRgister);
  const { error: registerError, loading: registerLoading } = userRgister;

  const [showPassword, setShowPassword] = useState(false);

  const RegisterSchema = Yup.object().shape({
    firstName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('First name required'),
    lastName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('Last name required'),
    email: Yup.string().email('Email must be a valid email address').required('Email is required'),
    password: Yup.string().required('Password is required'),
  });

  const formik = useFormik({
    initialValues: {
      firstName: '',
      lastName: '',
      email: '',
      password: '',
    },
    validationSchema: RegisterSchema,
    onSubmit: () => {
      dispatch(register(values.firstName, values.lastName, values.email, values.password));
    },
  });

  const { errors, touched, values, handleSubmit, isSubmitting, getFieldProps } = formik;
  useEffect(() => {
    if (userInfo) {
      navigate('/dashboard/app', { replace: true });
    }
  }, [navigate, userInfo]);
  return (
    <FormikProvider value={formik}>
      <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
        <Stack spacing={3}>
          <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
            <TextField
              fullWidth
              label="First name"
              {...getFieldProps('firstName')}
              error={Boolean(touched.firstName && errors.firstName)}
              helperText={touched.firstName && errors.firstName}
            />

            <TextField
              fullWidth
              label="Last name"
              {...getFieldProps('lastName')}
              error={Boolean(touched.lastName && errors.lastName)}
              helperText={touched.lastName && errors.lastName}
            />
          </Stack>

          <TextField
            fullWidth
            autoComplete="username"
            type="email"
            label="Email address"
            {...getFieldProps('email')}
            error={Boolean(touched.email && errors.email)}
            helperText={touched.email && errors.email}
          />

          <TextField
            fullWidth
            autoComplete="current-password"
            type={showPassword ? 'text' : 'password'}
            label="Password"
            {...getFieldProps('password')}
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton edge="end" onClick={() => setShowPassword((prev) => !prev)}>
                    <Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
                  </IconButton>
                </InputAdornment>
              ),
            }}
            error={Boolean(touched.password && errors.password)}
            helperText={touched.password && errors.password}
          />

          {registerError ? (
            <Alert severity="error">
              <AlertTitle>Register Error</AlertTitle>
              {registerError}
            </Alert>
          ) : null}

          <LoadingButton
            fullWidth
            size="large"
            type="submit"
            variant="contained"
            loading={registerLoading ? isSubmitting : null}
          >
            Register
          </LoadingButton>
        </Stack>
      </Form>
    </FormikProvider>
  );
}
Example #9
Source File: LoginForm.js    From Django-REST-Framework-React-BoilerPlate with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function LoginForm() {
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const userLogin = useSelector((state) => state.userLogin);
  const { error: loginError, loading: loginLoading, userInfo } = userLogin;

  const [showPassword, setShowPassword] = useState(false);

  const LoginSchema = Yup.object().shape({
    email: Yup.string().email('Email must be a valid email address').required('Email is required'),
    password: Yup.string().required('Password is required'),
  });

  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
    },
    validationSchema: LoginSchema,
    onSubmit: () => {
      dispatch(login(values.email, values.password));
    },
  });

  const { errors, touched, values, isSubmitting, handleSubmit, getFieldProps } = formik;

  const handleShowPassword = () => {
    setShowPassword((show) => !show);
  };

  useEffect(() => {
    if (userInfo) {
      navigate('/dashboard/app', { replace: true });
    }
  }, [navigate, userInfo]);
  return (
    <FormikProvider value={formik}>
      <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
        <Stack spacing={3}>
          <TextField
            fullWidth
            autoComplete="username"
            type="email"
            label="Email address"
            {...getFieldProps('email')}
            error={Boolean(touched.email && errors.email)}
            helperText={touched.email && errors.email}
          />

          <TextField
            fullWidth
            autoComplete="current-password"
            type={showPassword ? 'text' : 'password'}
            label="Password"
            {...getFieldProps('password')}
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton onClick={handleShowPassword} edge="end">
                    <Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
                  </IconButton>
                </InputAdornment>
              ),
            }}
            error={Boolean(touched.password && errors.password)}
            helperText={touched.password && errors.password}
          />
        </Stack>

        <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ my: 2 }}>
          <Link component={RouterLink} variant="subtitle2" to="#" underline="hover">
            Forgot password?
          </Link>
        </Stack>
        {loginError ? (
          <Alert severity="error">
            <AlertTitle>Login Error</AlertTitle>
            {loginError}
          </Alert>
        ) : null}

        <LoadingButton
          fullWidth
          size="large"
          type="submit"
          variant="contained"
          loading={loginLoading ? isSubmitting : null}
        >
          Login
        </LoadingButton>
      </Form>
    </FormikProvider>
  );
}
Example #10
Source File: User.js    From Django-REST-Framework-React-BoilerPlate with MIT License 4 votes vote down vote up
export default function User() {
  const userLogin = useSelector((state) => state.userLogin);
  const { userInfo } = userLogin;

  const listUser = useSelector((state) => state.listUser);
  const { loading, error, USERLIST } = listUser;

  const [page, setPage] = useState(0);

  const [order, setOrder] = useState('asc');

  const [selected, setSelected] = useState([]);

  const [orderBy, setOrderBy] = useState('name');

  const [filterName, setFilterName] = useState('');

  const [rowsPerPage, setRowsPerPage] = useState(5);

  const handleRequestSort = (event, property) => {
    const isAsc = orderBy === property && order === 'asc';
    setOrder(isAsc ? 'desc' : 'asc');
    setOrderBy(property);
  };

  const handleSelectAllClick = (event) => {
    if (event.target.checked) {
      const newSelecteds = USERLIST.map((n) => n.name);
      setSelected(newSelecteds);
      return;
    }
    setSelected([]);
  };

  const handleClick = (event, name) => {
    const selectedIndex = selected.indexOf(name);
    let newSelected = [];
    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, name);
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1));
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1));
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(selected.slice(0, selectedIndex), selected.slice(selectedIndex + 1));
    }
    setSelected(newSelected);
  };

  const handleChangePage = (event, newPage) => {
    setPage(newPage);
  };

  const handleChangeRowsPerPage = (event) => {
    setRowsPerPage(parseInt(event.target.value, 10));
    setPage(0);
  };

  const handleFilterByName = (event) => {
    setFilterName(event.target.value);
  };

  const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - USERLIST.length) : 0;

  const filteredUsers = applySortFilter(USERLIST, getComparator(order, orderBy), filterName);

  const isUserNotFound = filteredUsers.length === 0;

  return (
    <Page title="User">
      <Container>
        {userInfo ? <UsersListCall /> : null}

        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            User
          </Typography>
          <Button variant="contained" component={RouterLink} to="#" startIcon={<Iconify icon="eva:plus-fill" />}>
            New User
          </Button>
        </Stack>

        <Card>
          <UserListToolbar numSelected={selected.length} filterName={filterName} onFilterName={handleFilterByName} />
          {error ? (
            <Alert severity="error">
              <AlertTitle>List Loading Error</AlertTitle>
              {error}
            </Alert>
          ) : null}
          {loading ? (
            <Box sx={{ width: '100%' }}>
              <LinearProgress />
            </Box>
          ) : null}

          <Scrollbar>
            <TableContainer sx={{ minWidth: 800 }}>
              <Table>
                <UserListHead
                  order={order}
                  orderBy={orderBy}
                  headLabel={TABLE_HEAD}
                  rowCount={USERLIST.length}
                  numSelected={selected.length}
                  onRequestSort={handleRequestSort}
                  onSelectAllClick={handleSelectAllClick}
                />
                <TableBody>
                  {filteredUsers.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => {
                    const { id, name, role, status, company, avatarUrl, isVerified } = row;
                    const isItemSelected = selected.indexOf(name) !== -1;

                    return (
                      <TableRow
                        hover
                        key={id}
                        tabIndex={-1}
                        role="checkbox"
                        selected={isItemSelected}
                        aria-checked={isItemSelected}
                      >
                        <TableCell padding="checkbox">
                          <Checkbox checked={isItemSelected} onChange={(event) => handleClick(event, name)} />
                        </TableCell>
                        <TableCell component="th" scope="row" padding="none">
                          <Stack direction="row" alignItems="center" spacing={2}>
                            <Avatar alt={name} src={avatarUrl} />
                            <Typography variant="subtitle2" noWrap>
                              {name}
                            </Typography>
                          </Stack>
                        </TableCell>
                        <TableCell align="left">{company}</TableCell>
                        <TableCell align="left">{role}</TableCell>
                        <TableCell align="left">{isVerified ? 'Yes' : 'No'}</TableCell>
                        <TableCell align="left">
                          <Label variant="ghost" color={(status === 'banned' && 'error') || 'success'}>
                            {sentenceCase(status)}
                          </Label>
                        </TableCell>

                        <TableCell align="right">
                          <UserMoreMenu />
                        </TableCell>
                      </TableRow>
                    );
                  })}
                  {emptyRows > 0 && (
                    <TableRow style={{ height: 53 * emptyRows }}>
                      <TableCell colSpan={6} />
                    </TableRow>
                  )}
                </TableBody>

                {isUserNotFound && (
                  <TableBody>
                    <TableRow>
                      <TableCell align="center" colSpan={6} sx={{ py: 3 }}>
                        <SearchNotFound searchQuery={filterName} />
                      </TableCell>
                    </TableRow>
                  </TableBody>
                )}
              </Table>
            </TableContainer>
          </Scrollbar>

          <TablePagination
            rowsPerPageOptions={[5, 10, 25]}
            component="div"
            count={USERLIST.length}
            rowsPerPage={rowsPerPage}
            page={page}
            onPageChange={handleChangePage}
            onRowsPerPageChange={handleChangeRowsPerPage}
          />
        </Card>
      </Container>
    </Page>
  );
}
Example #11
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
ViewLogs = () => {
    const [total, setTotal] = useState(0);
    const [pageSize, setPageSize] = useState(10);
    const [page, setPage] = useState(0);
    const [rows, setRows] = useState([]);
    const [loading, setLoading] = useState(true);
    const [qs, setQs] = useState(null);
    const mountedRef = useRef(true);
    const [error, setError] = useState(null);

    const getLogs = (pz, direction, doc) => {
        const getTotal = () => {
            const userDocRef = FirebaseAuth.firestore().collection('users').doc(FirebaseAuth.auth().currentUser.uid);
            return userDocRef.get().then(function(userDoc){
                if (!mountedRef.current) return null
                if(userDoc.exists){
                    return userDoc.data().activityCount;
                }else{
                    return 0;
                }
            }).catch(() => {
                return 0;
            });
        }
    

        setLoading(true);
        let records = [];
        const collectionRef = FirebaseAuth.firestore().collection('users').doc(FirebaseAuth.auth().currentUser.uid).collection('activities');
        let query = collectionRef.orderBy('time', 'desc');
        if(direction && direction === 'next'){
            query = query.startAfter(doc);
        }
        if(direction && direction === 'previous'){
            query = query.endBefore(doc);
        }
        query = query.limit(pz);
        Promise.all([getTotal(), query.get()]).then(([activityCount, documentSnapshots]) => {
            if (!mountedRef.current) return null
            setTotal(activityCount);
            documentSnapshots.forEach(doc => {
                records.push({
                    'timestamp': doc.id,
                    'time': doc.data().time.toDate().toLocaleString(),
                    'action': doc.data().action
                });
            });
            if(records.length > 0){
                setRows(records);
                setQs(documentSnapshots);
            }
            setLoading(false);
        }).catch(e => {
            setError(e.message);
            setLoading(false);
        });
    }

    const title = 'View Activity Logs'
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/user/profile",
                text: "User",
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    },[setBreadcrumb]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    useEffect(() => {
        getLogs(pageSize);
    },[pageSize]);

    return (
        <UserPageLayout>
            {loading?(
                <Loader text="Loading logs..."></Loader>
            ):(
                <>
                {error?(
                    <Alert severity="error">{error}</Alert>
                ):(
                    <>
                        {total > 0 ? (
                            <DataTable columns={[
                                {name: "Activity", field: "action", style: {width: '50%'}},
                                {name: "Time", field: "time", style: {width: '50%'}}
                            ]}
                            rows={rows}
                            totalRows={total}
                            pageSize={pageSize}
                            page={page}
                            handlePageChane={(e, p) => {
                                if(p>page){
                                    getLogs(pageSize, 'next', qs.docs[qs.docs.length-1]);
                                }
                                if(p<page){
                                    getLogs(pageSize, 'previous', qs.docs[0]);
                                }
                                setPage(p);
                            }}
                            handlePageSizeChange={(e) => {
                                setPageSize(e.target.value);
                                setPage(0);
                            }}
                            ></DataTable>
                        ):(
                            <div>No activity is found</div>
                        )}
                    </>
                )}
                </>
            )}
        </UserPageLayout>
        
    )
}
Example #12
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
Invite = () => {

    const { code } = useParams();

    const title = 'View Invite';
    const history = useHistory();
    const mountedRef = useRef(true);

    const [invite, setInvite] = useState(null); 
    const [error, setError] = useState(null);
    const [inSubmit, setInSubmit] = useState(false);
    const [success, setSuccess] = useState(false);
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
        if(code){
            let isSubscribed = true;
            setError(null);
            const getInvite = CloudFunctions.httpsCallable('getInvite');
            getInvite({
                inviteId: code
            }).then(res => {
                if (!mountedRef.current) return null
                if(isSubscribed){
                    setInvite(res.data);
                }
            }).catch(err => {
                if (!mountedRef.current) return null
                if(isSubscribed){
                    setError(err.message);
                }
            });
            return () => (isSubscribed = false);
        }
    }, [code, setBreadcrumb, title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            {success?(
                <Redirect to={"/account/"+invite.accountId+"/"}></Redirect>
            ):(
                <Paper>
                    <Box p={2}>
                        <Stack spacing={3}>
                            {error !== null && 
                                <Alert severity="danger">{error}</Alert>
                            }
                            {invite === null?(
                                <Loader text="Loading the invite..."></Loader>
                            ):(
                                <>
                                    <Typography>This invite will grant you access to <strong>{invite.accountName}</strong>. Do you want to accept it?</Typography>
                                    <Stack direction="row" spacing={1} mt={2}>
                                        <Button disabled={inSubmit} variant="contained" onClick={e => {
                                            e.preventDefault();
                                            setInSubmit(true);
                                            const acceptInvite = CloudFunctions.httpsCallable('acceptInvite');
                                            acceptInvite({
                                                inviteId: code
                                            }).then(res => {
                                                if (!mountedRef.current) return null
                                                setSuccess(true);
                                            }).catch(err => {
                                                if (!mountedRef.current) return null
                                                setError(err.message);
                                            });
                                        }}>{inSubmit && <Loader />}
                                        Yes, accept the invite
                                        </Button>
                                        <Button color="secondary" variant="contained" disabled={inSubmit} onClick={() => history.push('/')}>Ignore</Button>
                                    </Stack>
                                </>
                            )}
                        </Stack>
                    </Box>
                </Paper>
            )}
        </>
    )
}
Example #13
Source File: ImageList.js    From fireact with MIT License 4 votes vote down vote up
ImageList = () => {
    const title = "Images";
    const { userData } = useContext(AuthContext);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const history = useHistory();
    const [refreshCount, setRefreshCount] = useState(0);
    const currentPage = useRef(0);
    const records = useRef([]);
    const useStaticData = imagesJson.useStaticData;
    const listFields = imagesJson.listFields;

    const handleFetch = useCallback((page, pageSize) => {
        return new Promise((resolve, reject) => {

            const ListImageApiFirestore = (page, pageSize) => {
                const start = page * pageSize;
                if(records.current.length-1>=start){
                    // if the page has been loaded, read from records
                    return new Promise((resolve, reject) => {
                        let docs = [];
                        for(let i=start; i<records.current.length; i++){
                            if(records.current.length<=i || i>=(start+pageSize)){
                                break;
                            }
                            docs.push(records.current[i]);
                        }
                        resolve({
                            total: -1,
                            data: docs
                        })
                    });
                }else{
                    // if the page hasn't been loaded, read from Firestore
                    const fields = ["title", "url"];
                    let doc = null;
                    if(page > 0 && records.current.length > 0){
                        // find the last document if the requested page is not the first page
                        doc = records.current[records.current.length-1]["_doc"];
                    }
                    currentPage.current = page;
                    const Firestore = FirebaseAuth.firestore();
                    const colRef = Firestore.collection('/accounts/'+userData.currentAccount.id+'/images');
                    let query = colRef.orderBy('createAt', 'desc');
                    if(doc !== null){
                        query = query.startAfter(doc);
                    }
                    query = query.limit(pageSize);
                    return query.get().then(documentSnapshots => {
                        let docs = [];
                        if(!documentSnapshots.empty){
                            documentSnapshots.forEach(documentSnapshot => {
                                docs.push({
                                    id: documentSnapshot.id,
                                    _doc: documentSnapshot
                                });
                                fields.forEach(field => {
                                    docs[docs.length-1][field] = documentSnapshot.data()[field];
                                })
                            });
                            records.current = records.current.concat(docs);
                        }
                        return {total: -1, data: docs}
                    }).catch(err => {
                        throw(err);
                    })
                }
            }

            let ListImageApi = useStaticData?ListImageApiStatic:ListImageApiFirestore;

            // apply custom filter here if you wish to pass additional parameters to the api calls
            ListImageApi(page, pageSize).then(images => {
                const handleDeletion = (id) => {
                    if(useStaticData){
                        DeleteImageApiStatic(id).then(() => {
                            setRefreshCount(refreshCount+1);
                        });
                    }else{
                        const Firestore = FirebaseAuth.firestore();
                        const DocRef = Firestore.doc('/accounts/'+userData.currentAccount.id+'/images/'+id);
                        DocRef.delete().then(() => {
                            // remove the record from records then update the list in the UI
                            for(let i=0; i<records.current.length; i++){
                                if(records.current[i].id === id){
                                    records.current.splice(i, 1);
                                }
                            }
                            setRefreshCount(refreshCount+1);
                        })
                    }
                    
                }

                let rows = [];
                // loop through the data to add the visual components in to the list
                for(let i=0; i<images.data.length; i++){
                    const row = {
                        id: images.data[i].id,
                        url: images.data[i].url,
                        title: images.data[i].title,
                        image: <img alt={images.data[i].title} src={images.data[i].url} width={200} />,
                        action: <ActionButtons id={images.data[i].id} handleDeletion={handleDeletion} />
                    }
                    rows.push(row);
                }
                resolve({
                    total: images.total,
                    data: rows
                });
            }).catch(err => {
                reject(err);
            });
        });
    },[refreshCount, userData, useStaticData]);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: null,
                text: title,
                active: false
            }
        ]);
    },[setBreadcrumb, title, userData]);

    return (
        <Stack spacing={3}>
            <Alert severity="info">
                This is a demo
            </Alert>
            <div style={{marginLeft: "auto"}}>
                <Stack direction="row" spacing={1}>
                    <Button variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/images/create")} >Create Image Link</Button>
                </Stack>
            </div>
            <DataList handleFetch={handleFetch} schema={listFields} />
        </Stack>
    )
}
Example #14
Source File: ImageEdit.js    From fireact with MIT License 4 votes vote down vote up
ImageEdit = () => {
    const mountedRef = useRef(true);

    const listName = 'images'
    const title = 'Edit Image';

    const useStaticData = imagesJson.useStaticData;
    const formSchema = imagesJson.formSchema;

    const [urlError, setUrlError] = useState(null);
    const [titleError, setTitleError] = useState(null);
    const validate = () => {
        return !urlError && !titleError;
    }
    const { userData } = useContext(AuthContext);
    const { imageId } = useParams();
    const [data, setData] = useState(null);
    const [isLoading, setIsLoading] = useState(true);


    const titleCase = (str) => {
        let splitStr = str.toLowerCase().split(' ');
        for (let i = 0; i < splitStr.length; i++) {
            splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);     
        }
        return splitStr.join(' '); 
    }

    const { setBreadcrumb } = useContext(BreadcrumbContext);
    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/"+listName,
                text: titleCase(listName),
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
        setIsLoading(true);
        if(useStaticData){
            GetImageApiStatic(imageId).then(data => {
                if (!mountedRef.current) return null
                setData(data);
                setIsLoading(false);
            })
        }else{
            const Firestore = FirebaseAuth.firestore();
            const DocRef = Firestore.doc('/accounts/'+userData.currentAccount.id+'/images/'+imageId);
            DocRef.get().then(doc => {
                if (!mountedRef.current) return null
                setData(doc.data());
                setIsLoading(false);
            })
        }
        
    },[setBreadcrumb, title, listName, userData, imageId, useStaticData]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    const EditImageApiFirestore = (id, data) => {
        const Firestore = FirebaseAuth.firestore();
        const DocRef = Firestore.doc('/accounts/'+userData.currentAccount.id+'/images/'+id);
        return DocRef.set(data, {merge: true});
    }

    return (
        <>
        {isLoading?(
            <Paper>
                <Box p={2}>
                    <Loader text="Loading..." />
                </Box>
            </Paper>
        ):(
            <DataEdit
                id = {imageId}
                schema = {formSchema}
                validation = {validate}
                success = {<Alert severity="success">{useStaticData?"Success! No data is saved because the database is a static file. This is just a demo.":"Success! The data is updated."}</Alert>}
                handleEdit = {useStaticData?EditImageApiStatic:EditImageApiFirestore}
            >
                <TextField
                    label="Image URL"
                    name="url"
                    defaultValue={data.url}
                    fullWidth
                    onBlur={(e) => {
                        if(!/^(http|https):\/\/[^ "]+$/.test(e.target.value) || e.target.value.length > 500){
                            setUrlError("Image URL must be a valid full URL less than 500 characters long.");
                        }else{
                            setUrlError(null);
                        }
                    }}
                    error={urlError?true:false}
                    helperText={urlError}
                />
                <TextField
                    label="Image Title"
                    name="title"
                    defaultValue={data.title}
                    fullWidth
                    onBlur={(e) => {
                        if(e.target.value.trim().length < 1 || e.target.value.trim().length > 100){
                            setTitleError("Image Title must be between 1 to 100 characters.");
                        }else{
                            setTitleError(null);
                        }
                    }}
                    error={titleError?true:false}
                    helperText={titleError}
                />
            </DataEdit>
        )}
        </>
    )

}
Example #15
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
UserRole = () => {
    const title = 'Change User Role';
    const history = useHistory();

    const { userData } = useContext(AuthContext);
    const { userId } = useParams();
    const mountedRef = useRef(true);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const [user, setUser] = useState(null);
    const [error, setError] = useState(null);
    const [success, setSuccess] = useState(false);
    const [inSubmit, setInSubmit] = useState(false);
    const [selectedRole, setSelectedRole] = useState(null);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/users",
                text: 'Manage Users',
                active: false
            },    
            {
                to: null,
                text: title,
                active: true
            }
        ]);
        setError(null);
        const getAccountUser = CloudFunctions.httpsCallable('getAccountUser');
        getAccountUser({
            accountId: userData.currentAccount.id,
            userId: userId
        }).then(res => {
            if (!mountedRef.current) return null
            res.data.lastLoginTime = new Date(res.data.lastLoginTime);
            setUser(res.data);
        }).catch(err => {
            if (!mountedRef.current) return null
            setError(err.message);
        });
    },[userData, userId, setBreadcrumb]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <Paper>
                <Box p={2}>
                {(userId !== userData.currentAccount.owner)?(
                    success?(
                        <>
                            <Alert severity="success" onClose={() => setSuccess(false)}>User role is successfully updated.</Alert>
                            <Stack direction="row" spacing={1} mt={2}>
                                <Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
                            </Stack>
                        </>

                    ):(
                        <Stack spacing={3}>
                            {error !== null && 
                                <Alert severity="error">{error}</Alert>
                            }
                            {user === null ? (
                                <Loader text="Loading user details" />
                            ):(
                                <Form handleSubmit={e => {
                                    e.preventDefault();
                                    setError(null);
                                    setSuccess(false);
                                    setInSubmit(true);
                                    const updateAccountUserRole = CloudFunctions.httpsCallable('updateAccountUserRole');
                                    updateAccountUserRole({
                                        accountId: userData.currentAccount.id,
                                        userId: userId,
                                        role: selectedRole
                                    }).then(res => {
                                        setInSubmit(false);
                                        setSuccess(true);
                                    }).catch(err => {
                                        setInSubmit(false);
                                        setError(err.message);
                                    });
                                }}
                                disabled={selectedRole===null || selectedRole===user.role || inSubmit}
                                submitBtnStyle={(selectedRole!=='remove')?"primary":"error"}
                                inSubmit={inSubmit}
                                enableDefaultButtons={true}
                                backToUrl={"/account/"+userData.currentAccount.id+"/users"}
                                >
                                    <Stack spacing={1} mb={5} style={{display: 'inline-block', textAlign: 'center'}}>
                                        <Avatar alt={user.displayName} src={user.photoUrl} sx={{width: 100, height:100, margin: 'auto'}} />
                                        <Typography><strong style={{fontSize: '1.3rem'}}>{user.displayName}</strong></Typography>
                                        <Typography>
                                            Last Login:<br /> {user.lastLoginTime.toLocaleString()}
                                        </Typography>
                                    </Stack>
                                    <FormControl fullWidth>
                                        <InputLabel>Role</InputLabel>
                                        <Select label="Role" defaultValue={user.role} onChange={e => {
                                            setSelectedRole(e.target.value);
                                        }}>
                                            <MenuItem value="user">user</MenuItem>
                                            <MenuItem value="admin">admin</MenuItem>
                                            <MenuItem value="remove"><em>-- Remove Access --</em></MenuItem>
                                        </Select>
                                    </FormControl>
                                </Form>
                            )}
                        </Stack>
                    )
                ):(
                    <>
                        <Alert severity="error">Cannot change account owner role.</Alert>
                        <Stack direction="row" spacing={1} mt={2}>
                            <Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
                        </Stack>
                    </>
                )}
                </Box>
            </Paper>
    )
}
Example #16
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
UserList = () => {
    const title = 'Users';
    const history = useHistory();  

    const { userData } = useContext(AuthContext);
    const mountedRef = useRef(true);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const [users, setUsers] = useState(null);
    const [data, setData] = useState([]);
    const [error, setError] = useState(null);
    const [total, setTotal] = useState(0);
    const [page, setPage] = useState(0);
    const [pageSize, setPageSize] = useState(10);

    useEffect(() => {
        setBreadcrumb(
            [
                {
                    to: "/",
                    text: "Home",
                    active: false
                },
                {
                    to: "/account/"+userData.currentAccount.id+"/",
                    text: userData.currentAccount.name,
                    active: false
                },      
                {
                    to: null,
                    text: title,
                    active: true
                }
            ]);
        setError(null);
        const getAccountUsers = CloudFunctions.httpsCallable('getAccountUsers');
        getAccountUsers({
            accountId: userData.currentAccount.id
        }).then(res => {
            if (!mountedRef.current) return null
            let totalCounter = 0;
            res.data.forEach(record => {
                record.nameCol = <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    flexWrap: 'wrap',
                }}><Avatar alt={record.displayName} src={record.photoUrl} /><strong style={{marginLeft: '15px'}}>{record.displayName}</strong></div>
                record.roleCol = record.id===userData.currentAccount.owner?"Owner":(record.role.charAt(0).toUpperCase()+record.role.slice(1));
                record.lastLoginTimeCol = (new Date(record.lastLoginTime)).toLocaleString();
                if(record.roleCol !== 'Owner'){
                    record.actionCol = <Button size="small" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users/change/"+record.id)}>Change Role</Button>
                }
                totalCounter++;
            });
            setTotal(totalCounter);
            setData(res.data);
        }).catch(err => {
            if (!mountedRef.current) return null
            setError(err.message);
        });
    },[userData, setBreadcrumb, history]);

    useEffect(() => {
        const startIndex = page * pageSize;
        let records = [];
        for(let i=startIndex; i<data.length; i++){
            if(i>=startIndex+pageSize){
                break;
            }
            records.push(data[i]);
        }
        if(records.length > 0){
            setUsers(records);
        }
        window.scrollTo(0, 0);
    },[page, pageSize, data])

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            <div style={{marginTop: '20px', marginBottom: '20px', textAlign: 'right'}}>
                <Button onClick={() => history.push("/account/"+userData.currentAccount.id+"/users/add")} color="primary" variant="contained"><i className="fa fa-plus"></i> Add User</Button>
            </div>
            <Paper width={1}>
                <Box p={2}>
                    {error !== null && 
                        <Alert severity="error">{error}</Alert>
                    }
                    {users === null ? (
                        <Loader text="Loading users" />
                    ):(
                        <DataTable columns={[
                            {name: "Name", field: "nameCol", style: {width: '40%'}},
                            {name: "Role", field: "roleCol", style: {width: '20%'}},
                            {name: "Last Login", field: "lastLoginTimeCol", style: {width: '30%'}},
                            {name: "Action", field: "actionCol", style: {width: '10%'}}
                        ]}
                        rows={users}
                        totalRows={total}
                        pageSize={pageSize}
                        page={page}
                        handlePageChane={(e, p) => {
                            setPage(p);
                        }}
                        handlePageSizeChange={(e) => {
                            setPage(0);
                            setPageSize(e.target.value);
                        }}
                        ></DataTable>
                    )}
                </Box>
            </Paper>
        </>

    )
}
Example #17
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
Plans = () => {
    const title = 'Select a Plan';

    const countries = countryJSON.countries;

    const { userData, authUser } = useContext(AuthContext);
    const stripe = useStripe();
    const elements = useElements();
    const mountedRef = useRef(true);
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    const CARD_ELEMENT_OPTIONS = {
        style: {
            base: {
              color: '#32325d',
              fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
              fontSmoothing: 'antialiased',
              fontSize: '16px',
              '::placeholder': {
                color: '#aab7c4'
              }
            },
            invalid: {
              color: '#fa755a',
              iconColor: '#fa755a'
            }
        },
        hidePostalCode: true
    };

    const [loading, setLoading] = useState(true);
    const [processing, setProcessing] = useState(false);
    const [plans, setPlans] = useState([]);
    const [selectedPlan, setSelectedPlan] = useState({id: 0});
    const [cardError, setCardError] = useState(null);
    const [errorMessage, setErrorMessage] = useState(null);
    const [country, setCountry] = useState("");
    const [countryError, setCountryError] = useState(null);
    const [state, setState] = useState("");
    const [states, setStates] = useState([]);
    const [stateError, setStateError] = useState(null);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },      
            {
                to: null,
                text: title,
                active: true
            }
        ]);
        setLoading(true);

        const plansQuery = FirebaseAuth.firestore().collection('plans').orderBy('price', 'asc');
        plansQuery.get().then(planSnapShots => {
            if (!mountedRef.current) return null
            let p = [];
            planSnapShots.forEach(doc => {
                p.push({
                    'id': doc.id,
                    'name': doc.data().name,
                    'price': doc.data().price,
                    'currency': doc.data().currency,
                    'paymentCycle': doc.data().paymentCycle,
                    'features': doc.data().features,
                    'stripePriceId': doc.data().stripePriceId,
                    'current': (userData.currentAccount.planId===doc.id)?true:false
                });
            });
            if(p.length > 0){
                const ascendingOrderPlans = p.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
                setPlans(ascendingOrderPlans);
            }
            setLoading(false);
        });
    },[userData, setBreadcrumb, title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    const subscribe = async(event) => {
        event.preventDefault();
        setProcessing(true);
        setErrorMessage(null);

        let hasError = false;
        let paymentMethodId = '';

        if(selectedPlan.price !== 0){
            if(country === ''){
                setCountryError('Please select a country.');
                hasError = true;
            }

            if(state === '' && countries[country] && countries[country].states){
                setStateError('Please select a state.');
                hasError = true;
            }

            setCardError(null);

            if (!stripe || !elements) {
                // Stripe.js has not loaded yet. Make sure to disable
                // form submission until Stripe.js has loaded.
                return;
            }
    
            // Get a reference to a mounted CardElement. Elements knows how
            // to find your CardElement because there can only ever be one of
            // each type of element.
            const cardElement = elements.getElement(CardElement);
    
            // Use your card Element with other Stripe.js APIs
            const {error, paymentMethod} = await stripe.createPaymentMethod({
                type: 'card',
                card: cardElement
            });
    
            if (error) {
                setCardError(error.message);
                hasError = true;
            } else {
                paymentMethodId = paymentMethod.id;
            }
        }

        
        if(!hasError){
            const createSubscription = CloudFunctions.httpsCallable('createSubscription');
            createSubscription({
                planId: selectedPlan.id,
                accountId: userData.currentAccount.id,
                paymentMethodId: paymentMethodId,
                billing: {
                    country: country,
                    state: state
                }
            }).then(res => {
                // physical page load to reload the account data
                if (!mountedRef.current) return null
                document.location = '/account/'+userData.currentAccount.id+'/';
            }).catch(err => {
                if (!mountedRef.current) return null
                setProcessing(false);
                setErrorMessage(err.message);
            });
        }else{
            setProcessing(false);
        }
    }

    return (
        <>
        {(!loading)?(
            <>{(userData.currentAccount.owner === authUser.user.uid)?(
            <>{plans.length > 0 ? (
            <Paper>
                <Box p={3} style={{textAlign: 'center'}} >
                    <h2>{title}</h2>
                    <Grid container spacing={3}>
                        
                            <>
                            {plans.map((plan,i) => 
                                <Grid container item xs={12} md={4} key={i} >
                                    <Card style={{
                                        width: '100%',
                                        display: 'flex',
                                        flexDirection: 'column',
                                        paddingBottom: '20px',
                                    }}>
                                        <CardHeader title={plan.name} subheader={"$"+plan.price+"/"+plan.paymentCycle} />
                                        <CardContent>
                                            <Divider />
                                            <ul style={{listStyleType: 'none', paddingLeft: '0px'}}>
                                            {plan.features.map((feature, i) => 
                                                <li key={i}>
                                                    <i className="fa fa-check" style={{color: "#2e7d32"}} /> {feature}
                                                </li>
                                            )}
                                            </ul>
                                        </CardContent>
                                        <CardActions style={{
                                            marginTop: 'auto',
                                            justifyContent: 'center',
                                        }}>
                                            {plan.current?(
                                                <Button color="success" variant="contained" disabled={true}>Current Plan</Button>
                                            ):(
                                                <Button color="success" variant={(plan.id!==selectedPlan.id)?"outlined":"contained"} onClick={() => {
                                                    for(let i=0; i<plans.length; i++){
                                                        if(plans[i].id === plan.id){
                                                            setSelectedPlan(plan);
                                                        }
                                                    }
                                                }}>{plan.id===selectedPlan.id && <><i className="fa fa-check" /> </>}{(plan.id!==selectedPlan.id)?"Select":"Selected"}</Button>    
                                            )}
                                        </CardActions>
                                    </Card>
                                </Grid>
                            )}
                            </>
                        
                    </Grid>
                    {selectedPlan.id !== 0 && selectedPlan.price > 0 && 
                        <div style={{justifyContent: 'center', marginTop: '50px'}}>
                            <h2>Billing Details</h2>
                            <Grid container spacing={3}>
                                <Grid container item xs={12}>
                                    <Card style={{
                                        width: '100%',
                                        paddingBottom: '20px',
                                    }}>
                                        <CardContent>
                                            <Container maxWidth="sm">
                                                <Stack spacing={3}>
                                                    {countryError !== null && 
                                                        <Alert severity="error" onClose={() => setCountryError(null)}>{countryError}</Alert>
                                                    }
                                                    <Autocomplete
                                                        value={(country !== '')?(countries.find(obj =>{
                                                            return obj.code === country
                                                        })):(null)}
                                                        options={countries}
                                                        autoHighlight
                                                        getOptionLabel={(option) => option.label}
                                                        renderOption={(props, option) => (
                                                            <Box component="li" sx={{ '& > img': { mr: 2, flexShrink: 0 } }} {...props}>
                                                                <img
                                                                    loading="lazy"
                                                                    width="20"
                                                                    src={`https://flagcdn.com/w20/${option.code.toLowerCase()}.png`}
                                                                    srcSet={`https://flagcdn.com/w40/${option.code.toLowerCase()}.png 2x`}
                                                                    alt=""
                                                                />
                                                                {option.label}
                                                            </Box>
                                                        )}
                                                        renderInput={(params) => (
                                                            <TextField
                                                                {...params}
                                                                label="Country"
                                                                inputProps={{
                                                                    ...params.inputProps,
                                                                    autoComplete: 'new-password',
                                                                }}
                                                            />
                                                        )}
                                                        onChange={(event, newValue) => {
                                                            if(newValue && newValue.code){
                                                                setCountry(newValue.code);
                                                                setState("");
                                                                if(newValue.states){
                                                                    setStates(newValue.states);
                                                                }else{
                                                                    setStates([]);
                                                                }
                                                                setCountryError(null);
                                                            }
                                                        }}
                                                    />
                                                    {states.length > 0 &&
                                                    <>
                                                        {stateError !== null && 
                                                            <Alert severity="error" onClose={() => setStateError(null)}>{stateError}</Alert>
                                                        }
                                                        <Autocomplete
                                                            value={(state !== '')?(states.find(obj =>{
                                                                return obj.code === state
                                                            })):(null)}
                                                            options={states}
                                                            autoHighlight
                                                            getOptionLabel={(option) => option.label}
                                                            renderOption={(props, option) => (
                                                                <Box component="li" {...props}>
                                                                    {option.label}
                                                                </Box>
                                                            )}
                                                            renderInput={(params) => (
                                                                <TextField
                                                                    {...params}
                                                                    label="State"
                                                                    inputProps={{
                                                                        ...params.inputProps,
                                                                        autoComplete: 'new-password',
                                                                    }}
                                                                />
                                                            )}
                                                            onChange={(event, newValue) => {
                                                                if(newValue && newValue.code){
                                                                    setState(newValue.code);
                                                                    setStateError(null);
                                                                }
                                                                
                                                            }}
                                                        />
                                                    </>
                                                    }
                                                    {cardError !== null && 
                                                        <Alert severity="error" onClose={() => setCardError(null)}>{cardError}</Alert>
                                                    }
                                                    <div style={{position: "relative", minHeight: '56px', padding: '15px'}}>
                                                        <CardElement options={CARD_ELEMENT_OPTIONS}></CardElement>
                                                        <fieldset style={{
                                                            borderColor: 'rgba(0, 0, 0, 0.23)',
                                                            borderStyle: 'solid',
                                                            borderWidth: '1px',
                                                            borderRadius: '4px',
                                                            position: 'absolute',
                                                            top: '-5px',
                                                            left: '0',
                                                            right: '0',
                                                            bottom: '0',
                                                            margin: '0',
                                                            padding: '0 8px',
                                                            overflow: 'hidden',
                                                            pointerEvents: 'none'
                                                            
                                                        }}></fieldset>
                                                    </div>
                                                </Stack>
                                            </Container>
                                        </CardContent>
                                    </Card>
                                </Grid>
                            </Grid>
                        </div>
                    }
                    {selectedPlan.id!==0 &&
                        <div style={{marginTop: '50px'}}>
                            <Container maxWidth="sm">
                                <Stack spacing={3}>
                                {errorMessage !== null && 
                                    <Alert severity="error" onClose={() => setErrorMessage(null)}>{errorMessage}</Alert>
                                }
                                <Button color="success" size="large" variant="contained" disabled={selectedPlan.id===0||processing?true:false} onClick={e => {
                                    subscribe(e);
                                }}>{processing?(<><Loader /> Processing...</>):(<>Subscribe Now</>)}</Button>
                                </Stack>
                            </Container>
                        </div>
                    }
                </Box>
            </Paper>
            ):(
                <Alert severity="warning">No plan is found.</Alert>
            )}</>
            ):(
                <Alert severity="error" >Access Denied.</Alert>
            )}</>
        ):(
            <Loader text="loading plans..." />
        )}
        </>

    )
}
Example #18
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
PaymentMethod = () => {
    const title = 'Update Payment Method';
    const mountedRef = useRef(true);
    const history = useHistory();

    const { userData, authUser } = useContext(AuthContext);
    const stripe = useStripe();
    const elements = useElements();
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    const CARD_ELEMENT_OPTIONS = {
        style: {
            base: {
              color: '#32325d',
              fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
              fontSmoothing: 'antialiased',
              fontSize: '16px',
              '::placeholder': {
                color: '#aab7c4'
              }
            },
            invalid: {
              color: '#fa755a',
              iconColor: '#fa755a'
            }
        },
        hidePostalCode: true
    };

    const [processing, setProcessing] = useState(false);
    const [success, setSuccess] = useState(false);
    const [cardError, setCardError] = useState(null);
    const [errorMessage, setErrorMessage] = useState(null);

    const subscribe = async(event) => {
        event.preventDefault();
        setProcessing(true);
        setErrorMessage(null);
        setSuccess(false);

        let hasError = false;
        let paymentMethodId = '';

        setCardError(null);

        if (!stripe || !elements) {
            // Stripe.js has not loaded yet. Make sure to disable
            // form submission until Stripe.js has loaded.
            return;
        }

        // Get a reference to a mounted CardElement. Elements knows how
        // to find your CardElement because there can only ever be one of
        // each type of element.
        const cardElement = elements.getElement(CardElement);

        // Use your card Element with other Stripe.js APIs
        const {error, paymentMethod} = await stripe.createPaymentMethod({
            type: 'card',
            card: cardElement,
        });

        if (error) {
            setCardError(error.message);
            hasError = true;
        } else {
            paymentMethodId = paymentMethod.id;
        }

        
        if(!hasError){
            const updatePaymentMethod = CloudFunctions.httpsCallable('updatePaymentMethod');
            updatePaymentMethod({
                accountId: userData.currentAccount.id,
                paymentMethodId: paymentMethodId
            }).then(res => {
                if (!mountedRef.current) return null
                setSuccess(true);
                setProcessing(false);
            }).catch(err => {
                if (!mountedRef.current) return null
                setProcessing(false);
                setErrorMessage(err.message);
            });
        }else{
            setProcessing(false);
        }
    }

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/billing",
                text: 'Billing',
                active: false
            },   
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    },[userData, setBreadcrumb, title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            <Paper>
                <Box p={2}>
                    {userData.currentAccount.price > 0 ? (
                        <Stack spacing={3}>
                            {(userData.currentAccount.owner === authUser.user.uid)?(
                                <>
                                    {success && 
                                    <Alert severity="success" onClose={() => setSuccess(false)}>The payment method has been successfully updated.</Alert>
                                    }
                                    {errorMessage !== null && 
                                    <Alert severity="error" onClose={() => setErrorMessage(null)}>{errorMessage}</Alert>
                                    }
                                    {cardError !== null && 
                                        <Alert severity="error" onClose={() => setCardError(null)}>{cardError}</Alert>
                                    }
                                    <div style={{position: "relative", minHeight: '56px', padding: '15px', maxWidth: '500px'}}>
                                        <CardElement options={CARD_ELEMENT_OPTIONS}></CardElement>
                                        <fieldset style={{
                                            borderColor: 'rgba(0, 0, 0, 0.23)',
                                            borderStyle: 'solid',
                                            borderWidth: '1px',
                                            borderRadius: '4px',
                                            position: 'absolute',
                                            top: '-5px',
                                            left: '0',
                                            right: '0',
                                            bottom: '0',
                                            margin: '0',
                                            padding: '0 8px',
                                            overflow: 'hidden',
                                            pointerEvents: 'none'
                                            
                                        }}></fieldset>
                                    </div>
                                    <Stack direction="row" spacing={1} mt={2}>
                                        <Button variant="contained" disabled={processing} onClick={(e) => subscribe(e)}>
                                            {processing?(
                                                <><Loader /> Processing...</>
                                            ):(
                                                <>Save</>
                                            )}
                                        </Button>
                                        <Button variant="contained" color="secondary" disabled={processing} onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing")}>Back</Button>
                                    </Stack>
                                </>
                            ):(
                                <Alert type="danger" message="Access Denied." dismissible={false} ></Alert>
                            )}
                        </Stack>
                    ):(
                        <Alert severity="error">The account doesn't support payment methods.</Alert>
                    )}
                </Box>
            </Paper>
        </>

    )
}
Example #19
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
PaymentList = () => {
    const title = 'Billing History';
    const history = useHistory();
    const currency = currencyJSON.currency

    const { userData, authUser } = useContext(AuthContext);
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    // document snapshots
    const [qs, setQs] = useState(null);
    const mountedRef = useRef(true);
    const [total, setTotal] = useState(0);
    const [pageSize, setPageSize] = useState(10);
    const [page, setPage] = useState(0);
    const [rows, setRows] = useState([]);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);

    const getInvoices = useCallback((accountId, pageSize, direction, doc) => {
        const getInvoiceCollectionCount = (accountId) => {
            const accountDocRef = FirebaseAuth.firestore().collection('accounts').doc(accountId);
            return accountDocRef.get().then(accountDoc => {
                if(accountDoc.exists){
                    return accountDoc.data().invoicesColCount;
                }else{
                    return 0;
                }
            }).catch(() => {
                return 0;
            })
        }
    
        setLoading(true);
        let records = [];
        const collectionRef = FirebaseAuth.firestore().collection('accounts').doc(accountId).collection('invoices');
        let query = collectionRef.orderBy('created', 'desc');
        if(direction && direction === 'next'){
            query = query.startAfter(doc);
        }
        if(direction && direction === 'previous'){
            query = query.endBefore(doc);
        }
        query = query.limit(pageSize);
        Promise.all([getInvoiceCollectionCount(accountId), query.get()]).then(([invoiceCount, documentSnapshots]) => {
            if (!mountedRef.current) return null
            setTotal(invoiceCount);
            documentSnapshots.forEach(doc => {
                records.push({
                    'id': doc.id,
                    'total': (doc.data().total / 100).toFixed(2),
                    'subTotal': (doc.data().subTotal / 100).toFixed(2),
                    'tax': ((doc.data().tax || 0) / 100).toFixed(2),
                    'amountPaid': (Math.round(doc.data().amountPaid / 100)).toFixed(2),
                    'created': (new Date(doc.data().created * 1000)).toLocaleString(),
                    'hostedInvoiceUrl': doc.data().hostedInvoiceUrl,
                    'currency': doc.data().currency,
                    'status': doc.data().status,
                    'amountCol': <>{currency[doc.data().currency].sign}{(doc.data().total / 100).toFixed(2)}</>,
                    'statusCol': <>{doc.data().status.toUpperCase()}</>,
                    'urlCol': doc.data().hostedInvoiceUrl?(
                        <Button href={doc.data().hostedInvoiceUrl} rel="noreferrer" target="_blank" variant="contained" size="small">View Invoice</Button>
                    ):(<></>)
                });
            });
            
            if(records.length > 0){
                setRows(records);
                setQs(documentSnapshots);
            }
            setLoading(false);
        }).catch(e => {
            if (!mountedRef.current) return null
            setError(e.message);
            setLoading(false);
        });
    },[currency]);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    },[userData, setBreadcrumb]);

    useEffect(() => {
        getInvoices(userData.currentAccount.id, pageSize);
    },[pageSize, userData, getInvoices]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);


    return (
        <Stack spacing={3}>
            {userData.currentAccount.owner === authUser.user.uid &&
                <Stack direction="row-reverse" spacing={1} mt={2}>
                    <Button color="error" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/delete")}>Delete Account</Button>
                    <Button color="info" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/plan")}>Change Subscription Plan</Button>
                    {userData.currentAccount.price > 0 && 
                    <Button color="info" variant="contained" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing/payment-method")}>Update Payment Method</Button>
                    }
                </Stack>
            }
            <Paper>
                    {loading?(
                        <Box p={3}>
                            <Loader text="Loading billing history..."></Loader>
                        </Box>
                    ):(
                        <>
                        {error?(
                            <Box p={3}>
                                <Alert severity="error">{error}</Alert>
                            </Box>
                        ):(
                            <>
                                {total > 0 ? (
                                    <DataTable columns={[
                                        {name: "Invoice ID", field: "id", style: {width: '30%'}},
                                        {name: "Amount", field: "amountCol", style: {width: '15%'}},
                                        {name: "Status", field: "statusCol", style: {width: '15%'}},
                                        {name: "Invoice Date", field: "created", style: {width: '30%'}},
                                        {name: "Invoice URL", field: "urlCol", style: {width: '10%'}}
                                    ]}
                                    rows={rows}
                                    totalRows={total}
                                    pageSize={pageSize}
                                    page={page}
                                    handlePageChane={(e, p) => {
                                        if(p>page){
                                            getInvoices(userData.currentAccount.id, pageSize, 'next', qs.docs[qs.docs.length-1]);
                                        }
                                        if(p<page){
                                            getInvoices(userData.currentAccount.id, pageSize, 'previous', qs.docs[0]);
                                        }
                                        setPage(p);
                                    }}
                                    handlePageSizeChange={(e) => {
                                        setPageSize(e.target.value);
                                        setPage(0);
                                    }}
                                    ></DataTable>
                                ):(
                                    <Box p={3}>No invoice is found</Box>
                                )}
                            </>
                        )}
                        </>
                    )}
            </Paper>
        </Stack>
    )
}
Example #20
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
NewAccount = () => {
    const title = 'Create New Account';
    const mountedRef = useRef(true);

    const [accountName, setAccountName] = useState({
        hasError: false,
        error: null,
        value: null
    });

    const [errorMessage, setErrorMessage] = useState(null);

    const [inSubmit, setInSubmit] = useState(false);

    const [redirect, setRedirect] = useState(null);
    const { setBreadcrumb } = useContext(BreadcrumbContext);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    }, [setBreadcrumb, title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);


    return (
        <Container>
            <Paper>
                <Box p={2}>
            {redirect === null && 
            <>

                            {errorMessage !== null && 
                                <Alert severity="error" dismissible={true} onDismiss={() => setErrorMessage(null)}>{errorMessage}</Alert>
                            }
                            <div className="card-body">
                                <Form handleSubmit={e =>{
                                    e.preventDefault();
                                    setInSubmit(true);
                                    setErrorMessage(null);
                                    const createAccount = CloudFunctions.httpsCallable('createAccount');
                                    createAccount({
                                        accountName: accountName.value,
                                    }).then(response => {
                                        if (!mountedRef.current) return null 
                                        const accountId = response.data.accountId;
                                        setRedirect('/account/'+accountId+'/billing/plan');
                                    }).catch(err => {
                                        if (!mountedRef.current) return null 
                                        setErrorMessage(err.message);
                                        setInSubmit(false);
                                    })
                                }}
                                disabled={accountName.hasError || accountName.value===null || inSubmit}
                                inSubmit={inSubmit}
                                enableDefaultButtons={true}>
                                    <Input label="Account Name" type="text" name="account-name" maxLen={100} required={true} changeHandler={setAccountName} fullWidth variant="outlined" />
                                </Form>
                            </div>

            </>
            }
            {redirect !== null &&
                <Redirect to={redirect}></Redirect>
            }
                </Box>
            </Paper>
        </Container>

    )
}
Example #21
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
DeleteAccount = () => {
    const title = 'Delete Account';
    const history = useHistory();
    const { userData } = useContext(AuthContext);
    const [error, setError] = useState(null);
    const [success, setSuccess] = useState(false);
    const [inSubmit, setInSubmit] = useState(false);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const mountedRef = useRef(true);
    const currency = currencyJSON.currency

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/billing",
                text: 'Billing',
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    },[userData,setBreadcrumb,title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            {success?(
                <Redirect to="/"></Redirect>
            ):(
                <>
                    <Paper>
                        <Box p={2}>
                            {error !== null && 
                                <Box p={3}>
                                    <Alert severity="error">{error}</Alert>
                                </Box>
                            }
                            <p>Your current subscription period will end on <strong>{(new Date(userData.currentAccount.subscriptionCurrentPeriodEnd * 1000)).toLocaleDateString()}</strong>.</p>
                            <p>The system will charge <strong>{currency[userData.currentAccount.currency].sign}{userData.currentAccount.price}/{userData.currentAccount.paymentCycle}</strong> to renew the subscription. Deleting the account will stop the subscription and no renewal payment will be charged.</p>
                            <p className="text-danger">Are you sure you want to delete your account?</p>
                            <Stack direction="row" spacing={1} mt={2}>
                                <Button variant="contained" color="error" disabled={inSubmit} onClick={() => {
                                    setInSubmit(true);
                                    const cancelSubscription = CloudFunctions.httpsCallable('cancelSubscription');
                                    cancelSubscription({
                                        accountId: userData.currentAccount.id
                                    }).then(res => {
                                        if (!mountedRef.current) return null
                                        setSuccess(true);
                                        setInSubmit(false);
                                    }).catch(err => {
                                        if (!mountedRef.current) return null
                                        setError(err.message);
                                        setInSubmit(false);
                                    })
                                }}>
                                {inSubmit && 
                                    <Loader />
                                }
                                    Yes, I want to delete the account</Button>
                                <Button variant="contained" color="secondary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/billing")}>No, Go Back</Button>
                            </Stack>
                        </Box>
                    </Paper>
                </>
            )}
            
        </>
    )
}
Example #22
Source File: index.js    From fireact with MIT License 4 votes vote down vote up
AddUser = () => {
    const title = 'Add User';
    const mountedRef = useRef(true);
    const history = useHistory(); 

    const { userData } = useContext(AuthContext);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const [emailAddress, setEmailAddress] = useState({
        hasError: false,
        error: null,
        value: null
    });
    const [error, setError] = useState(null);
    const [success, setSuccess] = useState(false);
    const [inSubmit, setInSubmit] = useState(false);
    const [selectedRole, setSelectedRole] = useState('user');
    const [inviteDialog, setInviteDialog] = useState(false);

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/users",
                text: 'Manage Users',
                active: false
            },    
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    }, [userData, setBreadcrumb, title]);

    useEffect(() => {
        return () => { 
            mountedRef.current = false
        }
    },[]);

    return (
        <>
            <Paper>
                <Box p={2}>
                {success?(
                        <>
                            {inviteDialog?(
                                <Alert severity="success">The invite is sent to the email address.</Alert>
                            ):(
                                <Alert severity="success">The user is added to the account.</Alert>
                            )}
                            <Stack direction="row" spacing={1} mt={2}>
                                <Button variant="contained" color="primary" onClick={() => history.push("/account/"+userData.currentAccount.id+"/users")} >Back to User List</Button>
                            </Stack>
                        </>
                    ):(
                        <>
                            {error !== null && 
                                <div style={{marginBottom: '20px'}}><Alert severity="error">{error}</Alert></div>
                            }
                            {inviteDialog?(
                                <>
                                    <Alert severity="info">The email is not registered by any existing user. Do you want to send an invite to the user?</Alert>
                                    <Stack direction="row" spacing={1} mt={2}>
                                        <Button variant="contained" color="primary" disabled={inSubmit} onClick={e => {
                                            e.preventDefault();
                                            setInSubmit(true);
                                            const inviteEmailToAccount = CloudFunctions.httpsCallable('inviteEmailToAccount');
                                            inviteEmailToAccount({
                                                accountId: userData.currentAccount.id,
                                                email: emailAddress.value,
                                                role: selectedRole
                                            }).then(res => {
                                                if (!mountedRef.current) return null
                                                setInSubmit(false);
                                                setSuccess(true);
                                            }).catch(err => {
                                                if (!mountedRef.current) return null
                                                setError(err.message);
                                            });
                                        }}>{inSubmit && <Loader />}
                                            Yes, send an invite</Button>
                                        <Button variant="contained" color="secondary" disabled={inSubmit} onClick={() => {
                                                history.push("/account/"+userData.currentAccount.id+"/users");
                                        }}>No</Button>
                                    </Stack>
                                </>
                            ):(
                                <Form handleSubmit={e => {
                                    e.preventDefault();
                                    setError(null);
                                    setSuccess(false);
                                    setInSubmit(true);
                                    const addUserToAccount = CloudFunctions.httpsCallable('addUserToAccount');
                                    addUserToAccount({
                                        accountId: userData.currentAccount.id,
                                        email: emailAddress.value,
                                        role: selectedRole
                                    }).then(res => {
                                        if (!mountedRef.current) return null
                                        setInSubmit(false);
                                        setSuccess(true);
                                    }).catch(err => {
                                        if (!mountedRef.current) return null
                                        setInSubmit(false);
                                        if(err.details && err.details.code === 'auth/user-not-found'){
                                            setInviteDialog(true);
                                            setInSubmit(false);
                                        }else{
                                            setError(err.message);
                                        }
                                    });
                                }}
                                disabled={emailAddress.hasError || emailAddress.value===null || selectedRole===null || inSubmit}
                                submitBtnStyle={(selectedRole!=='remove')?"primary":"danger"}
                                inSubmit={inSubmit}
                                enableDefaultButtons={true}
                                backToUrl={"/account/"+userData.currentAccount.id+"/users"}
                                >

                                    <Input label="Email Address" type="email" name="email-address" hasError={emailAddress.hasError} error={emailAddress.error} minLen={5} maxLen={50} required={true} validRegex="^[a-zA-Z0-9-_+\.]*@[a-zA-Z0-9-_\.]*\.[a-zA-Z0-9-_\.]*$" changeHandler={setEmailAddress} fullWidth />
                                    <FormControl fullWidth>
                                        <InputLabel>Role</InputLabel>
                                        <Select label="Role" value={selectedRole} onChange={e => {
                                            setSelectedRole(e.target.value);
                                        }}>
                                            <MenuItem value="user">user</MenuItem>
                                            <MenuItem value="admin">admin</MenuItem>
                                        </Select>
                                    </FormControl>
                                </Form>
                            )}
                        </>
                    )}                    
                </Box>
            </Paper>
        </>

    )
}