@material-ui/core#Stack JavaScript Examples

The following examples show how to use @material-ui/core#Stack. 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: AppNewsUpdate.js    From course-manager with MIT License 6 votes vote down vote up
export default function AppNewsUpdate() {
  return (
    <Card>
      <CardHeader title="News Update" />

      <Scrollbar>
        <Stack spacing={3} sx={{ p: 3, pr: 0 }}>
          {NEWS.map((news) => (
            <NewsItem key={news.title} news={news} />
          ))}
        </Stack>
      </Scrollbar>

      <Divider />

      <Box sx={{ p: 2, textAlign: 'right' }}>
        <Button
          to="#"
          size="small"
          color="inherit"
          component={RouterLink}
          endIcon={<Icon icon={arrowIosForwardFill} />}
        >
          View all
        </Button>
      </Box>
    </Card>
  );
}
Example #2
Source File: Login.js    From course-manager with MIT License 6 votes vote down vote up
// ----------------------------------------------------------------------

export default function Login() {
  return (
    <RootStyle title="Login | Minimal-UI">
      <MHidden width="mdDown">
        <SectionStyle>
          <Typography variant="h3" sx={{ px: 5, mt: 10, mb: 5 }}>
            Hi, Welcome Back
          </Typography>
          <img src="/static/illustrations/illustration_login.png" alt="login" />
        </SectionStyle>
      </MHidden>

      <Container maxWidth="sm">
        <ContentStyle>
          <Stack sx={{ mb: 5 }}>
            <Typography variant="h4" gutterBottom>
              Sign in to Minimal
            </Typography>
            <Typography sx={{ color: 'text.secondary' }}>Enter your details below.</Typography>
          </Stack>
          <LoginForm />
        </ContentStyle>
      </Container>
    </RootStyle>
  );
}
Example #3
Source File: Blog.js    From course-manager with MIT License 6 votes vote down vote up
// ----------------------------------------------------------------------

export default function Blog() {
  return (
    <Page title="Dashboard: Blog | Minimal-UI">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Blog
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="#"
            startIcon={<Icon icon={plusFill} />}
          >
            New Post
          </Button>
        </Stack>

        <Stack mb={5} direction="row" alignItems="center" justifyContent="space-between">
          <BlogPostsSearch posts={POSTS} />
          <BlogPostsSort options={SORT_OPTIONS} />
        </Stack>

        <Grid container spacing={3}>
          {POSTS.map((post, index) => (
            <BlogPostCard key={post.id} post={post} index={index} />
          ))}
        </Grid>
      </Container>
    </Page>
  );
}
Example #4
Source File: DashboardNavbar.js    From course-manager with MIT License 6 votes vote down vote up
export default function DashboardNavbar({ profile, onOpenSidebar }) {
  return (
    <RootStyle>
      <ToolbarStyle>
        <MHidden width="lgUp">
          <IconButton onClick={onOpenSidebar} sx={{ mr: 1, color: 'text.primary' }}>
            <Icon icon={menu2Fill} />
          </IconButton>
        </MHidden>

        <Searchbar />
        <Box sx={{ flexGrow: 1 }} />

        <Stack direction="row" spacing={{ xs: 0.5, sm: 1.5 }}>
          <LanguagePopover />
          <NotificationsPopover />
          {profile && <AccountPopover profile={profile} />}
        </Stack>
      </ToolbarStyle>
    </RootStyle>
  );
}
Example #5
Source File: AuthSocial.js    From course-manager with MIT License 6 votes vote down vote up
// ----------------------------------------------------------------------

