@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 |
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 |
// ----------------------------------------------------------------------
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 |
// ----------------------------------------------------------------------
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 |
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 |
// ----------------------------------------------------------------------
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 |
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 |
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 |
// ----------------------------------------------------------------------
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 |
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 |
// ----------------------------------------------------------------------
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 |
// ----------------------------------------------------------------------
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 |
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
</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 |
// ----------------------------------------------------------------------
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 |
// ----------------------------------------------------------------------
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 |
// ----------------------------------------------------------------------
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 |
// ----------------------------------------------------------------------
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 |
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>
);
}