export default function AuthSocial() {
  return (
    <>
      <Stack direction="row" spacing={2}>
        <Button fullWidth size="large" color="inherit" variant="outlined">
          <Icon icon={googleFill} color="#DF3E30" height={24} />
        </Button>

        <Button fullWidth size="large" color="inherit" variant="outlined">
          <Icon icon={facebookFill} color="#1877F2" height={24} />
        </Button>

        <Button fullWidth size="large" color="inherit" variant="outlined">
          <Icon icon={twitterFill} color="#1C9CEA" height={24} />
        </Button>
      </Stack>

      <Divider sx={{ my: 3 }}>
        <Typography variant="body2" sx={{ color: 'text.secondary' }}>
          OR
        </Typography>
      </Divider>
    </>
  );
}
Example #6
Source File: AppTasks.js    From course-manager with MIT License 6 votes vote down vote up
function TaskItem({ task, checked, formik, ...other }) {
  const { getFieldProps } = formik;

  return (
    <Stack direction="row" justifyContent="space-between" sx={{ py: 0.75 }}>
      <FormControlLabel
        control={
          <Checkbox {...getFieldProps('checked')} value={task} checked={checked} {...other} />
        }
        label={
          <Typography
            variant="body2"
            sx={{
              ...(checked && {
                color: 'text.disabled',
                textDecoration: 'line-through'
              })
            }}
          >
            {task}
          </Typography>
        }
      />
    </Stack>
  );
}
Example #7
Source File: AppNewsUpdate.js    From course-manager with MIT License 6 votes vote down vote up
function NewsItem({ news }) {
  const { image, title, description, postedAt } = news;

  return (
    <Stack direction="row" alignItems="center" spacing={2}>
      <Box
        component="img"
        alt={title}
        src={image}
        sx={{ width: 48, height: 48, borderRadius: 1.5 }}
      />
      <Box sx={{ minWidth: 240 }}>
        <Link to="#" color="inherit" underline="hover" component={RouterLink}>
          <Typography variant="subtitle2" noWrap>
            {title}
          </Typography>
        </Link>
        <Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap>
          {description}
        </Typography>
      </Box>
      <Typography variant="caption" sx={{ pr: 3, flexShrink: 0, color: 'text.secondary' }}>
        {formatDistance(postedAt, new Date())}
      </Typography>
    </Stack>
  );
}
Example #8
Source File: List.js    From course-manager with MIT License 5 votes vote down vote up
// ----------------------------------------------------------------------

export default function Courses() {
  const [courses, setCourses] = useState([]);
  const [page, setPage] = useState(1);
  const [isLoading, setIsLoading] = useState(false);
  const [canReadMore, setCanReadMore] = useState(true);
  const fetchData = async () => {
    setIsLoading(true);
    const queryString = RequestQueryBuilder.create({
      page,
      limit: 20,
      join: {
        field: 'videos',
        select: ['id']
      }
    });
    const response = await apis.course.find(queryString.query());
    const { data: fetchedCourses, count, page: fetchedPage, pageCount } = response;
    if (count > 0) {
      setCourses(
        fetchedCourses.map(({ id, title, description, thumbnailUrl, videos }) => ({
          id,
          title,
          description,
          videoCount: videos.length,
          thumbnailUrl
        }))
      );
    }
    setCanReadMore(fetchedPage < pageCount);
    setPage(fetchedPage);
    setIsLoading(false);
  };
  useEffect(() => {
    fetchData();
  }, []);
  const fetchMoreCourses = async () => {
    setPage(page + 1);
    await fetchData();
  };
  return (
    <Page title="Courses">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Courses
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="/dashboard/courses/create"
            startIcon={<Icon icon={plusFill} />}
          >
            New Course
          </Button>
        </Stack>

        <Stack direction="column" alignItems="center">
          <CourseList courses={courses} />
          {isLoading && <CircularProgress />}
          {canReadMore && !isLoading && (
            <Button style={{ marginTop: '24px' }} variant="contained" onClick={fetchMoreCourses}>
              More
            </Button>
          )}
        </Stack>
      </Container>
    </Page>
  );
}
Example #9
Source File: VideoCreateForm.js    From course-manager with MIT License 4 votes vote down vote up
function VideoCreateForm({ open, onClose, courseId, onDataCreated }) {
  const classes = useStyles();
  const [videoThumbnailUrl, setVideoThumbnailUrl] = useState('');
  const [videoUrl, setVideoUrl] = useState('');

  const VideoSchema = Yup.object().shape({
    title: Yup.string().required('Title is required'),
    description: Yup.string().required('Description is required')
  });

  const formik = useFormik({
    initialValues: {
      title: '',
      description: ''
    },
    validationSchema: VideoSchema,
    onSubmit: async (values) => {
      const data = {
        ...values,
        thumbnailUrl: videoThumbnailUrl,
        videoUrl,
        courseId
      };
      const newVideo = await apis.video.create(data);
      if (!newVideo) {
        return;
      }
      onDataCreated(newVideo);
      onClose();
    }
  });

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

  return (
    <Modal open={open} onClose={onClose}>
      <Card className={classes.card}>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            New Video
          </Typography>
        </Stack>
        <FormikProvider value={formik}>
          <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
            <Stack spacing={3}>
              <TextField
                fullWidth
                autoComplete="title"
                type="text"
                label="Title"
                {...getFieldProps('title')}
                error={Boolean(touched.title && errors.title)}
                helperText={touched.title && errors.title}
              />
              <TextField
                fullWidth
                autoComplete="description"
                type="text"
                label="Description"
                {...getFieldProps('description')}
                error={Boolean(touched.description && errors.description)}
                helperText={touched.description && errors.description}
              />
              <FileUploader
                initUrl={videoThumbnailUrl}
                type={VIDEO_THUMBNAIL_TYPE}
                setUrl={setVideoThumbnailUrl}
                title="Upload thumbnail"
                name="create-video-thumb"
              />
              <FileUploader
                initUrl={videoUrl}
                type={VIDEO_TYPE}
                setUrl={setVideoUrl}
                title="Upload video"
                name="create-video"
              />
              <LoadingButton
                fullWidth
                size="large"
                type="submit"
                variant="contained"
                loading={isSubmitting}
              >
                Submit
              </LoadingButton>
            </Stack>
          </Form>
        </FormikProvider>
      </Card>
    </Modal>
  );
}
Example #10
Source File: LoginForm.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function LoginForm() {
  const navigate = useNavigate();
  const [showPassword, setShowPassword] = useState(false);

  const LoginSchema = Yup.object().shape({
    username: Yup.string().required('Username is required'),
    password: Yup.string().required('Password is required')
  });

  setUpdateLoginState((newProfile) => {
    console.log(`${newProfile.username} logged in`);
  });

  const formik = useFormik({
    initialValues: {
      username: '',
      password: ''
    },
    validationSchema: LoginSchema,
    onSubmit: async (values) => {
      const user = await apis.auth.login(values);
      if (user) navigate('/dashboard', { replace: true });
    }
  });

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

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

  return (
    <FormikProvider value={formik}>
      <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
        <Stack spacing={3}>
          <TextField
            fullWidth
            autoComplete="username"
            type="text"
            label="Username"
            {...getFieldProps('username')}
            error={Boolean(touched.username && errors.username)}
            helperText={touched.username && errors.username}
          />

          <TextField
            fullWidth
            autoComplete="current-password"
            type={showPassword ? 'text' : 'password'}
            label="Password"
            {...getFieldProps('password')}
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton onClick={handleShowPassword} edge="end">
                    <Icon icon={showPassword ? eyeFill : eyeOffFill} />
                  </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="#">
            Forgot password?
          </Link>
        </Stack>

        <LoadingButton
          fullWidth
          size="large"
          type="submit"
          variant="contained"
          loading={isSubmitting}
        >
          Login
        </LoadingButton>
      </Form>
    </FormikProvider>
  );
}
Example #11
Source File: RegisterForm.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function RegisterForm() {
  const navigate = useNavigate();
  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: () => {
      navigate('/dashboard', { replace: true });
    }
  });

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

  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)}>
                    <Icon icon={showPassword ? eyeFill : eyeOffFill} />
                  </IconButton>
                </InputAdornment>
              )
            }}
            error={Boolean(touched.password && errors.password)}
            helperText={touched.password && errors.password}
          />

          <LoadingButton
            fullWidth
            size="large"
            type="submit"
            variant="contained"
            loading={isSubmitting}
          >
            Register
          </LoadingButton>
        </Stack>
      </Form>
    </FormikProvider>
  );
}
Example #12
Source File: CourseFilterSidebar.js    From course-manager with MIT License 4 votes vote down vote up
export default function ShopFilterSidebar({
  isOpenFilter,
  onResetFilter,
  onOpenFilter,
  onCloseFilter,
  formik
}) {
  const { values, getFieldProps, handleChange } = formik;

  return (
    <>
      <Button
        disableRipple
        color="inherit"
        endIcon={<Icon icon={roundFilterList} />}
        onClick={onOpenFilter}
      >
        Filters&nbsp;
      </Button>

      <FormikProvider value={formik}>
        <Form autoComplete="off" noValidate>
          <Drawer
            anchor="right"
            open={isOpenFilter}
            onClose={onCloseFilter}
            PaperProps={{
              sx: { width: 280, border: 'none', overflow: 'hidden' }
            }}
          >
            <Stack
              direction="row"
              alignItems="center"
              justifyContent="space-between"
              sx={{ px: 1, py: 2 }}
            >
              <Typography variant="subtitle1" sx={{ ml: 1 }}>
                Filters
              </Typography>
              <IconButton onClick={onCloseFilter}>
                <Icon icon={closeFill} width={20} height={20} />
              </IconButton>
            </Stack>

            <Divider />

            <Scrollbar>
              <Stack spacing={3} sx={{ p: 3 }}>
                <div>
                  <Typography variant="subtitle1" gutterBottom>
                    Gender
                  </Typography>
                  <FormGroup>
                    {FILTER_GENDER_OPTIONS.map((item) => (
                      <FormControlLabel
                        key={item}
                        control={
                          <Checkbox
                            {...getFieldProps('gender')}
                            value={item}
                            checked={values.gender.includes(item)}
                          />
                        }
                        label={item}
                      />
                    ))}
                  </FormGroup>
                </div>

                <div>
                  <Typography variant="subtitle1" gutterBottom>
                    Category
                  </Typography>
                  <RadioGroup {...getFieldProps('category')}>
                    {FILTER_CATEGORY_OPTIONS.map((item) => (
                      <FormControlLabel key={item} value={item} control={<Radio />} label={item} />
                    ))}
                  </RadioGroup>
                </div>

                <div>
                  <Typography variant="subtitle1" gutterBottom>
                    Colour
                  </Typography>
                  <ColorManyPicker
                    name="colors"
                    colors={FILTER_COLOR_OPTIONS}
                    onChange={handleChange}
                    onChecked={(color) => values.colors.includes(color)}
                    sx={{ maxWidth: 36 * 4 }}
                  />
                </div>

                <div>
                  <Typography variant="subtitle1" gutterBottom>
                    Price
                  </Typography>
                  <RadioGroup {...getFieldProps('priceRange')}>
                    {FILTER_PRICE_OPTIONS.map((item) => (
                      <FormControlLabel
                        key={item.value}
                        value={item.value}
                        control={<Radio />}
                        label={item.label}
                      />
                    ))}
                  </RadioGroup>
                </div>

                <div>
                  <Typography variant="subtitle1" gutterBottom>
                    Rating
                  </Typography>
                  <RadioGroup {...getFieldProps('rating')}>
                    {FILTER_RATING_OPTIONS.map((item, index) => (
                      <FormControlLabel
                        key={item}
                        value={item}
                        control={
                          <Radio
                            disableRipple
                            color="default"
                            icon={<Rating readOnly value={4 - index} />}
                            checkedIcon={<Rating readOnly value={4 - index} />}
                          />
                        }
                        label="& Up"
                        sx={{
                          my: 0.5,
                          borderRadius: 1,
                          '& > :first-of-type': { py: 0.5 },
                          '&:hover': {
                            opacity: 0.48,
                            '& > *': { bgcolor: 'transparent' }
                          },
                          ...(values.rating.includes(item) && {
                            bgcolor: 'background.neutral'
                          })
                        }}
                      />
                    ))}
                  </RadioGroup>
                </div>
              </Stack>
            </Scrollbar>

            <Box sx={{ p: 3 }}>
              <Button
                fullWidth
                size="large"
                type="submit"
                color="inherit"
                variant="outlined"
                onClick={onResetFilter}
                startIcon={<Icon icon={roundClearAll} />}
              >
                Clear All
              </Button>
            </Box>
          </Drawer>
        </Form>
      </FormikProvider>
    </>
  );
}
Example #13
Source File: Create.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Create() {
  const [thumbnailUrl, setThumbnailUrl] = useState('');
  const navigate = useNavigate();

  const CourseSchema = Yup.object().shape({
    title: Yup.string().required('Full name is required'),
    description: Yup.string().required('Username is required')
  });

  const formik = useFormik({
    initialValues: {
      title: '',
      description: ''
    },
    validationSchema: CourseSchema,
    onSubmit: async (values) => {
      const data = {
        ...values,
        thumbnailUrl
      };
      const newCourse = await apis.course.create(data);
      if (!newCourse) {
        return;
      }
      navigate('/dashboard/courses', { replace: true });
    }
  });

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

  return (
    <Page title="List | Minimal-UI">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            New Course
          </Typography>
        </Stack>
        <FormikProvider value={formik}>
          <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
            <Stack spacing={3}>
              <TextField
                fullWidth
                autoComplete="title"
                type="text"
                label="Title"
                {...getFieldProps('title')}
                error={Boolean(touched.title && errors.title)}
                helperText={touched.title && errors.title}
              />
              <TextField
                fullWidth
                autoComplete="description"
                type="text"
                label="Description"
                {...getFieldProps('description')}
                error={Boolean(touched.description && errors.description)}
                helperText={touched.description && errors.description}
              />
              <FileUploader
                initUrl={thumbnailUrl}
                type={COURSE_THUMBNAIL_TYPE}
                setUrl={setThumbnailUrl}
                title="Upload thumbnail"
                name="create-course-thumb"
              />
              <LoadingButton
                fullWidth
                size="large"
                type="submit"
                variant="contained"
                loading={isSubmitting}
              >
                Submit
              </LoadingButton>
            </Stack>
          </Form>
        </FormikProvider>
        <Card />
      </Container>
    </Page>
  );
}
Example #14
Source File: Edit.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Edit() {
  const navigate = useNavigate();
  const { id } = useParams();
  const [course, setCourse] = useState();
  const [videos, setVideos] = useState([]);
  const [isVideoModelOpen, setVideoModelOpen] = useState(false);
  const [thumbnailUrl, setThumbnailUrl] = useState('');
  useEffect(() => {
    async function fetchCourse() {
      const queryString = RequestQueryBuilder.create({
        join: {
          field: 'videos'
        }
      });
      const course = await apis.course.findOne(id, queryString.query());
      if (!course) navigate('/dashboard/courses', { replace: true });
      formik.initialValues = {
        title: course.title,
        description: course.description
      };
      setCourse(course);
      setVideos(course.videos);
      setThumbnailUrl(course.thumbnailUrl);
    }
    fetchCourse();
  }, []);

  const CourseSchema = Yup.object().shape({
    title: Yup.string().required('Full name is required'),
    description: Yup.string().required('Username is required')
  });

  const formik = useFormik({
    initialValues: course,
    enableReinitialize: true,
    validationSchema: CourseSchema,
    onSubmit: async (values) => {
      const data = {
        ...values,
        thumbnailUrl
      };
      const updatedCourse = await apis.course.update(id, data);
      if (!updatedCourse) {
        return;
      }
      navigate('/dashboard/courses', { replace: true });
    }
  });

  const { errors, touched, isSubmitting, handleSubmit, getFieldProps } = formik;
  const closeVideoForm = (e, reason) => {
    if (reason !== 'backdropClick') setVideoModelOpen(false);
  };

  const videoCreatedHandler = (newVideo) => {
    setVideos([...videos, newVideo]);
  };

  return (
    <Page title="List | Minimal-UI">
      <Container>
        <VideoCreateForm
          open={isVideoModelOpen}
          onClose={closeVideoForm}
          onDataCreated={videoCreatedHandler}
        />
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Edit Course
          </Typography>
        </Stack>
        {course && (
          <FormikProvider value={formik}>
            <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
              <Stack spacing={3}>
                <TextField
                  fullWidth
                  autoComplete="title"
                  type="text"
                  label="Title"
                  {...getFieldProps('title')}
                  error={Boolean(touched.title && errors.title)}
                  helperText={touched.title && errors.title}
                />
                <TextField
                  fullWidth
                  autoComplete="description"
                  type="text"
                  label="Description"
                  {...getFieldProps('description')}
                  error={Boolean(touched.description && errors.description)}
                  helperText={touched.description && errors.description}
                />
                <FileUploader
                  initUrl={thumbnailUrl}
                  type={COURSE_THUMBNAIL_TYPE}
                  setUrl={setThumbnailUrl}
                  title="Upload thumbnail"
                  name="edit-course-thumb"
                />
                <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
                  <Typography variant="h5" gutterBottom>
                    Videos
                  </Typography>
                  <Button
                    variant="contained"
                    onClick={() => setVideoModelOpen(true)}
                    startIcon={<Icon icon={plusFill} />}
                  >
                    Add video
                  </Button>
                </Stack>
                {videos && (
                  <Grid container spacing={3}>
                    {videos.map((video) => (
                      <Grid key={video.id} item xs={12} sm={6} md={3}>
                        <VideoCard video={video} />
                      </Grid>
                    ))}
                  </Grid>
                )}
                <LoadingButton
                  fullWidth
                  size="large"
                  type="submit"
                  variant="contained"
                  loading={isSubmitting}
                >
                  Submit
                </LoadingButton>
              </Stack>
            </Form>
          </FormikProvider>
        )}
        <Card />
      </Container>
    </Page>
  );
}
Example #15
Source File: Courses.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Courses() {
  const [courses, setCourses] = useState([]);
  const [page, setPage] = useState(1);
  const [isLoading, setIsLoading] = useState(false);
  const [canReadMore, setCanReadMore] = useState(true);
  const fetchData = async () => {
    setIsLoading(true);
    const queryString = RequestQueryBuilder.create({
      page,
      limit: 20
    });
    const response = await apis.course.find(queryString.query());
    console.log(response);
    const { data: fetchedCourses, count, page: fetchedPage, pageCount } = response;
    if (count > 0) {
      setCourses(
        fetchedCourses.map(({ id, email, fullName, account: { username }, roles }) => ({
          id,
          email,
          fullName,
          username,
          roles: roles.map(({ name }) => name).join(',')
        }))
      );
    }
    setCanReadMore(fetchedPage < pageCount);
    setPage(fetchedPage);
    setIsLoading(false);
  };
  useEffect(() => {
    fetchData();
  }, []);
  const fetchMoreCourses = async () => {
    setPage(page + 1);
    await fetchData();
  };
  // const [openFilter, setOpenFilter] = useState(false);
  //
  // const formik = useFormik({
  //   initialValues: {
  //     gender: '',
  //     category: '',
  //     colors: '',
  //     priceRange: '',
  //     rating: ''
  //   },
  //   onSubmit: () => {
  //     setOpenFilter(false);
  //   }
  // });
  //
  // const { resetForm, handleSubmit } = formik;
  //
  // const handleOpenFilter = () => {
  //   setOpenFilter(true);
  // };
  //
  // const handleCloseFilter = () => {
  //   setOpenFilter(false);
  // };
  //
  // const handleResetFilter = () => {
  //   handleSubmit();
  //   resetForm();
  // };

  return (
    <Page title="Courses">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Courses
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="/dashboard/course/create"
            startIcon={<Icon icon={plusFill} />}
          >
            New Course
          </Button>
        </Stack>

        {/* <Stack */}
        {/*  direction="row" */}
        {/*  flexWrap="wrap-reverse" */}
        {/*  alignItems="center" */}
        {/*  justifyContent="flex-end" */}
        {/*  sx={{ mb: 5 }} */}
        {/* > */}
        {/*  <Stack direction="row" spacing={1} flexShrink={0} sx={{ my: 1 }}> */}
        {/*    <CourseFilterSidebar */}
        {/*      formik={formik} */}
        {/*      isOpenFilter={openFilter} */}
        {/*      onResetFilter={handleResetFilter} */}
        {/*      onOpenFilter={handleOpenFilter} */}
        {/*      onCloseFilter={handleCloseFilter} */}
        {/*    /> */}
        {/*    <CourseSort /> */}
        {/*  </Stack> */}
        {/* </Stack> */}

        <Stack direction="column" alignItems="center">
          <CourseList courses={PRODUCTS} />
          {isLoading && <CircularProgress />}
          {canReadMore && !isLoading && (
            <Button style={{ marginTop: '24px' }} variant="contained" onClick={fetchMoreCourses}>
              More
            </Button>
          )}
        </Stack>
        {/* <ProductCartWidget /> */}
      </Container>
    </Page>
  );
}
Example #16
Source File: Create.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Create() {
  const navigate = useNavigate();
  const [isAdmin, setIsAdmin] = useState(false);
  const [isMod, setIsMod] = useState(false);
  const [isSupporter, setIsSupporter] = useState(false);

  const UserSchema = Yup.object().shape({
    fullName: Yup.string().required('Full name is required'),
    username: Yup.string().required('Username is required'),
    email: Yup.string().email('Email must be a valid email address').required('Email is required')
  });

  const formik = useFormik({
    initialValues: {
      fullName: '',
      username: '',
      email: ''
    },
    validationSchema: UserSchema,
    onSubmit: async (values) => {
      const roles = [];
      if (isAdmin) roles.push('ADMIN');
      if (isSupporter) roles.push('SUPPORTER');
      if (isMod) roles.push('MOD');

      const newUser = await apis.user.create({
        ...values,
        roles
      });
      console.log(`New user ${newUser.username}`);
      navigate('/dashboard/user', { replace: true });
    }
  });

  const handleChange = (event) => {
    switch (event.target.name) {
      case 'isAdmin':
        setIsAdmin(event.target.checked);
        if (event.target.checked) {
          setIsMod(false);
          setIsSupporter(false);
        }
        break;
      case 'isMod':
        setIsMod(event.target.checked);
        break;
      case 'isSupporter':
        setIsSupporter(event.target.checked);
        break;
      default:
        break;
    }
  };

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

  return (
    <Page title="List | Minimal-UI">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Edit User
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="#"
            startIcon={<Icon icon={plusFill} />}
          >
            New List
          </Button>
        </Stack>
        <FormikProvider value={formik}>
          <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
            <Stack spacing={3}>
              <TextField
                fullWidth
                autoComplete="username"
                type="text"
                label="Username"
                {...getFieldProps('username')}
                error={Boolean(touched.username && errors.username)}
                helperText={touched.username && errors.username}
              />
              <TextField
                fullWidth
                autoComplete="fullName"
                type="text"
                label="Full name"
                {...getFieldProps('fullName')}
                error={Boolean(touched.fullName && errors.fullName)}
                helperText={touched.fullName && errors.fullName}
              />
              <TextField
                fullWidth
                autoComplete="email"
                type="email"
                label="Email"
                {...getFieldProps('email')}
                error={Boolean(touched.email && errors.email)}
                helperText={touched.email && errors.email}
              />
              <FormControlLabel
                control={<ODCheckbox checked={isAdmin} onChange={handleChange} name="isAdmin" />}
                label="Is Admin"
              />
              <FormGroup row>
                <FormControlLabel
                  disabled={isAdmin}
                  control={<ODCheckbox checked={isMod} onChange={handleChange} name="isMod" />}
                  label="Is Mod"
                />
                <FormControlLabel
                  disabled={isAdmin}
                  control={
                    <ODCheckbox checked={isSupporter} onChange={handleChange} name="isSupporter" />
                  }
                  label="Is Supporter"
                />
              </FormGroup>
              <LoadingButton
                fullWidth
                size="large"
                type="submit"
                variant="contained"
                loading={isSubmitting}
              >
                Submit
              </LoadingButton>
            </Stack>
          </Form>
        </FormikProvider>
        <Card />
      </Container>
    </Page>
  );
}
Example #17
Source File: List.js    From course-manager with MIT License 4 votes vote down vote up
export default function List() {
  const [page, setPage] = useState(0);
  const [order, setOrder] = useState('asc');
  const [selected, setSelected] = useState([]);
  const [orderBy, setOrderBy] = useState('fullName');
  const [filterName, setFilterName] = useState('');
  const [rowsPerPage, setRowsPerPage] = useState(5);
  const [users, setUsers] = useState([]);
  const [total, setTotal] = useState(0);

  useEffect(() => {
    const fetchData = async () => {
      console.log(order.toUpperCase());
      const queryString = RequestQueryBuilder.create({
        page,
        limit: rowsPerPage,
        join: [
          {
            field: 'account',
            select: ['username']
          },
          {
            field: 'roles',
            select: ['name']
          }
        ],
        sort: [{ field: orderBy, order: order.toUpperCase() }]
      });
      const response = await apis.user.find(queryString.query());
      const { data: fetchedUsers, total: fetchedTotal } = response;
      if (fetchedUsers && fetchedUsers.length > 0) {
        setUsers(
          fetchedUsers.map(({ id, email, fullName, account: { username }, roles }) => ({
            id,
            email,
            fullName,
            username,
            roles: roles.map(({ name }) => name).join(',')
          }))
        );
      }
      setTotal(fetchedTotal);
    };
    fetchData();
  }, [page, orderBy, order, rowsPerPage]);

  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 = users.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 - users.length) : 0;

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

  const isUserNotFound = filteredUsers.length === 0;

  return (
    <Page title="Users">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Users
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="/dashboard/user/create"
            startIcon={<Icon icon={plusFill} />}
          >
            New User
          </Button>
        </Stack>

        <Card>
          <UserListToolbar
            numSelected={selected.length}
            filterName={filterName}
            onFilterName={handleFilterByName}
          />

          <Scrollbar>
            <TableContainer sx={{ minWidth: 800 }}>
              <Table>
                <UserListHead
                  order={order}
                  orderBy={orderBy}
                  headLabel={TABLE_HEAD}
                  rowCount={total}
                  numSelected={selected.length}
                  onRequestSort={handleRequestSort}
                  onSelectAllClick={handleSelectAllClick}
                />
                <TableBody>
                  {filteredUsers
                    .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                    .map((row) => {
                      const { id, fullName, roles, email, username } = row;
                      const isItemSelected = selected.indexOf(fullName) !== -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, fullName)}
                            />
                          </TableCell>
                          <TableCell component="th" scope="row" padding="none">
                            <Stack direction="row" alignItems="center" spacing={2}>
                              {/* <Avatar alt={fullName} src={avatarUrl} /> */}
                              <Typography variant="subtitle2" noWrap>
                                {fullName}
                              </Typography>
                            </Stack>
                          </TableCell>
                          <TableCell align="left">{username}</TableCell>
                          <TableCell align="left">{email}</TableCell>
                          <TableCell align="left">{roles}</TableCell>
                          <TableCell align="right">
                            <UserMoreMenu id={id} />
                          </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={total}
            rowsPerPage={rowsPerPage}
            page={page}
            onPageChange={handleChangePage}
            onRowsPerPageChange={handleChangeRowsPerPage}
          />
        </Card>
      </Container>
    </Page>
  );
}